| ... | @@ -4,6 +4,16 @@ | ... | @@ -4,6 +4,16 @@ |
| 4 | //! For Zon syntax, the root node is at nodes[0] and contains lhs as the node | 4 | //! For Zon syntax, the root node is at nodes[0] and contains lhs as the node |
| 5 | //! index of the main expression. | 5 | //! index of the main expression. |
| 6 | | 6 | |
| | 7 | const std = @import("../std.zig"); |
| | 8 | const assert = std.debug.assert; |
| | 9 | const testing = std.testing; |
| | 10 | const mem = std.mem; |
| | 11 | const Token = std.zig.Token; |
| | 12 | const Ast = @This(); |
| | 13 | const Allocator = std.mem.Allocator; |
| | 14 | const Parse = @import("Parse.zig"); |
| | 15 | const Writer = std.Io.Writer; |
| | 16 | |
| 7 | /// Reference to externally-owned data. | 17 | /// Reference to externally-owned data. |
| 8 | source: [:0]const u8, | 18 | source: [:0]const u8, |
| 9 | | 19 | |
| ... | @@ -128,12 +138,6 @@ pub fn deinit(tree: *Ast, gpa: Allocator) void { | ... | @@ -128,12 +138,6 @@ pub fn deinit(tree: *Ast, gpa: Allocator) void { |
| 128 | tree.* = undefined; | 138 | tree.* = undefined; |
| 129 | } | 139 | } |
| 130 | | 140 | |
| 131 | pub const RenderError = error{ | | |
| 132 | /// Ran out of memory allocating call stack frames to complete rendering, or | | |
| 133 | /// ran out of memory allocating space in the output buffer. | | |
| 134 | OutOfMemory, | | |
| 135 | }; | | |
| 136 | | | |
| 137 | pub const Mode = enum { zig, zon }; | 141 | pub const Mode = enum { zig, zon }; |
| 138 | | 142 | |
| 139 | /// Result should be freed with tree.deinit() when there are | 143 | /// Result should be freed with tree.deinit() when there are |
| ... | @@ -199,27 +203,25 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A | ... | @@ -199,27 +203,25 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A |
| 199 | | 203 | |
| 200 | /// `gpa` is used for allocating the resulting formatted source code. | 204 | /// `gpa` is used for allocating the resulting formatted source code. |
| 201 | /// Caller owns the returned slice of bytes, allocated with `gpa`. | 205 | /// Caller owns the returned slice of bytes, allocated with `gpa`. |
| 202 | pub fn render(tree: Ast, gpa: Allocator) RenderError![]u8 { | 206 | pub fn renderAlloc(tree: Ast, gpa: Allocator) error{OutOfMemory}![]u8 { |
| 203 | var buffer = std.ArrayList(u8).init(gpa); | 207 | var aw: std.io.Writer.Allocating = .init(gpa); |
| 204 | defer buffer.deinit(); | 208 | defer aw.deinit(); |
| 205 | | 209 | render(tree, gpa, &aw.writer, .{}) catch |err| switch (err) { |
| 206 | try tree.renderToArrayList(&buffer, .{}); | 210 | error.WriteFailed => return error.OutOfMemory, |
| 207 | return buffer.toOwnedSlice(); | 211 | }; |
| | 212 | return aw.toOwnedSlice(); |
| 208 | } | 213 | } |
| 209 | | 214 | |
| 210 | pub const Fixups = private_render.Fixups; | 215 | pub const Render = @import("Ast/Render.zig"); |
| 211 | | 216 | |
| 212 | pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8), fixups: Fixups) RenderError!void { | 217 | pub fn render(tree: Ast, gpa: Allocator, w: *Writer, fixups: Render.Fixups) Render.Error!void { |
| 213 | return @import("./render.zig").renderTree(buffer, tree, fixups); | 218 | return Render.tree(gpa, w, tree, fixups); |
| 214 | } | 219 | } |
| 215 | | 220 | |
| 216 | /// Returns an extra offset for column and byte offset of errors that | 221 | /// Returns an extra offset for column and byte offset of errors that |
| 217 | /// should point after the token in the error message. | 222 | /// should point after the token in the error message. |
| 218 | pub fn errorOffset(tree: Ast, parse_error: Error) u32 { | 223 | pub fn errorOffset(tree: Ast, parse_error: Error) u32 { |
| 219 | return if (parse_error.token_is_prev) | 224 | return if (parse_error.token_is_prev) @intCast(tree.tokenSlice(parse_error.token).len) else 0; |
| 220 | @as(u32, @intCast(tree.tokenSlice(parse_error.token).len)) | | |
| 221 | else | | |
| 222 | 0; | | |
| 223 | } | 225 | } |
| 224 | | 226 | |
| 225 | pub fn tokenLocation(self: Ast, start_offset: ByteOffset, token_index: TokenIndex) Location { | 227 | pub fn tokenLocation(self: Ast, start_offset: ByteOffset, token_index: TokenIndex) Location { |
| ... | @@ -318,254 +320,254 @@ pub fn rootDecls(tree: Ast) []const Node.Index { | ... | @@ -318,254 +320,254 @@ pub fn rootDecls(tree: Ast) []const Node.Index { |
| 318 | } | 320 | } |
| 319 | } | 321 | } |
| 320 | | 322 | |
| 321 | pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { | 323 | pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void { |
| 322 | switch (parse_error.tag) { | 324 | switch (parse_error.tag) { |
| 323 | .asterisk_after_ptr_deref => { | 325 | .asterisk_after_ptr_deref => { |
| 324 | // Note that the token will point at the `.*` but ideally the source | 326 | // Note that the token will point at the `.*` but ideally the source |
| 325 | // location would point to the `*` after the `.*`. | 327 | // location would point to the `*` after the `.*`. |
| 326 | return stream.writeAll("'.*' cannot be followed by '*'; are you missing a space?"); | 328 | return w.writeAll("'.*' cannot be followed by '*'; are you missing a space?"); |
| 327 | }, | 329 | }, |
| 328 | .chained_comparison_operators => { | 330 | .chained_comparison_operators => { |
| 329 | return stream.writeAll("comparison operators cannot be chained"); | 331 | return w.writeAll("comparison operators cannot be chained"); |
| 330 | }, | 332 | }, |
| 331 | .decl_between_fields => { | 333 | .decl_between_fields => { |
| 332 | return stream.writeAll("declarations are not allowed between container fields"); | 334 | return w.writeAll("declarations are not allowed between container fields"); |
| 333 | }, | 335 | }, |
| 334 | .expected_block => { | 336 | .expected_block => { |
| 335 | return stream.print("expected block, found '{s}'", .{ | 337 | return w.print("expected block, found '{s}'", .{ |
| 336 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 338 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 337 | }); | 339 | }); |
| 338 | }, | 340 | }, |
| 339 | .expected_block_or_assignment => { | 341 | .expected_block_or_assignment => { |
| 340 | return stream.print("expected block or assignment, found '{s}'", .{ | 342 | return w.print("expected block or assignment, found '{s}'", .{ |
| 341 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 343 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 342 | }); | 344 | }); |
| 343 | }, | 345 | }, |
| 344 | .expected_block_or_expr => { | 346 | .expected_block_or_expr => { |
| 345 | return stream.print("expected block or expression, found '{s}'", .{ | 347 | return w.print("expected block or expression, found '{s}'", .{ |
| 346 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 348 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 347 | }); | 349 | }); |
| 348 | }, | 350 | }, |
| 349 | .expected_block_or_field => { | 351 | .expected_block_or_field => { |
| 350 | return stream.print("expected block or field, found '{s}'", .{ | 352 | return w.print("expected block or field, found '{s}'", .{ |
| 351 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 353 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 352 | }); | 354 | }); |
| 353 | }, | 355 | }, |
| 354 | .expected_container_members => { | 356 | .expected_container_members => { |
| 355 | return stream.print("expected test, comptime, var decl, or container field, found '{s}'", .{ | 357 | return w.print("expected test, comptime, var decl, or container field, found '{s}'", .{ |
| 356 | tree.tokenTag(parse_error.token).symbol(), | 358 | tree.tokenTag(parse_error.token).symbol(), |
| 357 | }); | 359 | }); |
| 358 | }, | 360 | }, |
| 359 | .expected_expr => { | 361 | .expected_expr => { |
| 360 | return stream.print("expected expression, found '{s}'", .{ | 362 | return w.print("expected expression, found '{s}'", .{ |
| 361 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 363 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 362 | }); | 364 | }); |
| 363 | }, | 365 | }, |
| 364 | .expected_expr_or_assignment => { | 366 | .expected_expr_or_assignment => { |
| 365 | return stream.print("expected expression or assignment, found '{s}'", .{ | 367 | return w.print("expected expression or assignment, found '{s}'", .{ |
| 366 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 368 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 367 | }); | 369 | }); |
| 368 | }, | 370 | }, |
| 369 | .expected_expr_or_var_decl => { | 371 | .expected_expr_or_var_decl => { |
| 370 | return stream.print("expected expression or var decl, found '{s}'", .{ | 372 | return w.print("expected expression or var decl, found '{s}'", .{ |
| 371 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 373 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 372 | }); | 374 | }); |
| 373 | }, | 375 | }, |
| 374 | .expected_fn => { | 376 | .expected_fn => { |
| 375 | return stream.print("expected function, found '{s}'", .{ | 377 | return w.print("expected function, found '{s}'", .{ |
| 376 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 378 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 377 | }); | 379 | }); |
| 378 | }, | 380 | }, |
| 379 | .expected_inlinable => { | 381 | .expected_inlinable => { |
| 380 | return stream.print("expected 'while' or 'for', found '{s}'", .{ | 382 | return w.print("expected 'while' or 'for', found '{s}'", .{ |
| 381 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 383 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 382 | }); | 384 | }); |
| 383 | }, | 385 | }, |
| 384 | .expected_labelable => { | 386 | .expected_labelable => { |
| 385 | return stream.print("expected 'while', 'for', 'inline', or '{{', found '{s}'", .{ | 387 | return w.print("expected 'while', 'for', 'inline', or '{{', found '{s}'", .{ |
| 386 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 388 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 387 | }); | 389 | }); |
| 388 | }, | 390 | }, |
| 389 | .expected_param_list => { | 391 | .expected_param_list => { |
| 390 | return stream.print("expected parameter list, found '{s}'", .{ | 392 | return w.print("expected parameter list, found '{s}'", .{ |
| 391 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 393 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 392 | }); | 394 | }); |
| 393 | }, | 395 | }, |
| 394 | .expected_prefix_expr => { | 396 | .expected_prefix_expr => { |
| 395 | return stream.print("expected prefix expression, found '{s}'", .{ | 397 | return w.print("expected prefix expression, found '{s}'", .{ |
| 396 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 398 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 397 | }); | 399 | }); |
| 398 | }, | 400 | }, |
| 399 | .expected_primary_type_expr => { | 401 | .expected_primary_type_expr => { |
| 400 | return stream.print("expected primary type expression, found '{s}'", .{ | 402 | return w.print("expected primary type expression, found '{s}'", .{ |
| 401 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 403 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 402 | }); | 404 | }); |
| 403 | }, | 405 | }, |
| 404 | .expected_pub_item => { | 406 | .expected_pub_item => { |
| 405 | return stream.writeAll("expected function or variable declaration after pub"); | 407 | return w.writeAll("expected function or variable declaration after pub"); |
| 406 | }, | 408 | }, |
| 407 | .expected_return_type => { | 409 | .expected_return_type => { |
| 408 | return stream.print("expected return type expression, found '{s}'", .{ | 410 | return w.print("expected return type expression, found '{s}'", .{ |
| 409 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 411 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 410 | }); | 412 | }); |
| 411 | }, | 413 | }, |
| 412 | .expected_semi_or_else => { | 414 | .expected_semi_or_else => { |
| 413 | return stream.writeAll("expected ';' or 'else' after statement"); | 415 | return w.writeAll("expected ';' or 'else' after statement"); |
| 414 | }, | 416 | }, |
| 415 | .expected_semi_or_lbrace => { | 417 | .expected_semi_or_lbrace => { |
| 416 | return stream.writeAll("expected ';' or block after function prototype"); | 418 | return w.writeAll("expected ';' or block after function prototype"); |
| 417 | }, | 419 | }, |
| 418 | .expected_statement => { | 420 | .expected_statement => { |
| 419 | return stream.print("expected statement, found '{s}'", .{ | 421 | return w.print("expected statement, found '{s}'", .{ |
| 420 | tree.tokenTag(parse_error.token).symbol(), | 422 | tree.tokenTag(parse_error.token).symbol(), |
| 421 | }); | 423 | }); |
| 422 | }, | 424 | }, |
| 423 | .expected_suffix_op => { | 425 | .expected_suffix_op => { |
| 424 | return stream.print("expected pointer dereference, optional unwrap, or field access, found '{s}'", .{ | 426 | return w.print("expected pointer dereference, optional unwrap, or field access, found '{s}'", .{ |
| 425 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 427 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 426 | }); | 428 | }); |
| 427 | }, | 429 | }, |
| 428 | .expected_type_expr => { | 430 | .expected_type_expr => { |
| 429 | return stream.print("expected type expression, found '{s}'", .{ | 431 | return w.print("expected type expression, found '{s}'", .{ |
| 430 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 432 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 431 | }); | 433 | }); |
| 432 | }, | 434 | }, |
| 433 | .expected_var_decl => { | 435 | .expected_var_decl => { |
| 434 | return stream.print("expected variable declaration, found '{s}'", .{ | 436 | return w.print("expected variable declaration, found '{s}'", .{ |
| 435 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 437 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 436 | }); | 438 | }); |
| 437 | }, | 439 | }, |
| 438 | .expected_var_decl_or_fn => { | 440 | .expected_var_decl_or_fn => { |
| 439 | return stream.print("expected variable declaration or function, found '{s}'", .{ | 441 | return w.print("expected variable declaration or function, found '{s}'", .{ |
| 440 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 442 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 441 | }); | 443 | }); |
| 442 | }, | 444 | }, |
| 443 | .expected_loop_payload => { | 445 | .expected_loop_payload => { |
| 444 | return stream.print("expected loop payload, found '{s}'", .{ | 446 | return w.print("expected loop payload, found '{s}'", .{ |
| 445 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 447 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 446 | }); | 448 | }); |
| 447 | }, | 449 | }, |
| 448 | .expected_container => { | 450 | .expected_container => { |
| 449 | return stream.print("expected a struct, enum or union, found '{s}'", .{ | 451 | return w.print("expected a struct, enum or union, found '{s}'", .{ |
| 450 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), | 452 | tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)).symbol(), |
| 451 | }); | 453 | }); |
| 452 | }, | 454 | }, |
| 453 | .extern_fn_body => { | 455 | .extern_fn_body => { |
| 454 | return stream.writeAll("extern functions have no body"); | 456 | return w.writeAll("extern functions have no body"); |
| 455 | }, | 457 | }, |
| 456 | .extra_addrspace_qualifier => { | 458 | .extra_addrspace_qualifier => { |
| 457 | return stream.writeAll("extra addrspace qualifier"); | 459 | return w.writeAll("extra addrspace qualifier"); |
| 458 | }, | 460 | }, |
| 459 | .extra_align_qualifier => { | 461 | .extra_align_qualifier => { |
| 460 | return stream.writeAll("extra align qualifier"); | 462 | return w.writeAll("extra align qualifier"); |
| 461 | }, | 463 | }, |
| 462 | .extra_allowzero_qualifier => { | 464 | .extra_allowzero_qualifier => { |
| 463 | return stream.writeAll("extra allowzero qualifier"); | 465 | return w.writeAll("extra allowzero qualifier"); |
| 464 | }, | 466 | }, |
| 465 | .extra_const_qualifier => { | 467 | .extra_const_qualifier => { |
| 466 | return stream.writeAll("extra const qualifier"); | 468 | return w.writeAll("extra const qualifier"); |
| 467 | }, | 469 | }, |
| 468 | .extra_volatile_qualifier => { | 470 | .extra_volatile_qualifier => { |
| 469 | return stream.writeAll("extra volatile qualifier"); | 471 | return w.writeAll("extra volatile qualifier"); |
| 470 | }, | 472 | }, |
| 471 | .ptr_mod_on_array_child_type => { | 473 | .ptr_mod_on_array_child_type => { |
| 472 | return stream.print("pointer modifier '{s}' not allowed on array child type", .{ | 474 | return w.print("pointer modifier '{s}' not allowed on array child type", .{ |
| 473 | tree.tokenTag(parse_error.token).symbol(), | 475 | tree.tokenTag(parse_error.token).symbol(), |
| 474 | }); | 476 | }); |
| 475 | }, | 477 | }, |
| 476 | .invalid_bit_range => { | 478 | .invalid_bit_range => { |
| 477 | return stream.writeAll("bit range not allowed on slices and arrays"); | 479 | return w.writeAll("bit range not allowed on slices and arrays"); |
| 478 | }, | 480 | }, |
| 479 | .same_line_doc_comment => { | 481 | .same_line_doc_comment => { |
| 480 | return stream.writeAll("same line documentation comment"); | 482 | return w.writeAll("same line documentation comment"); |
| 481 | }, | 483 | }, |
| 482 | .unattached_doc_comment => { | 484 | .unattached_doc_comment => { |
| 483 | return stream.writeAll("unattached documentation comment"); | 485 | return w.writeAll("unattached documentation comment"); |
| 484 | }, | 486 | }, |
| 485 | .test_doc_comment => { | 487 | .test_doc_comment => { |
| 486 | return stream.writeAll("documentation comments cannot be attached to tests"); | 488 | return w.writeAll("documentation comments cannot be attached to tests"); |
| 487 | }, | 489 | }, |
| 488 | .comptime_doc_comment => { | 490 | .comptime_doc_comment => { |
| 489 | return stream.writeAll("documentation comments cannot be attached to comptime blocks"); | 491 | return w.writeAll("documentation comments cannot be attached to comptime blocks"); |
| 490 | }, | 492 | }, |
| 491 | .varargs_nonfinal => { | 493 | .varargs_nonfinal => { |
| 492 | return stream.writeAll("function prototype has parameter after varargs"); | 494 | return w.writeAll("function prototype has parameter after varargs"); |
| 493 | }, | 495 | }, |
| 494 | .expected_continue_expr => { | 496 | .expected_continue_expr => { |
| 495 | return stream.writeAll("expected ':' before while continue expression"); | 497 | return w.writeAll("expected ':' before while continue expression"); |
| 496 | }, | 498 | }, |
| 497 | | 499 | |
| 498 | .expected_semi_after_decl => { | 500 | .expected_semi_after_decl => { |
| 499 | return stream.writeAll("expected ';' after declaration"); | 501 | return w.writeAll("expected ';' after declaration"); |
| 500 | }, | 502 | }, |
| 501 | .expected_semi_after_stmt => { | 503 | .expected_semi_after_stmt => { |
| 502 | return stream.writeAll("expected ';' after statement"); | 504 | return w.writeAll("expected ';' after statement"); |
| 503 | }, | 505 | }, |
| 504 | .expected_comma_after_field => { | 506 | .expected_comma_after_field => { |
| 505 | return stream.writeAll("expected ',' after field"); | 507 | return w.writeAll("expected ',' after field"); |
| 506 | }, | 508 | }, |
| 507 | .expected_comma_after_arg => { | 509 | .expected_comma_after_arg => { |
| 508 | return stream.writeAll("expected ',' after argument"); | 510 | return w.writeAll("expected ',' after argument"); |
| 509 | }, | 511 | }, |
| 510 | .expected_comma_after_param => { | 512 | .expected_comma_after_param => { |
| 511 | return stream.writeAll("expected ',' after parameter"); | 513 | return w.writeAll("expected ',' after parameter"); |
| 512 | }, | 514 | }, |
| 513 | .expected_comma_after_initializer => { | 515 | .expected_comma_after_initializer => { |
| 514 | return stream.writeAll("expected ',' after initializer"); | 516 | return w.writeAll("expected ',' after initializer"); |
| 515 | }, | 517 | }, |
| 516 | .expected_comma_after_switch_prong => { | 518 | .expected_comma_after_switch_prong => { |
| 517 | return stream.writeAll("expected ',' after switch prong"); | 519 | return w.writeAll("expected ',' after switch prong"); |
| 518 | }, | 520 | }, |
| 519 | .expected_comma_after_for_operand => { | 521 | .expected_comma_after_for_operand => { |
| 520 | return stream.writeAll("expected ',' after for operand"); | 522 | return w.writeAll("expected ',' after for operand"); |
| 521 | }, | 523 | }, |
| 522 | .expected_comma_after_capture => { | 524 | .expected_comma_after_capture => { |
| 523 | return stream.writeAll("expected ',' after for capture"); | 525 | return w.writeAll("expected ',' after for capture"); |
| 524 | }, | 526 | }, |
| 525 | .expected_initializer => { | 527 | .expected_initializer => { |
| 526 | return stream.writeAll("expected field initializer"); | 528 | return w.writeAll("expected field initializer"); |
| 527 | }, | 529 | }, |
| 528 | .mismatched_binary_op_whitespace => { | 530 | .mismatched_binary_op_whitespace => { |
| 529 | return stream.print("binary operator '{s}' has whitespace on one side, but not the other", .{tree.tokenTag(parse_error.token).lexeme().?}); | 531 | return w.print("binary operator '{s}' has whitespace on one side, but not the other", .{tree.tokenTag(parse_error.token).lexeme().?}); |
| 530 | }, | 532 | }, |
| 531 | .invalid_ampersand_ampersand => { | 533 | .invalid_ampersand_ampersand => { |
| 532 | return stream.writeAll("ambiguous use of '&&'; use 'and' for logical AND, or change whitespace to ' & &' for bitwise AND"); | 534 | return w.writeAll("ambiguous use of '&&'; use 'and' for logical AND, or change whitespace to ' & &' for bitwise AND"); |
| 533 | }, | 535 | }, |
| 534 | .c_style_container => { | 536 | .c_style_container => { |
| 535 | return stream.print("'{s} {s}' is invalid", .{ | 537 | return w.print("'{s} {s}' is invalid", .{ |
| 536 | parse_error.extra.expected_tag.symbol(), tree.tokenSlice(parse_error.token), | 538 | parse_error.extra.expected_tag.symbol(), tree.tokenSlice(parse_error.token), |
| 537 | }); | 539 | }); |
| 538 | }, | 540 | }, |
| 539 | .zig_style_container => { | 541 | .zig_style_container => { |
| 540 | return stream.print("to declare a container do 'const {s} = {s}'", .{ | 542 | return w.print("to declare a container do 'const {s} = {s}'", .{ |
| 541 | tree.tokenSlice(parse_error.token), parse_error.extra.expected_tag.symbol(), | 543 | tree.tokenSlice(parse_error.token), parse_error.extra.expected_tag.symbol(), |
| 542 | }); | 544 | }); |
| 543 | }, | 545 | }, |
| 544 | .previous_field => { | 546 | .previous_field => { |
| 545 | return stream.writeAll("field before declarations here"); | 547 | return w.writeAll("field before declarations here"); |
| 546 | }, | 548 | }, |
| 547 | .next_field => { | 549 | .next_field => { |
| 548 | return stream.writeAll("field after declarations here"); | 550 | return w.writeAll("field after declarations here"); |
| 549 | }, | 551 | }, |
| 550 | .expected_var_const => { | 552 | .expected_var_const => { |
| 551 | return stream.writeAll("expected 'var' or 'const' before variable declaration"); | 553 | return w.writeAll("expected 'var' or 'const' before variable declaration"); |
| 552 | }, | 554 | }, |
| 553 | .wrong_equal_var_decl => { | 555 | .wrong_equal_var_decl => { |
| 554 | return stream.writeAll("variable initialized with '==' instead of '='"); | 556 | return w.writeAll("variable initialized with '==' instead of '='"); |
| 555 | }, | 557 | }, |
| 556 | .var_const_decl => { | 558 | .var_const_decl => { |
| 557 | return stream.writeAll("use 'var' or 'const' to declare variable"); | 559 | return w.writeAll("use 'var' or 'const' to declare variable"); |
| 558 | }, | 560 | }, |
| 559 | .extra_for_capture => { | 561 | .extra_for_capture => { |
| 560 | return stream.writeAll("extra capture in for loop"); | 562 | return w.writeAll("extra capture in for loop"); |
| 561 | }, | 563 | }, |
| 562 | .for_input_not_captured => { | 564 | .for_input_not_captured => { |
| 563 | return stream.writeAll("for input is not captured"); | 565 | return w.writeAll("for input is not captured"); |
| 564 | }, | 566 | }, |
| 565 | | 567 | |
| 566 | .invalid_byte => { | 568 | .invalid_byte => { |
| 567 | const tok_slice = tree.source[tree.tokens.items(.start)[parse_error.token]..]; | 569 | const tok_slice = tree.source[tree.tokens.items(.start)[parse_error.token]..]; |
| 568 | return stream.print("{s} contains invalid byte: '{f}'", .{ | 570 | return w.print("{s} contains invalid byte: '{f}'", .{ |
| 569 | switch (tok_slice[0]) { | 571 | switch (tok_slice[0]) { |
| 570 | '\'' => "character literal", | 572 | '\'' => "character literal", |
| 571 | '"', '\\' => "string literal", | 573 | '"', '\\' => "string literal", |
| ... | @@ -580,10 +582,10 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { | ... | @@ -580,10 +582,10 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { |
| 580 | const found_tag = tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)); | 582 | const found_tag = tree.tokenTag(parse_error.token + @intFromBool(parse_error.token_is_prev)); |
| 581 | const expected_symbol = parse_error.extra.expected_tag.symbol(); | 583 | const expected_symbol = parse_error.extra.expected_tag.symbol(); |
| 582 | switch (found_tag) { | 584 | switch (found_tag) { |
| 583 | .invalid => return stream.print("expected '{s}', found invalid bytes", .{ | 585 | .invalid => return w.print("expected '{s}', found invalid bytes", .{ |
| 584 | expected_symbol, | 586 | expected_symbol, |
| 585 | }), | 587 | }), |
| 586 | else => return stream.print("expected '{s}', found '{s}'", .{ | 588 | else => return w.print("expected '{s}', found '{s}'", .{ |
| 587 | expected_symbol, found_tag.symbol(), | 589 | expected_symbol, found_tag.symbol(), |
| 588 | }), | 590 | }), |
| 589 | } | 591 | } |
| ... | @@ -4136,17 +4138,7 @@ pub fn tokensToSpan(tree: *const Ast, start: Ast.TokenIndex, end: Ast.TokenIndex | ... | @@ -4136,17 +4138,7 @@ pub fn tokensToSpan(tree: *const Ast, start: Ast.TokenIndex, end: Ast.TokenIndex |
| 4136 | return Span{ .start = start_off, .end = end_off, .main = tree.tokenStart(main) }; | 4138 | return Span{ .start = start_off, .end = end_off, .main = tree.tokenStart(main) }; |
| 4137 | } | 4139 | } |
| 4138 | | 4140 | |
| 4139 | const std = @import("../std.zig"); | | |
| 4140 | const assert = std.debug.assert; | | |
| 4141 | const testing = std.testing; | | |
| 4142 | const mem = std.mem; | | |
| 4143 | const Token = std.zig.Token; | | |
| 4144 | const Ast = @This(); | | |
| 4145 | const Allocator = std.mem.Allocator; | | |
| 4146 | const Parse = @import("Parse.zig"); | | |
| 4147 | const private_render = @import("./render.zig"); | | |
| 4148 | | | |
| 4149 | test { | 4141 | test { |
| 4150 | _ = Parse; | 4142 | _ = Parse; |
| 4151 | _ = private_render; | 4143 | _ = Render; |
| 4152 | } | 4144 | } |