update: add debug, partialdef and partial

This commit is contained in:
Lucas F. 2026-01-03 21:06:54 -03:00
parent b09da93f0d
commit 1e0329a597
3 changed files with 207 additions and 7 deletions

View file

@ -21,6 +21,20 @@ pub const NodeType = enum {
load,
csrf_token,
lorem,
debug,
partialdef,
partial,
};
pub const PartialDefNode = struct {
name: []const u8,
body: []Node,
raw_open: []const u8,
raw_close: []const u8,
};
pub const PartialNode = struct {
name: []const u8,
};
pub const LoremNode = struct {
@ -156,7 +170,10 @@ pub const Node = struct {
firstof: ?FirstOfNode = null,
load: ?LoadNode = null,
lorem: ?LoremNode = null,
partialdef: ?PartialDefNode = null,
partial: ?PartialNode = null,
csrf_token: bool = false,
debug: bool = false,
pub fn deinit(self: Node, allocator: std.mem.Allocator) void {
switch (self.type) {
@ -251,6 +268,15 @@ pub const Node = struct {
if (l.method) |m| allocator.free(m);
if (l.format) |f| allocator.free(f);
},
.debug => {},
.partialdef => if (self.partialdef) |pd| {
allocator.free(pd.name);
for (pd.body) |n| n.deinit(allocator);
allocator.free(pd.body);
},
.partial => if (self.partial) |p| {
allocator.free(p.name);
},
}
}
};
@ -340,6 +366,64 @@ pub const Parser = struct {
return try list.toOwnedSlice(allocator);
}
fn parsePartialDefBlock(self: *Parser, allocator: std.mem.Allocator, name: []const u8, raw_open: []const u8) !Node {
var body = std.ArrayList(Node){};
defer body.deinit(allocator);
var depth: usize = 1;
while (self.pos < self.template.len and depth > 0) {
if (try self.parseText(allocator)) |node| {
try body.append(allocator, node);
continue;
}
if (try self.parseVariable(allocator)) |node| {
try body.append(allocator, node);
continue;
}
if (try self.parseTag(allocator)) |tag_node| {
const tag_name = tag_node.tag.?.name;
if (std.mem.eql(u8, tag_name, "partialdef")) {
depth += 1;
try body.append(allocator, tag_node);
continue;
}
if (std.mem.eql(u8, tag_name, "endpartialdef")) {
depth -= 1;
const raw_close = tag_node.tag.?.raw;
allocator.free(tag_node.tag.?.name);
allocator.free(tag_node.tag.?.args);
if (depth == 0) {
return Node{
.type = .partialdef,
.partialdef = .{
.name = try allocator.dupe(u8, name),
.body = try body.toOwnedSlice(allocator),
.raw_open = raw_open,
.raw_close = raw_close,
},
};
}
try body.append(allocator, tag_node);
continue;
}
try body.append(allocator, tag_node);
} else {
self.advance(1);
}
}
return error.UnclosedBlock;
}
fn parseAutoescapeBlock(self: *Parser, allocator: std.mem.Allocator, enabled: bool, raw_open: []const u8) !Node {
var body = std.ArrayList(Node){};
defer body.deinit(allocator);
@ -1106,6 +1190,41 @@ pub const Parser = struct {
continue;
}
if (std.mem.eql(u8, tag_name, "partialdef")) {
const partial_name = std.mem.trim(u8, node.tag.?.args, " \t\r\n");
const raw_open = node.tag.?.raw;
const duped_name = try allocator.dupe(u8, partial_name);
allocator.free(node.tag.?.name);
allocator.free(node.tag.?.args);
std.debug.print("3.0 - na real sou um partialdef\n", .{});
std.debug.print("===================================\n", .{});
const partialdef_node = try self.parsePartialDefBlock(allocator, duped_name, raw_open);
try list.append(allocator, partialdef_node);
continue;
}
if (std.mem.eql(u8, tag_name, "partial")) {
const partial_name = std.mem.trim(u8, node.tag.?.args, " \t\r\n\"'");
const duped_name = try allocator.dupe(u8, partial_name);
allocator.free(node.tag.?.name);
allocator.free(node.tag.?.args);
std.debug.print("3.0 - na real sou um partial\n", .{});
std.debug.print("===================================\n", .{});
try list.append(allocator, Node{
.type = .partial,
.partial = .{ .name = duped_name },
});
continue;
}
if (std.mem.eql(u8, tag_name, "lorem")) {
const args = node.tag.?.args;
@ -1129,9 +1248,8 @@ pub const Parser = struct {
method = try allocator.dupe(u8, trimmed);
} else if (std.mem.eql(u8, trimmed, "html")) {
std.debug.print("trimmed: {s}\n", .{trimmed});
format = try allocator.dupe(u8, trimmed);
format = try allocator.dupe(u8, trimmed);
}
}
allocator.free(node.tag.?.name);
@ -1515,6 +1633,25 @@ pub const Parser = struct {
continue;
}
if (std.mem.eql(u8, tag_name, "debug")) {
// Verifica se tem argumentos (não deve ter)
if (node.tag.?.args.len > 0 and !std.mem.allEqual(u8, node.tag.?.args, ' ')) {
return error.InvalidDebugArgs;
}
allocator.free(node.tag.?.name);
allocator.free(node.tag.?.args);
std.debug.print("3.0 - na real sou um debug\n", .{});
std.debug.print("===================================\n", .{});
try list.append(allocator, Node{
.type = .debug,
.debug = true,
});
continue;
}
if (std.mem.eql(u8, tag_name, "csrf_token")) {
// Verifica se tem argumentos (não deve ter)
if (node.tag.?.args.len > 0 and !std.mem.allEqual(u8, node.tag.?.args, ' ')) {

View file

@ -709,3 +709,66 @@ test "parse lorem com argumentos" {
try testing.expectEqualStrings("p", l.method.?);
try testing.expectEqualStrings("html", l.format.?);
}
test "parse debug simples" {
const allocator = testing.allocator;
const template = "Antes {% debug %} Depois";
const nodes = try parser.parse(allocator, template);
defer {
for (nodes) |node| node.deinit(allocator);
allocator.free(nodes);
}
try testing.expectEqual(@as(usize, 3), nodes.len);
try testing.expect(nodes[0].type == .text);
try testing.expectEqualStrings("Antes ", nodes[0].text.?.content);
try testing.expect(nodes[1].type == .debug);
try testing.expect(nodes[2].type == .text);
try testing.expectEqualStrings(" Depois", nodes[2].text.?.content);
}
test "parse debug sozinho" {
const allocator = testing.allocator;
const template = "{% debug %}";
const nodes = try parser.parse(allocator, template);
defer {
for (nodes) |node| node.deinit(allocator);
allocator.free(nodes);
}
try testing.expectEqual(@as(usize, 1), nodes.len);
try testing.expect(nodes[0].type == .debug);
}
test "parse partialdef simples" {
const allocator = testing.allocator;
const template = "{% partialdef cabecalho %}Cabeçalho{% endpartialdef %}";
const nodes = try parser.parse(allocator, template);
defer {
for (nodes) |node| node.deinit(allocator);
allocator.free(nodes);
}
try testing.expectEqual(@as(usize, 1), nodes.len);
try testing.expect(nodes[0].type == .partialdef);
const pd = nodes[0].partialdef.?;
try testing.expectEqualStrings("cabecalho", pd.name);
try testing.expectEqual(@as(usize, 1), pd.body.len);
try testing.expectEqualStrings("Cabeçalho", pd.body[0].text.?.content);
}
test "parse partial uso" {
const allocator = testing.allocator;
const template = "Início {% partial \"cabecalho\" %} Fim";
const nodes = try parser.parse(allocator, template);
defer {
for (nodes) |node| node.deinit(allocator);
allocator.free(nodes);
}
try testing.expectEqual(@as(usize, 3), nodes.len);
try testing.expect(nodes[1].type == .partial);
try testing.expectEqualStrings("cabecalho", nodes[1].partial.?.name);
}

10
todo.md
View file

@ -5,7 +5,7 @@
- [x] comment
- [x] csrf_token
- [x] cycle
- [ ] debug
- [x] debug
- [x] extends
- [x] filter
- [x] firstof
@ -16,8 +16,8 @@
- [x] load
- [x] lorem
- [x] now
- [ ] partial
- [ ] partialdef
- [x] partial
- [x] partialdef
- [ ] querystring
- [ ] regroup
- [ ] resetcycle
@ -108,9 +108,9 @@ ___
## To do
1 - Finalizar o parser — completar as tags que faltam da lista:
- [ ] debug
- [x] debug
- [x] lorem
- [ ] partial / partialdef
- [x] partial / partialdef
- [ ] querystring
- [ ] regroup
- [ ] resetcycle