udate: add include, with_block and now into parser
This commit is contained in:
parent
da8c1563c6
commit
3019009325
2 changed files with 473 additions and 1 deletions
365
src/parser.zig
365
src/parser.zig
|
|
@ -6,6 +6,33 @@ pub const NodeType = enum {
|
|||
tag,
|
||||
if_block,
|
||||
for_block,
|
||||
include,
|
||||
with_block,
|
||||
now,
|
||||
// extends, // <--- novo
|
||||
// block, // <--- novo
|
||||
// super, // <--- novo (para {{ block.super }})
|
||||
};
|
||||
|
||||
pub const NowNode = struct {
|
||||
format: []const u8,
|
||||
};
|
||||
|
||||
pub const Assignment = struct {
|
||||
key: []const u8,
|
||||
value_expr: []const u8,
|
||||
is_literal: bool,
|
||||
};
|
||||
|
||||
pub const WithNode = struct {
|
||||
assignments: []const Assignment,
|
||||
body: []Node,
|
||||
raw_open: []const u8,
|
||||
raw_close: []const u8,
|
||||
};
|
||||
|
||||
pub const IncludeNode = struct {
|
||||
template_name: []const u8,
|
||||
};
|
||||
|
||||
pub const TextNode = struct {
|
||||
|
|
@ -45,7 +72,10 @@ pub const Node = struct {
|
|||
variable: ?VariableNode = null,
|
||||
tag: ?TagNode = null,
|
||||
@"if": ?IfNode = null,
|
||||
@"for": ?ForNode = null, // <--- novo
|
||||
@"for": ?ForNode = null,
|
||||
include: ?IncludeNode = null,
|
||||
with: ?WithNode = null,
|
||||
now: ?NowNode = null,
|
||||
|
||||
pub fn deinit(self: Node, allocator: std.mem.Allocator) void {
|
||||
switch (self.type) {
|
||||
|
|
@ -73,6 +103,22 @@ pub const Node = struct {
|
|||
allocator.free(fb.empty_body);
|
||||
// raw_open e raw_close são slices originais — não free
|
||||
},
|
||||
.include => if (self.include) |inc| {
|
||||
allocator.free(inc.template_name);
|
||||
},
|
||||
.with_block => if (self.with) |w| {
|
||||
for (w.assignments) |a| {
|
||||
allocator.free(a.key);
|
||||
allocator.free(a.value_expr);
|
||||
}
|
||||
allocator.free(w.assignments);
|
||||
for (w.body) |n| n.deinit(allocator);
|
||||
allocator.free(w.body);
|
||||
// raw_open e raw_close são slices originais — não free
|
||||
},
|
||||
.now => if (self.now) |n| {
|
||||
allocator.free(n.format);
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -99,12 +145,202 @@ pub const Parser = struct {
|
|||
while (self.pos < self.template.len and std.ascii.isWhitespace(self.template[self.pos])) : (self.advance(1)) {}
|
||||
}
|
||||
|
||||
// fn parseAssignments(allocator: std.mem.Allocator, args: []const u8) ![]const Assignment {
|
||||
// var list = std.ArrayList(Assignment){};
|
||||
// defer list.deinit(allocator);
|
||||
//
|
||||
// // Implementação básica — você já tem uma melhor, use ela
|
||||
// // Por enquanto, só para passar teste
|
||||
// _ = args;
|
||||
// return try list.toOwnedSlice(allocator);
|
||||
// }
|
||||
|
||||
fn parseAssignments(
|
||||
self: *Parser,
|
||||
allocator: std.mem.Allocator,
|
||||
args: []const u8,
|
||||
) ![]const Assignment {
|
||||
var list = std.ArrayList(Assignment){};
|
||||
defer list.deinit(allocator);
|
||||
|
||||
_ = self;
|
||||
var i: usize = 0;
|
||||
while (i < args.len) {
|
||||
// Pula whitespaces iniciais
|
||||
while (i < args.len and std.mem.indexOfScalar(u8, " \t\r\n", args[i]) != null) : (i += 1) {}
|
||||
|
||||
if (i >= args.len) break;
|
||||
|
||||
// Parse key (até '=')
|
||||
const key_start = i;
|
||||
while (i < args.len and args[i] != '=') : (i += 1) {}
|
||||
if (i >= args.len or args[i] != '=') return error.InvalidAssignmentSyntax;
|
||||
const key = std.mem.trim(u8, args[key_start..i], " \t\r\n");
|
||||
if (key.len == 0) return error.InvalidAssignmentSyntax;
|
||||
i += 1; // Pula '='
|
||||
|
||||
// Pula whitespaces após '='
|
||||
while (i < args.len and std.mem.indexOfScalar(u8, " \t\r\n", args[i]) != null) : (i += 1) {}
|
||||
|
||||
// Parse value: se começa com ", parse até próximo " não escapado; senão, até próximo espaço
|
||||
const value_start = i;
|
||||
var in_quote = false;
|
||||
if (i < args.len and args[i] == '"') {
|
||||
in_quote = true;
|
||||
i += 1; // Pula aspa inicial
|
||||
}
|
||||
while (i < args.len) {
|
||||
if (in_quote) {
|
||||
if (args[i] == '"' and (i == 0 or args[i - 1] != '\\')) break; // Fecha aspa não escapada
|
||||
} else {
|
||||
if (std.mem.indexOfScalar(u8, " \t\r\n", args[i]) != null) break; // Fim sem quote
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
const value_end = i;
|
||||
var value = args[value_start..value_end];
|
||||
if (in_quote) {
|
||||
if (i >= args.len or args[i] != '"') return error.UnclosedQuoteInAssignment;
|
||||
i += 1; // Pula aspa final
|
||||
value = args[value_start + 1 .. value_end]; // Remove aspas
|
||||
// TODO: Se precisar, handle escapes como \" aqui (remova \\ antes de ")
|
||||
} else {
|
||||
value = std.mem.trim(u8, value, " \t\r\n");
|
||||
}
|
||||
|
||||
try list.append(allocator, .{
|
||||
.key = try allocator.dupe(u8, key),
|
||||
.value_expr = try allocator.dupe(u8, value),
|
||||
.is_literal = in_quote,
|
||||
});
|
||||
}
|
||||
|
||||
return try list.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
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){};
|
||||
defer body.deinit(allocator);
|
||||
|
||||
var depth: usize = 1;
|
||||
|
||||
while (self.pos < self.template.len and depth > 0) {
|
||||
if (try self.parseText(allocator)) |node| {
|
||||
std.debug.print("2.3 - Encontrei um texto: {s}\n", .{node.text.?.content});
|
||||
try body.append(allocator, node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (try self.parseVariable(allocator)) |node| {
|
||||
std.debug.print("2.3 - Encontrei uma variável: {s}\n", .{node.variable.?.content});
|
||||
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, "with")) {
|
||||
depth += 1;
|
||||
try body.append(allocator, tag_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, tag_name, "endwith")) {
|
||||
depth -= 1;
|
||||
const raw_close = tag_node.tag.?.raw;
|
||||
|
||||
allocator.free(tag_node.tag.?.name);
|
||||
allocator.free(tag_node.tag.?.args);
|
||||
|
||||
if (depth == 0) {
|
||||
// para fins de debug
|
||||
std.debug.print("2.4 - Encontrei um bloco with:\n - assignments: {any}\n - body: {any}\n - raw_open: {s}\n - raw_close: {s}\n", .{
|
||||
assignments,
|
||||
body.items,
|
||||
raw_open,
|
||||
raw_close,
|
||||
});
|
||||
// fim para fins de debug
|
||||
return Node{
|
||||
.type = .with_block,
|
||||
.with = .{
|
||||
.assignments = assignments,
|
||||
.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 parseComment(self: *Parser) !void {
|
||||
// Consome a tag open {% comment %}
|
||||
// Já estamos após o %}, então só avançamos
|
||||
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) : (self.advance(1)) {
|
||||
if (self.peek(2)) |closing| {
|
||||
if (std.mem.eql(u8, closing, "%}")) break;
|
||||
}
|
||||
}
|
||||
|
||||
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, "comment")) {
|
||||
depth += 1;
|
||||
} else if (std.mem.eql(u8, inner, "endcomment")) {
|
||||
depth -= 1;
|
||||
if (depth == 0) {
|
||||
self.advance(2); // consome %}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.advance(2);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
self.advance(1);
|
||||
}
|
||||
|
||||
return error.UnclosedComment;
|
||||
}
|
||||
|
||||
fn parseText(self: *Parser, allocator: std.mem.Allocator) !?Node {
|
||||
std.debug.print("2.0 - Vou verificar se sou texto\n", .{});
|
||||
const start = self.pos;
|
||||
|
||||
std.debug.print("2.1 - meu start é {d}\n", .{start});
|
||||
|
||||
while (self.pos < self.template.len) {
|
||||
if (self.peek(2)) |p| {
|
||||
if (std.mem.eql(u8, p, "{{") or std.mem.eql(u8, p, "{%")) {
|
||||
std.debug.print("2.2 - fiz o peek de 2 em 2 até que achei {{{{ ou {{%, então parei\n", .{});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -114,6 +350,7 @@ pub const Parser = struct {
|
|||
if (self.pos == start) return null;
|
||||
|
||||
const content = try allocator.dupe(u8, self.template[start..self.pos]);
|
||||
std.debug.print("2.2 - meu content é \'{s}\'\n", .{content});
|
||||
return Node{
|
||||
.type = .text,
|
||||
.text = .{ .content = content },
|
||||
|
|
@ -121,8 +358,11 @@ pub const Parser = struct {
|
|||
}
|
||||
|
||||
fn parseVariable(self: *Parser, allocator: std.mem.Allocator) !?Node {
|
||||
std.debug.print("2.0 - Vou verificar se sou variável\n", .{});
|
||||
std.debug.print("2.1 - meu start é {d}\n", .{self.pos});
|
||||
if (self.peek(2)) |p| {
|
||||
if (!std.mem.eql(u8, p, "{{")) return null;
|
||||
std.debug.print("2.1 - fiz o peek de 2 em 2 até que achei {{{{\n", .{});
|
||||
} else return null;
|
||||
|
||||
self.advance(2);
|
||||
|
|
@ -135,12 +375,15 @@ pub const Parser = struct {
|
|||
}
|
||||
}
|
||||
|
||||
std.debug.print("2.2 - fiz o peek de 2 em 2 até que achei }}}}\n", .{});
|
||||
if (self.pos + 2 > self.template.len or !std.mem.eql(u8, self.template[self.pos .. self.pos + 2], "}}")) {
|
||||
std.debug.print("2.3 - deu ruim achei uma variável que não fecha!\n", .{});
|
||||
return error.UnclosedVariable;
|
||||
}
|
||||
|
||||
const raw_content = self.template[content_start..self.pos];
|
||||
const content = std.mem.trim(u8, raw_content, " \t\r\n");
|
||||
std.debug.print("2.3 - meu content é \'{s}\'\n", .{content});
|
||||
|
||||
const duped = try allocator.dupe(u8, content);
|
||||
self.advance(2);
|
||||
|
|
@ -152,8 +395,11 @@ pub const Parser = struct {
|
|||
}
|
||||
|
||||
fn parseTag(self: *Parser, allocator: std.mem.Allocator) !?Node {
|
||||
std.debug.print("2.0 - Vou verificar se sou uma tag\n", .{});
|
||||
std.debug.print("2.1 - meu start é {d}\n", .{self.pos});
|
||||
if (self.peek(2)) |p| {
|
||||
if (!std.mem.eql(u8, p, "{%")) return null;
|
||||
std.debug.print("2.1 - fiz o peek de 2 em 2 até que achei {{%\n", .{});
|
||||
} else return null;
|
||||
|
||||
const raw_start = self.pos;
|
||||
|
|
@ -167,6 +413,7 @@ pub const Parser = struct {
|
|||
}
|
||||
}
|
||||
|
||||
std.debug.print("2.2 - fiz o peek de 2 em 2 até que achei %}}\n", .{});
|
||||
if (self.pos + 2 > self.template.len or !std.mem.eql(u8, self.template[self.pos .. self.pos + 2], "%}")) {
|
||||
return error.UnclosedTag;
|
||||
}
|
||||
|
|
@ -181,6 +428,7 @@ pub const Parser = struct {
|
|||
const name = try allocator.dupe(u8, name_raw);
|
||||
const args = try allocator.dupe(u8, args_raw);
|
||||
|
||||
std.debug.print("2.3 - meu node:\n - nome: {s}\n - args: {s}\n - raw: {s}\n", .{ name, args, raw_slice });
|
||||
self.advance(2);
|
||||
|
||||
return Node{
|
||||
|
|
@ -194,6 +442,7 @@ pub const Parser = struct {
|
|||
}
|
||||
|
||||
fn parseIfBlock(self: *Parser, allocator: std.mem.Allocator, condition: []const u8, raw_open: []const u8) !Node {
|
||||
std.debug.print("Vou verificar se sou bloco\n", .{});
|
||||
var true_body = std.ArrayList(Node){};
|
||||
defer true_body.deinit(allocator);
|
||||
var false_body = std.ArrayList(Node){};
|
||||
|
|
@ -204,11 +453,13 @@ pub const Parser = struct {
|
|||
|
||||
while (self.pos < self.template.len and depth > 0) {
|
||||
if (try self.parseText(allocator)) |node| {
|
||||
std.debug.print("2.3 - Encontrei um texto: {s}\n", .{node.text.?.content});
|
||||
try current_body.append(allocator, node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (try self.parseVariable(allocator)) |node| {
|
||||
std.debug.print("2.3 - Encontrei uma variável: {s}\n", .{node.variable.?.content});
|
||||
try current_body.append(allocator, node);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -231,6 +482,13 @@ pub const Parser = struct {
|
|||
allocator.free(tag_node.tag.?.args);
|
||||
|
||||
if (depth == 0) {
|
||||
std.debug.print("2.4 - Encontrei um bloco if:\n - condition: {s}\n - true_body: {any}\n - false_body: {any}\n - raw_open: {s}\n - raw_close: {s}\n", .{
|
||||
condition,
|
||||
true_body.items,
|
||||
false_body.items,
|
||||
raw_open,
|
||||
raw_close,
|
||||
});
|
||||
return Node{
|
||||
.type = .if_block,
|
||||
.@"if" = .{
|
||||
|
|
@ -276,11 +534,13 @@ pub const Parser = struct {
|
|||
|
||||
while (self.pos < self.template.len and depth > 0) {
|
||||
if (try self.parseText(allocator)) |node| {
|
||||
std.debug.print("2.3 - Encontrei um texto: {s}\n", .{node.text.?.content});
|
||||
try current_body.append(allocator, node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (try self.parseVariable(allocator)) |node| {
|
||||
std.debug.print("2.3 - Encontrei uma variável: {s}\n", .{node.variable.?.content});
|
||||
try current_body.append(allocator, node);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -303,6 +563,14 @@ pub const Parser = struct {
|
|||
allocator.free(tag_node.tag.?.name);
|
||||
allocator.free(tag_node.tag.?.args);
|
||||
|
||||
std.debug.print("2.4 - Encontrei um bloco for:\n - loop_var: {s}\n - iterable: {s}\n - body: {any}\n - empty_body: {any}\n - raw_open: {s}\n - raw_close: {s}\n", .{
|
||||
loop_var,
|
||||
iterable,
|
||||
body.items,
|
||||
empty_body.items,
|
||||
raw_open,
|
||||
raw_close,
|
||||
});
|
||||
return Node{
|
||||
.type = .for_block,
|
||||
.@"for" = .{
|
||||
|
|
@ -341,10 +609,89 @@ pub const Parser = struct {
|
|||
var list = std.ArrayList(Node){};
|
||||
defer list.deinit(allocator);
|
||||
|
||||
std.debug.print("O template recebido é:\n\n{s}\n\n", .{self.template});
|
||||
while (self.pos < self.template.len) {
|
||||
std.debug.print("1.0 - minha posição ainda é menor que o tamanho do template\n", .{});
|
||||
if (try self.parseTag(allocator)) |node| {
|
||||
std.debug.print("3.0 - na real sou uma tag\n", .{});
|
||||
const tag_name = node.tag.?.name;
|
||||
|
||||
std.debug.print("3.1 - meu tag name é: {s}\n", .{tag_name});
|
||||
|
||||
if (std.mem.eql(u8, tag_name, "comment")) {
|
||||
std.debug.print("3.0 - na real sou um comentário\n", .{});
|
||||
std.debug.print("===================================\n", .{});
|
||||
allocator.free(node.tag.?.name);
|
||||
allocator.free(node.tag.?.args);
|
||||
try self.parseComment();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, tag_name, "now")) {
|
||||
const args = node.tag.?.args;
|
||||
|
||||
// Remove aspas se existirem
|
||||
var format_str = args;
|
||||
if (format_str.len >= 2 and format_str[0] == '"' and format_str[format_str.len - 1] == '"') {
|
||||
format_str = format_str[1 .. format_str.len - 1];
|
||||
}
|
||||
|
||||
const duped_format = try allocator.dupe(u8, format_str);
|
||||
|
||||
// Libera a tag now
|
||||
allocator.free(node.tag.?.name);
|
||||
allocator.free(node.tag.?.args);
|
||||
|
||||
std.debug.print("3.0 - na real sou uma tag now\n", .{});
|
||||
std.debug.print("===================================\n", .{});
|
||||
|
||||
try list.append(allocator, Node{
|
||||
.type = .now,
|
||||
.now = .{ .format = duped_format },
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, tag_name, "with")) {
|
||||
const args = node.tag.?.args;
|
||||
const raw_open = node.tag.?.raw;
|
||||
|
||||
const assignments = try self.parseAssignments(allocator, args);
|
||||
|
||||
allocator.free(node.tag.?.name);
|
||||
allocator.free(node.tag.?.args);
|
||||
|
||||
const with_node = try self.parseWithBlock(allocator, assignments, raw_open);
|
||||
std.debug.print("3.0 - na real sou um bloco with\n", .{});
|
||||
std.debug.print("===================================\n", .{});
|
||||
try list.append(allocator, with_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, tag_name, "include")) {
|
||||
const args = node.tag.?.args;
|
||||
|
||||
// Remove aspas se existirem
|
||||
var template_name = args;
|
||||
if (template_name.len >= 2 and template_name[0] == '"' and template_name[template_name.len - 1] == '"') {
|
||||
template_name = template_name[1 .. template_name.len - 1];
|
||||
}
|
||||
|
||||
const duped_name = try allocator.dupe(u8, template_name);
|
||||
|
||||
// Libera a tag include
|
||||
allocator.free(node.tag.?.name);
|
||||
allocator.free(node.tag.?.args);
|
||||
|
||||
std.debug.print("3.0 - na real sou um include\n", .{});
|
||||
std.debug.print("===================================\n", .{});
|
||||
try list.append(allocator, Node{
|
||||
.type = .include,
|
||||
.include = .{ .template_name = duped_name },
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, tag_name, "if")) {
|
||||
const condition_raw = node.tag.?.args;
|
||||
const raw_open = node.tag.?.raw;
|
||||
|
|
@ -359,6 +706,8 @@ pub const Parser = struct {
|
|||
|
||||
const if_node = try self.parseIfBlock(allocator, condition, raw_open);
|
||||
try list.append(allocator, if_node);
|
||||
|
||||
std.debug.print("===================================\n", .{});
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -379,21 +728,30 @@ pub const Parser = struct {
|
|||
allocator.free(node.tag.?.args);
|
||||
|
||||
const for_node = try self.parseForBlock(allocator, loop_var, iterable, raw_open);
|
||||
|
||||
std.debug.print("===================================\n", .{});
|
||||
try list.append(allocator, for_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Para tags normais
|
||||
std.debug.print("===================================\n", .{});
|
||||
try list.append(allocator, node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (try self.parseVariable(allocator)) |node| {
|
||||
std.debug.print("3.0 - na real sou variável\n", .{});
|
||||
std.debug.print("4.0 - content: \'{s}\'\n", .{node.variable.?.content});
|
||||
std.debug.print("===================================\n", .{});
|
||||
try list.append(allocator, node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (try self.parseText(allocator)) |node| {
|
||||
std.debug.print("3.0 - na real sou texto\n", .{});
|
||||
std.debug.print("4.0 - content: \'{s}\'\n", .{node.text.?.content});
|
||||
std.debug.print("===================================\n", .{});
|
||||
try list.append(allocator, node);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -401,6 +759,11 @@ pub const Parser = struct {
|
|||
self.advance(1);
|
||||
}
|
||||
|
||||
std.debug.print("\nO resultado disso foi esse:\n", .{});
|
||||
for (list.items) |item| {
|
||||
std.debug.print(" -> type: {s}\n", .{@tagName(item.type)});
|
||||
}
|
||||
std.debug.print("\n", .{});
|
||||
return try list.toOwnedSlice(allocator);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -184,3 +184,112 @@ test "parse for block com empty" {
|
|||
try testing.expectEqual(@as(usize, 1), fb.empty_body.len);
|
||||
try testing.expectEqualStrings("Vazio", fb.empty_body[0].text.?.content);
|
||||
}
|
||||
|
||||
test "parse comment" {
|
||||
const allocator = testing.allocator;
|
||||
const template = "Bazinga! {% comment %}{% for item in lista %}Tem{% empty %}Vazio{% endfor %}{% endcomment %}";
|
||||
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("Bazinga! ", nodes[0].text.?.content);
|
||||
}
|
||||
|
||||
test "parse include simples" {
|
||||
const allocator = testing.allocator;
|
||||
const template = "Cabeçalho {% include \"header.zdt\" %} Conteúdo {% include \"footer.zdt\" %}";
|
||||
const nodes = try parser.parse(allocator, template);
|
||||
defer {
|
||||
for (nodes) |node| node.deinit(allocator);
|
||||
allocator.free(nodes);
|
||||
}
|
||||
|
||||
try testing.expectEqual(@as(usize, 4), nodes.len);
|
||||
|
||||
try testing.expect(nodes[0].type == .text);
|
||||
try testing.expectEqualStrings("Cabeçalho ", nodes[0].text.?.content);
|
||||
|
||||
try testing.expect(nodes[1].type == .include);
|
||||
try testing.expectEqualStrings("header.zdt", nodes[1].include.?.template_name);
|
||||
|
||||
try testing.expect(nodes[2].type == .text);
|
||||
try testing.expectEqualStrings(" Conteúdo ", nodes[2].text.?.content);
|
||||
|
||||
try testing.expect(nodes[3].type == .include);
|
||||
try testing.expectEqualStrings("footer.zdt", nodes[3].include.?.template_name);
|
||||
|
||||
}
|
||||
|
||||
test "parse include sem aspas (erro esperado no futuro, mas por enquanto aceita)" {
|
||||
const allocator = testing.allocator;
|
||||
const template = "{% include header.zdt %}";
|
||||
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 == .include);
|
||||
try testing.expectEqualStrings("header.zdt", nodes[0].include.?.template_name);
|
||||
}
|
||||
|
||||
test "parse with simples" {
|
||||
const allocator = testing.allocator;
|
||||
const template = "{% with nome=\"Lucas\" idade=30 %}Olá {{ nome }}, você tem {{ idade }} anos.{% endwith %}";
|
||||
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 == .with_block);
|
||||
const w = nodes[0].with.?;
|
||||
try testing.expectEqual(@as(usize, 2), w.assignments.len);
|
||||
try testing.expectEqual(@as(usize, 5), w.body.len);
|
||||
try testing.expect(w.body[0].type == .text);
|
||||
}
|
||||
|
||||
test "parse now simples" {
|
||||
const allocator = testing.allocator;
|
||||
const template = "Data atual: {% now \"Y-m-d\" %} às {% now \"H:i\" %}";
|
||||
const nodes = try parser.parse(allocator, template);
|
||||
defer {
|
||||
for (nodes) |node| node.deinit(allocator);
|
||||
allocator.free(nodes);
|
||||
}
|
||||
|
||||
try testing.expectEqual(@as(usize, 4), nodes.len);
|
||||
|
||||
try testing.expect(nodes[0].type == .text);
|
||||
try testing.expectEqualStrings("Data atual: ", nodes[0].text.?.content);
|
||||
|
||||
try testing.expect(nodes[1].type == .now);
|
||||
try testing.expectEqualStrings("Y-m-d", nodes[1].now.?.format);
|
||||
|
||||
try testing.expect(nodes[2].type == .text);
|
||||
try testing.expectEqualStrings(" às ", nodes[2].text.?.content);
|
||||
|
||||
try testing.expect(nodes[3].type == .now);
|
||||
try testing.expectEqualStrings("H:i", nodes[3].now.?.format);
|
||||
|
||||
}
|
||||
|
||||
test "parse now sem aspas" {
|
||||
const allocator = testing.allocator;
|
||||
const template = "{% now Y-m-d %}";
|
||||
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 == .now);
|
||||
try testing.expectEqualStrings("Y-m-d", nodes[0].now.?.format);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue