| ... | ... | @@ -406,15 +406,11 @@ pub const ModuleIndex = enum(u32) { |
| 406 | 406 | }; |
| 407 | 407 | |
| 408 | 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 | 411 | const file_index: File.Index = @enumFromInt(files.entries.len); |
| 411 | 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 | 414 | var w: Walk = .{ |
| 419 | 415 | .file = file_index, |
| 420 | 416 | }; |
| ... | ... | @@ -434,20 +430,41 @@ pub fn add_file(file_name: []const u8, bytes: []u8) !File.Index { |
| 434 | 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 | 437 | // Require every source file to end with a newline so that Zig's tokenizer |
| 439 | 438 | // can continue to require null termination and Autodoc implementation can |
| 440 | 439 | // avoid copying source bytes from the decompressed tar file buffer. |
| 441 | 440 | const adjusted_source: [:0]const u8 = s: { |
| 442 | 441 | if (source.len == 0) |
| 443 | 442 | break :s ""; |
| 444 | | |
| 445 | | assert(source[source.len - 1] == '\n'); |
| 443 | if (source[source.len - 1] != '\n') { |
| 444 | log.err("{s}: expected newline at end of file", .{file_name}); |
| 445 | break :s ""; |
| 446 | } |
| 446 | 447 | source[source.len - 1] = 0; |
| 447 | 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 | 470 | pub const Scope = struct { |