expression nodes finished

This commit is contained in:
ProgramSnail 2023-07-18 16:45:35 +03:00
parent 100779d2d4
commit 4276a966a7
10 changed files with 842 additions and 137 deletions

@ -1 +1 @@
Subproject commit befa2f03954304d5812f9117a11fd47b02a4fd28
Subproject commit 3b4be40ef780faef07580545e9468dafedada79b

BIN
include/.utils.hpp.kate-swp Normal file

Binary file not shown.

81
include/basic_nodes.hpp Normal file
View file

@ -0,0 +1,81 @@
#pragma once
#include <optional>
#include <string>
#include <utility>
#include <variant>
namespace nodes {
class Node {
public:
Node(std::pair<size_t, size_t> start_position,
std::pair<size_t, size_t> end_position)
: start_position_(start_position), end_position_(end_position) {}
std::pair<size_t, size_t> get_start_position() { return start_position_; }
std::pair<size_t, size_t> get_end_position() { return end_position_; }
protected:
std::pair<size_t, size_t> start_position_;
std::pair<size_t, size_t> end_position_;
};
struct unit {};
struct null {};
class Literal : public Node {
public:
template <typename T>
Literal(Node node, T &&value) : Node(node), value_(std::forward<T>(value)) {}
template <typename T> std::optional<T *> get() {
if (std::holds_alternative<T>(value_)) {
return &std::get<T>(value_);
}
return std::nullopt;
}
template <typename T> std::optional<const T *> get() const {
if (std::holds_alternative<T>(value_)) {
return &std::get<T>(value_);
}
return std::nullopt;
}
private:
std::variant<double, long long, std::string, char, bool, unit, null> value_;
};
class Identifier : public Node {
public:
enum IdentifierType {
SIMPLE_NAME,
SIMPLE_TYPE,
TYPECLASS,
ARGUMENT_NAME,
ARGUMENT_TYPE,
// ANNOTATION, used as std::string
OPERATOR,
PLACEHOLDER,
};
Identifier(Node node, IdentifierType type, std::string &&value)
: Node(node), type_(type), value_(std::move(value)) {}
Identifier(Node node, IdentifierType type, const std::string &value)
: Node(node), type_(type), value_(value) {}
IdentifierType get_type() { return type_; }
std::string *get() { return &value_; }
const std::string *get() const { return &value_; }
private:
IdentifierType type_;
std::string value_;
};
} // namespace nodes

View file

@ -14,7 +14,7 @@ public:
SymbolDocs(const std::string &description) : description_(description) {}
template <typename T>
bool set_annotation_info(const std::string &annotation, T &&info) {
bool add_annotation_info(const std::string &annotation, T &&info) {
if (annotations_info_.count(annotation) == 0) {
annotations_info_[annotation] = std::forward<T>(info);
return true;

View file

@ -0,0 +1,573 @@
#pragma once
#include "basic_nodes.hpp"
#include "type_nodes.hpp"
#include <optional>
#include <variant>
#include <vector>
namespace nodes {
class Expression;
class ExpressionStorage;
class ExpressionProxy {
public:
ExpressionProxy(ExpressionStorage &expression_storage, size_t id)
: expression_storage_(expression_storage), id_(id) {}
Expression *get();
const Expression *get() const;
private:
ExpressionStorage &expression_storage_;
size_t id_;
};
namespace utils {
inline std::optional<nodes::Expression *>
proxy_to_expr_optional(std::optional<nodes::ExpressionProxy> &proxy) {
if (proxy.has_value()) {
return proxy.value().get();
}
return std::nullopt;
}
inline std::optional<const nodes::Expression *>
proxy_to_expr_optional(const std::optional<nodes::ExpressionProxy> &proxy) {
if (proxy.has_value()) {
return proxy.value().get();
}
return std::nullopt;
}
} // namespace utils
// --- flow control
class Match : public Node {
public:
class Case : public Node {
public:
Case(Node node, bool match_left_with_right, ExpressionProxy value,
std::optional<ExpressionProxy> condition = std::nullopt,
std::optional<ExpressionProxy> expression = std::nullopt)
: Node(node), match_left_with_right_(match_left_with_right),
value_(value), condition_(condition), expression_(expression) {}
bool match_left_with_right() const { return match_left_with_right_; }
Expression *get_value() { return value_.get(); }
const Expression *get_value() const { return value_.get(); }
std::optional<Expression *> get_condition() {
return utils::proxy_to_expr_optional(condition_);
}
std::optional<const Expression *> get_condition() const {
return utils::proxy_to_expr_optional(condition_);
}
std::optional<Expression *> get_expression() {
return utils::proxy_to_expr_optional(expression_);
}
std::optional<const Expression *> get_expression() const {
return utils::proxy_to_expr_optional(expression_);
}
private:
bool match_left_with_right_;
ExpressionProxy value_;
std::optional<ExpressionProxy> condition_;
std::optional<ExpressionProxy> expression_;
};
Match(Node node, ExpressionProxy value, std::vector<Case> &&cases)
: Node(node), value_(value), cases_(std::move(cases)) {}
Match(Node node, ExpressionProxy value, const std::vector<Case> &cases)
: Node(node), value_(value), cases_(cases) {}
Expression *get_value() { return value_.get(); }
const Expression *get_value() const { return value_.get(); }
size_t cases_size() const { return cases_.size(); }
Case *get_case(size_t id) { return &cases_.at(id); }
const Case *get_case(size_t id) const { return &cases_.at(id); }
private:
ExpressionProxy value_;
std::vector<Case> cases_;
};
class Condition : public Node {
public:
Condition(Node node,
std::vector<std::pair<ExpressionProxy, ExpressionProxy>> &&cases,
std::optional<ExpressionProxy> else_case = std::nullopt)
: Node(node), cases_(std::move(cases)), else_case_(else_case) {}
Condition(
Node node,
const std::vector<std::pair<ExpressionProxy, ExpressionProxy>> &cases,
std::optional<ExpressionProxy> else_case = std::nullopt)
: Node(node), cases_(cases), else_case_(else_case) {}
size_t cases_size() const { return cases_.size(); }
std::pair<Expression *, Expression *> get_case(size_t id) {
return {cases_.at(id).first.get(), cases_[id].second.get()};
}
std::pair<const Expression *, const Expression *> get_case(size_t id) const {
return {cases_.at(id).first.get(), cases_[id].second.get()};
}
std::optional<Expression *> get_else_case() {
return utils::proxy_to_expr_optional(else_case_);
}
std::optional<const Expression *> get_else_case() const {
return utils::proxy_to_expr_optional(else_case_);
}
private:
std::vector<std::pair<ExpressionProxy, ExpressionProxy>> cases_;
std::optional<ExpressionProxy> else_case_;
};
class Loop : public Node {
public:
enum LoopType {
LOOP,
WHILE,
FOR,
};
// LOOP
Loop(Node node, ExpressionProxy expression)
: Node(node), type_(LOOP), expression_(expression) {}
// WHILE
Loop(Node node, ExpressionProxy expression, ExpressionProxy condition)
: Node(node), type_(WHILE), expression_(expression),
condition_(condition) {}
// FOR
Loop(Node node, ExpressionProxy expression, ExpressionProxy variable,
ExpressionProxy interval)
: Node(node), type_(FOR), expression_(expression), variable_(variable),
interval_(interval) {}
LoopType get_type() { return type_; }
Expression *get_expression() { return expression_.get(); }
const Expression *get_expression() const { return expression_.get(); }
std::optional<Expression *> get_condition() {
return utils::proxy_to_expr_optional(condition_);
}
std::optional<const Expression *> get_condition() const {
return utils::proxy_to_expr_optional(condition_);
}
std::optional<Expression *> get_variable() {
return utils::proxy_to_expr_optional(variable_);
}
std::optional<const Expression *> get_variable() const {
return utils::proxy_to_expr_optional(variable_);
}
std::optional<Expression *> get_interval() {
return utils::proxy_to_expr_optional(interval_);
}
std::optional<const Expression *> get_interval() const {
return utils::proxy_to_expr_optional(interval_);
}
private:
LoopType type_;
ExpressionProxy expression_;
std::optional<ExpressionProxy> condition_;
std::optional<ExpressionProxy> variable_;
std::optional<ExpressionProxy> interval_;
};
// --- containers
class Container : public Node {
public:
enum ContainerType {
BLOCK,
ARRAY,
};
Container(Node node, ContainerType type,
std::vector<ExpressionProxy> &&expressions)
: Node(node), type_(type), expressions_(std::move(expressions)) {}
Container(Node node, ContainerType type,
const std::vector<ExpressionProxy> &expressions)
: Node(node), type_(type), expressions_(expressions) {}
ContainerType get_type() { return type_; }
size_t expressions_size() const { return expressions_.size(); }
Expression *get_expression(size_t id) { return expressions_.at(id).get(); }
const Expression *get_expression(size_t id) const {
return expressions_.at(id).get();
}
private:
ContainerType type_;
std::vector<ExpressionProxy> expressions_;
};
// --- modifiers
class Return : public Node {
public:
enum ReturnType {
RETURN,
BRING,
};
Return(Node node, ReturnType type, ExpressionProxy expression)
: Node(node), type_(type), expression_(expression) {}
ReturnType get_type() { return type_; }
Expression *get_expression() { return expression_.get(); }
const Expression *get_expression() const { return expression_.get(); }
private:
ReturnType type_;
ExpressionProxy expression_;
};
class NameDefinition : public Node {
public:
enum Modifier {
LET, // %
VAR, // $
};
NameDefinition(Node node, Modifier modifier, Identifier &&name)
: Node(node), modifier_(modifier), name_(std::move(name)) {}
NameDefinition(Node node, Modifier modifier, const Identifier &name)
: Node(node), modifier_(modifier), name_(name) {}
Modifier get_modifier() { return modifier_; }
std::string *get_name() { return name_.get(); }
const std::string *get_name() const { return name_.get(); }
private:
Modifier modifier_;
Identifier name_;
};
class Access : public Node {
public:
enum AccessType {
ARRAY,
TUPLE, // only number literal index allowed
};
Access(Node node, AccessType type, ExpressionProxy value,
ExpressionProxy index)
: Node(node), type_(type), value_(value), index_(index) {}
AccessType get_type() { return type_; }
Expression *get_value() { return value_.get(); }
const Expression *get_value() const { return value_.get(); }
Expression *get_index() { return index_.get(); }
const Expression *get_index() const { return index_.get(); }
private:
AccessType type_;
ExpressionProxy value_;
ExpressionProxy index_;
};
class LoopControl : public Node {
public:
enum LoopControlType {
BREAK,
CONTINUE,
};
LoopControl(Node node, LoopControlType type) : Node(node), type_(type) {}
LoopControlType get_type() { return type_; }
private:
LoopControlType type_;
};
class ModifierExpression : public Node {
public:
enum Modifier {
REFERENCE, // <> x
MOVE, // <- x
IF_VALUE, // x?
VALUE_OR_PANIC, // x!
};
ModifierExpression(Node node, Modifier modifier, ExpressionProxy expression)
: Node(node), modifier_(modifier), expression_(expression) {}
Modifier get_modifier() { return modifier_; }
Expression *get_expression() { return expression_.get(); }
const Expression *get_expression() const { return expression_.get(); }
private:
Modifier modifier_;
ExpressionProxy expression_;
};
// --- other
class NameExpression : public Node {
public:
template <typename T, typename U, typename V>
NameExpression(Node node, T &&name, U &&arguments = {},
V &&prefix = std::nullopt, bool is_point_call = false)
: Node(node), name_(std::forward<T>(name)),
arguments_(std::forward<U>(arguments)),
prefix_(std::forward<V>(prefix)), is_point_call_(is_point_call) {}
std::string *get_name() { return name_.get(); }
const std::string *get_name() const { return name_.get(); }
std::optional<std::pair<std::string *, std::string *>> get_prefix() {
if (prefix_.has_value()) {
return std::pair<std::string *, std::string *>{
prefix_.value().first.get(), prefix_.value().second.get()};
}
return std::nullopt;
}
std::optional<std::pair<const std::string *, const std::string *>>
get_prefix() const {
if (prefix_.has_value()) {
return std::pair<const std::string *, const std::string *>{
prefix_.value().first.get(), prefix_.value().second.get()};
}
return std::nullopt;
}
size_t arguments_size() const { return arguments_.size(); }
Expression *get_argument_value(size_t id) {
return arguments_.at(id).second.get();
}
const Expression *get_argument_value(size_t id) const {
return arguments_.at(id).second.get();
}
std::optional<std::string *> get_argument_annotation(size_t id) {
if (arguments_.at(id).first.has_value()) {
return &arguments_[id].first.value();
}
return std::nullopt;
}
std::optional<const std::string *> get_argument_annotation(size_t id) const {
if (arguments_.at(id).first.has_value()) {
return &arguments_[id].first.value();
}
return std::nullopt;
}
bool is_point_call() { return is_point_call_; }
private:
Identifier name_;
std::vector<std::pair<std::optional<std::string>, ExpressionProxy>>
arguments_;
// universal function call syntax
std::optional<std::pair<Identifier, Identifier>> prefix_;
// for static methods
bool is_point_call_ = false; // x.f ... or f x ...
};
// explicit instantiation
template NameExpression::NameExpression(
Node, Identifier &&,
std::vector<std::pair<std::optional<std::string>, ExpressionProxy>> &&,
std::optional<std::pair<Identifier, Identifier>> &&, bool);
class Constructor : public Node {
public:
Constructor(
Node node, TypeProxy type,
std::vector<std::pair<std::optional<std::string>, ExpressionProxy>>
&&arguments)
: Node(node), type_(type), arguments_(std::move(arguments)) {}
Constructor(
Node node, TypeProxy type,
const std::vector<std::pair<std::optional<std::string>, ExpressionProxy>>
&arguments)
: Node(node), type_(type), arguments_(arguments) {}
Type *get_type() { return type_.get(); }
const Type *get_type() const { return type_.get(); }
size_t arguments_size() const { return arguments_.size(); }
Expression *get_argument_value(size_t id) {
return arguments_.at(id).second.get();
}
const Expression *get_argument_value(size_t id) const {
return arguments_.at(id).second.get();
}
std::optional<std::string *> get_argument_annotation(size_t id) {
if (arguments_.at(id).first.has_value()) {
return &arguments_[id].first.value();
}
return std::nullopt;
}
std::optional<const std::string *> get_argument_annotation(size_t id) const {
if (arguments_.at(id).first.has_value()) {
return &arguments_[id].first.value();
}
return std::nullopt;
}
private:
TypeProxy type_;
std::vector<std::pair<std::optional<std::string>, ExpressionProxy>>
arguments_;
};
class Lambda : public Node {
public:
Lambda(Node node, std::vector<Identifier> &&arguments,
ExpressionProxy expression)
: Node(node), arguments_(std::move(arguments)), expression_(expression) {}
Lambda(Node node, const std::vector<Identifier> &arguments,
ExpressionProxy expression)
: Node(node), arguments_(arguments), expression_(expression) {}
size_t arguments_size() const { return arguments_.size(); }
Identifier *get_argument(size_t id) { return &arguments_.at(id); }
const Identifier *get_argument(size_t id) const { return &arguments_.at(id); }
Expression *get_expression() { return expression_.get(); }
const Expression *get_expression() const { return expression_.get(); }
private:
std::vector<Identifier> arguments_;
ExpressionProxy expression_;
};
class Expression {
public:
template <typename T>
Expression(T &&expression) : expression_(std::forward<T>(expression)) {}
template <typename T> std::optional<T *> get() {
if (std::holds_alternative<T>(expression_)) {
return &std::get<T>(expression_);
}
return std::nullopt;
}
template <typename T> std::optional<const T *> get() const {
if (std::holds_alternative<T>(expression_)) {
return &std::get<T>(expression_);
}
return std::nullopt;
}
private:
std::variant<
// --- flow control
Match, Condition, Loop,
// --- operators
// CommaExpression is OperatorExpression for operator ','
// OperatorExpression is NameExpression with two arguments
// --- containers
// Block value is brought value ("bring x")
// Array value is array of expression's values
Container,
// --- modifiers
Return, NameDefinition,
// TupleAccess - Access with nmber Literal index
Access, LoopControl,
// Reference or SuffixExpression is ModifierExpression
ModifierExpression,
// --- other
NameExpression, Constructor, Lambda
>
expression_;
};
class ExpressionStorage {
friend ExpressionProxy;
public:
ExpressionProxy add_expression(const Expression &type) {
storage_.push_back(type);
return ExpressionProxy(*this, storage_.size() - 1);
}
ExpressionProxy add_expression(Expression &&type) {
storage_.push_back(std::move(type));
return ExpressionProxy(*this, storage_.size() - 1);
}
private:
Expression *get_expression(size_t id) { return &storage_.at(id); }
const Expression *get_expression(size_t id) const { return &storage_.at(id); }
private:
std::vector<Expression> storage_;
};
} // namespace nodes

View file

@ -1,135 +0,0 @@
#pragma once
#include <memory>
#include <optional>
#include <string>
#include <variant>
#include <vector>
namespace file {
// DEBUG: using T = long long;
class Node {
public:
Node(std::pair<size_t, size_t> start_position,
std::pair<size_t, size_t> end_position)
: start_position_(start_position), end_position_(end_position) {}
std::pair<size_t, size_t> get_start_position() { return start_position_; }
std::pair<size_t, size_t> get_end_position() { return end_position_; }
protected:
std::pair<size_t, size_t> start_position_;
std::pair<size_t, size_t> end_position_;
};
struct unit {};
struct null {};
class Literal : public Node {
public:
template <typename T>
Literal(Node node, T &&value) : Node(node), value_(std::forward<T>(value)) {}
template <typename T> std::optional<T *> get() {
if (std::holds_alternative<T>(value_)) {
return &std::get<T>(value_);
}
return std::nullopt;
}
template <typename T> std::optional<const T *> get() const {
if (std::holds_alternative<T>(value_)) {
return &std::get<T>(value_);
}
return std::nullopt;
}
private:
std::variant<double, long long, std::string, char, bool, unit, null> value_;
};
class Identifier : public Node {
public:
enum IdentifierType {
SIMPLE_NAME,
SIMPLE_TYPE,
TYPECLASS,
ARGUMENT_NAME,
ARGUMENT_TYPE,
ANNOTATION,
OPERATOR,
PLACEHOLDER,
};
Identifier(Node node, IdentifierType type, std::string &&value)
: Node(node), type_(type), value_(std::move(value)) {}
Identifier(Node node, IdentifierType type, const std::string &value)
: Node(node), type_(type), value_(value) {}
IdentifierType get_type() { return type_; }
std::string *get() { return &value_; }
const std::string *get() const { return &value_; }
private:
IdentifierType type_;
std::string value_;
};
class Type : public Node {
public:
Type(Node node, Identifier &&identifier, bool is_on_heap = false,
bool is_optional = false)
: Node(node), name_(std::move(identifier)), is_on_heap_(is_on_heap),
is_optional_(is_optional) {}
Type(Node node, const Identifier &identifier, bool is_on_heap = false,
bool is_optional = false)
: Node(node), name_(identifier), is_on_heap_(is_on_heap),
is_optional_(is_optional) {}
Type(Node node, Identifier &&identifier,
std::vector<std::unique_ptr<Type>> &&parameters, bool is_on_heap = false,
bool is_optional = false)
: Node(node), name_(std::move(identifier)),
parameters_(std::move(parameters)), is_on_heap_(is_on_heap),
is_optional_(is_optional) {}
Type(Node node, const Identifier &identifier,
std::vector<std::unique_ptr<Type>> &&parameters, bool is_on_heap = false,
bool is_optional = false)
: Node(node), name_(identifier), parameters_(std::move(parameters)),
is_on_heap_(is_on_heap), is_optional_(is_optional) {}
std::string *get_name() { return name_.get(); }
const std::string *get_name() const { return name_.get(); }
size_t get_parametrs_size() { return parameters_.size(); }
Type *get_parameter(size_t id) { return parameters_.at(id).get(); }
const Type *get_parameter(size_t id) const {
return parameters_.at(id).get();
}
bool is_on_heap() { return is_on_heap_; }
bool is_optional() { return is_optional_; }
private:
Identifier name_;
std::vector<std::unique_ptr<Type>> parameters_;
// or use allocator ??
bool is_on_heap_ = false;
bool is_optional_ = false;
};
// IN PROGRESS
} // namespace file

155
include/type_nodes.hpp Normal file
View file

@ -0,0 +1,155 @@
#pragma once
#include "basic_nodes.hpp"
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>
namespace nodes {
class Type;
class TypeStorage;
class TypeProxy {
public:
TypeProxy(TypeStorage &type_storage, size_t id)
: type_storage_(type_storage), id_(id) {}
Type *get();
const Type *get() const;
private:
TypeStorage &type_storage_;
size_t id_;
};
class Type : public Node {
public:
Type(Node node, Identifier &&identifier, bool is_on_heap = false,
bool is_optional = false)
: Node(node), name_(std::move(identifier)), is_on_heap_(is_on_heap),
is_optional_(is_optional) {}
Type(Node node, const Identifier &identifier, bool is_on_heap = false,
bool is_optional = false)
: Node(node), name_(identifier), is_on_heap_(is_on_heap),
is_optional_(is_optional) {}
Type(Node node, Identifier &&identifier, std::vector<TypeProxy> &&parameters,
bool is_on_heap = false, bool is_optional = false)
: Node(node), name_(std::move(identifier)),
parameters_(std::move(parameters)), is_on_heap_(is_on_heap),
is_optional_(is_optional) {}
Type(Node node, const Identifier &identifier,
std::vector<TypeProxy> &&parameters, bool is_on_heap = false,
bool is_optional = false)
: Node(node), name_(identifier), parameters_(std::move(parameters)),
is_on_heap_(is_on_heap), is_optional_(is_optional) {}
std::string *get_name() { return name_.get(); }
const std::string *get_name() const { return name_.get(); }
size_t get_parametrs_size() { return parameters_.size(); }
Type *get_parameter(size_t id) { return parameters_.at(id).get(); }
const Type *get_parameter(size_t id) const {
return parameters_.at(id).get();
}
bool is_on_heap() { return is_on_heap_; }
bool is_optional() { return is_optional_; }
private:
Identifier name_;
std::vector<TypeProxy> parameters_;
// or use allocator ??
bool is_on_heap_ = false;
bool is_optional_ = false;
};
class TypeStorage {
friend TypeProxy;
public:
TypeProxy add_type(const Type &type) {
storage_.push_back(type);
return TypeProxy(*this, storage_.size() - 1);
}
TypeProxy add_type(Type &&type) {
storage_.push_back(std::move(type));
return TypeProxy(*this, storage_.size() - 1);
}
private:
Type *get_type(size_t id) { return &storage_.at(id); }
const Type *get_type(size_t id) const { return &storage_.at(id); }
private:
std::vector<Type> storage_;
};
class TupleType : public Node {
public:
TupleType(Node node,
const std::vector<std::pair<std::optional<std::string>, TypeProxy>>
&fields)
: Node(node) {
fields_.reserve(fields.size());
for (auto &field : fields) {
if (field.first.has_value()) {
annotation_ids_[field.first.value()] = fields_.size();
}
fields_.push_back(field.second);
}
}
size_t size() { return fields_.size(); }
Type *get(size_t id) { return fields_.at(id).get(); }
const Type *get(size_t id) const { return fields_.at(id).get(); }
Type *get(const std::string &annotation) {
return fields_.at(annotation_ids_.at(annotation)).get();
}
const Type *get(const std::string &annotation) const {
return fields_.at(annotation_ids_.at(annotation)).get();
}
private:
std::unordered_map<std::string, size_t> annotation_ids_; // Annotations
std::vector<TypeProxy> fields_;
};
class VariantType : public Node {
public:
VariantType(Node node, std::vector<TupleType> &&constructors_)
: Node(node), constructors_(std::move(constructors_)) {}
VariantType(Node node, const std::vector<TupleType> &constructors_)
: Node(node), constructors_(constructors_) {}
size_t size() { return constructors_.size(); }
TupleType *get(size_t id) { return &constructors_.at(id); }
const TupleType *get(size_t id) const { return &constructors_.at(id); }
private:
// named constructors ??
std::vector<TupleType> constructors_;
};
} // namespace nodes

5
include/utils.hpp Normal file
View file

@ -0,0 +1,5 @@
#pragma once
namespace utils {
optional
} // namespace utils

13
src/expression_nodes.cpp Normal file
View file

@ -0,0 +1,13 @@
#include "../include/expression_nodes.hpp"
namespace nodes {
Expression* ExpressionProxy::get() {
return expression_storage_.get_expression(id_);
}
const Expression* ExpressionProxy::get() const {
return expression_storage_.get_expression(id_);
}
}; // namespace nodes

13
src/type_nodes.cpp Normal file
View file

@ -0,0 +1,13 @@
#include "../include/type_nodes.hpp"
namespace nodes {
Type* TypeProxy::get() {
return type_storage_.get_type(id_);
}
const Type* TypeProxy::get() const {
return type_storage_.get_type(id_);
}
}; // namespace nodes