stage2 parser: SwitchCase uses intrusive array instead of linkedlist
no perf impact, but the API is better
This commit is contained in:
@@ -1552,28 +1552,35 @@ pub const Node = struct {
|
||||
}
|
||||
};
|
||||
|
||||
/// Items sub-nodes appear in memory directly following SwitchCase.
|
||||
pub const SwitchCase = struct {
|
||||
base: Node = Node{ .id = .SwitchCase },
|
||||
items: ItemList,
|
||||
arrow_token: TokenIndex,
|
||||
payload: ?*Node,
|
||||
expr: *Node,
|
||||
items_len: NodeIndex,
|
||||
|
||||
pub const ItemList = LinkedList(*Node);
|
||||
/// After this the caller must initialize the fields_and_decls list.
|
||||
pub fn alloc(allocator: *mem.Allocator, items_len: NodeIndex) !*SwitchCase {
|
||||
const bytes = try allocator.alignedAlloc(u8, @alignOf(SwitchCase), sizeInBytes(items_len));
|
||||
return @ptrCast(*SwitchCase, bytes.ptr);
|
||||
}
|
||||
|
||||
pub fn free(self: *SwitchCase, allocator: *mem.Allocator) void {
|
||||
const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.items_len)];
|
||||
allocator.free(bytes);
|
||||
}
|
||||
|
||||
pub fn iterate(self: *const SwitchCase) Node.Iterator {
|
||||
return .{ .parent_node = &self.base, .index = 0, .node = self.items.first };
|
||||
return .{ .parent_node = &self.base, .index = 0, .node = null };
|
||||
}
|
||||
|
||||
pub fn iterateNext(self: *const SwitchCase, it: *Node.Iterator) ?*Node {
|
||||
var i = it.index;
|
||||
it.index += 1;
|
||||
|
||||
if (it.node) |child| {
|
||||
it.index -= 1;
|
||||
it.node = child.next;
|
||||
return child.data;
|
||||
}
|
||||
if (i < self.items_len) return self.itemsConst()[i];
|
||||
i -= self.items_len;
|
||||
|
||||
if (self.payload) |payload| {
|
||||
if (i < 1) return payload;
|
||||
@@ -1587,12 +1594,26 @@ pub const Node = struct {
|
||||
}
|
||||
|
||||
pub fn firstToken(self: *const SwitchCase) TokenIndex {
|
||||
return self.items.first.?.data.firstToken();
|
||||
return self.itemsConst()[0].firstToken();
|
||||
}
|
||||
|
||||
pub fn lastToken(self: *const SwitchCase) TokenIndex {
|
||||
return self.expr.lastToken();
|
||||
}
|
||||
|
||||
pub fn items(self: *SwitchCase) []*Node {
|
||||
const decls_start = @ptrCast([*]u8, self) + @sizeOf(SwitchCase);
|
||||
return @ptrCast([*]*Node, decls_start)[0..self.items_len];
|
||||
}
|
||||
|
||||
pub fn itemsConst(self: *const SwitchCase) []const *Node {
|
||||
const decls_start = @ptrCast([*]const u8, self) + @sizeOf(SwitchCase);
|
||||
return @ptrCast([*]const *Node, decls_start)[0..self.items_len];
|
||||
}
|
||||
|
||||
fn sizeInBytes(items_len: NodeIndex) usize {
|
||||
return @sizeOf(SwitchCase) + @sizeOf(*Node) * @as(usize, items_len);
|
||||
}
|
||||
};
|
||||
|
||||
pub const SwitchElse = struct {
|
||||
|
||||
@@ -2205,30 +2205,31 @@ const Parser = struct {
|
||||
/// <- SwitchItem (COMMA SwitchItem)* COMMA?
|
||||
/// / KEYWORD_else
|
||||
fn parseSwitchCase(p: *Parser) !?*Node {
|
||||
var list = Node.SwitchCase.ItemList{};
|
||||
var list_it = &list.first;
|
||||
var list = std.ArrayList(*Node).init(p.gpa);
|
||||
defer list.deinit();
|
||||
|
||||
if (try p.parseSwitchItem()) |first_item| {
|
||||
list_it = try p.llpush(*Node, list_it, first_item);
|
||||
try list.append(first_item);
|
||||
while (p.eatToken(.Comma) != null) {
|
||||
const next_item = (try p.parseSwitchItem()) orelse break;
|
||||
list_it = try p.llpush(*Node, list_it, next_item);
|
||||
try list.append(next_item);
|
||||
}
|
||||
} else if (p.eatToken(.Keyword_else)) |else_token| {
|
||||
const else_node = try p.arena.allocator.create(Node.SwitchElse);
|
||||
else_node.* = .{
|
||||
.token = else_token,
|
||||
};
|
||||
list_it = try p.llpush(*Node, list_it, &else_node.base);
|
||||
try list.append(&else_node.base);
|
||||
} else return null;
|
||||
|
||||
const node = try p.arena.allocator.create(Node.SwitchCase);
|
||||
const node = try Node.SwitchCase.alloc(&p.arena.allocator, list.items.len);
|
||||
node.* = .{
|
||||
.items = list,
|
||||
.items_len = list.items.len,
|
||||
.arrow_token = undefined, // set by caller
|
||||
.payload = null,
|
||||
.expr = undefined, // set by caller
|
||||
};
|
||||
std.mem.copy(*Node, node.items(), list.items);
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
|
||||
@@ -1613,37 +1613,35 @@ fn renderExpression(
|
||||
.SwitchCase => {
|
||||
const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
|
||||
|
||||
assert(switch_case.items.first != null);
|
||||
assert(switch_case.items_len != 0);
|
||||
const src_has_trailing_comma = blk: {
|
||||
const last_node = switch_case.items.first.?.findLast().data;
|
||||
const last_node = switch_case.items()[switch_case.items_len - 1];
|
||||
const maybe_comma = tree.nextToken(last_node.lastToken());
|
||||
break :blk tree.tokens[maybe_comma].id == .Comma;
|
||||
};
|
||||
|
||||
if (switch_case.items.first.?.next == null or !src_has_trailing_comma) {
|
||||
var it = switch_case.items.first;
|
||||
while (it) |node_node| : (it = node_node.next) {
|
||||
const node = node_node.data;
|
||||
if (node_node.next) |next_node| {
|
||||
if (switch_case.items_len == 1 or !src_has_trailing_comma) {
|
||||
const items = switch_case.items();
|
||||
for (items) |node, i| {
|
||||
if (i + 1 < items.len) {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
|
||||
|
||||
const comma_token = tree.nextToken(node.lastToken());
|
||||
try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
|
||||
try renderExtraNewline(tree, stream, start_col, next_node.data);
|
||||
try renderExtraNewline(tree, stream, start_col, items[i + 1]);
|
||||
} else {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var it = switch_case.items.first;
|
||||
while (it) |node_node| : (it = node_node.next) {
|
||||
const node = node_node.data;
|
||||
if (node_node.next) |next_node| {
|
||||
const items = switch_case.items();
|
||||
for (items) |node, i| {
|
||||
if (i + 1 < items.len) {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
|
||||
|
||||
const comma_token = tree.nextToken(node.lastToken());
|
||||
try renderToken(tree, stream, comma_token, indent, start_col, Space.Newline); // ,
|
||||
try renderExtraNewline(tree, stream, start_col, next_node.data);
|
||||
try renderExtraNewline(tree, stream, start_col, items[i + 1]);
|
||||
try stream.writeByteNTimes(' ', indent);
|
||||
} else {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Comma);
|
||||
|
||||
Reference in New Issue
Block a user