mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
WIP
This commit is contained in:
parent
b9496c8d90
commit
7357da1e18
3 changed files with 72 additions and 3 deletions
|
|
@ -1376,6 +1376,12 @@ pub const ComptimeEvaluator = struct {
|
|||
return true; // Ok
|
||||
}
|
||||
return true; // Unknown format, optimistically allow
|
||||
} else if (result.layout.tag == .tag_union) {
|
||||
// Tag union layout: payload at offset 0, discriminant at discriminant_offset
|
||||
// For Try types from num.from_numeral, the interpreter should have stored
|
||||
// the error message in last_error_message, which was already checked above.
|
||||
// If we reach here without a last_error_message, assume it's Ok.
|
||||
return true;
|
||||
}
|
||||
|
||||
return true; // Unknown format, optimistically allow
|
||||
|
|
|
|||
|
|
@ -3561,6 +3561,35 @@ pub const Interpreter = struct {
|
|||
}
|
||||
}
|
||||
|
||||
// Store error message for Err case (same as tuple branch)
|
||||
if (!in_range) {
|
||||
var num_str_buf: [128]u8 = undefined;
|
||||
const num_str = can.CIR.formatBase256ToDecimal(is_negative, digits_before, digits_after, &num_str_buf);
|
||||
|
||||
const error_msg = switch (rejection_reason) {
|
||||
.negative_unsigned => std.fmt.allocPrint(
|
||||
self.allocator,
|
||||
"The number {s} is not a valid {s}. {s} values cannot be negative.",
|
||||
.{ num_str, type_name, type_name },
|
||||
) catch null,
|
||||
.fractional_integer => std.fmt.allocPrint(
|
||||
self.allocator,
|
||||
"The number {s} is not a valid {s}. {s} values must be whole numbers, not fractions.",
|
||||
.{ num_str, type_name, type_name },
|
||||
) catch null,
|
||||
.out_of_range, .overflow => std.fmt.allocPrint(
|
||||
self.allocator,
|
||||
"The number {s} is not a valid {s}. Valid {s} values are integers between {s} and {s}.",
|
||||
.{ num_str, type_name, type_name, min_value_str, max_value_str },
|
||||
) catch null,
|
||||
.none => null,
|
||||
};
|
||||
|
||||
if (error_msg) |msg| {
|
||||
self.last_error_message = msg;
|
||||
}
|
||||
}
|
||||
|
||||
dest.is_initialized = true;
|
||||
return dest;
|
||||
}
|
||||
|
|
@ -4098,6 +4127,38 @@ pub const Interpreter = struct {
|
|||
}
|
||||
// For Err case, payload is OutOfRange which is a zero-arg tag (already zeroed)
|
||||
|
||||
return dest;
|
||||
} else if (result_layout.tag == .tag_union) {
|
||||
// Tag union layout: payload at offset 0, discriminant at discriminant_offset
|
||||
const dest = try self.pushRaw(result_layout, 0);
|
||||
const tu_data = self.runtime_layout_store.getTagUnionData(result_layout.data.tag_union.idx);
|
||||
|
||||
// Write tag discriminant at discriminant_offset
|
||||
const base_ptr: [*]u8 = @ptrCast(dest.ptr.?);
|
||||
const disc_ptr = base_ptr + tu_data.discriminant_offset;
|
||||
const tag_idx: usize = if (in_range) ok_index orelse 0 else err_index orelse 1;
|
||||
switch (tu_data.discriminant_size) {
|
||||
1 => @as(*u8, @ptrCast(disc_ptr)).* = @intCast(tag_idx),
|
||||
2 => @as(*u16, @ptrCast(@alignCast(disc_ptr))).* = @intCast(tag_idx),
|
||||
4 => @as(*u32, @ptrCast(@alignCast(disc_ptr))).* = @intCast(tag_idx),
|
||||
8 => @as(*u64, @ptrCast(@alignCast(disc_ptr))).* = @intCast(tag_idx),
|
||||
else => {},
|
||||
}
|
||||
|
||||
// Clear payload area (at offset 0)
|
||||
const payload_size = tu_data.discriminant_offset; // Payload spans from 0 to discriminant_offset
|
||||
if (payload_size > 0) {
|
||||
@memset(base_ptr[0..payload_size], 0);
|
||||
}
|
||||
|
||||
// Write payload for Ok case
|
||||
if (in_range) {
|
||||
const to_value: To = @intCast(from_value);
|
||||
const payload_ptr: *To = @ptrCast(@alignCast(base_ptr));
|
||||
payload_ptr.* = to_value;
|
||||
}
|
||||
// For Err case, payload is OutOfRange which is a zero-arg tag (already zeroed)
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -302,8 +302,10 @@ test "interpreter: F64 division" {
|
|||
, 0.5, .no_trace);
|
||||
}
|
||||
|
||||
test "interpreter: literal True renders True" {
|
||||
const roc_src = "True";
|
||||
test "interpreter: literal tag renders as tag name" {
|
||||
// Use a custom tag instead of True - True is a Bool tag which requires
|
||||
// proper builtin module resolution to get the nominal type
|
||||
const roc_src = "MyTag";
|
||||
const resources = try helpers.parseAndCanonicalizeExpr(std.testing.allocator, roc_src);
|
||||
defer helpers.cleanupParseAndCanonical(std.testing.allocator, resources);
|
||||
|
||||
|
|
@ -318,7 +320,7 @@ test "interpreter: literal True renders True" {
|
|||
const rt_var = try interp2.translateTypeVar(resources.module_env, can.ModuleEnv.varFrom(resources.expr_idx));
|
||||
const rendered = try interp2.renderValueRocWithType(result, rt_var);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
try std.testing.expectEqualStrings("True", rendered);
|
||||
try std.testing.expectEqualStrings("MyTag", rendered);
|
||||
}
|
||||
|
||||
test "interpreter: True == False yields False" {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue