demo
This commit is contained in:
parent
a35fcb00b5
commit
a6e0ae7a85
|
|
@ -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
|
||||
|
|
@ -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'},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 {
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue