aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/paragraph.zig8
-rw-r--r--src/parser.zig21
-rw-r--r--src/title.zig7
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;
}