Parse for loop
This commit is contained in:
parent
efb50a325b
commit
934296b384
2 changed files with 98 additions and 26 deletions
|
@ -7,8 +7,9 @@ pub fn main() !void {
|
||||||
const logging = false;
|
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 {
|
||||||
const items = comptime parseTemplate(template);
|
@setEvalBranchQuota(@intCast(u32, template.len * 6));
|
||||||
try executeTemplate(writer, items, args);
|
const tmpl = comptime parseTemplate(TokenIter{ .text = template }, .root);
|
||||||
|
try executeTemplate(writer, tmpl.item, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn executeTemplate(writer: anytype, comptime items: []const TemplateItem, args: anytype) !void {
|
fn executeTemplate(writer: anytype, comptime items: []const TemplateItem, args: anytype) !void {
|
||||||
|
@ -23,6 +24,9 @@ fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype) !v
|
||||||
.expression => |expr| switch (expr) {
|
.expression => |expr| switch (expr) {
|
||||||
.arg_deref => |fields| try argDeref(writer, fields, args),
|
.arg_deref => |fields| try argDeref(writer, fields, args),
|
||||||
},
|
},
|
||||||
|
.for_loop => {
|
||||||
|
try writer.writeAll("For loop");
|
||||||
|
},
|
||||||
else => @compileError("TODO"),
|
else => @compileError("TODO"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,14 +41,18 @@ fn argDeref(writer: anytype, comptime names: []const []const u8, arg: anytype) !
|
||||||
return argDeref(writer, names[1..], @field(arg, names[0]));
|
return argDeref(writer, names[1..], @field(arg, names[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseTemplate(comptime template: []const u8) []const TemplateItem {
|
const TemplateType = enum {
|
||||||
|
root,
|
||||||
|
subtemplate,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn parseTemplate(comptime tokens: TokenIter, comptime template_type: TemplateType) ParseResult([]const TemplateItem) {
|
||||||
comptime {
|
comptime {
|
||||||
@setEvalBranchQuota(@intCast(u32, template.len * 6));
|
var iter = tokens;
|
||||||
var iter = TokenIter{ .text = template };
|
|
||||||
var items: []const TemplateItem = &.{};
|
var items: []const TemplateItem = &.{};
|
||||||
var current_text: []const u8 = "";
|
var current_text: []const u8 = "";
|
||||||
|
|
||||||
while (iter.next()) |token| {
|
parse_loop: while (iter.next()) |token| {
|
||||||
if (logging) @compileLog(token);
|
if (logging) @compileLog(token);
|
||||||
switch (token) {
|
switch (token) {
|
||||||
.whitespace, .text => |text| current_text = current_text ++ text,
|
.whitespace, .text => |text| current_text = current_text ++ text,
|
||||||
|
@ -60,6 +68,9 @@ fn parseTemplate(comptime template: []const u8) []const TemplateItem {
|
||||||
}
|
}
|
||||||
const result = parseStatement(iter);
|
const result = parseStatement(iter);
|
||||||
iter = result.new_iter;
|
iter = result.new_iter;
|
||||||
|
if (result.item == .end_for) {
|
||||||
|
if (template_type == .subtemplate) break :parse_loop else @compileError("Unexpected end statement");
|
||||||
|
}
|
||||||
items = items ++ [_]TemplateItem{.{ .statement = result.item }};
|
items = items ++ [_]TemplateItem{.{ .statement = result.item }};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -76,40 +87,94 @@ fn parseTemplate(comptime template: []const u8) []const TemplateItem {
|
||||||
items = items ++ [_]TemplateItem{.{ .text = current_text }};
|
items = items ++ [_]TemplateItem{.{ .text = current_text }};
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return .{
|
||||||
|
.new_iter = iter,
|
||||||
|
.item = items,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseStatement(comptime tokens: TokenIter) ParseResult(Statement) {
|
fn parseStatement(comptime tokens: TokenIter) ParseResult(Statement) {
|
||||||
comptime {
|
comptime {
|
||||||
var iter = tokens;
|
var iter = tokens;
|
||||||
while (iter.next()) |token| switch (token) {
|
var stmt: Statement = while (iter.next()) |token| switch (token) {
|
||||||
.whitespace => {},
|
.whitespace => {},
|
||||||
.pound => {
|
.pound => {
|
||||||
const next = iter.next() orelse @compileError("Unexpected end of template");
|
const next = iter.next() orelse @compileError("Unexpected end of template");
|
||||||
if (logging) @compileLog("keyword", next);
|
|
||||||
if (next != .text) @compileError("Expected keyword following '#' character");
|
if (next != .text) @compileError("Expected keyword following '#' character");
|
||||||
const text = next.text;
|
const text = next.text;
|
||||||
const keyword = std.meta.stringToEnum(Keyword, text) orelse @compileError("Unknown keyword: " ++ text);
|
const keyword = std.meta.stringToEnum(Keyword, text) orelse @compileError("Unknown keyword: " ++ text);
|
||||||
|
|
||||||
_ = keyword;
|
switch (keyword) {
|
||||||
@panic("todo");
|
.end_for => break .{ .end_for = {} },
|
||||||
|
.@"for" => {
|
||||||
|
const result = parseForLoop(iter);
|
||||||
|
// statemnt already finished so just return
|
||||||
|
return .{
|
||||||
|
.new_iter = result.new_iter,
|
||||||
|
.item = .{ .for_loop = result.item },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
//else => @compileError("TODO"),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.period => {
|
.period => {
|
||||||
const expr = parseArgDeref(iter);
|
const expr = parseArgDeref(iter);
|
||||||
iter = expr.new_iter;
|
iter = expr.new_iter;
|
||||||
while (iter.next()) |it| switch (it) {
|
break .{ .expression = .{ .arg_deref = expr.item } };
|
||||||
.whitespace => {},
|
|
||||||
.close_bracket => break,
|
|
||||||
else => @compileError("TODO"),
|
|
||||||
};
|
|
||||||
return .{ .new_iter = iter, .item = .{
|
|
||||||
.expression = .{ .arg_deref = expr.item },
|
|
||||||
} };
|
|
||||||
},
|
},
|
||||||
else => @compileError(""),
|
else => @compileError(""),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// search for end of statement
|
||||||
|
while (iter.next()) |token| switch (token) {
|
||||||
|
.whitespace => {},
|
||||||
|
.close_bracket => return .{
|
||||||
|
.new_iter = iter,
|
||||||
|
.item = stmt,
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
@compileLog(iter.row);
|
||||||
|
@compileError("TODO" ++ @tagName(token));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@compileError("Unexpected end of template");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseForLoop(comptime tokens: TokenIter) ParseResult(ForLoop) {
|
||||||
|
comptime {
|
||||||
|
const indexable = parseExpression(tokens);
|
||||||
|
var iter = indexable.new_iter;
|
||||||
|
while (iter.next()) |token| switch (token) {
|
||||||
|
.whitespace => {},
|
||||||
|
.close_bracket => break,
|
||||||
|
else => @compileError("Unexpected token"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const subtemplate = parseTemplate(iter, .subtemplate);
|
||||||
|
|
||||||
|
return .{ .new_iter = subtemplate.new_iter, .item = .{
|
||||||
|
.indexable = indexable.item,
|
||||||
|
.subtemplate = subtemplate.item,
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseExpression(comptime tokens: TokenIter) ParseResult(Expression) {
|
||||||
|
comptime {
|
||||||
|
var iter = tokens;
|
||||||
|
while (iter.next()) |token| switch (token) {
|
||||||
|
.whitespace => {},
|
||||||
|
.period => {
|
||||||
|
const deref = parseArgDeref(iter);
|
||||||
|
return .{ .new_iter = deref.new_iter, .item = .{ .arg_deref = deref.item } };
|
||||||
|
},
|
||||||
|
else => @compileError("Expected Expression"),
|
||||||
|
};
|
||||||
|
|
||||||
@compileError("Unexpected end of template");
|
@compileError("Unexpected end of template");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,14 +222,15 @@ const Expression = union(enum) {
|
||||||
arg_deref: []const []const u8,
|
arg_deref: []const []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ForLoop = struct {
|
||||||
|
subtemplate: []const TemplateItem,
|
||||||
|
indexable: Expression,
|
||||||
|
};
|
||||||
|
|
||||||
const Statement = union(enum) {
|
const Statement = union(enum) {
|
||||||
expression: Expression,
|
expression: Expression,
|
||||||
for_loop: struct {
|
for_loop: ForLoop,
|
||||||
subtemplate: []const u8,
|
end_for: void,
|
||||||
indexable: Expression,
|
|
||||||
iteration_capture: []const u8,
|
|
||||||
index_capture: ?[]const u8,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const State = enum {
|
const State = enum {
|
||||||
|
@ -176,6 +242,7 @@ const State = enum {
|
||||||
|
|
||||||
const Keyword = enum {
|
const Keyword = enum {
|
||||||
@"for",
|
@"for",
|
||||||
|
end_for,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Token = union(enum) {
|
const Token = union(enum) {
|
||||||
|
@ -192,6 +259,8 @@ const TokenIter = struct {
|
||||||
text: []const u8,
|
text: []const u8,
|
||||||
peeked_token: ?Token = null,
|
peeked_token: ?Token = null,
|
||||||
|
|
||||||
|
row: usize = 0,
|
||||||
|
|
||||||
fn next(self: *TokenIter) ?Token {
|
fn next(self: *TokenIter) ?Token {
|
||||||
if (self.peeked_token) |token| {
|
if (self.peeked_token) |token| {
|
||||||
self.peeked_token = null;
|
self.peeked_token = null;
|
||||||
|
@ -211,6 +280,8 @@ const TokenIter = struct {
|
||||||
' ', '\t', '\n', '\r' => {
|
' ', '\t', '\n', '\r' => {
|
||||||
var idx: usize = 0;
|
var idx: usize = 0;
|
||||||
while (idx < remaining.len and std.mem.indexOfScalar(u8, " \t\n\r", remaining[idx]) != null) : (idx += 1) {}
|
while (idx < remaining.len and std.mem.indexOfScalar(u8, " \t\n\r", remaining[idx]) != null) : (idx += 1) {}
|
||||||
|
const newline_count = std.mem.count(u8, remaining[0..idx], "\n");
|
||||||
|
self.row += newline_count;
|
||||||
|
|
||||||
self.start += idx - 1;
|
self.start += idx - 1;
|
||||||
return .{ .whitespace = remaining[0..idx] };
|
return .{ .whitespace = remaining[0..idx] };
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
<h2> {{ REAL BRACKETS }} </h2>
|
<h2> {{ REAL BRACKETS }} </h2>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
{{#for .community}}
|
{#for .community}
|
||||||
|
{#end_for}
|
||||||
{{#for args.notes |$note, $i|}}
|
{{#for args.notes |$note, $i|}}
|
||||||
<h3>Note no. {{$i}}</h3>
|
<h3>Note no. {{$i}}</h3>
|
||||||
{{#template note_display ($note)}}
|
{{#template note_display ($note)}}
|
||||||
|
|
Loading…
Reference in a new issue