Add #format statement
This commit is contained in:
parent
6d18209d29
commit
091146b617
2 changed files with 68 additions and 5 deletions
|
@ -180,6 +180,13 @@ fn executeStatement(
|
||||||
context,
|
context,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
.format => |fmt| {
|
||||||
|
try std.fmt.format(
|
||||||
|
writer,
|
||||||
|
"{" ++ fmt.format ++ "}",
|
||||||
|
.{evaluateExpression(fmt.value, args, captures, context)},
|
||||||
|
);
|
||||||
|
},
|
||||||
//else => @compileError("TODO"),
|
//else => @compileError("TODO"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,11 +203,10 @@ fn htmlEscape(writer: anytype, str: []const u8) !void {
|
||||||
|
|
||||||
fn print(writer: anytype, arg: anytype) !void {
|
fn print(writer: anytype, arg: anytype) !void {
|
||||||
const T = @TypeOf(arg);
|
const T = @TypeOf(arg);
|
||||||
|
if (T == void) return;
|
||||||
if (comptime std.meta.trait.isZigString(T)) return htmlEscape(writer, arg);
|
if (comptime std.meta.trait.isZigString(T)) return htmlEscape(writer, arg);
|
||||||
if (comptime std.meta.trait.isNumber(T)) return std.fmt.format(writer, "{}", .{arg});
|
if (comptime std.meta.trait.isNumber(T)) return std.fmt.format(writer, "{}", .{arg});
|
||||||
@compileLog(@TypeOf(arg));
|
std.fmt.format(writer, "{}", .{arg});
|
||||||
|
|
||||||
@compileError("TODO");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Deref(comptime T: type, comptime names: []const []const u8) type {
|
fn Deref(comptime T: type, comptime names: []const []const u8) type {
|
||||||
|
@ -450,6 +456,9 @@ fn parseTemplate(
|
||||||
.call_template => |call| items = items ++ [_]TemplateItem{.{
|
.call_template => |call| items = items ++ [_]TemplateItem{.{
|
||||||
.statement = .{ .call_template = call },
|
.statement = .{ .call_template = call },
|
||||||
}},
|
}},
|
||||||
|
.format => |call| items = items ++ [_]TemplateItem{.{
|
||||||
|
.statement = .{ .format = call },
|
||||||
|
}},
|
||||||
.end_switch, .case_header => if (template_type == .switch_block)
|
.end_switch, .case_header => if (template_type == .switch_block)
|
||||||
break cb
|
break cb
|
||||||
else
|
else
|
||||||
|
@ -514,6 +523,7 @@ fn parseTemplateTokens(comptime tokens: ControlTokenIter) []const TemplateToken
|
||||||
.percent => items = items ++ [_]TemplateToken{.{ .text = "%" }},
|
.percent => items = items ++ [_]TemplateToken{.{ .text = "%" }},
|
||||||
.open_paren => items = items ++ [_]TemplateToken{.{ .text = "(" }},
|
.open_paren => items = items ++ [_]TemplateToken{.{ .text = "(" }},
|
||||||
.close_paren => items = items ++ [_]TemplateToken{.{ .text = ")" }},
|
.close_paren => items = items ++ [_]TemplateToken{.{ .text = ")" }},
|
||||||
|
.double_quote => items = items ++ [_]TemplateToken{.{ .text = "\"" }},
|
||||||
};
|
};
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
|
@ -684,6 +694,11 @@ fn parseControlBlock(comptime tokens: ControlTokenIter) ParseResult(ControlToken
|
||||||
iter = result.new_iter;
|
iter = result.new_iter;
|
||||||
break .{ .case_header = result.item };
|
break .{ .case_header = result.item };
|
||||||
},
|
},
|
||||||
|
.format => {
|
||||||
|
const result = parseFormat(iter);
|
||||||
|
iter = result.new_iter;
|
||||||
|
break .{ .format = result.item };
|
||||||
|
},
|
||||||
|
|
||||||
//else => @compileError("TODO"),
|
//else => @compileError("TODO"),
|
||||||
}
|
}
|
||||||
|
@ -706,7 +721,7 @@ fn parseControlBlock(comptime tokens: ControlTokenIter) ParseResult(ControlToken
|
||||||
iter = expr.new_iter;
|
iter = expr.new_iter;
|
||||||
break .{ .expression = expr.item };
|
break .{ .expression = expr.item };
|
||||||
},
|
},
|
||||||
else => @compileError("TODO"),
|
else => @compileError("TODO " ++ @tagName(token)),
|
||||||
};
|
};
|
||||||
|
|
||||||
// search for end of statement
|
// search for end of statement
|
||||||
|
@ -957,6 +972,42 @@ fn parseCallTemplate(comptime tokens: ControlTokenIter) ParseResult(ControlToken
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parseFormat(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter, FormatStmt) {
|
||||||
|
comptime {
|
||||||
|
var iter = skipWhitespace(tokens);
|
||||||
|
|
||||||
|
expectToken(iter.next(), .double_quote);
|
||||||
|
var fmt_str: []const u8 = "";
|
||||||
|
while (true) switch (iter.next() orelse @compileError("Unexpected end of template")) {
|
||||||
|
.text, .whitespace => |t| fmt_str = fmt_str ++ t,
|
||||||
|
.open_bracket => fmt_str = fmt_str ++ "{",
|
||||||
|
.close_bracket => fmt_str = fmt_str ++ "}",
|
||||||
|
.period => fmt_str = fmt_str ++ ".",
|
||||||
|
.pound => fmt_str = fmt_str ++ "#",
|
||||||
|
.pipe => fmt_str = fmt_str ++ "|",
|
||||||
|
.dollar => fmt_str = fmt_str ++ "$",
|
||||||
|
.slash => fmt_str = fmt_str ++ "/",
|
||||||
|
.equals => fmt_str = fmt_str ++ "=",
|
||||||
|
.at => fmt_str = fmt_str ++ "@",
|
||||||
|
.comma => fmt_str = fmt_str ++ ",",
|
||||||
|
.percent => fmt_str = fmt_str ++ "%",
|
||||||
|
.open_paren => fmt_str = fmt_str ++ "(",
|
||||||
|
.close_paren => fmt_str = fmt_str ++ ")",
|
||||||
|
.double_quote => break,
|
||||||
|
};
|
||||||
|
|
||||||
|
const expr = parseExpression(iter);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.new_iter = expr.new_iter,
|
||||||
|
.item = .{
|
||||||
|
.format = fmt_str,
|
||||||
|
.value = expr.item,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn ParseResult(comptime It: type, comptime T: type) type {
|
fn ParseResult(comptime It: type, comptime T: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
new_iter: It,
|
new_iter: It,
|
||||||
|
@ -1032,12 +1083,18 @@ const IfHeader = struct {
|
||||||
capture: ?[]const u8,
|
capture: ?[]const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FormatStmt = struct {
|
||||||
|
format: []const u8,
|
||||||
|
value: Expression,
|
||||||
|
};
|
||||||
|
|
||||||
const Statement = union(enum) {
|
const Statement = union(enum) {
|
||||||
expression: Expression,
|
expression: Expression,
|
||||||
@"for": For,
|
@"for": For,
|
||||||
@"if": If,
|
@"if": If,
|
||||||
@"switch": Switch,
|
@"switch": Switch,
|
||||||
call_template: CallTemplate,
|
call_template: CallTemplate,
|
||||||
|
format: FormatStmt,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ControlBlock = struct {
|
const ControlBlock = struct {
|
||||||
|
@ -1053,6 +1110,7 @@ const ControlBlock = struct {
|
||||||
switch_header: SwitchHeader,
|
switch_header: SwitchHeader,
|
||||||
case_header: CaseHeader,
|
case_header: CaseHeader,
|
||||||
end_switch: void,
|
end_switch: void,
|
||||||
|
format: FormatStmt,
|
||||||
};
|
};
|
||||||
block: Data,
|
block: Data,
|
||||||
strip_before: bool,
|
strip_before: bool,
|
||||||
|
@ -1067,6 +1125,7 @@ const Keyword = enum {
|
||||||
@"template",
|
@"template",
|
||||||
@"switch",
|
@"switch",
|
||||||
@"case",
|
@"case",
|
||||||
|
@"format",
|
||||||
};
|
};
|
||||||
|
|
||||||
const EndKeyword = enum {
|
const EndKeyword = enum {
|
||||||
|
@ -1102,6 +1161,7 @@ const ControlToken = union(enum) {
|
||||||
percent: void,
|
percent: void,
|
||||||
open_paren: void,
|
open_paren: void,
|
||||||
close_paren: void,
|
close_paren: void,
|
||||||
|
double_quote: void,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ControlTokenIter = struct {
|
const ControlTokenIter = struct {
|
||||||
|
@ -1136,6 +1196,7 @@ const ControlTokenIter = struct {
|
||||||
'%' => return .{ .percent = {} },
|
'%' => return .{ .percent = {} },
|
||||||
'(' => return .{ .open_paren = {} },
|
'(' => return .{ .open_paren = {} },
|
||||||
')' => return .{ .close_paren = {} },
|
')' => return .{ .close_paren = {} },
|
||||||
|
'"' => return .{ .double_quote = {} },
|
||||||
' ', '\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) {}
|
||||||
|
@ -1147,7 +1208,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] };
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
neither
|
neither
|
||||||
{=/if}
|
{=/if}
|
||||||
|
|
||||||
|
format: {#format "s" .x}
|
||||||
|
|
||||||
{#switch .snap case foo =}
|
{#switch .snap case foo =}
|
||||||
foo
|
foo
|
||||||
{= #case bar =}
|
{= #case bar =}
|
||||||
|
|
Loading…
Reference in a new issue