Commit e21ea5bd95

Vexu <git@vexu.eu>
2020-01-07 23:00:14
std-c parser loops
1 parent 83b4163
Changed files (2)
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,
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| {