| ... | @@ -1,1434 +0,0 @@ |
| 1 | // SPDX-License-Identifier: MIT |
| 2 | // Copyright (c) 2015-2021 Zig Contributors |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. |
| 6 | const std = @import("std"); |
| 7 | const mem = std.mem; |
| 8 | const assert = std.debug.assert; |
| 9 | const Allocator = std.mem.Allocator; |
| 10 | const ast = std.c.ast; |
| 11 | const Node = ast.Node; |
| 12 | const Type = ast.Type; |
| 13 | const Tree = ast.Tree; |
| 14 | const TokenIndex = ast.TokenIndex; |
| 15 | const Token = std.c.Token; |
| 16 | const TokenIterator = ast.Tree.TokenList.Iterator; |
| 17 | |
| 18 | pub const Error = error{ParseError} || Allocator.Error; |
| 19 | |
| 20 | pub const Options = struct { |
| 21 | // /// Keep simple macros unexpanded and add the definitions to the ast |
| 22 | // retain_macros: bool = false, |
| 23 | /// Warning or error |
| 24 | warn_as_err: union(enum) { |
| 25 | /// All warnings are warnings |
| 26 | None, |
| 27 | |
| 28 | /// Some warnings are errors |
| 29 | Some: []std.meta.Tag(ast.Error), |
| 30 | |
| 31 | /// All warnings are errors |
| 32 | All, |
| 33 | } = .All, |
| 34 | }; |
| 35 | |
| 36 | /// Result should be freed with tree.deinit() when there are |
| 37 | /// no more references to any of the tokens or nodes. |
| 38 | pub fn parse(allocator: *Allocator, source: []const u8, options: Options) !*Tree { |
| 39 | const tree = blk: { |
| 40 | // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists |
| 41 | // from being initialized with a pointer to this `arena`, which is created on |
| 42 | // the stack. Following code should instead refer to `&tree.arena_allocator`, a |
| 43 | // pointer to data which lives safely on the heap and will outlive `parse`. |
| 44 | var arena = std.heap.ArenaAllocator.init(allocator); |
| 45 | errdefer arena.deinit(); |
| 46 | const tree = try arena.allocator.create(ast.Tree); |
| 47 | tree.* = .{ |
| 48 | .root_node = undefined, |
| 49 | .arena_allocator = arena, |
| 50 | .tokens = undefined, |
| 51 | .sources = undefined, |
| 52 | }; |
| 53 | break :blk tree; |
| 54 | }; |
| 55 | errdefer tree.deinit(); |
| 56 | const arena = &tree.arena_allocator.allocator; |
| 57 | |
| 58 | tree.tokens = ast.Tree.TokenList.init(arena); |
| 59 | tree.sources = ast.Tree.SourceList.init(arena); |
| 60 | |
| 61 | var tokenizer = std.zig.Tokenizer.init(source); |
| 62 | while (true) { |
| 63 | const tree_token = try tree.tokens.addOne(); |
| 64 | tree_token.* = tokenizer.next(); |
| 65 | if (tree_token.id == .Eof) break; |
| 66 | } |
| 67 | // TODO preprocess here |
| 68 | var it = tree.tokens.iterator(0); |
| 69 | |
| 70 | while (true) { |
| 71 | const tok = it.peek().?.id; |
| 72 | switch (id) { |
| 73 | .LineComment, |
| 74 | .MultiLineComment, |
| 75 | => { |
| 76 | _ = it.next(); |
| 77 | }, |
| 78 | else => break, |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | var parse_arena = std.heap.ArenaAllocator.init(allocator); |
| 83 | defer parse_arena.deinit(); |
| 84 | |
| 85 | var parser = Parser{ |
| 86 | .scopes = Parser.SymbolList.init(allocator), |
| 87 | .arena = &parse_arena.allocator, |
| 88 | .it = &it, |
| 89 | .tree = tree, |
| 90 | .options = options, |
| 91 | }; |
| 92 | defer parser.symbols.deinit(); |
| 93 | |
| 94 | tree.root_node = try parser.root(); |
| 95 | return tree; |
| 96 | } |
| 97 | |
| 98 | const Parser = struct { |
| 99 | arena: *Allocator, |
| 100 | it: *TokenIterator, |
| 101 | tree: *Tree, |
| 102 | |
| 103 | arena: *Allocator, |
| 104 | scopes: ScopeList, |
| 105 | options: Options, |
| 106 | |
| 107 | const ScopeList = std.SegmentedLists(Scope); |
| 108 | const SymbolList = std.SegmentedLists(Symbol); |
| 109 | |
| 110 | const Scope = struct { |
| 111 | kind: ScopeKind, |
| 112 | syms: SymbolList, |
| 113 | }; |
| 114 | |
| 115 | const Symbol = struct { |
| 116 | name: []const u8, |
| 117 | ty: *Type, |
| 118 | }; |
| 119 | |
| 120 | const ScopeKind = enum { |
| 121 | Block, |
| 122 | Loop, |
| 123 | Root, |
| 124 | Switch, |
| 125 | }; |
| 126 | |
| 127 | fn pushScope(parser: *Parser, kind: ScopeKind) !void { |
| 128 | const new = try parser.scopes.addOne(); |
| 129 | new.* = .{ |
| 130 | .kind = kind, |
| 131 | .syms = SymbolList.init(parser.arena), |
| 132 | }; |
| 133 | } |
| 134 | |
| 135 | fn popScope(parser: *Parser, len: usize) void { |
| 136 | _ = parser.scopes.pop(); |
| 137 | } |
| 138 | |
| 139 | fn getSymbol(parser: *Parser, tok: TokenIndex) ?*Symbol { |
| 140 | const name = parser.tree.tokenSlice(tok); |
| 141 | var scope_it = parser.scopes.iterator(parser.scopes.len); |
| 142 | while (scope_it.prev()) |scope| { |
| 143 | var sym_it = scope.syms.iterator(scope.syms.len); |
| 144 | while (sym_it.prev()) |sym| { |
| 145 | if (mem.eql(u8, sym.name, name)) { |
| 146 | return sym; |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | return null; |
| 151 | } |
| 152 | |
| 153 | fn declareSymbol(parser: *Parser, type_spec: Node.TypeSpec, dr: *Node.Declarator) Error!void { |
| 154 | return; // TODO |
| 155 | } |
| 156 | |
| 157 | /// Root <- ExternalDeclaration* eof |
| 158 | fn root(parser: *Parser) Allocator.Error!*Node.Root { |
| 159 | try parser.pushScope(.Root); |
| 160 | defer parser.popScope(); |
| 161 | const node = try parser.arena.create(Node.Root); |
| 162 | node.* = .{ |
| 163 | .decls = Node.Root.DeclList.init(parser.arena), |
| 164 | .eof = undefined, |
| 165 | }; |
| 166 | while (parser.externalDeclarations() catch |e| switch (e) { |
| 167 | error.OutOfMemory => return error.OutOfMemory, |
| 168 | error.ParseError => return node, |
| 169 | }) |decl| { |
| 170 | try node.decls.push(decl); |
| 171 | } |
| 172 | node.eof = parser.eatToken(.Eof) orelse return node; |
| 173 | return node; |
| 174 | } |
| 175 | |
| 176 | /// ExternalDeclaration |
| 177 | /// <- DeclSpec Declarator OldStyleDecl* CompoundStmt |
| 178 | /// / Declaration |
| 179 | /// OldStyleDecl <- DeclSpec Declarator (COMMA Declarator)* SEMICOLON |
| 180 | fn externalDeclarations(parser: *Parser) !?*Node { |
| 181 | return parser.declarationExtra(false); |
| 182 | } |
| 183 | |
| 184 | /// Declaration |
| 185 | /// <- DeclSpec DeclInit SEMICOLON |
| 186 | /// / StaticAssert |
| 187 | /// DeclInit <- Declarator (EQUAL Initializer)? (COMMA Declarator (EQUAL Initializer)?)* |
| 188 | fn declaration(parser: *Parser) !?*Node { |
| 189 | return parser.declarationExtra(true); |
| 190 | } |
| 191 | |
| 192 | fn declarationExtra(parser: *Parser, local: bool) !?*Node { |
| 193 | if (try parser.staticAssert()) |decl| return decl; |
| 194 | const begin = parser.it.index + 1; |
| 195 | var ds = Node.DeclSpec{}; |
| 196 | const got_ds = try parser.declSpec(&ds); |
| 197 | if (local and !got_ds) { |
| 198 | // not a declaration |
| 199 | return null; |
| 200 | } |
| 201 | switch (ds.storage_class) { |
| 202 | .Auto, .Register => |tok| return parser.err(.{ |
| 203 | .InvalidStorageClass = .{ .token = tok }, |
| 204 | }), |
| 205 | .Typedef => { |
| 206 | const node = try parser.arena.create(Node.Typedef); |
| 207 | node.* = .{ |
| 208 | .decl_spec = ds, |
| 209 | .declarators = Node.Typedef.DeclaratorList.init(parser.arena), |
| 210 | .semicolon = undefined, |
| 211 | }; |
| 212 | while (true) { |
| 213 | const dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{ |
| 214 | .ExpectedDeclarator = .{ .token = parser.it.index }, |
| 215 | })); |
| 216 | try parser.declareSymbol(ds.type_spec, dr); |
| 217 | try node.declarators.push(&dr.base); |
| 218 | if (parser.eatToken(.Comma)) |_| {} else break; |
| 219 | } |
| 220 | return &node.base; |
| 221 | }, |
| 222 | else => {}, |
| 223 | } |
| 224 | var first_dr = try parser.declarator(.Must); |
| 225 | if (first_dr != null and declaratorIsFunction(first_dr.?)) { |
| 226 | // TODO typedeffed fn proto-only |
| 227 | const dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?); |
| 228 | try parser.declareSymbol(ds.type_spec, dr); |
| 229 | var old_decls = Node.FnDecl.OldDeclList.init(parser.arena); |
| 230 | const body = if (parser.eatToken(.Semicolon)) |_| |
| 231 | null |
| 232 | else blk: { |
| 233 | if (local) { |
| 234 | // TODO nested function warning |
| 235 | } |
| 236 | // TODO first_dr.is_old |
| 237 | // while (true) { |
| 238 | // var old_ds = Node.DeclSpec{}; |
| 239 | // if (!(try parser.declSpec(&old_ds))) { |
| 240 | // // not old decl |
| 241 | // break; |
| 242 | // } |
| 243 | // var old_dr = (try parser.declarator(.Must)); |
| 244 | // // if (old_dr == null) |
| 245 | // // try parser.err(.{ |
| 246 | // // .NoParamName = .{ .token = parser.it.index }, |
| 247 | // // }); |
| 248 | // // try old_decls.push(decl); |
| 249 | // } |
| 250 | const body_node = (try parser.compoundStmt()) orelse return parser.err(.{ |
| 251 | .ExpectedFnBody = .{ .token = parser.it.index }, |
| 252 | }); |
| 253 | break :blk @fieldParentPtr(Node.CompoundStmt, "base", body_node); |
| 254 | }; |
| 255 | |
| 256 | const node = try parser.arena.create(Node.FnDecl); |
| 257 | node.* = .{ |
| 258 | .decl_spec = ds, |
| 259 | .declarator = dr, |
| 260 | .old_decls = old_decls, |
| 261 | .body = body, |
| 262 | }; |
| 263 | return &node.base; |
| 264 | } else { |
| 265 | switch (ds.fn_spec) { |
| 266 | .Inline, .Noreturn => |tok| return parser.err(.{ |
| 267 | .FnSpecOnNonFn = .{ .token = tok }, |
| 268 | }), |
| 269 | else => {}, |
| 270 | } |
| 271 | // TODO threadlocal without static or extern on local variable |
| 272 | const node = try parser.arena.create(Node.VarDecl); |
| 273 | node.* = .{ |
| 274 | .decl_spec = ds, |
| 275 | .initializers = Node.VarDecl.Initializers.init(parser.arena), |
| 276 | .semicolon = undefined, |
| 277 | }; |
| 278 | if (first_dr == null) { |
| 279 | node.semicolon = try parser.expectToken(.Semicolon); |
| 280 | const ok = switch (ds.type_spec.spec) { |
| 281 | .Enum => |e| e.name != null, |
| 282 | .Record => |r| r.name != null, |
| 283 | else => false, |
| 284 | }; |
| 285 | const q = ds.type_spec.qual; |
| 286 | if (!ok) |
| 287 | try parser.warn(.{ |
| 288 | .NothingDeclared = .{ .token = begin }, |
| 289 | }) |
| 290 | else if (q.@"const" orelse q.atomic orelse q.@"volatile" orelse q.restrict) |tok| |
| 291 | try parser.warn(.{ |
| 292 | .QualifierIgnored = .{ .token = tok }, |
| 293 | }); |
| 294 | return &node.base; |
| 295 | } |
| 296 | var dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?); |
| 297 | while (true) { |
| 298 | try parser.declareSymbol(ds.type_spec, dr); |
| 299 | if (parser.eatToken(.Equal)) |tok| { |
| 300 | try node.initializers.push((try parser.initializer(dr)) orelse return parser.err(.{ |
| 301 | .ExpectedInitializer = .{ .token = parser.it.index }, |
| 302 | })); |
| 303 | } else try node.initializers.push(&dr.base); |
| 304 | if (parser.eatToken(.Comma) != null) break; |
| 305 | dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{ |
| 306 | .ExpectedDeclarator = .{ .token = parser.it.index }, |
| 307 | })); |
| 308 | } |
| 309 | node.semicolon = try parser.expectToken(.Semicolon); |
| 310 | return &node.base; |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | fn declaratorIsFunction(node: *Node) bool { |
| 315 | if (node.id != .Declarator) return false; |
| 316 | assert(node.id == .Declarator); |
| 317 | const dr = @fieldParentPtr(Node.Declarator, "base", node); |
| 318 | if (dr.suffix != .Fn) return false; |
| 319 | switch (dr.prefix) { |
| 320 | .None, .Identifer => return true, |
| 321 | .Complex => |inner| { |
| 322 | var inner_node = inner.inner; |
| 323 | while (true) { |
| 324 | if (inner_node.id != .Declarator) return false; |
| 325 | assert(inner_node.id == .Declarator); |
| 326 | const inner_dr = @fieldParentPtr(Node.Declarator, "base", inner_node); |
| 327 | if (inner_dr.pointer != null) return false; |
| 328 | switch (inner_dr.prefix) { |
| 329 | .None, .Identifer => return true, |
| 330 | .Complex => |c| inner_node = c.inner, |
| 331 | } |
| 332 | } |
| 333 | }, |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | /// StaticAssert <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON |
| 338 | fn staticAssert(parser: *Parser) !?*Node { |
| 339 | const tok = parser.eatToken(.Keyword_static_assert) orelse return null; |
| 340 | _ = try parser.expectToken(.LParen); |
| 341 | const const_expr = (try parser.constExpr()) orelse parser.err(.{ |
| 342 | .ExpectedExpr = .{ .token = parser.it.index }, |
| 343 | }); |
| 344 | _ = try parser.expectToken(.Comma); |
| 345 | const str = try parser.expectToken(.StringLiteral); |
| 346 | _ = try parser.expectToken(.RParen); |
| 347 | const node = try parser.arena.create(Node.StaticAssert); |
| 348 | node.* = .{ |
| 349 | .assert = tok, |
| 350 | .expr = const_expr, |
| 351 | .semicolon = try parser.expectToken(.Semicolon), |
| 352 | }; |
| 353 | return &node.base; |
| 354 | } |
| 355 | |
| 356 | /// DeclSpec <- (StorageClassSpec / TypeSpec / FnSpec / AlignSpec)* |
| 357 | /// returns true if any tokens were consumed |
| 358 | fn declSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { |
| 359 | var got = false; |
| 360 | while ((try parser.storageClassSpec(ds)) or (try parser.typeSpec(&ds.type_spec)) or (try parser.fnSpec(ds)) or (try parser.alignSpec(ds))) { |
| 361 | got = true; |
| 362 | } |
| 363 | return got; |
| 364 | } |
| 365 | |
| 366 | /// StorageClassSpec |
| 367 | /// <- Keyword_typedef / Keyword_extern / Keyword_static / Keyword_thread_local / Keyword_auto / Keyword_register |
| 368 | fn storageClassSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { |
| 369 | blk: { |
| 370 | if (parser.eatToken(.Keyword_typedef)) |tok| { |
| 371 | if (ds.storage_class != .None or ds.thread_local != null) |
| 372 | break :blk; |
| 373 | ds.storage_class = .{ .Typedef = tok }; |
| 374 | } else if (parser.eatToken(.Keyword_extern)) |tok| { |
| 375 | if (ds.storage_class != .None) |
| 376 | break :blk; |
| 377 | ds.storage_class = .{ .Extern = tok }; |
| 378 | } else if (parser.eatToken(.Keyword_static)) |tok| { |
| 379 | if (ds.storage_class != .None) |
| 380 | break :blk; |
| 381 | ds.storage_class = .{ .Static = tok }; |
| 382 | } else if (parser.eatToken(.Keyword_thread_local)) |tok| { |
| 383 | switch (ds.storage_class) { |
| 384 | .None, .Extern, .Static => {}, |
| 385 | else => break :blk, |
| 386 | } |
| 387 | ds.thread_local = tok; |
| 388 | } else if (parser.eatToken(.Keyword_auto)) |tok| { |
| 389 | if (ds.storage_class != .None or ds.thread_local != null) |
| 390 | break :blk; |
| 391 | ds.storage_class = .{ .Auto = tok }; |
| 392 | } else if (parser.eatToken(.Keyword_register)) |tok| { |
| 393 | if (ds.storage_class != .None or ds.thread_local != null) |
| 394 | break :blk; |
| 395 | ds.storage_class = .{ .Register = tok }; |
| 396 | } else return false; |
| 397 | return true; |
| 398 | } |
| 399 | try parser.warn(.{ |
| 400 | .DuplicateSpecifier = .{ .token = parser.it.index }, |
| 401 | }); |
| 402 | return true; |
| 403 | } |
| 404 | |
| 405 | /// TypeSpec |
| 406 | /// <- Keyword_void / Keyword_char / Keyword_short / Keyword_int / Keyword_long / Keyword_float / Keyword_double |
| 407 | /// / Keyword_signed / Keyword_unsigned / Keyword_bool / Keyword_complex / Keyword_imaginary / |
| 408 | /// / Keyword_atomic LPAREN TypeName RPAREN |
| 409 | /// / EnumSpec |
| 410 | /// / RecordSpec |
| 411 | /// / IDENTIFIER // typedef name |
| 412 | /// / TypeQual |
| 413 | fn typeSpec(parser: *Parser, type_spec: *Node.TypeSpec) !bool { |
| 414 | blk: { |
| 415 | if (parser.eatToken(.Keyword_void)) |tok| { |
| 416 | if (type_spec.spec != .None) |
| 417 | break :blk; |
| 418 | type_spec.spec = .{ .Void = tok }; |
| 419 | } else if (parser.eatToken(.Keyword_char)) |tok| { |
| 420 | switch (type_spec.spec) { |
| 421 | .None => { |
| 422 | type_spec.spec = .{ |
| 423 | .Char = .{ |
| 424 | .char = tok, |
| 425 | }, |
| 426 | }; |
| 427 | }, |
| 428 | .Int => |int| { |
| 429 | if (int.int != null) |
| 430 | break :blk; |
| 431 | type_spec.spec = .{ |
| 432 | .Char = .{ |
| 433 | .char = tok, |
| 434 | .sign = int.sign, |
| 435 | }, |
| 436 | }; |
| 437 | }, |
| 438 | else => break :blk, |
| 439 | } |
| 440 | } else if (parser.eatToken(.Keyword_short)) |tok| { |
| 441 | switch (type_spec.spec) { |
| 442 | .None => { |
| 443 | type_spec.spec = .{ |
| 444 | .Short = .{ |
| 445 | .short = tok, |
| 446 | }, |
| 447 | }; |
| 448 | }, |
| 449 | .Int => |int| { |
| 450 | if (int.int != null) |
| 451 | break :blk; |
| 452 | type_spec.spec = .{ |
| 453 | .Short = .{ |
| 454 | .short = tok, |
| 455 | .sign = int.sign, |
| 456 | }, |
| 457 | }; |
| 458 | }, |
| 459 | else => break :blk, |
| 460 | } |
| 461 | } else if (parser.eatToken(.Keyword_long)) |tok| { |
| 462 | switch (type_spec.spec) { |
| 463 | .None => { |
| 464 | type_spec.spec = .{ |
| 465 | .Long = .{ |
| 466 | .long = tok, |
| 467 | }, |
| 468 | }; |
| 469 | }, |
| 470 | .Int => |int| { |
| 471 | type_spec.spec = .{ |
| 472 | .Long = .{ |
| 473 | .long = tok, |
| 474 | .sign = int.sign, |
| 475 | .int = int.int, |
| 476 | }, |
| 477 | }; |
| 478 | }, |
| 479 | .Long => |*long| { |
| 480 | if (long.longlong != null) |
| 481 | break :blk; |
| 482 | long.longlong = tok; |
| 483 | }, |
| 484 | .Double => |*double| { |
| 485 | if (double.long != null) |
| 486 | break :blk; |
| 487 | double.long = tok; |
| 488 | }, |
| 489 | else => break :blk, |
| 490 | } |
| 491 | } else if (parser.eatToken(.Keyword_int)) |tok| { |
| 492 | switch (type_spec.spec) { |
| 493 | .None => { |
| 494 | type_spec.spec = .{ |
| 495 | .Int = .{ |
| 496 | .int = tok, |
| 497 | }, |
| 498 | }; |
| 499 | }, |
| 500 | .Short => |*short| { |
| 501 | if (short.int != null) |
| 502 | break :blk; |
| 503 | short.int = tok; |
| 504 | }, |
| 505 | .Int => |*int| { |
| 506 | if (int.int != null) |
| 507 | break :blk; |
| 508 | int.int = tok; |
| 509 | }, |
| 510 | .Long => |*long| { |
| 511 | if (long.int != null) |
| 512 | break :blk; |
| 513 | long.int = tok; |
| 514 | }, |
| 515 | else => break :blk, |
| 516 | } |
| 517 | } else if (parser.eatToken(.Keyword_signed) orelse parser.eatToken(.Keyword_unsigned)) |tok| { |
| 518 | switch (type_spec.spec) { |
| 519 | .None => { |
| 520 | type_spec.spec = .{ |
| 521 | .Int = .{ |
| 522 | .sign = tok, |
| 523 | }, |
| 524 | }; |
| 525 | }, |
| 526 | .Char => |*char| { |
| 527 | if (char.sign != null) |
| 528 | break :blk; |
| 529 | char.sign = tok; |
| 530 | }, |
| 531 | .Short => |*short| { |
| 532 | if (short.sign != null) |
| 533 | break :blk; |
| 534 | short.sign = tok; |
| 535 | }, |
| 536 | .Int => |*int| { |
| 537 | if (int.sign != null) |
| 538 | break :blk; |
| 539 | int.sign = tok; |
| 540 | }, |
| 541 | .Long => |*long| { |
| 542 | if (long.sign != null) |
| 543 | break :blk; |
| 544 | long.sign = tok; |
| 545 | }, |
| 546 | else => break :blk, |
| 547 | } |
| 548 | } else if (parser.eatToken(.Keyword_float)) |tok| { |
| 549 | if (type_spec.spec != .None) |
| 550 | break :blk; |
| 551 | type_spec.spec = .{ |
| 552 | .Float = .{ |
| 553 | .float = tok, |
| 554 | }, |
| 555 | }; |
| 556 | } else if (parser.eatToken(.Keyword_double)) |tok| { |
| 557 | if (type_spec.spec != .None) |
| 558 | break :blk; |
| 559 | type_spec.spec = .{ |
| 560 | .Double = .{ |
| 561 | .double = tok, |
| 562 | }, |
| 563 | }; |
| 564 | } else if (parser.eatToken(.Keyword_complex)) |tok| { |
| 565 | switch (type_spec.spec) { |
| 566 | .None => { |
| 567 | type_spec.spec = .{ |
| 568 | .Double = .{ |
| 569 | .complex = tok, |
| 570 | .double = null, |
| 571 | }, |
| 572 | }; |
| 573 | }, |
| 574 | .Float => |*float| { |
| 575 | if (float.complex != null) |
| 576 | break :blk; |
| 577 | float.complex = tok; |
| 578 | }, |
| 579 | .Double => |*double| { |
| 580 | if (double.complex != null) |
| 581 | break :blk; |
| 582 | double.complex = tok; |
| 583 | }, |
| 584 | else => break :blk, |
| 585 | } |
| 586 | } else if (parser.eatToken(.Keyword_bool)) |tok| { |
| 587 | if (type_spec.spec != .None) |
| 588 | break :blk; |
| 589 | type_spec.spec = .{ .Bool = tok }; |
| 590 | } else if (parser.eatToken(.Keyword_atomic)) |tok| { |
| 591 | // might be _Atomic qualifier |
| 592 | if (parser.eatToken(.LParen)) |_| { |
| 593 | if (type_spec.spec != .None) |
| 594 | break :blk; |
| 595 | const name = (try parser.typeName()) orelse return parser.err(.{ |
| 596 | .ExpectedTypeName = .{ .token = parser.it.index }, |
| 597 | }); |
| 598 | type_spec.spec.Atomic = .{ |
| 599 | .atomic = tok, |
| 600 | .typename = name, |
| 601 | .rparen = try parser.expectToken(.RParen), |
| 602 | }; |
| 603 | } else { |
| 604 | parser.putBackToken(tok); |
| 605 | } |
| 606 | } else if (parser.eatToken(.Keyword_enum)) |tok| { |
| 607 | if (type_spec.spec != .None) |
| 608 | break :blk; |
| 609 | type_spec.spec.Enum = try parser.enumSpec(tok); |
| 610 | } else if (parser.eatToken(.Keyword_union) orelse parser.eatToken(.Keyword_struct)) |tok| { |
| 611 | if (type_spec.spec != .None) |
| 612 | break :blk; |
| 613 | type_spec.spec.Record = try parser.recordSpec(tok); |
| 614 | } else if (parser.eatToken(.Identifier)) |tok| { |
| 615 | const ty = parser.getSymbol(tok) orelse { |
| 616 | parser.putBackToken(tok); |
| 617 | return false; |
| 618 | }; |
| 619 | switch (ty.id) { |
| 620 | .Enum => |e| blk: { |
| 621 | if (e.name) |some| |
| 622 | if (!parser.tree.tokenEql(some, tok)) |
| 623 | break :blk; |
| 624 | return parser.err(.{ |
| 625 | .MustUseKwToRefer = .{ .kw = e.tok, .name = tok }, |
| 626 | }); |
| 627 | }, |
| 628 | .Record => |r| blk: { |
| 629 | if (r.name) |some| |
| 630 | if (!parser.tree.tokenEql(some, tok)) |
| 631 | break :blk; |
| 632 | return parser.err(.{ |
| 633 | .MustUseKwToRefer = .{ |
| 634 | .kw = r.tok, |
| 635 | .name = tok, |
| 636 | }, |
| 637 | }); |
| 638 | }, |
| 639 | .Typedef => { |
| 640 | type_spec.spec = .{ |
| 641 | .Typedef = .{ |
| 642 | .sym = tok, |
| 643 | .sym_type = ty, |
| 644 | }, |
| 645 | }; |
| 646 | return true; |
| 647 | }, |
| 648 | else => {}, |
| 649 | } |
| 650 | parser.putBackToken(tok); |
| 651 | return false; |
| 652 | } |
| 653 | return parser.typeQual(&type_spec.qual); |
| 654 | } |
| 655 | return parser.err(.{ |
| 656 | .InvalidTypeSpecifier = .{ |
| 657 | .token = parser.it.index, |
| 658 | .type_spec = type_spec, |
| 659 | }, |
| 660 | }); |
| 661 | } |
| 662 | |
| 663 | /// TypeQual <- Keyword_const / Keyword_restrict / Keyword_volatile / Keyword_atomic |
| 664 | fn typeQual(parser: *Parser, qual: *Node.TypeQual) !bool { |
| 665 | blk: { |
| 666 | if (parser.eatToken(.Keyword_const)) |tok| { |
| 667 | if (qual.@"const" != null) |
| 668 | break :blk; |
| 669 | qual.@"const" = tok; |
| 670 | } else if (parser.eatToken(.Keyword_restrict)) |tok| { |
| 671 | if (qual.atomic != null) |
| 672 | break :blk; |
| 673 | qual.atomic = tok; |
| 674 | } else if (parser.eatToken(.Keyword_volatile)) |tok| { |
| 675 | if (qual.@"volatile" != null) |
| 676 | break :blk; |
| 677 | qual.@"volatile" = tok; |
| 678 | } else if (parser.eatToken(.Keyword_atomic)) |tok| { |
| 679 | if (qual.atomic != null) |
| 680 | break :blk; |
| 681 | qual.atomic = tok; |
| 682 | } else return false; |
| 683 | return true; |
| 684 | } |
| 685 | try parser.warn(.{ |
| 686 | .DuplicateQualifier = .{ .token = parser.it.index }, |
| 687 | }); |
| 688 | return true; |
| 689 | } |
| 690 | |
| 691 | /// FnSpec <- Keyword_inline / Keyword_noreturn |
| 692 | fn fnSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { |
| 693 | blk: { |
| 694 | if (parser.eatToken(.Keyword_inline)) |tok| { |
| 695 | if (ds.fn_spec != .None) |
| 696 | break :blk; |
| 697 | ds.fn_spec = .{ .Inline = tok }; |
| 698 | } else if (parser.eatToken(.Keyword_noreturn)) |tok| { |
| 699 | if (ds.fn_spec != .None) |
| 700 | break :blk; |
| 701 | ds.fn_spec = .{ .Noreturn = tok }; |
| 702 | } else return false; |
| 703 | return true; |
| 704 | } |
| 705 | try parser.warn(.{ |
| 706 | .DuplicateSpecifier = .{ .token = parser.it.index }, |
| 707 | }); |
| 708 | return true; |
| 709 | } |
| 710 | |
| 711 | /// AlignSpec <- Keyword_alignas LPAREN (TypeName / ConstExpr) RPAREN |
| 712 | fn alignSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { |
| 713 | if (parser.eatToken(.Keyword_alignas)) |tok| { |
| 714 | _ = try parser.expectToken(.LParen); |
| 715 | const node = (try parser.typeName()) orelse (try parser.constExpr()) orelse parser.err(.{ |
| 716 | .ExpectedExpr = .{ .token = parser.it.index }, |
| 717 | }); |
| 718 | if (ds.align_spec != null) { |
| 719 | try parser.warn(.{ |
| 720 | .DuplicateSpecifier = .{ .token = parser.it.index }, |
| 721 | }); |
| 722 | } |
| 723 | ds.align_spec = .{ |
| 724 | .alignas = tok, |
| 725 | .expr = node, |
| 726 | .rparen = try parser.expectToken(.RParen), |
| 727 | }; |
| 728 | return true; |
| 729 | } |
| 730 | return false; |
| 731 | } |
| 732 | |
| 733 | /// EnumSpec <- Keyword_enum IDENTIFIER? (LBRACE EnumField RBRACE)? |
| 734 | fn enumSpec(parser: *Parser, tok: TokenIndex) !*Node.EnumType { |
| 735 | const node = try parser.arena.create(Node.EnumType); |
| 736 | const name = parser.eatToken(.Identifier); |
| 737 | node.* = .{ |
| 738 | .tok = tok, |
| 739 | .name = name, |
| 740 | .body = null, |
| 741 | }; |
| 742 | const ty = try parser.arena.create(Type); |
| 743 | ty.* = .{ |
| 744 | .id = .{ |
| 745 | .Enum = node, |
| 746 | }, |
| 747 | }; |
| 748 | if (name) |some| |
| 749 | try parser.symbols.append(.{ |
| 750 | .name = parser.tree.tokenSlice(some), |
| 751 | .ty = ty, |
| 752 | }); |
| 753 | if (parser.eatToken(.LBrace)) |lbrace| { |
| 754 | var fields = Node.EnumType.FieldList.init(parser.arena); |
| 755 | try fields.push((try parser.enumField()) orelse return parser.err(.{ |
| 756 | .ExpectedEnumField = .{ .token = parser.it.index }, |
| 757 | })); |
| 758 | while (parser.eatToken(.Comma)) |_| { |
| 759 | try fields.push((try parser.enumField()) orelse break); |
| 760 | } |
| 761 | node.body = .{ |
| 762 | .lbrace = lbrace, |
| 763 | .fields = fields, |
| 764 | .rbrace = try parser.expectToken(.RBrace), |
| 765 | }; |
| 766 | } |
| 767 | return node; |
| 768 | } |
| 769 | |
| 770 | /// EnumField <- IDENTIFIER (EQUAL ConstExpr)? (COMMA EnumField) COMMA? |
| 771 | fn enumField(parser: *Parser) !?*Node { |
| 772 | const name = parser.eatToken(.Identifier) orelse return null; |
| 773 | const node = try parser.arena.create(Node.EnumField); |
| 774 | node.* = .{ |
| 775 | .name = name, |
| 776 | .value = null, |
| 777 | }; |
| 778 | if (parser.eatToken(.Equal)) |eq| { |
| 779 | node.value = (try parser.constExpr()) orelse parser.err(.{ |
| 780 | .ExpectedExpr = .{ .token = parser.it.index }, |
| 781 | }); |
| 782 | } |
| 783 | return &node.base; |
| 784 | } |
| 785 | |
| 786 | /// RecordSpec <- (Keyword_struct / Keyword_union) IDENTIFIER? (LBRACE RecordField+ RBRACE)? |
| 787 | fn recordSpec(parser: *Parser, tok: TokenIndex) !*Node.RecordType { |
| 788 | const node = try parser.arena.create(Node.RecordType); |
| 789 | const name = parser.eatToken(.Identifier); |
| 790 | const is_struct = parser.tree.tokenSlice(tok)[0] == 's'; |
| 791 | node.* = .{ |
| 792 | .tok = tok, |
| 793 | .kind = if (is_struct) .Struct else .Union, |
| 794 | .name = name, |
| 795 | .body = null, |
| 796 | }; |
| 797 | const ty = try parser.arena.create(Type); |
| 798 | ty.* = .{ |
| 799 | .id = .{ |
| 800 | .Record = node, |
| 801 | }, |
| 802 | }; |
| 803 | if (name) |some| |
| 804 | try parser.symbols.append(.{ |
| 805 | .name = parser.tree.tokenSlice(some), |
| 806 | .ty = ty, |
| 807 | }); |
| 808 | if (parser.eatToken(.LBrace)) |lbrace| { |
| 809 | try parser.pushScope(.Block); |
| 810 | defer parser.popScope(); |
| 811 | var fields = Node.RecordType.FieldList.init(parser.arena); |
| 812 | while (true) { |
| 813 | if (parser.eatToken(.RBrace)) |rbrace| { |
| 814 | node.body = .{ |
| 815 | .lbrace = lbrace, |
| 816 | .fields = fields, |
| 817 | .rbrace = rbrace, |
| 818 | }; |
| 819 | break; |
| 820 | } |
| 821 | try fields.push(try parser.recordField()); |
| 822 | } |
| 823 | } |
| 824 | return node; |
| 825 | } |
| 826 | |
| 827 | /// RecordField |
| 828 | /// <- TypeSpec* (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON |
| 829 | /// \ StaticAssert |
| 830 | fn recordField(parser: *Parser) Error!*Node { |
| 831 | if (try parser.staticAssert()) |decl| return decl; |
| 832 | var got = false; |
| 833 | var type_spec = Node.TypeSpec{}; |
| 834 | while (try parser.typeSpec(&type_spec)) got = true; |
| 835 | if (!got) |
| 836 | return parser.err(.{ |
| 837 | .ExpectedType = .{ .token = parser.it.index }, |
| 838 | }); |
| 839 | const node = try parser.arena.create(Node.RecordField); |
| 840 | node.* = .{ |
| 841 | .type_spec = type_spec, |
| 842 | .declarators = Node.RecordField.DeclaratorList.init(parser.arena), |
| 843 | .semicolon = undefined, |
| 844 | }; |
| 845 | while (true) { |
| 846 | const rdr = try parser.recordDeclarator(); |
| 847 | try parser.declareSymbol(type_spec, rdr.declarator); |
| 848 | try node.declarators.push(&rdr.base); |
| 849 | if (parser.eatToken(.Comma)) |_| {} else break; |
| 850 | } |
| 851 | |
| 852 | node.semicolon = try parser.expectToken(.Semicolon); |
| 853 | return &node.base; |
| 854 | } |
| 855 | |
| 856 | /// TypeName <- TypeSpec* AbstractDeclarator? |
| 857 | fn typeName(parser: *Parser) Error!?*Node { |
| 858 | @panic("TODO"); |
| 859 | } |
| 860 | |
| 861 | /// RecordDeclarator <- Declarator? (COLON ConstExpr)? |
| 862 | fn recordDeclarator(parser: *Parser) Error!*Node.RecordDeclarator { |
| 863 | @panic("TODO"); |
| 864 | } |
| 865 | |
| 866 | /// Pointer <- ASTERISK TypeQual* Pointer? |
| 867 | fn pointer(parser: *Parser) Error!?*Node.Pointer { |
| 868 | const asterisk = parser.eatToken(.Asterisk) orelse return null; |
| 869 | const node = try parser.arena.create(Node.Pointer); |
| 870 | node.* = .{ |
| 871 | .asterisk = asterisk, |
| 872 | .qual = .{}, |
| 873 | .pointer = null, |
| 874 | }; |
| 875 | while (try parser.typeQual(&node.qual)) {} |
| 876 | node.pointer = try parser.pointer(); |
| 877 | return node; |
| 878 | } |
| 879 | |
| 880 | const Named = enum { |
| 881 | Must, |
| 882 | Allowed, |
| 883 | Forbidden, |
| 884 | }; |
| 885 | |
| 886 | /// Declarator <- Pointer? DeclaratorSuffix |
| 887 | /// DeclaratorPrefix |
| 888 | /// <- IDENTIFIER // if named != .Forbidden |
| 889 | /// / LPAREN Declarator RPAREN |
| 890 | /// / (none) // if named != .Must |
| 891 | /// DeclaratorSuffix |
| 892 | /// <- DeclaratorPrefix (LBRACKET ArrayDeclarator? RBRACKET)* |
| 893 | /// / DeclaratorPrefix LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN |
| 894 | fn declarator(parser: *Parser, named: Named) Error!?*Node { |
| 895 | const ptr = try parser.pointer(); |
| 896 | var node: *Node.Declarator = undefined; |
| 897 | var inner_fn = false; |
| 898 | |
| 899 | // TODO sizof(int (int)) |
| 900 | // prefix |
| 901 | if (parser.eatToken(.LParen)) |lparen| { |
| 902 | const inner = (try parser.declarator(named)) orelse return parser.err(.{ |
| 903 | .ExpectedDeclarator = .{ .token = lparen + 1 }, |
| 904 | }); |
| 905 | inner_fn = declaratorIsFunction(inner); |
| 906 | node = try parser.arena.create(Node.Declarator); |
| 907 | node.* = .{ |
| 908 | .pointer = ptr, |
| 909 | .prefix = .{ |
| 910 | .Complex = .{ |
| 911 | .lparen = lparen, |
| 912 | .inner = inner, |
| 913 | .rparen = try parser.expectToken(.RParen), |
| 914 | }, |
| 915 | }, |
| 916 | .suffix = .None, |
| 917 | }; |
| 918 | } else if (named != .Forbidden) { |
| 919 | if (parser.eatToken(.Identifier)) |tok| { |
| 920 | node = try parser.arena.create(Node.Declarator); |
| 921 | node.* = .{ |
| 922 | .pointer = ptr, |
| 923 | .prefix = .{ .Identifer = tok }, |
| 924 | .suffix = .None, |
| 925 | }; |
| 926 | } else if (named == .Must) { |
| 927 | return parser.err(.{ |
| 928 | .ExpectedToken = .{ .token = parser.it.index, .expected_id = .Identifier }, |
| 929 | }); |
| 930 | } else { |
| 931 | if (ptr) |some| |
| 932 | return &some.base; |
| 933 | return null; |
| 934 | } |
| 935 | } else { |
| 936 | node = try parser.arena.create(Node.Declarator); |
| 937 | node.* = .{ |
| 938 | .pointer = ptr, |
| 939 | .prefix = .None, |
| 940 | .suffix = .None, |
| 941 | }; |
| 942 | } |
| 943 | // suffix |
| 944 | if (parser.eatToken(.LParen)) |lparen| { |
| 945 | if (inner_fn) |
| 946 | return parser.err(.{ |
| 947 | .InvalidDeclarator = .{ .token = lparen }, |
| 948 | }); |
| 949 | node.suffix = .{ |
| 950 | .Fn = .{ |
| 951 | .lparen = lparen, |
| 952 | .params = Node.Declarator.Params.init(parser.arena), |
| 953 | .rparen = undefined, |
| 954 | }, |
| 955 | }; |
| 956 | try parser.paramDecl(node); |
| 957 | node.suffix.Fn.rparen = try parser.expectToken(.RParen); |
| 958 | } else if (parser.eatToken(.LBracket)) |tok| { |
| 959 | if (inner_fn) |
| 960 | return parser.err(.{ |
| 961 | .InvalidDeclarator = .{ .token = tok }, |
| 962 | }); |
| 963 | node.suffix = .{ .Array = Node.Declarator.Arrays.init(parser.arena) }; |
| 964 | var lbrace = tok; |
| 965 | while (true) { |
| 966 | try node.suffix.Array.push(try parser.arrayDeclarator(lbrace)); |
| 967 | if (parser.eatToken(.LBracket)) |t| lbrace = t else break; |
| 968 | } |
| 969 | } |
| 970 | if (parser.eatToken(.LParen) orelse parser.eatToken(.LBracket)) |tok| |
| 971 | return parser.err(.{ |
| 972 | .InvalidDeclarator = .{ .token = tok }, |
| 973 | }); |
| 974 | return &node.base; |
| 975 | } |
| 976 | |
| 977 | /// ArrayDeclarator |
| 978 | /// <- ASTERISK |
| 979 | /// / Keyword_static TypeQual* AssignmentExpr |
| 980 | /// / TypeQual+ (ASTERISK / Keyword_static AssignmentExpr) |
| 981 | /// / TypeQual+ AssignmentExpr? |
| 982 | /// / AssignmentExpr |
| 983 | fn arrayDeclarator(parser: *Parser, lbracket: TokenIndex) !*Node.Array { |
| 984 | const arr = try parser.arena.create(Node.Array); |
| 985 | arr.* = .{ |
| 986 | .lbracket = lbracket, |
| 987 | .inner = .Inferred, |
| 988 | .rbracket = undefined, |
| 989 | }; |
| 990 | if (parser.eatToken(.Asterisk)) |tok| { |
| 991 | arr.inner = .{ .Unspecified = tok }; |
| 992 | } else { |
| 993 | // TODO |
| 994 | } |
| 995 | arr.rbracket = try parser.expectToken(.RBracket); |
| 996 | return arr; |
| 997 | } |
| 998 | |
| 999 | /// Params <- ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)? |
| 1000 | /// ParamDecl <- DeclSpec (Declarator / AbstractDeclarator) |
| 1001 | fn paramDecl(parser: *Parser, dr: *Node.Declarator) !void { |
| 1002 | var old_style = false; |
| 1003 | while (true) { |
| 1004 | var ds = Node.DeclSpec{}; |
| 1005 | if (try parser.declSpec(&ds)) { |
| 1006 | //TODO |
| 1007 | // TODO try parser.declareSymbol(ds.type_spec, dr); |
| 1008 | } else if (parser.eatToken(.Identifier)) |tok| { |
| 1009 | old_style = true; |
| 1010 | } else if (parser.eatToken(.Ellipsis)) |tok| { |
| 1011 | // TODO |
| 1012 | } |
| 1013 | } |
| 1014 | } |
| 1015 | |
| 1016 | /// Expr <- AssignmentExpr (COMMA Expr)* |
| 1017 | fn expr(parser: *Parser) Error!?*Expr { |
| 1018 | @panic("TODO"); |
| 1019 | } |
| 1020 | |
| 1021 | /// AssignmentExpr |
| 1022 | /// <- ConditionalExpr // TODO recursive? |
| 1023 | /// / UnaryExpr (EQUAL / ASTERISKEQUAL / SLASHEQUAL / PERCENTEQUAL / PLUSEQUAL / MINUSEQUA / |
| 1024 | /// / ANGLEBRACKETANGLEBRACKETLEFTEQUAL / ANGLEBRACKETANGLEBRACKETRIGHTEQUAL / |
| 1025 | /// / AMPERSANDEQUAL / CARETEQUAL / PIPEEQUAL) AssignmentExpr |
| 1026 | fn assignmentExpr(parser: *Parser) !?*Expr { |
| 1027 | @panic("TODO"); |
| 1028 | } |
| 1029 | |
| 1030 | /// ConstExpr <- ConditionalExpr |
| 1031 | fn constExpr(parser: *Parser) Error!?*Expr { |
| 1032 | const start = parser.it.index; |
| 1033 | const expression = try parser.conditionalExpr(); |
| 1034 | if (expression != null and expression.?.value == .None) |
| 1035 | return parser.err(.{ |
| 1036 | .ConsExpr = start, |
| 1037 | }); |
| 1038 | return expression; |
| 1039 | } |
| 1040 | |
| 1041 | /// ConditionalExpr <- LogicalOrExpr (QUESTIONMARK Expr COLON ConditionalExpr)? |
| 1042 | fn conditionalExpr(parser: *Parser) Error!?*Expr { |
| 1043 | @panic("TODO"); |
| 1044 | } |
| 1045 | |
| 1046 | /// LogicalOrExpr <- LogicalAndExpr (PIPEPIPE LogicalOrExpr)* |
| 1047 | fn logicalOrExpr(parser: *Parser) !*Node { |
| 1048 | const lhs = (try parser.logicalAndExpr()) orelse return null; |
| 1049 | } |
| 1050 | |
| 1051 | /// LogicalAndExpr <- BinOrExpr (AMPERSANDAMPERSAND LogicalAndExpr)* |
| 1052 | fn logicalAndExpr(parser: *Parser) !*Node { |
| 1053 | @panic("TODO"); |
| 1054 | } |
| 1055 | |
| 1056 | /// BinOrExpr <- BinXorExpr (PIPE BinOrExpr)* |
| 1057 | fn binOrExpr(parser: *Parser) !*Node { |
| 1058 | @panic("TODO"); |
| 1059 | } |
| 1060 | |
| 1061 | /// BinXorExpr <- BinAndExpr (CARET BinXorExpr)* |
| 1062 | fn binXorExpr(parser: *Parser) !*Node { |
| 1063 | @panic("TODO"); |
| 1064 | } |
| 1065 | |
| 1066 | /// BinAndExpr <- EqualityExpr (AMPERSAND BinAndExpr)* |
| 1067 | fn binAndExpr(parser: *Parser) !*Node { |
| 1068 | @panic("TODO"); |
| 1069 | } |
| 1070 | |
| 1071 | /// EqualityExpr <- ComparisionExpr ((EQUALEQUAL / BANGEQUAL) EqualityExpr)* |
| 1072 | fn equalityExpr(parser: *Parser) !*Node { |
| 1073 | @panic("TODO"); |
| 1074 | } |
| 1075 | |
| 1076 | /// ComparisionExpr <- ShiftExpr (ANGLEBRACKETLEFT / ANGLEBRACKETLEFTEQUAL /ANGLEBRACKETRIGHT / ANGLEBRACKETRIGHTEQUAL) ComparisionExpr)* |
| 1077 | fn comparisionExpr(parser: *Parser) !*Node { |
| 1078 | @panic("TODO"); |
| 1079 | } |
| 1080 | |
| 1081 | /// ShiftExpr <- AdditiveExpr (ANGLEBRACKETANGLEBRACKETLEFT / ANGLEBRACKETANGLEBRACKETRIGHT) ShiftExpr)* |
| 1082 | fn shiftExpr(parser: *Parser) !*Node { |
| 1083 | @panic("TODO"); |
| 1084 | } |
| 1085 | |
| 1086 | /// AdditiveExpr <- MultiplicativeExpr (PLUS / MINUS) AdditiveExpr)* |
| 1087 | fn additiveExpr(parser: *Parser) !*Node { |
| 1088 | @panic("TODO"); |
| 1089 | } |
| 1090 | |
| 1091 | /// MultiplicativeExpr <- UnaryExpr (ASTERISK / SLASH / PERCENT) MultiplicativeExpr)* |
| 1092 | fn multiplicativeExpr(parser: *Parser) !*Node { |
| 1093 | @panic("TODO"); |
| 1094 | } |
| 1095 | |
| 1096 | /// UnaryExpr |
| 1097 | /// <- LPAREN TypeName RPAREN UnaryExpr |
| 1098 | /// / Keyword_sizeof LAPERN TypeName RPAREN |
| 1099 | /// / Keyword_sizeof UnaryExpr |
| 1100 | /// / Keyword_alignof LAPERN TypeName RPAREN |
| 1101 | /// / (AMPERSAND / ASTERISK / PLUS / PLUSPLUS / MINUS / MINUSMINUS / TILDE / BANG) UnaryExpr |
| 1102 | /// / PrimaryExpr PostFixExpr* |
| 1103 | fn unaryExpr(parser: *Parser) !*Node { |
| 1104 | @panic("TODO"); |
| 1105 | } |
| 1106 | |
| 1107 | /// PrimaryExpr |
| 1108 | /// <- IDENTIFIER |
| 1109 | /// / INTEGERLITERAL / FLOATLITERAL / STRINGLITERAL / CHARLITERAL |
| 1110 | /// / LPAREN Expr RPAREN |
| 1111 | /// / Keyword_generic LPAREN AssignmentExpr (COMMA Generic)+ RPAREN |
| 1112 | fn primaryExpr(parser: *Parser) !*Node { |
| 1113 | @panic("TODO"); |
| 1114 | } |
| 1115 | |
| 1116 | /// Generic |
| 1117 | /// <- TypeName COLON AssignmentExpr |
| 1118 | /// / Keyword_default COLON AssignmentExpr |
| 1119 | fn generic(parser: *Parser) !*Node { |
| 1120 | @panic("TODO"); |
| 1121 | } |
| 1122 | |
| 1123 | /// PostFixExpr |
| 1124 | /// <- LPAREN TypeName RPAREN LBRACE Initializers RBRACE |
| 1125 | /// / LBRACKET Expr RBRACKET |
| 1126 | /// / LPAREN (AssignmentExpr (COMMA AssignmentExpr)*)? RPAREN |
| 1127 | /// / (PERIOD / ARROW) IDENTIFIER |
| 1128 | /// / (PLUSPLUS / MINUSMINUS) |
| 1129 | fn postFixExpr(parser: *Parser) !*Node { |
| 1130 | @panic("TODO"); |
| 1131 | } |
| 1132 | |
| 1133 | /// Initializers <- ((Designator+ EQUAL)? Initializer COMMA)* (Designator+ EQUAL)? Initializer COMMA? |
| 1134 | fn initializers(parser: *Parser) !*Node { |
| 1135 | @panic("TODO"); |
| 1136 | } |
| 1137 | |
| 1138 | /// Initializer |
| 1139 | /// <- LBRACE Initializers RBRACE |
| 1140 | /// / AssignmentExpr |
| 1141 | fn initializer(parser: *Parser, dr: *Node.Declarator) Error!?*Node { |
| 1142 | @panic("TODO"); |
| 1143 | } |
| 1144 | |
| 1145 | /// Designator |
| 1146 | /// <- LBRACKET ConstExpr RBRACKET |
| 1147 | /// / PERIOD IDENTIFIER |
| 1148 | fn designator(parser: *Parser) !*Node { |
| 1149 | @panic("TODO"); |
| 1150 | } |
| 1151 | |
| 1152 | /// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE |
| 1153 | fn compoundStmt(parser: *Parser) Error!?*Node { |
| 1154 | const lbrace = parser.eatToken(.LBrace) orelse return null; |
| 1155 | try parser.pushScope(.Block); |
| 1156 | defer parser.popScope(); |
| 1157 | const body_node = try parser.arena.create(Node.CompoundStmt); |
| 1158 | body_node.* = .{ |
| 1159 | .lbrace = lbrace, |
| 1160 | .statements = Node.CompoundStmt.StmtList.init(parser.arena), |
| 1161 | .rbrace = undefined, |
| 1162 | }; |
| 1163 | while (true) { |
| 1164 | if (parser.eatToken(.RBRACE)) |rbrace| { |
| 1165 | body_node.rbrace = rbrace; |
| 1166 | break; |
| 1167 | } |
| 1168 | try body_node.statements.push((try parser.declaration()) orelse (try parser.stmt())); |
| 1169 | } |
| 1170 | return &body_node.base; |
| 1171 | } |
| 1172 | |
| 1173 | /// Stmt |
| 1174 | /// <- CompoundStmt |
| 1175 | /// / Keyword_if LPAREN Expr RPAREN Stmt (Keyword_ELSE Stmt)? |
| 1176 | /// / Keyword_switch LPAREN Expr RPAREN Stmt |
| 1177 | /// / Keyword_while LPAREN Expr RPAREN Stmt |
| 1178 | /// / Keyword_do statement Keyword_while LPAREN Expr RPAREN SEMICOLON |
| 1179 | /// / Keyword_for LPAREN (Declaration / ExprStmt) ExprStmt Expr? RPAREN Stmt |
| 1180 | /// / Keyword_default COLON Stmt |
| 1181 | /// / Keyword_case ConstExpr COLON Stmt |
| 1182 | /// / Keyword_goto IDENTIFIER SEMICOLON |
| 1183 | /// / Keyword_continue SEMICOLON |
| 1184 | /// / Keyword_break SEMICOLON |
| 1185 | /// / Keyword_return Expr? SEMICOLON |
| 1186 | /// / IDENTIFIER COLON Stmt |
| 1187 | /// / ExprStmt |
| 1188 | fn stmt(parser: *Parser) Error!*Node { |
| 1189 | if (try parser.compoundStmt()) |node| return node; |
| 1190 | if (parser.eatToken(.Keyword_if)) |tok| { |
| 1191 | const node = try parser.arena.create(Node.IfStmt); |
| 1192 | _ = try parser.expectToken(.LParen); |
| 1193 | node.* = .{ |
| 1194 | .@"if" = tok, |
| 1195 | .cond = (try parser.expr()) orelse return parser.err(.{ |
| 1196 | .ExpectedExpr = .{ .token = parser.it.index }, |
| 1197 | }), |
| 1198 | .body = undefined, |
| 1199 | .@"else" = null, |
| 1200 | }; |
| 1201 | _ = try parser.expectToken(.RParen); |
| 1202 | node.body = try parser.stmt(); |
| 1203 | if (parser.eatToken(.Keyword_else)) |else_tok| { |
| 1204 | node.@"else" = .{ |
| 1205 | .tok = else_tok, |
| 1206 | .body = try parser.stmt(), |
| 1207 | }; |
| 1208 | } |
| 1209 | return &node.base; |
| 1210 | } |
| 1211 | if (parser.eatToken(.Keyword_while)) |tok| { |
| 1212 | try parser.pushScope(.Loop); |
| 1213 | defer parser.popScope(); |
| 1214 | _ = try parser.expectToken(.LParen); |
| 1215 | const cond = (try parser.expr()) orelse return parser.err(.{ |
| 1216 | .ExpectedExpr = .{ .token = parser.it.index }, |
| 1217 | }); |
| 1218 | const rparen = try parser.expectToken(.RParen); |
| 1219 | const node = try parser.arena.create(Node.WhileStmt); |
| 1220 | node.* = .{ |
| 1221 | .@"while" = tok, |
| 1222 | .cond = cond, |
| 1223 | .rparen = rparen, |
| 1224 | .body = try parser.stmt(), |
| 1225 | .semicolon = try parser.expectToken(.Semicolon), |
| 1226 | }; |
| 1227 | return &node.base; |
| 1228 | } |
| 1229 | if (parser.eatToken(.Keyword_do)) |tok| { |
| 1230 | try parser.pushScope(.Loop); |
| 1231 | defer parser.popScope(); |
| 1232 | const body = try parser.stmt(); |
| 1233 | _ = try parser.expectToken(.LParen); |
| 1234 | const cond = (try parser.expr()) orelse return parser.err(.{ |
| 1235 | .ExpectedExpr = .{ .token = parser.it.index }, |
| 1236 | }); |
| 1237 | _ = try parser.expectToken(.RParen); |
| 1238 | const node = try parser.arena.create(Node.DoStmt); |
| 1239 | node.* = .{ |
| 1240 | .do = tok, |
| 1241 | .body = body, |
| 1242 | .cond = cond, |
| 1243 | .@"while" = @"while", |
| 1244 | .semicolon = try parser.expectToken(.Semicolon), |
| 1245 | }; |
| 1246 | return &node.base; |
| 1247 | } |
| 1248 | if (parser.eatToken(.Keyword_for)) |tok| { |
| 1249 | try parser.pushScope(.Loop); |
| 1250 | defer parser.popScope(); |
| 1251 | _ = try parser.expectToken(.LParen); |
| 1252 | const init = if (try parser.declaration()) |decl| blk: { |
| 1253 | // TODO disallow storage class other than auto and register |
| 1254 | break :blk decl; |
| 1255 | } else try parser.exprStmt(); |
| 1256 | const cond = try parser.expr(); |
| 1257 | const semicolon = try parser.expectToken(.Semicolon); |
| 1258 | const incr = try parser.expr(); |
| 1259 | const rparen = try parser.expectToken(.RParen); |
| 1260 | const node = try parser.arena.create(Node.ForStmt); |
| 1261 | node.* = .{ |
| 1262 | .@"for" = tok, |
| 1263 | .init = init, |
| 1264 | .cond = cond, |
| 1265 | .semicolon = semicolon, |
| 1266 | .incr = incr, |
| 1267 | .rparen = rparen, |
| 1268 | .body = try parser.stmt(), |
| 1269 | }; |
| 1270 | return &node.base; |
| 1271 | } |
| 1272 | if (parser.eatToken(.Keyword_switch)) |tok| { |
| 1273 | try parser.pushScope(.Switch); |
| 1274 | defer parser.popScope(); |
| 1275 | _ = try parser.expectToken(.LParen); |
| 1276 | const switch_expr = try parser.exprStmt(); |
| 1277 | const rparen = try parser.expectToken(.RParen); |
| 1278 | const node = try parser.arena.create(Node.SwitchStmt); |
| 1279 | node.* = .{ |
| 1280 | .@"switch" = tok, |
| 1281 | .expr = switch_expr, |
| 1282 | .rparen = rparen, |
| 1283 | .body = try parser.stmt(), |
| 1284 | }; |
| 1285 | return &node.base; |
| 1286 | } |
| 1287 | if (parser.eatToken(.Keyword_default)) |tok| { |
| 1288 | _ = try parser.expectToken(.Colon); |
| 1289 | const node = try parser.arena.create(Node.LabeledStmt); |
| 1290 | node.* = .{ |
| 1291 | .kind = .{ .Default = tok }, |
| 1292 | .stmt = try parser.stmt(), |
| 1293 | }; |
| 1294 | return &node.base; |
| 1295 | } |
| 1296 | if (parser.eatToken(.Keyword_case)) |tok| { |
| 1297 | _ = try parser.expectToken(.Colon); |
| 1298 | const node = try parser.arena.create(Node.LabeledStmt); |
| 1299 | node.* = .{ |
| 1300 | .kind = .{ .Case = tok }, |
| 1301 | .stmt = try parser.stmt(), |
| 1302 | }; |
| 1303 | return &node.base; |
| 1304 | } |
| 1305 | if (parser.eatToken(.Keyword_goto)) |tok| { |
| 1306 | const node = try parser.arena.create(Node.JumpStmt); |
| 1307 | node.* = .{ |
| 1308 | .ltoken = tok, |
| 1309 | .kind = .{ .Goto = tok }, |
| 1310 | .semicolon = try parser.expectToken(.Semicolon), |
| 1311 | }; |
| 1312 | return &node.base; |
| 1313 | } |
| 1314 | if (parser.eatToken(.Keyword_continue)) |tok| { |
| 1315 | const node = try parser.arena.create(Node.JumpStmt); |
| 1316 | node.* = .{ |
| 1317 | .ltoken = tok, |
| 1318 | .kind = .Continue, |
| 1319 | .semicolon = try parser.expectToken(.Semicolon), |
| 1320 | }; |
| 1321 | return &node.base; |
| 1322 | } |
| 1323 | if (parser.eatToken(.Keyword_break)) |tok| { |
| 1324 | const node = try parser.arena.create(Node.JumpStmt); |
| 1325 | node.* = .{ |
| 1326 | .ltoken = tok, |
| 1327 | .kind = .Break, |
| 1328 | .semicolon = try parser.expectToken(.Semicolon), |
| 1329 | }; |
| 1330 | return &node.base; |
| 1331 | } |
| 1332 | if (parser.eatToken(.Keyword_return)) |tok| { |
| 1333 | const node = try parser.arena.create(Node.JumpStmt); |
| 1334 | node.* = .{ |
| 1335 | .ltoken = tok, |
| 1336 | .kind = .{ .Return = try parser.expr() }, |
| 1337 | .semicolon = try parser.expectToken(.Semicolon), |
| 1338 | }; |
| 1339 | return &node.base; |
| 1340 | } |
| 1341 | if (parser.eatToken(.Identifier)) |tok| { |
| 1342 | if (parser.eatToken(.Colon)) |_| { |
| 1343 | const node = try parser.arena.create(Node.LabeledStmt); |
| 1344 | node.* = .{ |
| 1345 | .kind = .{ .Label = tok }, |
| 1346 | .stmt = try parser.stmt(), |
| 1347 | }; |
| 1348 | return &node.base; |
| 1349 | } |
| 1350 | parser.putBackToken(tok); |
| 1351 | } |
| 1352 | return parser.exprStmt(); |
| 1353 | } |
| 1354 | |
| 1355 | /// ExprStmt <- Expr? SEMICOLON |
| 1356 | fn exprStmt(parser: *Parser) !*Node { |
| 1357 | const node = try parser.arena.create(Node.ExprStmt); |
| 1358 | node.* = .{ |
| 1359 | .expr = try parser.expr(), |
| 1360 | .semicolon = try parser.expectToken(.Semicolon), |
| 1361 | }; |
| 1362 | return &node.base; |
| 1363 | } |
| 1364 | |
| 1365 | fn eatToken(parser: *Parser, id: std.meta.Tag(Token.Id)) ?TokenIndex { |
| 1366 | while (true) { |
| 1367 | switch ((parser.it.next() orelse return null).id) { |
| 1368 | .LineComment, .MultiLineComment, .Nl => continue, |
| 1369 | else => |next_id| if (next_id == id) { |
| 1370 | return parser.it.index; |
| 1371 | } else { |
| 1372 | _ = parser.it.prev(); |
| 1373 | return null; |
| 1374 | }, |
| 1375 | } |
| 1376 | } |
| 1377 | } |
| 1378 | |
| 1379 | fn expectToken(parser: *Parser, id: std.meta.Tag(Token.Id)) Error!TokenIndex { |
| 1380 | while (true) { |
| 1381 | switch ((parser.it.next() orelse return error.ParseError).id) { |
| 1382 | .LineComment, .MultiLineComment, .Nl => continue, |
| 1383 | else => |next_id| if (next_id != id) { |
| 1384 | return parser.err(.{ |
| 1385 | .ExpectedToken = .{ .token = parser.it.index, .expected_id = id }, |
| 1386 | }); |
| 1387 | } else { |
| 1388 | return parser.it.index; |
| 1389 | }, |
| 1390 | } |
| 1391 | } |
| 1392 | } |
| 1393 | |
| 1394 | fn putBackToken(parser: *Parser, putting_back: TokenIndex) void { |
| 1395 | while (true) { |
| 1396 | const prev_tok = parser.it.next() orelse return; |
| 1397 | switch (prev_tok.id) { |
| 1398 | .LineComment, .MultiLineComment, .Nl => continue, |
| 1399 | else => { |
| 1400 | assert(parser.it.list.at(putting_back) == prev_tok); |
| 1401 | return; |
| 1402 | }, |
| 1403 | } |
| 1404 | } |
| 1405 | } |
| 1406 | |
| 1407 | fn err(parser: *Parser, msg: ast.Error) Error { |
| 1408 | try parser.tree.msgs.push(.{ |
| 1409 | .kind = .Error, |
| 1410 | .inner = msg, |
| 1411 | }); |
| 1412 | return error.ParseError; |
| 1413 | } |
| 1414 | |
| 1415 | fn warn(parser: *Parser, msg: ast.Error) Error!void { |
| 1416 | const is_warning = switch (parser.options.warn_as_err) { |
| 1417 | .None => true, |
| 1418 | .Some => |list| for (list) |item| (if (item == msg) break false) else true, |
| 1419 | .All => false, |
| 1420 | }; |
| 1421 | try parser.tree.msgs.push(.{ |
| 1422 | .kind = if (is_warning) .Warning else .Error, |
| 1423 | .inner = msg, |
| 1424 | }); |
| 1425 | if (!is_warning) return error.ParseError; |
| 1426 | } |
| 1427 | |
| 1428 | fn note(parser: *Parser, msg: ast.Error) Error!void { |
| 1429 | try parser.tree.msgs.push(.{ |
| 1430 | .kind = .Note, |
| 1431 | .inner = msg, |
| 1432 | }); |
| 1433 | } |
| 1434 | }; |