authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-01-05 20:19:17+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-01-05 20:25:52+02:00
log5feeff71236eb7bf8257b247660b6e9c33495ee8
treecb5f56b76bdc0371d91debf4916ba692f0bd6fae
parent795a5039995a1a23ba00d15488565f1a79d3f25b
signaturelock-open Commit is signed but in an unrecognized format.

std-c improve error reporting and decl parsing


2 files changed, 155 insertions(+), 96 deletions(-)

lib/std/c/ast.zig+12-4
...@@ -10,12 +10,11 @@ pub const Tree = struct {...@@ -10,12 +10,11 @@ pub const Tree = struct {
10 sources: SourceList,10 sources: SourceList,
11 root_node: *Node.Root,11 root_node: *Node.Root,
12 arena_allocator: std.heap.ArenaAllocator,12 arena_allocator: std.heap.ArenaAllocator,
13 errors: ErrorList,13 msgs: MsgList,
14 warnings: ?ErrorList,
1514
16 pub const SourceList = SegmentedList(Source, 4);15 pub const SourceList = SegmentedList(Source, 4);
17 pub const TokenList = Source.TokenList;16 pub const TokenList = Source.TokenList;
18 pub const ErrorList = SegmentedList(Error, 0);17 pub const MsgList = SegmentedList(Msg, 0);
1918
20 pub fn deinit(self: *Tree) void {19 pub fn deinit(self: *Tree) void {
21 // Here we copy the arena allocator into stack memory, because20 // Here we copy the arena allocator into stack memory, because
...@@ -26,6 +25,15 @@ pub const Tree = struct {...@@ -26,6 +25,15 @@ pub const Tree = struct {
26 }25 }
27};26};
2827
28pub const Msg = struct {
29 kind: enum {
30 Error,
31 Warning,
32 Note,
33 },
34 inner: Error,
35};
36
29pub const Error = union(enum) {37pub const Error = union(enum) {
30 InvalidToken: SingleTokenError("invalid token '{}'"),38 InvalidToken: SingleTokenError("invalid token '{}'"),
31 ExpectedToken: ExpectedToken,39 ExpectedToken: ExpectedToken,
...@@ -268,7 +276,7 @@ pub const Node = struct {...@@ -268,7 +276,7 @@ pub const Node = struct {
268276
269 pub const FnDef = struct {277 pub const FnDef = struct {
270 base: Node = Node{ .id = .FnDef },278 base: Node = Node{ .id = .FnDef },
271 decl_spec: *DeclSpec,279 decl_spec: DeclSpec,
272 declarator: *Node,280 declarator: *Node,
273 old_decls: OldDeclList,281 old_decls: OldDeclList,
274 body: *CompoundStmt,282 body: *CompoundStmt,
lib/std/c/parse.zig+143-92
...@@ -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),
7473
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 }
7989
80 /// Root <- ExternalDeclaration* eof90 /// 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 }
96106
97 /// ExternalDeclaration107 /// ExternalDeclaration
98 /// <- DeclSpec Declarator Declaration* CompoundStmt108 /// <- DeclSpec Declarator OldStyleDecl* CompoundStmt
99 /// / Declaration109 /// / 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 register132 // 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 declaration147 // .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 },
126153 });
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 }
136157
137 /// Declaration158 // TODO VarDecl, TypeDecl, TypeDef
138 /// <- DeclSpec (Declarator (EQUAL Initializer)? COMMA)* SEMICOLON159 return null;
139 /// / StaticAssert160 },
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 extern169 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 });
151183
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 }
154195
155 /// StaticAssert <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON196 /// 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 }
174213
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 }
182223
183 /// StorageClassSpec224 /// 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 }
461501
462 /// TypeQual <- Keyword_const / Keyword_restrict / Keyword_volatile / Keyword_atomic502 /// 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 {}
595633
596 /// ConstExpr <- ConditionalExpr634 /// 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 }
598645
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 IDENTIFIER718 /// / PERIOD IDENTIFIER
672 fn designator(parser: *Parser) !*Node {}719 fn designator(parser: *Parser) !*Node {}
673720
674 /// CompoundStmt <- LBRACE (Stmt / Declaration)* RBRACE721 /// 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 {
797844
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 {
811858
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 {
826873
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 }
838886
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 fails890 .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 }
849894
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};