aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ast.zig50
-rw-r--r--src/paragraph.zig59
2 files changed, 73 insertions, 36 deletions
diff --git a/src/ast.zig b/src/ast.zig
index 94bb2c5..e5a9ea2 100644
--- a/src/ast.zig
+++ b/src/ast.zig
@@ -3,6 +3,7 @@ const Lexed = @import("lexer/Lexed.zig");
const Lexer = @import("lexer/Lexer.zig");
const Element = @import("dom/Element.zig");
const Allocator = std.mem.Allocator;
+const paragraph = @import("paragraph.zig");
pub const Error = error{
InvalidSequence,
@@ -20,7 +21,7 @@ pub fn parse(parent: Allocator, content: []const u8) Error![]const u8 {
var l = try Lexer.init(content);
while (l.nextKind()) |it| {
switch (it) {
- .literal, .bold, .italic, .code => try elements.append(alloc, try parseContent(alloc, &l)),
+ .literal, .bold, .italic, .code => try elements.append(alloc, try paragraph.parseParagraph(alloc, &l)),
else => return Error.FeatureNotSupported,
}
}
@@ -33,37 +34,6 @@ pub fn parse(parent: Allocator, content: []const u8) Error![]const u8 {
return res.toOwnedSlice(parent);
}
-fn parseContent(alloc: Allocator, l: *Lexer) Error!Element {
- var content = Element.initEmpty(alloc);
- const v = (try l.next(alloc)).?;
- switch (v.kind) {
- .literal => {
- const el = try Element.initLitEscaped(alloc, v.content.items);
- try content.appendContent(el);
- },
- .bold => try content.appendContent(try parseModifier(alloc, l, .bold, "b")),
- .italic => try content.appendContent(try parseModifier(alloc, l, .italic, "em")),
- .code => try content.appendContent(try parseModifier(alloc, l, .code, "code")),
- else => return Error.InvalidSequence,
- }
- return content;
-}
-
-fn parseModifier(alloc: Allocator, l: *Lexer, knd: Lexed.Kind, tag: []const u8) Error!Element {
- var el = try Element.init(alloc, .content, tag);
- while (l.nextKind()) |it| {
- if (it == knd) {
- // consuming the finisher
- var v = (try l.next(alloc)).?;
- v.deinit();
- break;
- }
- if (it.isDelimiter()) return Error.UnclosedModifier;
- try el.appendContent(try parseContent(alloc, l));
- }
- return el;
-}
-
fn doTest(alloc: Allocator, t: []const u8, v: []const u8) !void {
const g = try parse(alloc, t);
defer alloc.free(g);
@@ -73,12 +43,20 @@ fn doTest(alloc: Allocator, t: []const u8, v: []const u8) !void {
};
}
-test "parse content" {
+test "parse paragraphs" {
var arena = std.heap.DebugAllocator(.{}).init;
defer if (arena.deinit() == .leak) std.debug.print("leaking!\n", .{});
const alloc = arena.allocator();
- try doTest(alloc, "hello world", "hello world");
- try doTest(alloc, "*hello* world", "<b>hello</b> world");
- try doTest(alloc, "*he_ll_o* world", "<b>he<em>ll</em>o</b> world");
+ try doTest(alloc, "hello world", "<p>hello world</p>");
+ try doTest(alloc, "*hello* world", "<p><b>hello</b> world</p>");
+ try doTest(alloc, "*he_ll_o* world", "<p><b>he<em>ll</em>o</b> world</p>");
+
+ try doTest(alloc,
+ \\hello
+ \\world
+ \\
+ \\foo bar
+ \\in new paragraph
+ , "<p>hello world</p><p>foo bar in new paragraph</p>");
}
diff --git a/src/paragraph.zig b/src/paragraph.zig
new file mode 100644
index 0000000..75651f4
--- /dev/null
+++ b/src/paragraph.zig
@@ -0,0 +1,59 @@
+const std = @import("std");
+const Lexed = @import("lexer/Lexed.zig");
+const Lexer = @import("lexer/Lexer.zig");
+const Element = @import("dom/Element.zig");
+const Allocator = std.mem.Allocator;
+const ast = @import("ast.zig");
+const Error = ast.Error;
+
+pub fn parseParagraph(alloc: Allocator, l: *Lexer) Error!Element {
+ var el = try Element.init(alloc, .content, "p");
+ while (l.nextKind()) |kind| {
+ switch (kind) {
+ // because nextKind returns only an hint for the next rune
+ .weak_delimiter => {
+ var v = (try l.next(alloc)).?;
+ defer v.deinit();
+ if (v.kind == .strong_delimiter) return el;
+ const next = l.nextKind() orelse return el;
+ switch (next) {
+ .literal, .italic, .code, .bold => try el.appendContent(try Element.initLit(alloc, " ")),
+ else => return el,
+ }
+ },
+ else => try el.appendContent(try parseContent(alloc, l)),
+ }
+ }
+ return el;
+}
+
+pub fn parseContent(alloc: Allocator, l: *Lexer) Error!Element {
+ var content = Element.initEmpty(alloc);
+ const v = (try l.next(alloc)).?;
+ switch (v.kind) {
+ .literal => {
+ const el = try Element.initLitEscaped(alloc, v.content.items);
+ try content.appendContent(el);
+ },
+ .bold => try content.appendContent(try parseModifier(alloc, l, .bold, "b")),
+ .italic => try content.appendContent(try parseModifier(alloc, l, .italic, "em")),
+ .code => try content.appendContent(try parseModifier(alloc, l, .code, "code")),
+ else => return Error.InvalidSequence,
+ }
+ return content;
+}
+
+fn parseModifier(alloc: Allocator, l: *Lexer, knd: Lexed.Kind, tag: []const u8) Error!Element {
+ var el = try Element.init(alloc, .content, tag);
+ while (l.nextKind()) |it| {
+ if (it == knd) {
+ // consuming the finisher
+ var v = (try l.next(alloc)).?;
+ v.deinit();
+ break;
+ }
+ if (it.isDelimiter()) return Error.UnclosedModifier;
+ try el.appendContent(try parseContent(alloc, l));
+ }
+ return el;
+}