| ... | @@ -70,11 +70,21 @@ const Parser = struct { | ... | @@ -70,11 +70,21 @@ const Parser = struct { |
| 70 | arena: *Allocator, | 70 | arena: *Allocator, |
| 71 | it: *TokenIterator, | 71 | it: *TokenIterator, |
| 72 | tree: *Tree, | 72 | tree: *Tree, |
| 73 | typedefs: std.StringHashMap(void), | | |
| 74 | | 73 | |
| 75 | fn isTypedef(parser: *Parser, tok: TokenIndex) bool { | 74 | /// only used for scopes |
| 76 | const token = parser.it.list.at(tok); | 75 | arena_allocator: std.heap.ArenaAllocator, |
| 77 | return parser.typedefs.contains(token.slice()); | 76 | // scopes: std.SegmentedLists(Scope), |
| | 77 | warnings: bool = true, |
| | 78 | |
| | 79 | // const Scope = struct { |
| | 80 | // types: |
| | 81 | // syms: |
| | 82 | // }; |
| | 83 | |
| | 84 | fn getTypeDef(parser: *Parser, tok: TokenIndex) bool { |
| | 85 | return false; // TODO |
| | 86 | // const token = parser.it.list.at(tok); |
| | 87 | // return parser.typedefs.contains(token.slice()); |
| 78 | } | 88 | } |
| 79 | | 89 | |
| 80 | /// Root <- ExternalDeclaration* eof | 90 | /// Root <- ExternalDeclaration* eof |
| ... | @@ -84,7 +94,7 @@ const Parser = struct { | ... | @@ -84,7 +94,7 @@ const Parser = struct { |
| 84 | .decls = Node.Root.DeclList.init(parser.arena), | 94 | .decls = Node.Root.DeclList.init(parser.arena), |
| 85 | .eof = undefined, | 95 | .eof = undefined, |
| 86 | }; | 96 | }; |
| 87 | while (parser.externalDeclarations() catch |err| switch (err) { | 97 | while (parser.externalDeclarations() catch |e| switch (e) { |
| 88 | error.OutOfMemory => return error.OutOfMemory, | 98 | error.OutOfMemory => return error.OutOfMemory, |
| 89 | error.ParseError => return node, | 99 | error.ParseError => return node, |
| 90 | }) |decl| { | 100 | }) |decl| { |
| ... | @@ -95,70 +105,99 @@ const Parser = struct { | ... | @@ -95,70 +105,99 @@ const Parser = struct { |
| 95 | } | 105 | } |
| 96 | | 106 | |
| 97 | /// ExternalDeclaration | 107 | /// ExternalDeclaration |
| 98 | /// <- DeclSpec Declarator Declaration* CompoundStmt | 108 | /// <- DeclSpec Declarator OldStyleDecl* CompoundStmt |
| 99 | /// / Declaration | 109 | /// / Declaration |
| | 110 | /// OldStyleDecl <- DeclSpec Declarator (COMMA Declarator)* SEMICOLON |
| 100 | fn externalDeclarations(parser: *Parser) !?*Node { | 111 | fn externalDeclarations(parser: *Parser) !?*Node { |
| | 112 | return parser.declarationExtra(false); |
| | 113 | } |
| | 114 | |
| | 115 | /// Declaration |
| | 116 | /// <- DeclSpec DeclInit SEMICOLON |
| | 117 | /// / StaticAssert |
| | 118 | /// DeclInit <- Declarator (EQUAL Initializer)? (COMMA Declarator (EQUAL Initializer)?)* |
| | 119 | fn declaration(parser: *Parser) !?*Node { |
| | 120 | return parser.declarationExtra(true); |
| | 121 | } |
| | 122 | |
| | 123 | fn declarationExtra(parser: *Parser, local: bool) !?*Node { |
| 101 | if (try parser.staticAssert()) |decl| return decl; | 124 | if (try parser.staticAssert()) |decl| return decl; |
| 102 | const ds = try parser.declSpec(); | 125 | var ds = Node.DeclSpec{}; |
| 103 | const dr = (try parser.declarator()); | 126 | const got_ds = try parser.declSpec(&ds); |
| 104 | if (dr == null) | 127 | if (local and !got_ds) { |
| 105 | try parser.warning(.{ | 128 | // not a declaration |
| 106 | .ExpectedDeclarator = .{ .token = parser.it.index }, | 129 | return null; |
| 107 | }); | 130 | } |
| | 131 | var dr = try parser.declarator(); |
| 108 | // TODO disallow auto and register | 132 | // TODO disallow auto and register |
| 109 | const next_tok = parser.it.peek().?; | 133 | const next_tok = parser.it.peek().?; |
| | 134 | if (next_tok.id == .Eof and !got_ds and dr == null) { |
| | 135 | return null; |
| | 136 | } |
| 110 | switch (next_tok.id) { | 137 | switch (next_tok.id) { |
| 111 | .Semicolon, | 138 | .Semicolon, |
| 112 | .Equal, | 139 | .Equal, |
| 113 | .Comma, | 140 | .Comma, |
| 114 | .Eof, | 141 | .Eof, |
| 115 | => return parser.declarationExtra(ds, dr, false), | 142 | => { |
| 116 | else => {}, | 143 | while (dr != null) { |
| 117 | } | 144 | if (parser.eatToken(.Equal)) |tok| { |
| 118 | var old_decls = Node.FnDef.OldDeclList.init(parser.arena); | 145 | // TODO typedef |
| 119 | while (try parser.declaration()) |decl| { | 146 | // dr.?.init = try parser.expect(initializer, .{ |
| 120 | // validate declaration | 147 | // .ExpectedInitializer = .{ .token = parser.it.index }, |
| 121 | try old_decls.push(decl); | 148 | // }); |
| 122 | } | 149 | } |
| 123 | const body = try parser.expect(compoundStmt, .{ | 150 | if (parser.eatToken(.Comma) != null) break; |
| 124 | .ExpectedFnBody = .{ .token = parser.it.index }, | 151 | dr = (try parser.declarator()) orelse return parser.err(.{ |
| 125 | }); | 152 | .ExpectedDeclarator = .{ .token = parser.it.index }, |
| 126 | | 153 | }); |
| 127 | const node = try parser.arena.create(Node.FnDef); | 154 | // .push(dr); |
| 128 | node.* = .{ | 155 | } |
| 129 | .decl_spec = ds, | 156 | const semicolon = try parser.expectToken(.Semicolon); |
| 130 | .declarator = dr orelse return null, | | |
| 131 | .old_decls = old_decls, | | |
| 132 | .body = @fieldParentPtr(Node.CompoundStmt, "base", body), | | |
| 133 | }; | | |
| 134 | return &node.base; | | |
| 135 | } | | |
| 136 | | 157 | |
| 137 | /// Declaration | 158 | // TODO VarDecl, TypeDecl, TypeDef |
| 138 | /// <- DeclSpec (Declarator (EQUAL Initializer)? COMMA)* SEMICOLON | 159 | return null; |
| 139 | /// / StaticAssert | 160 | }, |
| 140 | fn declaration(parser: *Parser) !?*Node { | 161 | else => { |
| 141 | if (try parser.staticAssert()) |decl| return decl; | 162 | if (dr == null) |
| 142 | const ds = try parser.declSpec(); | 163 | return parser.err(.{ |
| 143 | const dr = (try parser.declarator()); | 164 | .ExpectedDeclarator = .{ .token = parser.it.index }, |
| 144 | if (dr == null) | 165 | }); |
| 145 | try parser.warning(.{ | 166 | var old_decls = Node.FnDef.OldDeclList.init(parser.arena); |
| 146 | .ExpectedDeclarator = .{ .token = parser.it.index }, | 167 | while (true) { |
| 147 | }); | 168 | var old_ds = Node.DeclSpec{}; |
| 148 | // TODO disallow threadlocal without static or extern | 169 | if (!(try parser.declSpec(&old_ds))) { |
| 149 | return parser.declarationExtra(ds, dr, true); | 170 | // not old decl |
| 150 | } | 171 | break; |
| | 172 | } |
| | 173 | var old_dr = (try parser.declarator()); |
| | 174 | // if (old_dr == null) |
| | 175 | // try parser.err(.{ |
| | 176 | // .NoParamName = .{ .token = parser.it.index }, |
| | 177 | // }); |
| | 178 | // try old_decls.push(decl); |
| | 179 | } |
| | 180 | const body = (try parser.compoundStmt()) orelse return parser.err(.{ |
| | 181 | .ExpectedFnBody = .{ .token = parser.it.index }, |
| | 182 | }); |
| 151 | | 183 | |
| 152 | fn declarationExtra(parser: *Parser, ds: *Node.DeclSpec, dr: ?*Node, local: bool) !?*Node { | 184 | const node = try parser.arena.create(Node.FnDef); |
| | 185 | node.* = .{ |
| | 186 | .decl_spec = ds, |
| | 187 | .declarator = dr orelse return null, |
| | 188 | .old_decls = old_decls, |
| | 189 | .body = @fieldParentPtr(Node.CompoundStmt, "base", body), |
| | 190 | }; |
| | 191 | return &node.base; |
| | 192 | }, |
| | 193 | } |
| 153 | } | 194 | } |
| 154 | | 195 | |
| 155 | /// StaticAssert <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON | 196 | /// StaticAssert <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON |
| 156 | fn staticAssert(parser: *Parser) !?*Node { | 197 | fn staticAssert(parser: *Parser) !?*Node { |
| 157 | const tok = parser.eatToken(.Keyword_static_assert) orelse return null; | 198 | const tok = parser.eatToken(.Keyword_static_assert) orelse return null; |
| 158 | _ = try parser.expectToken(.LParen); | 199 | _ = try parser.expectToken(.LParen); |
| 159 | const const_expr = try parser.expect(constExpr, .{ | 200 | const const_expr = try parser.constExpr(); |
| 160 | .ExpectedExpr = .{ .token = parser.it.index }, | | |
| 161 | }); | | |
| 162 | _ = try parser.expectToken(.Comma); | 201 | _ = try parser.expectToken(.Comma); |
| 163 | const str = try parser.expectToken(.StringLiteral); | 202 | const str = try parser.expectToken(.StringLiteral); |
| 164 | _ = try parser.expectToken(.RParen); | 203 | _ = try parser.expectToken(.RParen); |
| ... | @@ -173,11 +212,13 @@ const Parser = struct { | ... | @@ -173,11 +212,13 @@ const Parser = struct { |
| 173 | } | 212 | } |
| 174 | | 213 | |
| 175 | /// DeclSpec <- (StorageClassSpec / TypeSpec / FnSpec / AlignSpec)* | 214 | /// DeclSpec <- (StorageClassSpec / TypeSpec / FnSpec / AlignSpec)* |
| 176 | fn declSpec(parser: *Parser) !*Node.DeclSpec { | 215 | /// returns true if any tokens were consumed |
| 177 | const ds = try parser.arena.create(Node.DeclSpec); | 216 | fn declSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { |
| 178 | ds.* = .{}; | 217 | var got = false; |
| 179 | while ((try parser.storageClassSpec(ds)) or (try parser.typeSpec(&ds.type_spec)) or (try parser.fnSpec(ds)) or (try parser.alignSpec(ds))) {} | 218 | while ((try parser.storageClassSpec(ds)) or (try parser.typeSpec(&ds.type_spec)) or (try parser.fnSpec(ds)) or (try parser.alignSpec(ds))) { |
| 180 | return ds; | 219 | got = true; |
| | 220 | } |
| | 221 | return got; |
| 181 | } | 222 | } |
| 182 | | 223 | |
| 183 | /// StorageClassSpec | 224 | /// StorageClassSpec |
| ... | @@ -213,7 +254,7 @@ const Parser = struct { | ... | @@ -213,7 +254,7 @@ const Parser = struct { |
| 213 | } else return false; | 254 | } else return false; |
| 214 | return true; | 255 | return true; |
| 215 | } | 256 | } |
| 216 | try parser.warning(.{ | 257 | try parser.warn(.{ |
| 217 | .DuplicateSpecifier = .{ .token = parser.it.index }, | 258 | .DuplicateSpecifier = .{ .token = parser.it.index }, |
| 218 | }); | 259 | }); |
| 219 | return true; | 260 | return true; |
| ... | @@ -420,7 +461,7 @@ const Parser = struct { | ... | @@ -420,7 +461,7 @@ const Parser = struct { |
| 420 | if (type_spec.spec != .None) | 461 | if (type_spec.spec != .None) |
| 421 | break :blk; | 462 | break :blk; |
| 422 | _ = try parser.expectToken(.LParen); | 463 | _ = try parser.expectToken(.LParen); |
| 423 | const name = try parser.expect(typeName, .{ | 464 | const name = (try parser.typeName()) orelse return parser.err(.{ |
| 424 | .ExpectedTypeName = .{ .token = parser.it.index }, | 465 | .ExpectedTypeName = .{ .token = parser.it.index }, |
| 425 | }); | 466 | }); |
| 426 | type_spec.spec.Atomic = .{ | 467 | type_spec.spec.Atomic = .{ |
| ... | @@ -440,7 +481,7 @@ const Parser = struct { | ... | @@ -440,7 +481,7 @@ const Parser = struct { |
| 440 | @panic("TODO record type"); | 481 | @panic("TODO record type"); |
| 441 | // return true; | 482 | // return true; |
| 442 | } else if (parser.eatToken(.Identifier)) |tok| { | 483 | } else if (parser.eatToken(.Identifier)) |tok| { |
| 443 | if (!parser.isTypedef(tok)) { | 484 | if (!parser.getTypeDef(tok)) { |
| 444 | parser.putBackToken(tok); | 485 | parser.putBackToken(tok); |
| 445 | return false; | 486 | return false; |
| 446 | } | 487 | } |
| ... | @@ -450,13 +491,12 @@ const Parser = struct { | ... | @@ -450,13 +491,12 @@ const Parser = struct { |
| 450 | return true; | 491 | return true; |
| 451 | } | 492 | } |
| 452 | } | 493 | } |
| 453 | try parser.tree.errors.push(.{ | 494 | return parser.err(.{ |
| 454 | .InvalidTypeSpecifier = .{ | 495 | .InvalidTypeSpecifier = .{ |
| 455 | .token = parser.it.index, | 496 | .token = parser.it.index, |
| 456 | .type_spec = type_spec, | 497 | .type_spec = type_spec, |
| 457 | }, | 498 | }, |
| 458 | }); | 499 | }); |
| 459 | return error.ParseError; | | |
| 460 | } | 500 | } |
| 461 | | 501 | |
| 462 | /// TypeQual <- Keyword_const / Keyword_restrict / Keyword_volatile / Keyword_atomic | 502 | /// TypeQual <- Keyword_const / Keyword_restrict / Keyword_volatile / Keyword_atomic |
| ... | @@ -481,7 +521,7 @@ const Parser = struct { | ... | @@ -481,7 +521,7 @@ const Parser = struct { |
| 481 | } else return false; | 521 | } else return false; |
| 482 | return true; | 522 | return true; |
| 483 | } | 523 | } |
| 484 | try parser.warning(.{ | 524 | try parser.warn(.{ |
| 485 | .DuplicateQualifier = .{ .token = parser.it.index }, | 525 | .DuplicateQualifier = .{ .token = parser.it.index }, |
| 486 | }); | 526 | }); |
| 487 | return true; | 527 | return true; |
| ... | @@ -501,7 +541,7 @@ const Parser = struct { | ... | @@ -501,7 +541,7 @@ const Parser = struct { |
| 501 | } else return false; | 541 | } else return false; |
| 502 | return true; | 542 | return true; |
| 503 | } | 543 | } |
| 504 | try parser.warning(.{ | 544 | try parser.warn(.{ |
| 505 | .DuplicateSpecifier = .{ .token = parser.it.index }, | 545 | .DuplicateSpecifier = .{ .token = parser.it.index }, |
| 506 | }); | 546 | }); |
| 507 | return true; | 547 | return true; |
| ... | @@ -511,11 +551,9 @@ const Parser = struct { | ... | @@ -511,11 +551,9 @@ const Parser = struct { |
| 511 | fn alignSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { | 551 | fn alignSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { |
| 512 | if (parser.eatToken(.Keyword_alignas)) |tok| { | 552 | if (parser.eatToken(.Keyword_alignas)) |tok| { |
| 513 | _ = try parser.expectToken(.LParen); | 553 | _ = try parser.expectToken(.LParen); |
| 514 | const node = (try parser.typeName()) orelse (try parser.expect(constExpr, .{ | 554 | const node = (try parser.typeName()) orelse (try parser.constExpr()); |
| 515 | .ExpectedExpr = .{ .token = parser.it.index }, | | |
| 516 | })); | | |
| 517 | if (ds.align_spec != null) { | 555 | if (ds.align_spec != null) { |
| 518 | try parser.warning(.{ | 556 | try parser.warn(.{ |
| 519 | .DuplicateSpecifier = .{ .token = parser.it.index }, | 557 | .DuplicateSpecifier = .{ .token = parser.it.index }, |
| 520 | }); | 558 | }); |
| 521 | } | 559 | } |
| ... | @@ -594,7 +632,16 @@ const Parser = struct { | ... | @@ -594,7 +632,16 @@ const Parser = struct { |
| 594 | fn assignmentExpr(parser: *Parser) !*Node {} | 632 | fn assignmentExpr(parser: *Parser) !*Node {} |
| 595 | | 633 | |
| 596 | /// ConstExpr <- ConditionalExpr | 634 | /// ConstExpr <- ConditionalExpr |
| 597 | const constExpr = conditionalExpr; | 635 | fn constExpr(parser: *Parser) Error!*Node { |
| | 636 | const start = parser.it.index; |
| | 637 | const expression = try parser.conditionalExpr(); |
| | 638 | // TODO |
| | 639 | // if (expression == nullor expression.?.value == null) |
| | 640 | // return parser.err(.{ |
| | 641 | // .ConsExpr = start, |
| | 642 | // }); |
| | 643 | return expression.?; |
| | 644 | } |
| 598 | | 645 | |
| 599 | /// ConditionalExpr <- LogicalOrExpr (QUESTIONMARK Expr COLON ConditionalExpr)? | 646 | /// ConditionalExpr <- LogicalOrExpr (QUESTIONMARK Expr COLON ConditionalExpr)? |
| 600 | fn conditionalExpr(parser: *Parser) !*Node {} | 647 | fn conditionalExpr(parser: *Parser) !*Node {} |
| ... | @@ -671,7 +718,7 @@ const Parser = struct { | ... | @@ -671,7 +718,7 @@ const Parser = struct { |
| 671 | /// / PERIOD IDENTIFIER | 718 | /// / PERIOD IDENTIFIER |
| 672 | fn designator(parser: *Parser) !*Node {} | 719 | fn designator(parser: *Parser) !*Node {} |
| 673 | | 720 | |
| 674 | /// CompoundStmt <- LBRACE (Stmt / Declaration)* RBRACE | 721 | /// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE |
| 675 | fn compoundStmt(parser: *Parser) Error!?*Node { | 722 | fn compoundStmt(parser: *Parser) Error!?*Node { |
| 676 | const lbrace = parser.eatToken(.LBrace) orelse return null; | 723 | const lbrace = parser.eatToken(.LBrace) orelse return null; |
| 677 | const body_node = try parser.arena.create(Node.CompoundStmt); | 724 | const body_node = try parser.arena.create(Node.CompoundStmt); |
| ... | @@ -680,7 +727,7 @@ const Parser = struct { | ... | @@ -680,7 +727,7 @@ const Parser = struct { |
| 680 | .statements = Node.CompoundStmt.StmtList.init(parser.arena), | 727 | .statements = Node.CompoundStmt.StmtList.init(parser.arena), |
| 681 | .rbrace = undefined, | 728 | .rbrace = undefined, |
| 682 | }; | 729 | }; |
| 683 | while ((try parser.stmt()) orelse (try parser.declaration())) |node| | 730 | while ((try parser.declaration()) orelse (try parser.stmt())) |node| |
| 684 | try body_node.statements.push(node); | 731 | try body_node.statements.push(node); |
| 685 | body_node.rbrace = try parser.expectToken(.RBrace); | 732 | body_node.rbrace = try parser.expectToken(.RBrace); |
| 686 | return &body_node.base; | 733 | return &body_node.base; |
| ... | @@ -708,7 +755,7 @@ const Parser = struct { | ... | @@ -708,7 +755,7 @@ const Parser = struct { |
| 708 | _ = try parser.expectToken(.LParen); | 755 | _ = try parser.expectToken(.LParen); |
| 709 | node.* = .{ | 756 | node.* = .{ |
| 710 | .@"if" = tok, | 757 | .@"if" = tok, |
| 711 | .cond = try parser.expect(expr, .{ | 758 | .cond = (try parser.expr()) orelse return parser.err(.{ |
| 712 | .ExpectedExpr = .{ .token = parser.it.index }, | 759 | .ExpectedExpr = .{ .token = parser.it.index }, |
| 713 | }), | 760 | }), |
| 714 | .@"else" = null, | 761 | .@"else" = null, |
| ... | @@ -717,7 +764,7 @@ const Parser = struct { | ... | @@ -717,7 +764,7 @@ const Parser = struct { |
| 717 | if (parser.eatToken(.Keyword_else)) |else_tok| { | 764 | if (parser.eatToken(.Keyword_else)) |else_tok| { |
| 718 | node.@"else" = .{ | 765 | node.@"else" = .{ |
| 719 | .tok = else_tok, | 766 | .tok = else_tok, |
| 720 | .stmt = try parser.expect(stmt, .{ | 767 | .stmt = (try parser.stmt()) orelse return parser.err(.{ |
| 721 | .ExpectedStmt = .{ .token = parser.it.index }, | 768 | .ExpectedStmt = .{ .token = parser.it.index }, |
| 722 | }), | 769 | }), |
| 723 | }; | 770 | }; |
| ... | @@ -797,7 +844,7 @@ const Parser = struct { | ... | @@ -797,7 +844,7 @@ const Parser = struct { |
| 797 | | 844 | |
| 798 | fn eatToken(parser: *Parser, id: @TagType(Token.Id)) ?TokenIndex { | 845 | fn eatToken(parser: *Parser, id: @TagType(Token.Id)) ?TokenIndex { |
| 799 | while (true) { | 846 | while (true) { |
| 800 | switch (parser.it.next() orelse return null) { | 847 | switch ((parser.it.next() orelse return null).id) { |
| 801 | .LineComment, .MultiLineComment, .Nl => continue, | 848 | .LineComment, .MultiLineComment, .Nl => continue, |
| 802 | else => |next_id| if (next_id == id) { | 849 | else => |next_id| if (next_id == id) { |
| 803 | return parser.it.index; | 850 | return parser.it.index; |
| ... | @@ -811,7 +858,7 @@ const Parser = struct { | ... | @@ -811,7 +858,7 @@ const Parser = struct { |
| 811 | | 858 | |
| 812 | fn expectToken(parser: *Parser, id: @TagType(Token.Id)) Error!TokenIndex { | 859 | fn expectToken(parser: *Parser, id: @TagType(Token.Id)) Error!TokenIndex { |
| 813 | while (true) { | 860 | while (true) { |
| 814 | switch (parser.it.next() orelse return null) { | 861 | switch ((parser.it.next() orelse return error.ParseError).id) { |
| 815 | .LineComment, .MultiLineComment, .Nl => continue, | 862 | .LineComment, .MultiLineComment, .Nl => continue, |
| 816 | else => |next_id| if (next_id != id) { | 863 | else => |next_id| if (next_id != id) { |
| 817 | return parser.err(.{ | 864 | return parser.err(.{ |
| ... | @@ -826,9 +873,10 @@ const Parser = struct { | ... | @@ -826,9 +873,10 @@ const Parser = struct { |
| 826 | | 873 | |
| 827 | fn putBackToken(parser: *Parser, putting_back: TokenIndex) void { | 874 | fn putBackToken(parser: *Parser, putting_back: TokenIndex) void { |
| 828 | while (true) { | 875 | while (true) { |
| 829 | switch (parser.it.next() orelse return null) { | 876 | const prev_tok = parser.it.next() orelse return; |
| | 877 | switch (prev_tok.id) { |
| 830 | .LineComment, .MultiLineComment, .Nl => continue, | 878 | .LineComment, .MultiLineComment, .Nl => continue, |
| 831 | else => |next_id| { | 879 | else => { |
| 832 | assert(parser.it.list.at(putting_back) == prev_tok); | 880 | assert(parser.it.list.at(putting_back) == prev_tok); |
| 833 | return; | 881 | return; |
| 834 | }, | 882 | }, |
| ... | @@ -836,23 +884,26 @@ const Parser = struct { | ... | @@ -836,23 +884,26 @@ const Parser = struct { |
| 836 | } | 884 | } |
| 837 | } | 885 | } |
| 838 | | 886 | |
| 839 | fn expect( | 887 | fn err(parser: *Parser, msg: ast.Error) Error { |
| 840 | parser: *Parser, | 888 | try parser.tree.msgs.push(.{ |
| 841 | parseFn: fn (*Parser) Error!?*Node, | 889 | .kind = .Error, |
| 842 | err: ast.Error, // if parsing fails | 890 | .inner = msg, |
| 843 | ) Error!*Node { | 891 | }); |
| 844 | return (try parseFn(parser)) orelse { | 892 | return error.ParseError; |
| 845 | try parser.tree.errors.push(err); | | |
| 846 | return error.ParseError; | | |
| 847 | }; | | |
| 848 | } | 893 | } |
| 849 | | 894 | |
| 850 | fn warning(parser: *Parser, err: ast.Error) Error!void { | 895 | fn warn(parser: *Parser, msg: ast.Error) Error!void { |
| 851 | if (parser.tree.warnings) |*w| { | 896 | try parser.tree.msgs.push(.{ |
| 852 | try w.push(err); | 897 | .kind = if (parser.warnings) .Warning else .Error, |
| 853 | return; | 898 | .inner = msg, |
| 854 | } | 899 | }); |
| 855 | try parser.tree.errors.push(err); | 900 | if (!parser.warnings) return error.ParseError; |
| 856 | return error.ParseError; | 901 | } |
| | 902 | |
| | 903 | fn note(parser: *Parser, msg: ast.Error) Error!void { |
| | 904 | try parser.tree.msgs.push(.{ |
| | 905 | .kind = .Note, |
| | 906 | .inner = msg, |
| | 907 | }); |
| 857 | } | 908 | } |
| 858 | }; | 909 | }; |