Support integer literals

This commit is contained in:
jaina heartles 2022-12-14 02:08:07 -08:00
parent 25d6ee0245
commit f2a23db588
2 changed files with 74 additions and 18 deletions

View file

@ -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] };

View file

@ -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}