diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-01-31 15:53:23 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-01-31 15:57:48 +0900 |
| commit | 7712c1d10ec45349c1cd6e66281b7d602350065d (patch) | |
| tree | 92208e7fb1955fd9847d91affa25ec096012ab9b /src/jv | |
| parent | 617ddc62aa4d3153850362526069b85bfaf5e59e (diff) | |
| download | zgjq-7712c1d10ec45349c1cd6e66281b7d602350065d.tar.gz zgjq-7712c1d10ec45349c1cd6e66281b7d602350065d.tar.zst zgjq-7712c1d10ec45349c1cd6e66281b7d602350065d.zip | |
implement slice expression
Diffstat (limited to 'src/jv')
| -rw-r--r-- | src/jv/ops.zig | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/jv/ops.zig b/src/jv/ops.zig index 8d5f8fc..e84cb7d 100644 --- a/src/jv/ops.zig +++ b/src/jv/ops.zig @@ -5,6 +5,7 @@ const Object = @import("./value.zig").Object; pub const OpsError = error{ InvalidType, + InternalError, Unimplemented, }; @@ -23,6 +24,61 @@ pub fn index(base: Value, key: Value) OpsError!Value { }; } +pub fn slice(allocator: std.mem.Allocator, base: Value, from: Value, to: Value) OpsError!Value { + switch (base) { + .array => |a| { + const len: i64 = @intCast(a.len()); + + var start: i64 = if (from == .null) 0 else if (from == .integer) from.integer else return error.InvalidType; + var end: i64 = if (to == .null) len else if (to == .integer) to.integer else return error.InvalidType; + + if (start < 0) start += len; + if (end < 0) end += len; + + start = @max(0, @min(start, len)); + end = @max(0, @min(end, len)); + + if (start >= end) { + const empty = Array.init(allocator) catch return error.InternalError; + return Value.initArray(empty); + } + + var result = Array.init(allocator) catch return error.InternalError; + const ustart: usize = @intCast(start); + const uend: usize = @intCast(end); + var i: usize = ustart; + while (i < uend) : (i += 1) { + result.append(allocator, a.get(i)) catch return error.InternalError; + } + return Value.initArray(result); + }, + .string => |s| { + const len: i64 = @intCast(s.len); + + var start: i64 = if (from == .null) 0 else if (from == .integer) from.integer else return error.InvalidType; + var end: i64 = if (to == .null) len else if (to == .integer) to.integer else return error.InvalidType; + + if (start < 0) start += len; + if (end < 0) end += len; + + start = @max(0, @min(start, len)); + end = @max(0, @min(end, len)); + + if (start >= end) { + const duped = allocator.dupe(u8, "") catch return error.InternalError; + return Value.initString(duped); + } + + const ustart: usize = @intCast(start); + const uend: usize = @intCast(end); + const duped = allocator.dupe(u8, s[ustart..uend]) catch return error.InternalError; + return Value.initString(duped); + }, + .null => return .null, + else => return error.InvalidType, + } +} + pub const CompareOp = enum { eq, ne, lt, gt, le, ge }; pub fn compare(lhs: Value, rhs: Value, op: CompareOp) OpsError!bool { |
