diff --git a/src/renderer.zig b/src/renderer.zig index 4f7c3dc..609578d 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -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 só 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);