| ... | @@ -406,15 +406,11 @@ pub const ModuleIndex = enum(u32) { | ... | @@ -406,15 +406,11 @@ pub const ModuleIndex = enum(u32) { |
| 406 | }; | 406 | }; |
| 407 | | 407 | |
| 408 | pub fn add_file(file_name: []const u8, bytes: []u8) !File.Index { | 408 | pub fn add_file(file_name: []const u8, bytes: []u8) !File.Index { |
| 409 | const ast = try parse(bytes); | 409 | const ast = try parse(file_name, bytes); |
| | 410 | assert(ast.errors.len == 0); |
| 410 | const file_index: File.Index = @enumFromInt(files.entries.len); | 411 | const file_index: File.Index = @enumFromInt(files.entries.len); |
| 411 | try files.put(gpa, file_name, .{ .ast = ast }); | 412 | try files.put(gpa, file_name, .{ .ast = ast }); |
| 412 | | 413 | |
| 413 | if (ast.errors.len > 0) { | | |
| 414 | log.err("can't index '{s}' because it has syntax errors", .{file_index.path()}); | | |
| 415 | return file_index; | | |
| 416 | } | | |
| 417 | | | |
| 418 | var w: Walk = .{ | 414 | var w: Walk = .{ |
| 419 | .file = file_index, | 415 | .file = file_index, |
| 420 | }; | 416 | }; |
| ... | @@ -434,20 +430,41 @@ pub fn add_file(file_name: []const u8, bytes: []u8) !File.Index { | ... | @@ -434,20 +430,41 @@ pub fn add_file(file_name: []const u8, bytes: []u8) !File.Index { |
| 434 | return file_index; | 430 | return file_index; |
| 435 | } | 431 | } |
| 436 | | 432 | |
| 437 | fn parse(source: []u8) Oom!Ast { | 433 | /// Parses a file and returns its `Ast`. If the file cannot be parsed, returns |
| | 434 | /// the `Ast` of an empty file, so that the rest of the Autodoc logic does not |
| | 435 | /// need to handle parse errors. |
| | 436 | fn parse(file_name: []const u8, source: []u8) Oom!Ast { |
| 438 | // Require every source file to end with a newline so that Zig's tokenizer | 437 | // Require every source file to end with a newline so that Zig's tokenizer |
| 439 | // can continue to require null termination and Autodoc implementation can | 438 | // can continue to require null termination and Autodoc implementation can |
| 440 | // avoid copying source bytes from the decompressed tar file buffer. | 439 | // avoid copying source bytes from the decompressed tar file buffer. |
| 441 | const adjusted_source: [:0]const u8 = s: { | 440 | const adjusted_source: [:0]const u8 = s: { |
| 442 | if (source.len == 0) | 441 | if (source.len == 0) |
| 443 | break :s ""; | 442 | break :s ""; |
| 444 | | 443 | if (source[source.len - 1] != '\n') { |
| 445 | assert(source[source.len - 1] == '\n'); | 444 | log.err("{s}: expected newline at end of file", .{file_name}); |
| | 445 | break :s ""; |
| | 446 | } |
| 446 | source[source.len - 1] = 0; | 447 | source[source.len - 1] = 0; |
| 447 | break :s source[0 .. source.len - 1 :0]; | 448 | break :s source[0 .. source.len - 1 :0]; |
| 448 | }; | 449 | }; |
| 449 | | 450 | |
| 450 | return Ast.parse(gpa, adjusted_source, .zig); | 451 | var ast = try Ast.parse(gpa, adjusted_source, .zig); |
| | 452 | if (ast.errors.len > 0) { |
| | 453 | defer ast.deinit(gpa); |
| | 454 | |
| | 455 | const token_offsets = ast.tokens.items(.start); |
| | 456 | var rendered_err: std.ArrayListUnmanaged(u8) = .{}; |
| | 457 | defer rendered_err.deinit(gpa); |
| | 458 | for (ast.errors) |err| { |
| | 459 | const err_offset = token_offsets[err.token] + ast.errorOffset(err); |
| | 460 | const err_loc = std.zig.findLineColumn(ast.source, err_offset); |
| | 461 | rendered_err.clearRetainingCapacity(); |
| | 462 | try ast.renderError(err, rendered_err.writer(gpa)); |
| | 463 | log.err("{s}:{}:{}: {s}", .{ file_name, err_loc.line + 1, err_loc.column + 1, rendered_err.items }); |
| | 464 | } |
| | 465 | return Ast.parse(gpa, "", .zig); |
| | 466 | } |
| | 467 | return ast; |
| 451 | } | 468 | } |
| 452 | | 469 | |
| 453 | pub const Scope = struct { | 470 | pub const Scope = struct { |