diff --git a/lib/std/c/ast.zig b/lib/std/c/ast.zig index 2f75e9b455..7e91a28f0c 100644 --- a/lib/std/c/ast.zig +++ b/lib/std/c/ast.zig @@ -229,6 +229,9 @@ pub const Node = struct { Label, CompoundStmt, IfStmt, + WhileStmt, + DoStmt, + ForStmt, StaticAssert, Declarator, Pointer, @@ -438,7 +441,7 @@ pub const Node = struct { pub const RecordDeclarator = struct { base: Node = Node{ .id = .RecordField }, declarator: *Declarator, - // bit_field_expr: ?*Expr, + bit_field_expr: ?*Expr, }; pub const TypeQual = struct { @@ -486,12 +489,41 @@ pub const Node = struct { base: Node = Node{ .id = .IfStmt }, @"if": TokenIndex, cond: *Node, + body: *Node, @"else": ?struct { tok: TokenIndex, - stmt: *Node, + body: *Node, }, }; + pub const WhileStmt = struct { + base: Node = Node{ .id = .WhileStmt }, + @"while": TokenIndex, + cond: *Expr, + rparen: TokenIndex, + body: *Node, + }; + + pub const DoStmt = struct { + base: Node = Node{ .id = .DoStmt }, + do: TokenIndex, + body: *Node, + @"while": TokenIndex, + cond: *Expr, + semicolon: TokenIndex, + }; + + pub const ForStmt = struct { + base: Node = Node{ .id = .ForStmt }, + @"for": TokenIndex, + init: ?*Node, + cond: ?*Expr, + semicolon: TokenIndex, + incr: ?*Expr, + rparen: TokenIndex, + body: *Node, + }; + pub const StaticAssert = struct { base: Node = Node{ .id = .StaticAssert }, assert: TokenIndex, diff --git a/lib/std/c/parse.zig b/lib/std/c/parse.zig index a38717e94b..5afbc88327 100644 --- a/lib/std/c/parse.zig +++ b/lib/std/c/parse.zig @@ -1119,23 +1119,88 @@ const Parser = struct { .cond = (try parser.expr()) orelse return parser.err(.{ .ExpectedExpr = .{ .token = parser.it.index }, }), + .body = undefined, .@"else" = null, }; _ = try parser.expectToken(.RParen); + node.body = (try parser.stmt()) orelse return parser.err(.{ + .ExpectedStmt = .{ .token = parser.it.index }, + }); if (parser.eatToken(.Keyword_else)) |else_tok| { node.@"else" = .{ .tok = else_tok, - .stmt = (try parser.stmt()) orelse return parser.err(.{ + .body = (try parser.stmt()) orelse return parser.err(.{ .ExpectedStmt = .{ .token = parser.it.index }, }), }; } return &node.base; } + + // TODO loop scope + if (parser.eatToken(.Keyword_while)) |tok| { + _ = try parser.expectToken(.LParen); + const cond = (try parser.expr()) orelse return parser.err(.{ + .ExpectedExpr = .{ .token = parser.it.index }, + }); + const rparen = try parser.expectToken(.RParen); + const node = try parser.arena.create(Node.WhileStmt); + node.* = .{ + .@"while" = tok, + .cond = cond, + .rparen = rparen, + .body = (try parser.stmt()) orelse return parser.err(.{ + .ExpectedStmt = .{ .token = parser.it.index }, + }), + .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); + _ = try parser.expectToken(.LParen); + const cond = (try parser.expr()) orelse return parser.err(.{ + .ExpectedExpr = .{ .token = parser.it.index }, + }); + _ = try parser.expectToken(.RParen); + const node = try parser.arena.create(Node.DoStmt); + node.* = .{ + .do = tok, + .body = body, + .cond = cond, + .@"while" = @"while", + .semicolon = try parser.expectToken(.Semicolon), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_for)) |tok| { + _ = try parser.expectToken(.LParen); + const init = if (try parser.declaration()) |decl| blk:{ + // TODO disallow storage class other than auto and register + break :blk decl; + } else try parser.exprStmt(); + const cond = try parser.expr(); + const semicolon = try parser.expectToken(.Semicolon); + const incr = try parser.expr(); + const rparen = try parser.expectToken(.RParen); + const node = try parser.arena.create(Node.ForStmt); + node.* = .{ + .@"for" = tok, + .init = init, + .cond = cond, + .semicolon = semicolon, + .incr = incr, + .rparen = rparen, + .body = (try parser.stmt()) orelse return parser.err(.{ + .ExpectedStmt = .{ .token = parser.it.index }, + }), + }; + return &node.base; + } // if (parser.eatToken(.Keyword_switch)) |tok| {} - // if (parser.eatToken(.Keyword_while)) |tok| {} - // if (parser.eatToken(.Keyword_do)) |tok| {} - // if (parser.eatToken(.Keyword_for)) |tok| {} // if (parser.eatToken(.Keyword_default)) |tok| {} // if (parser.eatToken(.Keyword_case)) |tok| {} if (parser.eatToken(.Keyword_goto)) |tok| {