mirror of
https://github.com/pantor/inja.git
synced 2026-03-25 18:32:45 +00:00
clang-format
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
---
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 2
|
||||
ColumnLimit: 160
|
||||
|
||||
---
|
||||
Language: Cpp
|
||||
|
||||
BasedOnStyle: LLVM
|
||||
ColumnLimit: 120
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
PointerAlignment: Left
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
SpaceBeforeCtorInitializerColon: false
|
||||
...
|
||||
|
||||
@@ -32,12 +32,11 @@ class Environment {
|
||||
TemplateStorage template_storage;
|
||||
|
||||
public:
|
||||
Environment() : Environment("") {}
|
||||
Environment(): Environment("") {}
|
||||
|
||||
explicit Environment(const std::string& global_path) : input_path(global_path), output_path(global_path) {}
|
||||
explicit Environment(const std::string& global_path): input_path(global_path), output_path(global_path) {}
|
||||
|
||||
Environment(const std::string& input_path, const std::string& output_path)
|
||||
: input_path(input_path), output_path(output_path) {}
|
||||
Environment(const std::string& input_path, const std::string& output_path): input_path(input_path), output_path(output_path) {}
|
||||
|
||||
/// Sets the opener and closer for template statements
|
||||
void set_statement(const std::string& open, const std::string& close) {
|
||||
@@ -109,7 +108,9 @@ public:
|
||||
return parse_template(filename);
|
||||
}
|
||||
|
||||
std::string render(std::string_view input, const json& data) { return render(parse(input), data); }
|
||||
std::string render(std::string_view input, const json& data) {
|
||||
return render(parse(input), data);
|
||||
}
|
||||
|
||||
std::string render(const Template& tmpl, const json& data) {
|
||||
std::stringstream os;
|
||||
@@ -138,8 +139,7 @@ public:
|
||||
file.close();
|
||||
}
|
||||
|
||||
void write_with_json_file(const std::string& filename, const std::string& filename_data,
|
||||
const std::string& filename_out) {
|
||||
void write_with_json_file(const std::string& filename, const std::string& filename_data, const std::string& filename_out) {
|
||||
const json data = load_json(filename_data);
|
||||
write(filename, data, filename_out);
|
||||
}
|
||||
@@ -195,7 +195,10 @@ public:
|
||||
@brief Adds a void callback with given number or arguments
|
||||
*/
|
||||
void add_void_callback(const std::string& name, int num_args, const VoidCallbackFunction& callback) {
|
||||
function_storage.add_callback(name, num_args, [callback](Arguments& args) { callback(args); return json(); });
|
||||
function_storage.add_callback(name, num_args, [callback](Arguments& args) {
|
||||
callback(args);
|
||||
return json();
|
||||
});
|
||||
}
|
||||
|
||||
/** Includes a template with a given name into the environment.
|
||||
|
||||
@@ -17,30 +17,29 @@ struct InjaError : public std::runtime_error {
|
||||
|
||||
const SourceLocation location;
|
||||
|
||||
explicit InjaError(const std::string &type, const std::string &message)
|
||||
explicit InjaError(const std::string& type, const std::string& message)
|
||||
: std::runtime_error("[inja.exception." + type + "] " + message), type(type), message(message), location({0, 0}) {}
|
||||
|
||||
explicit InjaError(const std::string &type, const std::string &message, SourceLocation location)
|
||||
: std::runtime_error("[inja.exception." + type + "] (at " + std::to_string(location.line) + ":" +
|
||||
std::to_string(location.column) + ") " + message),
|
||||
explicit InjaError(const std::string& type, const std::string& message, SourceLocation location)
|
||||
: std::runtime_error("[inja.exception." + type + "] (at " + std::to_string(location.line) + ":" + std::to_string(location.column) + ") " + message),
|
||||
type(type), message(message), location(location) {}
|
||||
};
|
||||
|
||||
struct ParserError : public InjaError {
|
||||
explicit ParserError(const std::string &message, SourceLocation location) : InjaError("parser_error", message, location) {}
|
||||
explicit ParserError(const std::string& message, SourceLocation location): InjaError("parser_error", message, location) {}
|
||||
};
|
||||
|
||||
struct RenderError : public InjaError {
|
||||
explicit RenderError(const std::string &message, SourceLocation location) : InjaError("render_error", message, location) {}
|
||||
explicit RenderError(const std::string& message, SourceLocation location): InjaError("render_error", message, location) {}
|
||||
};
|
||||
|
||||
struct FileError : public InjaError {
|
||||
explicit FileError(const std::string &message) : InjaError("file_error", message) {}
|
||||
explicit FileError(const std::string &message, SourceLocation location) : InjaError("file_error", message, location) {}
|
||||
explicit FileError(const std::string& message): InjaError("file_error", message) {}
|
||||
explicit FileError(const std::string& message, SourceLocation location): InjaError("file_error", message, location) {}
|
||||
};
|
||||
|
||||
struct DataError : public InjaError {
|
||||
explicit DataError(const std::string &message, SourceLocation location) : InjaError("data_error", message, location) {}
|
||||
explicit DataError(const std::string& message, SourceLocation location): InjaError("data_error", message, location) {}
|
||||
};
|
||||
|
||||
} // namespace inja
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace inja {
|
||||
|
||||
using Arguments = std::vector<const json*>;
|
||||
@@ -69,7 +68,7 @@ public:
|
||||
};
|
||||
|
||||
struct FunctionData {
|
||||
explicit FunctionData(const Operation& op, const CallbackFunction& cb = CallbackFunction{}) : operation(op), callback(cb) {}
|
||||
explicit FunctionData(const Operation& op, const CallbackFunction& cb = CallbackFunction {}): operation(op), callback(cb) {}
|
||||
const Operation operation;
|
||||
const CallbackFunction callback;
|
||||
};
|
||||
@@ -78,44 +77,44 @@ private:
|
||||
const int VARIADIC {-1};
|
||||
|
||||
std::map<std::pair<std::string, int>, FunctionData> function_storage = {
|
||||
{std::make_pair("at", 2), FunctionData { Operation::At }},
|
||||
{std::make_pair("default", 2), FunctionData { Operation::Default }},
|
||||
{std::make_pair("divisibleBy", 2), FunctionData { Operation::DivisibleBy }},
|
||||
{std::make_pair("even", 1), FunctionData { Operation::Even }},
|
||||
{std::make_pair("exists", 1), FunctionData { Operation::Exists }},
|
||||
{std::make_pair("existsIn", 2), FunctionData { Operation::ExistsInObject }},
|
||||
{std::make_pair("first", 1), FunctionData { Operation::First }},
|
||||
{std::make_pair("float", 1), FunctionData { Operation::Float }},
|
||||
{std::make_pair("int", 1), FunctionData { Operation::Int }},
|
||||
{std::make_pair("isArray", 1), FunctionData { Operation::IsArray }},
|
||||
{std::make_pair("isBoolean", 1), FunctionData { Operation::IsBoolean }},
|
||||
{std::make_pair("isFloat", 1), FunctionData { Operation::IsFloat }},
|
||||
{std::make_pair("isInteger", 1), FunctionData { Operation::IsInteger }},
|
||||
{std::make_pair("isNumber", 1), FunctionData { Operation::IsNumber }},
|
||||
{std::make_pair("isObject", 1), FunctionData { Operation::IsObject }},
|
||||
{std::make_pair("isString", 1), FunctionData { Operation::IsString }},
|
||||
{std::make_pair("last", 1), FunctionData { Operation::Last }},
|
||||
{std::make_pair("length", 1), FunctionData { Operation::Length }},
|
||||
{std::make_pair("lower", 1), FunctionData { Operation::Lower }},
|
||||
{std::make_pair("max", 1), FunctionData { Operation::Max }},
|
||||
{std::make_pair("min", 1), FunctionData { Operation::Min }},
|
||||
{std::make_pair("odd", 1), FunctionData { Operation::Odd }},
|
||||
{std::make_pair("range", 1), FunctionData { Operation::Range }},
|
||||
{std::make_pair("round", 2), FunctionData { Operation::Round }},
|
||||
{std::make_pair("sort", 1), FunctionData { Operation::Sort }},
|
||||
{std::make_pair("upper", 1), FunctionData { Operation::Upper }},
|
||||
{std::make_pair("super", 0), FunctionData { Operation::Super }},
|
||||
{std::make_pair("super", 1), FunctionData { Operation::Super }},
|
||||
{std::make_pair("join", 2), FunctionData { Operation::Join }},
|
||||
{std::make_pair("at", 2), FunctionData {Operation::At}},
|
||||
{std::make_pair("default", 2), FunctionData {Operation::Default}},
|
||||
{std::make_pair("divisibleBy", 2), FunctionData {Operation::DivisibleBy}},
|
||||
{std::make_pair("even", 1), FunctionData {Operation::Even}},
|
||||
{std::make_pair("exists", 1), FunctionData {Operation::Exists}},
|
||||
{std::make_pair("existsIn", 2), FunctionData {Operation::ExistsInObject}},
|
||||
{std::make_pair("first", 1), FunctionData {Operation::First}},
|
||||
{std::make_pair("float", 1), FunctionData {Operation::Float}},
|
||||
{std::make_pair("int", 1), FunctionData {Operation::Int}},
|
||||
{std::make_pair("isArray", 1), FunctionData {Operation::IsArray}},
|
||||
{std::make_pair("isBoolean", 1), FunctionData {Operation::IsBoolean}},
|
||||
{std::make_pair("isFloat", 1), FunctionData {Operation::IsFloat}},
|
||||
{std::make_pair("isInteger", 1), FunctionData {Operation::IsInteger}},
|
||||
{std::make_pair("isNumber", 1), FunctionData {Operation::IsNumber}},
|
||||
{std::make_pair("isObject", 1), FunctionData {Operation::IsObject}},
|
||||
{std::make_pair("isString", 1), FunctionData {Operation::IsString}},
|
||||
{std::make_pair("last", 1), FunctionData {Operation::Last}},
|
||||
{std::make_pair("length", 1), FunctionData {Operation::Length}},
|
||||
{std::make_pair("lower", 1), FunctionData {Operation::Lower}},
|
||||
{std::make_pair("max", 1), FunctionData {Operation::Max}},
|
||||
{std::make_pair("min", 1), FunctionData {Operation::Min}},
|
||||
{std::make_pair("odd", 1), FunctionData {Operation::Odd}},
|
||||
{std::make_pair("range", 1), FunctionData {Operation::Range}},
|
||||
{std::make_pair("round", 2), FunctionData {Operation::Round}},
|
||||
{std::make_pair("sort", 1), FunctionData {Operation::Sort}},
|
||||
{std::make_pair("upper", 1), FunctionData {Operation::Upper}},
|
||||
{std::make_pair("super", 0), FunctionData {Operation::Super}},
|
||||
{std::make_pair("super", 1), FunctionData {Operation::Super}},
|
||||
{std::make_pair("join", 2), FunctionData {Operation::Join}},
|
||||
};
|
||||
|
||||
public:
|
||||
void add_builtin(std::string_view name, int num_args, Operation op) {
|
||||
function_storage.emplace(std::make_pair(static_cast<std::string>(name), num_args), FunctionData { op });
|
||||
function_storage.emplace(std::make_pair(static_cast<std::string>(name), num_args), FunctionData {op});
|
||||
}
|
||||
|
||||
void add_callback(std::string_view name, int num_args, const CallbackFunction& callback) {
|
||||
function_storage.emplace(std::make_pair(static_cast<std::string>(name), num_args), FunctionData { Operation::Callback, callback });
|
||||
function_storage.emplace(std::make_pair(static_cast<std::string>(name), num_args), FunctionData {Operation::Callback, callback});
|
||||
}
|
||||
|
||||
FunctionData find_function(std::string_view name, int num_args) const {
|
||||
@@ -123,7 +122,7 @@ public:
|
||||
if (it != function_storage.end()) {
|
||||
return it->second;
|
||||
|
||||
// Find variadic function
|
||||
// Find variadic function
|
||||
} else if (num_args > 0) {
|
||||
it = function_storage.find(std::make_pair(static_cast<std::string>(name), VARIADIC));
|
||||
if (it != function_storage.end()) {
|
||||
@@ -131,7 +130,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
return FunctionData { Operation::None };
|
||||
return FunctionData {Operation::None};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
| || '_ \ | |/ _` | Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
| || | | || | (_| |
|
||||
|___|_| |_|/ |\__,_| Copyright (c) 2018-2021 Lars Berscheid
|
||||
|__/
|
||||
|__/
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
@@ -29,24 +29,26 @@ SOFTWARE.
|
||||
|
||||
namespace inja {
|
||||
#ifndef INJA_DATA_TYPE
|
||||
using json = nlohmann::json;
|
||||
using json = nlohmann::json;
|
||||
#else
|
||||
using json = INJA_DATA_TYPE;
|
||||
using json = INJA_DATA_TYPE;
|
||||
#endif
|
||||
}
|
||||
} // namespace inja
|
||||
|
||||
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(INJA_NOEXCEPTION)
|
||||
#ifndef INJA_THROW
|
||||
#define INJA_THROW(exception) throw exception
|
||||
#endif
|
||||
#ifndef INJA_THROW
|
||||
#define INJA_THROW(exception) throw exception
|
||||
#endif
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#ifndef INJA_THROW
|
||||
#define INJA_THROW(exception) std::abort(); std::ignore = exception
|
||||
#endif
|
||||
#ifndef INJA_NOEXCEPTION
|
||||
#define INJA_NOEXCEPTION
|
||||
#endif
|
||||
#include <cstdlib>
|
||||
#ifndef INJA_THROW
|
||||
#define INJA_THROW(exception) \
|
||||
std::abort(); \
|
||||
std::ignore = exception
|
||||
#endif
|
||||
#ifndef INJA_NOEXCEPTION
|
||||
#define INJA_NOEXCEPTION
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "environment.hpp"
|
||||
|
||||
@@ -43,7 +43,6 @@ class Lexer {
|
||||
size_t tok_start;
|
||||
size_t pos;
|
||||
|
||||
|
||||
Token scan_body(std::string_view close, Token::Kind closeKind, std::string_view close_trim = std::string_view(), bool trim = false) {
|
||||
again:
|
||||
// skip whitespace (except for \n as it might be a close)
|
||||
@@ -224,7 +223,9 @@ class Lexer {
|
||||
return make_token(Token::Kind::String);
|
||||
}
|
||||
|
||||
Token make_token(Token::Kind kind) const { return Token(kind, string_view::slice(m_in, tok_start, pos)); }
|
||||
Token make_token(Token::Kind kind) const {
|
||||
return Token(kind, string_view::slice(m_in, tok_start, pos));
|
||||
}
|
||||
|
||||
void skip_whitespaces_and_newlines() {
|
||||
if (pos < m_in.size()) {
|
||||
@@ -270,7 +271,7 @@ class Lexer {
|
||||
}
|
||||
|
||||
public:
|
||||
explicit Lexer(const LexerConfig& config) : config(config), state(State::Text), minus_state(MinusState::Number) {}
|
||||
explicit Lexer(const LexerConfig& config): config(config), state(State::Text), minus_state(MinusState::Number) {}
|
||||
|
||||
SourceLocation current_position() const {
|
||||
return get_source_location(m_in, tok_start);
|
||||
@@ -322,7 +323,7 @@ public:
|
||||
} else if (inja::string_view::starts_with(open_str, config.statement_open)) {
|
||||
if (inja::string_view::starts_with(open_str, config.statement_open_no_lstrip)) {
|
||||
state = State::StatementStartNoLstrip;
|
||||
} else if (inja::string_view::starts_with(open_str, config.statement_open_force_lstrip )) {
|
||||
} else if (inja::string_view::starts_with(open_str, config.statement_open_force_lstrip)) {
|
||||
state = State::StatementStartForceLstrip;
|
||||
must_lstrip = true;
|
||||
} else {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "function_storage.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
|
||||
namespace inja {
|
||||
|
||||
class NodeVisitor;
|
||||
@@ -29,7 +28,6 @@ class ExtendsStatementNode;
|
||||
class BlockStatementNode;
|
||||
class SetStatementNode;
|
||||
|
||||
|
||||
class NodeVisitor {
|
||||
public:
|
||||
virtual ~NodeVisitor() = default;
|
||||
@@ -61,16 +59,15 @@ public:
|
||||
|
||||
size_t pos;
|
||||
|
||||
AstNode(size_t pos) : pos(pos) { }
|
||||
virtual ~AstNode() { }
|
||||
AstNode(size_t pos): pos(pos) {}
|
||||
virtual ~AstNode() {}
|
||||
};
|
||||
|
||||
|
||||
class BlockNode : public AstNode {
|
||||
public:
|
||||
std::vector<std::shared_ptr<AstNode>> nodes;
|
||||
|
||||
explicit BlockNode() : AstNode(0) {}
|
||||
explicit BlockNode(): AstNode(0) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -81,7 +78,7 @@ class TextNode : public AstNode {
|
||||
public:
|
||||
const size_t length;
|
||||
|
||||
explicit TextNode(size_t pos, size_t length): AstNode(pos), length(length) { }
|
||||
explicit TextNode(size_t pos, size_t length): AstNode(pos), length(length) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -90,7 +87,7 @@ public:
|
||||
|
||||
class ExpressionNode : public AstNode {
|
||||
public:
|
||||
explicit ExpressionNode(size_t pos) : AstNode(pos) {}
|
||||
explicit ExpressionNode(size_t pos): AstNode(pos) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -101,7 +98,7 @@ class LiteralNode : public ExpressionNode {
|
||||
public:
|
||||
const json value;
|
||||
|
||||
explicit LiteralNode(std::string_view data_text, size_t pos) : ExpressionNode(pos), value(json::parse(data_text)) { }
|
||||
explicit LiteralNode(std::string_view data_text, size_t pos): ExpressionNode(pos), value(json::parse(data_text)) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -124,7 +121,7 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit DataNode(std::string_view ptr_name, size_t pos) : ExpressionNode(pos), name(ptr_name), ptr(json::json_pointer(convert_dot_to_ptr(ptr_name))) { }
|
||||
explicit DataNode(std::string_view ptr_name, size_t pos): ExpressionNode(pos), name(ptr_name), ptr(json::json_pointer(convert_dot_to_ptr(ptr_name))) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -150,98 +147,99 @@ public:
|
||||
std::vector<std::shared_ptr<ExpressionNode>> arguments;
|
||||
CallbackFunction callback;
|
||||
|
||||
explicit FunctionNode(std::string_view name, size_t pos) : ExpressionNode(pos), precedence(8), associativity(Associativity::Left), operation(Op::Callback), name(name), number_args(1) { }
|
||||
explicit FunctionNode(Op operation, size_t pos) : ExpressionNode(pos), operation(operation), number_args(1) {
|
||||
explicit FunctionNode(std::string_view name, size_t pos)
|
||||
: ExpressionNode(pos), precedence(8), associativity(Associativity::Left), operation(Op::Callback), name(name), number_args(1) {}
|
||||
explicit FunctionNode(Op operation, size_t pos): ExpressionNode(pos), operation(operation), number_args(1) {
|
||||
switch (operation) {
|
||||
case Op::Not: {
|
||||
number_args = 1;
|
||||
precedence = 4;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::And: {
|
||||
number_args = 2;
|
||||
precedence = 1;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Or: {
|
||||
number_args = 2;
|
||||
precedence = 1;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::In: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Equal: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::NotEqual: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Greater: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::GreaterEqual: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Less: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::LessEqual: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Add: {
|
||||
number_args = 2;
|
||||
precedence = 3;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Subtract: {
|
||||
number_args = 2;
|
||||
precedence = 3;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Multiplication: {
|
||||
number_args = 2;
|
||||
precedence = 4;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Division: {
|
||||
number_args = 2;
|
||||
precedence = 4;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Power: {
|
||||
number_args = 2;
|
||||
precedence = 5;
|
||||
associativity = Associativity::Right;
|
||||
} break;
|
||||
case Op::Modulo: {
|
||||
number_args = 2;
|
||||
precedence = 4;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::AtId: {
|
||||
number_args = 2;
|
||||
precedence = 8;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
default: {
|
||||
precedence = 1;
|
||||
associativity = Associativity::Left;
|
||||
}
|
||||
case Op::Not: {
|
||||
number_args = 1;
|
||||
precedence = 4;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::And: {
|
||||
number_args = 2;
|
||||
precedence = 1;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Or: {
|
||||
number_args = 2;
|
||||
precedence = 1;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::In: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Equal: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::NotEqual: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Greater: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::GreaterEqual: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Less: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::LessEqual: {
|
||||
number_args = 2;
|
||||
precedence = 2;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Add: {
|
||||
number_args = 2;
|
||||
precedence = 3;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Subtract: {
|
||||
number_args = 2;
|
||||
precedence = 3;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Multiplication: {
|
||||
number_args = 2;
|
||||
precedence = 4;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Division: {
|
||||
number_args = 2;
|
||||
precedence = 4;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::Power: {
|
||||
number_args = 2;
|
||||
precedence = 5;
|
||||
associativity = Associativity::Right;
|
||||
} break;
|
||||
case Op::Modulo: {
|
||||
number_args = 2;
|
||||
precedence = 4;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
case Op::AtId: {
|
||||
number_args = 2;
|
||||
precedence = 8;
|
||||
associativity = Associativity::Left;
|
||||
} break;
|
||||
default: {
|
||||
precedence = 1;
|
||||
associativity = Associativity::Left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,8 +252,8 @@ class ExpressionListNode : public AstNode {
|
||||
public:
|
||||
std::shared_ptr<ExpressionNode> root;
|
||||
|
||||
explicit ExpressionListNode() : AstNode(0) { }
|
||||
explicit ExpressionListNode(size_t pos) : AstNode(pos) { }
|
||||
explicit ExpressionListNode(): AstNode(0) {}
|
||||
explicit ExpressionListNode(size_t pos): AstNode(pos) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -264,7 +262,7 @@ public:
|
||||
|
||||
class StatementNode : public AstNode {
|
||||
public:
|
||||
StatementNode(size_t pos) : AstNode(pos) { }
|
||||
StatementNode(size_t pos): AstNode(pos) {}
|
||||
|
||||
virtual void accept(NodeVisitor& v) const = 0;
|
||||
};
|
||||
@@ -273,9 +271,9 @@ class ForStatementNode : public StatementNode {
|
||||
public:
|
||||
ExpressionListNode condition;
|
||||
BlockNode body;
|
||||
BlockNode *const parent;
|
||||
BlockNode* const parent;
|
||||
|
||||
ForStatementNode(BlockNode *const parent, size_t pos) : StatementNode(pos), parent(parent) { }
|
||||
ForStatementNode(BlockNode* const parent, size_t pos): StatementNode(pos), parent(parent) {}
|
||||
|
||||
virtual void accept(NodeVisitor& v) const = 0;
|
||||
};
|
||||
@@ -284,7 +282,7 @@ class ForArrayStatementNode : public ForStatementNode {
|
||||
public:
|
||||
const std::string value;
|
||||
|
||||
explicit ForArrayStatementNode(const std::string& value, BlockNode *const parent, size_t pos) : ForStatementNode(parent, pos), value(value) { }
|
||||
explicit ForArrayStatementNode(const std::string& value, BlockNode* const parent, size_t pos): ForStatementNode(parent, pos), value(value) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -296,7 +294,8 @@ public:
|
||||
const std::string key;
|
||||
const std::string value;
|
||||
|
||||
explicit ForObjectStatementNode(const std::string& key, const std::string& value, BlockNode *const parent, size_t pos) : ForStatementNode(parent, pos), key(key), value(value) { }
|
||||
explicit ForObjectStatementNode(const std::string& key, const std::string& value, BlockNode* const parent, size_t pos)
|
||||
: ForStatementNode(parent, pos), key(key), value(value) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -308,13 +307,13 @@ public:
|
||||
ExpressionListNode condition;
|
||||
BlockNode true_statement;
|
||||
BlockNode false_statement;
|
||||
BlockNode *const parent;
|
||||
BlockNode* const parent;
|
||||
|
||||
const bool is_nested;
|
||||
bool has_false_statement {false};
|
||||
|
||||
explicit IfStatementNode(BlockNode *const parent, size_t pos) : StatementNode(pos), parent(parent), is_nested(false) { }
|
||||
explicit IfStatementNode(bool is_nested, BlockNode *const parent, size_t pos) : StatementNode(pos), parent(parent), is_nested(is_nested) { }
|
||||
explicit IfStatementNode(BlockNode* const parent, size_t pos): StatementNode(pos), parent(parent), is_nested(false) {}
|
||||
explicit IfStatementNode(bool is_nested, BlockNode* const parent, size_t pos): StatementNode(pos), parent(parent), is_nested(is_nested) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -325,7 +324,7 @@ class IncludeStatementNode : public StatementNode {
|
||||
public:
|
||||
const std::string file;
|
||||
|
||||
explicit IncludeStatementNode(const std::string& file, size_t pos) : StatementNode(pos), file(file) { }
|
||||
explicit IncludeStatementNode(const std::string& file, size_t pos): StatementNode(pos), file(file) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -336,7 +335,7 @@ class ExtendsStatementNode : public StatementNode {
|
||||
public:
|
||||
const std::string file;
|
||||
|
||||
explicit ExtendsStatementNode(const std::string& file, size_t pos) : StatementNode(pos), file(file) { }
|
||||
explicit ExtendsStatementNode(const std::string& file, size_t pos): StatementNode(pos), file(file) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -347,9 +346,9 @@ class BlockStatementNode : public StatementNode {
|
||||
public:
|
||||
const std::string name;
|
||||
BlockNode block;
|
||||
BlockNode *const parent;
|
||||
BlockNode* const parent;
|
||||
|
||||
explicit BlockStatementNode(BlockNode *const parent, const std::string& name, size_t pos) : StatementNode(pos), name(name), parent(parent) { }
|
||||
explicit BlockStatementNode(BlockNode* const parent, const std::string& name, size_t pos): StatementNode(pos), name(name), parent(parent) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
@@ -361,7 +360,7 @@ public:
|
||||
const std::string key;
|
||||
ExpressionListNode expression;
|
||||
|
||||
explicit SetStatementNode(const std::string& key, size_t pos) : StatementNode(pos), key(key) { }
|
||||
explicit SetStatementNode(const std::string& key, size_t pos): StatementNode(pos), key(key) {}
|
||||
|
||||
void accept(NodeVisitor& v) const {
|
||||
v.visit(*this);
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "token.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
|
||||
namespace inja {
|
||||
|
||||
/*!
|
||||
@@ -38,8 +37,8 @@ class Parser {
|
||||
|
||||
std::string_view literal_start;
|
||||
|
||||
BlockNode *current_block {nullptr};
|
||||
ExpressionListNode *current_expression_list {nullptr};
|
||||
BlockNode* current_block {nullptr};
|
||||
ExpressionListNode* current_expression_list {nullptr};
|
||||
std::stack<std::pair<FunctionNode*, size_t>> function_stack;
|
||||
std::vector<std::shared_ptr<ExpressionNode>> arguments;
|
||||
|
||||
@@ -110,7 +109,6 @@ class Parser {
|
||||
template_storage.emplace(template_name, include_template);
|
||||
parse_into_template(template_storage[template_name], template_name);
|
||||
return;
|
||||
|
||||
} else if (!config.include_callback) {
|
||||
INJA_THROW(FileError("failed accessing file at '" + template_name + "'"));
|
||||
}
|
||||
@@ -137,7 +135,7 @@ class Parser {
|
||||
return std::string {tok.text.substr(1, tok.text.length() - 2)};
|
||||
}
|
||||
|
||||
bool parse_expression(Template &tmpl, Token::Kind closing) {
|
||||
bool parse_expression(Template& tmpl, Token::Kind closing) {
|
||||
while (tok.kind != closing && tok.kind != Token::Kind::Eof) {
|
||||
// Literals
|
||||
switch (tok.kind) {
|
||||
@@ -146,28 +144,24 @@ class Parser {
|
||||
literal_start = tok.text;
|
||||
add_literal(tmpl.content.c_str());
|
||||
}
|
||||
|
||||
} break;
|
||||
case Token::Kind::Number: {
|
||||
if (current_brace_level == 0 && current_bracket_level == 0) {
|
||||
literal_start = tok.text;
|
||||
add_literal(tmpl.content.c_str());
|
||||
}
|
||||
|
||||
} break;
|
||||
case Token::Kind::LeftBracket: {
|
||||
if (current_brace_level == 0 && current_bracket_level == 0) {
|
||||
literal_start = tok.text;
|
||||
}
|
||||
current_bracket_level += 1;
|
||||
|
||||
} break;
|
||||
case Token::Kind::LeftBrace: {
|
||||
if (current_brace_level == 0 && current_bracket_level == 0) {
|
||||
literal_start = tok.text;
|
||||
}
|
||||
current_brace_level += 1;
|
||||
|
||||
} break;
|
||||
case Token::Kind::RightBracket: {
|
||||
if (current_bracket_level == 0) {
|
||||
@@ -178,7 +172,6 @@ class Parser {
|
||||
if (current_brace_level == 0 && current_bracket_level == 0) {
|
||||
add_literal(tmpl.content.c_str());
|
||||
}
|
||||
|
||||
} break;
|
||||
case Token::Kind::RightBrace: {
|
||||
if (current_brace_level == 0) {
|
||||
@@ -189,33 +182,33 @@ class Parser {
|
||||
if (current_brace_level == 0 && current_bracket_level == 0) {
|
||||
add_literal(tmpl.content.c_str());
|
||||
}
|
||||
|
||||
} break;
|
||||
case Token::Kind::Id: {
|
||||
get_peek_token();
|
||||
|
||||
// Data Literal
|
||||
if (tok.text == static_cast<decltype(tok.text)>("true") || tok.text == static_cast<decltype(tok.text)>("false") || tok.text == static_cast<decltype(tok.text)>("null")) {
|
||||
if (tok.text == static_cast<decltype(tok.text)>("true") || tok.text == static_cast<decltype(tok.text)>("false") ||
|
||||
tok.text == static_cast<decltype(tok.text)>("null")) {
|
||||
if (current_brace_level == 0 && current_bracket_level == 0) {
|
||||
literal_start = tok.text;
|
||||
add_literal(tmpl.content.c_str());
|
||||
}
|
||||
|
||||
// Operator
|
||||
// Operator
|
||||
} else if (tok.text == "and" || tok.text == "or" || tok.text == "in" || tok.text == "not") {
|
||||
goto parse_operator;
|
||||
|
||||
// Functions
|
||||
// Functions
|
||||
} else if (peek_tok.kind == Token::Kind::LeftParen) {
|
||||
operator_stack.emplace(std::make_shared<FunctionNode>(static_cast<std::string>(tok.text), tok.text.data() - tmpl.content.c_str()));
|
||||
function_stack.emplace(operator_stack.top().get(), current_paren_level);
|
||||
function_stack.emplace(operator_stack.top().get(), current_paren_level);
|
||||
|
||||
// Variables
|
||||
// Variables
|
||||
} else {
|
||||
arguments.emplace_back(std::make_shared<DataNode>(static_cast<std::string>(tok.text), tok.text.data() - tmpl.content.c_str()));
|
||||
}
|
||||
|
||||
// Operators
|
||||
// Operators
|
||||
} break;
|
||||
case Token::Kind::Equal:
|
||||
case Token::Kind::NotEqual:
|
||||
@@ -231,7 +224,7 @@ class Parser {
|
||||
case Token::Kind::Percent:
|
||||
case Token::Kind::Dot: {
|
||||
|
||||
parse_operator:
|
||||
parse_operator:
|
||||
FunctionStorage::Operation operation;
|
||||
switch (tok.kind) {
|
||||
case Token::Kind::Id: {
|
||||
@@ -292,12 +285,14 @@ class Parser {
|
||||
}
|
||||
auto function_node = std::make_shared<FunctionNode>(operation, tok.text.data() - tmpl.content.c_str());
|
||||
|
||||
while (!operator_stack.empty() && ((operator_stack.top()->precedence > function_node->precedence) || (operator_stack.top()->precedence == function_node->precedence && function_node->associativity == FunctionNode::Associativity::Left)) && (operator_stack.top()->operation != FunctionStorage::Operation::ParenLeft)) {
|
||||
while (!operator_stack.empty() &&
|
||||
((operator_stack.top()->precedence > function_node->precedence) ||
|
||||
(operator_stack.top()->precedence == function_node->precedence && function_node->associativity == FunctionNode::Associativity::Left)) &&
|
||||
(operator_stack.top()->operation != FunctionStorage::Operation::ParenLeft)) {
|
||||
add_operator();
|
||||
}
|
||||
|
||||
operator_stack.emplace(function_node);
|
||||
|
||||
} break;
|
||||
case Token::Kind::Comma: {
|
||||
if (current_brace_level == 0 && current_bracket_level == 0) {
|
||||
@@ -307,13 +302,11 @@ class Parser {
|
||||
|
||||
function_stack.top().first->number_args += 1;
|
||||
}
|
||||
|
||||
} break;
|
||||
case Token::Kind::Colon: {
|
||||
if (current_brace_level == 0 && current_bracket_level == 0) {
|
||||
throw_parser_error("unexpected ':'");
|
||||
}
|
||||
|
||||
} break;
|
||||
case Token::Kind::LeftParen: {
|
||||
current_paren_level += 1;
|
||||
@@ -325,7 +318,6 @@ class Parser {
|
||||
function_stack.top().first->number_args = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
case Token::Kind::RightParen: {
|
||||
current_paren_level -= 1;
|
||||
@@ -370,15 +362,14 @@ class Parser {
|
||||
if (arguments.size() == 1) {
|
||||
current_expression_list->root = arguments[0];
|
||||
arguments = {};
|
||||
|
||||
} else if (arguments.size() > 1) {
|
||||
throw_parser_error("malformed expression");
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_statement(Template &tmpl, Token::Kind closing, std::string_view path) {
|
||||
bool parse_statement(Template& tmpl, Token::Kind closing, std::string_view path) {
|
||||
if (tok.kind != Token::Kind::Id) {
|
||||
return false;
|
||||
}
|
||||
@@ -395,12 +386,11 @@ class Parser {
|
||||
if (!parse_expression(tmpl, closing)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (tok.text == static_cast<decltype(tok.text)>("else")) {
|
||||
if (if_statement_stack.empty()) {
|
||||
throw_parser_error("else without matching if");
|
||||
}
|
||||
auto &if_statement_data = if_statement_stack.top();
|
||||
auto& if_statement_data = if_statement_stack.top();
|
||||
get_next_token();
|
||||
|
||||
if_statement_data->has_false_statement = true;
|
||||
@@ -420,7 +410,6 @@ class Parser {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (tok.text == static_cast<decltype(tok.text)>("endif")) {
|
||||
if (if_statement_stack.empty()) {
|
||||
throw_parser_error("endif without matching if");
|
||||
@@ -431,12 +420,11 @@ class Parser {
|
||||
if_statement_stack.pop();
|
||||
}
|
||||
|
||||
auto &if_statement_data = if_statement_stack.top();
|
||||
auto& if_statement_data = if_statement_stack.top();
|
||||
get_next_token();
|
||||
|
||||
current_block = if_statement_data->parent;
|
||||
if_statement_stack.pop();
|
||||
|
||||
} else if (tok.text == static_cast<decltype(tok.text)>("block")) {
|
||||
get_next_token();
|
||||
|
||||
@@ -456,18 +444,16 @@ class Parser {
|
||||
}
|
||||
|
||||
get_next_token();
|
||||
|
||||
} else if (tok.text == static_cast<decltype(tok.text)>("endblock")) {
|
||||
if (block_statement_stack.empty()) {
|
||||
throw_parser_error("endblock without matching block");
|
||||
}
|
||||
|
||||
auto &block_statement_data = block_statement_stack.top();
|
||||
auto& block_statement_data = block_statement_stack.top();
|
||||
get_next_token();
|
||||
|
||||
current_block = block_statement_data->parent;
|
||||
block_statement_stack.pop();
|
||||
|
||||
} else if (tok.text == static_cast<decltype(tok.text)>("for")) {
|
||||
get_next_token();
|
||||
|
||||
@@ -491,11 +477,13 @@ class Parser {
|
||||
value_token = tok;
|
||||
get_next_token();
|
||||
|
||||
for_statement_node = std::make_shared<ForObjectStatementNode>(static_cast<std::string>(key_token.text), static_cast<std::string>(value_token.text), current_block, tok.text.data() - tmpl.content.c_str());
|
||||
for_statement_node = std::make_shared<ForObjectStatementNode>(static_cast<std::string>(key_token.text), static_cast<std::string>(value_token.text),
|
||||
current_block, tok.text.data() - tmpl.content.c_str());
|
||||
|
||||
// Array type
|
||||
// Array type
|
||||
} else {
|
||||
for_statement_node = std::make_shared<ForArrayStatementNode>(static_cast<std::string>(value_token.text), current_block, tok.text.data() - tmpl.content.c_str());
|
||||
for_statement_node =
|
||||
std::make_shared<ForArrayStatementNode>(static_cast<std::string>(value_token.text), current_block, tok.text.data() - tmpl.content.c_str());
|
||||
}
|
||||
|
||||
current_block->nodes.emplace_back(for_statement_node);
|
||||
@@ -511,18 +499,16 @@ class Parser {
|
||||
if (!parse_expression(tmpl, closing)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (tok.text == static_cast<decltype(tok.text)>("endfor")) {
|
||||
if (for_statement_stack.empty()) {
|
||||
throw_parser_error("endfor without matching for");
|
||||
}
|
||||
|
||||
auto &for_statement_data = for_statement_stack.top();
|
||||
auto& for_statement_data = for_statement_stack.top();
|
||||
get_next_token();
|
||||
|
||||
current_block = for_statement_data->parent;
|
||||
for_statement_stack.pop();
|
||||
|
||||
} else if (tok.text == static_cast<decltype(tok.text)>("include")) {
|
||||
get_next_token();
|
||||
|
||||
@@ -532,7 +518,6 @@ class Parser {
|
||||
current_block->nodes.emplace_back(std::make_shared<IncludeStatementNode>(template_name, tok.text.data() - tmpl.content.c_str()));
|
||||
|
||||
get_next_token();
|
||||
|
||||
} else if (tok.text == static_cast<decltype(tok.text)>("extends")) {
|
||||
get_next_token();
|
||||
|
||||
@@ -542,7 +527,6 @@ class Parser {
|
||||
current_block->nodes.emplace_back(std::make_shared<ExtendsStatementNode>(template_name, tok.text.data() - tmpl.content.c_str()));
|
||||
|
||||
get_next_token();
|
||||
|
||||
} else if (tok.text == static_cast<decltype(tok.text)>("set")) {
|
||||
get_next_token();
|
||||
|
||||
@@ -565,14 +549,13 @@ class Parser {
|
||||
if (!parse_expression(tmpl, closing)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void parse_into(Template &tmpl, std::string_view path) {
|
||||
void parse_into(Template& tmpl, std::string_view path) {
|
||||
lexer.start(tmpl.content);
|
||||
current_block = &tmpl.root;
|
||||
|
||||
@@ -586,7 +569,8 @@ class Parser {
|
||||
if (!for_statement_stack.empty()) {
|
||||
throw_parser_error("unmatched for");
|
||||
}
|
||||
} return;
|
||||
}
|
||||
return;
|
||||
case Token::Kind::Text: {
|
||||
current_block->nodes.emplace_back(std::make_shared<TextNode>(tok.text.data() - tmpl.content.c_str(), tok.text.size()));
|
||||
} break;
|
||||
@@ -636,11 +620,10 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
explicit Parser(const ParserConfig& parser_config, const LexerConfig& lexer_config,
|
||||
TemplateStorage& template_storage, const FunctionStorage& function_storage)
|
||||
: config(parser_config), lexer(lexer_config), template_storage(template_storage), function_storage(function_storage) { }
|
||||
explicit Parser(const ParserConfig& parser_config, const LexerConfig& lexer_config, TemplateStorage& template_storage,
|
||||
const FunctionStorage& function_storage)
|
||||
: config(parser_config), lexer(lexer_config), template_storage(template_storage), function_storage(function_storage) {}
|
||||
|
||||
Template parse(std::string_view input, std::string_view path) {
|
||||
auto result = Template(static_cast<std::string>(input));
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace inja {
|
||||
/*!
|
||||
* \brief Class for rendering a Template with data.
|
||||
*/
|
||||
class Renderer : public NodeVisitor {
|
||||
class Renderer : public NodeVisitor {
|
||||
using Op = FunctionStorage::Operation;
|
||||
|
||||
const RenderConfig config;
|
||||
@@ -104,8 +104,7 @@ class Renderer : public NodeVisitor {
|
||||
data_eval_stack.push(result_ptr.get());
|
||||
}
|
||||
|
||||
template<size_t N, size_t N_start = 0, bool throw_not_found=true>
|
||||
std::array<const json*, N> get_arguments(const FunctionNode& node) {
|
||||
template <size_t N, size_t N_start = 0, bool throw_not_found = true> std::array<const json*, N> get_arguments(const FunctionNode& node) {
|
||||
if (node.arguments.size() < N_start + N) {
|
||||
throw_renderer_error("function needs " + std::to_string(N_start + N) + " variables, but has only found " + std::to_string(node.arguments.size()), node);
|
||||
}
|
||||
@@ -135,10 +134,9 @@ class Renderer : public NodeVisitor {
|
||||
return result;
|
||||
}
|
||||
|
||||
template<bool throw_not_found=true>
|
||||
Arguments get_argument_vector(const FunctionNode& node) {
|
||||
template <bool throw_not_found = true> Arguments get_argument_vector(const FunctionNode& node) {
|
||||
const size_t N = node.arguments.size();
|
||||
for (auto a: node.arguments) {
|
||||
for (auto a : node.arguments) {
|
||||
a->accept(*this);
|
||||
}
|
||||
|
||||
@@ -177,7 +175,7 @@ class Renderer : public NodeVisitor {
|
||||
output_stream->write(current_template->content.c_str() + node.pos, node.length);
|
||||
}
|
||||
|
||||
void visit(const ExpressionNode&) { }
|
||||
void visit(const ExpressionNode&) {}
|
||||
|
||||
void visit(const LiteralNode& node) {
|
||||
data_eval_stack.push(&node.value);
|
||||
@@ -186,10 +184,8 @@ class Renderer : public NodeVisitor {
|
||||
void visit(const DataNode& node) {
|
||||
if (additional_data.contains(node.ptr)) {
|
||||
data_eval_stack.push(&(additional_data[node.ptr]));
|
||||
|
||||
} else if (data_input->contains(node.ptr)) {
|
||||
data_eval_stack.push(&(*data_input)[node.ptr]);
|
||||
|
||||
} else {
|
||||
// Try to evaluate as a no-argument callback
|
||||
const auto function_data = function_storage.find_function(node.name, 0);
|
||||
@@ -198,7 +194,6 @@ class Renderer : public NodeVisitor {
|
||||
const auto value = std::make_shared<json>(function_data.callback(empty_args));
|
||||
data_tmp_stack.push_back(value);
|
||||
data_eval_stack.push(value.get());
|
||||
|
||||
} else {
|
||||
data_eval_stack.push(nullptr);
|
||||
not_found_stack.emplace(&node);
|
||||
@@ -325,12 +320,12 @@ class Renderer : public NodeVisitor {
|
||||
make_result(get_arguments<1>(node)[0]->get<int>() % 2 == 0);
|
||||
} break;
|
||||
case Op::Exists: {
|
||||
auto &&name = get_arguments<1>(node)[0]->get_ref<const std::string&>();
|
||||
auto&& name = get_arguments<1>(node)[0]->get_ref<const std::string&>();
|
||||
make_result(data_input->contains(json::json_pointer(DataNode::convert_dot_to_ptr(name))));
|
||||
} break;
|
||||
case Op::ExistsInObject: {
|
||||
const auto args = get_arguments<2>(node);
|
||||
auto &&name = args[1]->get_ref<const std::string&>();
|
||||
auto&& name = args[1]->get_ref<const std::string&>();
|
||||
make_result(args[0]->find(name) != args[0]->end());
|
||||
} break;
|
||||
case Op::First: {
|
||||
@@ -480,9 +475,9 @@ class Renderer : public NodeVisitor {
|
||||
print_data(eval_expression_list(node));
|
||||
}
|
||||
|
||||
void visit(const StatementNode&) { }
|
||||
void visit(const StatementNode&) {}
|
||||
|
||||
void visit(const ForStatementNode&) { }
|
||||
void visit(const ForStatementNode&) {}
|
||||
|
||||
void visit(const ForArrayStatementNode& node) {
|
||||
const auto result = eval_expression_list(node.condition);
|
||||
@@ -584,7 +579,7 @@ class Renderer : public NodeVisitor {
|
||||
void visit(const ExtendsStatementNode& node) {
|
||||
const auto included_template_it = template_storage.find(node.file);
|
||||
if (included_template_it != template_storage.end()) {
|
||||
const Template *parent_template = &included_template_it->second;
|
||||
const Template* parent_template = &included_template_it->second;
|
||||
render_to(*output_stream, *parent_template, *data_input, &additional_data);
|
||||
break_rendering = true;
|
||||
} else if (config.throw_at_missing_includes) {
|
||||
@@ -600,7 +595,7 @@ class Renderer : public NodeVisitor {
|
||||
if (block_it != current_template->block_storage.end()) {
|
||||
block_statement_stack.emplace_back(&node);
|
||||
block_it->second->block.accept(*this);
|
||||
block_statement_stack.pop_back();
|
||||
block_statement_stack.pop_back();
|
||||
}
|
||||
current_level = old_level;
|
||||
current_template = template_stack.back();
|
||||
@@ -615,7 +610,7 @@ class Renderer : public NodeVisitor {
|
||||
|
||||
public:
|
||||
Renderer(const RenderConfig& config, const TemplateStorage& template_storage, const FunctionStorage& function_storage)
|
||||
: config(config), template_storage(template_storage), function_storage(function_storage) { }
|
||||
: config(config), template_storage(template_storage), function_storage(function_storage) {}
|
||||
|
||||
void render_to(std::ostream& os, const Template& tmpl, const json& data, json* loop_data = nullptr) {
|
||||
output_stream = &os;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "node.hpp"
|
||||
|
||||
|
||||
namespace inja {
|
||||
|
||||
/*!
|
||||
@@ -16,9 +15,9 @@ class StatisticsVisitor : public NodeVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
void visit(const TextNode&) { }
|
||||
void visit(const ExpressionNode&) { }
|
||||
void visit(const LiteralNode&) { }
|
||||
void visit(const TextNode&) {}
|
||||
void visit(const ExpressionNode&) {}
|
||||
void visit(const LiteralNode&) {}
|
||||
|
||||
void visit(const DataNode&) {
|
||||
variable_counter += 1;
|
||||
@@ -34,8 +33,8 @@ class StatisticsVisitor : public NodeVisitor {
|
||||
node.root->accept(*this);
|
||||
}
|
||||
|
||||
void visit(const StatementNode&) { }
|
||||
void visit(const ForStatementNode&) { }
|
||||
void visit(const StatementNode&) {}
|
||||
void visit(const ForStatementNode&) {}
|
||||
|
||||
void visit(const ForArrayStatementNode& node) {
|
||||
node.condition.accept(*this);
|
||||
@@ -53,20 +52,20 @@ class StatisticsVisitor : public NodeVisitor {
|
||||
node.false_statement.accept(*this);
|
||||
}
|
||||
|
||||
void visit(const IncludeStatementNode&) { }
|
||||
void visit(const IncludeStatementNode&) {}
|
||||
|
||||
void visit(const ExtendsStatementNode&) { }
|
||||
void visit(const ExtendsStatementNode&) {}
|
||||
|
||||
void visit(const BlockStatementNode& node) {
|
||||
node.block.accept(*this);
|
||||
}
|
||||
|
||||
void visit(const SetStatementNode&) { }
|
||||
void visit(const SetStatementNode&) {}
|
||||
|
||||
public:
|
||||
unsigned int variable_counter;
|
||||
|
||||
explicit StatisticsVisitor() : variable_counter(0) { }
|
||||
explicit StatisticsVisitor(): variable_counter(0) {}
|
||||
};
|
||||
|
||||
} // namespace inja
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "node.hpp"
|
||||
#include "statistics.hpp"
|
||||
|
||||
|
||||
namespace inja {
|
||||
|
||||
/*!
|
||||
@@ -20,8 +19,8 @@ struct Template {
|
||||
std::string content;
|
||||
std::map<std::string, std::shared_ptr<BlockStatementNode>> block_storage;
|
||||
|
||||
explicit Template() { }
|
||||
explicit Template(const std::string& content): content(content) { }
|
||||
explicit Template() {}
|
||||
explicit Template(const std::string& content): content(content) {}
|
||||
|
||||
/// Return number of variables (total number, not distinct ones) in the template
|
||||
int count_variables() {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
|
||||
namespace inja {
|
||||
|
||||
/*!
|
||||
@@ -48,12 +47,12 @@ struct Token {
|
||||
Unknown,
|
||||
Eof,
|
||||
};
|
||||
|
||||
|
||||
Kind kind {Kind::Unknown};
|
||||
std::string_view text;
|
||||
|
||||
explicit constexpr Token() = default;
|
||||
explicit constexpr Token(Kind kind, std::string_view text) : kind(kind), text(text) {}
|
||||
explicit constexpr Token(Kind kind, std::string_view text): kind(kind), text(text) {}
|
||||
|
||||
std::string describe() const {
|
||||
switch (kind) {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "exceptions.hpp"
|
||||
|
||||
|
||||
namespace inja {
|
||||
|
||||
namespace string_view {
|
||||
@@ -55,14 +54,14 @@ inline SourceLocation get_source_location(std::string_view content, size_t pos)
|
||||
return {count_lines + 1, sliced.length() - last_newline};
|
||||
}
|
||||
|
||||
inline void replace_substring(std::string& s, const std::string& f,
|
||||
const std::string& t)
|
||||
{
|
||||
if (f.empty()) return;
|
||||
for (auto pos = s.find(f); // find first occurrence of f
|
||||
pos != std::string::npos; // make sure f was found
|
||||
s.replace(pos, f.size(), t), // replace with t, and
|
||||
pos = s.find(f, pos + t.size())) // find next occurrence of f
|
||||
inline void replace_substring(std::string& s, const std::string& f, const std::string& t) {
|
||||
if (f.empty()) {
|
||||
return;
|
||||
}
|
||||
for (auto pos = s.find(f); // find first occurrence of f
|
||||
pos != std::string::npos; // make sure f was found
|
||||
s.replace(pos, f.size(), t), // replace with t, and
|
||||
pos = s.find(f, pos + t.size())) // find next occurrence of f
|
||||
{}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,6 @@
|
||||
#include "hayai/hayai.hpp"
|
||||
#include <inja/inja.hpp>
|
||||
|
||||
|
||||
inja::Environment env;
|
||||
|
||||
const std::string test_file_directory {"../test/data/benchmark/"};
|
||||
@@ -13,11 +12,15 @@ auto large_data = env.load_json(test_file_directory + "large_data.json");
|
||||
std::string medium_template = env.load_file(test_file_directory + "medium_template.txt");
|
||||
std::string large_template = env.load_file(test_file_directory + "large_template.txt");
|
||||
|
||||
|
||||
BENCHMARK(SmallDataMediumTemplate, render, 5, 30) { env.render(medium_template, small_data); }
|
||||
BENCHMARK(LargeDataMediumTemplate, render, 5, 15) { env.render(medium_template, large_data); }
|
||||
BENCHMARK(LargeDataLargeTemplate, render, 5, 5) { env.render(large_template, large_data); }
|
||||
|
||||
BENCHMARK(SmallDataMediumTemplate, render, 5, 30) {
|
||||
env.render(medium_template, small_data);
|
||||
}
|
||||
BENCHMARK(LargeDataMediumTemplate, render, 5, 15) {
|
||||
env.render(medium_template, large_data);
|
||||
}
|
||||
BENCHMARK(LargeDataLargeTemplate, render, 5, 5) {
|
||||
env.render(large_template, large_data);
|
||||
}
|
||||
|
||||
int main() {
|
||||
hayai::ConsoleOutputter consoleOutputter;
|
||||
|
||||
@@ -5,7 +5,9 @@ TEST_CASE("loading") {
|
||||
inja::json data;
|
||||
data["name"] = "Jeff";
|
||||
|
||||
SUBCASE("Files should be loaded") { CHECK(env.load_file(test_file_directory + "simple.txt") == "Hello {{ name }}."); }
|
||||
SUBCASE("Files should be loaded") {
|
||||
CHECK(env.load_file(test_file_directory + "simple.txt") == "Hello {{ name }}.");
|
||||
}
|
||||
|
||||
SUBCASE("Files should be rendered") {
|
||||
CHECK(env.render_file(test_file_directory + "simple.txt", data) == "Hello Jeff.");
|
||||
@@ -29,8 +31,7 @@ TEST_CASE("complete-files") {
|
||||
|
||||
for (std::string test_name : {"simple-file", "nested", "nested-line", "html", "html-extend"}) {
|
||||
SUBCASE(test_name.c_str()) {
|
||||
CHECK(env.render_file_with_json_file(test_name + "/template.txt", test_name + "/data.json") ==
|
||||
env.load_file(test_name + "/result.txt"));
|
||||
CHECK(env.render_file_with_json_file(test_name + "/template.txt", test_name + "/data.json") == env.load_file(test_name + "/result.txt"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +50,7 @@ TEST_CASE("complete-files-whitespace-control") {
|
||||
|
||||
for (std::string test_name : {"nested-whitespace"}) {
|
||||
SUBCASE(test_name.c_str()) {
|
||||
CHECK(env.render_file_with_json_file(test_name + "/template.txt", test_name + "/data.json") ==
|
||||
env.load_file(test_name + "/result.txt"));
|
||||
CHECK(env.render_file_with_json_file(test_name + "/template.txt", test_name + "/data.json") == env.load_file(test_name + "/result.txt"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,8 @@ TEST_CASE("include-without-local-files") {
|
||||
inja::Environment env {test_file_directory};
|
||||
env.set_search_included_templates_in_files(false);
|
||||
|
||||
CHECK_THROWS_WITH(env.render_file_with_json_file("html/template.txt", "html/data.json"), "[inja.exception.render_error] (at 3:14) include 'header.txt' not found");
|
||||
CHECK_THROWS_WITH(env.render_file_with_json_file("html/template.txt", "html/data.json"),
|
||||
"[inja.exception.render_error] (at 3:14) include 'header.txt' not found");
|
||||
}
|
||||
|
||||
TEST_CASE("include-in-memory-and-file-template") {
|
||||
|
||||
@@ -56,8 +56,8 @@ TEST_CASE("functions") {
|
||||
SUBCASE("length") {
|
||||
CHECK(env.render("{{ length(names) }}", data) == "4"); // Length of array
|
||||
CHECK(env.render("{{ length(name) }}", data) == "5"); // Length of string
|
||||
// CHECK_THROWS_WITH( env.render("{{ length(5) }}", data), "[inja.exception.json_error]
|
||||
// [json.exception.type_error.302] type must be array, but is number" );
|
||||
// CHECK_THROWS_WITH( env.render("{{ length(5) }}", data), "[inja.exception.json_error]
|
||||
// [json.exception.type_error.302] type must be array, but is number" );
|
||||
}
|
||||
|
||||
SUBCASE("sort") {
|
||||
@@ -150,8 +150,7 @@ TEST_CASE("functions") {
|
||||
CHECK(env.render("{{ default(name, \"nobody\") }}", data) == "Peter");
|
||||
CHECK(env.render("{{ default(surname, \"nobody\") }}", data) == "nobody");
|
||||
CHECK(env.render("{{ default(surname, \"{{ surname }}\") }}", data) == "{{ surname }}");
|
||||
CHECK_THROWS_WITH(env.render("{{ default(surname, lastname) }}", data),
|
||||
"[inja.exception.render_error] (at 1:21) variable 'lastname' not found");
|
||||
CHECK_THROWS_WITH(env.render("{{ default(surname, lastname) }}", data), "[inja.exception.render_error] (at 1:21) variable 'lastname' not found");
|
||||
}
|
||||
|
||||
SUBCASE("exists") {
|
||||
@@ -159,7 +158,7 @@ TEST_CASE("functions") {
|
||||
CHECK(env.render("{{ exists(\"zipcode\") }}", data) == "false");
|
||||
CHECK(env.render("{{ exists(name) }}", data) == "false");
|
||||
CHECK(env.render("{{ exists(property) }}", data) == "true");
|
||||
|
||||
|
||||
// CHECK(env.render("{{ exists(\"keywords\") and length(keywords) > 0 }}", data) == "false");
|
||||
}
|
||||
|
||||
@@ -168,10 +167,8 @@ TEST_CASE("functions") {
|
||||
CHECK(env.render("{{ existsIn(brother, \"parents\") }}", data) == "false");
|
||||
CHECK(env.render("{{ existsIn(brother, property) }}", data) == "true");
|
||||
CHECK(env.render("{{ existsIn(brother, name) }}", data) == "false");
|
||||
CHECK_THROWS_WITH(env.render("{{ existsIn(sister, \"lastname\") }}", data),
|
||||
"[inja.exception.render_error] (at 1:13) variable 'sister' not found");
|
||||
CHECK_THROWS_WITH(env.render("{{ existsIn(brother, sister) }}", data),
|
||||
"[inja.exception.render_error] (at 1:22) variable 'sister' not found");
|
||||
CHECK_THROWS_WITH(env.render("{{ existsIn(sister, \"lastname\") }}", data), "[inja.exception.render_error] (at 1:13) variable 'sister' not found");
|
||||
CHECK_THROWS_WITH(env.render("{{ existsIn(brother, sister) }}", data), "[inja.exception.render_error] (at 1:22) variable 'sister' not found");
|
||||
}
|
||||
|
||||
SUBCASE("join") {
|
||||
@@ -212,7 +209,7 @@ TEST_CASE("callbacks") {
|
||||
inja::json data;
|
||||
data["age"] = 28;
|
||||
|
||||
env.add_callback("double", 1, [](inja::Arguments &args) {
|
||||
env.add_callback("double", 1, [](inja::Arguments& args) {
|
||||
int number = args.at(0)->get<int>();
|
||||
return 2 * number;
|
||||
});
|
||||
@@ -244,7 +241,7 @@ TEST_CASE("callbacks") {
|
||||
});
|
||||
|
||||
env.add_void_callback("log", 1, [](inja::Arguments) {
|
||||
|
||||
|
||||
});
|
||||
|
||||
env.add_callback("multiply", 0, [](inja::Arguments) { return 1.0; });
|
||||
@@ -262,7 +259,7 @@ TEST_CASE("callbacks") {
|
||||
|
||||
SUBCASE("Variadic") {
|
||||
env.add_callback("argmax", [](inja::Arguments& args) {
|
||||
auto result = std::max_element(args.begin(), args.end(), [](const inja::json* a, const inja::json* b) { return *a < *b;});
|
||||
auto result = std::max_element(args.begin(), args.end(), [](const inja::json* a, const inja::json* b) { return *a < *b; });
|
||||
return std::distance(args.begin(), result);
|
||||
});
|
||||
|
||||
|
||||
@@ -50,25 +50,20 @@ TEST_CASE("types") {
|
||||
SUBCASE("loops") {
|
||||
CHECK(env.render("{% for name in names %}a{% endfor %}", data) == "aa");
|
||||
CHECK(env.render("Hello {% for name in names %}{{ name }} {% endfor %}!", data) == "Hello Jeff Seb !");
|
||||
CHECK(env.render("Hello {% for name in names %}{{ loop.index }}: {{ name }}, {% endfor %}!", data) ==
|
||||
"Hello 0: Jeff, 1: Seb, !");
|
||||
CHECK(env.render("Hello {% for name in names %}{{ loop.index }}: {{ name }}, {% endfor %}!", data) == "Hello 0: Jeff, 1: Seb, !");
|
||||
CHECK(env.render("{% for type, name in relatives %}{{ loop.index1 }}: {{ type }}: {{ name }}{% if loop.is_last == "
|
||||
"false %}, {% endif %}{% endfor %}",
|
||||
data) == "1: brother: Chris, 2: mother: Maria, 3: sister: Jenny");
|
||||
CHECK(env.render("{% for v in vars %}{% if v > 0 %}+{% endif %}{% endfor %}", data) == "+++");
|
||||
CHECK(env.render(
|
||||
"{% for name in names %}{{ loop.index }}: {{ name }}{% if not loop.is_last %}, {% endif %}{% endfor %}!",
|
||||
data) == "0: Jeff, 1: Seb!");
|
||||
CHECK(env.render("{% for name in names %}{{ loop.index }}: {{ name }}{% if not loop.is_last %}, {% endif %}{% endfor %}!", data) == "0: Jeff, 1: Seb!");
|
||||
CHECK(env.render("{% for name in names %}{{ loop.index }}: {{ name }}{% if loop.is_last == false %}, {% endif %}{% "
|
||||
"endfor %}!",
|
||||
data) == "0: Jeff, 1: Seb!");
|
||||
|
||||
CHECK(env.render("{% for name in [] %}a{% endfor %}", data) == "");
|
||||
|
||||
CHECK_THROWS_WITH(env.render("{% for name ins names %}a{% endfor %}", data),
|
||||
"[inja.exception.parser_error] (at 1:13) expected 'in', got 'ins'");
|
||||
CHECK_THROWS_WITH(env.render("{% for name in empty_loop %}a{% endfor %}", data),
|
||||
"[inja.exception.render_error] (at 1:16) variable 'empty_loop' not found");
|
||||
CHECK_THROWS_WITH(env.render("{% for name ins names %}a{% endfor %}", data), "[inja.exception.parser_error] (at 1:13) expected 'in', got 'ins'");
|
||||
CHECK_THROWS_WITH(env.render("{% for name in empty_loop %}a{% endfor %}", data), "[inja.exception.render_error] (at 1:16) variable 'empty_loop' not found");
|
||||
// CHECK_THROWS_WITH( env.render("{% for name in relatives %}{{ name }}{% endfor %}", data),
|
||||
// "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is object" );
|
||||
}
|
||||
@@ -112,12 +107,10 @@ TEST_CASE("types") {
|
||||
CHECK(env.render("{% if age >= 30 %}Right{% else %}Wrong{% endif %}", data) == "Wrong");
|
||||
CHECK(env.render("{% if age in [28, 29, 30] %}True{% endif %}", data) == "True");
|
||||
CHECK(env.render("{% if age == 28 %}28{% else if age == 29 %}29{% endif %}", data) == "29");
|
||||
CHECK(env.render("{% if age == 26 %}26{% else if age == 27 %}27{% else if age == 28 %}28{% else %}29{% endif %}",
|
||||
data) == "29");
|
||||
CHECK(env.render("{% if age == 26 %}26{% else if age == 27 %}27{% else if age == 28 %}28{% else %}29{% endif %}", data) == "29");
|
||||
CHECK(env.render("{% if age == 25 %}+{% endif %}{% if age == 29 %}+{% else %}-{% endif %}", data) == "+");
|
||||
|
||||
CHECK_THROWS_WITH(env.render("{% if is_happy %}{% if is_happy %}{% endif %}", data),
|
||||
"[inja.exception.parser_error] (at 1:46) unmatched if");
|
||||
CHECK_THROWS_WITH(env.render("{% if is_happy %}{% if is_happy %}{% endif %}", data), "[inja.exception.parser_error] (at 1:46) unmatched if");
|
||||
CHECK_THROWS_WITH(env.render("{% if is_happy %}{% else if is_happy %}{% end if %}", data),
|
||||
"[inja.exception.parser_error] (at 1:43) expected statement, got 'end'");
|
||||
}
|
||||
@@ -128,8 +121,7 @@ TEST_CASE("types") {
|
||||
CHECK(env.render("{% set age=30 %}{{age}}", data) == "30");
|
||||
CHECK(env.render("{% set predefined.value=1 %}{% if existsIn(predefined, \"value\") %}{{predefined.value}}{% endif %}", data) == "1");
|
||||
CHECK(env.render("{% set brother.name=\"Bob\" %}{{brother.name}}", data) == "Bob");
|
||||
CHECK_THROWS_WITH(env.render("{% if predefined %}{% endif %}", data),
|
||||
"[inja.exception.render_error] (at 1:7) variable 'predefined' not found");
|
||||
CHECK_THROWS_WITH(env.render("{% if predefined %}{% endif %}", data), "[inja.exception.render_error] (at 1:7) variable 'predefined' not found");
|
||||
CHECK(env.render("{{age}}", data) == "29");
|
||||
CHECK(env.render("{{brother.name}}", data) == "Chris");
|
||||
}
|
||||
@@ -181,31 +173,24 @@ TEST_CASE("templates") {
|
||||
|
||||
inja::Template t2 = env.parse("{% include \"greeting\" %}!");
|
||||
CHECK(env.render(t2, data) == "Hello Peter!");
|
||||
CHECK_THROWS_WITH(env.parse("{% include \"does-not-exist\" %}!"),
|
||||
"[inja.exception.file_error] failed accessing file at 'does-not-exist'");
|
||||
CHECK_THROWS_WITH(env.parse("{% include \"does-not-exist\" %}!"), "[inja.exception.file_error] failed accessing file at 'does-not-exist'");
|
||||
|
||||
CHECK_THROWS_WITH(env.parse("{% include does-not-exist %}!"),
|
||||
"[inja.exception.parser_error] (at 1:12) expected string, got 'does-not-exist'");
|
||||
CHECK_THROWS_WITH(env.parse("{% include does-not-exist %}!"), "[inja.exception.parser_error] (at 1:12) expected string, got 'does-not-exist'");
|
||||
}
|
||||
|
||||
SUBCASE("include-callback") {
|
||||
inja::Environment env;
|
||||
|
||||
CHECK_THROWS_WITH(env.parse("{% include \"does-not-exist\" %}!"),
|
||||
"[inja.exception.file_error] failed accessing file at 'does-not-exist'");
|
||||
CHECK_THROWS_WITH(env.parse("{% include \"does-not-exist\" %}!"), "[inja.exception.file_error] failed accessing file at 'does-not-exist'");
|
||||
|
||||
env.set_search_included_templates_in_files(false);
|
||||
env.set_include_callback([&env](const std::string&, const std::string&) {
|
||||
return env.parse("Hello {{ name }}");
|
||||
});
|
||||
env.set_include_callback([&env](const std::string&, const std::string&) { return env.parse("Hello {{ name }}"); });
|
||||
|
||||
inja::Template t1 = env.parse("{% include \"greeting\" %}!");
|
||||
CHECK(env.render(t1, data) == "Hello Peter!");
|
||||
|
||||
env.set_search_included_templates_in_files(true);
|
||||
env.set_include_callback([&env](const std::string&, const std::string& name) {
|
||||
return env.parse("Bye " + name);
|
||||
});
|
||||
env.set_include_callback([&env](const std::string&, const std::string& name) { return env.parse("Bye " + name); });
|
||||
|
||||
inja::Template t2 = env.parse("{% include \"Jeff\" %}!");
|
||||
CHECK(env.render(t2, data) == "Bye Jeff!");
|
||||
@@ -218,8 +203,7 @@ TEST_CASE("templates") {
|
||||
inja::Environment env;
|
||||
env.include_template("city.tpl", env.parse("{{ loop.index }}:{{ city.name }};"));
|
||||
|
||||
CHECK(env.render("{% for city in cities %}{% include \"city.tpl\" %}{% endfor %}", loop_data) ==
|
||||
"0:Munich;1:New York;");
|
||||
CHECK(env.render("{% for city in cities %}{% include \"city.tpl\" %}{% endfor %}", loop_data) == "0:Munich;1:New York;");
|
||||
}
|
||||
|
||||
SUBCASE("count variables") {
|
||||
|
||||
@@ -27,7 +27,7 @@ Try this
|
||||
|
||||
TEST_CASE("copy environment") {
|
||||
inja::Environment env;
|
||||
env.add_callback("double", 1, [](inja::Arguments &args) {
|
||||
env.add_callback("double", 1, [](inja::Arguments& args) {
|
||||
int number = args.at(0)->get<int>();
|
||||
return 2 * number;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user