Add @isTag builtin

This commit is contained in:
jaina heartles 2022-12-10 00:32:24 -08:00
parent 4e3450de4e
commit b2007131c8
2 changed files with 90 additions and 1 deletions

View file

@ -1,6 +1,7 @@
const std = @import("std");
pub fn main() !void {
const Enum = enum { foo, bar };
try execute(
std.io.getStdOut().writer(),
.{ .test_tmpl = "{.x} {%context_foo}" },
@ -18,6 +19,7 @@ pub fn main() !void {
.quxx2 = true,
.maybe_foo = @as(?[]const u8, "foo"),
.maybe_bar = @as(?[]const u8, null),
.snap = Enum.bar,
.x = "y",
},
.{
@ -170,6 +172,9 @@ fn EvaluateExpression(
.capture_deref => |names| Deref(Captures, names),
.context_deref => |names| Deref(Context, names),
.equals => bool,
.builtin => |call| switch (call.*) {
.isTag => bool,
},
};
}
@ -193,6 +198,12 @@ fn evaluateExpression(
return T.eql(lhs, rhs);
} else return lhs == rhs;
},
.builtin => |call| switch (call.*) {
.isTag => |hdr| {
const val = evaluateExpression(hdr.expression, args, captures, context);
return std.meta.isTag(val, hdr.tag);
},
},
};
}
@ -402,6 +413,8 @@ fn parseTemplateTokens(comptime tokens: ControlTokenIter) []const TemplateToken
.at => items = items ++ [_]TemplateToken{.{ .text = "@" }},
.comma => items = items ++ [_]TemplateToken{.{ .text = "," }},
.percent => items = items ++ [_]TemplateToken{.{ .text = "%" }},
.open_paren => items = items ++ [_]TemplateToken{.{ .text = "(" }},
.close_paren => items = items ++ [_]TemplateToken{.{ .text = ")" }},
};
return items;
@ -419,18 +432,21 @@ fn parseExpression(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIt
.period => {
const names = parseDeref(iter);
iter = names.new_iter;
if (expr != null) break;
expr = .{ .arg_deref = names.item };
last_valid_iter = iter;
},
.dollar => {
const names = parseDeref(iter);
iter = names.new_iter;
if (expr != null) break;
expr = .{ .capture_deref = names.item };
last_valid_iter = iter;
},
.percent => {
const names = parseDeref(iter);
iter = names.new_iter;
if (expr != null) break;
expr = .{ .context_deref = names.item };
last_valid_iter = iter;
},
@ -450,6 +466,13 @@ fn parseExpression(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIt
last_valid_iter = iter;
} else break;
},
.at => {
if (expr != null) break;
const builtin = parseBuiltin(iter);
iter = builtin.new_iter;
expr = .{ .builtin = &builtin.item };
last_valid_iter = iter;
},
else => break,
};
@ -460,6 +483,54 @@ fn parseExpression(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIt
}
}
fn expectToken(comptime token: ?ControlToken, comptime exp: std.meta.Tag(ControlToken)) void {
comptime {
if (token == null) @compileError("Unexpected End Of Template");
const token_tag = std.meta.activeTag(token.?);
if (token_tag != exp)
@compileError("Expected " ++ @tagName(exp) ++ ", got " ++ @tagName(token_tag));
}
}
fn parseBuiltin(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter, BuiltinCall) {
comptime {
var iter = tokens;
const builtin = blk: {
const next = iter.next() orelse @compileError("Invalid Builtin");
if (next != .text) @compileError("Invalid Builtin");
break :blk std.meta.stringToEnum(Builtin, next.text) orelse @compileError("Invalid Builtin");
};
iter = skipWhitespace(iter);
expectToken(iter.next(), .open_paren);
iter = skipWhitespace(iter);
const call = switch (builtin) {
.isTag => blk: {
const expr = parseExpression(iter);
iter = expr.new_iter;
expectToken(iter.next(), .comma);
iter = skipWhitespace(iter);
const tag = iter.next();
expectToken(tag, .text);
break :blk .{
.isTag = .{
.tag = tag.?.text,
.expression = expr.item,
},
};
},
};
iter = skipWhitespace(iter);
expectToken(iter.next(), .close_paren);
return .{
.new_iter = iter,
.item = call,
};
}
}
fn parseControlBlock(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter, ControlBlock) {
comptime {
var iter = tokens;
@ -745,6 +816,7 @@ const Expression = union(enum) {
capture_deref: []const []const u8,
context_deref: []const []const u8,
equals: *const EqualsExpr,
builtin: *const BuiltinCall,
};
const For = struct {
@ -812,6 +884,17 @@ const EndKeyword = enum {
@"if",
};
const Builtin = enum {
isTag,
};
const BuiltinCall = union(Builtin) {
isTag: struct {
tag: []const u8,
expression: Expression,
},
};
const ControlToken = union(enum) {
text: []const u8,
open_bracket: void,
@ -826,6 +909,8 @@ const ControlToken = union(enum) {
at: void,
comma: void,
percent: void,
open_paren: void,
close_paren: void,
};
const ControlTokenIter = struct {
@ -858,6 +943,8 @@ const ControlTokenIter = struct {
'@' => return .{ .at = {} },
',' => return .{ .comma = {} },
'%' => return .{ .percent = {} },
'(' => return .{ .open_paren = {} },
')' => return .{ .close_paren = {} },
' ', '\t', '\n', '\r' => {
var idx: usize = 0;
while (idx < remaining.len and std.mem.indexOfScalar(u8, " \t\n\r", remaining[idx]) != null) : (idx += 1) {}
@ -869,7 +956,7 @@ const ControlTokenIter = struct {
},
else => {
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) {}
self.start += idx - 1;
return .{ .text = remaining[0..idx] };

View file

@ -16,6 +16,8 @@
{= /for}
{#if .quxx == .quxx2}eql{#else}neq{/if}
{#if .quxx == .qux}eql{#else}neq{/if}
{#if @isTag(.snap, foo)}foo{/if}
{#if @isTag(.snap, bar)}bar{/if}
{#if .qux=}
qux
{=#elif .quxx=}