Skip to content

Commit 5f4418c

Browse files
committed
chore: trying to get to the bottom of an issue
1 parent c31af9f commit 5f4418c

5 files changed

Lines changed: 187 additions & 48 deletions

File tree

src/Document.zig

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,27 @@ root: Node = .{
99
.value = .document,
1010
},
1111

12+
pub const Options = struct {
13+
tokenizer_options: ?tokenizer.Options = null,
14+
parser_options: ?parser.Options = null,
15+
};
16+
1217
/// Parses BBCode text and builds the internal tree structure.
1318
///
1419
/// Takes a BBCode string and parses it into a tree of nodes
1520
/// that can be traversed using the document's methods or Walker.
1621
///
1722
/// Args:
1823
/// bbcode: BBCode string to parse
19-
pub fn load(allocator: Allocator, reader: std.io.AnyReader) !Document {
20-
var tokens = try tokenizer.tokenize(allocator, reader);
24+
pub fn load(allocator: Allocator, reader: std.io.AnyReader, options: Options) !Document {
25+
var tokens = try tokenizer.tokenize(allocator, reader, options.tokenizer_options orelse .{});
2126
defer tokens.deinit(allocator);
22-
return try parser.parse(allocator, tokens);
27+
return try parser.parse(allocator, tokens, options.parser_options orelse .{});
2328
}
2429

25-
pub fn loadFromBuffer(allocator: Allocator, bbcode: []const u8) !Document {
30+
pub fn loadFromBuffer(allocator: Allocator, bbcode: []const u8, options: Options) !Document {
2631
var fbs = std.io.fixedBufferStream(bbcode);
27-
return try load(allocator, fbs.reader().any());
32+
return try load(allocator, fbs.reader().any(), options);
2833
}
2934

3035
/// Frees resources associated with the document.

src/Node.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub fn getName(self: Node) ![]const u8 {
5959
switch (self.value) {
6060
.element => |v| return v.name,
6161
.text => |v| return v,
62-
else => return error.InvalidNodeType,
62+
.document => return "document",
6363
}
6464
}
6565

src/formatters/markdown.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ test render {
184184
\\[list][*]one[*]two[*]three[/list]
185185
;
186186

187-
var document = try Document.loadFromBuffer(testing.allocator, bbcode_document);
187+
var document = try Document.loadFromBuffer(testing.allocator, bbcode_document, .{});
188188
defer document.deinit();
189189

190190
var out_buffer = std.ArrayListUnmanaged(u8){};

src/parser.zig

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
pub fn parse(allocator: std.mem.Allocator, tokens: TokenResult) !Document {
1+
pub const Options = struct {};
2+
3+
pub fn parse(allocator: std.mem.Allocator, tokens: TokenResult, options: Options) !Document {
4+
_ = options;
5+
26
var doc = Document{
37
.arena = std.heap.ArenaAllocator.init(allocator),
48
};
@@ -41,13 +45,19 @@ pub fn parse(allocator: std.mem.Allocator, tokens: TokenResult) !Document {
4145
},
4246
.closingElement => {
4347
const item = stack.getLastOrNull() orelse {
48+
logger.err("Tried to pop from an empty stack.\nDocument: {s}\nCurrent: {s}\nToken: {s} {s}\nInput: {s}", .{ doc, try current.getName(), token.name, token.value orelse "", tokens });
4449
return error.UnexpectedClosingElement;
4550
};
4651

4752
if (std.mem.eql(u8, item, try current.getName())) {
4853
_ = stack.pop();
4954
current = current.parent orelse break;
5055
} else {
56+
logger.err("Unexpected closing element in document.\nDocument: {s}\nCurrent: {s}\nExpected: {s}", .{
57+
doc,
58+
try current.getName(),
59+
item,
60+
});
5161
return error.UnexpectedClosingElement;
5262
}
5363
},
@@ -81,9 +91,46 @@ pub fn parse(allocator: std.mem.Allocator, tokens: TokenResult) !Document {
8191
// }
8292
// }
8393

94+
test "complex parsing" {
95+
const bbcode =
96+
\\Converts one or more arguments of any type to string in the best way possible and prints them to the console.
97+
\\The following BBCode tags are supported: [code]b[/code], [code]i[/code], [code]u[/code], [code]s[/code], [code]indent[/code], [code]code[/code], [code]url[/code], [code]center[/code], [code]right[/code], [code]color[/code], [code]bgcolor[/code], [code]fgcolor[/code].
98+
\\URL tags only support URLs wrapped by a URL tag, not URLs with a different title.
99+
\\When printing to standard output, the supported subset of BBCode is converted to ANSI escape codes for the terminal emulator to display. Support for ANSI escape codes varies across terminal emulators, especially for italic and strikethrough. In standard output, [code]code[/code] is represented with faint text but without any font change. Unsupported tags are left as-is in standard output.
100+
\\[codeblocks]
101+
// \\[gdscript skip-lint]
102+
// \\print_rich("[color=green][b]Hello world![/b][/color]") # Prints "Hello world!", in green with a bold font.
103+
// \\[/gdscript]
104+
// \\[csharp skip-lint]
105+
// \\GD.PrintRich("[color=green][b]Hello world![/b][/color]"); // Prints "Hello world!", in green with a bold font.
106+
// \\[/csharp]
107+
\\[/codeblocks]
108+
\\[b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print] or [method print_rich]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed.
109+
\\[b]Note:[/b] On Windows, only Windows 10 and later correctly displays ANSI escape codes in standard output.
110+
\\[b]Note:[/b] Output displayed in the editor supports clickable [code skip-lint][url=address]text[/url][/code] tags. The [code skip-lint][url][/code] tag's [code]address[/code] value is handled by [method OS.shell_open] when clicked.
111+
;
112+
113+
var fbs = std.io.fixedBufferStream(bbcode);
114+
115+
var tokens = try tokenizer.tokenize(testing.allocator, fbs.reader().any(), .{
116+
.equals_required_in_parameters = false,
117+
});
118+
defer tokens.deinit(testing.allocator);
119+
120+
std.debug.print("Tokens: {s}\n", .{tokens});
121+
122+
var document = try parse(testing.allocator, tokens, .{});
123+
defer document.deinit();
124+
125+
// std.debug.print("Document: {s}\n", .{document});
126+
}
127+
128+
const testing = std.testing;
129+
const logger = std.log.scoped(.parser);
130+
const ArrayList = std.ArrayListUnmanaged;
131+
const TokenResult = tokenizer.TokenResult;
132+
84133
const std = @import("std");
85134
const tokenizer = @import("tokenizer.zig");
86-
const TokenResult = tokenizer.TokenResult;
87135
const Document = @import("Document.zig");
88-
const ArrayList = std.ArrayListUnmanaged;
89136
const Node = @import("Node.zig");

0 commit comments

Comments
 (0)