|
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 | + |
2 | 6 | var doc = Document{ |
3 | 7 | .arena = std.heap.ArenaAllocator.init(allocator), |
4 | 8 | }; |
@@ -41,13 +45,19 @@ pub fn parse(allocator: std.mem.Allocator, tokens: TokenResult) !Document { |
41 | 45 | }, |
42 | 46 | .closingElement => { |
43 | 47 | 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 }); |
44 | 49 | return error.UnexpectedClosingElement; |
45 | 50 | }; |
46 | 51 |
|
47 | 52 | if (std.mem.eql(u8, item, try current.getName())) { |
48 | 53 | _ = stack.pop(); |
49 | 54 | current = current.parent orelse break; |
50 | 55 | } else { |
| 56 | + logger.err("Unexpected closing element in document.\nDocument: {s}\nCurrent: {s}\nExpected: {s}", .{ |
| 57 | + doc, |
| 58 | + try current.getName(), |
| 59 | + item, |
| 60 | + }); |
51 | 61 | return error.UnexpectedClosingElement; |
52 | 62 | } |
53 | 63 | }, |
@@ -81,9 +91,46 @@ pub fn parse(allocator: std.mem.Allocator, tokens: TokenResult) !Document { |
81 | 91 | // } |
82 | 92 | // } |
83 | 93 |
|
| 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 | + |
84 | 133 | const std = @import("std"); |
85 | 134 | const tokenizer = @import("tokenizer.zig"); |
86 | | -const TokenResult = tokenizer.TokenResult; |
87 | 135 | const Document = @import("Document.zig"); |
88 | | -const ArrayList = std.ArrayListUnmanaged; |
89 | 136 | const Node = @import("Node.zig"); |
0 commit comments