@@ -1534,6 +1534,7 @@ using json = nlohmann::json;
15341534
15351535using Arguments = std::vector<const json *>;
15361536using CallbackFunction = std::function<json(Arguments &args)>;
1537+ using VoidCallbackFunction = std::function<void (Arguments &args)>;
15371538
15381539/* !
15391540 * \brief Class for builtin functions and user-defined callbacks.
@@ -2161,6 +2162,11 @@ class Lexer {
21612162 pos = 0 ;
21622163 state = State::Text;
21632164 minus_state = MinusState::Number;
2165+
2166+ // Consume byte order mark (BOM) for UTF-8
2167+ if (inja::string_view::starts_with (m_in, " \xEF\xBB\xBF " )) {
2168+ m_in = m_in.substr (3 );
2169+ }
21642170 }
21652171
21662172 Token scan () {
@@ -2206,8 +2212,7 @@ class Lexer {
22062212 } else if (inja::string_view::starts_with (open_str, config.comment_open )) {
22072213 state = State::CommentStart;
22082214 must_lstrip = config.lstrip_blocks ;
2209- } else if ((pos == 0 || m_in[pos - 1 ] == ' \n ' ) &&
2210- inja::string_view::starts_with (open_str, config.line_statement )) {
2215+ } else if ((pos == 0 || m_in[pos - 1 ] == ' \n ' ) && inja::string_view::starts_with (open_str, config.line_statement )) {
22112216 state = State::LineStart;
22122217 } else {
22132218 pos += 1 ; // wasn't actually an opening sequence
@@ -3378,7 +3383,10 @@ class Renderer : public NodeVisitor {
33783383
33793384 void print_json (const std::shared_ptr<json> value) {
33803385 if (value->is_string ()) {
3381- *output_stream << value->get_ref <const std::string &>();
3386+ *output_stream << value->get_ref <const json::string_t &>();
3387+ } else if (value->is_number_integer ()) {
3388+ *output_stream << value->get <const json::number_integer_t >();
3389+ } else if (value->is_null ()) {
33823390 } else {
33833391 *output_stream << value->dump ();
33843392 }
@@ -3476,11 +3484,11 @@ class Renderer : public NodeVisitor {
34763484
34773485 void visit (const JsonNode& node) {
34783486 if (json_additional_data.contains (node.ptr )) {
3479- json_eval_stack.push (&json_additional_data[node.ptr ]);
3480-
3487+ json_eval_stack.push (&( json_additional_data[node.ptr ]) );
3488+
34813489 } else if (json_input->contains (node.ptr )) {
34823490 json_eval_stack.push (&(*json_input)[node.ptr ]);
3483-
3491+
34843492 } else {
34853493 // Try to evaluate as a no-argument callback
34863494 auto function_data = function_storage.find_function (node.name , 0 );
@@ -3564,7 +3572,7 @@ class Renderer : public NodeVisitor {
35643572 case Op::Add: {
35653573 auto args = get_arguments<2 >(node);
35663574 if (args[0 ]->is_string () && args[1 ]->is_string ()) {
3567- result_ptr = std::make_shared<json>(args[0 ]->get < std::string>() + args[1 ]->get < std::string>());
3575+ result_ptr = std::make_shared<json>(args[0 ]->get_ref < const std::string& >() + args[1 ]->get_ref < const std::string& >());
35683576 json_tmp_stack.push_back (result_ptr);
35693577 } else if (args[0 ]->is_number_integer () && args[1 ]->is_number_integer ()) {
35703578 result_ptr = std::make_shared<json>(args[0 ]->get <int >() + args[1 ]->get <int >());
@@ -3915,6 +3923,7 @@ class Renderer : public NodeVisitor {
39153923 json_input = &data;
39163924 if (loop_data) {
39173925 json_additional_data = *loop_data;
3926+ current_loop_data = &json_additional_data[" loop" ];
39183927 }
39193928
39203929 current_template->root .accept (*this );
@@ -3979,7 +3988,9 @@ class Environment {
39793988 // / Sets the opener and closer for template expressions
39803989 void set_expression (const std::string &open, const std::string &close) {
39813990 lexer_config.expression_open = open;
3991+ lexer_config.expression_open_force_lstrip = open + " -" ;
39823992 lexer_config.expression_close = close;
3993+ lexer_config.expression_close_force_rstrip = " -" + close;
39833994 lexer_config.update_open_chars ();
39843995 }
39853996
@@ -4088,7 +4099,14 @@ class Environment {
40884099 @brief Adds a variadic callback
40894100 */
40904101 void add_callback (const std::string &name, const CallbackFunction &callback) {
4091- function_storage.add_callback (name, -1 , callback);
4102+ add_callback (name, -1 , callback);
4103+ }
4104+
4105+ /* !
4106+ @brief Adds a variadic void callback
4107+ */
4108+ void add_void_callback (const std::string &name, const VoidCallbackFunction &callback) {
4109+ add_void_callback (name, -1 , callback);
40924110 }
40934111
40944112 /* !
@@ -4098,6 +4116,13 @@ class Environment {
40984116 function_storage.add_callback (name, num_args, callback);
40994117 }
41004118
4119+ /* !
4120+ @brief Adds a void callback with given number or arguments
4121+ */
4122+ void add_void_callback (const std::string &name, int num_args, const VoidCallbackFunction &callback) {
4123+ function_storage.add_callback (name, num_args, [callback](Arguments& args) { callback (args); return json (); });
4124+ }
4125+
41014126 /* * Includes a template with a given name into the environment.
41024127 * Then, a template can be rendered in another template using the
41034128 * include "<name>" syntax.
0 commit comments