diff --git a/lib/std/c/ast.zig b/lib/std/c/ast.zig index 7e91a28f0c..093ea4cc1b 100644 --- a/lib/std/c/ast.zig +++ b/lib/std/c/ast.zig @@ -48,7 +48,6 @@ pub const Error = union(enum) { InvalidToken: SingleTokenError("invalid token '{}'"), ExpectedToken: ExpectedToken, ExpectedExpr: SingleTokenError("expected expression, found '{}'"), - ExpectedStmt: SingleTokenError("expected statement, found '{}'"), ExpectedTypeName: SingleTokenError("expected type name, found '{}'"), ExpectedFnBody: SingleTokenError("expected function body, found '{}'"), ExpectedDeclarator: SingleTokenError("expected declarator, found '{}'"), @@ -70,7 +69,6 @@ pub const Error = union(enum) { .InvalidToken => |*x| return x.render(tree, stream), .ExpectedToken => |*x| return x.render(tree, stream), .ExpectedExpr => |*x| return x.render(tree, stream), - .ExpectedStmt => |*x| return x.render(tree, stream), .ExpectedTypeName => |*x| return x.render(tree, stream), .ExpectedDeclarator => |*x| return x.render(tree, stream), .ExpectedFnBody => |*x| return x.render(tree, stream), @@ -94,7 +92,6 @@ pub const Error = union(enum) { .InvalidToken => |x| return x.token, .ExpectedToken => |x| return x.token, .ExpectedExpr => |x| return x.token, - .ExpectedStmt => |x| return x.token, .ExpectedTypeName => |x| return x.token, .ExpectedDeclarator => |x| return x.token, .ExpectedFnBody => |x| return x.token, @@ -226,9 +223,10 @@ pub const Node = struct { RecordField, JumpStmt, ExprStmt, - Label, + LabeledStmt, CompoundStmt, IfStmt, + SwitchStmt, WhileStmt, DoStmt, ForStmt, @@ -454,26 +452,29 @@ pub const Node = struct { pub const JumpStmt = struct { base: Node = Node{ .id = .JumpStmt }, ltoken: TokenIndex, - kind: Kind, - semicolon: TokenIndex, - - pub const Kind = union(enum) { + kind: union(enum) { Break, Continue, Return: ?*Node, Goto: TokenIndex, - }; + }, + semicolon: TokenIndex, }; pub const ExprStmt = struct { base: Node = Node{ .id = .ExprStmt }, - expr: ?*Node, + expr: ?*Expr, semicolon: TokenIndex, }; - pub const Label = struct { - base: Node = Node{ .id = .Label }, - identifier: TokenIndex, + pub const LabeledStmt = struct { + base: Node = Node{ .id = .LabeledStmt }, + kind: union(enum) { + Label: TokenIndex, + Case: TokenIndex, + Default: TokenIndex, + }, + stmt: *Node, }; pub const CompoundStmt = struct { @@ -496,6 +497,14 @@ pub const Node = struct { }, }; + pub const SwitchStmt = struct { + base: Node = Node{ .id = .SwitchStmt }, + @"switch": TokenIndex, + expr: *Expr, + rparen: TokenIndex, + stmt: *Node, + }; + pub const WhileStmt = struct { base: Node = Node{ .id = .WhileStmt }, @"while": TokenIndex, diff --git a/lib/std/c/parse.zig b/lib/std/c/parse.zig index 5afbc88327..7473cf0ac6 100644 --- a/lib/std/c/parse.zig +++ b/lib/std/c/parse.zig @@ -104,7 +104,14 @@ const Parser = struct { ty: *Type, }; - fn pushScope(parser: *Parser) usize { + const ScopeKind = enum { + Block, + Loop, + Root, + Switch, + }; + + fn pushScope(parser: *Parser, kind: ScopeKind) usize { return parser.symbols.len; } @@ -130,6 +137,8 @@ const Parser = struct { /// Root <- ExternalDeclaration* eof fn root(parser: *Parser) Allocator.Error!*Node.Root { + const scope = parser.pushScope(.Root); + defer parser.popScope(scope); const node = try parser.arena.create(Node.Root); node.* = .{ .decls = Node.Root.DeclList.init(parser.arena), @@ -779,7 +788,7 @@ const Parser = struct { .ty = ty, }); if (parser.eatToken(.LBrace)) |lbrace| { - const scope = parser.pushScope(); + const scope = parser.pushScope(.Block); defer parser.popScope(scope); var fields = Node.RecordType.FieldList.init(parser.arena); while (true) { @@ -1079,18 +1088,22 @@ const Parser = struct { /// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE fn compoundStmt(parser: *Parser) Error!?*Node { - const scope = parser.pushScope(); - defer parser.popScope(scope); const lbrace = parser.eatToken(.LBrace) orelse return null; + const scope = parser.pushScope(.Block); + defer parser.popScope(scope); const body_node = try parser.arena.create(Node.CompoundStmt); body_node.* = .{ .lbrace = lbrace, .statements = Node.CompoundStmt.StmtList.init(parser.arena), .rbrace = undefined, }; - while ((try parser.declaration()) orelse (try parser.stmt())) |node| - try body_node.statements.push(node); - body_node.rbrace = try parser.expectToken(.RBrace); + while (true) { + if (parser.eatToken(.RBRACE)) |rbrace| { + body_node.rbrace = rbrace; + break; + } + try body_node.statements.push((try parser.declaration()) orelse (try parser.stmt())); + } return &body_node.base; } @@ -1109,7 +1122,7 @@ const Parser = struct { /// / Keyword_return Expr? SEMICOLON /// / IDENTIFIER COLON Stmt /// / ExprStmt - fn stmt(parser: *Parser) Error!?*Node { + fn stmt(parser: *Parser) Error!*Node { if (try parser.compoundStmt()) |node| return node; if (parser.eatToken(.Keyword_if)) |tok| { const node = try parser.arena.create(Node.IfStmt); @@ -1123,22 +1136,18 @@ const Parser = struct { .@"else" = null, }; _ = try parser.expectToken(.RParen); - node.body = (try parser.stmt()) orelse return parser.err(.{ - .ExpectedStmt = .{ .token = parser.it.index }, - }); + node.body = try parser.stmt(); if (parser.eatToken(.Keyword_else)) |else_tok| { node.@"else" = .{ .tok = else_tok, - .body = (try parser.stmt()) orelse return parser.err(.{ - .ExpectedStmt = .{ .token = parser.it.index }, - }), + .body = try parser.stmt(), }; } return &node.base; } - - // TODO loop scope if (parser.eatToken(.Keyword_while)) |tok| { + const scope = parser.pushScope(.Loop); + defer parser.popScope(scope); _ = try parser.expectToken(.LParen); const cond = (try parser.expr()) orelse return parser.err(.{ .ExpectedExpr = .{ .token = parser.it.index }, @@ -1149,18 +1158,15 @@ const Parser = struct { .@"while" = tok, .cond = cond, .rparen = rparen, - .body = (try parser.stmt()) orelse return parser.err(.{ - .ExpectedStmt = .{ .token = parser.it.index }, - }), + .body = try parser.stmt(), .semicolon = try parser.expectToken(.Semicolon), }; return &node.base; } if (parser.eatToken(.Keyword_do)) |tok| { - const body = (try parser.stmt()) orelse return parser.err(.{ - .ExpectedStmt = .{ .token = parser.it.index }, - }); - const @"while" = try parser.expectToken(.Keyword_while); + const scope = parser.pushScope(.Loop); + defer parser.popScope(scope); + const body = try parser.stmt(); _ = try parser.expectToken(.LParen); const cond = (try parser.expr()) orelse return parser.err(.{ .ExpectedExpr = .{ .token = parser.it.index }, @@ -1177,6 +1183,8 @@ const Parser = struct { return &node.base; } if (parser.eatToken(.Keyword_for)) |tok| { + const scope = parser.pushScope(.Loop); + defer parser.popScope(scope); _ = try parser.expectToken(.LParen); const init = if (try parser.declaration()) |decl| blk:{ // TODO disallow storage class other than auto and register @@ -1194,15 +1202,43 @@ const Parser = struct { .semicolon = semicolon, .incr = incr, .rparen = rparen, - .body = (try parser.stmt()) orelse return parser.err(.{ - .ExpectedStmt = .{ .token = parser.it.index }, - }), + .body = try parser.stmt(), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_switch)) |tok| { + const scope = parser.pushScope(.Switch); + defer parser.popScope(scope); + _ = try parser.expectToken(.LParen); + const switch_expr = try parser.exprStmt(); + const rparen = try parser.expectToken(.RParen); + const node = try parser.arena.create(Node.SwitchStmt); + node.* = .{ + .@"switch" = tok, + .expr = switch_expr, + .rparen = rparen, + .body = try parser.stmt(), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_default)) |tok| { + _ = try parser.expectToken(.Colon); + const node = try parser.arena.create(Node.LabeledStmt); + node.* = .{ + .kind = .{.Default = tok }, + .stmt = try parser.stmt(), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_case)) |tok| { + _ = try parser.expectToken(.Colon); + const node = try parser.arena.create(Node.LabeledStmt); + node.* = .{ + .kind = .{.Case = tok }, + .stmt = try parser.stmt(), }; return &node.base; } - // if (parser.eatToken(.Keyword_switch)) |tok| {} - // if (parser.eatToken(.Keyword_default)) |tok| {} - // if (parser.eatToken(.Keyword_case)) |tok| {} if (parser.eatToken(.Keyword_goto)) |tok| { const node = try parser.arena.create(Node.JumpStmt); node.* = .{ @@ -1241,29 +1277,24 @@ const Parser = struct { } if (parser.eatToken(.Identifier)) |tok| { if (parser.eatToken(.Colon)) |_| { - const node = try parser.arena.create(Node.Label); + const node = try parser.arena.create(Node.LabeledStmt); node.* = .{ - .identifier = tok, + .kind = .{.Label = tok }, + .stmt = try parser.stmt(), }; return &node.base; } parser.putBackToken(tok); } - if (try parser.exprStmt()) |node| return node; - return null; + return parser.exprStmt(); } /// ExprStmt <- Expr? SEMICOLON - fn exprStmt(parser: *Parser) !?*Node { + fn exprStmt(parser: *Parser) !*Node { const node = try parser.arena.create(Node.ExprStmt); - const expr_node = try parser.expr(); - const semicolon = if (expr_node != null) - try parser.expectToken(.Semicolon) - else - parser.eatToken(.Semicolon) orelse return null; node.* = .{ - .expr = expr_node, - .semicolon = semicolon, + .expr = try parser.expr(), + .semicolon = try parser.expectToken(.Semicolon), }; return &node.base; }