mymarkdown

My markdown
git clone https://git.grace.moe/mymarkdown
Log | Files | Refs

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:
Msrc/AstGen3.zig | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/IndentationScanner.zig | 4+++-
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()));