Add @isTag builtin
This commit is contained in:
parent
4e3450de4e
commit
b2007131c8
2 changed files with 90 additions and 1 deletions
|
@ -1,6 +1,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
|
const Enum = enum { foo, bar };
|
||||||
try execute(
|
try execute(
|
||||||
std.io.getStdOut().writer(),
|
std.io.getStdOut().writer(),
|
||||||
.{ .test_tmpl = "{.x} {%context_foo}" },
|
.{ .test_tmpl = "{.x} {%context_foo}" },
|
||||||
|
@ -18,6 +19,7 @@ pub fn main() !void {
|
||||||
.quxx2 = true,
|
.quxx2 = true,
|
||||||
.maybe_foo = @as(?[]const u8, "foo"),
|
.maybe_foo = @as(?[]const u8, "foo"),
|
||||||
.maybe_bar = @as(?[]const u8, null),
|
.maybe_bar = @as(?[]const u8, null),
|
||||||
|
.snap = Enum.bar,
|
||||||
.x = "y",
|
.x = "y",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
|
@ -170,6 +172,9 @@ fn EvaluateExpression(
|
||||||
.capture_deref => |names| Deref(Captures, names),
|
.capture_deref => |names| Deref(Captures, names),
|
||||||
.context_deref => |names| Deref(Context, names),
|
.context_deref => |names| Deref(Context, names),
|
||||||
.equals => bool,
|
.equals => bool,
|
||||||
|
.builtin => |call| switch (call.*) {
|
||||||
|
.isTag => bool,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,6 +198,12 @@ fn evaluateExpression(
|
||||||
return T.eql(lhs, rhs);
|
return T.eql(lhs, rhs);
|
||||||
} else return 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 = "@" }},
|
.at => items = items ++ [_]TemplateToken{.{ .text = "@" }},
|
||||||
.comma => items = items ++ [_]TemplateToken{.{ .text = "," }},
|
.comma => items = items ++ [_]TemplateToken{.{ .text = "," }},
|
||||||
.percent => items = items ++ [_]TemplateToken{.{ .text = "%" }},
|
.percent => items = items ++ [_]TemplateToken{.{ .text = "%" }},
|
||||||
|
.open_paren => items = items ++ [_]TemplateToken{.{ .text = "(" }},
|
||||||
|
.close_paren => items = items ++ [_]TemplateToken{.{ .text = ")" }},
|
||||||
};
|
};
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
|
@ -419,18 +432,21 @@ fn parseExpression(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIt
|
||||||
.period => {
|
.period => {
|
||||||
const names = parseDeref(iter);
|
const names = parseDeref(iter);
|
||||||
iter = names.new_iter;
|
iter = names.new_iter;
|
||||||
|
if (expr != null) break;
|
||||||
expr = .{ .arg_deref = names.item };
|
expr = .{ .arg_deref = names.item };
|
||||||
last_valid_iter = iter;
|
last_valid_iter = iter;
|
||||||
},
|
},
|
||||||
.dollar => {
|
.dollar => {
|
||||||
const names = parseDeref(iter);
|
const names = parseDeref(iter);
|
||||||
iter = names.new_iter;
|
iter = names.new_iter;
|
||||||
|
if (expr != null) break;
|
||||||
expr = .{ .capture_deref = names.item };
|
expr = .{ .capture_deref = names.item };
|
||||||
last_valid_iter = iter;
|
last_valid_iter = iter;
|
||||||
},
|
},
|
||||||
.percent => {
|
.percent => {
|
||||||
const names = parseDeref(iter);
|
const names = parseDeref(iter);
|
||||||
iter = names.new_iter;
|
iter = names.new_iter;
|
||||||
|
if (expr != null) break;
|
||||||
expr = .{ .context_deref = names.item };
|
expr = .{ .context_deref = names.item };
|
||||||
last_valid_iter = iter;
|
last_valid_iter = iter;
|
||||||
},
|
},
|
||||||
|
@ -450,6 +466,13 @@ fn parseExpression(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIt
|
||||||
last_valid_iter = iter;
|
last_valid_iter = iter;
|
||||||
} else break;
|
} 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,
|
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) {
|
fn parseControlBlock(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter, ControlBlock) {
|
||||||
comptime {
|
comptime {
|
||||||
var iter = tokens;
|
var iter = tokens;
|
||||||
|
@ -745,6 +816,7 @@ const Expression = union(enum) {
|
||||||
capture_deref: []const []const u8,
|
capture_deref: []const []const u8,
|
||||||
context_deref: []const []const u8,
|
context_deref: []const []const u8,
|
||||||
equals: *const EqualsExpr,
|
equals: *const EqualsExpr,
|
||||||
|
builtin: *const BuiltinCall,
|
||||||
};
|
};
|
||||||
|
|
||||||
const For = struct {
|
const For = struct {
|
||||||
|
@ -812,6 +884,17 @@ const EndKeyword = enum {
|
||||||
@"if",
|
@"if",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Builtin = enum {
|
||||||
|
isTag,
|
||||||
|
};
|
||||||
|
|
||||||
|
const BuiltinCall = union(Builtin) {
|
||||||
|
isTag: struct {
|
||||||
|
tag: []const u8,
|
||||||
|
expression: Expression,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const ControlToken = union(enum) {
|
const ControlToken = union(enum) {
|
||||||
text: []const u8,
|
text: []const u8,
|
||||||
open_bracket: void,
|
open_bracket: void,
|
||||||
|
@ -826,6 +909,8 @@ const ControlToken = union(enum) {
|
||||||
at: void,
|
at: void,
|
||||||
comma: void,
|
comma: void,
|
||||||
percent: void,
|
percent: void,
|
||||||
|
open_paren: void,
|
||||||
|
close_paren: void,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ControlTokenIter = struct {
|
const ControlTokenIter = struct {
|
||||||
|
@ -858,6 +943,8 @@ const ControlTokenIter = struct {
|
||||||
'@' => return .{ .at = {} },
|
'@' => return .{ .at = {} },
|
||||||
',' => return .{ .comma = {} },
|
',' => return .{ .comma = {} },
|
||||||
'%' => return .{ .percent = {} },
|
'%' => return .{ .percent = {} },
|
||||||
|
'(' => return .{ .open_paren = {} },
|
||||||
|
')' => return .{ .close_paren = {} },
|
||||||
' ', '\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) {}
|
||||||
|
@ -869,7 +956,7 @@ const ControlTokenIter = struct {
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
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) {}
|
||||||
|
|
||||||
self.start += idx - 1;
|
self.start += idx - 1;
|
||||||
return .{ .text = remaining[0..idx] };
|
return .{ .text = remaining[0..idx] };
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
{= /for}
|
{= /for}
|
||||||
{#if .quxx == .quxx2}eql{#else}neq{/if}
|
{#if .quxx == .quxx2}eql{#else}neq{/if}
|
||||||
{#if .quxx == .qux}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=}
|
{#if .qux=}
|
||||||
qux
|
qux
|
||||||
{=#elif .quxx=}
|
{=#elif .quxx=}
|
||||||
|
|
Loading…
Reference in a new issue