mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
Unify Interpreter2 bool semantics
This commit is contained in:
parent
90841c3b65
commit
b719ba70bd
5 changed files with 672 additions and 271 deletions
|
|
@ -113,8 +113,10 @@
|
|||
|
||||
5) Match (wider coverage)
|
||||
- Current minimal support: assign, underscore, int & string literals, nominal passthrough, OR patterns.
|
||||
- Progress:
|
||||
- Tuple destructuring patterns now match in Interpreter2 (see `match (1, 2)` test).
|
||||
- TODO:
|
||||
- Tuple and record destructuring patterns (bind sub‑components recursively).
|
||||
- Record destructuring patterns (bind sub-components recursively).
|
||||
- Tag union patterns (tag name and payloads) once tag unions are represented for runtime.
|
||||
- Guards support.
|
||||
- Add tests incrementally (starting from simple patterns), always with Roc syntax and early compilation failure
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -46,6 +46,13 @@ pub fn renderValueRocWithType(ctx: *RenderCtx, value: StackValue, rt_var: types.
|
|||
tag_index = @intCast(value.asI128());
|
||||
have_tag = true;
|
||||
}
|
||||
if (have_tag and tag_index < tags.len) {
|
||||
const tag_name = ctx.env.getIdent(tags.items(.name)[tag_index]);
|
||||
var out = std.ArrayList(u8).init(gpa);
|
||||
errdefer out.deinit();
|
||||
try out.appendSlice(tag_name);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
} else if (value.layout.tag == .record) {
|
||||
var acc = try value.asRecord(ctx.layout_store);
|
||||
if (acc.findFieldIndex(ctx.env, "tag")) |idx| {
|
||||
|
|
@ -135,8 +142,12 @@ pub fn renderValueRoc(ctx: *RenderCtx, value: StackValue) ![]u8 {
|
|||
try buf.append('"');
|
||||
for (s) |ch| {
|
||||
switch (ch) {
|
||||
'\\' => { try buf.appendSlice("\\\\"); },
|
||||
'"' => { try buf.appendSlice("\\\""); },
|
||||
'\\' => {
|
||||
try buf.appendSlice("\\\\");
|
||||
},
|
||||
'"' => {
|
||||
try buf.appendSlice("\\\"");
|
||||
},
|
||||
else => try buf.append(ch),
|
||||
}
|
||||
}
|
||||
|
|
@ -194,4 +205,3 @@ pub fn renderValueRoc(ctx: *RenderCtx, value: StackValue) ![]u8 {
|
|||
}
|
||||
return try std.fmt.allocPrint(gpa, "<unsupported>", .{});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -186,6 +186,116 @@ test "interpreter2: literal True renders True" {
|
|||
try std.testing.expectEqualStrings("True", rendered);
|
||||
}
|
||||
|
||||
test "interpreter2: True == False yields False" {
|
||||
const roc_src = "True == False";
|
||||
const resources = try helpers.parseAndCanonicalizeExpr(std.testing.allocator, roc_src);
|
||||
defer helpers.cleanupParseAndCanonical(std.testing.allocator, resources);
|
||||
|
||||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = RocOps{
|
||||
.env = @ptrCast(&host),
|
||||
.roc_alloc = testRocAlloc,
|
||||
.roc_dealloc = testRocDealloc,
|
||||
.roc_realloc = testRocRealloc,
|
||||
.roc_dbg = testRocDbg,
|
||||
.roc_expect_failed = testRocExpectFailed,
|
||||
.roc_crashed = testRocCrashed,
|
||||
.host_fns = undefined,
|
||||
};
|
||||
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const ct_var = can.ModuleEnv.varFrom(resources.expr_idx);
|
||||
const rt_var = try interp2.translateTypeVar(resources.module_env, ct_var);
|
||||
const rendered = try interp2.renderValueRocWithType(result, rt_var);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
try std.testing.expectEqualStrings("False", rendered);
|
||||
}
|
||||
|
||||
test "interpreter2: \"hi\" == \"hi\" yields True" {
|
||||
const roc_src = "\"hi\" == \"hi\"";
|
||||
const resources = try helpers.parseAndCanonicalizeExpr(std.testing.allocator, roc_src);
|
||||
defer helpers.cleanupParseAndCanonical(std.testing.allocator, resources);
|
||||
|
||||
try helpers.runExpectBool(roc_src, true, .no_trace);
|
||||
|
||||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = RocOps{
|
||||
.env = @ptrCast(&host),
|
||||
.roc_alloc = testRocAlloc,
|
||||
.roc_dealloc = testRocDealloc,
|
||||
.roc_realloc = testRocRealloc,
|
||||
.roc_dbg = testRocDbg,
|
||||
.roc_expect_failed = testRocExpectFailed,
|
||||
.roc_crashed = testRocCrashed,
|
||||
.host_fns = undefined,
|
||||
};
|
||||
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const ct_var = can.ModuleEnv.varFrom(resources.expr_idx);
|
||||
const rt_var = try interp2.translateTypeVar(resources.module_env, ct_var);
|
||||
const rendered = try interp2.renderValueRocWithType(result, rt_var);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
try std.testing.expectEqualStrings("True", rendered);
|
||||
}
|
||||
|
||||
test "interpreter2: match tuple pattern destructures" {
|
||||
const roc_src = "match (1, 2) { (1, b) => b, _ => 0 }";
|
||||
const resources = try helpers.parseAndCanonicalizeExpr(std.testing.allocator, roc_src);
|
||||
defer helpers.cleanupParseAndCanonical(std.testing.allocator, resources);
|
||||
|
||||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = RocOps{
|
||||
.env = @ptrCast(&host),
|
||||
.roc_alloc = testRocAlloc,
|
||||
.roc_dealloc = testRocDealloc,
|
||||
.roc_realloc = testRocRealloc,
|
||||
.roc_dbg = testRocDbg,
|
||||
.roc_expect_failed = testRocExpectFailed,
|
||||
.roc_crashed = testRocCrashed,
|
||||
.host_fns = undefined,
|
||||
};
|
||||
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
try std.testing.expectEqualStrings("2", rendered);
|
||||
}
|
||||
|
||||
test "interpreter2: match bool patterns" {
|
||||
const roc_src = "match True { True => 1, False => 0 }";
|
||||
const resources = try helpers.parseAndCanonicalizeExpr(std.testing.allocator, roc_src);
|
||||
defer helpers.cleanupParseAndCanonical(std.testing.allocator, resources);
|
||||
|
||||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = RocOps{
|
||||
.env = @ptrCast(&host),
|
||||
.roc_alloc = testRocAlloc,
|
||||
.roc_dealloc = testRocDealloc,
|
||||
.roc_realloc = testRocRealloc,
|
||||
.roc_dbg = testRocDbg,
|
||||
.roc_expect_failed = testRocExpectFailed,
|
||||
.roc_crashed = testRocCrashed,
|
||||
.host_fns = undefined,
|
||||
};
|
||||
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
try std.testing.expectEqualStrings("1", rendered);
|
||||
}
|
||||
|
||||
test "interpreter2: tuples and records" {
|
||||
// Tuple test: (1, 2)
|
||||
const src_tuple = "(1, 2)";
|
||||
|
|
|
|||
|
|
@ -188,12 +188,12 @@ pub const Store = struct {
|
|||
|
||||
pub fn mkBool(self: *Self, gpa: Allocator, idents: *base.Ident.Store, ext_var: Var) std.mem.Allocator.Error!Content {
|
||||
// TODO: Hardcode idents once in store, do no create fn anno
|
||||
const true_ident = try idents.insert(gpa, base.Ident.for_text("True"));
|
||||
const false_ident = try idents.insert(gpa, base.Ident.for_text("False"));
|
||||
const true_ident = try idents.insert(gpa, base.Ident.for_text("True"));
|
||||
|
||||
const true_tag = try self.mkTag(true_ident, &[_]Var{});
|
||||
const false_tag = try self.mkTag(false_ident, &[_]Var{});
|
||||
return try self.mkTagUnion(&[_]Tag{ true_tag, false_tag }, ext_var);
|
||||
const true_tag = try self.mkTag(true_ident, &[_]Var{});
|
||||
return try self.mkTagUnion(&[_]Tag{ false_tag, true_tag }, ext_var);
|
||||
}
|
||||
|
||||
pub fn mkResult(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue