Compare commits
3 commits
6d18209d29
...
d504cef8ff
Author | SHA1 | Date | |
---|---|---|---|
d504cef8ff | |||
11bdaad6d7 | |||
091146b617 |
3 changed files with 77 additions and 12 deletions
|
@ -180,6 +180,13 @@ fn executeStatement(
|
|||
context,
|
||||
);
|
||||
},
|
||||
.format => |fmt| {
|
||||
try std.fmt.format(
|
||||
writer,
|
||||
"{" ++ fmt.format ++ "}",
|
||||
.{evaluateExpression(fmt.value, args, captures, context)},
|
||||
);
|
||||
},
|
||||
//else => @compileError("TODO"),
|
||||
}
|
||||
}
|
||||
|
@ -196,11 +203,10 @@ fn htmlEscape(writer: anytype, str: []const u8) !void {
|
|||
|
||||
fn print(writer: anytype, arg: anytype) !void {
|
||||
const T = @TypeOf(arg);
|
||||
if (T == void) return;
|
||||
if (comptime std.meta.trait.isZigString(T)) return htmlEscape(writer, arg);
|
||||
if (comptime std.meta.trait.isNumber(T)) return std.fmt.format(writer, "{}", .{arg});
|
||||
@compileLog(@TypeOf(arg));
|
||||
|
||||
@compileError("TODO");
|
||||
try std.fmt.format(writer, "{}", .{arg});
|
||||
}
|
||||
|
||||
fn Deref(comptime T: type, comptime names: []const []const u8) type {
|
||||
|
@ -450,6 +456,9 @@ fn parseTemplate(
|
|||
.call_template => |call| items = items ++ [_]TemplateItem{.{
|
||||
.statement = .{ .call_template = call },
|
||||
}},
|
||||
.format => |call| items = items ++ [_]TemplateItem{.{
|
||||
.statement = .{ .format = call },
|
||||
}},
|
||||
.end_switch, .case_header => if (template_type == .switch_block)
|
||||
break cb
|
||||
else
|
||||
|
@ -514,6 +523,7 @@ fn parseTemplateTokens(comptime tokens: ControlTokenIter) []const TemplateToken
|
|||
.percent => items = items ++ [_]TemplateToken{.{ .text = "%" }},
|
||||
.open_paren => items = items ++ [_]TemplateToken{.{ .text = "(" }},
|
||||
.close_paren => items = items ++ [_]TemplateToken{.{ .text = ")" }},
|
||||
.double_quote => items = items ++ [_]TemplateToken{.{ .text = "\"" }},
|
||||
};
|
||||
|
||||
return items;
|
||||
|
@ -684,6 +694,11 @@ fn parseControlBlock(comptime tokens: ControlTokenIter) ParseResult(ControlToken
|
|||
iter = result.new_iter;
|
||||
break .{ .case_header = result.item };
|
||||
},
|
||||
.format => {
|
||||
const result = parseFormat(iter);
|
||||
iter = result.new_iter;
|
||||
break .{ .format = result.item };
|
||||
},
|
||||
|
||||
//else => @compileError("TODO"),
|
||||
}
|
||||
|
@ -706,7 +721,7 @@ fn parseControlBlock(comptime tokens: ControlTokenIter) ParseResult(ControlToken
|
|||
iter = expr.new_iter;
|
||||
break .{ .expression = expr.item };
|
||||
},
|
||||
else => @compileError("TODO"),
|
||||
else => @compileError("TODO " ++ @tagName(token)),
|
||||
};
|
||||
|
||||
// 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 {
|
||||
return struct {
|
||||
new_iter: It,
|
||||
|
@ -1032,12 +1083,18 @@ const IfHeader = struct {
|
|||
capture: ?[]const u8,
|
||||
};
|
||||
|
||||
const FormatStmt = struct {
|
||||
format: []const u8,
|
||||
value: Expression,
|
||||
};
|
||||
|
||||
const Statement = union(enum) {
|
||||
expression: Expression,
|
||||
@"for": For,
|
||||
@"if": If,
|
||||
@"switch": Switch,
|
||||
call_template: CallTemplate,
|
||||
format: FormatStmt,
|
||||
};
|
||||
|
||||
const ControlBlock = struct {
|
||||
|
@ -1053,6 +1110,7 @@ const ControlBlock = struct {
|
|||
switch_header: SwitchHeader,
|
||||
case_header: CaseHeader,
|
||||
end_switch: void,
|
||||
format: FormatStmt,
|
||||
};
|
||||
block: Data,
|
||||
strip_before: bool,
|
||||
|
@ -1067,6 +1125,7 @@ const Keyword = enum {
|
|||
@"template",
|
||||
@"switch",
|
||||
@"case",
|
||||
@"format",
|
||||
};
|
||||
|
||||
const EndKeyword = enum {
|
||||
|
@ -1102,6 +1161,7 @@ const ControlToken = union(enum) {
|
|||
percent: void,
|
||||
open_paren: void,
|
||||
close_paren: void,
|
||||
double_quote: void,
|
||||
};
|
||||
|
||||
const ControlTokenIter = struct {
|
||||
|
@ -1136,6 +1196,7 @@ const ControlTokenIter = struct {
|
|||
'%' => return .{ .percent = {} },
|
||||
'(' => return .{ .open_paren = {} },
|
||||
')' => return .{ .close_paren = {} },
|
||||
'"' => return .{ .double_quote = {} },
|
||||
' ', '\t', '\n', '\r' => {
|
||||
var idx: usize = 0;
|
||||
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 => {
|
||||
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] };
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
neither
|
||||
{=/if}
|
||||
|
||||
format: {#format "s" .x}
|
||||
|
||||
{#switch .snap case foo =}
|
||||
foo
|
||||
{= #case bar =}
|
||||
|
|
|
@ -117,14 +117,16 @@ pub fn toCharArrayZ(value: DateTime) [array_len + 1:0]u8 {
|
|||
return buf;
|
||||
}
|
||||
|
||||
pub fn format(value: DateTime, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
||||
pub fn format(value: DateTime, comptime fmt: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
||||
if (comptime std.ascii.eqlIgnoreCase(fmt, "rfc3339") or fmt.len == 0) {
|
||||
return std.fmt.format(
|
||||
writer,
|
||||
"{:0>4}-{:0>2}-{:0>2}T{:0>2}:{:0>2}:{:0>2}Z",
|
||||
.{ value.year(), value.month().numeric(), value.day(), value.hour(), value.minute(), value.second() },
|
||||
);
|
||||
} else @compileError("Unknown DateTime format " ++ fmt);
|
||||
}
|
||||
|
||||
pub fn jsonStringify(value: DateTime, _: std.json.StringifyOptions, writer: anytype) !void {
|
||||
try std.fmt.format(writer, "\"{}\"", .{value});
|
||||
try std.fmt.format(writer, "\"{rfc3339}\"", .{value});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue