Commit 4c0776b2a5
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,
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;
}