std.zig.ast: extract out Node.LabeledBlock from Node.Block
This is part of an ongoing effort to reduce size of in-memory AST. This enum flattening pattern is widespread throughout the self-hosted compiler. This is a API breaking change for consumers of the self-hosted parser.master
parent
c12a262503
commit
9a5a1013a8
|
@ -526,6 +526,7 @@ pub const Node = struct {
|
|||
Comptime,
|
||||
Nosuspend,
|
||||
Block,
|
||||
LabeledBlock,
|
||||
|
||||
// Misc
|
||||
DocComment,
|
||||
|
@ -654,6 +655,7 @@ pub const Node = struct {
|
|||
.Comptime => Comptime,
|
||||
.Nosuspend => Nosuspend,
|
||||
.Block => Block,
|
||||
.LabeledBlock => LabeledBlock,
|
||||
.DocComment => DocComment,
|
||||
.SwitchCase => SwitchCase,
|
||||
.SwitchElse => SwitchElse,
|
||||
|
@ -666,6 +668,13 @@ pub const Node = struct {
|
|||
.FieldInitializer => FieldInitializer,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isBlock(tag: Tag) bool {
|
||||
return switch (tag) {
|
||||
.Block, .LabeledBlock => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Prefer `castTag` to this.
|
||||
|
@ -729,6 +738,7 @@ pub const Node = struct {
|
|||
.Root,
|
||||
.ContainerField,
|
||||
.Block,
|
||||
.LabeledBlock,
|
||||
.Payload,
|
||||
.PointerPayload,
|
||||
.PointerIndexPayload,
|
||||
|
@ -739,6 +749,7 @@ pub const Node = struct {
|
|||
.DocComment,
|
||||
.TestDecl,
|
||||
=> return false,
|
||||
|
||||
.While => {
|
||||
const while_node = @fieldParentPtr(While, "base", n);
|
||||
if (while_node.@"else") |@"else"| {
|
||||
|
@ -746,7 +757,7 @@ pub const Node = struct {
|
|||
continue;
|
||||
}
|
||||
|
||||
return while_node.body.tag != .Block;
|
||||
return !while_node.body.tag.isBlock();
|
||||
},
|
||||
.For => {
|
||||
const for_node = @fieldParentPtr(For, "base", n);
|
||||
|
@ -755,7 +766,7 @@ pub const Node = struct {
|
|||
continue;
|
||||
}
|
||||
|
||||
return for_node.body.tag != .Block;
|
||||
return !for_node.body.tag.isBlock();
|
||||
},
|
||||
.If => {
|
||||
const if_node = @fieldParentPtr(If, "base", n);
|
||||
|
@ -764,7 +775,7 @@ pub const Node = struct {
|
|||
continue;
|
||||
}
|
||||
|
||||
return if_node.body.tag != .Block;
|
||||
return !if_node.body.tag.isBlock();
|
||||
},
|
||||
.Else => {
|
||||
const else_node = @fieldParentPtr(Else, "base", n);
|
||||
|
@ -773,29 +784,40 @@ pub const Node = struct {
|
|||
},
|
||||
.Defer => {
|
||||
const defer_node = @fieldParentPtr(Defer, "base", n);
|
||||
return defer_node.expr.tag != .Block;
|
||||
return !defer_node.expr.tag.isBlock();
|
||||
},
|
||||
.Comptime => {
|
||||
const comptime_node = @fieldParentPtr(Comptime, "base", n);
|
||||
return comptime_node.expr.tag != .Block;
|
||||
return !comptime_node.expr.tag.isBlock();
|
||||
},
|
||||
.Suspend => {
|
||||
const suspend_node = @fieldParentPtr(Suspend, "base", n);
|
||||
if (suspend_node.body) |body| {
|
||||
return body.tag != .Block;
|
||||
return !body.tag.isBlock();
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
.Nosuspend => {
|
||||
const nosuspend_node = @fieldParentPtr(Nosuspend, "base", n);
|
||||
return nosuspend_node.expr.tag != .Block;
|
||||
return !nosuspend_node.expr.tag.isBlock();
|
||||
},
|
||||
else => return true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts the node is a Block or LabeledBlock and returns the statements slice.
|
||||
pub fn blockStatements(base: *Node) []*Node {
|
||||
if (base.castTag(.Block)) |block| {
|
||||
return block.statements();
|
||||
} else if (base.castTag(.LabeledBlock)) |labeled_block| {
|
||||
return labeled_block.statements();
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dump(self: *Node, indent: usize) void {
|
||||
{
|
||||
var i: usize = 0;
|
||||
|
@ -1460,7 +1482,6 @@ pub const Node = struct {
|
|||
statements_len: NodeIndex,
|
||||
lbrace: TokenIndex,
|
||||
rbrace: TokenIndex,
|
||||
label: ?TokenIndex,
|
||||
|
||||
/// After this the caller must initialize the statements list.
|
||||
pub fn alloc(allocator: *mem.Allocator, statements_len: NodeIndex) !*Block {
|
||||
|
@ -1483,10 +1504,6 @@ pub const Node = struct {
|
|||
}
|
||||
|
||||
pub fn firstToken(self: *const Block) TokenIndex {
|
||||
if (self.label) |label| {
|
||||
return label;
|
||||
}
|
||||
|
||||
return self.lbrace;
|
||||
}
|
||||
|
||||
|
@ -1509,6 +1526,57 @@ pub const Node = struct {
|
|||
}
|
||||
};
|
||||
|
||||
/// The statements of the block follow LabeledBlock directly in memory.
|
||||
pub const LabeledBlock = struct {
|
||||
base: Node = Node{ .tag = .LabeledBlock },
|
||||
statements_len: NodeIndex,
|
||||
lbrace: TokenIndex,
|
||||
rbrace: TokenIndex,
|
||||
label: TokenIndex,
|
||||
|
||||
/// After this the caller must initialize the statements list.
|
||||
pub fn alloc(allocator: *mem.Allocator, statements_len: NodeIndex) !*LabeledBlock {
|
||||
const bytes = try allocator.alignedAlloc(u8, @alignOf(LabeledBlock), sizeInBytes(statements_len));
|
||||
return @ptrCast(*LabeledBlock, bytes.ptr);
|
||||
}
|
||||
|
||||
pub fn free(self: *LabeledBlock, allocator: *mem.Allocator) void {
|
||||
const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.statements_len)];
|
||||
allocator.free(bytes);
|
||||
}
|
||||
|
||||
pub fn iterate(self: *const LabeledBlock, index: usize) ?*Node {
|
||||
var i = index;
|
||||
|
||||
if (i < self.statements_len) return self.statementsConst()[i];
|
||||
i -= self.statements_len;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn firstToken(self: *const LabeledBlock) TokenIndex {
|
||||
return self.label;
|
||||
}
|
||||
|
||||
pub fn lastToken(self: *const LabeledBlock) TokenIndex {
|
||||
return self.rbrace;
|
||||
}
|
||||
|
||||
pub fn statements(self: *LabeledBlock) []*Node {
|
||||
const decls_start = @ptrCast([*]u8, self) + @sizeOf(LabeledBlock);
|
||||
return @ptrCast([*]*Node, decls_start)[0..self.statements_len];
|
||||
}
|
||||
|
||||
pub fn statementsConst(self: *const LabeledBlock) []const *Node {
|
||||
const decls_start = @ptrCast([*]const u8, self) + @sizeOf(LabeledBlock);
|
||||
return @ptrCast([*]const *Node, decls_start)[0..self.statements_len];
|
||||
}
|
||||
|
||||
fn sizeInBytes(statements_len: NodeIndex) usize {
|
||||
return @sizeOf(LabeledBlock) + @sizeOf(*Node) * @as(usize, statements_len);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Defer = struct {
|
||||
base: Node = Node{ .tag = .Defer },
|
||||
defer_token: TokenIndex,
|
||||
|
|
|
@ -364,9 +364,10 @@ const Parser = struct {
|
|||
const name_node = try p.expectNode(parseStringLiteralSingle, .{
|
||||
.ExpectedStringLiteral = .{ .token = p.tok_i },
|
||||
});
|
||||
const block_node = try p.expectNode(parseBlock, .{
|
||||
.ExpectedLBrace = .{ .token = p.tok_i },
|
||||
});
|
||||
const block_node = (try p.parseBlock(null)) orelse {
|
||||
try p.errors.append(p.gpa, .{ .ExpectedLBrace = .{ .token = p.tok_i } });
|
||||
return error.ParseError;
|
||||
};
|
||||
|
||||
const test_node = try p.arena.allocator.create(Node.TestDecl);
|
||||
test_node.* = .{
|
||||
|
@ -540,12 +541,14 @@ const Parser = struct {
|
|||
if (p.eatToken(.Semicolon)) |_| {
|
||||
break :blk null;
|
||||
}
|
||||
break :blk try p.expectNodeRecoverable(parseBlock, .{
|
||||
const body_block = (try p.parseBlock(null)) orelse {
|
||||
// Since parseBlock only return error.ParseError on
|
||||
// a missing '}' we can assume this function was
|
||||
// supposed to end here.
|
||||
.ExpectedSemiOrLBrace = .{ .token = p.tok_i },
|
||||
});
|
||||
try p.errors.append(p.gpa, .{ .ExpectedSemiOrLBrace = .{ .token = p.tok_i } });
|
||||
break :blk null;
|
||||
};
|
||||
break :blk body_block;
|
||||
},
|
||||
.as_type => null,
|
||||
};
|
||||
|
@ -823,10 +826,7 @@ const Parser = struct {
|
|||
var colon: TokenIndex = undefined;
|
||||
const label_token = p.parseBlockLabel(&colon);
|
||||
|
||||
if (try p.parseBlock()) |node| {
|
||||
node.cast(Node.Block).?.label = label_token;
|
||||
return node;
|
||||
}
|
||||
if (try p.parseBlock(label_token)) |node| return node;
|
||||
|
||||
if (try p.parseLoopStatement()) |node| {
|
||||
if (node.cast(Node.For)) |for_node| {
|
||||
|
@ -1003,14 +1003,13 @@ const Parser = struct {
|
|||
fn parseBlockExpr(p: *Parser) Error!?*Node {
|
||||
var colon: TokenIndex = undefined;
|
||||
const label_token = p.parseBlockLabel(&colon);
|
||||
const block_node = (try p.parseBlock()) orelse {
|
||||
const block_node = (try p.parseBlock(label_token)) orelse {
|
||||
if (label_token) |label| {
|
||||
p.putBackToken(label + 1); // ":"
|
||||
p.putBackToken(label); // IDENTIFIER
|
||||
}
|
||||
return null;
|
||||
};
|
||||
block_node.cast(Node.Block).?.label = label_token;
|
||||
return block_node;
|
||||
}
|
||||
|
||||
|
@ -1177,7 +1176,7 @@ const Parser = struct {
|
|||
p.putBackToken(token); // IDENTIFIER
|
||||
}
|
||||
|
||||
if (try p.parseBlock()) |node| return node;
|
||||
if (try p.parseBlock(null)) |node| return node;
|
||||
if (try p.parseCurlySuffixExpr()) |node| return node;
|
||||
|
||||
return null;
|
||||
|
@ -1189,7 +1188,7 @@ const Parser = struct {
|
|||
}
|
||||
|
||||
/// Block <- LBRACE Statement* RBRACE
|
||||
fn parseBlock(p: *Parser) !?*Node {
|
||||
fn parseBlock(p: *Parser, label_token: ?TokenIndex) !?*Node {
|
||||
const lbrace = p.eatToken(.LBrace) orelse return null;
|
||||
|
||||
var statements = std.ArrayList(*Node).init(p.gpa);
|
||||
|
@ -1211,16 +1210,26 @@ const Parser = struct {
|
|||
|
||||
const statements_len = @intCast(NodeIndex, statements.items.len);
|
||||
|
||||
const block_node = try Node.Block.alloc(&p.arena.allocator, statements_len);
|
||||
block_node.* = .{
|
||||
.label = null,
|
||||
.lbrace = lbrace,
|
||||
.statements_len = statements_len,
|
||||
.rbrace = rbrace,
|
||||
};
|
||||
std.mem.copy(*Node, block_node.statements(), statements.items);
|
||||
|
||||
return &block_node.base;
|
||||
if (label_token) |label| {
|
||||
const block_node = try Node.LabeledBlock.alloc(&p.arena.allocator, statements_len);
|
||||
block_node.* = .{
|
||||
.label = label,
|
||||
.lbrace = lbrace,
|
||||
.statements_len = statements_len,
|
||||
.rbrace = rbrace,
|
||||
};
|
||||
std.mem.copy(*Node, block_node.statements(), statements.items);
|
||||
return &block_node.base;
|
||||
} else {
|
||||
const block_node = try Node.Block.alloc(&p.arena.allocator, statements_len);
|
||||
block_node.* = .{
|
||||
.lbrace = lbrace,
|
||||
.statements_len = statements_len,
|
||||
.rbrace = rbrace,
|
||||
};
|
||||
std.mem.copy(*Node, block_node.statements(), statements.items);
|
||||
return &block_node.base;
|
||||
}
|
||||
}
|
||||
|
||||
/// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
|
||||
|
@ -1658,11 +1667,8 @@ const Parser = struct {
|
|||
var colon: TokenIndex = undefined;
|
||||
const label = p.parseBlockLabel(&colon);
|
||||
|
||||
if (label) |token| {
|
||||
if (try p.parseBlock()) |node| {
|
||||
node.cast(Node.Block).?.label = token;
|
||||
return node;
|
||||
}
|
||||
if (label) |label_token| {
|
||||
if (try p.parseBlock(label_token)) |node| return node;
|
||||
}
|
||||
|
||||
if (try p.parseLoopTypeExpr()) |node| {
|
||||
|
@ -3440,6 +3446,7 @@ const Parser = struct {
|
|||
}
|
||||
}
|
||||
|
||||
/// TODO Delete this function. I don't like the inversion of control.
|
||||
fn expectNode(
|
||||
p: *Parser,
|
||||
parseFn: NodeParseFn,
|
||||
|
@ -3449,6 +3456,7 @@ const Parser = struct {
|
|||
return (try p.expectNodeRecoverable(parseFn, err)) orelse return error.ParseError;
|
||||
}
|
||||
|
||||
/// TODO Delete this function. I don't like the inversion of control.
|
||||
fn expectNodeRecoverable(
|
||||
p: *Parser,
|
||||
parseFn: NodeParseFn,
|
||||
|
|
|
@ -392,28 +392,50 @@ fn renderExpression(
|
|||
return renderToken(tree, stream, any_type.token, indent, start_col, space);
|
||||
},
|
||||
|
||||
.Block => {
|
||||
const block = @fieldParentPtr(ast.Node.Block, "base", base);
|
||||
.Block, .LabeledBlock => {
|
||||
const block: struct {
|
||||
label: ?ast.TokenIndex,
|
||||
statements: []*ast.Node,
|
||||
lbrace: ast.TokenIndex,
|
||||
rbrace: ast.TokenIndex,
|
||||
} = b: {
|
||||
if (base.castTag(.Block)) |block| {
|
||||
break :b .{
|
||||
.label = null,
|
||||
.statements = block.statements(),
|
||||
.lbrace = block.lbrace,
|
||||
.rbrace = block.rbrace,
|
||||
};
|
||||
} else if (base.castTag(.LabeledBlock)) |block| {
|
||||
break :b .{
|
||||
.label = block.label,
|
||||
.statements = block.statements(),
|
||||
.lbrace = block.lbrace,
|
||||
.rbrace = block.rbrace,
|
||||
};
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
|
||||
if (block.label) |label| {
|
||||
try renderToken(tree, stream, label, indent, start_col, Space.None);
|
||||
try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);
|
||||
}
|
||||
|
||||
if (block.statements_len == 0) {
|
||||
if (block.statements.len == 0) {
|
||||
try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None);
|
||||
return renderToken(tree, stream, block.rbrace, indent, start_col, space);
|
||||
} else {
|
||||
const block_indent = indent + indent_delta;
|
||||
try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline);
|
||||
|
||||
const block_statements = block.statements();
|
||||
for (block_statements) |statement, i| {
|
||||
for (block.statements) |statement, i| {
|
||||
try stream.writeByteNTimes(' ', block_indent);
|
||||
try renderStatement(allocator, stream, tree, block_indent, start_col, statement);
|
||||
|
||||
if (i + 1 < block_statements.len) {
|
||||
try renderExtraNewline(tree, stream, start_col, block_statements[i + 1]);
|
||||
if (i + 1 < block.statements.len) {
|
||||
try renderExtraNewline(tree, stream, start_col, block.statements[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1841,7 +1863,7 @@ fn renderExpression(
|
|||
|
||||
const rparen = tree.nextToken(for_node.array_expr.lastToken());
|
||||
|
||||
const body_is_block = for_node.body.tag == .Block;
|
||||
const body_is_block = for_node.body.tag.isBlock();
|
||||
const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());
|
||||
const body_on_same_line = body_is_block or src_one_line_to_body;
|
||||
|
||||
|
@ -2578,6 +2600,7 @@ fn renderDocCommentsToken(
|
|||
fn nodeIsBlock(base: *const ast.Node) bool {
|
||||
return switch (base.tag) {
|
||||
.Block,
|
||||
.LabeledBlock,
|
||||
.If,
|
||||
.For,
|
||||
.While,
|
||||
|
|
|
@ -1343,7 +1343,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
|||
|
||||
const body_block = body_node.cast(ast.Node.Block).?;
|
||||
|
||||
_ = try astgen.blockExpr(self, params_scope, .none, body_block);
|
||||
try astgen.blockExpr(self, params_scope, body_block);
|
||||
|
||||
if (gen_scope.instructions.items.len == 0 or
|
||||
!gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())
|
||||
|
|
|
@ -107,31 +107,46 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
|||
.NullLiteral => return rlWrap(mod, scope, rl, try nullLiteral(mod, scope, node.castTag(.NullLiteral).?)),
|
||||
.OptionalType => return rlWrap(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)),
|
||||
.UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?),
|
||||
.Block => return blockExpr(mod, scope, rl, node.castTag(.Block).?),
|
||||
.Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)),
|
||||
.LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?),
|
||||
else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn blockExpr(
|
||||
pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block) InnerError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
try blockExprStmts(mod, parent_scope, &block_node.base, block_node.statements());
|
||||
}
|
||||
|
||||
fn labeledBlockExpr(
|
||||
mod: *Module,
|
||||
parent_scope: *Scope,
|
||||
rl: ResultLoc,
|
||||
block_node: *ast.Node.Block,
|
||||
block_node: *ast.Node.LabeledBlock,
|
||||
) InnerError!*zir.Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
if (block_node.label) |label| {
|
||||
return mod.failTok(parent_scope, label, "TODO implement labeled blocks", .{});
|
||||
const statements = block_node.statements();
|
||||
|
||||
if (statements.len == 0) {
|
||||
// Hot path for `{}`.
|
||||
return rlWrapVoid(mod, parent_scope, rl, &block_node.base, {});
|
||||
}
|
||||
|
||||
return mod.failNode(parent_scope, &block_node.base, "TODO implement labeled blocks", .{});
|
||||
}
|
||||
|
||||
fn blockExprStmts(mod: *Module, parent_scope: *Scope, node: *ast.Node, statements: []*ast.Node) !void {
|
||||
const tree = parent_scope.tree();
|
||||
|
||||
var block_arena = std.heap.ArenaAllocator.init(mod.gpa);
|
||||
defer block_arena.deinit();
|
||||
|
||||
const tree = parent_scope.tree();
|
||||
|
||||
var scope = parent_scope;
|
||||
for (block_node.statements()) |statement| {
|
||||
for (statements) |statement| {
|
||||
const src = tree.token_locs[statement.firstToken()].start;
|
||||
_ = try addZIRNoOp(mod, scope, src, .dbg_stmt);
|
||||
switch (statement.tag) {
|
||||
|
@ -162,12 +177,6 @@ pub fn blockExpr(
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
const src = tree.token_locs[block_node.firstToken()].start;
|
||||
return addZIRInstConst(mod, parent_scope, src, .{
|
||||
.ty = Type.initTag(.void),
|
||||
.val = Value.initTag(.void_value),
|
||||
});
|
||||
}
|
||||
|
||||
fn varDecl(
|
||||
|
@ -1184,6 +1193,7 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
|
|||
.Slice,
|
||||
.Deref,
|
||||
.ArrayAccess,
|
||||
.Block,
|
||||
=> return false,
|
||||
|
||||
// Forward the question to a sub-expression.
|
||||
|
@ -1210,11 +1220,11 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
|
|||
.Switch,
|
||||
.Call,
|
||||
.BuiltinCall, // TODO some of these can return false
|
||||
.LabeledBlock,
|
||||
=> return true,
|
||||
|
||||
// Depending on AST properties, they may need memory locations.
|
||||
.If => return node.castTag(.If).?.@"else" != null,
|
||||
.Block => return node.castTag(.Block).?.label != null,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,19 +118,31 @@ const Scope = struct {
|
|||
self.* = undefined;
|
||||
}
|
||||
|
||||
fn complete(self: *Block, c: *Context) !*ast.Node.Block {
|
||||
fn complete(self: *Block, c: *Context) !*ast.Node {
|
||||
// We reserve 1 extra statement if the parent is a Loop. This is in case of
|
||||
// do while, we want to put `if (cond) break;` at the end.
|
||||
const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop);
|
||||
const node = try ast.Node.Block.alloc(c.arena, alloc_len);
|
||||
node.* = .{
|
||||
.statements_len = self.statements.items.len,
|
||||
.lbrace = self.lbrace,
|
||||
.rbrace = try appendToken(c, .RBrace, "}"),
|
||||
.label = self.label,
|
||||
};
|
||||
mem.copy(*ast.Node, node.statements(), self.statements.items);
|
||||
return node;
|
||||
const rbrace = try appendToken(c, .RBrace, "}");
|
||||
if (self.label) |label| {
|
||||
const node = try ast.Node.LabeledBlock.alloc(c.arena, alloc_len);
|
||||
node.* = .{
|
||||
.statements_len = self.statements.items.len,
|
||||
.lbrace = self.lbrace,
|
||||
.rbrace = rbrace,
|
||||
.label = label,
|
||||
};
|
||||
mem.copy(*ast.Node, node.statements(), self.statements.items);
|
||||
return &node.base;
|
||||
} else {
|
||||
const node = try ast.Node.Block.alloc(c.arena, alloc_len);
|
||||
node.* = .{
|
||||
.statements_len = self.statements.items.len,
|
||||
.lbrace = self.lbrace,
|
||||
.rbrace = rbrace,
|
||||
};
|
||||
mem.copy(*ast.Node, node.statements(), self.statements.items);
|
||||
return &node.base;
|
||||
}
|
||||
}
|
||||
|
||||
/// Given the desired name, return a name that does not shadow anything from outer scopes.
|
||||
|
@ -320,15 +332,9 @@ pub const Context = struct {
|
|||
return node;
|
||||
}
|
||||
|
||||
fn createBlock(c: *Context, label: ?[]const u8, statements_len: ast.NodeIndex) !*ast.Node.Block {
|
||||
const label_node = if (label) |l| blk: {
|
||||
const ll = try appendIdentifier(c, l);
|
||||
_ = try appendToken(c, .Colon, ":");
|
||||
break :blk ll;
|
||||
} else null;
|
||||
fn createBlock(c: *Context, statements_len: ast.NodeIndex) !*ast.Node.Block {
|
||||
const block_node = try ast.Node.Block.alloc(c.arena, statements_len);
|
||||
block_node.* = .{
|
||||
.label = label_node,
|
||||
.lbrace = try appendToken(c, .LBrace, "{"),
|
||||
.statements_len = statements_len,
|
||||
.rbrace = undefined,
|
||||
|
@ -640,8 +646,8 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
|
|||
var last = block_scope.statements.items[block_scope.statements.items.len - 1];
|
||||
while (true) {
|
||||
switch (last.tag) {
|
||||
.Block => {
|
||||
const stmts = last.castTag(.Block).?.statements();
|
||||
.Block, .LabeledBlock => {
|
||||
const stmts = last.blockStatements();
|
||||
if (stmts.len == 0) break;
|
||||
|
||||
last = stmts[stmts.len - 1];
|
||||
|
@ -669,7 +675,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
|
|||
}
|
||||
|
||||
const body_node = try block_scope.complete(rp.c);
|
||||
proto_node.setTrailer("body_node", &body_node.base);
|
||||
proto_node.setTrailer("body_node", body_node);
|
||||
return addTopLevelDecl(c, fn_name, &proto_node.base);
|
||||
}
|
||||
|
||||
|
@ -1275,7 +1281,7 @@ fn transStmt(
|
|||
.WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)),
|
||||
.DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)),
|
||||
.NullStmtClass => {
|
||||
const block = try rp.c.createBlock(null, 0);
|
||||
const block = try rp.c.createBlock(0);
|
||||
block.rbrace = try appendToken(rp.c, .RBrace, "}");
|
||||
return &block.base;
|
||||
},
|
||||
|
@ -1356,7 +1362,7 @@ fn transBinaryOperator(
|
|||
const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
|
||||
grouped_expr.* = .{
|
||||
.lparen = lparen,
|
||||
.expr = &block_node.base,
|
||||
.expr = block_node,
|
||||
.rparen = rparen,
|
||||
};
|
||||
return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
|
||||
|
@ -1521,8 +1527,7 @@ fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompo
|
|||
var block_scope = try Scope.Block.init(rp.c, scope, false);
|
||||
defer block_scope.deinit();
|
||||
try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope);
|
||||
const node = try block_scope.complete(rp.c);
|
||||
return &node.base;
|
||||
return try block_scope.complete(rp.c);
|
||||
}
|
||||
|
||||
fn transCStyleCastExprClass(
|
||||
|
@ -2589,7 +2594,7 @@ fn transDoWhileLoop(
|
|||
// zig: if (!cond) break;
|
||||
// zig: }
|
||||
const node = try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value);
|
||||
break :blk node.cast(ast.Node.Block).?;
|
||||
break :blk node.castTag(.Block).?;
|
||||
} else blk: {
|
||||
// the C statement is without a block, so we need to create a block to contain it.
|
||||
// c: do
|
||||
|
@ -2600,7 +2605,7 @@ fn transDoWhileLoop(
|
|||
// zig: if (!cond) break;
|
||||
// zig: }
|
||||
new = true;
|
||||
const block = try rp.c.createBlock(null, 2);
|
||||
const block = try rp.c.createBlock(2);
|
||||
block.statements_len = 1; // over-allocated so we can add another below
|
||||
block.statements()[0] = try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value);
|
||||
break :blk block;
|
||||
|
@ -2659,8 +2664,7 @@ fn transForLoop(
|
|||
while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value);
|
||||
if (block_scope) |*bs| {
|
||||
try bs.statements.append(&while_node.base);
|
||||
const node = try bs.complete(rp.c);
|
||||
return &node.base;
|
||||
return try bs.complete(rp.c);
|
||||
} else {
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
return &while_node.base;
|
||||
|
@ -2768,7 +2772,7 @@ fn transSwitch(
|
|||
|
||||
const result_node = try switch_scope.pending_block.complete(rp.c);
|
||||
switch_scope.pending_block.deinit();
|
||||
return &result_node.base;
|
||||
return result_node;
|
||||
}
|
||||
|
||||
fn transCase(
|
||||
|
@ -2820,7 +2824,7 @@ fn transCase(
|
|||
switch_scope.pending_block.deinit();
|
||||
switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);
|
||||
|
||||
try switch_scope.pending_block.statements.append(&pending_node.base);
|
||||
try switch_scope.pending_block.statements.append(pending_node);
|
||||
|
||||
return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value);
|
||||
}
|
||||
|
@ -2857,7 +2861,7 @@ fn transDefault(
|
|||
const pending_node = try switch_scope.pending_block.complete(rp.c);
|
||||
switch_scope.pending_block.deinit();
|
||||
switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);
|
||||
try switch_scope.pending_block.statements.append(&pending_node.base);
|
||||
try switch_scope.pending_block.statements.append(pending_node);
|
||||
|
||||
return transStmt(rp, scope, ZigClangDefaultStmt_getSubStmt(stmt), .unused, .r_value);
|
||||
}
|
||||
|
@ -2972,7 +2976,7 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr,
|
|||
const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
|
||||
grouped_expr.* = .{
|
||||
.lparen = lparen,
|
||||
.expr = &block_node.base,
|
||||
.expr = block_node,
|
||||
.rparen = rparen,
|
||||
};
|
||||
return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
|
||||
|
@ -3304,7 +3308,7 @@ fn transCreatePreCrement(
|
|||
const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
|
||||
grouped_expr.* = .{
|
||||
.lparen = try appendToken(rp.c, .LParen, "("),
|
||||
.expr = &block_node.base,
|
||||
.expr = block_node,
|
||||
.rparen = try appendToken(rp.c, .RParen, ")"),
|
||||
};
|
||||
return &grouped_expr.base;
|
||||
|
@ -3398,7 +3402,7 @@ fn transCreatePostCrement(
|
|||
const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
|
||||
grouped_expr.* = .{
|
||||
.lparen = try appendToken(rp.c, .LParen, "("),
|
||||
.expr = &block_node.base,
|
||||
.expr = block_node,
|
||||
.rparen = try appendToken(rp.c, .RParen, ")"),
|
||||
};
|
||||
return &grouped_expr.base;
|
||||
|
@ -3589,7 +3593,7 @@ fn transCreateCompoundAssign(
|
|||
const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
|
||||
grouped_expr.* = .{
|
||||
.lparen = try appendToken(rp.c, .LParen, "("),
|
||||
.expr = &block_node.base,
|
||||
.expr = block_node,
|
||||
.rparen = try appendToken(rp.c, .RParen, ")"),
|
||||
};
|
||||
return &grouped_expr.base;
|
||||
|
@ -3748,7 +3752,7 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
|
|||
const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
|
||||
grouped_expr.* = .{
|
||||
.lparen = lparen,
|
||||
.expr = &block_node.base,
|
||||
.expr = block_node,
|
||||
.rparen = try appendToken(rp.c, .RParen, ")"),
|
||||
};
|
||||
return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
|
||||
|
@ -4191,7 +4195,7 @@ fn transCreateNodeAssign(
|
|||
const block_node = try block_scope.complete(rp.c);
|
||||
// semicolon must immediately follow rbrace because it is the last token in a block
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
return &block_node.base;
|
||||
return block_node;
|
||||
}
|
||||
|
||||
fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node {
|
||||
|
@ -4484,7 +4488,6 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
|
|||
|
||||
const block = try ast.Node.Block.alloc(c.arena, 1);
|
||||
block.* = .{
|
||||
.label = null,
|
||||
.lbrace = block_lbrace,
|
||||
.statements_len = 1,
|
||||
.rbrace = try appendToken(c, .RBrace, "}"),
|
||||
|
@ -5475,9 +5478,9 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
|
|||
if (last != .Eof and last != .Nl)
|
||||
return m.fail(c, "unable to translate C expr: unexpected token .{}", .{@tagName(last)});
|
||||
_ = try appendToken(c, .Semicolon, ";");
|
||||
const type_of_arg = if (expr.tag != .Block) expr else blk: {
|
||||
const blk = @fieldParentPtr(ast.Node.Block, "base", expr);
|
||||
const blk_last = blk.statements()[blk.statements_len - 1];
|
||||
const type_of_arg = if (!expr.tag.isBlock()) expr else blk: {
|
||||
const stmts = expr.blockStatements();
|
||||
const blk_last = stmts[stmts.len - 1];
|
||||
const br = blk_last.cast(ast.Node.ControlFlowExpression).?;
|
||||
break :blk br.getRHS().?;
|
||||
};
|
||||
|
@ -5500,7 +5503,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
|
|||
.visib_token = pub_tok,
|
||||
.extern_export_inline_token = inline_tok,
|
||||
.name_token = name_tok,
|
||||
.body_node = &block_node.base,
|
||||
.body_node = block_node,
|
||||
});
|
||||
mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
|
||||
|
||||
|
@ -5555,8 +5558,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
|
|||
|
||||
const break_node = try transCreateNodeBreak(c, block_scope.label, last);
|
||||
try block_scope.statements.append(&break_node.base);
|
||||
const block_node = try block_scope.complete(c);
|
||||
return &block_node.base;
|
||||
return try block_scope.complete(c);
|
||||
},
|
||||
else => {
|
||||
m.i -= 1;
|
||||
|
|
Loading…
Reference in New Issue