From 1a7db9a83446263ae92e1f04d67e402f6a796989 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Fri, 18 Nov 2022 01:58:13 -0800 Subject: [PATCH] Split expression/statements in parser --- src/template/lib.zig | 114 +++++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 47 deletions(-) diff --git a/src/template/lib.zig b/src/template/lib.zig index 649b30e..fe88b9f 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -142,7 +142,7 @@ fn parseTemplate(comptime tokens: TokenIter, comptime template_type: TemplateTyp items = items ++ [_]TemplateItem{.{ .text = current_text }}; current_text = ""; } - const result = parseExpressionOrStatement(iter, true); + const result = parseStatement(iter); iter = result.new_iter; const stmt = result.item.executable; if (stmt == .end_for) { @@ -177,10 +177,33 @@ fn parseTemplate(comptime tokens: TokenIter, comptime template_type: TemplateTyp } } -fn parseExpressionOrStatement( - comptime tokens: TokenIter, - comptime as_statement: bool, -) ParseResult(if (as_statement) Statement else Expression) { +fn parseExpression(comptime tokens: TokenIter) ParseResult(Expression) { + comptime { + var iter = tokens; + + var expr: Expression = while (iter.next()) |token| switch (token) { + .whitespace => {}, + .period => { + const names = parseDeref(iter); + iter = names.new_iter; + break .{ .arg_deref = names.item }; + }, + .dollar => { + const names = parseDeref(iter); + iter = names.new_iter; + break .{ .capture_deref = names.item }; + }, + else => @compileError("TODO"), + }; + + return .{ + .new_iter = iter, + .item = expr, + }; + } +} + +fn parseStatement(comptime tokens: TokenIter) ParseResult(Statement) { comptime { var iter = tokens; var first_token: bool = true; @@ -189,13 +212,12 @@ fn parseExpressionOrStatement( defer first_token = false; switch (token) { .equals => { - if (as_statement and first_token) { + if (first_token) { strip_before = true; } else @compileError("Unexpected '='"); }, .whitespace => {}, .pound => { - if (!as_statement) @compileError("Unexpected Token"); const next = iter.next() orelse @compileError("Unexpected end of template"); if (next != .text) @compileError("Expected keyword following '#' character"); const text = next.text; @@ -230,7 +252,6 @@ fn parseExpressionOrStatement( } }, .slash => { - if (!as_statement) !@compileError("Unexpected Token"); const next = iter.next() orelse @compileError("Unexpected end of template"); if (next != .text) @compileError("Expected keyword following '/' character"); const text = next.text; @@ -241,50 +262,44 @@ fn parseExpressionOrStatement( .@"if" => break .{ .end_if = {} }, } }, - .period => { - const names = parseDeref(iter); - iter = names.new_iter; - break .{ .expression = .{ .arg_deref = names.item } }; + .period, .dollar => { + iter.putBack(token); + const expr = parseExpression(iter); + iter = expr.new_iter; + break .{ .expression = expr.item }; }, - .dollar => { - const names = parseDeref(iter); - iter = names.new_iter; - break .{ .expression = .{ .capture_deref = names.item } }; - }, - else => if (as_statement) @compileError("TODO") else break, + else => @compileError("TODO"), } }; - if (as_statement) { - // search for end of statement - var strip_after: bool = false; - while (iter.next()) |token| switch (token) { - .whitespace => {}, - .equals => { - if (iter.peek()) |t| { - if (t == .close_bracket) { - strip_after = true; - continue; - } + // search for end of statement + var strip_after: bool = false; + while (iter.next()) |token| switch (token) { + .whitespace => {}, + .equals => { + if (iter.peek()) |t| { + if (t == .close_bracket) { + strip_after = true; + continue; } - @compileError("Unexpected '='"); + } + @compileError("Unexpected '='"); + }, + .close_bracket => return .{ + .new_iter = iter, + .item = .{ + .executable = stmt, + .strip_before = strip_before, + .strip_after = strip_after, }, - .close_bracket => return .{ - .new_iter = iter, - .item = .{ - .executable = stmt, - .strip_before = strip_before, - .strip_after = strip_after, - }, - }, - else => { - @compileLog(iter.row); - @compileError("TODO" ++ @tagName(token)); - }, - }; + }, + else => { + @compileLog(iter.row); + @compileError("TODO" ++ @tagName(token)); + }, + }; - @compileError("Unexpected end of template"); - } else return .{ .new_iter = iter, .item = stmt.expression }; + @compileError("Unexpected end of template"); } } @@ -312,7 +327,7 @@ fn endStatement(comptime tokens: TokenIter) TokenIter { fn parseForLoop(comptime tokens: TokenIter) ParseResult(ForLoop) { comptime { - const iterable = parseExpressionOrStatement(tokens, false); + const iterable = parseExpression(tokens); var iter = iterable.new_iter; iter = skipWhitespace(iter); @@ -347,7 +362,7 @@ fn parseForLoop(comptime tokens: TokenIter) ParseResult(ForLoop) { fn parseIfStatement(comptime tokens: TokenIter) ParseResult(IfStatement) { comptime { - const condition = parseExpressionOrStatement(tokens, false); + const condition = parseExpression(tokens); var iter = endStatement(condition.new_iter); const subtemplate = parseTemplate(iter, .if_block); @@ -500,4 +515,9 @@ const TokenIter = struct { self.peeked_token = token; return token; } + + fn putBack(self: *TokenIter, token: Token) void { + std.debug.assert(self.peeked_token == null); + self.peeked_token = token; + } };