From b7550e9b01c838d68ccc7d95bafb87748db3349c Mon Sep 17 00:00:00 2001 From: "Lucas F." Date: Sat, 3 Jan 2026 18:38:25 -0300 Subject: [PATCH] update: add verbatim --- src/parser.zig | 59 +++++++++++++++++++++++++++++++++++++++++++++ src/parser_test.zig | 29 ++++++++++++++++++++++ todo.md | 2 +- 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/parser.zig b/src/parser.zig index c7d5ad2..8b30a6e 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -340,6 +340,52 @@ pub const Parser = struct { return error.UnclosedBlock; } + fn parseVerbatim(self: *Parser, allocator: std.mem.Allocator) !Node { + const start = self.pos; + + var depth: usize = 1; + + while (self.pos < self.template.len and depth > 0) { + if (self.peek(2)) |p| { + if (std.mem.eql(u8, p, "{%")) { + self.advance(2); + self.skipWhitespace(); + + const content_start = self.pos; + while (self.pos < self.template.len and !std.mem.eql(u8, self.peek(2) orelse "", "%}")) : (self.advance(1)) {} + + if (self.pos + 2 > self.template.len or !std.mem.eql(u8, self.template[self.pos .. self.pos + 2], "%}")) { + return error.UnclosedTag; + } + + const inner = std.mem.trim(u8, self.template[content_start..self.pos], " \t\r\n"); + + if (std.mem.eql(u8, inner, "verbatim")) { + depth += 1; + } else if (std.mem.eql(u8, inner, "endverbatim")) { + depth -= 1; + if (depth == 0) { + // Copia até o início da tag endverbatim + const content_end = content_start - 3; // retrocede "{% " + const content = try allocator.dupe(u8, self.template[start..content_end]); + self.advance(2); // consome %} + return Node{ + .type = .text, + .text = .{ .content = content }, + }; + } + } + + self.advance(2); + continue; + } + } + self.advance(1); + } + + return error.UnclosedVerbatim; + } + fn parseSpacelessBlock(self: *Parser, allocator: std.mem.Allocator, raw_open: []const u8) !Node { var body = std.ArrayList(Node){}; defer body.deinit(allocator); @@ -525,6 +571,7 @@ pub const Parser = struct { return error.UnclosedBlock; } + fn parseWithBlock(self: *Parser, allocator: std.mem.Allocator, assignments: []const Assignment, raw_open: []const u8) !Node { std.debug.print("Vou verificar se sou bloco with\n", .{}); var body = std.ArrayList(Node){}; @@ -1164,6 +1211,18 @@ pub const Parser = struct { continue; } + if (std.mem.eql(u8, tag_name, "verbatim")) { + allocator.free(node.tag.?.name); + allocator.free(node.tag.?.args); + + std.debug.print("3.0 - na real sou um verbatim\n", .{}); + std.debug.print("===================================\n", .{}); + + const verbatim_node = try self.parseVerbatim(allocator); + try list.append(allocator, verbatim_node); + continue; + } + // Para tags normais std.debug.print("===================================\n", .{}); try list.append(allocator, node); diff --git a/src/parser_test.zig b/src/parser_test.zig index 2b00150..6fb7e7f 100644 --- a/src/parser_test.zig +++ b/src/parser_test.zig @@ -471,3 +471,32 @@ test "parse spaceless aninhado" { } try testing.expectEqual(@as(usize, 3), sl.body.len); } + +test "parse verbatim simples" { + const allocator = testing.allocator; + const template = "Texto {% verbatim %}{{ variável }}{% endblock %}{% endverbatim %} Texto"; + 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.expectEqualStrings("Texto ", nodes[0].text.?.content); + try testing.expectEqualStrings("{{ variável }}{% endblock %}", nodes[1].text.?.content); + try testing.expectEqualStrings(" Texto", nodes[2].text.?.content); +} + +test "parse verbatim aninhado" { + const allocator = testing.allocator; + const template = "{% verbatim %}Outer {% verbatim %}Inner{% endverbatim %} Outer{% endverbatim %}"; + 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 == .text); + try testing.expectEqualStrings("Outer {% verbatim %}Inner{% endverbatim %} Outer", nodes[0].text.?.content); +} diff --git a/todo.md b/todo.md index f28dbda..a422649 100644 --- a/todo.md +++ b/todo.md @@ -96,7 +96,7 @@ ___ - [x] filter — super útil (ex.: {{ var|upper }}) - [x] autoescape — segurança importante - [x] spaceless — remove espaços em branco -- [ ] verbatim — como raw +- [x] verbatim — como raw - [ ] url — reverse de URLs (quando tiver routing) - [ ] cycle — alternar valores em loop - [ ] firstof — fallback de variáveis