blob: 84a8b8a0595aad3f62418f13b2140b7cceb67c82 [file] [log] [blame]
// 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_