mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-10 11:09:50 +00:00
check for parse/token errors and print them on run (#8586)
* check for parse/token errors and print them on run * return early on parse fail if errors are not allowed * fix merge issue
This commit is contained in:
parent
c1b088e870
commit
ea76b7b1ee
4 changed files with 67 additions and 9 deletions
|
|
@ -1106,7 +1106,7 @@ fn rocRun(allocs: *Allocators, args: cli_args.RunArgs) !void {
|
|||
|
||||
// Set up shared memory with ModuleEnv
|
||||
std.log.debug("Setting up shared memory for Roc file: {s}", .{args.path});
|
||||
const shm_result = setupSharedMemoryWithModuleEnv(allocs, args.path) catch |err| {
|
||||
const shm_result = setupSharedMemoryWithModuleEnv(allocs, args.path, args.allow_errors) catch |err| {
|
||||
std.log.err("Failed to set up shared memory with ModuleEnv: {}", .{err});
|
||||
return err;
|
||||
};
|
||||
|
|
@ -1461,7 +1461,7 @@ fn writeToWindowsSharedMemory(data: []const u8, total_size: usize) !SharedMemory
|
|||
/// This parses, canonicalizes, and type-checks all modules, with the resulting ModuleEnvs
|
||||
/// ending up in shared memory because all allocations were done into shared memory.
|
||||
/// Platform type modules have their e_anno_only expressions converted to e_hosted_lambda.
|
||||
pub fn setupSharedMemoryWithModuleEnv(allocs: *Allocators, roc_file_path: []const u8) !SharedMemoryResult {
|
||||
pub fn setupSharedMemoryWithModuleEnv(allocs: *Allocators, roc_file_path: []const u8, allow_errors: bool) !SharedMemoryResult {
|
||||
// Create shared memory with SharedMemoryAllocator
|
||||
const page_size = try SharedMemoryAllocator.getSystemPageSize();
|
||||
var shm = try SharedMemoryAllocator.create(SHARED_MEMORY_SIZE, page_size);
|
||||
|
|
@ -1692,10 +1692,39 @@ pub fn setupSharedMemoryWithModuleEnv(allocs: *Allocators, roc_file_path: []cons
|
|||
app_env.module_name = app_module_name;
|
||||
try app_env.common.calcLineStarts(shm_allocator);
|
||||
|
||||
var error_count: usize = 0;
|
||||
|
||||
var app_parse_ast = try parse.parse(&app_env.common, allocs.gpa);
|
||||
defer app_parse_ast.deinit(allocs.gpa);
|
||||
app_parse_ast.store.emptyScratch();
|
||||
if (app_parse_ast.hasErrors()) {
|
||||
const stderr = stderrWriter();
|
||||
defer stderr.flush() catch {};
|
||||
for (app_parse_ast.tokenize_diagnostics.items) |diagnostic| {
|
||||
error_count += 1;
|
||||
var report = app_parse_ast.tokenizeDiagnosticToReport(diagnostic, allocs.gpa, roc_file_path) catch continue;
|
||||
defer report.deinit();
|
||||
reporting.renderReportToTerminal(&report, stderr, ColorPalette.ANSI, reporting.ReportingConfig.initColorTerminal()) catch continue;
|
||||
}
|
||||
for (app_parse_ast.parse_diagnostics.items) |diagnostic| {
|
||||
error_count += 1;
|
||||
var report = app_parse_ast.parseDiagnosticToReport(&app_env.common, diagnostic, allocs.gpa, roc_file_path) catch continue;
|
||||
defer report.deinit();
|
||||
reporting.renderReportToTerminal(&report, stderr, ColorPalette.ANSI, reporting.ReportingConfig.initColorTerminal()) catch continue;
|
||||
}
|
||||
// If errors are not allowed then we should not move past parsing. return early and let caller handle error/exit
|
||||
if (!allow_errors) {
|
||||
return SharedMemoryResult{
|
||||
.handle = SharedMemoryHandle{
|
||||
.fd = shm.handle,
|
||||
.ptr = shm.base_ptr,
|
||||
.size = shm.getUsedSize(),
|
||||
},
|
||||
.error_count = error_count,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
app_parse_ast.store.emptyScratch();
|
||||
try app_env.initCIRFields(app_module_name);
|
||||
|
||||
var app_module_envs_map = std.AutoHashMap(base.Ident.Idx, Can.AutoImportedType).init(allocs.gpa);
|
||||
|
|
@ -1851,7 +1880,7 @@ pub fn setupSharedMemoryWithModuleEnv(allocs: *Allocators, roc_file_path: []cons
|
|||
// Render all type problems (errors and warnings) exactly as roc check would
|
||||
// Count errors so the caller can decide whether to proceed with execution
|
||||
// Skip rendering in test mode to avoid polluting test output
|
||||
const error_count = if (!builtin.is_test)
|
||||
error_count += if (!builtin.is_test)
|
||||
renderTypeProblems(allocs.gpa, &app_checker, &app_env, roc_file_path)
|
||||
else
|
||||
0;
|
||||
|
|
|
|||
|
|
@ -1018,7 +1018,7 @@ test "fx platform issue8433" {
|
|||
}
|
||||
}
|
||||
|
||||
test "run aborts on errors by default" {
|
||||
test "run aborts on type errors by default" {
|
||||
// Tests that roc run aborts when there are type errors (without --allow-errors)
|
||||
const allocator = testing.allocator;
|
||||
|
||||
|
|
@ -1039,7 +1039,28 @@ test "run aborts on errors by default" {
|
|||
try testing.expect(std.mem.indexOf(u8, run_result.stderr, "UNDEFINED VARIABLE") != null);
|
||||
}
|
||||
|
||||
test "run with --allow-errors attempts execution despite errors" {
|
||||
test "run aborts on parse errors by default" {
|
||||
// Tests that roc run aborts when there are parse errors (without --allow-errors)
|
||||
const allocator = testing.allocator;
|
||||
|
||||
const run_result = try std.process.Child.run(.{
|
||||
.allocator = allocator,
|
||||
.argv = &[_][]const u8{
|
||||
"./zig-out/bin/roc",
|
||||
"test/fx/parse_error.roc",
|
||||
},
|
||||
});
|
||||
defer allocator.free(run_result.stdout);
|
||||
defer allocator.free(run_result.stderr);
|
||||
|
||||
// Should fail with type errors
|
||||
try checkFailure(run_result);
|
||||
|
||||
// Should show the errors
|
||||
try testing.expect(std.mem.indexOf(u8, run_result.stderr, "PARSE ERROR") != null);
|
||||
}
|
||||
|
||||
test "run with --allow-errors attempts execution despite type errors" {
|
||||
// Tests that roc run --allow-errors attempts to execute even with type errors
|
||||
const allocator = testing.allocator;
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ test "integration - shared memory setup and parsing" {
|
|||
const roc_path = "test/int/app.roc";
|
||||
|
||||
// Test that we can set up shared memory with ModuleEnv
|
||||
const shm_result = try main.setupSharedMemoryWithModuleEnv(&allocs, roc_path);
|
||||
const shm_result = try main.setupSharedMemoryWithModuleEnv(&allocs, roc_path, true);
|
||||
const shm_handle = shm_result.handle;
|
||||
|
||||
// Clean up shared memory resources
|
||||
|
|
@ -170,7 +170,7 @@ test "integration - compilation pipeline for different platforms" {
|
|||
|
||||
for (test_apps) |roc_path| {
|
||||
// Test the full compilation pipeline (parse -> canonicalize -> typecheck)
|
||||
const shm_result = main.setupSharedMemoryWithModuleEnv(&allocs, roc_path) catch |err| {
|
||||
const shm_result = main.setupSharedMemoryWithModuleEnv(&allocs, roc_path, true) catch |err| {
|
||||
std.log.warn("Failed to set up shared memory for {s}: {}\n", .{ roc_path, err });
|
||||
continue;
|
||||
};
|
||||
|
|
@ -212,7 +212,7 @@ test "integration - error handling for non-existent file" {
|
|||
const roc_path = "test/nonexistent/app.roc";
|
||||
|
||||
// This should fail because the file doesn't exist
|
||||
const result = main.setupSharedMemoryWithModuleEnv(&allocs, roc_path);
|
||||
const result = main.setupSharedMemoryWithModuleEnv(&allocs, roc_path, true);
|
||||
|
||||
// We expect this to fail - the important thing is that it doesn't crash
|
||||
if (result) |shm_result| {
|
||||
|
|
|
|||
8
test/fx/parse_error.roc
Normal file
8
test/fx/parse_error.roc
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
app [main!] {
|
||||
pf: platform "./platform/main.roc",
|
||||
}
|
||||
import pf.Stdout
|
||||
main! = |_args| {
|
||||
Stdout.line!("Hello world")
|
||||
Ok({})
|
||||
}}
|
||||
Loading…
Add table
Add a link
Reference in a new issue