diff --git a/.clang-format b/.clang-format index 5486ac5..3a48294 100644 --- a/.clang-format +++ b/.clang-format @@ -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 ... diff --git a/include/inja/environment.hpp b/include/inja/environment.hpp index 9e6f7c4..a652935 100644 --- a/include/inja/environment.hpp +++ b/include/inja/environment.hpp @@ -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. diff --git a/include/inja/exceptions.hpp b/include/inja/exceptions.hpp index b1458b4..f0dc8aa 100644 --- a/include/inja/exceptions.hpp +++ b/include/inja/exceptions.hpp @@ -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 diff --git a/include/inja/function_storage.hpp b/include/inja/function_storage.hpp index 1a6641f..891e45f 100644 --- a/include/inja/function_storage.hpp +++ b/include/inja/function_storage.hpp @@ -4,7 +4,6 @@ #include #include - namespace inja { using Arguments = std::vector; @@ -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, 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(name), num_args), FunctionData { op }); + function_storage.emplace(std::make_pair(static_cast(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(name), num_args), FunctionData { Operation::Callback, callback }); + function_storage.emplace(std::make_pair(static_cast(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(name), VARIADIC)); if (it != function_storage.end()) { @@ -131,7 +130,7 @@ public: } } - return FunctionData { Operation::None }; + return FunctionData {Operation::None}; } }; diff --git a/include/inja/inja.hpp b/include/inja/inja.hpp index 1434f57..381da4b 100644 --- a/include/inja/inja.hpp +++ b/include/inja/inja.hpp @@ -4,7 +4,7 @@ | || '_ \ | |/ _` | Licensed under the MIT License . | || | | || | (_| | |___|_| |_|/ |\__,_| 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 - #ifndef INJA_THROW - #define INJA_THROW(exception) std::abort(); std::ignore = exception - #endif - #ifndef INJA_NOEXCEPTION - #define INJA_NOEXCEPTION - #endif +#include +#ifndef INJA_THROW +#define INJA_THROW(exception) \ + std::abort(); \ + std::ignore = exception +#endif +#ifndef INJA_NOEXCEPTION +#define INJA_NOEXCEPTION +#endif #endif #include "environment.hpp" diff --git a/include/inja/lexer.hpp b/include/inja/lexer.hpp index 5f45da1..c777600 100644 --- a/include/inja/lexer.hpp +++ b/include/inja/lexer.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 { diff --git a/include/inja/node.hpp b/include/inja/node.hpp index 2df0054..1946805 100644 --- a/include/inja/node.hpp +++ b/include/inja/node.hpp @@ -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> 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> 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 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); diff --git a/include/inja/parser.hpp b/include/inja/parser.hpp index 61e2aa8..3ea1793 100644 --- a/include/inja/parser.hpp +++ b/include/inja/parser.hpp @@ -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> function_stack; std::vector> 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("true") || tok.text == static_cast("false") || tok.text == static_cast("null")) { + if (tok.text == static_cast("true") || tok.text == static_cast("false") || + tok.text == static_cast("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(static_cast(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(static_cast(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(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("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("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("block")) { get_next_token(); @@ -456,18 +444,16 @@ class Parser { } get_next_token(); - } else if (tok.text == static_cast("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("for")) { get_next_token(); @@ -491,11 +477,13 @@ class Parser { value_token = tok; get_next_token(); - for_statement_node = std::make_shared(static_cast(key_token.text), static_cast(value_token.text), current_block, tok.text.data() - tmpl.content.c_str()); + for_statement_node = std::make_shared(static_cast(key_token.text), static_cast(value_token.text), + current_block, tok.text.data() - tmpl.content.c_str()); - // Array type + // Array type } else { - for_statement_node = std::make_shared(static_cast(value_token.text), current_block, tok.text.data() - tmpl.content.c_str()); + for_statement_node = + std::make_shared(static_cast(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("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("include")) { get_next_token(); @@ -532,7 +518,6 @@ class Parser { current_block->nodes.emplace_back(std::make_shared(template_name, tok.text.data() - tmpl.content.c_str())); get_next_token(); - } else if (tok.text == static_cast("extends")) { get_next_token(); @@ -542,7 +527,6 @@ class Parser { current_block->nodes.emplace_back(std::make_shared(template_name, tok.text.data() - tmpl.content.c_str())); get_next_token(); - } else if (tok.text == static_cast("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(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(input)); diff --git a/include/inja/renderer.hpp b/include/inja/renderer.hpp index 67dc09d..f24bb91 100644 --- a/include/inja/renderer.hpp +++ b/include/inja/renderer.hpp @@ -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 - std::array get_arguments(const FunctionNode& node) { + template std::array 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 - Arguments get_argument_vector(const FunctionNode& node) { + template 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(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() % 2 == 0); } break; case Op::Exists: { - auto &&name = get_arguments<1>(node)[0]->get_ref(); + auto&& name = get_arguments<1>(node)[0]->get_ref(); 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(); + auto&& name = args[1]->get_ref(); 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; diff --git a/include/inja/statistics.hpp b/include/inja/statistics.hpp index f9b3f88..da33593 100644 --- a/include/inja/statistics.hpp +++ b/include/inja/statistics.hpp @@ -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 diff --git a/include/inja/template.hpp b/include/inja/template.hpp index 45b276b..a396dd5 100644 --- a/include/inja/template.hpp +++ b/include/inja/template.hpp @@ -9,7 +9,6 @@ #include "node.hpp" #include "statistics.hpp" - namespace inja { /*! @@ -20,8 +19,8 @@ struct Template { std::string content; std::map> 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() { diff --git a/include/inja/token.hpp b/include/inja/token.hpp index 5391342..207e78e 100644 --- a/include/inja/token.hpp +++ b/include/inja/token.hpp @@ -4,7 +4,6 @@ #include #include - 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) { diff --git a/include/inja/utils.hpp b/include/inja/utils.hpp index c1d13d5..4de05fd 100644 --- a/include/inja/utils.hpp +++ b/include/inja/utils.hpp @@ -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 {} } diff --git a/single_include/inja/inja.hpp b/single_include/inja/inja.hpp index 0273fd4..6aad870 100644 --- a/single_include/inja/inja.hpp +++ b/single_include/inja/inja.hpp @@ -4,7 +4,7 @@ | || '_ \ | |/ _` | Licensed under the MIT License . | || | | || | (_| | |___|_| |_|/ |\__,_| 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 - #ifndef INJA_THROW - #define INJA_THROW(exception) std::abort(); std::ignore = exception - #endif - #ifndef INJA_NOEXCEPTION - #define INJA_NOEXCEPTION - #endif +#include +#ifndef INJA_THROW +#define INJA_THROW(exception) \ + std::abort(); \ + std::ignore = exception +#endif +#ifndef INJA_NOEXCEPTION +#define INJA_NOEXCEPTION +#endif #endif // #include "environment.hpp" @@ -91,7 +93,6 @@ namespace inja { #include #include - namespace inja { using Arguments = std::vector; @@ -156,7 +157,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; }; @@ -165,44 +166,44 @@ private: const int VARIADIC {-1}; std::map, 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(name), num_args), FunctionData { op }); + function_storage.emplace(std::make_pair(static_cast(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(name), num_args), FunctionData { Operation::Callback, callback }); + function_storage.emplace(std::make_pair(static_cast(name), num_args), FunctionData {Operation::Callback, callback}); } FunctionData find_function(std::string_view name, int num_args) const { @@ -210,7 +211,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(name), VARIADIC)); if (it != function_storage.end()) { @@ -218,7 +219,7 @@ public: } } - return FunctionData { Operation::None }; + return FunctionData {Operation::None}; } }; @@ -256,30 +257,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 @@ -287,7 +287,6 @@ struct DataError : public InjaError { #endif // INCLUDE_INJA_EXCEPTIONS_HPP_ - namespace inja { namespace string_view { @@ -333,14 +332,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 {} } @@ -349,7 +348,6 @@ inline void replace_substring(std::string& s, const std::string& f, #endif // INCLUDE_INJA_UTILS_HPP_ - namespace inja { class NodeVisitor; @@ -370,7 +368,6 @@ class ExtendsStatementNode; class BlockStatementNode; class SetStatementNode; - class NodeVisitor { public: virtual ~NodeVisitor() = default; @@ -402,16 +399,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> nodes; - explicit BlockNode() : AstNode(0) {} + explicit BlockNode(): AstNode(0) {} void accept(NodeVisitor& v) const { v.visit(*this); @@ -422,7 +418,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); @@ -431,7 +427,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); @@ -442,7 +438,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); @@ -465,7 +461,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); @@ -491,98 +487,99 @@ public: std::vector> 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; + } } } @@ -595,8 +592,8 @@ class ExpressionListNode : public AstNode { public: std::shared_ptr 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); @@ -605,7 +602,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; }; @@ -614,9 +611,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; }; @@ -625,7 +622,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); @@ -637,7 +634,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); @@ -649,13 +647,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); @@ -666,7 +664,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); @@ -677,7 +675,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); @@ -688,9 +686,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); @@ -702,7 +700,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); @@ -720,7 +718,6 @@ public: // #include "node.hpp" - namespace inja { /*! @@ -733,9 +730,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; @@ -751,8 +748,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); @@ -770,20 +767,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 @@ -791,7 +788,6 @@ public: #endif // INCLUDE_INJA_STATISTICS_HPP_ - namespace inja { /*! @@ -802,8 +798,8 @@ struct Template { std::string content; std::map> 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() { @@ -928,7 +924,6 @@ struct RenderConfig { #include #include - namespace inja { /*! @@ -972,12 +967,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) { @@ -1035,7 +1030,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) @@ -1216,7 +1210,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()) { @@ -1262,7 +1258,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); @@ -1314,7 +1310,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 { @@ -1434,7 +1430,6 @@ public: // #include "utils.hpp" - namespace inja { /*! @@ -1456,8 +1451,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> function_stack; std::vector> arguments; @@ -1528,7 +1523,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 + "'")); } @@ -1555,7 +1549,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) { @@ -1564,28 +1558,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) { @@ -1596,7 +1586,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) { @@ -1607,33 +1596,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("true") || tok.text == static_cast("false") || tok.text == static_cast("null")) { + if (tok.text == static_cast("true") || tok.text == static_cast("false") || + tok.text == static_cast("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(static_cast(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(static_cast(tok.text), tok.text.data() - tmpl.content.c_str())); } - // Operators + // Operators } break; case Token::Kind::Equal: case Token::Kind::NotEqual: @@ -1649,7 +1638,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: { @@ -1710,12 +1699,14 @@ class Parser { } auto function_node = std::make_shared(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) { @@ -1725,13 +1716,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; @@ -1743,7 +1732,6 @@ class Parser { function_stack.top().first->number_args = 0; } } - } break; case Token::Kind::RightParen: { current_paren_level -= 1; @@ -1788,15 +1776,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; } @@ -1813,12 +1800,11 @@ class Parser { if (!parse_expression(tmpl, closing)) { return false; } - } else if (tok.text == static_cast("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; @@ -1838,7 +1824,6 @@ class Parser { return false; } } - } else if (tok.text == static_cast("endif")) { if (if_statement_stack.empty()) { throw_parser_error("endif without matching if"); @@ -1849,12 +1834,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("block")) { get_next_token(); @@ -1874,18 +1858,16 @@ class Parser { } get_next_token(); - } else if (tok.text == static_cast("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("for")) { get_next_token(); @@ -1909,11 +1891,13 @@ class Parser { value_token = tok; get_next_token(); - for_statement_node = std::make_shared(static_cast(key_token.text), static_cast(value_token.text), current_block, tok.text.data() - tmpl.content.c_str()); + for_statement_node = std::make_shared(static_cast(key_token.text), static_cast(value_token.text), + current_block, tok.text.data() - tmpl.content.c_str()); - // Array type + // Array type } else { - for_statement_node = std::make_shared(static_cast(value_token.text), current_block, tok.text.data() - tmpl.content.c_str()); + for_statement_node = + std::make_shared(static_cast(value_token.text), current_block, tok.text.data() - tmpl.content.c_str()); } current_block->nodes.emplace_back(for_statement_node); @@ -1929,18 +1913,16 @@ class Parser { if (!parse_expression(tmpl, closing)) { return false; } - } else if (tok.text == static_cast("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("include")) { get_next_token(); @@ -1950,7 +1932,6 @@ class Parser { current_block->nodes.emplace_back(std::make_shared(template_name, tok.text.data() - tmpl.content.c_str())); get_next_token(); - } else if (tok.text == static_cast("extends")) { get_next_token(); @@ -1960,7 +1941,6 @@ class Parser { current_block->nodes.emplace_back(std::make_shared(template_name, tok.text.data() - tmpl.content.c_str())); get_next_token(); - } else if (tok.text == static_cast("set")) { get_next_token(); @@ -1983,14 +1963,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; @@ -2004,7 +1983,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(tok.text.data() - tmpl.content.c_str(), tok.text.size())); } break; @@ -2054,11 +2034,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(input)); @@ -2119,7 +2098,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; @@ -2205,8 +2184,7 @@ class Renderer : public NodeVisitor { data_eval_stack.push(result_ptr.get()); } - template - std::array get_arguments(const FunctionNode& node) { + template std::array 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); } @@ -2236,10 +2214,9 @@ class Renderer : public NodeVisitor { return result; } - template - Arguments get_argument_vector(const FunctionNode& node) { + template 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); } @@ -2278,7 +2255,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); @@ -2287,10 +2264,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); @@ -2299,7 +2274,6 @@ class Renderer : public NodeVisitor { const auto value = std::make_shared(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); @@ -2426,12 +2400,12 @@ class Renderer : public NodeVisitor { make_result(get_arguments<1>(node)[0]->get() % 2 == 0); } break; case Op::Exists: { - auto &&name = get_arguments<1>(node)[0]->get_ref(); + auto&& name = get_arguments<1>(node)[0]->get_ref(); 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(); + auto&& name = args[1]->get_ref(); make_result(args[0]->find(name) != args[0]->end()); } break; case Op::First: { @@ -2581,9 +2555,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); @@ -2685,7 +2659,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) { @@ -2701,7 +2675,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(); @@ -2716,7 +2690,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; @@ -2760,12 +2734,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) { @@ -2837,7 +2810,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; @@ -2866,8 +2841,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); } @@ -2923,7 +2897,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. diff --git a/test/benchmark.cpp b/test/benchmark.cpp index 2cfc07b..92c696f 100644 --- a/test/benchmark.cpp +++ b/test/benchmark.cpp @@ -3,7 +3,6 @@ #include "hayai/hayai.hpp" #include - 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; diff --git a/test/test-files.cpp b/test/test-files.cpp index 2de97fc..aa01cff 100644 --- a/test/test-files.cpp +++ b/test/test-files.cpp @@ -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") { diff --git a/test/test-functions.cpp b/test/test-functions.cpp index 92eca89..667f553 100644 --- a/test/test-functions.cpp +++ b/test/test-functions.cpp @@ -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(); 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); }); diff --git a/test/test-renderer.cpp b/test/test-renderer.cpp index 2801ed0..2089791 100644 --- a/test/test-renderer.cpp +++ b/test/test-renderer.cpp @@ -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") { diff --git a/test/test-units.cpp b/test/test-units.cpp index 2366dde..bbef190 100644 --- a/test/test-units.cpp +++ b/test/test-units.cpp @@ -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(); return 2 * number; });