aboutsummaryrefslogtreecommitdiff
path: root/include/inja/node.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/inja/node.hpp')
-rw-r--r--include/inja/node.hpp328
1 files changed, 328 insertions, 0 deletions
diff --git a/include/inja/node.hpp b/include/inja/node.hpp
new file mode 100644
index 0000000..84a8b8a
--- /dev/null
+++ b/include/inja/node.hpp
@@ -0,0 +1,328 @@
+// Copyright (c) 2020 Pantor. All rights reserved.
+
+#ifndef INCLUDE_INJA_NODE_HPP_
+#define INCLUDE_INJA_NODE_HPP_
+
+#include <string>
+#include <utility>
+
+#include <nlohmann/json.hpp>
+
+#include "function_storage.hpp"
+#include "string_view.hpp"
+
+
+namespace inja {
+
+class NodeVisitor;
+class BlockNode;
+class TextNode;
+class ExpressionNode;
+class LiteralNode;
+class JsonNode;
+class FunctionNode;
+class ExpressionListNode;
+class StatementNode;
+class ForStatementNode;
+class ForArrayStatementNode;
+class ForObjectStatementNode;
+class IfStatementNode;
+class IncludeStatementNode;
+class SetStatementNode;
+
+
+class NodeVisitor {
+public:
+ virtual void visit(const BlockNode& node) = 0;
+ virtual void visit(const TextNode& node) = 0;
+ virtual void visit(const ExpressionNode& node) = 0;
+ virtual void visit(const LiteralNode& node) = 0;
+ virtual void visit(const JsonNode& node) = 0;
+ virtual void visit(const FunctionNode& node) = 0;
+ virtual void visit(const ExpressionListNode& node) = 0;
+ virtual void visit(const StatementNode& node) = 0;
+ virtual void visit(const ForStatementNode& node) = 0;
+ virtual void visit(const ForArrayStatementNode& node) = 0;
+ virtual void visit(const ForObjectStatementNode& node) = 0;
+ virtual void visit(const IfStatementNode& node) = 0;
+ virtual void visit(const IncludeStatementNode& node) = 0;
+ virtual void visit(const SetStatementNode& node) = 0;
+};
+
+/*!
+ * \brief Base node class for the abstract syntax tree (AST).
+ */
+class AstNode {
+public:
+ virtual void accept(NodeVisitor& v) const = 0;
+
+ size_t pos;
+
+ AstNode(size_t pos) : pos(pos) { }
+ virtual ~AstNode() { };
+};
+
+
+class BlockNode : public AstNode {
+public:
+ std::vector<std::shared_ptr<AstNode>> nodes;
+
+ explicit BlockNode() : AstNode(0) {}
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ }
+};
+
+class TextNode : public AstNode {
+public:
+ const size_t length;
+
+ explicit TextNode(size_t pos, size_t length): AstNode(pos), length(length) { }
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ }
+};
+
+class ExpressionNode : public AstNode {
+public:
+ explicit ExpressionNode(size_t pos) : AstNode(pos) {}
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ }
+};
+
+class LiteralNode : public ExpressionNode {
+public:
+ const nlohmann::json value;
+
+ explicit LiteralNode(const nlohmann::json& value, size_t pos) : ExpressionNode(pos), value(value) { }
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ }
+};
+
+class JsonNode : public ExpressionNode {
+public:
+ const std::string name;
+ const json::json_pointer ptr;
+
+ static std::string convert_dot_to_json_ptr(nonstd::string_view ptr_name) {
+ std::string result;
+ do {
+ nonstd::string_view part;
+ std::tie(part, ptr_name) = string_view::split(ptr_name, '.');
+ result.push_back('/');
+ result.append(part.begin(), part.end());
+ } while (!ptr_name.empty());
+ 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))) { }
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ }
+};
+
+class FunctionNode : public ExpressionNode {
+ using Op = FunctionStorage::Operation;
+
+public:
+ enum class Associativity {
+ Left,
+ Right,
+ };
+
+ unsigned int precedence;
+ Associativity associativity;
+
+ Op operation;
+
+ std::string name;
+ int number_args; // Should also be negative -> -1 for unknown number
+ CallbackFunction callback;
+
+ explicit FunctionNode(nonstd::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: {
+ precedence = 4;
+ associativity = Associativity::Left;
+ } break;
+ case Op::And: {
+ precedence = 1;
+ associativity = Associativity::Left;
+ } break;
+ case Op::Or: {
+ precedence = 1;
+ associativity = Associativity::Left;
+ } break;
+ case Op::In: {
+ precedence = 2;
+ associativity = Associativity::Left;
+ } break;
+ case Op::Equal: {
+ precedence = 2;
+ associativity = Associativity::Left;
+ } break;
+ case Op::NotEqual: {
+ precedence = 2;
+ associativity = Associativity::Left;
+ } break;
+ case Op::Greater: {
+ precedence = 2;
+ associativity = Associativity::Left;
+ } break;
+ case Op::GreaterEqual: {
+ precedence = 2;
+ associativity = Associativity::Left;
+ } break;
+ case Op::Less: {
+ precedence = 2;
+ associativity = Associativity::Left;
+ } break;
+ case Op::LessEqual: {
+ precedence = 2;
+ associativity = Associativity::Left;
+ } break;
+ case Op::Add: {
+ precedence = 3;
+ associativity = Associativity::Left;
+ } break;
+ case Op::Subtract: {
+ precedence = 3;
+ associativity = Associativity::Left;
+ } break;
+ case Op::Multiplication: {
+ precedence = 4;
+ associativity = Associativity::Left;
+ } break;
+ case Op::Division: {
+ precedence = 4;
+ associativity = Associativity::Left;
+ } break;
+ case Op::Power: {
+ precedence = 5;
+ associativity = Associativity::Right;
+ } break;
+ case Op::Modulo: {
+ precedence = 4;
+ associativity = Associativity::Left;
+ } break;
+ case Op::AtId: {
+ precedence = 8;
+ associativity = Associativity::Left;
+ } break;
+ default: {
+ precedence = 1;
+ associativity = Associativity::Left;
+ }
+ }
+ }
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ }
+};
+
+class ExpressionListNode : public AstNode {
+public:
+ std::vector<std::shared_ptr<ExpressionNode>> rpn_output;
+
+ explicit ExpressionListNode() : AstNode(0) { }
+ explicit ExpressionListNode(size_t pos) : AstNode(pos) { }
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ }
+};
+
+class StatementNode : public AstNode {
+public:
+ StatementNode(size_t pos) : AstNode(pos) { }
+
+ virtual void accept(NodeVisitor& v) const = 0;
+};
+
+class ForStatementNode : public StatementNode {
+public:
+ ExpressionListNode condition;
+ BlockNode body;
+ BlockNode *const parent;
+
+ ForStatementNode(BlockNode *const parent, size_t pos) : StatementNode(pos), parent(parent) { }
+
+ virtual void accept(NodeVisitor& v) const = 0;
+};
+
+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) { }
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ }
+};
+
+class ForObjectStatementNode : public ForStatementNode {
+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) { }
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ }
+};
+
+class IfStatementNode : public StatementNode {
+public:
+ ExpressionListNode condition;
+ BlockNode true_statement;
+ BlockNode false_statement;
+ 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) { }
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ }
+};
+
+class IncludeStatementNode : public StatementNode {
+public:
+ const std::string file;
+
+ explicit IncludeStatementNode(const std::string& file, size_t pos) : StatementNode(pos), file(file) { }
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ };
+};
+
+class SetStatementNode : public StatementNode {
+public:
+ const std::string key;
+ ExpressionListNode expression;
+
+ explicit SetStatementNode(const std::string& key, size_t pos) : StatementNode(pos), key(key) { }
+
+ void accept(NodeVisitor& v) const {
+ v.visit(*this);
+ };
+};
+
+} // namespace inja
+
+#endif // INCLUDE_INJA_NODE_HPP_