aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/jq/codegen.zig3
-rw-r--r--src/jq/execute.zig13
-rw-r--r--src/root.zig21
3 files changed, 37 insertions, 0 deletions
diff --git a/src/jq/codegen.zig b/src/jq/codegen.zig
index e377a5c..21c5832 100644
--- a/src/jq/codegen.zig
+++ b/src/jq/codegen.zig
@@ -28,6 +28,7 @@ pub const Opcode = enum {
gt,
le,
ge,
+ alt,
@"const",
const_true,
const_false,
@@ -58,6 +59,7 @@ pub const Instr = union(Opcode) {
gt,
le,
ge,
+ alt,
@"const": ConstIndex,
const_true,
const_false,
@@ -108,6 +110,7 @@ const Codegen = struct {
.gt => .gt,
.le => .le,
.ge => .ge,
+ .alt => .alt,
else => return error.Unimplemented,
};
try self.emit(op_instr);
diff --git a/src/jq/execute.zig b/src/jq/execute.zig
index f2bfe8c..0565004 100644
--- a/src/jq/execute.zig
+++ b/src/jq/execute.zig
@@ -328,6 +328,19 @@ pub const Runtime = struct {
const result = try jv.ops.compare(lhs, rhs, .ge);
try self.values.push(.{ .bool = result });
},
+ .alt => {
+ std.debug.assert(self.values.ensureSize(3));
+
+ _ = self.values.pop();
+ const lhs = self.values.pop();
+ const rhs = self.values.pop();
+ const is_falsy = switch (lhs) {
+ .null => true,
+ .bool => |b| !b,
+ else => false,
+ };
+ try self.values.push(if (is_falsy) rhs else lhs);
+ },
.@"const" => |idx| {
std.debug.assert(self.values.ensureSize(1));
diff --git a/src/root.zig b/src/root.zig
index b612d89..7aee514 100644
--- a/src/root.zig
+++ b/src/root.zig
@@ -254,3 +254,24 @@ test "or operator" {
try testRun("true", "{\"a\":false,\"b\":true}", ".a or .b");
try testRun("false", "{\"a\":false,\"b\":false}", ".a or .b");
}
+
+test "alternative operator" {
+ try testRun("\"default\"", "null", ". // \"default\"");
+ try testRun("\"hello\"", "\"hello\"", ". // \"default\"");
+
+ try testRun("\"default\"", "false", ". // \"default\"");
+ try testRun("true", "true", ". // \"default\"");
+
+ try testRun("123", "{\"a\":123}", ".a // \"default\"");
+ try testRun("\"default\"", "{\"a\":123}", ".b // \"default\"");
+ try testRun("\"default\"", "{\"a\":null}", ".a // \"default\"");
+
+ try testRun("\"third\"", "null", "null // false // \"third\"");
+ try testRun("\"first\"", "null", "\"first\" // \"second\" // \"third\"");
+
+ try testRun("0", "0", ". // 42");
+ try testRun("\"\"", "\"\"", ". // \"default\"");
+
+ try testRun("[]", "[]", ". // \"default\"");
+ try testRun("{}", "{}", ". // \"default\"");
+}