update: block and extends

This commit is contained in:
Lucas F. 2026-01-11 14:43:58 -03:00
parent 13ad344005
commit da8076a1d9

View file

@ -52,6 +52,69 @@ pub const Renderer = struct {
};
}
fn checkForExtends(self: *const Renderer, nodes: []parser.Node) ?parser.Node {
_ = self;
for (nodes) |n| {
if (n.type == .extends) return n;
}
return null;
}
fn readTemplateFile(self: *const Renderer, path: []const u8) RenderError![]const u8 {
const max_size = 10 * 1024 * 1024;
const base_template = std.fs.cwd().readFileAlloc(self.allocator, path, max_size) catch |err| switch (err) {
error.FileNotFound => return RenderError.FileNotFound,
error.AccessDenied => return RenderError.AccessDenied,
error.FileTooBig => return RenderError.FileTooBig,
error.NoSpaceLeft => return RenderError.NoSpaceLeft,
error.OutOfMemory => return RenderError.OutOfMemory,
else => return RenderError.Unexpected,
};
return base_template;
}
pub fn render(self: *const Renderer, template: []const u8, writer: anytype) RenderError!void {
const base_template = try self.readTemplateFile(template);
return self.renderString(base_template, writer);
}
pub fn renderString_bkp(self: *const Renderer, template: []const u8, writer: anytype) RenderError!void {
var arena = std.heap.ArenaAllocator.init(self.allocator);
defer arena.deinit();
const alloc = arena.allocator();
var p = parser.Parser.init(template);
const nodes = try p.parse(alloc);
defer {
for (nodes) |node| node.deinit(alloc);
alloc.free(nodes);
}
const has_extends = self.checkForExtends(nodes);
if (has_extends) {
for (nodes) |node| {
if (node.type == .extends) {
const base_template = try self.readTemplateFile(node.extends.?.parent_name);
defer self.allocator.free(base_template);
var base_parser = parser.Parser.init(base_template);
const base_nodes = try base_parser.parse(alloc);
defer {
for (base_nodes) |n| n.deinit(alloc);
alloc.free(base_nodes);
}
try self.renderWithInheritance(alloc, base_nodes, nodes, writer);
return;
}
}
} else {
for (nodes) |node| {
try self.renderNode(alloc, nodes, node, writer, null);
}
}
}
pub fn renderString(self: *const Renderer, template: []const u8, writer: anytype) RenderError!void {
var arena = std.heap.ArenaAllocator.init(self.allocator);
defer arena.deinit();
@ -64,12 +127,52 @@ pub const Renderer = struct {
alloc.free(nodes);
}
for (nodes) |node| {
try self.renderNode(alloc, node, writer, null);
const block_extends = self.checkForExtends(nodes);
if (block_extends) |ext| {
const base_template = try self.readTemplateFile(ext.extends.?.parent_name);
defer self.allocator.free(base_template);
var base_parser = parser.Parser.init(base_template);
const base_nodes = try base_parser.parse(alloc);
defer {
for (base_nodes) |n| n.deinit(alloc);
alloc.free(base_nodes);
}
try self.renderWithInheritance(alloc, base_nodes, nodes, writer);
} else {
for (nodes) |node| {
try self.renderNode(alloc, nodes, node, writer, null);
}
}
}
fn renderNode(self: *const Renderer, alloc: Allocator, node: parser.Node, writer: anytype, context: ?*Context) RenderError!void {
fn renderWithInheritance(self: *const Renderer, alloc: Allocator, base_nodes: []parser.Node, child_nodes: []parser.Node, writer: anytype) RenderError!void {
for (base_nodes) |base_node| {
if (base_node.type == .block) {
const block_name = base_node.block.?.name;
// Procura no filho
const child_block = self.findChildBlock(child_nodes, block_name);
if (child_block) |child| {
// Renderiza o filho
for (child.body) |child_node| {
try self.renderNode(alloc, child_nodes, child_node, writer, null);
}
} else {
// Renderiza o do pai
for (base_node.block.?.body) |child| {
try self.renderNode(alloc, child_nodes, child, writer, null);
}
}
} else {
// Qualquer outra coisa no base
try self.renderNode(alloc, child_nodes, base_node, writer, null);
}
}
}
fn renderNode(self: *const Renderer, alloc: Allocator, nodes: []parser.Node, node: parser.Node, writer: anytype, context: ?*Context) RenderError!void {
switch (node.type) {
.text => try writer.writeAll(node.text.?.content),
.variable => {
@ -77,7 +180,7 @@ pub const Renderer = struct {
var value: Value = Value.null;
if (context != null) {
value = context.?.get(var_name) orelse Value.null;
}else{
} else {
value = self.context.get(var_name) orelse Value.null;
}
@ -104,17 +207,16 @@ pub const Renderer = struct {
try self.valueToString(alloc, &buf, value);
try writer.writeAll(buf.items);
},
.if_block => {
const condition = self.evaluateCondition(node.@"if".?.condition) catch return false;
if (condition) {
for (node.@"if".?.true_body) |child| {
try self.renderNode(alloc, child, writer, null);
try self.renderNode(alloc, nodes, child, writer, null);
}
} else {
for (node.@"if".?.false_body) |child| {
try self.renderNode(alloc, child, writer, null);
try self.renderNode(alloc, nodes, child, writer, null);
}
}
},
@ -129,20 +231,35 @@ pub const Renderer = struct {
var ctx = Context.init(alloc);
defer ctx.deinit();
try ctx.set(node.@"for".?.loop_var,item);
try ctx.set(node.@"for".?.loop_var, item);
for (node.@"for".?.body) |child| {
try self.renderNode(alloc, child, writer, &ctx);
try self.renderNode(alloc, nodes, child, writer, &ctx);
}
for (node.@"for".?.empty_body) |child| {
try self.renderNode(alloc, child, writer, &ctx);
try self.renderNode(alloc, nodes, child, writer, &ctx);
}
}
},
.super => std.debug.print("\n\ntenho SUPER!!\n\n", .{}),
.block => {
for (node.block.?.body) |child| {
try self.renderNode(alloc, nodes, child, writer, null);
}
},
else => {},
}
}
fn findChildBlock(self: *const Renderer, nodes: []parser.Node, name: []const u8) ?parser.BlockNode {
_ = self;
for (nodes) |n| {
if (n.type != .block) continue;
if (std.mem.eql(u8, n.block.?.name, name)) return n.block.?;
}
return null;
}
fn valueToString(self: *const Renderer, alloc: Allocator, buf: *ArrayListUnmanaged(u8), value: Value) !void {
_ = self;
var w = buf.writer(alloc);