diff options
| author | Anhgelus Morhtuuzh <william@herges.fr> | 2026-04-18 20:21:10 +0200 |
|---|---|---|
| committer | Anhgelus Morhtuuzh <william@herges.fr> | 2026-04-18 20:21:10 +0200 |
| commit | 8c5214df39ab82c3d42ccd492d8699f8a5aadb0a (patch) | |
| tree | 3ca338fffd31620470a898fd900c7a5f12188c5a /src | |
| parent | 9b47b7ee8b80bf427116b4d2cf42e6f3c9d8be62 (diff) | |
feat(ast): test errors
Diffstat (limited to 'src')
| -rw-r--r-- | src/paragraph.zig | 8 | ||||
| -rw-r--r-- | src/parser.zig | 21 | ||||
| -rw-r--r-- | src/title.zig | 7 |
3 files changed, 25 insertions, 11 deletions
diff --git a/src/paragraph.zig b/src/paragraph.zig index 86d074b..8cdaeb0 100644 --- a/src/paragraph.zig +++ b/src/paragraph.zig @@ -5,7 +5,7 @@ const Lexer = @import("lexer/Lexer.zig"); const Element = @import("dom/Element.zig"); const parser = @import("parser.zig"); -pub const Error = error{UnclosedModifier} || Lexer.Error; +pub const Error = error{ModifierNotClosed} || Lexer.Error; pub fn parse(alloc: Allocator, l: *Lexer) Error!Element { var el = try Element.init(alloc, .content, "p"); @@ -51,10 +51,10 @@ fn parseModifier(alloc: Allocator, l: *Lexer, knd: Lexed.Kind, tag: []const u8) // consuming the finisher var v = (try l.next(alloc)).?; v.deinit(); - break; + return el; } - if (it.isDelimiter()) return Error.UnclosedModifier; + if (it.isDelimiter()) return Error.ModifierNotClosed; try el.appendContent(try parseContent(alloc, l)); } - return el; + return Error.ModifierNotClosed; } diff --git a/src/parser.zig b/src/parser.zig index 5f8c676..af571d4 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -7,9 +7,8 @@ const paragraph = @import("paragraph.zig"); const title = @import("title.zig"); pub const Error = error{ - InvalidSequence, FeatureNotSupported, -} || Lexer.Error || paragraph.Error; +} || Lexer.Error || paragraph.Error || title.Error; pub fn parse(parent: Allocator, content: []const u8) Error![]const u8 { var arena = std.heap.ArenaAllocator.init(parent); @@ -19,20 +18,21 @@ pub fn parse(parent: Allocator, content: []const u8) Error![]const u8 { var elements = try std.ArrayList(Element).initCapacity(alloc, 2); var l = try Lexer.init(content); - while (l.nextKind()) |it| { + base: while (l.nextKind()) |it| { try elements.append(alloc, switch (it) { .literal, .bold, .italic, .code => try paragraph.parse(alloc, &l), .title => try title.parse(alloc, &l), .weak_delimiter, .strong_delimiter => { var v = (try l.next(alloc)).?; v.deinit(); - continue; + continue :base; }, else => return Error.FeatureNotSupported, }); } var res = try std.ArrayList(u8).initCapacity(parent, elements.items.len); + errdefer res.deinit(parent); for (elements.items) |it| { var v = it; try res.appendSlice(parent, try v.render(alloc)); @@ -49,6 +49,11 @@ fn doTest(alloc: Allocator, t: []const u8, v: []const u8) !void { }; } +fn doTestError(alloc: Allocator, t: []const u8, err: Error) !void { + _ = parse(alloc, t) catch |e| return std.testing.expect(err == e); + return std.testing.expect(false); +} + test "parse paragraphs" { var arena = std.heap.DebugAllocator(.{}).init; defer if (arena.deinit() == .leak) std.debug.print("leaking!\n", .{}); @@ -65,13 +70,17 @@ test "parse paragraphs" { \\foo bar \\in new paragraph , "<p>hello world</p><p>foo bar in new paragraph</p>"); + + try doTestError(alloc, "hello *world", Error.ModifierNotClosed); + try doTestError(alloc, "hello *wo_rld*", Error.ModifierNotClosed); + try doTestError(alloc, "*hell*o *wo_rld*", Error.ModifierNotClosed); } test "parse title" { var arena = std.heap.DebugAllocator(.{}).init; defer if (arena.deinit() == .leak) std.debug.print("leaking!\n", .{}); const alloc = arena.allocator(); - + try doTest(alloc, "# hey", "<h1>hey</h1>"); try doTest(alloc, "## hey", "<h2>hey</h2>"); try doTest(alloc, "### hey", "<h3>hey</h3>"); @@ -82,4 +91,6 @@ test "parse title" { \\## subtitle \\hehe , "<h1>title</h1><p>hello world ;3</p><h2>subtitle</h2><p>hehe</p>"); + + try doTestError(alloc, "# aa :::", Error.InvalidTitleContent); } diff --git a/src/title.zig b/src/title.zig index 88848e5..d9b5612 100644 --- a/src/title.zig +++ b/src/title.zig @@ -5,10 +5,10 @@ const Lexer = @import("lexer/Lexer.zig"); const Element = @import("dom/Element.zig"); const paragraph = @import("paragraph.zig"); -pub const Error = paragraph.Error || Lexer.Error; +pub const Error = error{InvalidTitleContent} || paragraph.Error || Lexer.Error; pub fn parse(alloc: Allocator, l: *Lexer) Error!Element { - const v = (try l.next(alloc)).?; + var v = (try l.next(alloc)).?; var el = try Element.init(alloc, .content, switch (v.content.items.len) { 1 => "h1", 2 => "h2", @@ -19,5 +19,8 @@ pub fn parse(alloc: Allocator, l: *Lexer) Error!Element { else => unreachable, }); try el.appendContent(try paragraph.parseContent(alloc, l)); + v = (try l.next(alloc)) orelse return el; + if (!v.kind.isDelimiter()) return Error.InvalidTitleContent; + v.deinit(); return el; } |
