| author | |
| committer | |
| log | dccf1247b21ee2b15f6ec3c01c908b29b5c60f24 |
| tree | 5804f1c6e72bbc23f704540aaa348c79e2b2a0ff |
| parent | a20c0b31de2b6d8de568707429754a6d39d3346d |
| signature | Commit is signed but in an unrecognized format. |
3 files changed, 211 insertions(+), 10 deletions(-)
lib/std/c/ast.zig+48-5| ... | @@ -26,21 +26,43 @@ pub const Tree = struct { | ... | @@ -26,21 +26,43 @@ pub const Tree = struct { |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | pub const Error = union(enum) { | 28 | pub const Error = union(enum) { |
| 29 | InvalidToken: InvalidToken, | 29 | InvalidToken: SingleTokenError("Invalid token '{}'"), |
| 30 | ExpectedToken: ExpectedToken, | ||
| 31 | ExpectedExpr: SingleTokenError("Expected expression, found '{}'"), | ||
| 32 | ExpectedStmt: SingleTokenError("Expected statement, found '{}'"), | ||
| 30 | 33 | ||
| 31 | pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void { | 34 | pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void { |
| 32 | switch (self.*) { | 35 | switch (self.*) { |
| 33 | .InvalidToken => |*x| return x.render(tokens, stream), | 36 | .InvalidToken => |*x| return x.render(tokens, stream), |
| 37 | .ExpectedToken => |*x| return x.render(tokens, stream), | ||
| 38 | .ExpectedExpr => |*x| return x.render(tokens, stream), | ||
| 39 | .ExpectedStmt => |*x| return x.render(tokens, stream), | ||
| 34 | } | 40 | } |
| 35 | } | 41 | } |
| 36 | 42 | ||
| 37 | pub fn loc(self: *const Error) TokenIndex { | 43 | pub fn loc(self: *const Error) TokenIndex { |
| 38 | switch (self.*) { | 44 | switch (self.*) { |
| 39 | .InvalidToken => |x| return x.token, | 45 | .InvalidToken => |x| return x.token, |
| 46 | .ExpectedToken => |x| return x.token, | ||
| 47 | .ExpectedExpr => |x| return x.token, | ||
| 48 | .ExpectedStmt => |x| return x.token, | ||
| 40 | } | 49 | } |
| 41 | } | 50 | } |
| 42 | 51 | ||
| 43 | pub const InvalidToken = SingleTokenError("Invalid token '{}'"); | 52 | pub const ExpectedToken = struct { |
| 53 | token: TokenIndex, | ||
| 54 | expected_id: @TagType(Token.Id), | ||
| 55 | |||
| 56 | pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void { | ||
| 57 | const found_token = tokens.at(self.token); | ||
| 58 | if (found_token.id == .Invalid) { | ||
| 59 | return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()}); | ||
| 60 | } else { | ||
| 61 | const token_name = found_token.id.symbol(); | ||
| 62 | return stream.print("expected '{}', found '{}'", .{ self.expected_id.symbol(), token_name }); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | }; | ||
| 44 | 66 | ||
| 45 | fn SingleTokenError(comptime msg: []const u8) type { | 67 | fn SingleTokenError(comptime msg: []const u8) type { |
| 46 | return struct { | 68 | return struct { |
| ... | @@ -62,6 +84,8 @@ pub const Node = struct { | ... | @@ -62,6 +84,8 @@ pub const Node = struct { |
| 62 | JumpStmt, | 84 | JumpStmt, |
| 63 | ExprStmt, | 85 | ExprStmt, |
| 64 | Label, | 86 | Label, |
| 87 | CompoundStmt, | ||
| 88 | IfStmt, | ||
| 65 | }; | 89 | }; |
| 66 | 90 | ||
| 67 | pub const Root = struct { | 91 | pub const Root = struct { |
| ... | @@ -73,7 +97,7 @@ pub const Node = struct { | ... | @@ -73,7 +97,7 @@ pub const Node = struct { |
| 73 | }; | 97 | }; |
| 74 | 98 | ||
| 75 | pub const JumpStmt = struct { | 99 | pub const JumpStmt = struct { |
| 76 | base: Node = Node{ .id = .JumpStmt}, | 100 | base: Node = Node{ .id = .JumpStmt }, |
| 77 | ltoken: TokenIndex, | 101 | ltoken: TokenIndex, |
| 78 | kind: Kind, | 102 | kind: Kind, |
| 79 | semicolon: TokenIndex, | 103 | semicolon: TokenIndex, |
| ... | @@ -87,14 +111,33 @@ pub const Node = struct { | ... | @@ -87,14 +111,33 @@ pub const Node = struct { |
| 87 | }; | 111 | }; |
| 88 | 112 | ||
| 89 | pub const ExprStmt = struct { | 113 | pub const ExprStmt = struct { |
| 90 | base: Node = Node{ .id = .ExprStmt}, | 114 | base: Node = Node{ .id = .ExprStmt }, |
| 91 | expr: ?*Node, | 115 | expr: ?*Node, |
| 92 | semicolon: TokenIndex, | 116 | semicolon: TokenIndex, |
| 93 | }; | 117 | }; |
| 94 | 118 | ||
| 95 | pub const Label = struct { | 119 | pub const Label = struct { |
| 96 | base: Node = Node{ .id = .Label}, | 120 | base: Node = Node{ .id = .Label }, |
| 97 | identifier: TokenIndex, | 121 | identifier: TokenIndex, |
| 98 | colon: TokenIndex, | 122 | colon: TokenIndex, |
| 99 | }; | 123 | }; |
| 124 | |||
| 125 | pub const CompoundStmt = struct { | ||
| 126 | base: Node = Node{ .id = .CompoundStmt }, | ||
| 127 | lbrace: TokenIndex, | ||
| 128 | statements: StmtList, | ||
| 129 | rbrace: TokenIndex, | ||
| 130 | |||
| 131 | pub const StmtList = Root.DeclList; | ||
| 132 | }; | ||
| 133 | |||
| 134 | pub const IfStmt = struct { | ||
| 135 | base: Node = Node{ .id = .IfStmt }, | ||
| 136 | @"if": TokenIndex, | ||
| 137 | cond: *Node, | ||
| 138 | @"else": ?struct { | ||
| 139 | tok: TokenIndex, | ||
| 140 | stmt: *Node, | ||
| 141 | }, | ||
| 142 | }; | ||
| 100 | }; | 143 | }; |
lib/std/c/parse.zig+45-2| ... | @@ -284,7 +284,19 @@ const Parser = struct { | ... | @@ -284,7 +284,19 @@ const Parser = struct { |
| 284 | fn designator(parser: *Parser) !*Node {} | 284 | fn designator(parser: *Parser) !*Node {} |
| 285 | 285 | ||
| 286 | /// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE | 286 | /// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE |
| 287 | fn compoundStmt(parser: *Parser) !?*Node {} | 287 | fn compoundStmt(parser: *Parser) !?*Node { |
| 288 | const lbrace = parser.eatToken(.LBrace) orelse return null; | ||
| 289 | const node = try parser.arena.create(Node.CompoundStmt); | ||
| 290 | node.* = .{ | ||
| 291 | .lbrace = lbrace, | ||
| 292 | .statements = Node.JumpStmt.StmtList.init(parser.arena), | ||
| 293 | .rbrace = undefined, | ||
| 294 | }; | ||
| 295 | while (parser.declaration() orelse parser.stmt()) |node| | ||
| 296 | try node.statements.push(node); | ||
| 297 | node.rbrace = try parser.expectToken(.RBrace); | ||
| 298 | return &node.base; | ||
| 299 | } | ||
| 288 | 300 | ||
| 289 | /// Stmt | 301 | /// Stmt |
| 290 | /// <- CompoundStmt | 302 | /// <- CompoundStmt |
| ... | @@ -303,7 +315,27 @@ const Parser = struct { | ... | @@ -303,7 +315,27 @@ const Parser = struct { |
| 303 | /// / ExprStmt | 315 | /// / ExprStmt |
| 304 | fn stmt(parser: *Parser) !?*Node { | 316 | fn stmt(parser: *Parser) !?*Node { |
| 305 | if (parser.compoundStmt()) |node| return node; | 317 | if (parser.compoundStmt()) |node| return node; |
| 306 | // if (parser.eatToken(.Keyword_if)) |tok| {} | 318 | if (parser.eatToken(.Keyword_if)) |tok| { |
| 319 | const node = try parser.arena.create(Node.IfStmt); | ||
| 320 | _ = try parser.expectToken(.LParen); | ||
| 321 | node.* = .{ | ||
| 322 | .@"if" = tok, | ||
| 323 | .cond = try parser.expect(expr, .{ | ||
| 324 | .ExpectedExpr = .{ .token = it.index }, | ||
| 325 | }), | ||
| 326 | .@"else" = null, | ||
| 327 | }; | ||
| 328 | _ = try parser.expectToken(.RParen); | ||
| 329 | if (parser.eatToken(.Keyword_else)) |else_tok| { | ||
| 330 | node.@"else" = .{ | ||
| 331 | .tok = else_tok, | ||
| 332 | .stmt = try parser.stmt(expr, .{ | ||
| 333 | .ExpectedStmt = .{ .token = it.index }, | ||
| 334 | }), | ||
| 335 | }; | ||
| 336 | } | ||
| 337 | return &node.base; | ||
| 338 | } | ||
| 307 | // if (parser.eatToken(.Keyword_switch)) |tok| {} | 339 | // if (parser.eatToken(.Keyword_switch)) |tok| {} |
| 308 | // if (parser.eatToken(.Keyword_while)) |tok| {} | 340 | // if (parser.eatToken(.Keyword_while)) |tok| {} |
| 309 | // if (parser.eatToken(.Keyword_do)) |tok| {} | 341 | // if (parser.eatToken(.Keyword_do)) |tok| {} |
| ... | @@ -407,4 +439,15 @@ const Parser = struct { | ... | @@ -407,4 +439,15 @@ const Parser = struct { |
| 407 | return; | 439 | return; |
| 408 | } | 440 | } |
| 409 | } | 441 | } |
| 442 | |||
| 443 | fn expect( | ||
| 444 | parser: *Parser, | ||
| 445 | parseFn: fn (*Parser) Error!?*Node, | ||
| 446 | err: ast.Error, // if parsing fails | ||
| 447 | ) Error!*Node { | ||
| 448 | return (try parseFn(arena, it, tree)) orelse { | ||
| 449 | try parser.tree.errors.push(err); | ||
| 450 | return error.ParseError; | ||
| 451 | }; | ||
| 452 | } | ||
| 410 | }; | 453 | }; |
lib/std/c/tokenizer.zig+118-3| ... | @@ -6,7 +6,7 @@ pub const Source = struct { | ... | @@ -6,7 +6,7 @@ pub const Source = struct { |
| 6 | file_name: []const u8, | 6 | file_name: []const u8, |
| 7 | tokens: TokenList, | 7 | tokens: TokenList, |
| 8 | 8 | ||
| 9 | pub const TokenList = SegmentedList(Token, 64); | 9 | pub const TokenList = std.SegmentedList(Token, 64); |
| 10 | }; | 10 | }; |
| 11 | 11 | ||
| 12 | pub const Token = struct { | 12 | pub const Token = struct { |
| ... | @@ -134,6 +134,121 @@ pub const Token = struct { | ... | @@ -134,6 +134,121 @@ pub const Token = struct { |
| 134 | Keyword_ifndef, | 134 | Keyword_ifndef, |
| 135 | Keyword_error, | 135 | Keyword_error, |
| 136 | Keyword_pragma, | 136 | Keyword_pragma, |
| 137 | |||
| 138 | pub fn symbol(tok: Token) []const u8 { | ||
| 139 | return switch (tok.id) { | ||
| 140 | .Invalid => "Invalid", | ||
| 141 | .Eof => "Eof", | ||
| 142 | .Nl => "NewLine", | ||
| 143 | .Identifier => "Identifier", | ||
| 144 | .MacroString => "MacroString", | ||
| 145 | .StringLiteral => "StringLiteral", | ||
| 146 | .CharLiteral => "CharLiteral", | ||
| 147 | .IntegerLiteral => "IntegerLiteral", | ||
| 148 | .FloatLiteral => "FloatLiteral", | ||
| 149 | .LineComment => "LineComment", | ||
| 150 | .MultiLineComment => "MultiLineComment", | ||
| 151 | |||
| 152 | .Bang => "!", | ||
| 153 | .BangEqual => "!=", | ||
| 154 | .Pipe => "|", | ||
| 155 | .PipePipe => "||", | ||
| 156 | .PipeEqual => "|=", | ||
| 157 | .Equal => "=", | ||
| 158 | .EqualEqual => "==", | ||
| 159 | .LParen => "(", | ||
| 160 | .RParen => ")", | ||
| 161 | .LBrace => "{", | ||
| 162 | .RBrace => "}", | ||
| 163 | .LBracket => "[", | ||
| 164 | .RBracket => "]", | ||
| 165 | .Period => ".", | ||
| 166 | .Ellipsis => "...", | ||
| 167 | .Caret => "^", | ||
| 168 | .CaretEqual => "^=", | ||
| 169 | .Plus => "+", | ||
| 170 | .PlusPlus => "++", | ||
| 171 | .PlusEqual => "+=", | ||
| 172 | .Minus => "-", | ||
| 173 | .MinusMinus => "--", | ||
| 174 | .MinusEqual => "-=", | ||
| 175 | .Asterisk => "*", | ||
| 176 | .AsteriskEqual => "*=", | ||
| 177 | .Percent => "%", | ||
| 178 | .PercentEqual => "%=", | ||
| 179 | .Arrow => "->", | ||
| 180 | .Colon => ":", | ||
| 181 | .Semicolon => ";", | ||
| 182 | .Slash => "/", | ||
| 183 | .SlashEqual => "/=", | ||
| 184 | .Comma => ",", | ||
| 185 | .Ampersand => "&", | ||
| 186 | .AmpersandAmpersand => "&&", | ||
| 187 | .AmpersandEqual => "&=", | ||
| 188 | .QuestionMark => "?", | ||
| 189 | .AngleBracketLeft => "<", | ||
| 190 | .AngleBracketLeftEqual => "<=", | ||
| 191 | .AngleBracketAngleBracketLeft => "<<", | ||
| 192 | .AngleBracketAngleBracketLeftEqual => "<<=", | ||
| 193 | .AngleBracketRight => ">", | ||
| 194 | .AngleBracketRightEqual => ">=", | ||
| 195 | .AngleBracketAngleBracketRight => ">>", | ||
| 196 | .AngleBracketAngleBracketRightEqual => ">>=", | ||
| 197 | .Tilde => "~", | ||
| 198 | .Hash => "#", | ||
| 199 | .HashHash => "##", | ||
| 200 | .Keyword_auto => "auto", | ||
| 201 | .Keyword_break => "break", | ||
| 202 | .Keyword_case => "case", | ||
| 203 | .Keyword_char => "char", | ||
| 204 | .Keyword_const => "const", | ||
| 205 | .Keyword_continue => "continue", | ||
| 206 | .Keyword_default => "default", | ||
| 207 | .Keyword_do => "do", | ||
| 208 | .Keyword_double => "double", | ||
| 209 | .Keyword_else => "else", | ||
| 210 | .Keyword_enum => "enum", | ||
| 211 | .Keyword_extern => "extern", | ||
| 212 | .Keyword_float => "float", | ||
| 213 | .Keyword_for => "for", | ||
| 214 | .Keyword_goto => "goto", | ||
| 215 | .Keyword_if => "if", | ||
| 216 | .Keyword_int => "int", | ||
| 217 | .Keyword_long => "long", | ||
| 218 | .Keyword_register => "register", | ||
| 219 | .Keyword_return => "return", | ||
| 220 | .Keyword_short => "short", | ||
| 221 | .Keyword_signed => "signed", | ||
| 222 | .Keyword_sizeof => "sizeof", | ||
| 223 | .Keyword_static => "static", | ||
| 224 | .Keyword_struct => "struct", | ||
| 225 | .Keyword_switch => "switch", | ||
| 226 | .Keyword_typedef => "typedef", | ||
| 227 | .Keyword_union => "union", | ||
| 228 | .Keyword_unsigned => "unsigned", | ||
| 229 | .Keyword_void => "void", | ||
| 230 | .Keyword_volatile => "volatile", | ||
| 231 | .Keyword_while => "while", | ||
| 232 | .Keyword_bool => "_Bool", | ||
| 233 | .Keyword_complex => "_Complex", | ||
| 234 | .Keyword_imaginary => "_Imaginary", | ||
| 235 | .Keyword_inline => "inline", | ||
| 236 | .Keyword_restrict => "restrict", | ||
| 237 | .Keyword_alignas => "_Alignas", | ||
| 238 | .Keyword_alignof => "_Alignof", | ||
| 239 | .Keyword_atomic => "_Atomic", | ||
| 240 | .Keyword_generic => "_Generic", | ||
| 241 | .Keyword_noreturn => "_Noreturn", | ||
| 242 | .Keyword_static_assert => "_Static_assert", | ||
| 243 | .Keyword_thread_local => "_Thread_local", | ||
| 244 | .Keyword_include => "include", | ||
| 245 | .Keyword_define => "define", | ||
| 246 | .Keyword_ifdef => "ifdef", | ||
| 247 | .Keyword_ifndef => "ifndef", | ||
| 248 | .Keyword_error => "error", | ||
| 249 | .Keyword_pragma => "pragma", | ||
| 250 | }; | ||
| 251 | } | ||
| 137 | }; | 252 | }; |
| 138 | 253 | ||
| 139 | pub const Keyword = struct { | 254 | pub const Keyword = struct { |
| ... | @@ -1121,8 +1236,7 @@ pub const Tokenizer = struct { | ... | @@ -1121,8 +1236,7 @@ pub const Tokenizer = struct { |
| 1121 | } | 1236 | } |
| 1122 | } else if (self.index == self.source.buffer.len) { | 1237 | } else if (self.index == self.source.buffer.len) { |
| 1123 | switch (state) { | 1238 | switch (state) { |
| 1124 | .AfterStringLiteral, | 1239 | .AfterStringLiteral, .Start => {}, |
| 1125 | .Start => {}, | ||
| 1126 | .u, .u8, .U, .L, .Identifier => { | 1240 | .u, .u8, .U, .L, .Identifier => { |
| 1127 | result.id = Token.getKeyword(self.source.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier; | 1241 | result.id = Token.getKeyword(self.source.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier; |
| 1128 | }, | 1242 | }, |
| ... | @@ -1416,6 +1530,7 @@ fn expectTokens(source: []const u8, expected_tokens: []const Token.Id) void { | ... | @@ -1416,6 +1530,7 @@ fn expectTokens(source: []const u8, expected_tokens: []const Token.Id) void { |
| 1416 | .source = &Source{ | 1530 | .source = &Source{ |
| 1417 | .buffer = source, | 1531 | .buffer = source, |
| 1418 | .file_name = undefined, | 1532 | .file_name = undefined, |
| 1533 | .tokens = undefined, | ||
| 1419 | }, | 1534 | }, |
| 1420 | }; | 1535 | }; |
| 1421 | for (expected_tokens) |expected_token_id| { | 1536 | for (expected_tokens) |expected_token_id| { |