Skip to content

Commit 8fd302c

Browse files
committed
Improve eval error message output
1 parent 19b40aa commit 8fd302c

File tree

5 files changed

+87
-3
lines changed

5 files changed

+87
-3
lines changed

src/build/roc/Builtin.roc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ Builtin :: [].{
1515

1616
is_eq : List(item), List(item) -> Bool
1717
where [item.is_eq : item, item -> Bool]
18+
# is_eq = |self, other| {
19+
# if List.len(self) != List.len(other) {
20+
# Bool.False
21+
# } else {
22+
# list_is_eq_helper(self, other, 0)
23+
# }
24+
# }
1825

1926
first : List(item) -> Try(item, [ListWasEmpty])
2027
first = |list| List.get(list, 0)

src/playground_wasm/main.zig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,6 +1327,14 @@ fn parseReplResult(result: []const u8) ReplStepResult {
13271327
.error_stage = .parse,
13281328
.error_details = if (result.len > 13) result[13..] else null,
13291329
};
1330+
} else if (std.mem.startsWith(u8, result, "**") and std.mem.indexOf(u8, result, "**\n") != null) {
1331+
// New markdown-formatted error messages (e.g., "**UNEXPECTED TOKEN IN EXPRESSION**\n...")
1332+
return ReplStepResult{
1333+
.output = result,
1334+
.try_type = .@"error",
1335+
.error_stage = .parse,
1336+
.error_details = extractErrorDetails(result),
1337+
};
13301338
} else if (std.mem.indexOf(u8, result, "Canonicalize") != null) {
13311339
return ReplStepResult{
13321340
.output = result,

src/repl/eval.zig

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const CrashContext = eval_mod.CrashContext;
1515
const BuiltinTypes = eval_mod.BuiltinTypes;
1616
const builtin_loading = eval_mod.builtin_loading;
1717
const collections = @import("collections");
18+
const reporting = @import("reporting");
1819

1920
const AST = parse.AST;
2021
const Allocator = std.mem.Allocator;
@@ -385,6 +386,53 @@ pub const Repl = struct {
385386
};
386387
defer parse_ast.deinit(self.allocator);
387388

389+
// Check for parse errors and render them
390+
if (parse_ast.hasErrors()) {
391+
// Render the first error as the error message
392+
if (parse_ast.tokenize_diagnostics.items.len > 0) {
393+
var report = try parse_ast.tokenizeDiagnosticToReport(
394+
parse_ast.tokenize_diagnostics.items[0],
395+
self.allocator,
396+
null,
397+
);
398+
defer report.deinit();
399+
400+
var output = std.array_list.Managed(u8).init(self.allocator);
401+
var unmanaged = output.moveToUnmanaged();
402+
var writer_alloc = std.Io.Writer.Allocating.fromArrayList(self.allocator, &unmanaged);
403+
report.render(&writer_alloc.writer, .markdown) catch |err| switch (err) {
404+
error.WriteFailed => return error.OutOfMemory,
405+
else => return err,
406+
};
407+
unmanaged = writer_alloc.toArrayList();
408+
output = unmanaged.toManaged(self.allocator);
409+
return try output.toOwnedSlice();
410+
} else if (parse_ast.parse_diagnostics.items.len > 0) {
411+
var report = try parse_ast.parseDiagnosticToReport(
412+
&module_env.common,
413+
parse_ast.parse_diagnostics.items[0],
414+
self.allocator,
415+
"repl",
416+
);
417+
defer report.deinit();
418+
419+
var output = std.array_list.Managed(u8).init(self.allocator);
420+
var unmanaged = output.moveToUnmanaged();
421+
var writer_alloc = std.Io.Writer.Allocating.fromArrayList(self.allocator, &unmanaged);
422+
report.render(&writer_alloc.writer, .markdown) catch |err| switch (err) {
423+
error.WriteFailed => return error.OutOfMemory,
424+
else => return err,
425+
};
426+
unmanaged = writer_alloc.toArrayList();
427+
output = unmanaged.toManaged(self.allocator);
428+
// Trim trailing newlines from the output and return a properly allocated copy
429+
const full_result = try output.toOwnedSlice();
430+
defer self.allocator.free(full_result);
431+
const trimmed = std.mem.trimRight(u8, full_result, "\n");
432+
return try self.allocator.dupe(u8, trimmed);
433+
}
434+
}
435+
388436
// Empty scratch space
389437
parse_ast.store.emptyScratch();
390438

@@ -453,6 +501,25 @@ pub const Repl = struct {
453501
const expr_idx: AST.Expr.Idx = @enumFromInt(parse_ast.root_node_idx);
454502

455503
const canonical_expr = try czer.canonicalizeExpr(expr_idx) orelse {
504+
// Check for diagnostics and render them as error messages
505+
const diagnostics = try module_env.getDiagnostics();
506+
if (diagnostics.len > 0) {
507+
// Render the first diagnostic as the error message
508+
const diagnostic = diagnostics[0];
509+
var report = try module_env.diagnosticToReport(diagnostic, self.allocator, "repl");
510+
defer report.deinit();
511+
512+
var output = std.array_list.Managed(u8).init(self.allocator);
513+
var unmanaged = output.moveToUnmanaged();
514+
var writer_alloc = std.Io.Writer.Allocating.fromArrayList(self.allocator, &unmanaged);
515+
report.render(&writer_alloc.writer, .markdown) catch |err| switch (err) {
516+
error.WriteFailed => return error.OutOfMemory,
517+
else => return err,
518+
};
519+
unmanaged = writer_alloc.toArrayList();
520+
output = unmanaged.toManaged(self.allocator);
521+
return try output.toOwnedSlice();
522+
}
456523
return try self.allocator.dupe(u8, "Canonicalize expr error: expression returned null");
457524
};
458525
const final_expr_idx = canonical_expr.get_idx();

test/playground-integration/main.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,9 +1189,9 @@ pub fn main() !void {
11891189
repl_error_steps[3] = .{
11901190
.message = .{ .type = "REPL_STEP", .input = "x +" }, // Invalid syntax - incomplete expression
11911191
.expected_status = "SUCCESS",
1192-
.expected_result_output_contains = "Crash:",
1192+
.expected_result_output_contains = "UNEXPECTED TOKEN",
11931193
.expected_result_type = "error",
1194-
.expected_result_error_stage = "evaluation",
1194+
.expected_result_error_stage = "parse",
11951195
};
11961196
repl_error_steps[4] = .{
11971197
.message = .{ .type = "REPL_STEP", .input = "x" }, // Should still work

test/snapshots/repl/return_outside_function.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ type=repl
88
» return 42
99
~~~
1010
# OUTPUT
11-
Canonicalize expr error: expression returned null
11+
**UNEXPECTED TOKEN IN EXPRESSION**
12+
The token **return** is not expected in an expression.
13+
Expressions can be identifiers, literals, function calls, or operators.
1214
# PROBLEMS
1315
NIL

0 commit comments

Comments
 (0)