| ... | @@ -13,7 +13,7 @@ pub const Error = error{ParseError} || Allocator.Error; | ... | @@ -13,7 +13,7 @@ pub const Error = error{ParseError} || Allocator.Error; |
| 13 | | 13 | |
| 14 | /// Result should be freed with tree.deinit() when there are | 14 | /// Result should be freed with tree.deinit() when there are |
| 15 | /// no more references to any of the tokens or nodes. | 15 | /// no more references to any of the tokens or nodes. |
| 16 | pub fn parse(allocator: *Allocator, source: []const u8) !*Tree { | 16 | pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { |
| 17 | const tree = blk: { | 17 | const tree = blk: { |
| 18 | // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists | 18 | // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists |
| 19 | // from being initialized with a pointer to this `arena`, which is created on | 19 | // from being initialized with a pointer to this `arena`, which is created on |
| ... | @@ -48,29 +48,32 @@ pub fn parse(allocator: *Allocator, source: []const u8) !*Tree { | ... | @@ -48,29 +48,32 @@ pub fn parse(allocator: *Allocator, source: []const u8) !*Tree { |
| 48 | | 48 | |
| 49 | while (it.peek().?.id == .LineComment) _ = it.next(); | 49 | while (it.peek().?.id == .LineComment) _ = it.next(); |
| 50 | | 50 | |
| 51 | tree.root_node = try parseRoot(arena, &it, tree); | 51 | tree.root_node = parseRoot(arena, &it, tree) catch |err| blk: { |
| | 52 | switch (err) { |
| | 53 | error.ParseError => { |
| | 54 | assert(tree.errors.len != 0); |
| | 55 | break :blk undefined; |
| | 56 | }, |
| | 57 | error.OutOfMemory => { |
| | 58 | return error.OutOfMemory; |
| | 59 | }, |
| | 60 | } |
| | 61 | }; |
| | 62 | |
| 52 | return tree; | 63 | return tree; |
| 53 | } | 64 | } |
| 54 | | 65 | |
| 55 | /// Root <- skip ContainerMembers eof | 66 | /// Root <- skip ContainerMembers eof |
| 56 | fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root { | 67 | fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!*Node.Root { |
| 57 | const node = try arena.create(Node.Root); | 68 | const node = try arena.create(Node.Root); |
| 58 | node.* = Node.Root{ | 69 | node.* = Node.Root{ |
| 59 | .decls = undefined, | 70 | .decls = try parseContainerMembers(arena, it, tree), |
| 60 | .eof_token = undefined, | 71 | .eof_token = eatToken(it, .Eof) orelse { |
| 61 | }; | 72 | try tree.errors.push(AstError{ |
| 62 | node.decls = parseContainerMembers(arena, it, tree) catch |err| { | 73 | .ExpectedContainerMembers = .{ .token = it.index }, |
| 63 | // TODO: Switch on the error type | 74 | }); |
| 64 | // https://github.com/ziglang/zig/issues/2473 | 75 | return error.ParseError; |
| 65 | if (err == error.ParseError) return node; | 76 | }, |
| 66 | assert(err == Allocator.Error.OutOfMemory); | | |
| 67 | return Allocator.Error.OutOfMemory; | | |
| 68 | }; | | |
| 69 | node.eof_token = eatToken(it, .Eof) orelse { | | |
| 70 | try tree.errors.push(AstError{ | | |
| 71 | .ExpectedContainerMembers = AstError.ExpectedContainerMembers{ .token = it.index }, | | |
| 72 | }); | | |
| 73 | return node; | | |
| 74 | }; | 77 | }; |
| 75 | return node; | 78 | return node; |
| 76 | } | 79 | } |
| ... | @@ -303,7 +306,17 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -303,7 +306,17 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 303 | fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 306 | fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 304 | const cc = parseFnCC(arena, it, tree); | 307 | const cc = parseFnCC(arena, it, tree); |
| 305 | const fn_token = eatToken(it, .Keyword_fn) orelse { | 308 | const fn_token = eatToken(it, .Keyword_fn) orelse { |
| 306 | if (cc == null) return null else return error.ParseError; | 309 | if (cc) |fnCC| { |
| | 310 | if (fnCC == .Extern) { |
| | 311 | putBackToken(it, fnCC.Extern); // 'extern' is also used in ContainerDecl |
| | 312 | } else { |
| | 313 | try tree.errors.push(AstError{ |
| | 314 | .ExpectedToken = .{ .token = it.index, .expected_id = .Keyword_fn }, |
| | 315 | }); |
| | 316 | return error.ParseError; |
| | 317 | } |
| | 318 | } |
| | 319 | return null; |
| 307 | }; | 320 | }; |
| 308 | const name_token = eatToken(it, .Identifier); | 321 | const name_token = eatToken(it, .Identifier); |
| 309 | const lparen = try expectToken(it, tree, .LParen); | 322 | const lparen = try expectToken(it, tree, .LParen); |
| ... | @@ -390,7 +403,7 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -390,7 +403,7 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 390 | .visib_token = null, | 403 | .visib_token = null, |
| 391 | .thread_local_token = null, | 404 | .thread_local_token = null, |
| 392 | .name_token = name_token, | 405 | .name_token = name_token, |
| 393 | .eq_token = eq_token orelse undefined, | 406 | .eq_token = eq_token, |
| 394 | .mut_token = mut_token, | 407 | .mut_token = mut_token, |
| 395 | .comptime_token = null, | 408 | .comptime_token = null, |
| 396 | .extern_export_token = null, | 409 | .extern_export_token = null, |
| ... | @@ -2177,7 +2190,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2177,7 +2190,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2177 | node.* = Node.PrefixOp{ | 2190 | node.* = Node.PrefixOp{ |
| 2178 | .op_token = token.index, | 2191 | .op_token = token.index, |
| 2179 | .op = op, | 2192 | .op = op, |
| 2180 | .rhs = undefined, | 2193 | .rhs = undefined, // set by caller |
| 2181 | }; | 2194 | }; |
| 2182 | return &node.base; | 2195 | return &node.base; |
| 2183 | } | 2196 | } |
| ... | @@ -2819,8 +2832,8 @@ fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2819,8 +2832,8 @@ fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2819 | .doc_comments = null, | 2832 | .doc_comments = null, |
| 2820 | .visib_token = null, | 2833 | .visib_token = null, |
| 2821 | .use_token = token, | 2834 | .use_token = token, |
| 2822 | .expr = undefined, | 2835 | .expr = undefined, // set by caller |
| 2823 | .semicolon_token = undefined, | 2836 | .semicolon_token = undefined, // set by caller |
| 2824 | }; | 2837 | }; |
| 2825 | return &node.base; | 2838 | return &node.base; |
| 2826 | } | 2839 | } |
| ... | @@ -2979,9 +2992,9 @@ fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*No | ... | @@ -2979,9 +2992,9 @@ fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*No |
| 2979 | const node = try arena.create(Node.InfixOp); | 2992 | const node = try arena.create(Node.InfixOp); |
| 2980 | node.* = Node.InfixOp{ | 2993 | node.* = Node.InfixOp{ |
| 2981 | .op_token = index, | 2994 | .op_token = index, |
| 2982 | .lhs = undefined, | 2995 | .lhs = undefined, // set by caller |
| 2983 | .op = op, | 2996 | .op = op, |
| 2984 | .rhs = undefined, | 2997 | .rhs = undefined, // set by caller |
| 2985 | }; | 2998 | }; |
| 2986 | return &node.base; | 2999 | return &node.base; |
| 2987 | } | 3000 | } |