Add capture syntax

This commit is contained in:
jaina heartles 2022-11-16 00:01:45 -08:00
parent 9d74bce266
commit 8ebe77541f
2 changed files with 33 additions and 17 deletions

View file

@ -12,31 +12,40 @@ const logging = false;
pub fn execute(writer: anytype, comptime template: []const u8, args: anytype) !void { pub fn execute(writer: anytype, comptime template: []const u8, args: anytype) !void {
@setEvalBranchQuota(@intCast(u32, template.len * 6)); @setEvalBranchQuota(@intCast(u32, template.len * 6));
const tmpl = comptime parseTemplate(TokenIter{ .text = template }, .root); const tmpl = comptime parseTemplate(TokenIter{ .text = template }, .root);
try executeTemplate(writer, tmpl.item, args); try executeTemplate(writer, tmpl.item, args, .{ .bar = "abc" });
} }
fn executeTemplate(writer: anytype, comptime items: []const TemplateItem, args: anytype) !void { fn executeTemplate(writer: anytype, comptime items: []const TemplateItem, args: anytype, captures: anytype) !void {
inline for (items) |it| switch (it) { inline for (items) |it| switch (it) {
.text => |text| try writer.writeAll(text), .text => |text| try writer.writeAll(text),
.statement => |stmt| try executeStatement(writer, stmt, args), .statement => |stmt| try executeStatement(writer, stmt, args, captures),
}; };
} }
fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype) !void { fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype, captures: anytype) !void {
switch (stmt) { switch (stmt) {
.expression => |expr| switch (expr) { .expression => |expr| switch (expr) {
.arg_deref => |fields| { .arg_deref => |fields| {
const arg = argDeref(args, fields); const arg = deref(args, fields);
try print(writer, arg);
},
.capture_deref => |fields| {
const arg = deref(captures, fields);
try print(writer, arg); try print(writer, arg);
}, },
}, },
.for_loop => |loop| { .for_loop => |loop| {
const fields = loop.iterable.arg_deref; const fields = loop.iterable.arg_deref;
const iterable = argDeref(args, fields); const iterable = deref(args, fields);
const subtemplate = loop.subtemplate; const subtemplate = loop.subtemplate;
try writer.writeAll("capture on " ++ loop.capture ++ ": "); try writer.writeAll("capture on " ++ loop.capture ++ ": ");
for (iterable) |_| { for (iterable) |_| {
try executeTemplate(writer, subtemplate, args); try executeTemplate(
writer,
subtemplate,
args,
captures,
);
} }
}, },
else => @compileError("TODO"), else => @compileError("TODO"),
@ -49,7 +58,7 @@ fn print(writer: anytype, arg: anytype) !void {
@compileError("TODO"); @compileError("TODO");
} }
fn ArgDeref(comptime T: type, comptime names: []const []const u8) type { fn Deref(comptime T: type, comptime names: []const []const u8) type {
if (names.len == 0) return T; if (names.len == 0) return T;
// Compiler segfaults when I use std.meta to get this info so we search it manually // Compiler segfaults when I use std.meta to get this info so we search it manually
@ -57,12 +66,12 @@ fn ArgDeref(comptime T: type, comptime names: []const []const u8) type {
if (std.mem.eql(u8, f.name, names[0])) break f; if (std.mem.eql(u8, f.name, names[0])) break f;
} else @compileError("Unknown field " ++ names[0] ++ " in type " ++ @typeName(T)); } else @compileError("Unknown field " ++ names[0] ++ " in type " ++ @typeName(T));
return ArgDeref(field.field_type, names[1..]); return Deref(field.field_type, names[1..]);
} }
fn argDeref(arg: anytype, comptime names: []const []const u8) ArgDeref(@TypeOf(arg), names) { fn deref(arg: anytype, comptime names: []const []const u8) Deref(@TypeOf(arg), names) {
if (names.len == 0) return arg; if (names.len == 0) return arg;
return argDeref(@field(arg, names[0]), names[1..]); return deref(@field(arg, names[0]), names[1..]);
} }
const TemplateType = enum { const TemplateType = enum {
@ -146,9 +155,14 @@ fn parseStatement(comptime tokens: TokenIter) ParseResult(Statement) {
} }
}, },
.period => { .period => {
const expr = parseArgDeref(iter); const names = parseDeref(iter);
iter = expr.new_iter; iter = names.new_iter;
break .{ .expression = .{ .arg_deref = expr.item } }; break .{ .expression = .{ .arg_deref = names.item } };
},
.dollar => {
const names = parseDeref(iter);
iter = names.new_iter;
break .{ .expression = .{ .capture_deref = names.item } };
}, },
else => @compileError(""), else => @compileError(""),
}; };
@ -229,8 +243,8 @@ fn parseExpression(comptime tokens: TokenIter) ParseResult(Expression) {
while (iter.next()) |token| switch (token) { while (iter.next()) |token| switch (token) {
.whitespace => {}, .whitespace => {},
.period => { .period => {
const deref = parseArgDeref(iter); const names = parseDeref(iter);
return .{ .new_iter = deref.new_iter, .item = .{ .arg_deref = deref.item } }; return .{ .new_iter = names.new_iter, .item = .{ .arg_deref = names.item } };
}, },
else => @compileError("Expected Expression"), else => @compileError("Expected Expression"),
}; };
@ -239,7 +253,7 @@ fn parseExpression(comptime tokens: TokenIter) ParseResult(Expression) {
} }
} }
fn parseArgDeref(comptime tokens: TokenIter) ParseResult([]const []const u8) { fn parseDeref(comptime tokens: TokenIter) ParseResult([]const []const u8) {
comptime { comptime {
var iter = tokens; var iter = tokens;
var fields: []const []const u8 = &.{}; var fields: []const []const u8 = &.{};
@ -280,6 +294,7 @@ const TemplateItem = union(enum) {
const Expression = union(enum) { const Expression = union(enum) {
arg_deref: []const []const u8, arg_deref: []const []const u8,
capture_deref: []const []const u8,
}; };
const ForLoop = struct { const ForLoop = struct {

View file

@ -9,6 +9,7 @@
<h2> {{ REAL BRACKETS }} </h2> <h2> {{ REAL BRACKETS }} </h2>
<section> <section>
{$bar}
{#for .foo |$f|}a testing thing {#end_for} {#for .foo |$f|}a testing thing {#end_for}
{{#for args.notes |$note, $i|}} {{#for args.notes |$note, $i|}}
<h3>Note no. {{$i}}</h3> <h3>Note no. {{$i}}</h3>