Support integer literals
This commit is contained in:
parent
25d6ee0245
commit
f2a23db588
2 changed files with 74 additions and 18 deletions
|
@ -235,6 +235,7 @@ fn EvaluateExpression(
|
||||||
.slice => |sl| []const std.meta.Elem(EvaluateExpression(sl.iterable, Args, Captures, Context)),
|
.slice => |sl| []const std.meta.Elem(EvaluateExpression(sl.iterable, Args, Captures, Context)),
|
||||||
},
|
},
|
||||||
.optional_unwrap => |expr| std.meta.Child(EvaluateExpression(expr.*, Args, Captures, Context)),
|
.optional_unwrap => |expr| std.meta.Child(EvaluateExpression(expr.*, Args, Captures, Context)),
|
||||||
|
.int => isize,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,8 +272,8 @@ fn evaluateExpression(
|
||||||
},
|
},
|
||||||
.slice => |sl| {
|
.slice => |sl| {
|
||||||
const iterable = try evaluateExpression(sl.iterable, args, captures, context);
|
const iterable = try evaluateExpression(sl.iterable, args, captures, context);
|
||||||
const start = try evaluateExpression(sl.start, args, captures, context);
|
const start = std.math.cast(usize, try evaluateExpression(sl.start, args, captures, context)) orelse return error.IndexOutOfBounds;
|
||||||
const end = try evaluateExpression(sl.end, args, captures, context);
|
const end = std.math.cast(usize, try evaluateExpression(sl.end, args, captures, context)) orelse return error.IndexOutOfBounds;
|
||||||
|
|
||||||
if (comptime std.meta.trait.is(.Array)(@TypeOf(iterable))) @compileError("Cannot slice an array, pass a slice or pointer to array instead");
|
if (comptime std.meta.trait.is(.Array)(@TypeOf(iterable))) @compileError("Cannot slice an array, pass a slice or pointer to array instead");
|
||||||
if (start > iterable.len or end > iterable.len) return error.IndexOutOfBounds;
|
if (start > iterable.len or end > iterable.len) return error.IndexOutOfBounds;
|
||||||
|
@ -283,6 +284,7 @@ fn evaluateExpression(
|
||||||
const val = try evaluateExpression(expr.*, args, captures, context);
|
const val = try evaluateExpression(expr.*, args, captures, context);
|
||||||
return val orelse error.NullOptional;
|
return val orelse error.NullOptional;
|
||||||
},
|
},
|
||||||
|
.int => |i| return i,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,7 +514,7 @@ fn parseTemplateTokens(comptime tokens: ControlTokenIter) []const TemplateToken
|
||||||
|
|
||||||
while (iter.next()) |token| switch (token) {
|
while (iter.next()) |token| switch (token) {
|
||||||
.whitespace => |wsp| items = items ++ [_]TemplateToken{.{ .whitespace = wsp }},
|
.whitespace => |wsp| items = items ++ [_]TemplateToken{.{ .whitespace = wsp }},
|
||||||
.text => |text| items = items ++ [_]TemplateToken{.{ .text = text }},
|
.number, .text => |text| items = items ++ [_]TemplateToken{.{ .text = text }},
|
||||||
.open_bracket => {
|
.open_bracket => {
|
||||||
const next = iter.next() orelse @compileError("Unexpected end of template");
|
const next = iter.next() orelse @compileError("Unexpected end of template");
|
||||||
if (next == .open_bracket) {
|
if (next == .open_bracket) {
|
||||||
|
@ -550,6 +552,33 @@ fn parseTemplateTokens(comptime tokens: ControlTokenIter) []const TemplateToken
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tryParseIdentifier(comptime tokens: ControlTokenIter) ?ParseResult(ControlTokenIter, []const u8) {
|
||||||
|
comptime {
|
||||||
|
var iter = skipWhitespace(tokens);
|
||||||
|
|
||||||
|
var ident: []const u8 = "";
|
||||||
|
var first: bool = true;
|
||||||
|
while (iter.next()) |token| switch (token) {
|
||||||
|
.number, .text => |text| {
|
||||||
|
if (first and token == .number) return null;
|
||||||
|
ident = ident ++ text;
|
||||||
|
first = false;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
iter.putBack(token);
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (first) return null;
|
||||||
|
|
||||||
|
return ParseResult(ControlTokenIter, []const u8){
|
||||||
|
.new_iter = iter,
|
||||||
|
.item = ident,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parseExpression(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter, Expression) {
|
fn parseExpression(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter, Expression) {
|
||||||
comptime {
|
comptime {
|
||||||
var iter = tokens;
|
var iter = tokens;
|
||||||
|
@ -564,25 +593,24 @@ fn parseExpression(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIt
|
||||||
if (expr == null) {
|
if (expr == null) {
|
||||||
expr = .{ .args = {} };
|
expr = .{ .args = {} };
|
||||||
if (iter.peek()) |n| if (n == .text) iter.putBack(.{ .period = {} });
|
if (iter.peek()) |n| if (n == .text) iter.putBack(.{ .period = {} });
|
||||||
} else switch (iter.next() orelse break) {
|
} else if (tryParseIdentifier(iter)) |ident| {
|
||||||
.text => |text| expr = .{
|
iter = ident.new_iter;
|
||||||
|
|
||||||
|
expr = .{
|
||||||
.deref = &.{
|
.deref = &.{
|
||||||
.container = expr.?,
|
.container = expr.?,
|
||||||
.field = text,
|
.field = ident.item,
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
.question_mark => expr = .{
|
} else if (iter.peek()) |next| if (next == .question_mark) {
|
||||||
|
_ = iter.next();
|
||||||
|
expr = .{
|
||||||
.optional_unwrap = blk: {
|
.optional_unwrap = blk: {
|
||||||
const e = expr.?;
|
const e = expr.?;
|
||||||
break :blk &e;
|
break :blk &e;
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
else => |t2| {
|
};
|
||||||
iter.pushBack(t2);
|
|
||||||
iter.pushBack(token);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
last_valid_iter = iter;
|
last_valid_iter = iter;
|
||||||
},
|
},
|
||||||
.dollar => {
|
.dollar => {
|
||||||
|
@ -622,6 +650,12 @@ fn parseExpression(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIt
|
||||||
expr = .{ .builtin = &builtin.item };
|
expr = .{ .builtin = &builtin.item };
|
||||||
last_valid_iter = iter;
|
last_valid_iter = iter;
|
||||||
},
|
},
|
||||||
|
.number => |n| {
|
||||||
|
if (expr != null) break;
|
||||||
|
const num = std.fmt.parseInt(isize, n, 10) catch @compileError("Error parsing integer");
|
||||||
|
expr = .{ .int = num };
|
||||||
|
last_valid_iter = iter;
|
||||||
|
},
|
||||||
else => break,
|
else => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -808,7 +842,7 @@ fn parseControlBlock(comptime tokens: ControlTokenIter) ParseResult(ControlToken
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
@compileLog(iter.row);
|
@compileLog(iter.row);
|
||||||
@compileError("TODO " ++ @tagName(token) ++ " " ++ token.text);
|
@compileError("TODO " ++ @tagName(token));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1011,7 +1045,7 @@ fn parseFormat(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter,
|
||||||
expectToken(iter.next(), .double_quote);
|
expectToken(iter.next(), .double_quote);
|
||||||
var fmt_str: []const u8 = "";
|
var fmt_str: []const u8 = "";
|
||||||
while (true) switch (iter.next() orelse @compileError("Unexpected end of template")) {
|
while (true) switch (iter.next() orelse @compileError("Unexpected end of template")) {
|
||||||
.text, .whitespace => |t| fmt_str = fmt_str ++ t,
|
.text, .number, .whitespace => |t| fmt_str = fmt_str ++ t,
|
||||||
.open_bracket => fmt_str = fmt_str ++ "{",
|
.open_bracket => fmt_str = fmt_str ++ "{",
|
||||||
.close_bracket => fmt_str = fmt_str ++ "}",
|
.close_bracket => fmt_str = fmt_str ++ "}",
|
||||||
.period => fmt_str = fmt_str ++ ".",
|
.period => fmt_str = fmt_str ++ ".",
|
||||||
|
@ -1071,6 +1105,7 @@ const Expression = union(enum) {
|
||||||
equals: *const EqualsExpr,
|
equals: *const EqualsExpr,
|
||||||
builtin: *const BuiltinCall,
|
builtin: *const BuiltinCall,
|
||||||
optional_unwrap: *const Expression,
|
optional_unwrap: *const Expression,
|
||||||
|
int: isize,
|
||||||
};
|
};
|
||||||
|
|
||||||
const For = struct {
|
const For = struct {
|
||||||
|
@ -1193,6 +1228,7 @@ const BuiltinCall = union(Builtin) {
|
||||||
|
|
||||||
const ControlToken = union(enum) {
|
const ControlToken = union(enum) {
|
||||||
text: []const u8,
|
text: []const u8,
|
||||||
|
number: []const u8,
|
||||||
open_bracket: void,
|
open_bracket: void,
|
||||||
close_bracket: void,
|
close_bracket: void,
|
||||||
period: void,
|
period: void,
|
||||||
|
@ -1219,6 +1255,18 @@ const ControlTokenIter = struct {
|
||||||
|
|
||||||
row: usize = 0,
|
row: usize = 0,
|
||||||
|
|
||||||
|
fn isControlChar(ch: u8) bool {
|
||||||
|
return switch (ch) {
|
||||||
|
'{', '}', '.', '#', '|', '$', '/', '=', '@', ',', '%', '(', ')', '"', '?' => true,
|
||||||
|
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isTextChar(ch: u8) bool {
|
||||||
|
return !std.ascii.isWhitespace(ch) and !std.ascii.isDigit(ch) and !isControlChar(ch);
|
||||||
|
}
|
||||||
|
|
||||||
fn next(self: *ControlTokenIter) ?ControlToken {
|
fn next(self: *ControlTokenIter) ?ControlToken {
|
||||||
if (self.peeked_token_count != 0) {
|
if (self.peeked_token_count != 0) {
|
||||||
const t = self.peeked_tokens[self.peeked_token_count - 1].?;
|
const t = self.peeked_tokens[self.peeked_token_count - 1].?;
|
||||||
|
@ -1257,9 +1305,16 @@ const ControlTokenIter = struct {
|
||||||
self.start += idx - 1;
|
self.start += idx - 1;
|
||||||
return .{ .whitespace = remaining[0..idx] };
|
return .{ .whitespace = remaining[0..idx] };
|
||||||
},
|
},
|
||||||
|
'0'...'9' => {
|
||||||
|
var idx: usize = 0;
|
||||||
|
while (idx < remaining.len and std.ascii.isDigit(remaining[idx])) : (idx += 1) {}
|
||||||
|
|
||||||
|
self.start += idx - 1;
|
||||||
|
return .{ .number = remaining[0..idx] };
|
||||||
|
},
|
||||||
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 isTextChar(remaining[idx])) : (idx += 1) {}
|
||||||
|
|
||||||
self.start += idx - 1;
|
self.start += idx - 1;
|
||||||
return .{ .text = remaining[0..idx] };
|
return .{ .text = remaining[0..idx] };
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
{=/if}
|
{=/if}
|
||||||
|
|
||||||
sliced: {#for @slice(.foo, .start, .end) |$s|}{$s}, {/for}
|
sliced: {#for @slice(.foo, .start, .end) |$s|}{$s}, {/for}
|
||||||
|
sliced: {#for @slice(.foo, 1, 3) |$s|}{$s}, {/for}
|
||||||
|
|
||||||
format: {#format "s" .x}
|
format: {#format "s" .x}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue