aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/code.zig1
-rw-r--r--src/content.zig2
-rw-r--r--src/eval/Element.zig43
-rw-r--r--src/eval/Image.zig16
-rw-r--r--src/eval/Root.zig53
-rw-r--r--src/eval/Title.zig12
-rw-r--r--src/eval/blocks.zig26
-rw-r--r--src/eval/list.zig15
-rw-r--r--src/eval/paragraph.zig17
-rw-r--r--src/link.zig16
-rw-r--r--src/list.zig2
-rw-r--r--src/paragraph.zig14
-rw-r--r--src/parser.zig32
-rw-r--r--src/testing.zig14
-rw-r--r--src/title.zig1
15 files changed, 92 insertions, 172 deletions
diff --git a/src/code.zig b/src/code.zig
index 7b7d23a..5c5c0f2 100644
--- a/src/code.zig
+++ b/src/code.zig
@@ -25,7 +25,6 @@ pub fn parse(alloc: Allocator, l: *Lexer) Error!Element {
const code = try Element.Code.init(alloc);
code.attribute = data;
const el = try Element.Figure.init(alloc, code.element());
- errdefer el.deinit(alloc);
while (l.next()) |it| {
if (it.kind == .code_block) return Error.InvalidCodeBlock;
if (it.kind.isDelimiter()) {
diff --git a/src/content.zig b/src/content.zig
index b1ac0c7..96a361a 100644
--- a/src/content.zig
+++ b/src/content.zig
@@ -13,7 +13,6 @@ pub const Error = error{ ModifierNotClosed, IllegalPlacement } || Allocator.Erro
pub fn parse(alloc: Allocator, l: *Lexer) Error!Element {
var content = try Element.Empty.init(alloc);
- errdefer content.deinit(alloc);
const v = l.next().?;
switch (v.kind) {
.literal => {
@@ -30,7 +29,6 @@ pub fn parse(alloc: Allocator, l: *Lexer) Error!Element {
fn parseModifier(alloc: Allocator, l: *Lexer, knd: Token.Kind, comptime tag: []const u8) Error!Element {
var el = try Element.Simple(tag).init(alloc);
- errdefer el.deinit(alloc);
while (l.peek()) |next| {
if (next.kind == knd) {
// consuming the finisher
diff --git a/src/eval/Element.zig b/src/eval/Element.zig
index 265ccf1..72b6d7d 100644
--- a/src/eval/Element.zig
+++ b/src/eval/Element.zig
@@ -5,6 +5,7 @@ pub const paragraph = @import("paragraph.zig");
pub const Title = @import("Title.zig");
pub const list = @import("list.zig");
pub const Image = @import("Image.zig");
+pub const Root = @import("Root.zig");
const blocks = @import("blocks.zig");
pub const Code = blocks.Code;
pub const Figure = blocks.Figure;
@@ -12,7 +13,6 @@ pub const Figure = blocks.Figure;
const Element = @This();
vtable: struct {
- deinit: *const fn (*anyopaque, Allocator) void,
html: *const fn (*anyopaque, Allocator) HTML.Error!HTML,
},
ptr: *anyopaque,
@@ -24,10 +24,6 @@ pub fn renderHTML(self: Element, alloc: Allocator) HTML.Error![]const u8 {
return el.render(alloc);
}
-pub fn deinit(self: Element, alloc: Allocator) void {
- self.vtable.deinit(self.ptr, alloc);
-}
-
pub fn html(self: Element, alloc: Allocator) HTML.Error!HTML {
return self.vtable.html(self.ptr, alloc);
}
@@ -44,18 +40,7 @@ pub const Empty = struct {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = Self.html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- const self: *Self = @ptrCast(@alignCast(context));
- for (self.content.items) |it| it.deinit(alloc);
- self.content.deinit(alloc);
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = Self.html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
@@ -79,16 +64,7 @@ pub const Literal = struct {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = Self.html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- const self: *Self = @ptrCast(@alignCast(context));
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = Self.html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
@@ -110,11 +86,7 @@ pub fn Simple(comptime tag: []const u8) type {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = Self.html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
+ return .{ .ptr = self, .vtable = .{ .html = Self.html } };
}
pub fn toTag(self: *Self, alloc: Allocator, comptime target: []const u8) !*Simple(target) {
@@ -135,13 +107,6 @@ pub fn Simple(comptime tag: []const u8) type {
alloc.destroy(self);
}
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- var self: *Self = @ptrCast(@alignCast(context));
- for (self.content.items) |it| it.deinit(alloc);
- self.content.deinit(alloc);
- alloc.destroy(self);
- }
-
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
const self: *Self = @ptrCast(@alignCast(context));
var el = try HTML.Content.init(alloc, tag);
diff --git a/src/eval/Image.zig b/src/eval/Image.zig
index aa30585..53478b6 100644
--- a/src/eval/Image.zig
+++ b/src/eval/Image.zig
@@ -17,16 +17,7 @@ pub fn init(alloc: Allocator, src: []const u8) !*Self {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = html } };
-}
-
-pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
-}
-
-fn destroy(context: *anyopaque, alloc: Allocator) void {
- const self: *Self = @ptrCast(@alignCast(context));
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
@@ -38,12 +29,13 @@ fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
}
test "html" {
- const alloc = std.testing.allocator;
+ var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena.deinit();
+ var alloc = arena.allocator();
const expect = std.testing.expect;
const eql = std.mem.eql;
var img = try init(alloc, "foo");
- defer img.deinit(alloc);
const h = try img.element().renderHTML(alloc);
defer alloc.free(h);
try expect(eql(u8, h, "<img src=\"foo\">"));
diff --git a/src/eval/Root.zig b/src/eval/Root.zig
new file mode 100644
index 0000000..1834dd0
--- /dev/null
+++ b/src/eval/Root.zig
@@ -0,0 +1,53 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const Arena = std.heap.ArenaAllocator;
+const HTML = @import("html/Element.zig");
+const Element = @import("Element.zig");
+
+const Self = @This();
+
+content: std.ArrayList(Element),
+arena: Arena,
+
+pub fn init(parent: Allocator) !*Self {
+ var s = Self{
+ .content = undefined,
+ .arena = .init(parent),
+ };
+ var alloc = s.arena.allocator();
+ s.content = try .initCapacity(alloc, 2);
+ const v = try alloc.create(Self);
+ v.* = s;
+ return v;
+}
+
+pub fn deinit(self: *Self) void {
+ self.arena.deinit();
+}
+
+pub fn allocator(self: *Self) Allocator {
+ return self.arena.allocator();
+}
+
+pub fn append(self: *Self, el: Element) !void {
+ try self.content.append(self.allocator(), el);
+}
+
+pub fn element(self: *Self) Element {
+ return .{ .vtable = .{ .html = html }, .ptr = self };
+}
+
+pub fn renderHTML(self: *Self, alloc: Allocator) HTML.Error![]const u8 {
+ return try self.element().renderHTML(alloc);
+}
+
+fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
+ const self: *Self = @ptrCast(@alignCast(context));
+ const el = try HTML.Root.init(alloc);
+ errdefer el.deinit();
+ if (self.content.items.len == 0) return el.element();
+ for (self.content.items) |it| {
+ try el.append(try it.html(el.allocator()));
+ }
+ return el.element();
+}
diff --git a/src/eval/Title.zig b/src/eval/Title.zig
index 2e89953..ebb7fa2 100644
--- a/src/eval/Title.zig
+++ b/src/eval/Title.zig
@@ -15,17 +15,7 @@ pub fn init(alloc: Allocator, level: u3, content: Parent) !*Self {
}
pub fn element(self: *Self) Parent {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = html } };
-}
-
-pub fn deinit(self: *Self, alloc: Allocator) void {
- self.element().deinit(alloc);
-}
-
-fn destroy(context: *anyopaque, alloc: Allocator) void {
- var self: *Self = @ptrCast(@alignCast(context));
- self.content.deinit(alloc);
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
diff --git a/src/eval/blocks.zig b/src/eval/blocks.zig
index 63a8f12..63c0291 100644
--- a/src/eval/blocks.zig
+++ b/src/eval/blocks.zig
@@ -16,18 +16,7 @@ pub const Code = struct {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = Self.html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- var self: *Self = @ptrCast(@alignCast(context));
- for (self.content.items) |it| it.deinit(alloc);
- self.content.deinit(alloc);
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = Self.html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
@@ -54,18 +43,7 @@ pub const Figure = struct {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = Self.html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- const self: *Self = @ptrCast(@alignCast(context));
- self.content.deinit(alloc);
- if (self.caption) |cap| cap.deinit(alloc);
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = Self.html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
diff --git a/src/eval/list.zig b/src/eval/list.zig
index 08f180a..06b7af7 100644
--- a/src/eval/list.zig
+++ b/src/eval/list.zig
@@ -18,21 +18,10 @@ fn List(comptime tag: []const u8) type {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = html } };
+ return .{ .ptr = self, .vtable = .{ .html = html } };
}
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- var self: *Self = @ptrCast(@alignCast(context));
- for (self.content.items) |it| it.deinit(alloc);
- self.content.deinit(alloc);
- alloc.destroy(self);
- }
-
- fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
+ fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
const self: *Self = @ptrCast(@alignCast(context));
var el = try HTML.Content.init(alloc, tag);
for (self.content.items) |it| {
diff --git a/src/eval/paragraph.zig b/src/eval/paragraph.zig
index b076081..e57f995 100644
--- a/src/eval/paragraph.zig
+++ b/src/eval/paragraph.zig
@@ -26,17 +26,7 @@ pub const Link = struct {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- var self: *Self = @ptrCast(@alignCast(context));
- self.content.deinit(alloc);
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
@@ -59,14 +49,15 @@ fn doTest(alloc: Allocator, el: Element, exp: []const u8) !void {
}
test "paragraph" {
- const alloc = std.testing.allocator;
+ var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena.deinit();
+ const alloc = arena.allocator();
const lit = (try Element.Literal.init(alloc, "hello world")).element();
try doTest(alloc, lit, "hello world");
var p = try Block.init(alloc);
try p.content.append(alloc, lit);
- defer p.deinit(alloc);
try doTest(alloc, p.element(), "<p>hello world</p>");
const link = (try Link.init(alloc, (try Element.Literal.init(alloc, "foo")).element(), "example.org")).element();
diff --git a/src/link.zig b/src/link.zig
index ef92b1c..07cbf95 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -18,7 +18,6 @@ pub fn parse(alloc: Allocator, l: *Lexer) Error!Element {
if (v.kind != .link) return Error.InvalidLink;
if (!eql(u8, v.content, "[")) return (try Element.Literal.init(alloc, v.content)).element();
var el = try Element.Empty.init(alloc);
- errdefer el.deinit(alloc);
while (l.peek()) |next| switch (next.kind) {
.weak_delimiter, .strong_delimiter => return Error.InvalidLink,
.link => {
@@ -35,14 +34,10 @@ pub fn parse(alloc: Allocator, l: *Lexer) Error!Element {
if (href.kind != .literal) return Error.InvalidLink;
const finisher = l.next() orelse return Error.InvalidLink;
if (!finisher.equals(.link, ")")) return Error.InvalidLink;
- var in: Element = undefined;
- if (el.content.items.len > 0) {
- in = el.element();
- } else {
- el.deinit(alloc);
- in = (try Element.Literal.init(alloc, href.content)).element();
- }
- errdefer in.deinit(alloc);
+ const in: Element = if (el.content.items.len > 0)
+ el.element()
+ else
+ (try Element.Literal.init(alloc, href.content)).element();
return (try Link.init(alloc, in, href.content)).element();
}
@@ -69,10 +64,8 @@ pub fn parseImage(alloc: Allocator, l: *Lexer) ImageError!Element {
it = l.next() orelse return ImageError.InvalidImage;
if (!it.equals(.link, ")")) return ImageError.InvalidImage;
const img = try Element.Image.init(alloc, src);
- errdefer img.deinit(alloc);
img.alt = alt;
const el = try Element.Figure.init(alloc, img.element());
- errdefer el.deinit(alloc);
it = l.peek() orelse return el.element();
switch (it.kind) {
.strong_delimiter => return el.element(),
@@ -80,7 +73,6 @@ pub fn parseImage(alloc: Allocator, l: *Lexer) ImageError!Element {
else => return ImageError.InvalidImage,
}
const p = try paragraph.parse(alloc, l);
- errdefer p.deinit(alloc);
const p_el: *Element.paragraph.Block = @ptrCast(@alignCast(p.ptr));
el.caption = (try p_el.toEmpty(alloc)).element();
return el.element();
diff --git a/src/list.zig b/src/list.zig
index 0facef9..fe3a246 100644
--- a/src/list.zig
+++ b/src/list.zig
@@ -12,14 +12,12 @@ pub const Error = paragraph.Error || Allocator.Error;
pub fn parseOrdored(alloc: Allocator, l: *Lexer) Error!Element {
const el = try Element.list.Ordored.init(alloc);
- errdefer el.deinit(alloc);
try parse(alloc, &el.content, l, .list_ordored);
return el.element();
}
pub fn parseUnordored(alloc: Allocator, l: *Lexer) Error!Element {
const el = try Element.list.Unordored.init(alloc);
- errdefer el.deinit(alloc);
try parse(alloc, &el.content, l, .list_unordored);
return el.element();
}
diff --git a/src/paragraph.zig b/src/paragraph.zig
index b50b2ec..e1a01cf 100644
--- a/src/paragraph.zig
+++ b/src/paragraph.zig
@@ -15,7 +15,6 @@ pub const Error = content.Error || link.Error || Allocator.Error;
pub fn parse(alloc: Allocator, l: *Lexer) Error!Element {
var el = try Paragraph.Block.init(alloc);
- errdefer el.deinit(alloc);
while (l.peek()) |next| switch (next.kind) {
.strong_delimiter => return el.element(),
.weak_delimiter => {
@@ -31,19 +30,10 @@ pub fn parse(alloc: Allocator, l: *Lexer) Error!Element {
pub fn parseLine(alloc: Allocator, l: *Lexer) Error!Element {
var line = try Element.Empty.init(alloc);
- errdefer line.deinit(alloc);
while (l.peek()) |next| switch (next.kind) {
.weak_delimiter, .strong_delimiter => return line.element(),
- .link => {
- var el = try link.parse(alloc, l);
- errdefer el.deinit(alloc);
- try line.content.append(alloc, el);
- },
- else => {
- var el = try content.parse(alloc, l);
- errdefer el.deinit(alloc);
- try line.content.append(alloc, el);
- },
+ .link => try line.content.append(alloc, try link.parse(alloc, l)),
+ else => try line.content.append(alloc, try content.parse(alloc, l)),
};
return line.element();
}
diff --git a/src/parser.zig b/src/parser.zig
index c35d47f..9d89d7d 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -19,25 +19,7 @@ pub const Error = error{FeatureNotSupported} ||
code.Error ||
Allocator.Error;
-pub const Document = struct {
- arena: std.heap.ArenaAllocator,
- root: []Element,
-
- pub fn renderHTML(self: @This(), alloc: Allocator) Element.HTML.Error![]const u8 {
- var content = try std.ArrayList(u8).initCapacity(alloc, self.root.len * 6);
- errdefer content.deinit(alloc);
- for (self.root) |it| {
- const v = try it.renderHTML(alloc);
- defer alloc.free(v);
- try content.appendSlice(alloc, v);
- }
- return content.toOwnedSlice(alloc);
- }
-
- pub fn deinit(self: @This()) void {
- self.arena.deinit();
- }
-};
+pub const Document = *Element.Root;
pub fn parseReader(parent: Allocator, r: *std.io.Reader) !Document {
var l = try Lexer.initReader(parent, r);
@@ -51,13 +33,11 @@ pub fn parse(parent: Allocator, content: []const u8) Error!Document {
}
fn gen(parent: Allocator, l: *Lexer) Error!Document {
- var arena = std.heap.ArenaAllocator.init(parent);
- const alloc = arena.allocator();
- errdefer arena.deinit();
-
- var elements = try std.ArrayList(Element).initCapacity(alloc, 2);
+ var root = try Element.Root.init(parent);
+ errdefer root.deinit();
+ const alloc = root.allocator();
base: while (l.peek()) |it| {
- try elements.append(alloc, switch (it.kind) {
+ try root.append(switch (it.kind) {
// other blocks
.title => try title.parse(alloc, l),
.list_ordored => try list.parseOrdored(alloc, l),
@@ -76,7 +56,7 @@ fn gen(parent: Allocator, l: *Lexer) Error!Document {
return Error.FeatureNotSupported,
});
}
- return .{ .root = try elements.toOwnedSlice(alloc), .arena = arena };
+ return root;
}
fn doTest(alloc: Allocator, t: []const u8, v: []const u8) !void {
diff --git a/src/testing.zig b/src/testing.zig
index 6d19e0e..bf0690e 100644
--- a/src/testing.zig
+++ b/src/testing.zig
@@ -4,10 +4,13 @@ const Lexer = @import("lexer/Lexer.zig");
const Element = @import("eval/Element.zig");
const parser = @import("parser.zig");
-pub fn do(comptime parse: fn (Allocator, *Lexer) parser.Error!Element, alloc: Allocator, t: []const u8, v: []const u8) !void {
+pub fn do(comptime parse: fn (Allocator, *Lexer) parser.Error!Element, parent: Allocator, t: []const u8, v: []const u8) !void {
+ var arena = std.heap.ArenaAllocator.init(parent);
+ defer arena.deinit();
+ var alloc = arena.allocator();
+
var l = try Lexer.init(t);
var p = try parse(alloc, &l);
- defer p.deinit(alloc);
const g = try p.renderHTML(alloc);
defer alloc.free(g);
std.testing.expect(std.mem.eql(u8, g, v)) catch |err| {
@@ -16,8 +19,11 @@ pub fn do(comptime parse: fn (Allocator, *Lexer) parser.Error!Element, alloc: Al
};
}
-pub fn doError(comptime parse: fn (Allocator, *Lexer) parser.Error!Element, alloc: Allocator, t: []const u8, err: parser.Error) !void {
+pub fn doError(comptime parse: fn (Allocator, *Lexer) parser.Error!Element, parent: Allocator, t: []const u8, err: parser.Error) !void {
+ var arena = std.heap.ArenaAllocator.init(parent);
+ defer arena.deinit();
+
var l = try Lexer.init(t);
- _ = parse(alloc, &l) catch |e| return std.testing.expect(err == e);
+ _ = parse(arena.allocator(), &l) catch |e| return std.testing.expect(err == e);
return std.testing.expect(false);
}
diff --git a/src/title.zig b/src/title.zig
index 87d7f5f..cf432b4 100644
--- a/src/title.zig
+++ b/src/title.zig
@@ -16,7 +16,6 @@ pub fn parse(alloc: Allocator, l: *Lexer) Error!Element {
paragraph.Error.IllegalPlacement => return Error.InvalidTitleContent,
else => return err,
});
- errdefer el.deinit(alloc);
var next = l.next() orelse return el.element();
if (!next.kind.isDelimiter()) return Error.InvalidTitleContent;
return el.element();