commit 1c42ebec4a31796e58576808fdac8556aef60805
parent f9a0127ec0fe3282cdf207309e4bc0686cc49de4
Author: gracefu <81774659+gracefuu@users.noreply.github.com>
Date: Wed, 21 May 2025 23:08:08 +0800
Shrink code size some more
Diffstat:
2 files changed, 107 insertions(+), 27 deletions(-)
diff --git a/src/AstGen3.zig b/src/AstGen3.zig
@@ -10,6 +10,7 @@ const Node = Ast.Node;
const Error = Ast.Error;
const IndentationScanner = @import("IndentationScanner.zig");
const IndentAlignment = IndentationScanner.IndentAlignment;
+const IndentOptions = IndentationScanner.IndentOptions;
const PaddedMany = @import("padded_str.zig").PaddedMany;
const PaddedSlice = @import("padded_str.zig").PaddedSlice;
const str = @import("str.zig");
@@ -66,6 +67,22 @@ fn appendNode(self: *AstGen, node: Node) !Node.Idx {
}
return @enumFromInt(idx);
}
+fn ensureUnusedCapacityNode(self: *AstGen, additional_count: usize) !void {
+ if (self.nodes.items.len > (1 << @bitSizeOf(
+ @typeInfo(Node.Idx).@"enum".tag_type,
+ )) - additional_count) return error.OutOfNodeIdx;
+ return self.nodes.ensureUnusedCapacity(self.gpa, additional_count);
+}
+fn appendAssumeCapacityNode(self: *AstGen, node: Node) Node.Idx {
+ const idx = self.nodes.items.len;
+ const cap = if (PRINT_ALLOC_STATS) self.nodes.capacity;
+ self.nodes.appendAssumeCapacity(node);
+ if (PRINT_ALLOC_STATS and cap != self.nodes.capacity) {
+ self.num_node_allocs += 1;
+ }
+ return @enumFromInt(idx);
+}
+
fn appendContainerNode(self: *AstGen, parent_idx: Node.Idx, container_node_tag: Node.Tag, ptr: PaddedMany) !Node.Idx {
self.getNode(parent_idx).incrementNumChildren();
switch (container_node_tag) {
@@ -119,6 +136,59 @@ fn appendLeafNode(self: *AstGen, parent_idx: Node.Idx, leaf_node_tag: Node.Tag,
}
}
+fn appendAssumeCapacityContainerNode(self: *AstGen, parent_idx: Node.Idx, container_node_tag: Node.Tag, ptr: PaddedMany) Node.Idx {
+ self.getNode(parent_idx).incrementNumChildren();
+ switch (container_node_tag) {
+ .document => unreachable,
+
+ .list,
+ .heading,
+ .quote,
+ .paragraph,
+ .unordered_item,
+ .ordered_item,
+ .term_item,
+ .task_item,
+ .elaboration,
+ => return self.appendAssumeCapacityNode(.{
+ .data = .{ .list = .{ .off = @intCast(self.input.ptr.calcOffsetTo(ptr)) } },
+ .tag = container_node_tag,
+ }),
+
+ .marker,
+ .thematic_break,
+ .text,
+ .space_text,
+ => unreachable,
+ }
+}
+fn appendAssumeCapacityLeafNode(self: *AstGen, parent_idx: Node.Idx, leaf_node_tag: Node.Tag, ptr: PaddedMany, len: StrLen) Node.Idx {
+ self.getNode(parent_idx).incrementNumChildren();
+ switch (leaf_node_tag) {
+ .document => unreachable,
+
+ .list,
+ .heading,
+ .quote,
+ .paragraph,
+ .unordered_item,
+ .ordered_item,
+ .term_item,
+ .task_item,
+ .elaboration,
+ => unreachable,
+
+ .marker,
+ .thematic_break,
+ .text,
+ .space_text,
+ => return self.appendAssumeCapacityNode(.{
+ .data = .{ .text = .{ .off = @intCast(self.input.ptr.calcOffsetTo(ptr)), .len = len } },
+ .tag = leaf_node_tag,
+ }),
+ }
+}
+
fn appendError(self: *AstGen, err: Error) !void {
if (self.errors.items.len > std.math.maxInt(
@typeInfo(Error.Idx).@"enum".tag_type,
@@ -277,7 +347,7 @@ fn parseRoot(self: *AstGen) !void {
assert(root == .root);
if (self.scanner.peek()) |p| assert(self.input.ptr._ptr == p.@"1".ptr._ptr);
- _ = try self.parseColumn(root);
+ _ = try self.parseColumn(root, null);
assert(self.scanner.peek() == null);
}
@@ -289,7 +359,13 @@ fn parseRoot(self: *AstGen) !void {
fn parseInlineColumn(
self: *AstGen,
parent_idx: Node.Idx,
+ indent_opts: IndentOptions,
) !void {
+ var error_state = false;
+ try self.scanner.indent(indent_opts);
+ defer if (!error_state) self.scanner.dedent();
+ errdefer error_state = true;
+
// TODO: Inline parsing
{
var peek_maybe = self.scanner.peek();
@@ -325,7 +401,13 @@ fn parseInlineColumn(
fn parseColumn(
self: *AstGen,
parent_idx: Node.Idx,
+ indent_opts_maybe: ?IndentOptions,
) !void {
+ var error_state = false;
+ if (indent_opts_maybe) |indent_opts| try self.scanner.indent(indent_opts);
+ defer if (indent_opts_maybe != null and !error_state) self.scanner.dedent();
+ errdefer error_state = true;
+
// The type of list and the idx of the list node
var current_list: ?struct { Node.Tag, Node.Idx } = null;
// The elaboratable node idx and the required length of the elaboration marker
@@ -361,12 +443,11 @@ fn parseColumn(
inline '#' => {
const marker_len = line.indexOfNotChar('#');
tracy_frame.setName(@tagName(.heading));
- const block_idx = try self.appendContainerNode(parent_idx, .heading, line.ptr);
- _ = try self.appendLeafNode(block_idx, .marker, line.ptr, try castStrLen(marker_len, error.MarkerTooLong));
+ try self.ensureUnusedCapacityNode(2);
+ const block_idx = self.appendAssumeCapacityContainerNode(parent_idx, .heading, line.ptr);
+ _ = self.appendAssumeCapacityLeafNode(block_idx, .marker, line.ptr, try castStrLen(marker_len, error.MarkerTooLong));
last_elaboratable_idx = .{ block_idx, marker_len };
- try self.scanner.indent(.{ .skip = line_start + marker_len });
- try self.parseInlineColumn(block_idx);
- self.scanner.dedent();
+ try self.parseInlineColumn(block_idx, .{ .skip = line_start + marker_len });
break :block_idx block_idx;
},
@@ -393,21 +474,22 @@ fn parseColumn(
tracy_frame.setName(@tagName(@as(Node.Tag, @enumFromInt(m))));
break :blk .{ base_marker_len, @enumFromInt(m) };
};
+ try self.ensureUnusedCapacityNode(3);
const list_node_idx = blk: {
if (current_list) |cur| {
const cur_tag, const cur_node_idx = cur;
- if (list_type == cur_tag) break :blk cur_node_idx;
+ if (list_type == cur_tag) {
+ break :blk cur_node_idx;
+ }
}
- const list_node_idx = try self.appendContainerNode(parent_idx, .list, line.ptr);
+ const list_node_idx = self.appendAssumeCapacityContainerNode(parent_idx, .list, line.ptr);
current_list = .{ list_type, list_node_idx };
break :blk list_node_idx;
};
- const block_idx = try self.appendContainerNode(list_node_idx, list_type, line.ptr);
- _ = try self.appendLeafNode(block_idx, .marker, line.ptr, try castStrLen(marker_len, error.MarkerTooLong));
+ const block_idx = self.appendAssumeCapacityContainerNode(list_node_idx, list_type, line.ptr);
+ _ = self.appendAssumeCapacityLeafNode(block_idx, .marker, line.ptr, try castStrLen(marker_len, error.MarkerTooLong));
last_elaboratable_idx = .{ block_idx, base_marker_len };
- try self.scanner.indent(.{ .skip = line_start + marker_len });
- try self.parseInlineColumn(block_idx);
- self.scanner.dedent();
+ try self.parseInlineColumn(block_idx, .{ .skip = line_start + marker_len });
break :block_idx block_idx;
},
@@ -415,21 +497,20 @@ fn parseColumn(
inline '+' => {
tracy_frame.setName(@tagName(.elaboration));
const marker_len = try castStrLen(line.indexOfNotChar('+'), error.MarkerTooLong);
+ try self.ensureUnusedCapacityNode(2);
const block_idx = if (last_elaboratable_idx) |elab| blk: {
const elaboratable_idx, const required_marker_len = elab;
- const block_idx = try self.appendContainerNode(elaboratable_idx, .elaboration, line.ptr);
+ const block_idx = self.appendAssumeCapacityContainerNode(elaboratable_idx, .elaboration, line.ptr);
if (marker_len != required_marker_len)
try self.appendNodeError(.incorrect_elaboration_marker, elaboratable_idx);
break :blk block_idx;
} else blk: {
- const block_idx = try self.appendContainerNode(parent_idx, .elaboration, line.ptr);
+ const block_idx = self.appendAssumeCapacityContainerNode(parent_idx, .elaboration, line.ptr);
try self.appendNodeError(.elaboration_after_unelaboratable_node, block_idx);
break :blk block_idx;
};
- _ = try self.appendLeafNode(block_idx, .marker, line.ptr, marker_len);
- try self.scanner.indent(.{ .skip = line_start + marker_len });
- try self.parseColumn(block_idx);
- self.scanner.dedent();
+ _ = self.appendAssumeCapacityLeafNode(block_idx, .marker, line.ptr, marker_len);
+ try self.parseColumn(block_idx, .{ .skip = line_start + marker_len });
break :block_idx block_idx;
},
@@ -438,9 +519,7 @@ fn parseColumn(
tracy_frame.setName(@tagName(@as(Node.Tag, @enumFromInt(m))));
const block_idx = try self.appendContainerNode(parent_idx, @enumFromInt(m), line.ptr);
last_elaboratable_idx = null;
- try self.scanner.indent(.{ .skip = line_start + 1 });
- try self.parseInlineColumn(block_idx);
- self.scanner.dedent();
+ try self.parseInlineColumn(block_idx, .{ .skip = line_start + 1 });
break :block_idx block_idx;
},
@@ -449,9 +528,7 @@ fn parseColumn(
tracy_frame.setName(@tagName(@as(Node.Tag, @enumFromInt(m))));
const block_idx = try self.appendContainerNode(parent_idx, @enumFromInt(m), line.ptr);
last_elaboratable_idx = null;
- try self.scanner.indent(.{ .skip = line_start + 1 });
- try self.parseColumn(block_idx);
- self.scanner.dedent();
+ try self.parseColumn(block_idx, .{ .skip = line_start + 1 });
break :block_idx block_idx;
},
@@ -473,7 +550,8 @@ fn parseColumn(
// Parse paragraph
{
tracy_frame.setName(@tagName(.paragraph));
- const paragraph_idx = try self.appendContainerNode(parent_idx, .paragraph, line.ptr);
+ try self.ensureUnusedCapacityNode(3);
+ const paragraph_idx = self.appendAssumeCapacityContainerNode(parent_idx, .paragraph, line.ptr);
last_elaboratable_idx = null;
try self.insertTextLine(.text, .text, paragraph_idx, line);
self.scanner.advance();
diff --git a/src/IndentationScanner.zig b/src/IndentationScanner.zig
@@ -266,6 +266,8 @@ pub noinline fn advance(it: *IndentationScanner) void {
} else unreachable;
}
+pub const IndentOptions = struct { skip: usize };
+
/// Treats the next `skip` characters as whitespace,
/// finds the correct level of indentation,
/// then pushes it onto the indentation stack.
@@ -273,7 +275,7 @@ pub noinline fn advance(it: *IndentationScanner) void {
/// Precondition: peek() would not have returned null.
pub fn indent(
it: *IndentationScanner,
- opts: struct { skip: usize },
+ opts: IndentOptions,
) error{TooMuchIndentation}!void {
const level, const spaces, const content = it._cur_line orelse unreachable;
assert(level.compare(.eq, it.curLevel()));