This commit is contained in:
Xuan Son Nguyen 2025-12-27 12:22:34 +01:00
parent a35fcb00b5
commit a6e0ae7a85
4 changed files with 71 additions and 107 deletions

View File

@ -1,79 +0,0 @@
#include "common.h"
#include <chat-peg-parser.h>
#include <sstream>
namespace jinja {
struct compiler {
common_chat_peg_native_builder builder;
common_peg_parser root;
compiler() : root(builder.choice()) {
auto & p = builder;
auto ws = p.rule("ws", p.chars("[ \t]", 0, -1));
auto num = p.rule("num", p.chars("[0-9]", 1, -1));
//
// expressions
//
auto expression = p.choice();
auto var_name = p.rule("var_name", p.chars("[a-zA-Z_]", 1, -1) << p.chars("[a-zA-Z0-9_]", 0, -1));
expression |= var_name;
// value
auto p_int = p.rule("value_int", num);
auto p_flt = p.rule("value_flt", num << "." << p.optional(num));
auto p_str = p.rule("value_str",
p.json_string() |
p.literal("'") + p.chars("[^']*", 0, -1) + p.literal("'")
);
expression |= p_int;
expression |= p_flt;
expression |= p_str;
// function calls
auto p_args = p.rule("args", expression << ws << p.zero_or_more("," << ws << expression));
auto p_func = p.rule("func", ws << var_name << ws << "(" << ws << p_args << ws << ")");
expression |= p_func;
// indexing
auto p_idx = p.rule("idx", ws << "[" << ws << expression << ws << "]");
expression |= p_idx;
// set
auto p_set = p.rule("set", "set " << ws << var_name << ws << "=" << expression);
expression |= p_set;
// if, else, endif
auto p_if = p.rule("if", "if " << ws << expression << ws);
auto p_else = p.rule("else", "else " << ws << expression << ws);
auto p_endif = p.rule("endif", p.literal("endif"));
expression |= p_if;
expression |= p_else;
expression |= p_endif;
expression = p.space() + expression + p.space();
//
// root
//
// auto strip = p.rule("strip", "-" << expression << "-");
auto print = p.rule("print", "{{" << (expression) << "}}");
auto ctrl = p.rule("ctrl", "{%" << (expression) << "%}");
root |= print;
root |= ctrl;
root |= p.rule("text", p.negate(root));
root = p.one_or_more(root);
root += p.end();
}
};
} // namespace jinja

View File

@ -48,6 +48,38 @@ struct token {
std::string value;
};
std::string type_to_string(token::type t) {
switch (t) {
case token::undefined: return "undefined";
case token::text: return "text";
case token::numeric_literal: return "numeric_literal";
case token::string_literal: return "string_literal";
case token::identifier: return "identifier";
case token::equals: return "equals";
case token::open_paren: return "open_paren";
case token::close_paren: return "close_paren";
case token::open_statement: return "open_statement";
case token::close_statement: return "close_statement";
case token::open_expression: return "open_expression";
case token::close_expression: return "close_expression";
case token::open_square_bracket: return "open_square_bracket";
case token::close_square_bracket: return "close_square_bracket";
case token::open_curly_bracket: return "open_curly_bracket";
case token::close_curly_bracket: return "close_curly_bracket";
case token::comma: return "comma";
case token::dot: return "dot";
case token::colon: return "colon";
case token::pipe: return "pipe";
case token::call_operator: return "call_operator";
case token::additive_binary_operator: return "additive_binary_operator";
case token::multiplicative_binary_operator: return "multiplicative_binary_operator";
case token::comparison_binary_operator: return "comparison_binary_operator";
case token::unary_operator: return "unary_operator";
case token::comment: return "comment";
default: return "unknown";
}
}
struct lexer {
const std::map<char, char> escape_chars = {
{'n', '\n'},

View File

@ -0,0 +1,39 @@
#include "jinja-lexer.h"
#include "jinja-vm.h"
namespace jinja {
void parse(const std::vector<token> & tokens) {
auto program = std::make_unique<jinja::program>();
size_t current = 0;
/**
* Consume the next token if it matches the expected type, otherwise throw an error.
* @param type The expected token type
* @param error The error message to throw if the token does not match the expected type
* @returns The consumed token
*/
auto expect = [&](const token::type & type, const std::string & error) -> token {
const auto & prev = tokens[current++];
if (prev.t != type) {
throw std::runtime_error("Parser Error: " + error + " (" + type_to_string(prev.t) + " != " + type_to_string(type) + ")");
}
return prev;
};
auto next_token = [&]() -> const token & {
if (current >= tokens.size()) {
return token{token::undefined, ""};
}
return tokens[current++];
};
auto expect_identifier = [&](const std::string & name) -> void {
if (!is_identifier(name)) {
throw std::runtime_error("Expected " + name);
}
++current;
};
}
}; // namespace jinja

View File

@ -1,28 +0,0 @@
#include <common.h>
#include <sstream>
struct vm_context {
std::ostringstream out;
};
struct op_base {
virtual ~op_base() = default;
virtual void execute(vm_context & ctx) = 0;
};
struct op_print : public op_base {
std::string message;
op_print(const std::string & message) : message(message) {}
void execute(vm_context & ctx) override {
ctx.out << message;
}
};
struct op_load : public op_base {
std::string dst;
std::string src;
std::string value;
op_load(const std::string & dst) : dst(dst) {}
void execute(vm_context & ctx) override {
}
};