fix codacy issues
diff --git a/README.md b/README.md
index d81a2fb..d2df546 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,6 @@
   </a>
 </p>
 
-
 Inja is a template engine for modern C++, loosely inspired by [jinja](http://jinja.pocoo.org) for python. It has an easy and yet powerful template syntax with all variables, loops, conditions, includes, callbacks, and comments you need, nested and combined as you like. Inja uses the wonderful [json](https://github.com/nlohmann/json) library by nlohmann for data input. Most importantly, inja needs only two header files, which is (nearly) as trivial as integration in C++ can get. Of course, everything is tested on all relevant compilers. Here is what it looks like:
 
 ```.cpp
@@ -58,7 +57,6 @@
 
 If you are using [cget](https://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install pantor/inja`. A specific version can be installed with `cget install pantor/inja@v2.1.0`.
 
-
 ## Tutorial
 
 This tutorial will give you an idea how to use inja. It will explain the most important concepts and give practical advices using examples and executable code. Beside this tutorial, you may check out the [documentation](https://pantor.github.io/inja).
@@ -134,7 +132,6 @@
 ```
 If no variable is found, valid JSON is printed directly, otherwise an `inja::RenderError` is thrown.
 
-
 ### Statements
 
 Statements can be written either with the `{% ... %}` syntax or the `##` syntax for entire lines. Note that `##` needs to start the line without indentation. The most important statements are loops, conditions and file includes. All statements can be nested.
@@ -197,7 +194,6 @@
 render("{% set new_hour=23 %}{{ new_hour }}pm", data); // "23pm"
 ```
 
-
 ### Functions
 
 A few functions are implemented within the inja template syntax. They can be called with
@@ -315,13 +311,12 @@
 render("Hello{# Todo #}!", data); // "Hello!"
 ```
 
-
 ## Supported compilers
 
 Inja uses `string_view` from C++17, but includes the [polyfill](https://github.com/martinmoene/string-view-lite) from martinmoene. This way, the minimum version is C++11. Currently, the following compilers are tested:
 
-- GCC 4.8 - 9 (and possibly later)
-- Clang 3.5 - 9 (and possibly later)
-- Microsoft Visual C++ 2016 - 2019 (and possibly later)
+  - GCC 4.8 - 9 (and possibly later)
+  - Clang 3.5 - 9 (and possibly later)
+  - Microsoft Visual C++ 2016 - 2019 (and possibly later)
 
 The unit tests fail to compile with GCC 4.8 but should just work fine. A complete list of supported compiler / os versions can be found in the [CI definition](https://github.com/pantor/inja/blob/master/.github/workflows/ci.yml).
diff --git a/include/inja/exceptions.hpp b/include/inja/exceptions.hpp
index c7dfe56..bcb8383 100644
--- a/include/inja/exceptions.hpp
+++ b/include/inja/exceptions.hpp
@@ -17,36 +17,32 @@
   std::string type;
   std::string message;
 
-  bool has_location {false};
   SourceLocation location;
 
-  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) {}
 
-  InjaError(const std::string &type, const std::string &message, SourceLocation location)
+  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), has_location(true), location(location) {}
+        type(type), message(message), location(location) {}
 };
 
 struct ParserError : public InjaError {
-  ParserError(const std::string &message) : InjaError("parser_error", message) {}
-  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 {
-  RenderError(const std::string &message) : InjaError("render_error", message) {}
-  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 {
-  FileError(const std::string &message) : InjaError("file_error", message) {}
-  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 JsonError : public InjaError {
-  JsonError(const std::string &message) : InjaError("json_error", message) {}
-  JsonError(const std::string &message, SourceLocation location) : InjaError("json_error", message, location) {}
+  explicit JsonError(const std::string &message, SourceLocation location) : InjaError("json_error", message, location) {}
 };
 
 } // namespace inja
diff --git a/include/inja/lexer.hpp b/include/inja/lexer.hpp
index d93aafc..2d3145c 100644
--- a/include/inja/lexer.hpp
+++ b/include/inja/lexer.hpp
@@ -37,8 +37,8 @@
 
   const LexerConfig &config;
 
-  State state;
-  MinusState minus_state;
+  State state {State::Text};
+  MinusState minus_state {MinusState::Number};
   nonstd::string_view m_in;
   size_t tok_start;
   size_t pos;
diff --git a/include/inja/node.hpp b/include/inja/node.hpp
index 5851f8b..2beadfd 100644
--- a/include/inja/node.hpp
+++ b/include/inja/node.hpp
@@ -121,9 +121,7 @@
     return result;
   }
 
-  explicit JsonNode(nonstd::string_view ptr_name, size_t pos) : ExpressionNode(pos), name(ptr_name) {
-    ptr = json::json_pointer(convert_dot_to_json_ptr(ptr_name));
-  }
+  explicit JsonNode(nonstd::string_view ptr_name, size_t pos) : ExpressionNode(pos), name(ptr_name), ptr(json::json_pointer(convert_dot_to_json_ptr(ptr_name))) { }
 
   void accept(NodeVisitor& v) const {
     v.visit(*this);
@@ -254,9 +252,9 @@
 public:
   ExpressionListNode condition;
   BlockNode body;
-  BlockNode *parent;
+  BlockNode *const parent;
 
-  ForStatementNode(size_t pos) : StatementNode(pos) { }
+  ForStatementNode(BlockNode *const parent, size_t pos) : StatementNode(pos), parent(parent) { }
 
   virtual void accept(NodeVisitor& v) const = 0;
 };
@@ -265,7 +263,7 @@
 public:
   std::string value;
 
-  explicit ForArrayStatementNode(const std::string& value, size_t pos) : ForStatementNode(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);
@@ -277,7 +275,7 @@
   std::string key;
   std::string value;
 
-  explicit ForObjectStatementNode(const std::string& key, const std::string& value, size_t pos) : ForStatementNode(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);
@@ -289,13 +287,13 @@
   ExpressionListNode condition;
   BlockNode true_statement;
   BlockNode false_statement;
-  BlockNode *parent;
+  BlockNode *const parent;
 
   bool is_nested;
   bool has_false_statement {false};
 
-  explicit IfStatementNode(size_t pos) : StatementNode(pos), is_nested(false) { }
-  explicit IfStatementNode(bool is_nested, size_t pos) : StatementNode(pos), 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);
diff --git a/include/inja/parser.hpp b/include/inja/parser.hpp
index f75c5bd..d676d75 100644
--- a/include/inja/parser.hpp
+++ b/include/inja/parser.hpp
@@ -320,9 +320,8 @@
     if (tok.text == static_cast<decltype(tok.text)>("if")) {
       get_next_token();
 
-      auto if_statement_node = std::make_shared<IfStatementNode>(tok.text.data() - tmpl.content.c_str());
+      auto if_statement_node = std::make_shared<IfStatementNode>(current_block, tok.text.data() - tmpl.content.c_str());
       current_block->nodes.emplace_back(if_statement_node);
-      if_statement_node->parent = current_block;
       if_statement_stack.emplace(if_statement_node.get());
       current_block = &if_statement_node->true_statement;
       current_expression_list = &if_statement_node->condition;
@@ -345,9 +344,8 @@
       if (tok.kind == Token::Kind::Id && tok.text == static_cast<decltype(tok.text)>("if")) {
         get_next_token();
 
-        auto if_statement_node = std::make_shared<IfStatementNode>(true, tok.text.data() - tmpl.content.c_str());
+        auto if_statement_node = std::make_shared<IfStatementNode>(true, current_block, tok.text.data() - tmpl.content.c_str());
         current_block->nodes.emplace_back(if_statement_node);
-        if_statement_node->parent = current_block;
         if_statement_stack.emplace(if_statement_node.get());
         current_block = &if_statement_node->true_statement;
         current_expression_list = &if_statement_node->condition;
@@ -396,15 +394,14 @@
         value_token = tok;
         get_next_token();
 
-        for_statement_node = std::make_shared<ForObjectStatementNode>(static_cast<std::string>(key_token.text), static_cast<std::string>(value_token.text), tok.text.data() - tmpl.content.c_str());
+        for_statement_node = std::make_shared<ForObjectStatementNode>(static_cast<std::string>(key_token.text), static_cast<std::string>(value_token.text), current_block, tok.text.data() - tmpl.content.c_str());
 
       // Array type
       } else {
-        for_statement_node = std::make_shared<ForArrayStatementNode>(static_cast<std::string>(value_token.text), tok.text.data() - tmpl.content.c_str());
+        for_statement_node = std::make_shared<ForArrayStatementNode>(static_cast<std::string>(value_token.text), current_block, tok.text.data() - tmpl.content.c_str());
       }
 
       current_block->nodes.emplace_back(for_statement_node);
-      for_statement_node->parent = current_block;
       for_statement_stack.emplace(for_statement_node.get());
       current_block = &for_statement_node->body;
       current_expression_list = &for_statement_node->condition;
diff --git a/single_include/inja/inja.hpp b/single_include/inja/inja.hpp
index 0b7bb62..dbf1d99 100644
--- a/single_include/inja/inja.hpp
+++ b/single_include/inja/inja.hpp
@@ -1684,36 +1684,32 @@
   std::string type;
   std::string message;
 
-  bool has_location {false};
   SourceLocation location;
 
-  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) {}
 
-  InjaError(const std::string &type, const std::string &message, SourceLocation location)
+  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), has_location(true), location(location) {}
+        type(type), message(message), location(location) {}
 };
 
 struct ParserError : public InjaError {
-  ParserError(const std::string &message) : InjaError("parser_error", message) {}
-  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 {
-  RenderError(const std::string &message) : InjaError("render_error", message) {}
-  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 {
-  FileError(const std::string &message) : InjaError("file_error", message) {}
-  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 JsonError : public InjaError {
-  JsonError(const std::string &message) : InjaError("json_error", message) {}
-  JsonError(const std::string &message, SourceLocation location) : InjaError("json_error", message, location) {}
+  explicit JsonError(const std::string &message, SourceLocation location) : InjaError("json_error", message, location) {}
 };
 
 } // namespace inja
@@ -1914,8 +1910,8 @@
 
   const LexerConfig &config;
 
-  State state;
-  MinusState minus_state;
+  State state {State::Text};
+  MinusState minus_state {MinusState::Number};
   nonstd::string_view m_in;
   size_t tok_start;
   size_t pos;
@@ -2405,9 +2401,7 @@
     return result;
   }
 
-  explicit JsonNode(nonstd::string_view ptr_name, size_t pos) : ExpressionNode(pos), name(ptr_name) {
-    ptr = json::json_pointer(convert_dot_to_json_ptr(ptr_name));
-  }
+  explicit JsonNode(nonstd::string_view ptr_name, size_t pos) : ExpressionNode(pos), name(ptr_name), ptr(json::json_pointer(convert_dot_to_json_ptr(ptr_name))) { }
 
   void accept(NodeVisitor& v) const {
     v.visit(*this);
@@ -2538,9 +2532,9 @@
 public:
   ExpressionListNode condition;
   BlockNode body;
-  BlockNode *parent;
+  BlockNode *const parent;
 
-  ForStatementNode(size_t pos) : StatementNode(pos) { }
+  ForStatementNode(BlockNode *const parent, size_t pos) : StatementNode(pos), parent(parent) { }
 
   virtual void accept(NodeVisitor& v) const = 0;
 };
@@ -2549,7 +2543,7 @@
 public:
   std::string value;
 
-  explicit ForArrayStatementNode(const std::string& value, size_t pos) : ForStatementNode(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);
@@ -2561,7 +2555,7 @@
   std::string key;
   std::string value;
 
-  explicit ForObjectStatementNode(const std::string& key, const std::string& value, size_t pos) : ForStatementNode(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);
@@ -2573,13 +2567,13 @@
   ExpressionListNode condition;
   BlockNode true_statement;
   BlockNode false_statement;
-  BlockNode *parent;
+  BlockNode *const parent;
 
   bool is_nested;
   bool has_false_statement {false};
 
-  explicit IfStatementNode(size_t pos) : StatementNode(pos), is_nested(false) { }
-  explicit IfStatementNode(bool is_nested, size_t pos) : StatementNode(pos), 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);
@@ -3031,9 +3025,8 @@
     if (tok.text == static_cast<decltype(tok.text)>("if")) {
       get_next_token();
 
-      auto if_statement_node = std::make_shared<IfStatementNode>(tok.text.data() - tmpl.content.c_str());
+      auto if_statement_node = std::make_shared<IfStatementNode>(current_block, tok.text.data() - tmpl.content.c_str());
       current_block->nodes.emplace_back(if_statement_node);
-      if_statement_node->parent = current_block;
       if_statement_stack.emplace(if_statement_node.get());
       current_block = &if_statement_node->true_statement;
       current_expression_list = &if_statement_node->condition;
@@ -3056,9 +3049,8 @@
       if (tok.kind == Token::Kind::Id && tok.text == static_cast<decltype(tok.text)>("if")) {
         get_next_token();
 
-        auto if_statement_node = std::make_shared<IfStatementNode>(true, tok.text.data() - tmpl.content.c_str());
+        auto if_statement_node = std::make_shared<IfStatementNode>(true, current_block, tok.text.data() - tmpl.content.c_str());
         current_block->nodes.emplace_back(if_statement_node);
-        if_statement_node->parent = current_block;
         if_statement_stack.emplace(if_statement_node.get());
         current_block = &if_statement_node->true_statement;
         current_expression_list = &if_statement_node->condition;
@@ -3107,15 +3099,14 @@
         value_token = tok;
         get_next_token();
 
-        for_statement_node = std::make_shared<ForObjectStatementNode>(static_cast<std::string>(key_token.text), static_cast<std::string>(value_token.text), tok.text.data() - tmpl.content.c_str());
+        for_statement_node = std::make_shared<ForObjectStatementNode>(static_cast<std::string>(key_token.text), static_cast<std::string>(value_token.text), current_block, tok.text.data() - tmpl.content.c_str());
 
       // Array type
       } else {
-        for_statement_node = std::make_shared<ForArrayStatementNode>(static_cast<std::string>(value_token.text), tok.text.data() - tmpl.content.c_str());
+        for_statement_node = std::make_shared<ForArrayStatementNode>(static_cast<std::string>(value_token.text), current_block, tok.text.data() - tmpl.content.c_str());
       }
 
       current_block->nodes.emplace_back(for_statement_node);
-      for_statement_node->parent = current_block;
       for_statement_stack.emplace(for_statement_node.get());
       current_block = &for_statement_node->body;
       current_expression_list = &for_statement_node->condition;