srctree

Gregory Mullen parent 33eede74 80e83a56
add Build directive to template

src/template-compiler.zig added: 428, removed: 271, total 157
@@ -119,31 +119,32 @@ fn emitVars(a: Allocator, fdata: []const u8, current: *AbstTree) !void {
while (data.len > 0) {
if (std.mem.indexOf(u8, data, "<")) |offset| {
data = data[offset..];
if (Template.Directive.init(data)) |drct| switch (drct.kind) {
.noun => |noun| {
if (Template.Directive.init(data)) |drct| switch (drct.verb) {
.variable => |_| {
data = data[drct.end..];
switch (noun.otherwise) {
switch (drct.otherwise) {
.ign => {
try current.append(makeFieldName(noun.vari), ": []const u8,\n");
try current.append(makeFieldName(drct.noun), ": []const u8,\n");
},
.str => |str| {
var buffer: [0xFF]u8 = undefined;
const kind = try std.fmt.bufPrint(&buffer, ": []const u8 = \"{s}\",\n", .{str});
try current.append(makeFieldName(noun.vari), kind);
try current.append(makeFieldName(drct.noun), kind);
},
.del => {
try current.append(makeFieldName(noun.vari), ": ?[]const u8 = null,\n");
try current.append(makeFieldName(drct.noun), ": ?[]const u8 = null,\n");
},
.template => |_| {
var buffer: [0xFF]u8 = undefined;
const kind = try std.fmt.bufPrint(&buffer, ": ?{s},\n", .{makeStructName(noun.vari)});
try current.append(makeFieldName(noun.vari[1 .. noun.vari.len - 5]), kind);
const kind = try std.fmt.bufPrint(&buffer, ": ?{s},\n", .{makeStructName(drct.noun)});
try current.append(makeFieldName(drct.noun[1 .. drct.noun.len - 5]), kind);
},
.blob => unreachable,
}
},
.verb => |verb| {
else => |verb| {
data = data[drct.end..];
const name = makeStructName(verb.vari);
const name = makeStructName(drct.noun);
var this = try AbstTree.init(a, name);
const gop = try tree.getOrPut(this.name);
if (!gop.found_existing) {
@@ -152,25 +153,27 @@ fn emitVars(a: Allocator, fdata: []const u8, current: *AbstTree) !void {
this = gop.value_ptr.*;
}
 
switch (verb.word) {
switch (verb) {
.variable => unreachable,
.foreach => {
var buffer: [0xFF]u8 = undefined;
const kind = try std.fmt.bufPrint(&buffer, ": []const {s},\n", .{name});
try current.append(makeFieldName(verb.vari), kind);
try emitVars(a, verb.blob, this);
try current.append(makeFieldName(drct.noun), kind);
try emitVars(a, drct.otherwise.blob.trimmed, this);
},
.forrow => {
var buffer: [0xFF]u8 = undefined;
const kind = try std.fmt.bufPrint(&buffer, ": []const []const u8,\n", .{});
try current.append(makeFieldName(verb.vari), kind);
try emitVars(a, verb.blob, this);
try current.append(makeFieldName(drct.noun), kind);
try emitVars(a, drct.otherwise.blob.trimmed, this);
},
.with => {
var buffer: [0xFF]u8 = undefined;
const kind = try std.fmt.bufPrint(&buffer, ": ?{s},\n", .{name});
try current.append(makeFieldName(verb.vari), kind);
try emitVars(a, verb.blob, this);
try current.append(makeFieldName(drct.noun), kind);
try emitVars(a, drct.otherwise.blob.trimmed, this);
},
.build => unreachable,
}
},
} else if (std.mem.indexOfPos(u8, data, 1, "<")) |next| {
 
src/template.zig added: 428, removed: 271, total 157
@@ -4,9 +4,14 @@ const compiled = @import("templates-compiled");
pub const Structs = @import("templates-compiled-structs");
const isWhitespace = std.ascii.isWhitespace;
const indexOf = std.mem.indexOf;
const indexOfScalar = std.mem.indexOfScalar;
const indexOfPos = std.mem.indexOfPos;
const indexOfScalarPos = std.mem.indexOfScalarPos;
const lastIndexOf = std.mem.lastIndexOf;
const startsWith = std.mem.startsWith;
const count = std.mem.count;
const eql = std.mem.eql;
const isUpper = std.ascii.isUpper;
 
const Allocator = std.mem.Allocator;
 
@@ -173,11 +178,6 @@ pub const DataMap = struct {
}
};
 
pub const TemplateRuntime = struct {
name: []const u8 = "undefined",
blob: []const u8,
};
 
pub const Template = struct {
// path: []const u8,
name: []const u8 = "undefined",
@@ -205,255 +205,302 @@ pub const Template = struct {
};
 
pub const Directive = struct {
kind: Kind,
verb: Verb,
noun: []const u8,
otherwise: union(enum) {
ign: void,
del: void,
str: []const u8,
template: Template,
blob: struct {
trimmed: []const u8,
whitespace: []const u8,
},
} = .{ .ign = {} },
 
end: usize,
 
pub const Kind = union(enum) {
noun: Noun,
verb: Verb,
};
pub const Noun = struct {
vari: []const u8,
otherwise: union(enum) {
ign: void,
del: void,
str: []const u8,
template: Template,
} = .{ .ign = {} },
pub const Verb = enum {
variable,
foreach,
forrow,
with,
build,
};
 
pub const Verb = struct {
vari: []const u8,
blob: []const u8,
whitespace: []const u8,
word: Word,
const Positions = struct {
start: usize,
start_ws: usize,
end: usize,
end_ws: usize,
width: usize,
};
 
const Word = enum {
foreach,
forrow,
with,
pub fn initVerb(verb: []const u8, noun: []const u8, blob: []const u8) ?Directive {
var pos: Positions = undefined;
var word: Verb = undefined;
if (std.mem.eql(u8, verb, "For")) {
pos = calcPos("For", blob, noun) orelse return null;
word = .foreach;
} else if (std.mem.eql(u8, verb, "ForRow")) {
pos = calcPos("ForRow", blob, noun) orelse return null;
word = .forrow;
} else if (std.mem.eql(u8, verb, "With")) {
pos = calcPos("With", blob, noun) orelse return null;
word = .with;
} else if (std.mem.eql(u8, verb, "With")) {
pos = calcPos("With", blob, noun) orelse return null;
word = .with;
} else if (std.mem.eql(u8, verb, "Build")) {
const b_noun = noun[1..(indexOfScalarPos(u8, noun, 1, ' ') orelse return null)];
const tail = noun[b_noun.len + 1 ..];
const b_html = tail[1..(indexOfScalarPos(u8, tail, 2, ' ') orelse return null)];
if (getBuiltin(b_html)) |bi| {
return Directive{
.verb = .build,
.noun = b_noun,
.otherwise = .{ .template = bi },
.end = verb.len + 1 + noun.len,
};
} else if (getDynamic(b_html)) |bi| {
return Directive{
.verb = .build,
.noun = b_noun,
.otherwise = .{ .template = bi },
.end = verb.len + 1 + noun.len,
};
} else unreachable;
} else return null;
 
// TODO convert to while
//inline for (Word) |tag_name| {
// if (eql(u8, noun, @tagName(tag_name))) {
// pos = calcPos(@tagName(tag_name), blob, verb) orelse return null;
// word = tag_name;
// break;
// }
//} else return null;
 
std.debug.assert(pos.width > 1);
return .{
.verb = word,
.noun = noun[1..pos.width],
.otherwise = .{ .blob = .{
.trimmed = blob[pos.start..pos.end_ws],
.whitespace = blob[pos.start_ws..pos.end_ws],
} },
.end = pos.end,
};
}
 
const Positions = struct {
start: usize,
start_ws: usize,
end: usize,
end_ws: usize,
width: usize,
};
fn calcPos(comptime keyword: []const u8, blob: []const u8, noun: []const u8) ?Positions {
const open: *const [keyword.len + 2]u8 = "<" ++ keyword ++ " ";
const close: *const [keyword.len + 3]u8 = "</" ++ keyword ++ ">";
 
pub fn init(noun: []const u8, verb: []const u8, blob: []const u8) ?Directive {
var pos: Positions = undefined;
var word: Word = undefined;
if (std.mem.eql(u8, noun, "For")) {
pos = calcPos("For", blob, verb) orelse return null;
word = .foreach;
} else if (std.mem.eql(u8, noun, "ForRow")) {
pos = calcPos("ForRow", blob, verb) orelse return null;
word = .forrow;
} else if (std.mem.eql(u8, noun, "With")) {
pos = calcPos("With", blob, verb) orelse return null;
word = .with;
} else return null;
 
std.debug.assert(pos.width > 1);
return .{
.end = pos.end,
.kind = .{
.verb = .{
.vari = verb[1..pos.width],
.blob = blob[pos.start..pos.end_ws],
.whitespace = blob[pos.start_ws..pos.end_ws],
.word = word,
},
},
};
var start = 1 + (indexOf(u8, blob, ">") orelse return null);
var close_pos: usize = indexOfPos(u8, blob, 0, close) orelse return null;
var skip = count(u8, blob[start..close_pos], open);
while (skip > 0) : (skip -= 1) {
close_pos = indexOfPos(u8, blob, close_pos + 1, close) orelse close_pos;
}
 
fn calcPos(comptime keyword: []const u8, blob: []const u8, verb: []const u8) ?Positions {
const open: *const [keyword.len + 2]u8 = "<" ++ keyword ++ " ";
const close: *const [keyword.len + 3]u8 = "</" ++ keyword ++ ">";
const end = close_pos + close.len;
const end_ws = end - close.len;
const start_ws = start;
while (start < end and isWhitespace(blob[start])) : (start +|= 1) {}
 
var start = 1 + (indexOf(u8, blob, ">") orelse return null);
var close_pos: usize = indexOfPos(u8, blob, 0, close) orelse return null;
var skip = count(u8, blob[start..close_pos], open);
while (skip > 0) : (skip -= 1) {
close_pos = indexOfPos(u8, blob, close_pos + 1, close) orelse close_pos;
}
//while (endws > start and isWhitespace(blob[endws])) : (endws -|= 1) {}
//endws += 1;
 
const end = close_pos + close.len;
const end_ws = end - close.len;
const start_ws = start;
while (start < end and isWhitespace(blob[start])) : (start +|= 1) {}
 
//while (endws > start and isWhitespace(blob[endws])) : (endws -|= 1) {}
//endws += 1;
 
var width: usize = 1;
while (width < verb.len and validChar(verb[width])) {
width += 1;
}
return .{
.start = start,
.start_ws = start_ws,
.width = width,
.end = end,
.end_ws = end_ws,
};
var width: usize = 1;
while (width < noun.len and validChar(noun[width])) {
width += 1;
}
return .{
.start = start,
.start_ws = start_ws,
.width = width,
.end = end,
.end_ws = end_ws,
};
}
 
pub fn doTyped(self: Verb, T: type, ctx: anytype, out: anytype) anyerror!void {
var local: [0xff]u8 = undefined;
const realname = local[0..makeFieldName(self.vari, &local)];
inline for (std.meta.fields(T)) |field| {
if (field.type == []const u8 or
field.type == ?[]const u8) continue;
switch (@typeInfo(field.type)) {
.Pointer => {
if (std.mem.eql(u8, field.name, realname)) {
const child = @field(ctx, field.name);
for (child) |each| {
switch (field.type) {
[]const []const u8 => {
std.debug.assert(self.word == .forrow);
try out.writeAll(each);
try out.writeAll(self.whitespace);
},
else => {
std.debug.assert(self.word == .foreach);
try self.forEachTyped(@TypeOf(each), each, out);
},
}
pub fn doTyped(self: Directive, T: type, ctx: anytype, out: anytype) anyerror!void {
var local: [0xff]u8 = undefined;
const realname = local[0..makeFieldName(self.noun, &local)];
inline for (std.meta.fields(T)) |field| {
if (field.type == []const u8 or
field.type == ?[]const u8) continue;
switch (@typeInfo(field.type)) {
.Pointer => {
if (eql(u8, field.name, realname)) {
const child = @field(ctx, field.name);
for (child) |each| {
switch (field.type) {
[]const []const u8 => {
std.debug.assert(self.verb == .forrow);
try out.writeAll(each);
try out.writeAll(self.otherwise.blob.whitespace);
},
else => {
std.debug.assert(self.verb == .foreach);
try self.forEachTyped(@TypeOf(each), each, out);
},
}
}
},
.Optional => {
if (std.mem.eql(u8, field.name, realname)) {
const child = @field(ctx, field.name);
if (child) |exists| {
std.debug.assert(self.word == .with);
try self.withTyped(@TypeOf(exists), exists, out);
}
}
},
.Optional => {
if (eql(u8, field.name, realname)) {
const child = @field(ctx, field.name);
if (child) |exists| {
std.debug.assert(self.verb == .with);
try self.withTyped(@TypeOf(exists), exists, out);
}
},
else => comptime unreachable,
}
}
},
.Struct => {
if (eql(u8, field.name, realname)) {
const child = @field(ctx, field.name);
std.debug.assert(self.verb == .build);
try self.withTyped(@TypeOf(child), child, out);
}
},
else => comptime unreachable,
}
}
}
 
pub fn do(self: Verb, ctx: *const DataMap, out: anytype) anyerror!void {
if (ctx.getBlock(self.vari) catch |err| switch (err) {
error.NotABlock => ctx[0..1],
else => return err,
}) |block| {
switch (self.word) {
.foreach => for (block) |s| try self.forEach(s, out),
.forrow => for (block) |s| try self.forEach(s, out),
.with => {
std.debug.assert(block.len == 1);
try self.with(block[0], out);
},
}
return;
} else if (self.word == .foreach) {
std.debug.print("<For {s}> ctx block missing.\n", .{self.vari});
pub fn do(self: Directive, ctx: *const DataMap, out: anytype) anyerror!void {
if (ctx.getBlock(self.noun) catch |err| switch (err) {
error.NotABlock => ctx[0..1],
else => return err,
}) |block| {
switch (self.verb) {
.foreach => for (block) |s| try self.forEach(s, out),
.forrow => for (block) |s| try self.forEach(s, out),
.with => {
std.debug.assert(block.len == 1);
try self.with(block[0], out);
},
.build => unreachable,
.variable => unreachable,
}
return;
} else {
if (self.verb != .with)
std.debug.print("<For {s}> ctx block missing.\n", .{self.noun});
}
}
 
pub fn forEachTyped(self: Directive, T: type, data: T, out: anytype) anyerror!void {
var p = PageRuntime(T){
.data = data,
.template = .{
.name = self.noun,
.blob = self.otherwise.blob.trimmed,
},
};
try p.format("", .{}, out);
}
 
pub fn forEach(self: Directive, block: DataMap, out: anytype) anyerror!void {
try self.forEachTyped(DataMap, block, out);
}
 
pub fn withTyped(self: Directive, T: type, block: T, out: anytype) anyerror!void {
var p = PageRuntime(T){
.data = block,
.template = if (self.otherwise == .template) self.otherwise.template else .{
.name = self.noun,
.blob = self.otherwise.blob.trimmed,
},
};
try p.format("", .{}, out);
}
 
pub fn with(self: Directive, data: DataMap, out: anytype) anyerror!void {
return try self.withTyped(DataMap, data, out);
}
 
fn getDynamic(name: []const u8) ?Template {
for (0..dynamic.len) |i| {
if (eql(u8, dynamic[i].name, name)) {
return dynamic[i];
}
}
return null;
}
 
pub fn forEachTyped(self: Verb, T: type, data: T, out: anytype) anyerror!void {
var p = PageRuntime(T){
.data = data,
.template = .{
.name = self.vari,
.blob = self.blob,
},
};
try p.format("", .{}, out);
fn getBuiltin(name: []const u8) ?Template {
for (0..builtin.len) |i| {
if (eql(u8, builtin[i].name, name)) {
return builtin[i];
}
}
 
pub fn forEach(self: Verb, block: DataMap, out: anytype) anyerror!void {
try self.forEachTyped(DataMap, block, out);
}
 
pub fn withTyped(self: Verb, T: type, block: T, out: anytype) anyerror!void {
var p = PageRuntime(T){
.data = block,
.template = .{
.name = self.vari,
.blob = self.blob,
},
};
try p.format("", .{}, out);
}
 
pub fn with(self: Verb, data: DataMap, out: anytype) anyerror!void {
return try self.withTyped(DataMap, data, out);
}
};
return null;
}
 
pub fn init(str: []const u8) ?Directive {
if (str.len < 2) return null;
if (!std.ascii.isUpper(str[1]) and str[1] != '_') return null;
const end = 1 + (std.mem.indexOf(u8, str, ">") orelse return null);
if (!isUpper(str[1]) and str[1] != '_') return null;
const end = 1 + (indexOf(u8, str, ">") orelse return null);
const tag = str[0..end];
const verb = tag[1 .. indexOfScalar(u8, tag, ' ') orelse tag.len - 1];
 
if (verb.len == tag.len - 2) {
if (verb[0] == '_') {
if (getBuiltin(verb)) |bi| {
return Directive{
.noun = verb,
.verb = .variable,
.otherwise = .{ .template = bi },
.end = end,
};
}
}
return Directive{
.verb = .variable,
.noun = verb,
.end = end,
};
}
 
var width: usize = 1;
while (width < str.len and validChar(str[width])) {
width += 1;
}
 
const vari = str[1..width];
const verb = str[width..];
const noun = tag[verb.len + 1 ..];
 
if (vari[0] == '_') {
for (0..builtin.len) |subtemp_i| {
if (std.mem.eql(u8, builtin[subtemp_i].name, vari)) {
return Directive{
.end = end,
.kind = .{ .noun = .{
.vari = vari,
.otherwise = .{ .template = builtin[subtemp_i] },
} },
};
}
}
return Directive{
.end = end,
.kind = .{ .noun = .{
.vari = vari,
} },
};
} else if (Verb.init(vari, verb, str)) |kind| {
if (initVerb(verb, noun, str)) |kind| {
return kind;
} else if (std.mem.startsWith(u8, verb, " ORELSE ")) {
return Directive{
.end = end,
.kind = .{
.noun = .{
.vari = str[1..width],
.otherwise = .{ .str = str[width + 8 .. end - 1] },
},
},
};
} else if (std.mem.startsWith(u8, verb, " ORNULL>")) {
return Directive{
.end = end,
.kind = .{ .noun = .{
.vari = str[1..width],
.otherwise = .{ .del = {} },
} },
};
} else {
return Directive{
.end = end,
.kind = .{ .noun = .{
.vari = vari,
} },
};
}
if (startsWith(u8, noun, " ORELSE ")) {
return Directive{
.verb = .variable,
.noun = verb,
.otherwise = .{ .str = tag[width + 8 .. end - 1] },
.end = end,
};
} else if (startsWith(u8, noun, " ORNULL>")) {
return Directive{
.verb = .variable,
.noun = verb,
.otherwise = .{ .del = {} },
.end = end,
};
} else if (startsWith(u8, noun, " />")) {
return Directive{
.verb = .variable,
.noun = verb,
.end = end,
};
} else return null;
}
};
 
fn tail(path: []const u8) []const u8 {
fn tailPath(path: []const u8) []const u8 {
if (std.mem.indexOf(u8, path, "/")) |i| {
return path[i + 1 ..];
}
@@ -466,14 +513,14 @@ pub const builtin: [compiled.data.len]Template = blk: {
for (compiled.data, &t) |filedata, *dst| {
dst.* = Template{
//.path = filedata.path,
.name = tail(filedata.path),
.name = tailPath(filedata.path),
.blob = filedata.blob,
};
}
break :blk t;
};
 
pub var dynamic: []Template = undefined;
pub var dynamic: []const Template = undefined;
 
fn loadTemplates(a: Allocator) !void {
var cwd = std.fs.cwd();
@@ -492,8 +539,8 @@ fn loadTemplates(a: Allocator) !void {
file.name,
});
defer a.free(name);
const tail_ = tail(file.name);
const name_ = try a.dupe(u8, tail_);
const tail = tailPath(file.name);
const name_ = try a.dupe(u8, tail);
try list.append(.{
//.path = path,
.name = name_,
@@ -685,6 +732,54 @@ test "directive something" {
try std.testing.expectEqualStrings("Some Text Here", p);
}
 
test "directive typed something" {
var a = std.testing.allocator;
 
const Something = struct {
something: []const u8,
};
 
const t = Template{
//.path = "/dev/null",
.name = "test",
.blob = "<Something>",
};
 
const page = Page(t, Something);
 
const p = page.init(.{
.something = "Some Text Here",
});
 
const built = try p.build(a);
defer a.free(built);
try std.testing.expectEqualStrings("Some Text Here", built);
}
 
test "directive typed something /" {
var a = std.testing.allocator;
 
const Something = struct {
something: []const u8,
};
 
const t = Template{
//.path = "/dev/null",
.name = "test",
.blob = "<Something />",
};
 
const page = Page(t, Something);
 
const p = page.init(.{
.something = "Some Text Here",
});
 
const built = try p.build(a);
defer a.free(built);
try std.testing.expectEqualStrings("Some Text Here", built);
}
 
test "directive nothing" {
var a = std.testing.allocator;
var t = Template{
@@ -1044,3 +1139,55 @@ test "directive ForRow" {
defer a.free(build);
try std.testing.expectEqualStrings(expected, build);
}
 
test "directive Build" {
var a = std.testing.allocator;
 
const blob =
\\<Build Name _template.html />
;
 
const expected: []const u8 =
\\<div>
\\AliceBobCharlieEve
\\</div>
;
 
const FE = struct {
const This = struct {
this: []const u8,
};
name: struct {
slice: []const This,
},
};
 
const t = Template{
//.path = "/dev/null",
.name = "test",
.blob = blob,
};
const page = Page(t, FE);
 
dynamic = &[1]Template{
.{
.name = "_template.html",
.blob = "<div>\n<For Slice><This></For>\n</div>",
},
};
 
const slice = FE{
.name = .{
.slice = &[4]FE.This{
.{ .this = "Alice" },
.{ .this = "Bob" },
.{ .this = "Charlie" },
.{ .this = "Eve" },
},
},
};
const p = page.init(slice);
const build = try p.build(a);
defer a.free(build);
try std.testing.expectEqualStrings(expected, build);
}
 
src/template/page.zig added: 428, removed: 271, total 157
@@ -1,9 +1,10 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const eql = std.mem.eql;
 
const Templates = @import("../template.zig");
const Template = Templates.Template;
const TemplateRuntime = Templates.TemplateRuntime;
//const TemplateRuntime = Templates.TemplateRuntime;
const DataMap = Templates.DataMap;
const Directive = Templates.Directive;
 
@@ -18,10 +19,10 @@ pub fn PageRuntime(comptime PageDataType: type) type {
return struct {
pub const Self = @This();
pub const Kind = PageDataType;
template: TemplateRuntime,
template: Template,
data: PageDataType,
 
pub fn init(t: TemplateRuntime, d: PageDataType) PageRuntime(PageDataType) {
pub fn init(t: Template, d: PageDataType) PageRuntime(PageDataType) {
return .{
.template = t,
.data = d,
@@ -60,9 +61,10 @@ pub fn PageRuntime(comptime PageDataType: type) type {
drct: Directive,
out: anytype,
) anyerror!void {
switch (drct.kind) {
.noun => |noun| {
const var_name = ctx.get(noun.vari);
switch (drct.verb) {
.variable => {
const noun = drct.noun;
const var_name = ctx.get(noun);
if (var_name) |v_blob| {
switch (v_blob) {
.slice => |s_blob| try out.writeAll(s_blob),
@@ -70,8 +72,8 @@ pub fn PageRuntime(comptime PageDataType: type) type {
.reader => |_| unreachable,
}
} else {
if (DEBUG) std.debug.print("[missing var {s}]\n", .{noun.vari});
switch (noun.otherwise) {
if (DEBUG) std.debug.print("[missing var {s}]\n", .{noun});
switch (drct.otherwise) {
.str => |str| try out.writeAll(str),
// Not really an error, just instruct caller to print original text
.ign => return error.IgnoreDirective,
@@ -83,10 +85,11 @@ pub fn PageRuntime(comptime PageDataType: type) type {
unreachable;
};
},
.blob => unreachable,
}
}
},
.verb => |verb| verb.do(ctx, out) catch unreachable,
else => drct.do(ctx, out) catch unreachable,
}
}
 
@@ -97,14 +100,15 @@ pub fn PageRuntime(comptime PageDataType: type) type {
drct: Directive,
out: anytype,
) anyerror!void {
switch (drct.kind) {
.noun => |noun| {
const var_name = typeField(noun.vari, ctx);
switch (drct.verb) {
.variable => {
const noun = drct.noun;
const var_name = typeField(noun, ctx);
if (var_name) |data_blob| {
try out.writeAll(data_blob);
} else {
if (DEBUG) std.debug.print("[missing var {s}]\n", .{noun.vari});
switch (noun.otherwise) {
switch (drct.otherwise) {
.str => |str| try out.writeAll(str),
// Not really an error, just instruct caller to print original text
.ign => return error.IgnoreDirective,
@@ -116,7 +120,7 @@ pub fn PageRuntime(comptime PageDataType: type) type {
if (otype.child == []const u8) continue;
 
var local: [0xff]u8 = undefined;
const realname = local[0..makeFieldName(noun.vari[1 .. noun.vari.len - 5], &local)];
const realname = local[0..makeFieldName(noun[1 .. noun.len - 5], &local)];
if (std.mem.eql(u8, field.name, realname)) {
if (@field(self.data, field.name)) |subdata| {
var subpage = subt.pageOf(otype.child, subdata);
@@ -137,12 +141,11 @@ pub fn PageRuntime(comptime PageDataType: type) type {
else => {}, //@compileLog(field.type),
};
},
.blob => unreachable,
}
}
},
.verb => |verb| {
verb.doTyped(PageDataType, ctx, out) catch unreachable;
},
else => drct.doTyped(PageDataType, ctx, out) catch unreachable,
}
}
pub fn format(self: Self, comptime fmts: []const u8, _: std.fmt.FormatOptions, out: anytype) !void {
@@ -218,9 +221,10 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
drct: Directive,
out: anytype,
) anyerror!void {
switch (drct.kind) {
.noun => |noun| {
const var_name = ctx.get(noun.vari);
switch (drct.verb) {
.variable => {
const noun = drct.noun;
const var_name = ctx.get(noun);
if (var_name) |v_blob| {
switch (v_blob) {
.slice => |s_blob| try out.writeAll(s_blob),
@@ -229,7 +233,7 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
}
} else {
if (DEBUG) std.debug.print("[missing var {s}]\n", .{noun.vari});
switch (noun.otherwise) {
switch (drct.otherwise) {
.str => |str| try out.writeAll(str),
// Not really an error, just instruct caller to print original text
.ign => return error.IgnoreDirective,
@@ -241,10 +245,11 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
unreachable;
};
},
.blob => unreachable,
}
}
},
.verb => |verb| verb.do(ctx, out) catch unreachable,
else => drct.do(ctx, out) catch unreachable,
}
}
 
@@ -255,14 +260,15 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
drct: Directive,
out: anytype,
) anyerror!void {
switch (drct.kind) {
.noun => |noun| {
const var_name = typeField(noun.vari, ctx);
switch (drct.verb) {
.variable => {
const noun = drct.noun;
const var_name = typeField(noun, ctx);
if (var_name) |data_blob| {
try out.writeAll(data_blob);
} else {
if (DEBUG) std.debug.print("[missing var {s}]\n", .{noun.vari});
switch (noun.otherwise) {
if (DEBUG) std.debug.print("[missing var {s}]\n", .{noun});
switch (drct.otherwise) {
.str => |str| try out.writeAll(str),
// Not really an error, just instruct caller to print original text
.ign => return error.IgnoreDirective,
@@ -274,8 +280,8 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
if (otype.child == []const u8) continue;
 
var local: [0xff]u8 = undefined;
const realname = local[0..makeFieldName(noun.vari[1 .. noun.vari.len - 5], &local)];
if (std.mem.eql(u8, field.name, realname)) {
const realname = local[0..makeFieldName(noun[1 .. noun.len - 5], &local)];
if (eql(u8, field.name, realname)) {
if (@field(self.data, field.name)) |subdata| {
var subpage = subt.pageOf(otype.child, subdata);
try subpage.format(fmts, .{}, out);
@@ -286,7 +292,7 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
}
},
.Struct => {
if (std.mem.eql(u8, field.name, noun.vari)) {
if (eql(u8, field.name, noun)) {
const subdata = @field(self.data, field.name);
var subpage = subt.pageOf(@TypeOf(subdata), subdata);
try subpage.format(fmts, .{}, out);
@@ -295,11 +301,12 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
else => {}, //@compileLog(field.type),
};
},
.blob => unreachable,
}
}
},
.verb => |verb| {
verb.doTyped(PageDataType, ctx, out) catch unreachable;
else => {
drct.doTyped(PageDataType, ctx, out) catch unreachable;
},
}
}