mirror of
https://codeberg.org/ProgramSnail/lang_2023.git
synced 2026-01-25 13:07:13 +00:00
Merge pull request 'v0.0.1' (#1) from dev into main
Reviewed-on: https://codeberg.org/ProgramSnail/lang-interpreter/pulls/1
This commit is contained in:
commit
e3d1a758df
64 changed files with 14500 additions and 0 deletions
18
.clang_tidy
Normal file
18
.clang_tidy
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
Checks: "*,
|
||||||
|
-abseil-*,
|
||||||
|
-altera-*,
|
||||||
|
-android-*,
|
||||||
|
-fuchsia-*,
|
||||||
|
-google-*,
|
||||||
|
-llvm*,
|
||||||
|
-modernize-use-trailing-return-type,
|
||||||
|
-zircon-*,
|
||||||
|
-readability-else-after-return,
|
||||||
|
-readability-static-accessed-through-instance,
|
||||||
|
-readability-avoid-const-params-in-decls,
|
||||||
|
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||||
|
-misc-non-private-member-variables-in-classes,
|
||||||
|
"
|
||||||
|
WarningsAsErrors: ''
|
||||||
|
HeaderFilterRegex: ''
|
||||||
|
FormatStyle: none
|
||||||
2
.clangd
Normal file
2
.clangd
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
CompileFlags:
|
||||||
|
Add: [-std=c++17]
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -11,3 +11,9 @@ compile_commands.json
|
||||||
CTestTestfile.cmake
|
CTestTestfile.cmake
|
||||||
_deps
|
_deps
|
||||||
|
|
||||||
|
|
||||||
|
build
|
||||||
|
build_make
|
||||||
|
cmake-build-debug
|
||||||
|
|
||||||
|
.idea
|
||||||
|
|
|
||||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[submodule "lang-parser"]
|
||||||
|
path = lang-parser
|
||||||
|
url = https://codeberg.org/ProgramSnail/lang-parser.git
|
||||||
|
[submodule "tree-sitter"]
|
||||||
|
path = tree-sitter
|
||||||
|
url = https://github.com/tree-sitter/tree-sitter.git
|
||||||
35
CMakeLists.txt
Normal file
35
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
project(LangInterpreter)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
# find_package(Catch2 2 REQUIRED)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
|
||||||
|
|
||||||
|
include_directories(include
|
||||||
|
tree-sitter/lib/src
|
||||||
|
tree-sitter/lib/include)
|
||||||
|
|
||||||
|
|
||||||
|
# add_executable(interpreter_tests tests/tests.cpp)
|
||||||
|
# target_link_libraries(tests PRIVATE Catch2::Catch2WithMain)
|
||||||
|
|
||||||
|
add_executable(lang_interpreter src/main.cpp
|
||||||
|
src/types.cpp
|
||||||
|
src/values.cpp
|
||||||
|
src/utils.cpp
|
||||||
|
src/global_info.cpp
|
||||||
|
src/typeclass_graph.cpp
|
||||||
|
src/visitor.cpp
|
||||||
|
src/build_visitor.cpp
|
||||||
|
src/print_visitor.cpp
|
||||||
|
src/find_symbols_visitor.cpp
|
||||||
|
src/link_symbols_visitor.cpp
|
||||||
|
src/type_check_visitor.cpp
|
||||||
|
src/typed_print_visitor.cpp
|
||||||
|
src/execute_visitor.cpp
|
||||||
|
lang-parser/src/parser.c
|
||||||
|
lang-parser/src/tree_sitter/parser.h
|
||||||
|
tree-sitter/lib/src/lib.c)
|
||||||
|
|
@ -1,2 +1,9 @@
|
||||||
# lang-interpreter
|
# lang-interpreter
|
||||||
|
|
||||||
|
Build steps:
|
||||||
|
|
||||||
|
- clone submodules
|
||||||
|
- cd lang-parser/ && tree-sitter generate
|
||||||
|
- mkdir build && cd build/ && cmake .. && make
|
||||||
|
|
||||||
|
**lang_interpreter** is interpreter
|
||||||
|
|
|
||||||
73
archived/abstract_types_contexts.hpp
Normal file
73
archived/abstract_types_contexts.hpp
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
namespace info {
|
||||||
|
|
||||||
|
class AbstractTypesContextManager {
|
||||||
|
public:
|
||||||
|
void EnterContext() {
|
||||||
|
contexts_.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExitContext() {
|
||||||
|
if (contexts_.empty()) {
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
|
||||||
|
contexts_.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExitFromAllContexts() {
|
||||||
|
contexts_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefineType(const std::string& type, utils::IdType id) {
|
||||||
|
return contexts_.back().DefineType(type, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetTypeId(const std::string& type) {
|
||||||
|
for (ssize_t i = contexts_.size() - 1; i >= 0; --i) {
|
||||||
|
auto maybe_type = contexts_[i].GetTypeId(type);
|
||||||
|
if (maybe_type.has_value()) {
|
||||||
|
return maybe_type.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Context {
|
||||||
|
public:
|
||||||
|
bool DefineType(const std::string& type, utils::IdType id) {
|
||||||
|
if (types_.count(type) > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
types_[type] = id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetTypeId(const std::string& type) {
|
||||||
|
auto type_iter = types_.find(type);
|
||||||
|
|
||||||
|
if (type_iter == types_.end()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, utils::IdType> types_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Context> contexts_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace info
|
||||||
118
archived/symbols_info.hpp
Normal file
118
archived/symbols_info.hpp
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
class Node;
|
||||||
|
} // namespace interpreter
|
||||||
|
|
||||||
|
namespace info {
|
||||||
|
|
||||||
|
struct VariantTypeInfo;
|
||||||
|
struct TupleTypeInfo;
|
||||||
|
struct AliasTypeInfo;
|
||||||
|
|
||||||
|
struct TypeInfo;
|
||||||
|
|
||||||
|
struct TypeclassInfo;
|
||||||
|
|
||||||
|
enum class BuiltInTypeInfo {
|
||||||
|
StringT,
|
||||||
|
IntT,
|
||||||
|
FloatT,
|
||||||
|
UnitT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeUsageInfo {
|
||||||
|
interpreter::tokens::TypeExpression* node;
|
||||||
|
TypeInfo* info = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ParameterInfo {
|
||||||
|
std::string type;
|
||||||
|
std::vector<interpreter::tokens::TypeclassExpression*> typeclass_nodes;
|
||||||
|
std::vector<TypeclassInfo*> typeclass_types;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AbstractTypeInfo {
|
||||||
|
enum { Basic, Abstract } modifier;
|
||||||
|
ParameterInfo type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AliasTypeInfo {
|
||||||
|
enum {Alias, Type, Let} modifier;
|
||||||
|
std::vector<std::string> parameters;
|
||||||
|
TypeUsageInfo value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnyTypeInfo {
|
||||||
|
ParameterInfo type;
|
||||||
|
std::vector<ParameterInfo> parameters;
|
||||||
|
interpreter::tokens::AnyType* value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeInfo {
|
||||||
|
std::variant<AbstractTypeInfo, AliasTypeInfo, AnyTypeInfo> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConstructorInfo {
|
||||||
|
std::string name;
|
||||||
|
size_t order;
|
||||||
|
utils::IdType type_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionDeclarationInfo {
|
||||||
|
std::vector<ParameterInfo> parameters;
|
||||||
|
std::vector<interpreter::tokens::AnyType*> argument_type_nodes;
|
||||||
|
std::vector<AnyTypeInfo*> argument_types;
|
||||||
|
interpreter::tokens::FunctionDeclaration* node = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionDefinitionInfo {
|
||||||
|
std::vector<ParameterInfo> parameters;
|
||||||
|
std::vector<std::string> argument_names;
|
||||||
|
interpreter::tokens::FunctionDefinitionStatement* node = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionInfo {
|
||||||
|
size_t argument_count = 0;
|
||||||
|
std::optional<FunctionDeclarationInfo> declaration;
|
||||||
|
std::optional<FunctionDefinitionInfo> definition;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeclassInfo {
|
||||||
|
std::vector<ParameterInfo> parameters;
|
||||||
|
std::vector<FunctionDeclarationInfo> requirements;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImportInfo {
|
||||||
|
std::string module_name;
|
||||||
|
std::vector<std::string> symbols;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NamespaceInfo {
|
||||||
|
enum Modifier { Const, Var };
|
||||||
|
|
||||||
|
std::unordered_map<std::string, utils::IdType> types;
|
||||||
|
std::unordered_map<std::string, utils::IdType> typeclasses;
|
||||||
|
std::unordered_map<std::string, utils::IdType> functions;
|
||||||
|
std::unordered_map<std::string, utils::IdType> constructors;
|
||||||
|
std::unordered_map<std::string, NamespaceInfo> namespaces;
|
||||||
|
std::unordered_map<std::string, std::vector<NamespaceInfo>> variable_namespaces;
|
||||||
|
|
||||||
|
std::optional<Modifier> modifier;
|
||||||
|
std::optional<std::string> variable;
|
||||||
|
std::string type_name;
|
||||||
|
TypeInfo* type_info = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace info
|
||||||
235
archived/type_graph.hpp
Normal file
235
archived/type_graph.hpp
Normal file
|
|
@ -0,0 +1,235 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Temporary frozen, TODO
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
namespace info {
|
||||||
|
|
||||||
|
// TODO: fix dfs, etc.
|
||||||
|
// TODO: optimize recalc
|
||||||
|
|
||||||
|
class TypeGraph {
|
||||||
|
public:
|
||||||
|
size_t AddVertex(const std::vector<std::string>& methods = {},
|
||||||
|
const std::vector<std::string>& typeclasses = {}) {
|
||||||
|
is_calculated_ = false;
|
||||||
|
|
||||||
|
Vertex vertex;
|
||||||
|
|
||||||
|
for (auto& method : methods) {
|
||||||
|
vertex.new_requirements.methods.insert(storage_.GetId(method));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& typeclass : typeclasses) {
|
||||||
|
vertex.new_requirements.typeclasses.insert(storage_.GetId(typeclass));
|
||||||
|
}
|
||||||
|
|
||||||
|
verticles_.push_back(vertex);
|
||||||
|
edges_.emplace_back();
|
||||||
|
back_edges_.emplace_back();
|
||||||
|
|
||||||
|
groups_.AddElement();
|
||||||
|
|
||||||
|
return verticles_.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> VertexMethods(size_t id) {
|
||||||
|
if (!is_calculated_) {
|
||||||
|
// error
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t cluster_id = verticles_[id].cluster.value();
|
||||||
|
|
||||||
|
std::vector<std::string> methods;
|
||||||
|
|
||||||
|
methods.reserve(cluster_requirements_[cluster_id].methods.size());
|
||||||
|
|
||||||
|
for (auto& method : cluster_requirements_[cluster_id].methods) {
|
||||||
|
methods.push_back(std::move(storage_.GetValue(method)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<utils::IdType> VertexTypeclasses(size_t id) {
|
||||||
|
if (!is_calculated_) {
|
||||||
|
// error
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t cluster_id = verticles_[id].cluster.value();
|
||||||
|
|
||||||
|
typeclasses_[id].methods[method.first].definition = method.second.definition;
|
||||||
|
std::vector<utils::IdType> typeclasses;
|
||||||
|
|
||||||
|
typeclasses.reserve(cluster_requirements_[cluster_id].typeclasses.size());
|
||||||
|
|
||||||
|
for (auto& typeclass : cluster_requirements_[cluster_id].typeclasses) {
|
||||||
|
typeclasses.push_back(typeclass);
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeclasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddMethod(size_t id, const std::string& method) {
|
||||||
|
is_calculated_ = false;
|
||||||
|
|
||||||
|
verticles_[id].new_requirements.methods.insert(storage_.GetId(method));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTypeclass(size_t id, utils::IdType typeclass) {
|
||||||
|
is_calculated_ = false;
|
||||||
|
|
||||||
|
verticles_[id].new_requirements.typeclasses.insert(typeclass);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddEdge(size_t from, size_t to) {
|
||||||
|
is_calculated_ = false;
|
||||||
|
|
||||||
|
edges_[from].push_back(to);
|
||||||
|
back_edges_[to].push_back(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetEqual(size_t u, size_t v) {
|
||||||
|
AddEdge(u, v);
|
||||||
|
AddEdge(v, u);
|
||||||
|
groups_.Unite(u, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Calculate() {
|
||||||
|
if (is_calculated_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto clusters = FindClusters();
|
||||||
|
|
||||||
|
std::vector<RequirementsData> cluster_requirements(clusters.size());
|
||||||
|
std::vector<std::unordered_set<size_t>> cluster_edges(clusters.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < clusters.size(); ++i) {
|
||||||
|
for (auto& vertex_id : clusters[i]) {
|
||||||
|
for (auto& method : verticles_[vertex_id].new_requirements.methods) {
|
||||||
|
cluster_requirements[i].methods.insert(method);
|
||||||
|
}
|
||||||
|
verticles_[vertex_id].new_requirements.methods.clear();
|
||||||
|
|
||||||
|
for (auto& typeclass : verticles_[vertex_id].new_requirements.typeclasses) {
|
||||||
|
cluster_requirements[i].typeclasses.insert(typeclass);
|
||||||
|
}
|
||||||
|
verticles_[vertex_id].new_requirements.methods.clear();
|
||||||
|
|
||||||
|
for (auto& edge : edges_[vertex_id]) {
|
||||||
|
cluster_edges[i].insert(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check, that clusters are top sorted
|
||||||
|
for (size_t i = 0; i < clusters.size(); ++i) {
|
||||||
|
for (auto& edge : cluster_edges[i]) {
|
||||||
|
for (auto& method : cluster_requirements[edge].methods) {
|
||||||
|
cluster_requirements[i].methods.insert(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& typeclass : cluster_requirements[edge].typeclasses) {
|
||||||
|
cluster_requirements[i].typeclasses.insert(typeclass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < clusters.size(); ++i) {
|
||||||
|
for (auto& vertex_id : clusters[i]) {
|
||||||
|
verticles_[vertex_id].cluster = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clusters_ = std::move(clusters);
|
||||||
|
cluster_requirements_ = std::move(cluster_requirements);
|
||||||
|
|
||||||
|
is_calculated_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct RequirementsData {
|
||||||
|
std::unordered_set<utils::IdType> methods;
|
||||||
|
std::unordered_set<utils::IdType> typeclasses;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
RequirementsData new_requirements;
|
||||||
|
std::optional<size_t> cluster;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::vector<size_t>> FindClusters() {
|
||||||
|
std::vector<std::vector<size_t>> clusters;
|
||||||
|
|
||||||
|
auto sorted_verticles = BackTopSort();
|
||||||
|
|
||||||
|
std::vector<size_t> marks(sorted_verticles.size(), 0);
|
||||||
|
for (size_t i = 0; i < sorted_verticles.size(); ++i) {
|
||||||
|
if (marks[i] == 0) {
|
||||||
|
clusters.emplace_back();
|
||||||
|
BackVisitDfs(i, clusters[i], marks, back_edges_, clusters.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clusters;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackVisitDfs(size_t id,
|
||||||
|
std::vector<size_t>& verticles,
|
||||||
|
std::vector<size_t>& marks,
|
||||||
|
const std::vector<std::vector<size_t>>& edges,
|
||||||
|
size_t mark) {
|
||||||
|
if (marks[id] != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
marks[id] = mark;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < edges[id].size(); ++i) {
|
||||||
|
BackVisitDfs(id, verticles, marks, edges, mark);
|
||||||
|
}
|
||||||
|
|
||||||
|
verticles.push_back(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> BackTopSort() {
|
||||||
|
std::vector<size_t> sorted_verticles;
|
||||||
|
std::vector<size_t> marks(verticles_.size(), 0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < marks.size(); ++i) {
|
||||||
|
BackVisitDfs(i, sorted_verticles, marks, edges_, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sorted_verticles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::vector<size_t>> edges_;
|
||||||
|
std::vector<std::vector<size_t>> back_edges_;
|
||||||
|
std::vector<Vertex> verticles_;
|
||||||
|
|
||||||
|
std::vector<std::vector<size_t>> clusters_;
|
||||||
|
std::vector<RequirementsData> cluster_requirements_;
|
||||||
|
|
||||||
|
utils::Storage<std::string> storage_;
|
||||||
|
utils::GroupsManager groups_;
|
||||||
|
|
||||||
|
bool is_calculated_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace info
|
||||||
151
include/build_visitor.hpp
Normal file
151
include/build_visitor.hpp
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
#include "visitor.hpp"
|
||||||
|
#include "parse_tree.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
class BuildVisitor : public Visitor {
|
||||||
|
public:
|
||||||
|
explicit BuildVisitor(const parser::ParseTree& parse_tree) : parse_tree_(parse_tree) {}
|
||||||
|
|
||||||
|
void VisitSourceFile(SourceFile* source_file) override {
|
||||||
|
current_node_ = parse_tree_.GetRoot();
|
||||||
|
Visit(source_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
void Visit(SourceFile* node) override;
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
void Visit(NamespaceSources* node) override;
|
||||||
|
void Visit(Namespace* node) override;
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
void Visit(ImportStatement* node) override;
|
||||||
|
void Visit(AliasDefinitionStatement* node) override;
|
||||||
|
void Visit(VariableDefinitionStatement* node) override;
|
||||||
|
void Visit(FunctionDeclaration* node) override;
|
||||||
|
void Visit(FunctionDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeDefinitionStatement* node) override;
|
||||||
|
void Visit(AbstractTypeDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeclassDefinitionStatement* node) override;
|
||||||
|
void Visit(PartitionStatement* node) override;
|
||||||
|
|
||||||
|
void Visit(NamespaceStatement& node) override; // variant
|
||||||
|
void Visit(SourceStatement& node) override; // variant
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
void Visit(FunctionDefinition* node) override;
|
||||||
|
void Visit(TypeDefinition* node) override;
|
||||||
|
void Visit(AnyAnnotatedType* node) override;
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
void Visit(TypeConstructorPatternParameter* node) override;
|
||||||
|
void Visit(TypeConstructorPattern* node) override;
|
||||||
|
void Visit(MatchCase* node) override;
|
||||||
|
void Visit(Match* node) override;
|
||||||
|
void Visit(Condition* node) override;
|
||||||
|
void Visit(DoWhileLoop* node) override;
|
||||||
|
void Visit(WhileLoop* node) override;
|
||||||
|
void Visit(ForLoop* node) override;
|
||||||
|
void Visit(LoopLoop* node) override;
|
||||||
|
|
||||||
|
void Visit(Pattern& node) override; // variant
|
||||||
|
void Visit(FlowControl& node) override; // variant
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
void Visit(BlockStatement& node) override; // variant
|
||||||
|
|
||||||
|
void Visit(Block* node) override;
|
||||||
|
|
||||||
|
void Visit(SubExpressionToken& node) override; // variant
|
||||||
|
void Visit(SubExpression& node) override; // variant
|
||||||
|
void Visit(PrefixedExpression& node) override; // variant
|
||||||
|
void Visit(Expression& node) override; // variant
|
||||||
|
void Visit(SuperExpression& node) override; // variant
|
||||||
|
|
||||||
|
void Visit(ScopedStatement* node) override;
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
void Visit(ReferenceExpression* node) override;
|
||||||
|
void Visit(AccessExpression* node) override;
|
||||||
|
|
||||||
|
// Other expressions
|
||||||
|
|
||||||
|
void Visit(FunctionCallExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(TupleExpression* node) override;
|
||||||
|
void Visit(VariantExpression* node) override;
|
||||||
|
void Visit(ReturnExpression* node) override;
|
||||||
|
void Visit(TypeConstructorParameter* node) override;
|
||||||
|
void Visit(TypeConstructor* node) override;
|
||||||
|
void Visit(LambdaFunction* node) override;
|
||||||
|
void Visit(ArrayExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(LoopControlExpression& node) override; // enum
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
void Visit(PartitionName* node) override;
|
||||||
|
void Visit(NameExpression* node) override;
|
||||||
|
void Visit(TupleName* node) override;
|
||||||
|
void Visit(VariantName* node) override;
|
||||||
|
void Visit(AnnotatedName* node) override;
|
||||||
|
|
||||||
|
void Visit(AnyName& node) override; // variant
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
void Visit(FunctionType* node) override;
|
||||||
|
void Visit(TupleType* node) override;
|
||||||
|
void Visit(VariantType* node) override;
|
||||||
|
void Visit(TypeExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(AnyType& node) override; // variant
|
||||||
|
|
||||||
|
void Visit(ExtendedScopedAnyType* node) override;
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
void Visit(ParametrizedTypeclass* node) override;
|
||||||
|
|
||||||
|
// Typeclass & Type
|
||||||
|
|
||||||
|
void Visit(ParametrizedType* node) override;
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
// // void Visit(AnyIdentifier* node) override; // std::string
|
||||||
|
|
||||||
|
void Visit(FloatNumberLiteral* node) override;
|
||||||
|
void Visit(NumberLiteral* node) override;
|
||||||
|
void Visit(StringLiteral* node) override;
|
||||||
|
void Visit(CharLiteral* node) override;
|
||||||
|
void Visit(UnitLiteral* node) override;
|
||||||
|
void Visit(BoolLiteral* node) override;
|
||||||
|
|
||||||
|
void Visit(Literal& node) override; // variant
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void VisitBinaryOperatorExpression(FunctionCallExpression* node);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const parser::ParseTree& parse_tree_;
|
||||||
|
parser::ParseTree::Node current_node_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
25
include/builtin_functions.hpp
Normal file
25
include/builtin_functions.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
|
||||||
|
namespace info::builtin {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void Print(const T& value) { // only for strings ??
|
||||||
|
std::cout << "\x1b[1;32mOutput:\x1b[0m ";
|
||||||
|
std::cout << value;
|
||||||
|
std::cout << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline T Read() {
|
||||||
|
T value;
|
||||||
|
std::cout << "\x1b[1;32mInput:\x1b[0m ";
|
||||||
|
std::cin >> value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace info
|
||||||
275
include/contexts.hpp
Normal file
275
include/contexts.hpp
Normal file
|
|
@ -0,0 +1,275 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "error_handling.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
namespace info {
|
||||||
|
|
||||||
|
template<typename Value, typename ValueManager>
|
||||||
|
class ContextManager {
|
||||||
|
public:
|
||||||
|
ContextManager() {
|
||||||
|
contexts_.emplace_back(true); // no difference ??
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ContextCount() {
|
||||||
|
return contexts_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
utils::IdType AddValue(const T& value, utils::ValueType value_type) {
|
||||||
|
return value_manager_.AddValue(value, value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType AddAnyValue(Value&& value, utils::ValueType value_type) {
|
||||||
|
return value_manager_.AddAnyValue(std::move(value), value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T*> GetValue(utils::IdType value_id) {
|
||||||
|
return value_manager_.template GetValue<T>(value_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* GetAnyValue(utils::IdType value_id) {
|
||||||
|
return value_manager_.GetAnyValue(value_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddValueRequirement(utils::IdType type, utils::IdType requrement) {
|
||||||
|
return value_manager_.AddValueRequirement(type, requrement);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EqualValues(utils::IdType first_type, utils::IdType second_type) {
|
||||||
|
return value_manager_.EqualValues(first_type, second_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::ValueType GetValueType(utils::IdType value_id) {
|
||||||
|
return value_manager_.GetValueType(value_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModifiyValue(utils::IdType value_id, utils::ValueType new_value_type) {
|
||||||
|
value_manager_.SetValueType(value_id, new_value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType ToModifiedValue(utils::IdType value_id, utils::ValueType new_value_type) {
|
||||||
|
Value value = *GetAnyValue(value_id);
|
||||||
|
return AddAnyValue(std::move(value), new_value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType ToModifiedValueCopy(utils::IdType value_id,
|
||||||
|
utils::ValueType new_value_type) {
|
||||||
|
Value* value = GetAnyValue(value_id);
|
||||||
|
return value->DeepCopy(&value_manager_, new_value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make deep copy if not temporary
|
||||||
|
utils::IdType ToTemporaryValue(utils::IdType value_id) {
|
||||||
|
if (GetValueType(value_id) == utils::ValueType::Tmp) {
|
||||||
|
return value_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToModifiedValueCopy(value_id, utils::ValueType::Tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueManager* GetValueManager() {
|
||||||
|
return &value_manager_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterContext(bool is_hiding_previous = false) {
|
||||||
|
contexts_.emplace_back(is_hiding_previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExitContext() {
|
||||||
|
if (contexts_.empty()) {
|
||||||
|
error_handling::HandleInternalError("contexts_ is empty",
|
||||||
|
"ContextManager.ExitContext",
|
||||||
|
std::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
contexts_.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChangeHidingOfCurrentContextTo(bool is_hiding_previous) {
|
||||||
|
contexts_.back().ChangeHidingTo(is_hiding_previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefineVariable(const std::string& name, utils::IdType value_id) {
|
||||||
|
return contexts_.back().DefineVariable(name, value_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefineLocalType(const std::string& name, utils::IdType type_id) {
|
||||||
|
return contexts_.back().DefineLocalType(name, type_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssignVariable(const std::string& name, utils::IdType value_id) {
|
||||||
|
for (ssize_t i = (ssize_t)contexts_.size() - 1; i >= 0; --i) {
|
||||||
|
if (contexts_[i].AssignVariable(name, value_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contexts_[i].IsHidingPrevious()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssignLocalType(const std::string& name, utils::IdType type_id) {
|
||||||
|
for (ssize_t i = (ssize_t)contexts_.size() - 1; i >= 0; --i) {
|
||||||
|
if (contexts_[i].AssignLocalType(name, type_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contexts_[i].IsHidingPrevious()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoveVariable(const std::string& name) {
|
||||||
|
for (ssize_t i = (ssize_t)contexts_.size() - 1; i >= 0; --i) {
|
||||||
|
if (contexts_[i].RemoveVariable(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contexts_[i].IsHidingPrevious()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterVariableContext(const std::string& name,
|
||||||
|
utils::IdType value_id,
|
||||||
|
bool is_hiding_previous = false) {
|
||||||
|
EnterContext(is_hiding_previous);
|
||||||
|
|
||||||
|
DefineVariable(name, value_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindVariable(const std::string& name) {
|
||||||
|
for (ssize_t i = (ssize_t)contexts_.size() - 1; i >= 0; --i) {
|
||||||
|
auto maybe_variable = contexts_[i].FindVariable(name);
|
||||||
|
if (maybe_variable.has_value()) {
|
||||||
|
return maybe_variable.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contexts_[i].IsHidingPrevious()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindLocalType(const std::string& name) {
|
||||||
|
for (ssize_t i = (ssize_t)contexts_.size() - 1; i >= 0; --i) {
|
||||||
|
auto maybe_type = contexts_[i].FindLocalType(name);
|
||||||
|
if (maybe_type.has_value()) {
|
||||||
|
return maybe_type.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contexts_[i].IsHidingPrevious()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Context {
|
||||||
|
public:
|
||||||
|
explicit Context(bool is_hiding_previous) : is_hiding_previous_(is_hiding_previous) {}
|
||||||
|
|
||||||
|
bool DefineVariable(const std::string& name, utils::IdType value_id) {
|
||||||
|
if (name == "_") { // placeholder
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variables_.count(name) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
variables_[name] = value_id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefineLocalType(const std::string& name, utils::IdType type_id) {
|
||||||
|
if (local_types_.count(name) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
local_types_[name] = type_id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssignVariable(const std::string& name, utils::IdType value_id) {
|
||||||
|
if (name == "_") { // placeholder
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto variable_iter = variables_.find(name);
|
||||||
|
if (variable_iter == variables_.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
variable_iter->second = value_id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssignLocalType(const std::string& name, utils::IdType type_id) {
|
||||||
|
auto local_type_iter = local_types_.find(name);
|
||||||
|
if (local_type_iter == local_types_.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
local_type_iter->second = type_id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoveVariable(const std::string& name) {
|
||||||
|
return variables_.erase(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindVariable(const std::string& name) {
|
||||||
|
auto variable_iter = variables_.find(name);
|
||||||
|
|
||||||
|
if (variable_iter == variables_.end()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return variable_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindLocalType(const std::string& name) {
|
||||||
|
auto local_abstract_type_iter = local_types_.find(name);
|
||||||
|
|
||||||
|
if (local_abstract_type_iter == local_types_.end()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return local_abstract_type_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsHidingPrevious() {
|
||||||
|
return is_hiding_previous_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChangeHidingTo(bool is_hiding_previous) {
|
||||||
|
is_hiding_previous_ = is_hiding_previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, utils::IdType> variables_;
|
||||||
|
std::unordered_map<std::string, utils::IdType> local_types_;
|
||||||
|
|
||||||
|
bool is_hiding_previous_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Context> contexts_;
|
||||||
|
ValueManager value_manager_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace info
|
||||||
114
include/definitions.hpp
Normal file
114
include/definitions.hpp
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
class Node;
|
||||||
|
} // namespace interpreter
|
||||||
|
|
||||||
|
namespace info::definition {
|
||||||
|
|
||||||
|
struct Namespace;
|
||||||
|
|
||||||
|
struct TypeUsage {
|
||||||
|
interpreter::tokens::TypeExpression* node;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Parameter {
|
||||||
|
std::string type;
|
||||||
|
std::vector<interpreter::tokens::ParametrizedTypeclass*> typeclass_nodes;
|
||||||
|
|
||||||
|
interpreter::tokens::AnyAnnotatedType* node = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AbstractType {
|
||||||
|
utils::AbstractTypeModifier modifier;
|
||||||
|
Parameter type;
|
||||||
|
interpreter::tokens::AbstractTypeDefinitionStatement* node = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AliasType {
|
||||||
|
utils::AliasModifier modifier;
|
||||||
|
std::vector<std::string> parameters;
|
||||||
|
TypeUsage value;
|
||||||
|
interpreter::tokens::AliasDefinitionStatement* node = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnyType {
|
||||||
|
Parameter type;
|
||||||
|
std::vector<Parameter> parameters;
|
||||||
|
utils::ClassModifier modifier;
|
||||||
|
interpreter::tokens::TypeDefinitionStatement* node = nullptr;
|
||||||
|
|
||||||
|
utils::IdType parent_namespace = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Type {
|
||||||
|
std::variant<AliasType, AnyType> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Constructor {
|
||||||
|
std::string name;
|
||||||
|
std::optional<size_t> order; // no order for tuple types
|
||||||
|
utils::IdType type_id = 0;
|
||||||
|
std::optional<interpreter::tokens::TupleType*> constructor_tuple_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionDeclaration {
|
||||||
|
std::vector<Parameter> parameters;
|
||||||
|
std::vector<interpreter::tokens::AnyType*> argument_types;
|
||||||
|
interpreter::tokens::FunctionDeclaration* node = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionDefinition {
|
||||||
|
std::vector<std::string> argument_names;
|
||||||
|
interpreter::tokens::FunctionDefinitionStatement* node = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Function {
|
||||||
|
size_t argument_count = 0;
|
||||||
|
std::optional<FunctionDeclaration> declaration;
|
||||||
|
std::optional<FunctionDefinition> definition;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Typeclass {
|
||||||
|
std::vector<Parameter> parameters;
|
||||||
|
interpreter::tokens::TypeclassDefinitionStatement* node;
|
||||||
|
|
||||||
|
utils::IdType parent_namespace = 0;
|
||||||
|
|
||||||
|
utils::IdType graph_id_ = 0; // TODO: make safe??
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Import {
|
||||||
|
std::string module_name;
|
||||||
|
std::vector<std::string> symbols; // size == 0 => all symbols imported
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Namespace {
|
||||||
|
std::unordered_map<std::string, utils::IdType> types;
|
||||||
|
std::unordered_map<std::string, utils::IdType> functions;
|
||||||
|
std::unordered_map<std::string, utils::IdType> constructors;
|
||||||
|
std::unordered_map<std::string, utils::IdType> namespaces;
|
||||||
|
std::unordered_map<std::string, utils::IdType> var_namespaces;
|
||||||
|
std::unordered_map<std::string, utils::IdType> const_namespaces;
|
||||||
|
|
||||||
|
utils::IdType parent_namespace = 0;
|
||||||
|
|
||||||
|
utils::ClassInternalsModifier modifier = utils::ClassInternalsModifier::Static;
|
||||||
|
std::string type_name;
|
||||||
|
|
||||||
|
// all nodes have same info
|
||||||
|
std::optional<interpreter::tokens::Namespace*> any_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace info::definition
|
||||||
78
include/error_handling.hpp
Normal file
78
include/error_handling.hpp
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
namespace error_handling {
|
||||||
|
|
||||||
|
inline void PrintPosition(std::ostream& out,
|
||||||
|
std::pair<size_t, size_t> start_position,
|
||||||
|
std::pair<size_t, size_t> end_position) {
|
||||||
|
out << '['
|
||||||
|
<< start_position.first + 1
|
||||||
|
<< ", "
|
||||||
|
<< start_position.second + 1
|
||||||
|
<< "] - ["
|
||||||
|
<< end_position.first + 1
|
||||||
|
<< ", "
|
||||||
|
<< end_position.second + 1
|
||||||
|
<< ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HandleParsingError(const std::string& message,
|
||||||
|
std::pair<size_t, size_t> start_position,
|
||||||
|
std::pair<size_t, size_t> end_position) {
|
||||||
|
std::cerr << "\x1b[1;31mParsing Error:\x1b[0m " << message << " at ";
|
||||||
|
PrintPosition(std::cerr, start_position, end_position);
|
||||||
|
std::cerr << ".\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HandleGeneralError(const std::string& message) {
|
||||||
|
std::cerr << "\x1b[1;31mGeneral Error:\x1b[0m " << message << ".\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HandleInternalError(const std::string& message,
|
||||||
|
const std::string& place,
|
||||||
|
std::optional<const interpreter::tokens::BaseNode*> node) {
|
||||||
|
std::cerr << "\x1b[1;31mInternal Error:\x1b[0m " << message << " at " << place;
|
||||||
|
if (node.has_value()) {
|
||||||
|
std::cerr << ", at ";
|
||||||
|
PrintPosition(std::cerr, node.value()->start_position, node.value()->end_position);
|
||||||
|
}
|
||||||
|
std::cerr << ".\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HandleTypecheckError(const std::string& message,
|
||||||
|
const interpreter::tokens::BaseNode& node) {
|
||||||
|
std::cerr << "\x1b[1;31mTypecheck Error:\x1b[0m " << message << " at ";
|
||||||
|
PrintPosition(std::cerr, node.start_position, node.end_position);
|
||||||
|
std::cerr << ".\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HandleRuntimeError(const std::string& message,
|
||||||
|
const interpreter::tokens::BaseNode& node) {
|
||||||
|
std::cerr << "\x1b[1;31mRuntime Error:\x1b[0m " << message << " at ";
|
||||||
|
PrintPosition(std::cerr, node.start_position, node.end_position);
|
||||||
|
std::cerr << ".\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HandleNamesError(const std::string& message,
|
||||||
|
const interpreter::tokens::BaseNode& node) {
|
||||||
|
std::cerr << "\x1b[1;31mNames Error:\x1b[0m " << message << " at ";
|
||||||
|
PrintPosition(std::cerr, node.start_position, node.end_position);
|
||||||
|
std::cerr << ".\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void DebugPrint(const T& value) {
|
||||||
|
std::cerr << "\x1b[1;33mDebug:\x1b[0m " << value << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace error_handling
|
||||||
193
include/execute_visitor.hpp
Normal file
193
include/execute_visitor.hpp
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "contexts.hpp"
|
||||||
|
#include "global_info.hpp"
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
#include "values.hpp"
|
||||||
|
#include "visitor.hpp"
|
||||||
|
#include "error_handling.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
class ExecuteVisitor : public Visitor {
|
||||||
|
public:
|
||||||
|
explicit ExecuteVisitor(info::GlobalInfo& global_info,
|
||||||
|
info::ContextManager<info::type::Type, info::type::TypeManager>& type_context_manager,
|
||||||
|
info::ContextManager<info::value::Value, info::value::ValueManager>& context_manager)
|
||||||
|
: global_info_(global_info),
|
||||||
|
typeclass_graph_(*global_info.GetTypeclassGraph()),
|
||||||
|
type_context_manager_(type_context_manager),
|
||||||
|
context_manager_(context_manager) {}
|
||||||
|
|
||||||
|
void VisitSourceFile(SourceFile* node) override {
|
||||||
|
error_handling::HandleInternalError("VisitSourceFile unavailible",
|
||||||
|
"ExecuteVisitor.VisitSourceFile",
|
||||||
|
&node->base);
|
||||||
|
};
|
||||||
|
|
||||||
|
void ExecutePartition(interpreter::tokens::PartitionStatement* partition) {
|
||||||
|
Visit(partition);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
void Visit(SourceFile* node) override;
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
void Visit(NamespaceSources* node) override;
|
||||||
|
void Visit(Namespace* node) override;
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
void Visit(ImportStatement* node) override;
|
||||||
|
void Visit(AliasDefinitionStatement* node) override;
|
||||||
|
void Visit(VariableDefinitionStatement* node) override;
|
||||||
|
void Visit(FunctionDeclaration* node) override;
|
||||||
|
void Visit(FunctionDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeDefinitionStatement* node) override;
|
||||||
|
void Visit(AbstractTypeDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeclassDefinitionStatement* node) override;
|
||||||
|
void Visit(PartitionStatement* node) override;
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
// // void Visit(FunctionDefinition* node) override;
|
||||||
|
// // void Visit(TypeDefinition* node) override;
|
||||||
|
// // void Visit(AnyAnnotatedType* node) override;
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
void Visit(TypeConstructorPatternParameter* node) override;
|
||||||
|
void Visit(TypeConstructorPattern* node) override;
|
||||||
|
void Visit(MatchCase* node) override;
|
||||||
|
void Visit(Match* node) override;
|
||||||
|
void Visit(Condition* node) override;
|
||||||
|
void Visit(DoWhileLoop* node) override;
|
||||||
|
void Visit(WhileLoop* node) override;
|
||||||
|
void Visit(ForLoop* node) override;
|
||||||
|
void Visit(LoopLoop* node) override;
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
void Visit(Block* node) override;
|
||||||
|
|
||||||
|
void Visit(ScopedStatement* node) override;
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
void Visit(ReferenceExpression* node) override;
|
||||||
|
void Visit(AccessExpression* node) override;
|
||||||
|
|
||||||
|
// Simple Expressions
|
||||||
|
|
||||||
|
void Visit(FunctionCallExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(TupleExpression* node) override;
|
||||||
|
void Visit(VariantExpression* node) override;
|
||||||
|
void Visit(ReturnExpression* node) override;
|
||||||
|
void Visit(TypeConstructorParameter* node) override;
|
||||||
|
void Visit(TypeConstructor* node) override;
|
||||||
|
void Visit(LambdaFunction* node) override;
|
||||||
|
void Visit(ArrayExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(LoopControlExpression& node) override; // enum
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
// // void Visit(PartitionName* node) override;
|
||||||
|
void Visit(NameExpression* node) override;
|
||||||
|
void Visit(TupleName* node) override;
|
||||||
|
void Visit(VariantName* node) override;
|
||||||
|
void Visit(AnnotatedName* node) override;
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
void Visit(FunctionType* node) override;
|
||||||
|
void Visit(TupleType* node) override;
|
||||||
|
void Visit(VariantType* node) override;
|
||||||
|
void Visit(TypeExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(ExtendedScopedAnyType* node) override;
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
void Visit(ParametrizedTypeclass* node) override;
|
||||||
|
|
||||||
|
// Typeclass & Type
|
||||||
|
|
||||||
|
void Visit(ParametrizedType* node) override;
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
// // void Visit(std::string* node) override; // std::string
|
||||||
|
|
||||||
|
void Visit(FloatNumberLiteral* node) override;
|
||||||
|
void Visit(NumberLiteral* node) override;
|
||||||
|
void Visit(StringLiteral* node) override;
|
||||||
|
void Visit(CharLiteral* node) override;
|
||||||
|
void Visit(UnitLiteral* node) override;
|
||||||
|
void Visit(BoolLiteral* node) override;
|
||||||
|
|
||||||
|
bool HandleCondition(Expression& condition, const BaseNode& base_node);
|
||||||
|
void CollectTypeContext(const ParametrizedType& type);
|
||||||
|
void CheckPattern(Pattern& node, const BaseNode& base_node);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* ExtractValue(utils::IdType value, const BaseNode& base_node) {
|
||||||
|
std::optional<T*> maybe_value_info = context_manager_.GetValue<T>(value);
|
||||||
|
if (!maybe_value_info.has_value()) {
|
||||||
|
error_handling::HandleRuntimeError("Value has value class that is different from exprected one", base_node);
|
||||||
|
}
|
||||||
|
return maybe_value_info.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* ExtractInternalValue(utils::IdType value, const BaseNode& base_node) {
|
||||||
|
info::value::InternalValue* value_info = ExtractValue<info::value::InternalValue>(value, base_node);
|
||||||
|
std::optional<T*> maybe_internal_value_info = value_info->GetValue<T>();
|
||||||
|
if (!maybe_internal_value_info.has_value()) {
|
||||||
|
error_handling::HandleRuntimeError("Value has internal value class that is different from exprected one", base_node);
|
||||||
|
}
|
||||||
|
return maybe_internal_value_info.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType GraphIdByTypeId(utils::IdType type_id) {
|
||||||
|
auto maybe_any_type = global_info_.GetTypeInfo<info::definition::AnyType>(type_id);
|
||||||
|
if (!maybe_any_type.has_value()) {
|
||||||
|
error_handling::HandleInternalError("Only AnyType implemented",
|
||||||
|
"ExecuteVisitor.ExtractInternalValue",
|
||||||
|
std::nullopt);
|
||||||
|
}
|
||||||
|
return maybe_any_type.value()->node->definition->type->graph_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
bool HandleBuiltinFunctionCall(FunctionCallExpression* node);
|
||||||
|
|
||||||
|
bool HandleBuiltinTypeFunctionCall(FunctionCallExpression* node,
|
||||||
|
info::type::InternalType type);
|
||||||
|
private:
|
||||||
|
info::GlobalInfo& global_info_;
|
||||||
|
info::TypeclassGraph& typeclass_graph_;
|
||||||
|
info::ContextManager<info::type::Type, info::type::TypeManager>& type_context_manager_;
|
||||||
|
|
||||||
|
info::ContextManager<info::value::Value, info::value::ValueManager>& context_manager_;
|
||||||
|
// local types store types graph ids
|
||||||
|
|
||||||
|
utils::IdType current_value_;
|
||||||
|
std::optional<LoopControlExpression> active_loop_control_expression_;
|
||||||
|
std::optional<utils::IsConstModifier> is_const_definition_;
|
||||||
|
bool case_matched_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
127
include/find_symbols_visitor.hpp
Normal file
127
include/find_symbols_visitor.hpp
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <any>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
#include "visitor.hpp"
|
||||||
|
#include "global_info.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
class FindSymbolsVisitor : public Visitor {
|
||||||
|
public:
|
||||||
|
explicit FindSymbolsVisitor(info::GlobalInfo& global_info)
|
||||||
|
: namespace_visitor_(global_info.CreateVisitor()) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
// void Visit(SourceFile* node) override; // default
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
// void Visit(NamespaceSources* node) override; // default
|
||||||
|
void Visit(Namespace* node) override;
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
void Visit(ImportStatement* node) override;
|
||||||
|
void Visit(AliasDefinitionStatement* node) override;
|
||||||
|
// // void Visit(VariableDefinitionStatement* node) override;
|
||||||
|
void Visit(FunctionDeclaration* node) override;
|
||||||
|
void Visit(FunctionDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeDefinitionStatement* node) override;
|
||||||
|
void Visit(AbstractTypeDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeclassDefinitionStatement* node) override;
|
||||||
|
void Visit(PartitionStatement* node) override;
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
// // void Visit(FunctionDefinition* node) override;
|
||||||
|
// // void Visit(TypeDefinition* node) override;
|
||||||
|
void Visit(AnyAnnotatedType* node) override;
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
// // void Visit(TypeConstructorPatternParameter* node) override;
|
||||||
|
// // void Visit(TypeConstructorPattern* node) override;
|
||||||
|
// // void Visit(MatchCase* node) override;
|
||||||
|
// // void Visit(Match* node) override;
|
||||||
|
// // void Visit(Condition* node) override;
|
||||||
|
// // void Visit(DoWhileLoop* node) override;
|
||||||
|
// // void Visit(WhileLoop* node) override;
|
||||||
|
// // void Visit(ForLoop* node) override;
|
||||||
|
// // void Visit(LoopLoop* node) override;
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
// // void Visit(Block* node) override;
|
||||||
|
// //
|
||||||
|
// // void Visit(ScopedStatement* node) override;
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
// // void Visit(ReferenceExpression* node) override;
|
||||||
|
// // void Visit(AccessExpression* node) override;
|
||||||
|
|
||||||
|
// Simple Expressions
|
||||||
|
|
||||||
|
// // void Visit(FunctionCallExpression* node) override;
|
||||||
|
|
||||||
|
// // void Visit(TupleExpression* node) override;
|
||||||
|
// // void Visit(VariantExpression* node) override;
|
||||||
|
// // void Visit(ReturnExpression* node) override;
|
||||||
|
// // void Visit(TypeConstructorParameter* node) override;
|
||||||
|
// // void Visit(TypeConstructor* node) override;
|
||||||
|
// // void Visit(LambdaFunction* node) override;
|
||||||
|
// // void Visit(ArrayExpression* node) override;
|
||||||
|
|
||||||
|
// // void Visit(LoopControlExpression& node) override; // enum
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
// // void Visit(PartitionName* node) override;
|
||||||
|
// // void Visit(NameExpression* node) override;
|
||||||
|
// // void Visit(TupleName* node) override;
|
||||||
|
// // void Visit(VariantName* node) override;
|
||||||
|
// // void Visit(AnnotatedName* node) override;
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
// // void Visit(FunctionType* node) override;
|
||||||
|
// // void Visit(TupleType* node) override;
|
||||||
|
// // void Visit(VariantType* node) override;
|
||||||
|
// // void Visit(TypeExpression* node) override;
|
||||||
|
|
||||||
|
// // void Visit(ExtendedScopedAnyType* node) override;
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
// // void Visit(ParametrizedTypeclass* node) override;
|
||||||
|
|
||||||
|
// Typeclass & Type
|
||||||
|
|
||||||
|
// // void Visit(ParametrizedType* node) override;
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
// // void Visit(std::string* node) override; // std::string
|
||||||
|
|
||||||
|
// // void Visit(FloatNumberLiteral* node) override;
|
||||||
|
// // void Visit(NumberLiteral* node) override;
|
||||||
|
// // void Visit(StringLiteral* node) override;
|
||||||
|
// // void Visit(CharLiteral* node) override;
|
||||||
|
// // void Visit(UnitLiteral* node) override;
|
||||||
|
// // void Visit(BoolLiteral* node) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
info::GlobalInfo::NamespaceVisitor namespace_visitor_;
|
||||||
|
|
||||||
|
std::any current_info_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
401
include/global_info.hpp
Normal file
401
include/global_info.hpp
Normal file
|
|
@ -0,0 +1,401 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "definitions.hpp"
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
#include "typeclass_graph.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
namespace info {
|
||||||
|
|
||||||
|
// TODO: add classes / structs and functions module interface
|
||||||
|
class GlobalInfo {
|
||||||
|
friend class NamespaceVisitor;
|
||||||
|
public:
|
||||||
|
GlobalInfo() {
|
||||||
|
namespaces_.emplace_back(); // global namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PartitionInfo {
|
||||||
|
std::vector<std::string> path;
|
||||||
|
interpreter::tokens::PartitionStatement* node = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NamespaceVisitor {
|
||||||
|
friend GlobalInfo;
|
||||||
|
NamespaceVisitor() = delete;
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct Path {
|
||||||
|
std::vector<std::optional<utils::IdType>> path_types;
|
||||||
|
definition::Namespace* result;
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddImport(definition::Import&& import_info, const std::optional<std::string>& name = std::nullopt);
|
||||||
|
|
||||||
|
void AddEnterNamespace(const std::string& name,
|
||||||
|
utils::ClassInternalsModifier modifier,
|
||||||
|
std::optional<interpreter::tokens::Namespace*> node,
|
||||||
|
const interpreter::tokens::BaseNode& base_node);
|
||||||
|
|
||||||
|
void EnterNamespace(const std::string& name,
|
||||||
|
utils::ClassInternalsModifier modifier);
|
||||||
|
|
||||||
|
void ExitNamespace();
|
||||||
|
|
||||||
|
void ToGlobalNamespace();
|
||||||
|
|
||||||
|
utils::IdType AddFunctionDeclaration(const std::string& name,
|
||||||
|
definition::FunctionDeclaration&& function_declaration_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node);
|
||||||
|
|
||||||
|
utils::IdType AddFunctionDefinition(const std::string& name,
|
||||||
|
definition::FunctionDefinition&& function_definition_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node);
|
||||||
|
|
||||||
|
utils::IdType AddType(const std::string& type,
|
||||||
|
definition::Type&& type_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node);
|
||||||
|
|
||||||
|
utils::IdType AddAbstractType(const std::string& abstract_type,
|
||||||
|
definition::AbstractType&& abstract_type_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node);
|
||||||
|
|
||||||
|
utils::IdType AddTypeclass(const std::string& typeclass,
|
||||||
|
definition::Typeclass&& typeclass_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node);
|
||||||
|
|
||||||
|
utils::IdType AddConstructor(const std::string& constructor,
|
||||||
|
definition::Constructor&& constructor_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node);
|
||||||
|
|
||||||
|
utils::IdType AddPartition(const std::vector<std::string>& path,
|
||||||
|
interpreter::tokens::PartitionStatement* node,
|
||||||
|
const interpreter::tokens::BaseNode& base_node);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindNamespaceId(const std::optional<std::vector<std::string>>& path);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindFunctionId(const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& name);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindMethodId(const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& name,
|
||||||
|
utils::IsConstModifier modifier);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindTypeId(const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& type);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindLocalTypeId(const std::string& type);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindAbstractTypeId(const std::string& abstract_type);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindTypeclassId(const std::string& typeclass);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindConstructorId(const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& constructor);
|
||||||
|
|
||||||
|
std::optional<definition::Namespace*> FindNamespace(const std::optional<std::vector<std::string>>& path) {
|
||||||
|
std::optional<utils::IdType> id = FindNamespaceId(path);
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &global_info_.GetNamespaceInfo(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<definition::Function*> FindFunction(const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& name) {
|
||||||
|
std::optional<utils::IdType> id = FindFunctionId(path, name);
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &global_info_.GetFunctionInfo(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<definition::Function*> FindMethod(const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& name,
|
||||||
|
utils::IsConstModifier modifier) {
|
||||||
|
std::optional<utils::IdType> id = FindMethodId(path, type, name, modifier);
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &global_info_.GetFunctionInfo(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<definition::Type*> FindAnyType(const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& type) {
|
||||||
|
std::optional<utils::IdType> id = FindTypeId(path, type);
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &global_info_.GetAnyTypeInfo(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T*> FindType(const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& type) {
|
||||||
|
std::optional<utils::IdType> id = FindTypeId(path, type);
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return global_info_.GetTypeInfo<T>(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<definition::Type*> FindAnyLocalType(const std::string& type) {
|
||||||
|
std::optional<utils::IdType> id = FindLocalTypeId(type);
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &global_info_.GetAnyTypeInfo(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T*> FindLocalType(const std::string& type) {
|
||||||
|
std::optional<utils::IdType> id = FindLocalTypeId(type);
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return global_info_.GetTypeInfo<T>(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<definition::AbstractType*> FindAbstractType(const std::string& abstract_type) {
|
||||||
|
std::optional<utils::IdType> id = FindAbstractTypeId(abstract_type);
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &global_info_.GetAbstractTypeInfo(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<definition::Typeclass*> FindTypeclass(const std::string& typeclass) {
|
||||||
|
std::optional<utils::IdType> id = FindTypeclassId(typeclass);
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &global_info_.GetTypeclassInfo(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<definition::Constructor*> FindConstructor(const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& constructor) {
|
||||||
|
std::optional<utils::IdType> id = FindConstructorId(path, constructor);
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &global_info_.GetConstructorInfo(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
NamespaceVisitor CreateVisitor() {
|
||||||
|
return global_info_.CreateVisitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalInfo* GetGlobalInfo() {
|
||||||
|
return &global_info_;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeclassGraph* GetTypeclassGraph() {
|
||||||
|
return global_info_.GetTypeclassGraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string>& GetCurrentPath() {
|
||||||
|
return current_path_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<utils::IdType>& GetCurrentPathNamespaces() {
|
||||||
|
return namespace_stack_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use only after LinkSymbolsVisitor
|
||||||
|
std::vector<std::optional<utils::IdType>> GetCurrentPathTypes() {
|
||||||
|
std::vector<std::optional<utils::IdType>> types;
|
||||||
|
|
||||||
|
types.reserve(namespace_stack_.size());
|
||||||
|
for (auto& namespace_id : namespace_stack_) {
|
||||||
|
definition::Namespace& namespace_info = global_info_.GetNamespaceInfo(namespace_id);
|
||||||
|
if (namespace_info.any_node.has_value() && namespace_info.any_node.value()->link_type_id_.has_value()) {
|
||||||
|
types.push_back(namespace_info.any_node.value()->link_type_id_.value());
|
||||||
|
} else {
|
||||||
|
types.push_back(std::nullopt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType GetCurrentNamespaceId() {
|
||||||
|
return namespace_stack_.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
definition::Namespace* GetCurrentNamespace() {
|
||||||
|
return &global_info_.namespaces_[GetCurrentNamespaceId()];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetCurrentNamespaceTypeId() {
|
||||||
|
if (!GetCurrentNamespace()->any_node.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return GetCurrentNamespace()->any_node.value()->link_type_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<definition::Type*> GetCurrentNamespaceAnyType() {
|
||||||
|
std::optional<utils::IdType> id = GetCurrentNamespaceTypeId();
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &global_info_.GetAnyTypeInfo(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T*> GetCurrentNamespaceType() {
|
||||||
|
std::optional<utils::IdType> id = GetCurrentNamespaceTypeId();
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return global_info_.GetTypeInfo<T>(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetCurrentNamespaceTypeclassId() {
|
||||||
|
if (!GetCurrentNamespace()->any_node.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return GetCurrentNamespace()->any_node.value()->link_typeclass_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<definition::Typeclass*> GetCurrentNamespaceTypeclass() {
|
||||||
|
std::optional<utils::IdType> id = GetCurrentNamespaceTypeclassId();
|
||||||
|
if (!id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &global_info_.GetTypeclassInfo(id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInGlobalNamespace() {
|
||||||
|
return namespace_stack_.size() == 1;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
NamespaceVisitor(GlobalInfo& global_info) : global_info_(global_info),
|
||||||
|
namespace_stack_ {global_info.GlobalNamespaceId} {}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T> FindSomething(
|
||||||
|
const std::optional<std::vector<std::string>>& path,
|
||||||
|
std::function<std::optional<T>(utils::IdType)> search_func);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindNamespaceIn(
|
||||||
|
utils::IdType current_namespace,
|
||||||
|
const std::vector<std::string>& path);
|
||||||
|
private:
|
||||||
|
GlobalInfo& global_info_;
|
||||||
|
|
||||||
|
std::vector<utils::IdType> namespace_stack_;
|
||||||
|
std::vector<std::string> current_path_;
|
||||||
|
};
|
||||||
|
|
||||||
|
NamespaceVisitor CreateVisitor() {
|
||||||
|
return NamespaceVisitor(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
definition::Function& GetFunctionInfo(utils::IdType id) {
|
||||||
|
return functions_.at(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
definition::Type& GetAnyTypeInfo(utils::IdType id) {
|
||||||
|
return types_.at(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T*> GetTypeInfo(utils::IdType id) {
|
||||||
|
if (!std::holds_alternative<T>(types_.at(id).type)) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &std::get<T>(types_[id].type);
|
||||||
|
}
|
||||||
|
|
||||||
|
definition::AbstractType& GetAbstractTypeInfo(utils::IdType id) {
|
||||||
|
return abstract_types_.at(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
definition::Typeclass& GetTypeclassInfo(utils::IdType id) {
|
||||||
|
return typeclasses_.at(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
definition::Constructor& GetConstructorInfo(utils::IdType id) {
|
||||||
|
return constructors_.at(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
definition::Namespace& GetNamespaceInfo(utils::IdType id) {
|
||||||
|
return namespaces_.at(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
PartitionInfo& GetPartitionInfo(utils::IdType id) {
|
||||||
|
return partitions_.at(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindPartition(const std::vector<std::string>& path) {
|
||||||
|
auto trie_ans = partitions_trie_.Find(path);
|
||||||
|
return trie_ans.has_value() ? std::optional<utils::IdType>(*trie_ans.value()) : std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<utils::IdType> FindPartitionsByPrefix(const std::vector<std::string>& path) { // optimize ??
|
||||||
|
auto trie_ans = partitions_trie_.FindByPrefix(path);
|
||||||
|
|
||||||
|
std::vector<utils::IdType> ans(trie_ans.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ans.size(); ++i) {
|
||||||
|
ans[i] = *trie_ans[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeclassGraph* GetTypeclassGraph() {
|
||||||
|
return &typeclass_graph_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<definition::Namespace*> GetTypeNamespace(utils::IdType id,
|
||||||
|
utils::ClassInternalsModifier modifier);
|
||||||
|
|
||||||
|
std::unordered_map<std::string, utils::IdType>* ChooseNamespaces(
|
||||||
|
utils::ClassInternalsModifier modifier,
|
||||||
|
definition::Namespace* current_namespace);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> AddTypeclassToGraph(utils::IdType typeclass);
|
||||||
|
|
||||||
|
// function declarations & definitions should be added latter
|
||||||
|
std::optional<utils::IdType> AddAnnotatedTypeToGraph(interpreter::tokens::AnnotatedType* node);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CollectFunctionInfo(
|
||||||
|
utils::IdType current_namespace,
|
||||||
|
utils::ClassInternalsModifier modifier,
|
||||||
|
std::vector<std::pair<std::string, std::pair<utils::ClassInternalsModifier, interpreter::tokens::FunctionDeclaration*>>>& function_declarations,
|
||||||
|
std::vector<std::pair<std::string, interpreter::tokens::FunctionDefinitionStatement*>>& function_definitions);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const utils::IdType GlobalNamespaceId = 0;
|
||||||
|
|
||||||
|
std::vector<definition::Function> functions_;
|
||||||
|
std::vector<definition::Type> types_;
|
||||||
|
std::vector<definition::AbstractType> abstract_types_;
|
||||||
|
std::vector<definition::Typeclass> typeclasses_;
|
||||||
|
std::vector<definition::Constructor> constructors_;
|
||||||
|
|
||||||
|
std::vector<definition::Namespace> namespaces_;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, utils::IdType> name_to_typeclass_;
|
||||||
|
std::unordered_map<std::string, utils::IdType> name_to_abstract_type_;
|
||||||
|
|
||||||
|
std::vector<PartitionInfo> partitions_;
|
||||||
|
utils::Trie<std::string, utils::IdType> partitions_trie_;
|
||||||
|
|
||||||
|
std::vector<definition::Import> imports_;
|
||||||
|
std::unordered_map<std::string, definition::Import> usages_;
|
||||||
|
|
||||||
|
TypeclassGraph typeclass_graph_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace info
|
||||||
717
include/interpreter_tree.hpp
Normal file
717
include/interpreter_tree.hpp
Normal file
|
|
@ -0,0 +1,717 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <variant>
|
||||||
|
#include <optional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
namespace interpreter::tokens {
|
||||||
|
|
||||||
|
struct BaseNode {
|
||||||
|
std::pair<size_t, size_t> start_position;
|
||||||
|
std::pair<size_t, size_t> end_position;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> type_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------- Declarations -----------------
|
||||||
|
|
||||||
|
using AnyIdentifier = std::string;
|
||||||
|
using NameOrOperatorIdentifier = std::string;
|
||||||
|
using NameIdentifier = std::string;
|
||||||
|
using AnyTypeIdentifier = std::string;
|
||||||
|
using TypeIdentifier = std::string;
|
||||||
|
using AbstractTypeIdentifier = std::string;
|
||||||
|
using OperatorIdentifier = std::string;
|
||||||
|
using TypeclassIdentifier = std::string;
|
||||||
|
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
struct SourceFile;
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
struct Namespace;
|
||||||
|
struct NamespaceSources;
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
struct ImportStatement;
|
||||||
|
struct AliasDefinitionStatement;
|
||||||
|
struct VariableDefinitionStatement;
|
||||||
|
struct FunctionDeclaration;
|
||||||
|
struct FunctionDefinitionStatement;
|
||||||
|
struct TypeDefinitionStatement;
|
||||||
|
struct AbstractTypeDefinitionStatement;
|
||||||
|
struct TypeclassDefinitionStatement;
|
||||||
|
struct PartitionStatement;
|
||||||
|
|
||||||
|
//
|
||||||
|
using NamespaceStatement = std::variant<
|
||||||
|
std::unique_ptr<AliasDefinitionStatement>,
|
||||||
|
std::unique_ptr<FunctionDeclaration>,
|
||||||
|
std::unique_ptr<FunctionDefinitionStatement>,
|
||||||
|
std::unique_ptr<TypeDefinitionStatement>,
|
||||||
|
std::unique_ptr<PartitionStatement>,
|
||||||
|
std::unique_ptr<Namespace>>;
|
||||||
|
//
|
||||||
|
using SourceStatement = std::variant<
|
||||||
|
std::unique_ptr<ImportStatement>,
|
||||||
|
std::unique_ptr<AbstractTypeDefinitionStatement>,
|
||||||
|
std::unique_ptr<TypeclassDefinitionStatement>,
|
||||||
|
std::unique_ptr<NamespaceStatement>>;
|
||||||
|
//
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
using ImportSymbol = AnyIdentifier; // can be extended name
|
||||||
|
|
||||||
|
struct FunctionDefinition;
|
||||||
|
struct TypeDefinition;
|
||||||
|
struct AnyAnnotatedType;
|
||||||
|
|
||||||
|
// TypeIdentifier <-> AbstractTypeIdentifier <-> std::string
|
||||||
|
using AnnotatedType = AnyAnnotatedType;
|
||||||
|
|
||||||
|
using AnnotatedAbstractType = AnyAnnotatedType;
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
struct TypeConstructorPatternParameter;
|
||||||
|
struct TypeConstructorPattern;
|
||||||
|
|
||||||
|
struct Match;
|
||||||
|
struct Condition;
|
||||||
|
struct DoWhileLoop;
|
||||||
|
struct WhileLoop;
|
||||||
|
struct ForLoop;
|
||||||
|
struct LoopLoop;
|
||||||
|
|
||||||
|
using FlowControl = std::variant<
|
||||||
|
std::unique_ptr<Match>,
|
||||||
|
std::unique_ptr<Condition>,
|
||||||
|
std::unique_ptr<DoWhileLoop>,
|
||||||
|
std::unique_ptr<WhileLoop>,
|
||||||
|
std::unique_ptr<ForLoop>,
|
||||||
|
std::unique_ptr<LoopLoop>>;
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
struct Block;
|
||||||
|
|
||||||
|
struct FloatNumberLiteral;
|
||||||
|
struct NumberLiteral;
|
||||||
|
struct StringLiteral;
|
||||||
|
struct CharLiteral;
|
||||||
|
struct UnitLiteral;
|
||||||
|
struct BoolLiteral;
|
||||||
|
|
||||||
|
using Literal = std::variant<
|
||||||
|
std::unique_ptr<FloatNumberLiteral>,
|
||||||
|
std::unique_ptr<NumberLiteral>,
|
||||||
|
std::unique_ptr<StringLiteral>,
|
||||||
|
std::unique_ptr<CharLiteral>,
|
||||||
|
std::unique_ptr<UnitLiteral>,
|
||||||
|
std::unique_ptr<BoolLiteral>>;
|
||||||
|
|
||||||
|
//
|
||||||
|
struct NameExpression;
|
||||||
|
struct ScopedStatement;
|
||||||
|
struct AccessExpression;
|
||||||
|
struct ReferenceExpression;
|
||||||
|
using SubExpressionToken = std::variant<
|
||||||
|
std::unique_ptr<NameExpression>,
|
||||||
|
std::unique_ptr<ScopedStatement>,
|
||||||
|
std::unique_ptr<AccessExpression>,
|
||||||
|
std::unique_ptr<Literal>,
|
||||||
|
std::unique_ptr<ReferenceExpression>>;
|
||||||
|
//
|
||||||
|
struct FunctionCallExpression;
|
||||||
|
struct ArrayExpression;
|
||||||
|
using SubExpression = std::variant< // BiaryOperatorExpression is FunctionCallExpression
|
||||||
|
std::unique_ptr<FunctionCallExpression>,
|
||||||
|
std::unique_ptr<SubExpressionToken>>;
|
||||||
|
//
|
||||||
|
enum class LoopControlExpression {
|
||||||
|
Break,
|
||||||
|
Continue,
|
||||||
|
};
|
||||||
|
//
|
||||||
|
struct ReturnExpression;
|
||||||
|
using PrefixedExpression = std::variant<
|
||||||
|
std::unique_ptr<ReturnExpression>,
|
||||||
|
std::unique_ptr<LoopControlExpression>,
|
||||||
|
std::unique_ptr<Block>>;
|
||||||
|
//
|
||||||
|
struct LambdaFunction;
|
||||||
|
struct TypeConstructor;
|
||||||
|
using Expression = std::variant<
|
||||||
|
std::unique_ptr<LambdaFunction>,
|
||||||
|
std::unique_ptr<TypeConstructor>,
|
||||||
|
std::unique_ptr<PrefixedExpression>,
|
||||||
|
std::unique_ptr<SubExpression>>;
|
||||||
|
//
|
||||||
|
struct TupleExpression;
|
||||||
|
struct VariantExpression;
|
||||||
|
using SuperExpression = std::variant<
|
||||||
|
std::unique_ptr<FlowControl>,
|
||||||
|
std::unique_ptr<TupleExpression>,
|
||||||
|
std::unique_ptr<VariantExpression>,
|
||||||
|
std::unique_ptr<ArrayExpression>,
|
||||||
|
std::unique_ptr<Expression>>;
|
||||||
|
//
|
||||||
|
|
||||||
|
struct ScopedStatement;
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
struct ReferenceExpression;
|
||||||
|
|
||||||
|
// Other expressions
|
||||||
|
|
||||||
|
struct FunctionCallExpression;
|
||||||
|
|
||||||
|
struct TupleExpression;
|
||||||
|
struct VariantExpression;
|
||||||
|
struct ReturnExpression;
|
||||||
|
struct TypeConstructorParameter;
|
||||||
|
struct TypeConstructor;
|
||||||
|
struct LambdaFunction;
|
||||||
|
struct ArrayExpression;
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
struct PartitionName {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<AnyIdentifier> path; // name is last element of path
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NameExpression;
|
||||||
|
struct TupleName;
|
||||||
|
struct VariantName;
|
||||||
|
struct AnnotatedName;
|
||||||
|
|
||||||
|
// // ScopedAnyName <-> AnyName
|
||||||
|
using AnyName = std::variant<
|
||||||
|
std::unique_ptr<AnnotatedName>,
|
||||||
|
std::unique_ptr<TupleName>,
|
||||||
|
std::unique_ptr<VariantName>>;
|
||||||
|
|
||||||
|
using ScopedAnyName = AnyName;
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
struct FunctionType;
|
||||||
|
struct TupleType;
|
||||||
|
struct VariantType;
|
||||||
|
struct TypeExpression;
|
||||||
|
struct TypeExpression;
|
||||||
|
|
||||||
|
using Constructor = std::string;
|
||||||
|
|
||||||
|
// // ScopedAnyType <-> AnyType
|
||||||
|
using AnyType = std::variant<
|
||||||
|
std::unique_ptr<TypeExpression>,
|
||||||
|
std::unique_ptr<TupleType>,
|
||||||
|
std::unique_ptr<VariantType>,
|
||||||
|
std::unique_ptr<FunctionType>>;
|
||||||
|
|
||||||
|
using ScopedAnyType = AnyType;
|
||||||
|
|
||||||
|
struct ExtendedScopedAnyType;
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
struct ParametrizedTypeclass;
|
||||||
|
|
||||||
|
// TypeclassSubExpression -> ParametrizedTypeclass
|
||||||
|
|
||||||
|
// Typeclass & Type
|
||||||
|
|
||||||
|
struct ParametrizedType;
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
using Pattern = std::variant<
|
||||||
|
std::unique_ptr<NameIdentifier>,
|
||||||
|
std::unique_ptr<Literal>,
|
||||||
|
std::unique_ptr<TypeConstructorPattern>>;
|
||||||
|
|
||||||
|
|
||||||
|
using ScopedPattern = Pattern;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// ----------------- Sources -----------------
|
||||||
|
|
||||||
|
struct SourceFile {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<SourceStatement> statements;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------- Namespaces, partittions -----------------
|
||||||
|
|
||||||
|
struct NamespaceSources {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<NamespaceStatement> statements;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Namespace {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
utils::ClassInternalsModifier modifier;
|
||||||
|
TypeIdentifier type;
|
||||||
|
NamespaceSources scope;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> link_type_id_;
|
||||||
|
std::optional<utils::IdType> link_typeclass_id_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------- Definitions -----------------
|
||||||
|
|
||||||
|
struct ImportStatement {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::optional<TypeIdentifier> name;
|
||||||
|
std::string module_name;
|
||||||
|
std::vector<ImportSymbol> symbols;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AliasDefinitionStatement {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
utils::AliasModifier modifier;
|
||||||
|
TypeIdentifier type;
|
||||||
|
std::vector<AbstractTypeIdentifier> parameters;
|
||||||
|
std::unique_ptr<TypeExpression> value;
|
||||||
|
|
||||||
|
utils::IdType type_id_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VariableDefinitionStatement {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
utils::IsConstModifier modifier;
|
||||||
|
utils::AssignmentModifier assignment_modifier;
|
||||||
|
AnyName name;
|
||||||
|
SuperExpression value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionDeclaration {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
bool is_in_interface = false;
|
||||||
|
NameOrOperatorIdentifier name;
|
||||||
|
std::vector<std::unique_ptr<AnnotatedAbstractType>> parameters;
|
||||||
|
std::unique_ptr<FunctionType> type;
|
||||||
|
|
||||||
|
utils::IdType function_id_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionDefinitionStatement {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::unique_ptr<FunctionDefinition> definition;
|
||||||
|
SuperExpression value;
|
||||||
|
|
||||||
|
utils::IdType function_id_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeDefinitionStatement {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
bool is_in_interface = false;
|
||||||
|
utils::ClassModifier modifier;
|
||||||
|
std::unique_ptr<TypeDefinition> definition;
|
||||||
|
AnyType value;
|
||||||
|
|
||||||
|
utils::IdType type_id_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AbstractTypeDefinitionStatement {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
utils::AbstractTypeModifier modifier;
|
||||||
|
std::unique_ptr<AnnotatedType> type;
|
||||||
|
|
||||||
|
utils::IdType type_id_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeclassDefinitionStatement {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::unique_ptr<TypeDefinition> definition;
|
||||||
|
std::vector<std::pair<utils::ClassInternalsModifier,
|
||||||
|
std::unique_ptr<FunctionDeclaration>>> requirements;
|
||||||
|
|
||||||
|
utils::IdType typeclass_id_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PartitionStatement {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
utils::PartitionModifier modifier;
|
||||||
|
PartitionName name;
|
||||||
|
SuperExpression value;
|
||||||
|
|
||||||
|
utils::IdType executable_id_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Definition parts -----------------
|
||||||
|
|
||||||
|
struct FunctionDefinition {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
NameOrOperatorIdentifier name;
|
||||||
|
std::vector<NameIdentifier> arguments;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeDefinition {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::unique_ptr<AnnotatedType> type;
|
||||||
|
std::vector<std::unique_ptr<AnnotatedAbstractType>> parameters;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnyAnnotatedType {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
AnyTypeIdentifier type;
|
||||||
|
std::vector<std::unique_ptr<ParametrizedTypeclass>> typeclasses;
|
||||||
|
|
||||||
|
utils::IdType graph_id_ = 0; // for types
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------- Flow control -----------------
|
||||||
|
|
||||||
|
struct TypeConstructorPatternParameter {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::optional<NameIdentifier> name;
|
||||||
|
ScopedPattern value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeConstructorPattern {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::unique_ptr<TypeExpression> constructor;
|
||||||
|
std::vector<TypeConstructorPatternParameter> parameters;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MatchCase {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
Pattern value;
|
||||||
|
std::optional<Expression> condition;
|
||||||
|
std::optional<Expression> statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Match {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
Expression value;
|
||||||
|
std::vector<MatchCase> matches;
|
||||||
|
|
||||||
|
bool is_consuming_value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Condition {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<Expression> conditions; // if, elif
|
||||||
|
std::vector<Expression> statements; // if, elif, else
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DoWhileLoop {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
Expression condition;
|
||||||
|
Expression statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WhileLoop {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
Expression condition;
|
||||||
|
Expression statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ForLoop {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
utils::IsConstModifier variable_modifier;
|
||||||
|
AnyName variable;
|
||||||
|
Expression interval;
|
||||||
|
Expression statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LoopLoop {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
Expression statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------- Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
using BlockStatement = std::variant<
|
||||||
|
std::unique_ptr<Expression>,
|
||||||
|
std::unique_ptr<VariableDefinitionStatement>,
|
||||||
|
std::unique_ptr<FlowControl>,
|
||||||
|
std::unique_ptr<PrefixedExpression>>;
|
||||||
|
|
||||||
|
struct Block {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<BlockStatement> statements;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ScopedStatement {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
SuperExpression statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Operators -----------------
|
||||||
|
|
||||||
|
// struct BinaryOperatorExpression {
|
||||||
|
// BaseNode base;
|
||||||
|
//
|
||||||
|
// OperatorIdentifier operator_name;
|
||||||
|
// SubExpression left_expression;
|
||||||
|
// SubExpression right_expression;
|
||||||
|
// size_t precedence = utils::MaxOperatorPrecedence;
|
||||||
|
//
|
||||||
|
// utils::IdType function_id_;
|
||||||
|
// bool is_method_ = false;
|
||||||
|
// };
|
||||||
|
|
||||||
|
struct ReferenceExpression {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
utils::ReferenceModifier reference;
|
||||||
|
std::unique_ptr<ScopedStatement> expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AccessExpression {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::unique_ptr<NameExpression> name;
|
||||||
|
SubExpressionToken id;
|
||||||
|
|
||||||
|
bool is_string_access_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Other Expressions -----------------
|
||||||
|
|
||||||
|
struct FunctionCallExpression {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::optional<std::variant<std::unique_ptr<SubExpressionToken>,
|
||||||
|
std::unique_ptr<TypeExpression>>> prefix;
|
||||||
|
NameOrOperatorIdentifier name;
|
||||||
|
std::vector<std::unique_ptr<TypeExpression>> parameters;
|
||||||
|
std::vector<SubExpression> arguments;
|
||||||
|
|
||||||
|
std::optional<size_t> precedence; // for operators
|
||||||
|
bool is_binary_operator_expression = false; // for operators
|
||||||
|
|
||||||
|
// only one from two is present
|
||||||
|
std::optional<utils::IdType> function_id_;
|
||||||
|
std::optional<utils::IdType> graph_id_; // for type or typeclass
|
||||||
|
|
||||||
|
std::optional<std::string> abstract_type_name_; // for typeclasses
|
||||||
|
|
||||||
|
bool is_method_of_first_argument_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TupleExpression {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<SubExpression> expressions;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VariantExpression {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<SubExpression> expressions;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ReturnExpression {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
Expression expression;
|
||||||
|
|
||||||
|
bool is_from_definition = false; // from definition or from current block
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeConstructorParameter {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::optional<NameIdentifier> name;
|
||||||
|
std::optional<utils::AssignmentModifier> asignment_modifier;
|
||||||
|
SubExpression value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeConstructor {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::unique_ptr<TypeExpression> constructor;
|
||||||
|
std::vector<TypeConstructorParameter> parameters;
|
||||||
|
|
||||||
|
bool is_allocated_on_heap = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LambdaFunction {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<AnnotatedAbstractType>> parameters;
|
||||||
|
std::vector<NameIdentifier> arguments;
|
||||||
|
Expression expression;
|
||||||
|
|
||||||
|
std::vector<utils::IdType> argument_graph_ids_;
|
||||||
|
utils::IdType return_type_graph_id_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ArrayExpression {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<SubExpression> elements;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Name -----------------
|
||||||
|
|
||||||
|
struct NameExpression {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<NameIdentifier> names;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TupleName {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<ScopedAnyName> names;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VariantName {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<ScopedAnyName> names;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnnotatedName {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
NameIdentifier name;
|
||||||
|
std::optional<ScopedAnyType> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------- Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type -----------------
|
||||||
|
|
||||||
|
struct FunctionType {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<ScopedAnyType> types;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TupleType {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::optional<Constructor> type;
|
||||||
|
std::vector<std::pair<std::optional<NameIdentifier>, std::unique_ptr<ExtendedScopedAnyType>>> entities;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VariantType {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::optional<Constructor> type;
|
||||||
|
std::vector<std::variant<Constructor, std::unique_ptr<TupleType>>> constructors;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ParametrizedType {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
AnyTypeIdentifier type;
|
||||||
|
std::vector<std::unique_ptr<TypeExpression>> parameters;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> type_id_; // std::nullopt, if it is namespace without type
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeExpression {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<ParametrizedType> path;
|
||||||
|
ParametrizedType type;
|
||||||
|
|
||||||
|
std::optional<size_t> array_size; // if array; 0 - dynamic size
|
||||||
|
|
||||||
|
std::optional<utils::IdType> type_id_;
|
||||||
|
std::optional<utils::IdType> constructor_id_;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExtendedScopedAnyType {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::vector<utils::ReferenceModifier> references;
|
||||||
|
AnyType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Typeclass -----------------
|
||||||
|
|
||||||
|
struct ParametrizedTypeclass {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
TypeclassIdentifier typeclass;
|
||||||
|
std::vector<std::unique_ptr<TypeExpression>> parameters;
|
||||||
|
|
||||||
|
utils::IdType typeclass_id_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------- Comments [IGNORE] -----------------
|
||||||
|
// ----------------- Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
struct FloatNumberLiteral {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
double value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NumberLiteral {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
int64_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringLiteral {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
std::string value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CharLiteral {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
char value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UnitLiteral {
|
||||||
|
BaseNode base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoolLiteral {
|
||||||
|
BaseNode base;
|
||||||
|
|
||||||
|
bool value;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace interpereter::tokens
|
||||||
142
include/link_symbols_visitor.hpp
Normal file
142
include/link_symbols_visitor.hpp
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "definitions.hpp"
|
||||||
|
#include "error_handling.hpp"
|
||||||
|
#include "typeclass_graph.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
#include "visitor.hpp"
|
||||||
|
#include "global_info.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
// TODO, (maybe add VisitSourceFile?)
|
||||||
|
class LinkSymbolsVisitor : public Visitor {
|
||||||
|
public:
|
||||||
|
explicit LinkSymbolsVisitor(info::GlobalInfo& global_info)
|
||||||
|
: namespace_visitor_(global_info.CreateVisitor()),
|
||||||
|
global_info_(global_info),
|
||||||
|
typeclass_graph_(*global_info.GetTypeclassGraph()) {}
|
||||||
|
|
||||||
|
void VisitSourceFile(SourceFile* source_file) override {
|
||||||
|
Visitor::Visit(source_file);
|
||||||
|
namespace_visitor_.GetTypeclassGraph()->CalculateGraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
// // void Visit(SourceFile* node) override;
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
// // void Visit(NamespaceSources* node) override;
|
||||||
|
void Visit(Namespace* node) override;
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
// // void Visit(ImportStatement* node) override;
|
||||||
|
// // void Visit(AliasDefinitionStatement* node) override;
|
||||||
|
// // void Visit(VariableDefinitionStatement* node) override;
|
||||||
|
// // void Visit(FunctionDeclaration* node) override;
|
||||||
|
// // void Visit(FunctionDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeDefinitionStatement* node) override;
|
||||||
|
// // void Visit(AbstractTypeDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeclassDefinitionStatement* node) override;
|
||||||
|
// // void Visit(PartitionStatement* node) override;
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
// // void Visit(FunctionDefinition* node) override;
|
||||||
|
// // void Visit(TypeDefinition* node) override;
|
||||||
|
// // void Visit(AnyAnnotatedType* node) override;
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
// // void Visit(TypeConstructorPatternParameter* node) override;
|
||||||
|
// // void Visit(TypeConstructorPattern* node) override;
|
||||||
|
// // void Visit(MatchCase* node) override;
|
||||||
|
// // void Visit(Match* node) override;
|
||||||
|
// // void Visit(Condition* node) override;
|
||||||
|
// // void Visit(DoWhileLoop* node) override;
|
||||||
|
// // void Visit(WhileLoop* node) override;
|
||||||
|
// // void Visit(ForLoop* node) override;
|
||||||
|
// // void Visit(LoopLoop* node) override;
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
// // void Visit(Block* node) override;
|
||||||
|
// // void Visit(ScopedStatement* node) override;
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
// // void Visit(ReferenceExpression* node) override;
|
||||||
|
// // void Visit(AccessExpression* node) override;
|
||||||
|
|
||||||
|
// Simple Expressions
|
||||||
|
|
||||||
|
// // void Visit(FunctionCallExpression* node) override;
|
||||||
|
|
||||||
|
// // void Visit(TupleExpression* node) override;
|
||||||
|
// // void Visit(VariantExpression* node) override;
|
||||||
|
// // void Visit(ReturnExpression* node) override;
|
||||||
|
// // void Visit(TypeConstructorParameter* node) override;
|
||||||
|
// // void Visit(TypeConstructor* node) override;
|
||||||
|
// // void Visit(LambdaFunction* node) override;
|
||||||
|
// // void Visit(ArrayExpression* node) override;
|
||||||
|
|
||||||
|
// // void Visit(LoopControlExpression& node) override; // enum
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
// // void Visit(PartitionName* node) override;
|
||||||
|
// // void Visit(NameExpression* node) override;
|
||||||
|
// // void Visit(TupleName* node) override;
|
||||||
|
// // void Visit(VariantName* node) override;
|
||||||
|
// // void Visit(AnnotatedName* node) override;
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
// // void Visit(FunctionType* node) override;
|
||||||
|
// // void Visit(TupleType* node) override;
|
||||||
|
// // void Visit(VariantType* node) override;
|
||||||
|
void Visit(TypeExpression* node) override;
|
||||||
|
|
||||||
|
// // void Visit(ExtendedScopedAnyType* node) override;
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
void Visit(ParametrizedTypeclass* node) override;
|
||||||
|
|
||||||
|
// Typeclass & Type
|
||||||
|
|
||||||
|
// // void Visit(ParametrizedType* node) override;
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
// // void Visit(std::string* node) override; // std::string
|
||||||
|
|
||||||
|
// // void Visit(FloatNumberLiteral* node) override;
|
||||||
|
// // void Visit(NumberLiteral* node) override;
|
||||||
|
// // void Visit(StringLiteral* node) override;
|
||||||
|
// // void Visit(CharLiteral* node) override;
|
||||||
|
// // void Visit(BoolLiteral* node) override;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void AddTypeFunctionsToTypeclassGraph(utils::IdType type_id,
|
||||||
|
utils::IdType graph_id,
|
||||||
|
utils::ClassInternalsModifier namespace_modifier,
|
||||||
|
const BaseNode& base_node);
|
||||||
|
|
||||||
|
private:
|
||||||
|
info::GlobalInfo::NamespaceVisitor namespace_visitor_;
|
||||||
|
info::GlobalInfo& global_info_;
|
||||||
|
info::TypeclassGraph& typeclass_graph_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
36
include/node.hpp
Normal file
36
include/node.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "parse_tree.hpp"
|
||||||
|
|
||||||
|
namespace info {
|
||||||
|
class GlobalInfo;
|
||||||
|
class Context;
|
||||||
|
} // namespace info
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
class Visitor;
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
//public:
|
||||||
|
//Node(info::GlobalInfo& global_info) : global_info_(global_info) {}
|
||||||
|
|
||||||
|
// ?? not needed ?? virtual void Accept(Visitor* visitor);
|
||||||
|
|
||||||
|
/* ------------ use visitor instead ------------
|
||||||
|
virtual void build(parser::ParseTree::Cursor& cursor) = 0; // build tree from parse tree
|
||||||
|
|
||||||
|
virtual void find_symbols() = 0; // find types, typeclasses, namespaces, ..
|
||||||
|
virtual void assign_types() = 0; // typecheck
|
||||||
|
virtual void execute(info::Context& context) = 0; // execute part of tree
|
||||||
|
*/
|
||||||
|
/*private:
|
||||||
|
size_t start_position_; // ??
|
||||||
|
size_t end_position_; // ??
|
||||||
|
Node* parent_; // ??
|
||||||
|
info::GlobalInfo& global_info_;*/
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
132
include/parse_token_types.hpp
Normal file
132
include/parse_token_types.hpp
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace parser::tokens {
|
||||||
|
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
const std::string SourceFile = "source_file";
|
||||||
|
const std::string SourceStatement = "source_statement";
|
||||||
|
const std::string NamespaceSources = "namespace_sources";
|
||||||
|
const std::string NamespaceStatement = "namespace_statement";
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
const std::string Namespace = "namespace";
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
const std::string ImportStatement = "import_statement";
|
||||||
|
const std::string AliasDefinitionStatement = "alias_definition_statement";
|
||||||
|
const std::string VariableDefinitionStatement = "variable_definition_statement";
|
||||||
|
const std::string FunctionDeclaration = "function_declaration";
|
||||||
|
const std::string FunctionDefinitionStatement = "function_definition_statement";
|
||||||
|
const std::string TypeDefinitionStatement = "type_definition_statement";
|
||||||
|
const std::string AbstractTypeDefinitionStatement = "abstract_type_definition_statement";
|
||||||
|
const std::string TypeclassDefinitionStatement = "typeclass_definition_statement";
|
||||||
|
const std::string PartitionStatement = "partition_statement";
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
const std::string ImportSymbol = "import_symbol";
|
||||||
|
const std::string FunctionDefinition = "function_definition";
|
||||||
|
const std::string TypeDefinition = "type_definition";
|
||||||
|
const std::string AnnotatedAbstractType = "annotated_abstract_type";
|
||||||
|
const std::string AnnotatedType = "annotated_type";
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
const std::string TypeConstructorPatternParameter = "type_constructor_pattern_parameter";
|
||||||
|
const std::string TypeConstructorPattern = "type_constructor_pattern";
|
||||||
|
const std::string ScopedPattern = "scoped_pattern";
|
||||||
|
const std::string Pattern = "pattern";
|
||||||
|
const std::string MatchCase = "match_case";
|
||||||
|
const std::string Match = "match";
|
||||||
|
const std::string Condition = "condition";
|
||||||
|
const std::string DoWhileLoop = "do_while_loop";
|
||||||
|
const std::string WhileLoop = "while_loop";
|
||||||
|
const std::string ForLoop = "for_loop";
|
||||||
|
const std::string LoopLoop = "loop_loop";
|
||||||
|
const std::string FlowControl = "flow_control";
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
const std::string BlockStatement = "block_statement";
|
||||||
|
const std::string Block = "block";
|
||||||
|
const std::string SubExpressionToken = "subexpression_token";
|
||||||
|
const std::string SubExpression = "subexpression";
|
||||||
|
const std::string PrefixedExpression = "prefixed_expression";
|
||||||
|
const std::string Expression = "expression";
|
||||||
|
const std::string SuperExpression = "superexpression";
|
||||||
|
const std::string ScopedStatement = "scoped_statement";
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
const std::string BinaryOperatorExpression = "binary_operator_expression";
|
||||||
|
const std::string ReferenceExpression = "reference_expression";
|
||||||
|
const std::string AccessExpression = "access_expression";
|
||||||
|
|
||||||
|
// Other expressions
|
||||||
|
|
||||||
|
const std::string FunctionArgument = "function_argument";
|
||||||
|
const std::string FunctionCallExpression = "function_call_expression";
|
||||||
|
const std::string TupleExpression = "tuple_expression";
|
||||||
|
const std::string VariantExpression = "variant_expression";
|
||||||
|
const std::string ReturnExpression = "return_expression";
|
||||||
|
const std::string TypeConstructorParameter = "type_constructor_parameter";
|
||||||
|
const std::string TypeConstructor = "type_constructor";
|
||||||
|
const std::string LambdaFunction = "lambda_function";
|
||||||
|
const std::string ArrayExpression = "array_expression";
|
||||||
|
const std::string LoopControlExpression = "loop_control_expression";
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
const std::string PartitionName = "partition_name";
|
||||||
|
const std::string NameExpression = "name_expression";
|
||||||
|
const std::string TupleName = "tuple_name";
|
||||||
|
const std::string VariantName = "variant_name";
|
||||||
|
const std::string AnnotatedName = "annotated_name";
|
||||||
|
const std::string AnyName = "any_name";
|
||||||
|
const std::string ScopedAnyName = "scoped_any_name";
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
const std::string FunctionType = "function_type";
|
||||||
|
const std::string TupleType = "tuple_type";
|
||||||
|
const std::string VariantType = "variant_type";
|
||||||
|
const std::string TypeExpression = "type_expression";
|
||||||
|
const std::string Constructor = "constructor";
|
||||||
|
const std::string AnyType = "any_type";
|
||||||
|
const std::string ScopedAnyType = "scoped_any_type";
|
||||||
|
const std::string ExtendedScopedAnyType = "extended_scoped_any_type";
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
const std::string ParametrizedTypeclass = "parametrized_typeclass";
|
||||||
|
|
||||||
|
|
||||||
|
// Typeclass & Type
|
||||||
|
|
||||||
|
const std::string ParametrizedType = "parametrized_type";
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
const std::string TypeclassIdentifier = "typeclass_identifier";
|
||||||
|
const std::string NameIdentifier = "name_identifier";
|
||||||
|
const std::string TypeIdentifier = "type_identifier";
|
||||||
|
const std::string AbstractTypeIdentifier = "abstract_type_identifier";
|
||||||
|
const std::string OperatorIdentifier = "operator";
|
||||||
|
|
||||||
|
const std::string FloatNumberLiteral = "float_number_literal";
|
||||||
|
const std::string NumberLiteral = "number_literal";
|
||||||
|
const std::string StringLiteral = "string_literal";
|
||||||
|
const std::string CharLiteral = "char_literal";
|
||||||
|
const std::string UnitLiteral = "unit_literal";
|
||||||
|
const std::string BoolLiteral = "bool_literal";
|
||||||
|
|
||||||
|
const std::string Literal = "literal";
|
||||||
|
|
||||||
|
} // namespace parser::tokens
|
||||||
142
include/parse_tree.hpp
Normal file
142
include/parse_tree.hpp
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "tree_sitter/api.h"
|
||||||
|
|
||||||
|
extern "C" const TSLanguage* tree_sitter_LANG();
|
||||||
|
|
||||||
|
namespace parser {
|
||||||
|
|
||||||
|
class ParseTree {
|
||||||
|
public:
|
||||||
|
class Node {
|
||||||
|
public:
|
||||||
|
Node() : uninitialized_(true) {
|
||||||
|
for (unsigned int& i : node_.context) {
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
node_.id = nullptr;
|
||||||
|
node_.tree = nullptr;
|
||||||
|
|
||||||
|
source_ = nullptr;
|
||||||
|
};
|
||||||
|
Node(const TSNode& node, const std::string* source) : uninitialized_(false), node_(node), source_(source) {}
|
||||||
|
|
||||||
|
std::string GetType() {
|
||||||
|
return ts_node_type(node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<size_t, size_t> GetStartPoint() {
|
||||||
|
TSPoint point = ts_node_start_point(node_);
|
||||||
|
return {point.row, point.column};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<size_t, size_t> GetEndPoint() {
|
||||||
|
TSPoint point = ts_node_end_point(node_);
|
||||||
|
return {point.row, point.column};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetAsSExpression() {
|
||||||
|
return ts_node_string(node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetValue() { // from source
|
||||||
|
size_t start = ts_node_start_byte(node_);
|
||||||
|
size_t end = ts_node_end_byte(node_);
|
||||||
|
return source_->substr(start, end - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsNull() {
|
||||||
|
return ts_node_is_null(node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsNamed() {
|
||||||
|
return ts_node_is_named(node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsMissing() {
|
||||||
|
return ts_node_is_missing(node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsExtra() { // comments, etc.
|
||||||
|
return ts_node_is_extra(node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasError() {
|
||||||
|
return ts_node_has_error(node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node NthChild(size_t n) {
|
||||||
|
return Node(ts_node_child(node_, n), source_);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ChildCount() {
|
||||||
|
return ts_node_child_count(node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node NthNamedChild(size_t n) {
|
||||||
|
return Node(ts_node_named_child(node_, n), source_);
|
||||||
|
}
|
||||||
|
size_t NamedChildCount() {
|
||||||
|
return ts_node_named_child_count(node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node ChildByFieldName(const std::string& name) {
|
||||||
|
return Node(ts_node_child_by_field_name(node_, name.c_str(), name.size()), source_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node PreviousSibling() {
|
||||||
|
return Node(ts_node_prev_sibling(node_), source_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node PreviousNamedSibling() {
|
||||||
|
return Node(ts_node_prev_named_sibling(node_), source_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node NextSibling() {
|
||||||
|
return Node(ts_node_next_sibling(node_), source_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node NextNamedSibling() {
|
||||||
|
return Node(ts_node_next_named_sibling(node_), source_);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
bool uninitialized_;
|
||||||
|
TSNode node_;
|
||||||
|
const std::string* source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ParseTree(const std::string& source) : source_(source) {
|
||||||
|
TSParser* parser = ts_parser_new();
|
||||||
|
ts_parser_set_language(parser, tree_sitter_LANG());
|
||||||
|
|
||||||
|
tree_ = ts_parser_parse_string(
|
||||||
|
parser,
|
||||||
|
nullptr,
|
||||||
|
source_.c_str(),
|
||||||
|
source_.size());
|
||||||
|
|
||||||
|
ts_parser_delete(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseTree(const ParseTree& parse_tree) : tree_(ts_tree_copy(parse_tree.tree_)), source_(parse_tree.source_) {}
|
||||||
|
|
||||||
|
Node GetRoot() const {
|
||||||
|
return Node(ts_tree_root_node(tree_), &source_);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ParseTree() {
|
||||||
|
ts_tree_delete(tree_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsProperlyParsed() { // TODO: check
|
||||||
|
return !GetRoot().HasError();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
TSTree* tree_;
|
||||||
|
std::string source_; // for token value extraction
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace parser
|
||||||
123
include/print_visitor.hpp
Normal file
123
include/print_visitor.hpp
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
#include "visitor.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
class PrintVisitor : public Visitor {
|
||||||
|
public:
|
||||||
|
explicit PrintVisitor(std::ostream& out) : out_(out) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
void Visit(SourceFile* node) override;
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
void Visit(NamespaceSources* node) override;
|
||||||
|
void Visit(Namespace* node) override;
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
void Visit(ImportStatement* node) override;
|
||||||
|
void Visit(AliasDefinitionStatement* node) override;
|
||||||
|
void Visit(VariableDefinitionStatement* node) override;
|
||||||
|
void Visit(FunctionDeclaration* node) override;
|
||||||
|
void Visit(FunctionDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeDefinitionStatement* node) override;
|
||||||
|
void Visit(AbstractTypeDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeclassDefinitionStatement* node) override;
|
||||||
|
void Visit(PartitionStatement* node) override;
|
||||||
|
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
void Visit(FunctionDefinition* node) override;
|
||||||
|
void Visit(TypeDefinition* node) override;
|
||||||
|
void Visit(AnyAnnotatedType* node) override;
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
void Visit(TypeConstructorPatternParameter* node) override;
|
||||||
|
void Visit(TypeConstructorPattern* node) override;
|
||||||
|
void Visit(MatchCase* node) override;
|
||||||
|
void Visit(Match* node) override;
|
||||||
|
void Visit(Condition* node) override;
|
||||||
|
void Visit(DoWhileLoop* node) override;
|
||||||
|
void Visit(WhileLoop* node) override;
|
||||||
|
void Visit(ForLoop* node) override;
|
||||||
|
void Visit(LoopLoop* node) override;
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
void Visit(Block* node) override;
|
||||||
|
|
||||||
|
void Visit(ScopedStatement* node) override;
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
void Visit(ReferenceExpression* node) override;
|
||||||
|
void Visit(AccessExpression* node) override;
|
||||||
|
|
||||||
|
// Simple Expressions
|
||||||
|
|
||||||
|
void Visit(FunctionCallExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(TupleExpression* node) override;
|
||||||
|
void Visit(VariantExpression* node) override;
|
||||||
|
void Visit(ReturnExpression* node) override;
|
||||||
|
void Visit(TypeConstructorParameter* node) override;
|
||||||
|
void Visit(TypeConstructor* node) override;
|
||||||
|
void Visit(LambdaFunction* node) override;
|
||||||
|
void Visit(ArrayExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(LoopControlExpression& node) override; // enum
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
void Visit(PartitionName* node) override;
|
||||||
|
void Visit(NameExpression* node) override;
|
||||||
|
void Visit(TupleName* node) override;
|
||||||
|
void Visit(VariantName* node) override;
|
||||||
|
void Visit(AnnotatedName* node) override;
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
void Visit(FunctionType* node) override;
|
||||||
|
void Visit(TupleType* node) override;
|
||||||
|
void Visit(VariantType* node) override;
|
||||||
|
void Visit(TypeExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(ExtendedScopedAnyType* node) override;
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
void Visit(ParametrizedTypeclass* node) override;
|
||||||
|
|
||||||
|
// Typeclass & Type
|
||||||
|
|
||||||
|
void Visit(ParametrizedType* node) override;
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
void Visit(std::string* node) override; // std::string
|
||||||
|
|
||||||
|
void Visit(FloatNumberLiteral* node) override;
|
||||||
|
void Visit(NumberLiteral* node) override;
|
||||||
|
void Visit(StringLiteral* node) override;
|
||||||
|
void Visit(CharLiteral* node) override;
|
||||||
|
void Visit(UnitLiteral* node) override;
|
||||||
|
void Visit(BoolLiteral* node) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::ostream& out_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
246
include/type_check_visitor.hpp
Normal file
246
include/type_check_visitor.hpp
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
#include "typeclass_graph.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "contexts.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
#include "visitor.hpp"
|
||||||
|
#include "global_info.hpp"
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
// TODO: class fields and constructors can't be accessed not from associated namespace
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
class TypeCheckVisitor : public Visitor {
|
||||||
|
public:
|
||||||
|
explicit TypeCheckVisitor(info::GlobalInfo& global_info,
|
||||||
|
info::ContextManager<info::type::Type, info::type::TypeManager>& context_manager)
|
||||||
|
: namespace_visitor_(global_info.CreateVisitor()),
|
||||||
|
global_info_(global_info),
|
||||||
|
typeclass_graph_(*global_info.GetTypeclassGraph()),
|
||||||
|
context_manager_(context_manager) {}
|
||||||
|
|
||||||
|
void VisitSourceFile(SourceFile* source_file) override {
|
||||||
|
// init internal type abstrac types
|
||||||
|
for (size_t i = 0; i < info::type::InternalTypesCount; ++i) {
|
||||||
|
info::type::InternalType type = static_cast<info::type::InternalType>(i);
|
||||||
|
Visit(namespace_visitor_.FindAbstractType(info::type::ToString(type)).value()->node);
|
||||||
|
}
|
||||||
|
|
||||||
|
Visit(source_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
void Visit(SourceFile* node) override;
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
void Visit(NamespaceSources* node) override;
|
||||||
|
void Visit(Namespace* node) override;
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
void Visit(ImportStatement* node) override;
|
||||||
|
void Visit(AliasDefinitionStatement* node) override;
|
||||||
|
void Visit(VariableDefinitionStatement* node) override;
|
||||||
|
void Visit(FunctionDeclaration* node) override;
|
||||||
|
void Visit(FunctionDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeDefinitionStatement* node) override;
|
||||||
|
void Visit(AbstractTypeDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeclassDefinitionStatement* node) override;
|
||||||
|
void Visit(PartitionStatement* node) override;
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
void Visit(FunctionDefinition* node) override;
|
||||||
|
void Visit(TypeDefinition* node) override;
|
||||||
|
void Visit(AnyAnnotatedType* node) override;
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
void Visit(TypeConstructorPatternParameter* node) override;
|
||||||
|
void Visit(TypeConstructorPattern* node) override;
|
||||||
|
void Visit(MatchCase* node) override;
|
||||||
|
void Visit(Match* node) override;
|
||||||
|
void Visit(Condition* node) override;
|
||||||
|
void Visit(DoWhileLoop* node) override;
|
||||||
|
void Visit(WhileLoop* node) override;
|
||||||
|
void Visit(ForLoop* node) override;
|
||||||
|
void Visit(LoopLoop* node) override;
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
void Visit(Block* node) override;
|
||||||
|
|
||||||
|
void Visit(ScopedStatement* node) override;
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
void Visit(ReferenceExpression* node) override;
|
||||||
|
void Visit(AccessExpression* node) override;
|
||||||
|
|
||||||
|
// Simple Expressions
|
||||||
|
|
||||||
|
void Visit(FunctionCallExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(TupleExpression* node) override;
|
||||||
|
void Visit(VariantExpression* node) override;
|
||||||
|
void Visit(ReturnExpression* node) override;
|
||||||
|
void Visit(TypeConstructorParameter* node) override;
|
||||||
|
void Visit(TypeConstructor* node) override;
|
||||||
|
void Visit(LambdaFunction* node) override;
|
||||||
|
void Visit(ArrayExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(LoopControlExpression& node) override; // enum
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
void Visit(PartitionName* node) override;
|
||||||
|
void Visit(NameExpression* node) override;
|
||||||
|
void Visit(TupleName* node) override;
|
||||||
|
void Visit(VariantName* node) override;
|
||||||
|
void Visit(AnnotatedName* node) override;
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
void Visit(FunctionType* node) override;
|
||||||
|
void Visit(TupleType* node) override;
|
||||||
|
void Visit(VariantType* node) override;
|
||||||
|
void Visit(TypeExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(ExtendedScopedAnyType* node) override;
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
void Visit(ParametrizedTypeclass* node) override;
|
||||||
|
|
||||||
|
// Typeclass & Type
|
||||||
|
|
||||||
|
void Visit(ParametrizedType* node) override;
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
// // void Visit(std::string* node) override; // std::string
|
||||||
|
|
||||||
|
void Visit(FloatNumberLiteral* node) override;
|
||||||
|
void Visit(NumberLiteral* node) override;
|
||||||
|
void Visit(StringLiteral* node) override;
|
||||||
|
void Visit(CharLiteral* node) override;
|
||||||
|
void Visit(UnitLiteral* node) override;
|
||||||
|
void Visit(BoolLiteral* node) override;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void CollectTypeContext(const ParametrizedType& type,
|
||||||
|
std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
|
||||||
|
void CollectTypeExpressionContext(const TypeExpression& type_expression,
|
||||||
|
std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
|
||||||
|
utils::IdType TypeInContext(utils::IdType type,
|
||||||
|
const std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
|
||||||
|
void CheckPattern(Pattern& node, const BaseNode& base_node);
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<FunctionDeclaration*>
|
||||||
|
FindExpressionMethodAndUpdate(FunctionCallExpression* node,
|
||||||
|
utils::IdType expression_type);
|
||||||
|
|
||||||
|
std::optional<FunctionDeclaration*>
|
||||||
|
FindTypeFunctionAndUpdate(FunctionCallExpression* node,
|
||||||
|
TypeExpression* type_node,
|
||||||
|
std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
|
||||||
|
std::optional<FunctionDeclaration*> FindFunctionAndUpdate(FunctionCallExpression* node);
|
||||||
|
|
||||||
|
std::optional<FunctionDeclaration*>
|
||||||
|
FindAbstractTypeTypeclassFunctionAndUpdate(
|
||||||
|
FunctionCallExpression* node,
|
||||||
|
info::type::AbstractType* abstract_type,
|
||||||
|
bool is_method);
|
||||||
|
|
||||||
|
std::optional<FunctionDeclaration*>
|
||||||
|
FindDefinedTypeFunctionAndUpdate(
|
||||||
|
FunctionCallExpression* node,
|
||||||
|
info::definition::AnyType* defined_type,
|
||||||
|
utils::IdType type,
|
||||||
|
bool is_method);
|
||||||
|
|
||||||
|
void ResetReturnedAndBroughtTypes() {
|
||||||
|
if (returned_type_.has_value()) {
|
||||||
|
all_branches_returned_value_ = false;
|
||||||
|
}
|
||||||
|
if (brought_type_.has_value()) {
|
||||||
|
all_branches_brought_value_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddGraphIdLocalTypes(utils::IdType graph_id, utils::IdType type) {
|
||||||
|
std::unordered_set<utils::IdType> requirement_graph_ids = typeclass_graph_.GetDependenciesSet(graph_id);
|
||||||
|
requirement_graph_ids.insert(graph_id);
|
||||||
|
|
||||||
|
for (auto& requirement_graph_id : requirement_graph_ids) {
|
||||||
|
context_manager_.DefineLocalType(typeclass_graph_.GetVertex(requirement_graph_id).name, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType AddGraphIdLocalAbstractTypes(utils::IdType graph_id) {
|
||||||
|
std::unordered_set<utils::IdType> requirement_graph_ids = typeclass_graph_.GetDependenciesSet(graph_id);
|
||||||
|
requirement_graph_ids.insert(graph_id);
|
||||||
|
|
||||||
|
utils::IdType abstract_type = context_manager_.AddValue(
|
||||||
|
info::type::AbstractType(utils::AbstractTypeModifier::Abstract,
|
||||||
|
graph_id,
|
||||||
|
typeclass_graph_),
|
||||||
|
utils::ValueType::Tmp);
|
||||||
|
|
||||||
|
for (auto& requirement_graph_id : requirement_graph_ids) {
|
||||||
|
context_manager_.DefineLocalType(typeclass_graph_.GetVertex(requirement_graph_id).name, abstract_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return abstract_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisitDefinedType(info::definition::AnyType* defined_type,
|
||||||
|
const std::unordered_map<std::string, utils::IdType>& context) {
|
||||||
|
Visitor::Visit(defined_type->node->value);
|
||||||
|
current_type_ = TypeInContext(current_type_, context);
|
||||||
|
current_type_ =
|
||||||
|
context_manager_.AddValue(info::type::DefinedType(defined_type->node->type_id_,
|
||||||
|
current_type_,
|
||||||
|
defined_type->modifier,
|
||||||
|
context_manager_.GetValueManager()),
|
||||||
|
utils::ValueType::Tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
info::GlobalInfo::NamespaceVisitor namespace_visitor_;
|
||||||
|
info::GlobalInfo& global_info_;
|
||||||
|
info::TypeclassGraph& typeclass_graph_;
|
||||||
|
info::ContextManager<info::type::Type, info::type::TypeManager>& context_manager_;
|
||||||
|
|
||||||
|
std::unordered_set<utils::IdType> type_namespaces_;
|
||||||
|
utils::IdType current_type_;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> returned_type_;
|
||||||
|
bool all_branches_returned_value_ = true;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> brought_type_;
|
||||||
|
bool all_branches_brought_value_ = true;
|
||||||
|
|
||||||
|
std::unordered_map<info::type::InternalType, utils::IdType> internal_to_abstract_type_;
|
||||||
|
|
||||||
|
std::optional<utils::IsConstModifier> is_const_definition_;
|
||||||
|
|
||||||
|
bool is_in_statement_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
91
include/typeclass_graph.hpp
Normal file
91
include/typeclass_graph.hpp
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "utils.hpp"
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
|
||||||
|
namespace info {
|
||||||
|
|
||||||
|
// move constructor parameters ??
|
||||||
|
class TypeclassGraph {
|
||||||
|
public:
|
||||||
|
enum class Modifier {
|
||||||
|
Typeclass = 0,
|
||||||
|
Type = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionInfo {
|
||||||
|
utils::ClassInternalsModifier modifier = utils::ClassInternalsModifier::Static;
|
||||||
|
interpreter::tokens::FunctionDeclaration* declaration = nullptr;
|
||||||
|
std::optional<interpreter::tokens::FunctionDefinitionStatement*> definition;
|
||||||
|
bool is_defined_in_owner = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vertex { // make constructor ??
|
||||||
|
std::string name;
|
||||||
|
std::unordered_map<std::string, FunctionInfo> functions;
|
||||||
|
std::unordered_set<std::string> dependencies; // TODO: parameters
|
||||||
|
interpreter::tokens::BaseNode* base_node; // for error handling
|
||||||
|
std::optional<utils::IdType> type_id; // for defined types
|
||||||
|
Modifier modifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
utils::IdType AddVertex(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<std::string>& dependencies,
|
||||||
|
const std::vector<std::pair<std::string, std::pair<utils::ClassInternalsModifier, interpreter::tokens::FunctionDeclaration*>>>& function_declarations,
|
||||||
|
const std::vector<std::pair<std::string, interpreter::tokens::FunctionDefinitionStatement*>>& function_definitions,
|
||||||
|
interpreter::tokens::BaseNode* base_node,
|
||||||
|
Modifier modifier);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FindFunctionTypeclass(const std::string& name);
|
||||||
|
|
||||||
|
bool IsFunctionInVertex(const std::string& name, utils::IdType vertex_id) {
|
||||||
|
return verticles_[vertex_id].functions.count(name) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if vertex_id == std::nullopt, info can be not complete
|
||||||
|
std::optional<FunctionInfo*> GetFunctionInfo(const std::string& name,
|
||||||
|
std::optional<utils::IdType> vertex_id);
|
||||||
|
|
||||||
|
const Vertex& GetVertex(utils::IdType id) {
|
||||||
|
return verticles_.at(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Vertex*> GetTypeVertex(utils::IdType id) {
|
||||||
|
if (verticles_.at(id).modifier == Modifier::Type) {
|
||||||
|
return &verticles_[id];
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cache ??
|
||||||
|
std::unordered_set<utils::IdType> GetDependenciesSet(utils::IdType id);
|
||||||
|
std::vector<utils::IdType> GetDependenciesVector(utils::IdType id);
|
||||||
|
|
||||||
|
const std::unordered_map<std::string, FunctionInfo>& GetVertexFunctions(utils::IdType id) {
|
||||||
|
return verticles_.at(id).functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsCalculated() {
|
||||||
|
return is_calculated_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// can exit by typecheck error
|
||||||
|
void CalculateGraph();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, utils::IdType> method_to_vertex_;
|
||||||
|
std::unordered_map<std::string, utils::IdType> name_to_typeclass_;
|
||||||
|
std::vector<Vertex> verticles_;
|
||||||
|
|
||||||
|
bool is_calculated_ = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace info
|
||||||
126
include/typed_print_visitor.hpp
Normal file
126
include/typed_print_visitor.hpp
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "visitor.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "contexts.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
class TypedPrintVisitor : public Visitor {
|
||||||
|
public:
|
||||||
|
explicit TypedPrintVisitor(std::ostream& out,
|
||||||
|
info::ContextManager<info::type::Type, info::type::TypeManager>& context_manager)
|
||||||
|
: out_(out), context_manager_(context_manager) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
void Visit(SourceFile* node) override;
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
void Visit(NamespaceSources* node) override;
|
||||||
|
void Visit(Namespace* node) override;
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
void Visit(ImportStatement* node) override;
|
||||||
|
void Visit(AliasDefinitionStatement* node) override;
|
||||||
|
void Visit(VariableDefinitionStatement* node) override;
|
||||||
|
void Visit(FunctionDeclaration* node) override;
|
||||||
|
void Visit(FunctionDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeDefinitionStatement* node) override;
|
||||||
|
void Visit(AbstractTypeDefinitionStatement* node) override;
|
||||||
|
void Visit(TypeclassDefinitionStatement* node) override;
|
||||||
|
void Visit(PartitionStatement* node) override;
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
void Visit(FunctionDefinition* node) override;
|
||||||
|
void Visit(TypeDefinition* node) override;
|
||||||
|
void Visit(AnyAnnotatedType* node) override;
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
void Visit(TypeConstructorPatternParameter* node) override;
|
||||||
|
void Visit(TypeConstructorPattern* node) override;
|
||||||
|
void Visit(MatchCase* node) override;
|
||||||
|
void Visit(Match* node) override;
|
||||||
|
void Visit(Condition* node) override;
|
||||||
|
void Visit(DoWhileLoop* node) override;
|
||||||
|
void Visit(WhileLoop* node) override;
|
||||||
|
void Visit(ForLoop* node) override;
|
||||||
|
void Visit(LoopLoop* node) override;
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
void Visit(Block* node) override;
|
||||||
|
|
||||||
|
void Visit(ScopedStatement* node) override;
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
void Visit(ReferenceExpression* node) override;
|
||||||
|
void Visit(AccessExpression* node) override;
|
||||||
|
|
||||||
|
// Simple Expressions
|
||||||
|
|
||||||
|
void Visit(FunctionCallExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(TupleExpression* node) override;
|
||||||
|
void Visit(VariantExpression* node) override;
|
||||||
|
void Visit(ReturnExpression* node) override;
|
||||||
|
void Visit(TypeConstructorParameter* node) override;
|
||||||
|
void Visit(TypeConstructor* node) override;
|
||||||
|
void Visit(LambdaFunction* node) override;
|
||||||
|
void Visit(ArrayExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(LoopControlExpression& node) override; // enum
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
void Visit(PartitionName* node) override;
|
||||||
|
void Visit(NameExpression* node) override;
|
||||||
|
void Visit(TupleName* node) override;
|
||||||
|
void Visit(VariantName* node) override;
|
||||||
|
void Visit(AnnotatedName* node) override;
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
void Visit(FunctionType* node) override;
|
||||||
|
void Visit(TupleType* node) override;
|
||||||
|
void Visit(VariantType* node) override;
|
||||||
|
void Visit(TypeExpression* node) override;
|
||||||
|
|
||||||
|
void Visit(ExtendedScopedAnyType* node) override;
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
void Visit(ParametrizedTypeclass* node) override;
|
||||||
|
|
||||||
|
// Typeclass & Type
|
||||||
|
|
||||||
|
void Visit(ParametrizedType* node) override;
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
void Visit(std::string* node) override; // std::string
|
||||||
|
|
||||||
|
void Visit(FloatNumberLiteral* node) override;
|
||||||
|
void Visit(NumberLiteral* node) override;
|
||||||
|
void Visit(StringLiteral* node) override;
|
||||||
|
void Visit(CharLiteral* node) override;
|
||||||
|
void Visit(UnitLiteral* node) override;
|
||||||
|
void Visit(BoolLiteral* node) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::ostream& out_;
|
||||||
|
info::ContextManager<info::type::Type, info::type::TypeManager>& context_manager_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
401
include/types.hpp
Normal file
401
include/types.hpp
Normal file
|
|
@ -0,0 +1,401 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "error_handling.hpp"
|
||||||
|
#include "typeclass_graph.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
namespace info::type {
|
||||||
|
|
||||||
|
// TODO: move in constructors
|
||||||
|
|
||||||
|
class TypeManager;
|
||||||
|
|
||||||
|
class AbstractType { // latter will be found in context
|
||||||
|
public:
|
||||||
|
AbstractType(utils::AbstractTypeModifier modifier,
|
||||||
|
utils::IdType graph_id,
|
||||||
|
info::TypeclassGraph& typeclass_graph)
|
||||||
|
: modifier_(modifier),
|
||||||
|
graph_id_(graph_id),
|
||||||
|
typeclass_graph_(typeclass_graph) {}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> InContext(const std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
bool Same(const AbstractType& type) const;
|
||||||
|
bool operator<(const AbstractType& type) const;
|
||||||
|
bool operator>(const AbstractType& type) const;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const;
|
||||||
|
|
||||||
|
utils::IdType GetGraphId() {
|
||||||
|
return graph_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasTypeclass(utils::IdType graph_id) { // TODO: cache dependencies set
|
||||||
|
return graph_id == graph_id_ || typeclass_graph_.GetDependenciesSet(graph_id_).count(graph_id) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToString() {
|
||||||
|
return "Abstract " + std::to_string(graph_id_);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
utils::AbstractTypeModifier modifier_;
|
||||||
|
utils::IdType graph_id_;
|
||||||
|
info::TypeclassGraph& typeclass_graph_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DefinedType {
|
||||||
|
public:
|
||||||
|
DefinedType() = default;
|
||||||
|
DefinedType(utils::IdType type_id,
|
||||||
|
utils::IdType type,
|
||||||
|
utils::ClassModifier class_modifier,
|
||||||
|
TypeManager* type_manager)
|
||||||
|
: type_id_(type_id), type_(type), class_modifier_(class_modifier), type_manager_(type_manager) {}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> InContext(const std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
bool Same(const DefinedType& type) const;
|
||||||
|
bool operator<(const DefinedType& type) const;
|
||||||
|
bool operator>(const DefinedType& type) const;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const;
|
||||||
|
|
||||||
|
utils::IdType GetTypeId() const {
|
||||||
|
return type_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType GetType() const {
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::ClassModifier GetClassModifier() const {
|
||||||
|
return class_modifier_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToString() {
|
||||||
|
return "Defined";
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
utils::IdType type_id_; // in defined types
|
||||||
|
utils::IdType type_; // in types manager, created using context types (if specific type)
|
||||||
|
utils::ClassModifier class_modifier_;
|
||||||
|
TypeManager* type_manager_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
const size_t InternalTypesCount = 6;
|
||||||
|
enum class InternalType {
|
||||||
|
Float = 0,
|
||||||
|
Int = 1,
|
||||||
|
String = 2,
|
||||||
|
Char = 3,
|
||||||
|
Bool = 4,
|
||||||
|
Unit = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::optional<InternalType> ToInternalType(const std::string& type) {
|
||||||
|
if (type.empty()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type[0]) {
|
||||||
|
case 'F':
|
||||||
|
if (type == "Float") { return InternalType::Float; }
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
if (type == "Int") { return InternalType::Int; }
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
if (type == "String") { return InternalType::String; }
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
if (type == "Char") { return InternalType::Char; }
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
if (type == "Bool") { return InternalType::Bool; }
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
if (type == "Unit") { return InternalType::Unit; }
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string ToString(InternalType type) {
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case InternalType::Float:
|
||||||
|
result = "Float";
|
||||||
|
break;
|
||||||
|
case InternalType::Int:
|
||||||
|
result = "Int";
|
||||||
|
break;
|
||||||
|
case InternalType::String:
|
||||||
|
result = "String";
|
||||||
|
break;
|
||||||
|
case InternalType::Char:
|
||||||
|
result = "Char";
|
||||||
|
break;
|
||||||
|
case InternalType::Bool:
|
||||||
|
result = "Bool";
|
||||||
|
break;
|
||||||
|
case InternalType::Unit:
|
||||||
|
result = "Unit";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TupleType {
|
||||||
|
public:
|
||||||
|
TupleType() = default;
|
||||||
|
TupleType(const std::optional<std::string>& name,
|
||||||
|
const std::vector<std::pair<std::optional<std::string>, utils::IdType>>& fields,
|
||||||
|
TypeManager* type_manager)
|
||||||
|
: name_(name), fields_(fields), type_manager_(type_manager) {}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> InContext(const std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
bool Same(const TupleType& type) const;
|
||||||
|
bool operator<(const TupleType& type) const;
|
||||||
|
bool operator>(const TupleType& type) const;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const;
|
||||||
|
|
||||||
|
const std::vector<std::pair<std::optional<std::string>, utils::IdType>>& GetFields() const {
|
||||||
|
return fields_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToString();
|
||||||
|
private:
|
||||||
|
std::optional<std::string> name_;
|
||||||
|
std::vector<std::pair<std::optional<std::string>, utils::IdType>> fields_;
|
||||||
|
TypeManager* type_manager_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VariantType {
|
||||||
|
public:
|
||||||
|
VariantType() = default;
|
||||||
|
VariantType(const std::optional<std::string>& name,
|
||||||
|
const std::vector<TupleType>& constructors,
|
||||||
|
std::optional<size_t> current_constructor)
|
||||||
|
: name_(name), constructors_(constructors), current_constructor_(current_constructor) {}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> InContext(const std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
bool Same(const VariantType& type) const;
|
||||||
|
bool operator<(const VariantType& type) const;
|
||||||
|
bool operator>(const VariantType& type) const;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const;
|
||||||
|
|
||||||
|
const std::vector<TupleType>& GetConstructors() const {
|
||||||
|
return constructors_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCurrentConstructor(size_t constructor) {
|
||||||
|
current_constructor_ = constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToString();
|
||||||
|
private:
|
||||||
|
std::optional<std::string> name_;
|
||||||
|
std::vector<TupleType> constructors_;
|
||||||
|
std::optional<size_t> current_constructor_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OptionalType {
|
||||||
|
public:
|
||||||
|
OptionalType() = default;
|
||||||
|
OptionalType(utils::IdType type,
|
||||||
|
TypeManager* type_manager)
|
||||||
|
: type_(type), type_manager_(type_manager) {}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> InContext(const std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
bool Same(const OptionalType& type) const;
|
||||||
|
bool operator<(const OptionalType& type) const;
|
||||||
|
bool operator>(const OptionalType& type) const;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const;
|
||||||
|
|
||||||
|
std::string ToString();
|
||||||
|
private:
|
||||||
|
utils::IdType type_;
|
||||||
|
TypeManager* type_manager_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ReferenceToType {
|
||||||
|
public:
|
||||||
|
ReferenceToType() = default;
|
||||||
|
ReferenceToType(const std::vector<utils::ReferenceModifier>& references,
|
||||||
|
utils::IdType type,
|
||||||
|
TypeManager* type_manager)
|
||||||
|
: references_(references), type_(type), type_manager_(type_manager) {}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> InContext(const std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
bool Same(const ReferenceToType& type) const;
|
||||||
|
bool operator<(const ReferenceToType& type) const;
|
||||||
|
bool operator>(const ReferenceToType& type) const;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const;
|
||||||
|
|
||||||
|
std::string ToString();
|
||||||
|
private:
|
||||||
|
std::vector<utils::ReferenceModifier> references_;
|
||||||
|
utils::IdType type_;
|
||||||
|
TypeManager* type_manager_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////
|
||||||
|
|
||||||
|
class FunctionType {
|
||||||
|
public:
|
||||||
|
FunctionType() = default;
|
||||||
|
FunctionType(const std::vector<utils::IdType>& argument_types,
|
||||||
|
utils::IdType return_type,
|
||||||
|
TypeManager* type_manager)
|
||||||
|
: argument_types_(argument_types), return_type_(return_type), type_manager_(type_manager) {}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> InContext(const std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
bool Same(const FunctionType& type) const;
|
||||||
|
bool operator<(const FunctionType& type) const;
|
||||||
|
bool operator>(const FunctionType& type) const;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const;
|
||||||
|
|
||||||
|
std::string ToString();
|
||||||
|
private:
|
||||||
|
std::vector<utils::IdType> argument_types_;
|
||||||
|
utils::IdType return_type_;
|
||||||
|
TypeManager* type_manager_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArrayType {
|
||||||
|
public:
|
||||||
|
ArrayType() = default;
|
||||||
|
ArrayType(size_t size,
|
||||||
|
utils::IdType elements_type,
|
||||||
|
TypeManager* type_manager)
|
||||||
|
: size_(size), elements_type_(elements_type), type_manager_(type_manager) {}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> InContext(const std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
bool Same(const ArrayType& type) const;
|
||||||
|
bool operator<(const ArrayType& type) const;
|
||||||
|
bool operator>(const ArrayType& type) const;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const;
|
||||||
|
|
||||||
|
utils::IdType GetElementsType() {
|
||||||
|
return elements_type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToString();
|
||||||
|
private:
|
||||||
|
size_t size_; // = 0 for dynamic
|
||||||
|
utils::IdType elements_type_;
|
||||||
|
TypeManager* type_manager_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Type {
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
explicit Type(const T& type) : type_(type) {}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> InContext(const std::unordered_map<std::string, utils::IdType>& context);
|
||||||
|
bool Same(const Type& type) const;
|
||||||
|
bool operator<(const Type& type) const; // TODO: rule exceptions
|
||||||
|
bool operator>(const Type& type) const;
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const;
|
||||||
|
|
||||||
|
std::string GetTypeName() const;
|
||||||
|
|
||||||
|
std::variant<AbstractType,
|
||||||
|
DefinedType,
|
||||||
|
InternalType,
|
||||||
|
TupleType,
|
||||||
|
VariantType,
|
||||||
|
ReferenceToType,
|
||||||
|
FunctionType,
|
||||||
|
ArrayType,
|
||||||
|
OptionalType>& GetType() {
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToString();
|
||||||
|
private:
|
||||||
|
std::variant<AbstractType,
|
||||||
|
DefinedType,
|
||||||
|
InternalType,
|
||||||
|
TupleType,
|
||||||
|
VariantType,
|
||||||
|
ReferenceToType,
|
||||||
|
FunctionType,
|
||||||
|
ArrayType,
|
||||||
|
OptionalType> type_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TypeManager {
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
utils::IdType AddValue(const T& type, utils::ValueType value_type) {
|
||||||
|
types_.push_back(std::pair<Type, utils::ValueType> {type, value_type});
|
||||||
|
return types_.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType AddAnyValue(Type&& type, utils::ValueType value_type) {
|
||||||
|
types_.push_back(std::pair<Type, utils::ValueType> {std::move(type), value_type});
|
||||||
|
return types_.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T*> GetValue(utils::IdType type_id) {
|
||||||
|
if (!std::holds_alternative<T>(types_.at(type_id).first.GetType())) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &std::get<T>(types_.at(type_id).first.GetType());
|
||||||
|
}
|
||||||
|
|
||||||
|
Type* GetAnyValue(utils::IdType type_id) {
|
||||||
|
return &types_.at(type_id).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::ValueType GetValueType(utils::IdType type_id) {
|
||||||
|
return types_.at(type_id).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetValueType(utils::IdType type_id, utils::ValueType value_type) {
|
||||||
|
types_.at(type_id).second = value_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EqualValues(utils::IdType first_type, utils::IdType second_type) {
|
||||||
|
return GetAnyValue(first_type)->Same(*GetAnyValue(second_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddValueRequirement(utils::IdType type, utils::IdType requrement) {
|
||||||
|
return *GetAnyValue(requrement) < *GetAnyValue(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::pair<Type, utils::ValueType>> types_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace info::type
|
||||||
|
|
||||||
225
include/utils.hpp
Normal file
225
include/utils.hpp
Normal file
|
|
@ -0,0 +1,225 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
using std::size_t;
|
||||||
|
|
||||||
|
using IdType = size_t;
|
||||||
|
|
||||||
|
const std::string ClassInternalVarName = "self";
|
||||||
|
const size_t MaxOperatorPrecedence = 4;
|
||||||
|
|
||||||
|
struct ValueReturnedMarker {};
|
||||||
|
struct ValueBroughtMarker {};
|
||||||
|
|
||||||
|
enum class ReferenceModifier { Reference = 0, UniqueReference = 1, Dereference = 2 };
|
||||||
|
enum class IsConstModifier { Const = 0, Var = 1 };
|
||||||
|
enum class ClassInternalsModifier { Static = 0, Const = 1, Var = 2};
|
||||||
|
enum class ClassModifier { Struct = 0, Class = 1 };
|
||||||
|
enum class AssignmentModifier { Assign = 0, Move = 1 };
|
||||||
|
enum class AliasModifier { Alias = 0, Type = 1, Let = 2 };
|
||||||
|
enum class AbstractTypeModifier { Basic = 0, Abstract = 1 };
|
||||||
|
enum class PartitionModifier { Exec = 0, Test = 1 };
|
||||||
|
|
||||||
|
enum class ValueType { Const = 0, Var = 1, Tmp = 2 };
|
||||||
|
|
||||||
|
ValueType IsConstModifierToValueType(IsConstModifier modifier);
|
||||||
|
|
||||||
|
ValueType ClassInternalsModifierToValueType(ClassInternalsModifier modifier);
|
||||||
|
|
||||||
|
bool IsBuiltinFunction(const std::string& name);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Storage {
|
||||||
|
public:
|
||||||
|
Storage() = default;
|
||||||
|
|
||||||
|
IdType GetId(const T& value) {
|
||||||
|
IdType id = 0;
|
||||||
|
auto value_position = value_to_id_.find(value);
|
||||||
|
|
||||||
|
if (value_position == value_to_id_.end()) {
|
||||||
|
id = id_to_value_.size();
|
||||||
|
value_to_id_[value] = id;
|
||||||
|
id_to_value_.push_back(value);
|
||||||
|
} else {
|
||||||
|
id = value_position->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& GetValue(IdType id) {
|
||||||
|
return id_to_value_[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<T> id_to_value_;
|
||||||
|
std::unordered_map<T, IdType> value_to_id_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
class Trie { // optimize ??
|
||||||
|
public:
|
||||||
|
Trie() {
|
||||||
|
verticles_.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Insert(const std::vector<Key>& path, const Value& value) {
|
||||||
|
return RecursiveInsert(verticles_[0], path, 0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Value*> Find(const std::vector<Key>& path) {
|
||||||
|
return RecursiveFind(verticles_[0], path, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Value*> FindByPrefix(const std::vector<Key>& path) {
|
||||||
|
return RecursiveFindByPrefix(verticles_[0], path, 0);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
struct Vertex {
|
||||||
|
std::unordered_map<Key, size_t> children_;
|
||||||
|
std::optional<Value> value;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool RecursiveInsert(Vertex& vertex,
|
||||||
|
const std::vector<Key>& path,
|
||||||
|
size_t path_position,
|
||||||
|
const Value& value) {
|
||||||
|
if (path_position == path.size()) {
|
||||||
|
if (vertex.value.has_value()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
vertex.value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto child_iter = vertex.children_.find(path[path_position]);
|
||||||
|
|
||||||
|
if (child_iter != vertex.children_.end()) {
|
||||||
|
return RecursiveInsert(verticles_[child_iter->second], path, path_position + 1, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex.children_[path[path_position]] = verticles_.size();
|
||||||
|
verticles_.emplace_back();
|
||||||
|
return RecursiveInsert(verticles_.back(), path, path_position + 1, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Value*> RecursiveFind(Vertex& vertex,
|
||||||
|
const std::vector<Key>& path,
|
||||||
|
size_t path_position) {
|
||||||
|
if (path_position == path.size()) {
|
||||||
|
if (!vertex.value.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &vertex.value.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto child_iter = vertex.children_.find(path[path_position]);
|
||||||
|
|
||||||
|
if (child_iter != vertex.children_.end()) {
|
||||||
|
return RecursiveFind(verticles_[child_iter->second], path, path_position + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Value*> RecursiveFindByPrefix(Vertex& vertex,
|
||||||
|
const std::vector<Key>& path,
|
||||||
|
size_t path_position) {
|
||||||
|
if (path_position == path.size()) {
|
||||||
|
std::vector<Value*> ans;
|
||||||
|
RecursiveGetAll(vertex, ans);
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto child_iter = vertex.children_.find(path[path_position]);
|
||||||
|
|
||||||
|
if (child_iter != vertex.children_.end()) {
|
||||||
|
return RecursiveFindByPrefix(verticles_[child_iter->second], path, path_position + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecursiveGetAll(Vertex& vertex, std::vector<Value*>& accumulator) {
|
||||||
|
std::vector<Value*> ans;
|
||||||
|
|
||||||
|
if (vertex.value.has_value()) {
|
||||||
|
accumulator.push_back(&vertex.value.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& child : vertex.children_) {
|
||||||
|
RecursiveGetAll(verticles_[child.second], accumulator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Vertex> verticles_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GroupsManager { // TODO: recall right algorithm name
|
||||||
|
public:
|
||||||
|
GroupsManager() = default;
|
||||||
|
|
||||||
|
explicit GroupsManager(size_t n) {
|
||||||
|
edges_.resize(n);
|
||||||
|
ranks_.resize(n);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
edges_[i] = i;
|
||||||
|
ranks_[i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unite(size_t u, size_t v) { // TODO: recall choice algorithm
|
||||||
|
u = GetGroupRoot(u);
|
||||||
|
v = GetGroupRoot(v);
|
||||||
|
if (ranks_[v] >= ranks_[u]) {
|
||||||
|
edges_[u] = v;
|
||||||
|
ranks_[v] = std::max(ranks_[u] + 1, ranks_[v]);
|
||||||
|
} else {
|
||||||
|
edges_[v] = u;
|
||||||
|
// always ranks_[u] > ranks_[v]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInOneGroup(size_t u, size_t v) {
|
||||||
|
return GetGroupRoot(u) == GetGroupRoot(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AddElement() {
|
||||||
|
size_t id = edges_.size();
|
||||||
|
edges_.push_back(id);
|
||||||
|
ranks_.push_back(1);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetGroupRoot(size_t v) {
|
||||||
|
if (edges_[v] == v) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
return edges_[v] = GetGroupRoot(edges_[v]);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::vector<size_t> edges_;
|
||||||
|
std::vector<size_t> ranks_;
|
||||||
|
};
|
||||||
|
|
||||||
|
void BackVisitDfs(size_t id,
|
||||||
|
std::vector<size_t>& verticles,
|
||||||
|
std::vector<size_t>& marks,
|
||||||
|
const std::vector<std::vector<size_t>>& edges,
|
||||||
|
size_t mark);
|
||||||
|
|
||||||
|
std::vector<size_t> BackTopSort(const std::vector<std::vector<size_t>>& edges_);
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
244
include/values.hpp
Normal file
244
include/values.hpp
Normal file
|
|
@ -0,0 +1,244 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
namespace info::value {
|
||||||
|
|
||||||
|
struct ValueManager;
|
||||||
|
|
||||||
|
struct Unit {};
|
||||||
|
|
||||||
|
struct InternalValue {
|
||||||
|
public:
|
||||||
|
InternalValue() = default;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
explicit InternalValue(const T& value) : value(value) {} // move ??
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T*> GetValue() {
|
||||||
|
if (!std::holds_alternative<T>(value)) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &std::get<T>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Same(const InternalValue& value) const;
|
||||||
|
std::optional<utils::IdType> GetFieldValue(const std::string& name) const;
|
||||||
|
|
||||||
|
utils::IdType DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::variant<double,
|
||||||
|
int64_t,
|
||||||
|
std::string,
|
||||||
|
char,
|
||||||
|
bool,
|
||||||
|
Unit> value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TupleValue { /// no need to store strings (only store associated type) ??
|
||||||
|
public:
|
||||||
|
TupleValue() = default;
|
||||||
|
|
||||||
|
TupleValue(std::vector<std::pair<std::optional<std::string>, utils::IdType>>&& fields,
|
||||||
|
ValueManager* value_manager)
|
||||||
|
: fields(std::move(fields)), value_manager_(value_manager) {}
|
||||||
|
|
||||||
|
bool Same(const TupleValue& other_value) const;
|
||||||
|
std::optional<utils::IdType> GetFieldValue(const std::string& name) const;
|
||||||
|
|
||||||
|
utils::IdType DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type); // TODO
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::vector<std::pair<std::optional<std::string>, utils::IdType>> fields;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValueManager* value_manager_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VariantValue {
|
||||||
|
public:
|
||||||
|
explicit VariantValue() = default;
|
||||||
|
|
||||||
|
VariantValue(TupleValue&& value, size_t current_constructor)
|
||||||
|
: value(std::move(value)), current_constructor(current_constructor) {}
|
||||||
|
|
||||||
|
bool Same(const VariantValue& other_value) const;
|
||||||
|
std::optional<utils::IdType> GetFieldValue(const std::string& name) const;
|
||||||
|
|
||||||
|
utils::IdType DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type);
|
||||||
|
|
||||||
|
public:
|
||||||
|
TupleValue value;
|
||||||
|
size_t current_constructor;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ReferenceToValue {
|
||||||
|
public:
|
||||||
|
ReferenceToValue() = default;
|
||||||
|
|
||||||
|
ReferenceToValue(const std::vector<utils::ReferenceModifier>& references,
|
||||||
|
utils::IdType value,
|
||||||
|
ValueManager* value_manager)
|
||||||
|
: references(references), value(value), value_manager_(value_manager) {}
|
||||||
|
|
||||||
|
bool Same(const ReferenceToValue& other_value) const;
|
||||||
|
std::optional<utils::IdType> GetFieldValue(const std::string& name) const;
|
||||||
|
|
||||||
|
utils::IdType DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::vector<utils::ReferenceModifier> references;
|
||||||
|
utils::IdType value;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValueManager* value_manager_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionValue {
|
||||||
|
public:
|
||||||
|
FunctionValue() = default;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
FunctionValue(const T& function, ValueManager* value_manager)
|
||||||
|
: function(function), value_manager_(value_manager) {}
|
||||||
|
|
||||||
|
bool Same(const FunctionValue& other_value) const;
|
||||||
|
std::optional<utils::IdType> GetFieldValue(const std::string& name) const;
|
||||||
|
|
||||||
|
utils::IdType DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::variant<interpreter::tokens::FunctionDeclaration*,
|
||||||
|
interpreter::tokens::LambdaFunction*> function;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValueManager* value_manager_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ArrayValue {
|
||||||
|
public:
|
||||||
|
ArrayValue() = default;
|
||||||
|
|
||||||
|
ArrayValue(std::vector<utils::IdType>&& elements,
|
||||||
|
bool is_constant_size,
|
||||||
|
ValueManager* value_manager)
|
||||||
|
: elements(std::move(elements)), is_constant_size(is_constant_size), value_manager_(value_manager) {}
|
||||||
|
|
||||||
|
bool Same(const ArrayValue& other_value) const;
|
||||||
|
std::optional<utils::IdType> GetFieldValue(const std::string& name) const;
|
||||||
|
|
||||||
|
utils::IdType DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::vector<utils::IdType> elements;
|
||||||
|
bool is_constant_size = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValueManager* value_manager_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OptionalValue {
|
||||||
|
public:
|
||||||
|
OptionalValue() = default;
|
||||||
|
|
||||||
|
OptionalValue(std::optional<utils::IdType> value, ValueManager* value_manager)
|
||||||
|
: value(value), value_manager_(value_manager) {}
|
||||||
|
|
||||||
|
bool Same(const OptionalValue& other_value) const;
|
||||||
|
std::optional<utils::IdType> GetFieldValue(const std::string& name) const;
|
||||||
|
|
||||||
|
utils::IdType DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::optional<utils::IdType> value;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValueManager* value_manager_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Value { // DefinedValue ??
|
||||||
|
public:
|
||||||
|
Value() = default;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
explicit Value(const T& value) : value(value) {} // move ??
|
||||||
|
|
||||||
|
bool Same(const Value& other_value) const;
|
||||||
|
std::optional<utils::IdType> GetFieldValue(const std::string& name) const;
|
||||||
|
|
||||||
|
utils::IdType DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::variant<InternalValue,
|
||||||
|
TupleValue,
|
||||||
|
VariantValue,
|
||||||
|
ReferenceToValue,
|
||||||
|
FunctionValue, // ??
|
||||||
|
ArrayValue,
|
||||||
|
OptionalValue> value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ValueManager {
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
utils::IdType ExplicitAddValue(const T& value, utils::ValueType value_type) {
|
||||||
|
values_.push_back(std::pair<Value, utils::ValueType> {Value(value), value_type});
|
||||||
|
return values_.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType ExplicitAddAnyValue(Value&& value, utils::ValueType value_type) {
|
||||||
|
values_.push_back(std::pair<Value, utils::ValueType> {std::move(value), value_type});
|
||||||
|
return values_.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
utils::IdType AddValue(const T& value, utils::ValueType value_type) {
|
||||||
|
return ExplicitAddValue(std::move(value), value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType AddAnyValue(Value&& value, utils::ValueType value_type) {
|
||||||
|
return ExplicitAddAnyValue(std::move(value), value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T*> GetValue(utils::IdType value_id) {
|
||||||
|
if (!std::holds_alternative<T>(values_.at(value_id).first.value)) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return &std::get<T>(values_.at(value_id).first.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* GetAnyValue(utils::IdType value_id) {
|
||||||
|
return &values_.at(value_id).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::ValueType GetValueType(utils::IdType value_id) {
|
||||||
|
return values_.at(value_id).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetValueType(utils::IdType value_id, utils::ValueType value_type) {
|
||||||
|
values_.at(value_id).second = value_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EqualValues(utils::IdType first_value, utils::IdType second_value) {
|
||||||
|
return GetAnyValue(first_value)->Same(*GetAnyValue(second_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddValueRequirement(utils::IdType value, utils::IdType requrement) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::pair<Value, utils::ValueType>> values_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace info::value
|
||||||
141
include/visitor.hpp
Normal file
141
include/visitor.hpp
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "interpreter_tree.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
using namespace tokens;
|
||||||
|
|
||||||
|
class Visitor {
|
||||||
|
public:
|
||||||
|
virtual void VisitSourceFile(SourceFile* source_file) {
|
||||||
|
Visit(source_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
virtual void Visit(SourceFile* node);
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
virtual void Visit(NamespaceSources* node);
|
||||||
|
virtual void Visit(Namespace* node);
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
virtual void Visit(ImportStatement* node);
|
||||||
|
virtual void Visit(AliasDefinitionStatement* node);
|
||||||
|
virtual void Visit(VariableDefinitionStatement* node);
|
||||||
|
virtual void Visit(FunctionDeclaration* node);
|
||||||
|
virtual void Visit(FunctionDefinitionStatement* node);
|
||||||
|
virtual void Visit(TypeDefinitionStatement* node);
|
||||||
|
virtual void Visit(AbstractTypeDefinitionStatement* node);
|
||||||
|
virtual void Visit(TypeclassDefinitionStatement* node);
|
||||||
|
virtual void Visit(PartitionStatement* node);
|
||||||
|
|
||||||
|
virtual void Visit(NamespaceStatement& node); // variant
|
||||||
|
virtual void Visit(SourceStatement& node); // variant
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
virtual void Visit(FunctionDefinition* node);
|
||||||
|
virtual void Visit(TypeDefinition* node);
|
||||||
|
virtual void Visit(AnyAnnotatedType* node);
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
virtual void Visit(TypeConstructorPatternParameter* node);
|
||||||
|
virtual void Visit(TypeConstructorPattern* node);
|
||||||
|
virtual void Visit(MatchCase* node);
|
||||||
|
virtual void Visit(Match* node);
|
||||||
|
virtual void Visit(Condition* node);
|
||||||
|
virtual void Visit(DoWhileLoop* node);
|
||||||
|
virtual void Visit(WhileLoop* node);
|
||||||
|
virtual void Visit(ForLoop* node);
|
||||||
|
virtual void Visit(LoopLoop* node);
|
||||||
|
|
||||||
|
virtual void Visit(Pattern& node); // variant
|
||||||
|
virtual void Visit(FlowControl& node); // variant
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
virtual void Visit(BlockStatement& node); // variant
|
||||||
|
|
||||||
|
virtual void Visit(Block* node);
|
||||||
|
|
||||||
|
virtual void Visit(SubExpressionToken& node); // variant
|
||||||
|
virtual void Visit(SubExpression& node); // variant
|
||||||
|
virtual void Visit(PrefixedExpression& node); // variant
|
||||||
|
virtual void Visit(Expression& node); // variant
|
||||||
|
virtual void Visit(SuperExpression& node); // variant
|
||||||
|
|
||||||
|
virtual void Visit(ScopedStatement* node);
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
virtual void Visit(ReferenceExpression* node);
|
||||||
|
virtual void Visit(AccessExpression* node);
|
||||||
|
|
||||||
|
// Other expressions
|
||||||
|
|
||||||
|
virtual void Visit(FunctionCallExpression* node);
|
||||||
|
|
||||||
|
virtual void Visit(TupleExpression* node);
|
||||||
|
virtual void Visit(VariantExpression* node);
|
||||||
|
virtual void Visit(ReturnExpression* node);
|
||||||
|
virtual void Visit(TypeConstructorParameter* node);
|
||||||
|
virtual void Visit(TypeConstructor* node);
|
||||||
|
virtual void Visit(LambdaFunction* node);
|
||||||
|
virtual void Visit(ArrayExpression* node);
|
||||||
|
|
||||||
|
virtual void Visit(LoopControlExpression& node); // enum
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
virtual void Visit(PartitionName* node);
|
||||||
|
virtual void Visit(NameExpression* node);
|
||||||
|
virtual void Visit(TupleName* node);
|
||||||
|
virtual void Visit(VariantName* node);
|
||||||
|
virtual void Visit(AnnotatedName* node);
|
||||||
|
|
||||||
|
virtual void Visit(AnyName& node); // variant
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
virtual void Visit(FunctionType* node);
|
||||||
|
virtual void Visit(TupleType* node);
|
||||||
|
virtual void Visit(VariantType* node);
|
||||||
|
virtual void Visit(TypeExpression* node);
|
||||||
|
|
||||||
|
virtual void Visit(AnyType& node); // variant
|
||||||
|
|
||||||
|
virtual void Visit(ExtendedScopedAnyType* node);
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
virtual void Visit(ParametrizedTypeclass* node);
|
||||||
|
|
||||||
|
// Typeclass & Type
|
||||||
|
|
||||||
|
virtual void Visit(ParametrizedType* node);
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
virtual void Visit(AnyIdentifier* node); // std::string
|
||||||
|
|
||||||
|
virtual void Visit(FloatNumberLiteral* node);
|
||||||
|
virtual void Visit(NumberLiteral* node);
|
||||||
|
virtual void Visit(StringLiteral* node);
|
||||||
|
virtual void Visit(CharLiteral* node);
|
||||||
|
virtual void Visit(UnitLiteral* node);
|
||||||
|
virtual void Visit(BoolLiteral* node);
|
||||||
|
|
||||||
|
virtual void Visit(Literal& node); // variant
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
|
|
||||||
1
lang-parser
Submodule
1
lang-parser
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit ddb08e9b65123324800d1126d38764764363c0e5
|
||||||
1585
src/build_visitor.cpp
Normal file
1585
src/build_visitor.cpp
Normal file
File diff suppressed because it is too large
Load diff
1262
src/execute_visitor.cpp
Normal file
1262
src/execute_visitor.cpp
Normal file
File diff suppressed because it is too large
Load diff
218
src/find_symbols_visitor.cpp
Normal file
218
src/find_symbols_visitor.cpp
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "../include/error_handling.hpp"
|
||||||
|
#include "../include/find_symbols_visitor.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
void FindSymbolsVisitor::Visit(Namespace* node) {
|
||||||
|
if (namespace_visitor_.GetCurrentNamespace()->modifier != utils::ClassInternalsModifier::Static) {
|
||||||
|
// other type of error??
|
||||||
|
error_handling::HandleParsingError("Can't use const /var namespace inside const / var namespace",
|
||||||
|
node->base.start_position,
|
||||||
|
node->base.end_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace_visitor_.AddEnterNamespace(node->type, node->modifier, node, node->base);
|
||||||
|
|
||||||
|
Visitor::Visit(&node->scope);
|
||||||
|
|
||||||
|
namespace_visitor_.ExitNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
// TODO: add imported symbols to symbol table (global info)
|
||||||
|
void FindSymbolsVisitor::Visit(ImportStatement* node) {
|
||||||
|
info::definition::Import info;
|
||||||
|
info.module_name = node->module_name;
|
||||||
|
info.symbols = node->symbols;
|
||||||
|
namespace_visitor_.AddImport(std::move(info), node->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindSymbolsVisitor::Visit(AliasDefinitionStatement* node) {
|
||||||
|
info::definition::Type info;
|
||||||
|
|
||||||
|
info::definition::AliasType alias_info;
|
||||||
|
|
||||||
|
alias_info.modifier = node->modifier;
|
||||||
|
|
||||||
|
alias_info.parameters = node->parameters;
|
||||||
|
alias_info.value.node = node->value.get();
|
||||||
|
alias_info.node = node;
|
||||||
|
|
||||||
|
info.type = std::move(alias_info);
|
||||||
|
|
||||||
|
node->type_id_ = namespace_visitor_.AddType(node->type, std::move(info), node->base);
|
||||||
|
|
||||||
|
Visitor::Visit(node->value.get()); // to visit all tree
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindSymbolsVisitor::Visit(FunctionDeclaration* node) {
|
||||||
|
info::definition::FunctionDeclaration info;
|
||||||
|
|
||||||
|
info.parameters.resize(node->parameters.size());
|
||||||
|
for (size_t i = 0; i < node->parameters.size(); ++i) {
|
||||||
|
Visit(node->parameters[i].get());
|
||||||
|
info.parameters[i] = std::move(std::any_cast<info::definition::Parameter>(current_info_));
|
||||||
|
current_info_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
info.argument_types.resize(node->type->types.size());
|
||||||
|
for (size_t i = 0; i < node->type->types.size(); ++i) {
|
||||||
|
info.argument_types[i] = &node->type->types[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
info.node = node;
|
||||||
|
|
||||||
|
node->function_id_ = namespace_visitor_.AddFunctionDeclaration(node->name, std::move(info), node->base);
|
||||||
|
|
||||||
|
Visitor::Visit(node->type.get()); // to visit all tree
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindSymbolsVisitor::Visit(FunctionDefinitionStatement* node) {
|
||||||
|
info::definition::FunctionDefinition info;
|
||||||
|
|
||||||
|
auto definition = node->definition.get();
|
||||||
|
|
||||||
|
info.argument_names.resize(definition->arguments.size());
|
||||||
|
for (size_t i = 0; i < definition->arguments.size(); ++i) {
|
||||||
|
info.argument_names[i] = definition->arguments[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
info.node = node;
|
||||||
|
|
||||||
|
node->function_id_ = namespace_visitor_.AddFunctionDefinition(definition->name, std::move(info), node->base);
|
||||||
|
|
||||||
|
Visitor::Visit(definition); // to visit all tree
|
||||||
|
Visitor::Visit(node->value); // to visit all tree
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindSymbolsVisitor::Visit(TypeDefinitionStatement* node) {
|
||||||
|
info::definition::Type info;
|
||||||
|
|
||||||
|
auto definition = node->definition.get();
|
||||||
|
|
||||||
|
info::definition::AnyType any_type_info;
|
||||||
|
|
||||||
|
Visit(definition->type.get());
|
||||||
|
any_type_info.type = std::move(std::any_cast<info::definition::Parameter>(current_info_));
|
||||||
|
current_info_.reset();
|
||||||
|
|
||||||
|
any_type_info.parameters.resize(definition->parameters.size());
|
||||||
|
for (size_t i = 0; i < definition->parameters.size(); ++i) {
|
||||||
|
Visit(definition->parameters[i].get());
|
||||||
|
any_type_info.parameters[i] = std::move(std::any_cast<info::definition::Parameter>(current_info_));
|
||||||
|
current_info_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
any_type_info.node = node;
|
||||||
|
any_type_info.parent_namespace = namespace_visitor_.GetCurrentNamespaceId();
|
||||||
|
any_type_info.modifier = node->modifier;
|
||||||
|
|
||||||
|
std::string type = any_type_info.type.type;
|
||||||
|
|
||||||
|
info.type = std::move(any_type_info);
|
||||||
|
|
||||||
|
node->type_id_ = namespace_visitor_.AddType(type, std::move(info), node->base);
|
||||||
|
|
||||||
|
auto maybe_graph_type_vertex = namespace_visitor_.GetTypeclassGraph()->GetTypeVertex(node->definition->type->graph_id_);
|
||||||
|
|
||||||
|
if (!maybe_graph_type_vertex.has_value()) {
|
||||||
|
error_handling::HandleInternalError("Type vertex in TypeclassGraph is not type vertex",
|
||||||
|
"FindSymbolsVisitor.FunctionDefinitionStatement",
|
||||||
|
&node->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
maybe_graph_type_vertex.value()->type_id = node->type_id_;
|
||||||
|
|
||||||
|
// definition visited earlier
|
||||||
|
Visitor::Visit(node->value); // to visit all tree
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindSymbolsVisitor::Visit(AbstractTypeDefinitionStatement* node) {
|
||||||
|
info::definition::AbstractType info;
|
||||||
|
|
||||||
|
Visit(node->type.get());
|
||||||
|
info.type = std::move(std::any_cast<info::definition::Parameter>(current_info_));
|
||||||
|
current_info_.reset();
|
||||||
|
|
||||||
|
info.modifier = node->modifier;
|
||||||
|
info.node = node;
|
||||||
|
|
||||||
|
std::string type = info.type.type;
|
||||||
|
|
||||||
|
node->type_id_ = namespace_visitor_.AddAbstractType(type, std::move(info), node->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindSymbolsVisitor::Visit(TypeclassDefinitionStatement* node) {
|
||||||
|
info::definition::Typeclass info;
|
||||||
|
|
||||||
|
auto definition = node->definition.get();
|
||||||
|
|
||||||
|
std::string& typeclass_name = definition->type.get()->type;
|
||||||
|
|
||||||
|
info.parameters.resize(definition->parameters.size());
|
||||||
|
for (size_t i = 0; i < definition->parameters.size(); ++i) {
|
||||||
|
Visit(definition->parameters[i].get());
|
||||||
|
info.parameters[i] = std::move(std::any_cast<info::definition::Parameter>(current_info_));
|
||||||
|
current_info_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < node->requirements.size(); ++i) {
|
||||||
|
namespace_visitor_.AddEnterNamespace(typeclass_name, node->requirements[i].first, std::nullopt, node->base);
|
||||||
|
Visit(node->requirements[i].second.get());
|
||||||
|
namespace_visitor_.ExitNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
info.node = node;
|
||||||
|
info.parent_namespace = namespace_visitor_.GetCurrentNamespaceId();
|
||||||
|
|
||||||
|
node->typeclass_id_ = namespace_visitor_.AddTypeclass(typeclass_name, std::move(info), node->base);
|
||||||
|
|
||||||
|
// no need to visit definition->type, because it is typeclass
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindSymbolsVisitor::Visit(PartitionStatement* node) {
|
||||||
|
node->executable_id_ = namespace_visitor_.AddPartition(node->name.path, node, node->base);
|
||||||
|
|
||||||
|
Visitor::Visit(node->value); // to visit all tree
|
||||||
|
}
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
void FindSymbolsVisitor::Visit(AnyAnnotatedType* node) {
|
||||||
|
info::definition::Parameter info;
|
||||||
|
|
||||||
|
info.type = node->type;
|
||||||
|
|
||||||
|
info.typeclass_nodes.resize(node->typeclasses.size());
|
||||||
|
for (size_t i = 0; i < node->typeclasses.size(); ++i) {
|
||||||
|
info.typeclass_nodes[i] = node->typeclasses[i].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& typeclass : node->typeclasses) {
|
||||||
|
Visitor::Visit(typeclass.get()); // to visit all tree
|
||||||
|
}
|
||||||
|
|
||||||
|
info.node = node;
|
||||||
|
|
||||||
|
auto maybe_typeclass_graph_id = namespace_visitor_.GetGlobalInfo()->AddAnnotatedTypeToGraph(node); // definitions and declarations should be added latter
|
||||||
|
|
||||||
|
if (!maybe_typeclass_graph_id.has_value()) {
|
||||||
|
error_handling::HandleInternalError("Can't add annotated type to typeclass graph",
|
||||||
|
"FindSymbolsVisitor.AnyAnnotatedType",
|
||||||
|
&node->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->graph_id_ = maybe_typeclass_graph_id.value();
|
||||||
|
|
||||||
|
current_info_ = std::move(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
601
src/global_info.cpp
Normal file
601
src/global_info.cpp
Normal file
|
|
@ -0,0 +1,601 @@
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "../include/global_info.hpp"
|
||||||
|
#include "../include/types.hpp"
|
||||||
|
#include "../include/error_handling.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace info {
|
||||||
|
|
||||||
|
void GlobalInfo::NamespaceVisitor::AddImport(definition::Import&& import_info,
|
||||||
|
const std::optional<std::string>& name) {
|
||||||
|
if (name.has_value()) {
|
||||||
|
global_info_.usages_[name.value()] = std::move(import_info);
|
||||||
|
} else {
|
||||||
|
global_info_.imports_.push_back(std::move(import_info));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalInfo::NamespaceVisitor::AddEnterNamespace(const std::string& name,
|
||||||
|
utils::ClassInternalsModifier modifier,
|
||||||
|
std::optional<interpreter::tokens::Namespace*> node,
|
||||||
|
const interpreter::tokens::BaseNode& base_node) {
|
||||||
|
if (type::ToInternalType(name).has_value()) {
|
||||||
|
error_handling::HandleNamesError("Can't define basic type namespace", base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto current_namespaces =
|
||||||
|
global_info_.ChooseNamespaces(modifier, &global_info_.namespaces_[namespace_stack_.back()]);
|
||||||
|
|
||||||
|
utils::IdType id = 0;
|
||||||
|
|
||||||
|
auto namespace_iter = current_namespaces->find(name);
|
||||||
|
if (namespace_iter == current_namespaces->end()) {
|
||||||
|
id = global_info_.namespaces_.size();
|
||||||
|
(*current_namespaces)[name] = id;
|
||||||
|
global_info_.namespaces_.emplace_back();
|
||||||
|
|
||||||
|
global_info_.namespaces_.back().modifier = modifier;
|
||||||
|
} else {
|
||||||
|
id = namespace_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
definition::Namespace* namespace_info = &global_info_.namespaces_[id];
|
||||||
|
|
||||||
|
if (!namespace_info->any_node.has_value()) { // ??
|
||||||
|
namespace_info->any_node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace_info->parent_namespace = namespace_stack_.back();
|
||||||
|
|
||||||
|
namespace_info->type_name = name;
|
||||||
|
|
||||||
|
namespace_stack_.push_back(id);
|
||||||
|
current_path_.push_back(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalInfo::NamespaceVisitor::EnterNamespace(const std::string& name,
|
||||||
|
utils::ClassInternalsModifier modifier) {
|
||||||
|
for (ssize_t i = (ssize_t)namespace_stack_.size() - 1; i >= 0; --i) {
|
||||||
|
auto current_namespaces =
|
||||||
|
global_info_.ChooseNamespaces(modifier, &global_info_.namespaces_[i]);
|
||||||
|
auto namespace_iter = current_namespaces->find(name);
|
||||||
|
if (namespace_iter != current_namespaces->end()) {
|
||||||
|
namespace_stack_.push_back(namespace_iter->second);
|
||||||
|
current_path_.push_back(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error_handling::HandleInternalError("Can't find namespace " + name,
|
||||||
|
"GlobalInfo.NamespaceVisitor.EnterNamespace",
|
||||||
|
std::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalInfo::NamespaceVisitor::ExitNamespace() {
|
||||||
|
if (namespace_stack_.size() <= 1) {
|
||||||
|
error_handling::HandleInternalError("Can't exit from global namespace",
|
||||||
|
"GlobalInfo.NamespaceVisitor.ExitNamespace",
|
||||||
|
std::nullopt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace_stack_.pop_back();
|
||||||
|
current_path_.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalInfo::NamespaceVisitor::ToGlobalNamespace() {
|
||||||
|
namespace_stack_.clear();
|
||||||
|
current_path_.clear();
|
||||||
|
|
||||||
|
namespace_stack_.push_back(global_info_.GlobalNamespaceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType GlobalInfo::NamespaceVisitor::AddFunctionDeclaration(
|
||||||
|
const std::string& name,
|
||||||
|
definition::FunctionDeclaration&& function_declaration_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node) {
|
||||||
|
utils::IdType id = 0;
|
||||||
|
|
||||||
|
auto function_id_iter = global_info_.namespaces_[namespace_stack_.back()].functions.find(name);
|
||||||
|
if (function_id_iter == global_info_.namespaces_[namespace_stack_.back()].functions.end()) {
|
||||||
|
id = global_info_.functions_.size();
|
||||||
|
global_info_.namespaces_[namespace_stack_.back()].functions[name] = id;
|
||||||
|
global_info_.functions_.emplace_back();
|
||||||
|
global_info_.functions_.back().argument_count = function_declaration_info.argument_types.size(); // add return type
|
||||||
|
} else {
|
||||||
|
id = function_id_iter->second;
|
||||||
|
if (global_info_.functions_[id].argument_count != function_declaration_info.argument_types.size()) {
|
||||||
|
error_handling::HandleNamesError("Function declaration: not same argument count in function definition and declaration", base_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global_info_.functions_[id].declaration.has_value()) {
|
||||||
|
error_handling::HandleNamesError("Second function declaration", base_node);
|
||||||
|
}
|
||||||
|
global_info_.functions_[id].declaration = std::move(function_declaration_info);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType GlobalInfo::NamespaceVisitor::AddFunctionDefinition(
|
||||||
|
const std::string& name,
|
||||||
|
definition::FunctionDefinition&& function_definition_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node) {
|
||||||
|
utils::IdType id = 0;
|
||||||
|
|
||||||
|
auto function_id_iter = global_info_.namespaces_[namespace_stack_.back()].functions.find(name);
|
||||||
|
if (function_id_iter == global_info_.namespaces_[namespace_stack_.back()].functions.end()) {
|
||||||
|
id = global_info_.functions_.size();
|
||||||
|
global_info_.namespaces_[namespace_stack_.back()].functions[name] = id;
|
||||||
|
global_info_.functions_.emplace_back();
|
||||||
|
global_info_.functions_.back().argument_count = function_definition_info.argument_names.size() + 1;
|
||||||
|
} else {
|
||||||
|
id = function_id_iter->second;
|
||||||
|
if (global_info_.functions_[id].argument_count != function_definition_info.argument_names.size() + 1) {
|
||||||
|
error_handling::HandleNamesError("Function definition: not same argument count in function definition and declaration", base_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global_info_.functions_[id].definition.has_value()) {
|
||||||
|
error_handling::HandleNamesError("Second function definition", base_node);
|
||||||
|
}
|
||||||
|
global_info_.functions_[id].definition = std::move(function_definition_info);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: internal types, etc.
|
||||||
|
// TODO: extended constructor names (point separated names)
|
||||||
|
utils::IdType GlobalInfo::NamespaceVisitor::AddType(const std::string& type,
|
||||||
|
definition::Type&& type_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node) {
|
||||||
|
if (type::ToInternalType(type).has_value()) {
|
||||||
|
error_handling::HandleNamesError("Can't redefine basic type", base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType id = 0;
|
||||||
|
|
||||||
|
auto type_id_iter = global_info_.namespaces_[namespace_stack_.back()].types.find(type);
|
||||||
|
|
||||||
|
if (type_id_iter == global_info_.namespaces_[namespace_stack_.back()].types.end()) {
|
||||||
|
id = global_info_.types_.size();
|
||||||
|
global_info_.namespaces_[namespace_stack_.back()].types[type] = id;
|
||||||
|
global_info_.types_.push_back(std::move(type_info));
|
||||||
|
} else {
|
||||||
|
error_handling::HandleNamesError("More then one type with the same name in namespace", base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
definition::Type& moved_type_info = global_info_.types_.back();
|
||||||
|
|
||||||
|
if (!std::holds_alternative<definition::AnyType>(moved_type_info.type)) {
|
||||||
|
error_handling::HandleInternalError("Not AnyType constructor search is not implemented yet",
|
||||||
|
"GlobalInfo.NamespaceVisitor.AddType",
|
||||||
|
&base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
definition::AnyType& any_type_info = std::get<definition::AnyType>(moved_type_info.type);
|
||||||
|
if (std::holds_alternative<std::unique_ptr<interpreter::tokens::VariantType>>(any_type_info.node->value)) {
|
||||||
|
interpreter::tokens::VariantType& variant_type_info = *std::get<std::unique_ptr<interpreter::tokens::VariantType>>(any_type_info.node->value);
|
||||||
|
for (size_t i = 0; i < variant_type_info.constructors.size(); ++i) {
|
||||||
|
std::string constructor_name;
|
||||||
|
definition::Constructor constructor_info;
|
||||||
|
|
||||||
|
constructor_info.type_id = id;
|
||||||
|
constructor_info.order = i;
|
||||||
|
|
||||||
|
if (std::holds_alternative<interpreter::tokens::Constructor>(variant_type_info.constructors[i])) {
|
||||||
|
constructor_name = std::get<interpreter::tokens::Constructor>(variant_type_info.constructors[i]);
|
||||||
|
} else if (std::holds_alternative<
|
||||||
|
std::unique_ptr<interpreter::tokens::TupleType>>(variant_type_info.constructors[i])) {
|
||||||
|
constructor_info.constructor_tuple_node =
|
||||||
|
std::get<std::unique_ptr<interpreter::tokens::TupleType>>(variant_type_info.constructors[i]).get();
|
||||||
|
|
||||||
|
auto maybe_constructor_name = constructor_info.constructor_tuple_node.value()->type;
|
||||||
|
|
||||||
|
if (maybe_constructor_name.has_value()) {
|
||||||
|
constructor_name = maybe_constructor_name.value();
|
||||||
|
} else {
|
||||||
|
constructor_name = type;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_handling::HandleInternalError("Unexprected VariantType constructor node type",
|
||||||
|
"GlobalInfo.NamespaceVisitor.AddType",
|
||||||
|
&base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor_info.name = constructor_name;
|
||||||
|
|
||||||
|
AddConstructor(constructor_name, std::move(constructor_info), base_node);
|
||||||
|
}
|
||||||
|
} else if (std::holds_alternative<std::unique_ptr<interpreter::tokens::TupleType>>(any_type_info.node->value)) {
|
||||||
|
definition::Constructor constructor_info;
|
||||||
|
constructor_info.type_id = id;
|
||||||
|
// constructor_info.order = std::nullopt;
|
||||||
|
constructor_info.name = type;
|
||||||
|
constructor_info.constructor_tuple_node = std::get<std::unique_ptr<interpreter::tokens::TupleType>>(any_type_info.node->value).get();
|
||||||
|
|
||||||
|
AddConstructor(type, std::move(constructor_info), base_node);
|
||||||
|
} else {
|
||||||
|
// TODO: constructors for function types (??), array types (??), ...
|
||||||
|
error_handling::HandleInternalError("Not VariantType constructor search is not implemented yet",
|
||||||
|
"GlobalInfo.NamespaceVisitor.AddType",
|
||||||
|
&base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: link abstract type with let definitions
|
||||||
|
utils::IdType GlobalInfo::NamespaceVisitor::AddAbstractType(const std::string& abstract_type,
|
||||||
|
definition::AbstractType&& abstract_type_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node) {
|
||||||
|
// if (type::ToInternalType(abstract_type).has_value()) {
|
||||||
|
// error_handling::HandleNamesError("Can't redefine basic type as abstract type", base_node);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (FindAbstractType(abstract_type).has_value()) {
|
||||||
|
error_handling::HandleNamesError("More then one abstract type with the same name in namespace", base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType id = global_info_.abstract_types_.size();
|
||||||
|
global_info_.name_to_abstract_type_[abstract_type] = id;
|
||||||
|
global_info_.abstract_types_.push_back(std::move(abstract_type_info));
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: which info needed ??
|
||||||
|
utils::IdType GlobalInfo::NamespaceVisitor::AddTypeclass(const std::string& typeclass,
|
||||||
|
definition::Typeclass&& typeclass_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node) {
|
||||||
|
if (type::ToInternalType(typeclass).has_value()) {
|
||||||
|
error_handling::HandleNamesError("Can't redefine basic type as typeclass", base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FindTypeclass(typeclass).has_value()) {
|
||||||
|
error_handling::HandleNamesError("More then one typeclass with the same name", base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType id = global_info_.typeclasses_.size();
|
||||||
|
global_info_.name_to_typeclass_[typeclass] = id;
|
||||||
|
global_info_.typeclasses_.push_back(std::move(typeclass_info));
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType GlobalInfo::NamespaceVisitor::AddConstructor(const std::string& constructor,
|
||||||
|
definition::Constructor&& constructor_info,
|
||||||
|
const interpreter::tokens::BaseNode& base_node) {
|
||||||
|
if (type::ToInternalType(constructor).has_value()) {
|
||||||
|
error_handling::HandleNamesError("Can't redefine basic type as constructor", base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto constructor_id_iter = global_info_.namespaces_[namespace_stack_.back()].constructors.find(constructor);
|
||||||
|
|
||||||
|
if (constructor_id_iter != global_info_.namespaces_[namespace_stack_.back()].constructors.end()) {
|
||||||
|
error_handling::HandleNamesError("More then one constructor with the same name in namespace", base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType id = global_info_.constructors_.size();
|
||||||
|
global_info_.namespaces_[namespace_stack_.back()].constructors[constructor] = id;
|
||||||
|
global_info_.constructors_.push_back(std::move(constructor_info));
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType GlobalInfo::NamespaceVisitor::AddPartition(const std::vector<std::string>& path,
|
||||||
|
interpreter::tokens::PartitionStatement* node,
|
||||||
|
const interpreter::tokens::BaseNode& base_node) {
|
||||||
|
PartitionInfo partition;
|
||||||
|
|
||||||
|
partition.path.reserve(current_path_.size() + path.size());
|
||||||
|
partition.path = current_path_;
|
||||||
|
|
||||||
|
for (auto& path_name : path) {
|
||||||
|
partition.path.push_back(path_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
partition.node = node;
|
||||||
|
|
||||||
|
utils::IdType id = global_info_.partitions_.size();
|
||||||
|
|
||||||
|
global_info_.partitions_.push_back(partition);
|
||||||
|
if (!global_info_.partitions_trie_.Insert(partition.path, id)) {
|
||||||
|
error_handling::HandleNamesError("Partition with this name already exists", base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GlobalInfo::NamespaceVisitor::FindNamespaceId(const std::optional<std::vector<std::string>>& path) {
|
||||||
|
return FindSomething<utils::IdType>(path,
|
||||||
|
[] (utils::IdType current_namespace) -> std::optional<utils::IdType> {
|
||||||
|
return current_namespace;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GlobalInfo::NamespaceVisitor::FindFunctionId(
|
||||||
|
const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& name) {
|
||||||
|
return FindSomething<utils::IdType>(path,
|
||||||
|
[name, this] (utils::IdType current_namespace) -> std::optional<utils::IdType> {
|
||||||
|
|
||||||
|
auto function_info_iter = global_info_.namespaces_[current_namespace].functions.find(name);
|
||||||
|
if (function_info_iter == global_info_.namespaces_[current_namespace].functions.end()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function_info_iter->second;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GlobalInfo::NamespaceVisitor::FindMethodId(
|
||||||
|
const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& name,
|
||||||
|
utils::IsConstModifier modifier) {
|
||||||
|
return GlobalInfo::NamespaceVisitor::FindSomething<utils::IdType>(path,
|
||||||
|
[type, name, modifier, this] (utils::IdType current_namespace) -> std::optional<utils::IdType> {
|
||||||
|
|
||||||
|
|
||||||
|
auto variable_namespace_iter =
|
||||||
|
(modifier == utils::IsConstModifier::Const
|
||||||
|
? global_info_.namespaces_[current_namespace].const_namespaces.find(type)
|
||||||
|
: global_info_.namespaces_[current_namespace].var_namespaces.find(type));
|
||||||
|
if (variable_namespace_iter ==
|
||||||
|
(modifier == utils::IsConstModifier::Const
|
||||||
|
? global_info_.namespaces_[current_namespace].const_namespaces.end()
|
||||||
|
: global_info_.namespaces_[current_namespace].var_namespaces.end())) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto method_iter = global_info_.namespaces_[variable_namespace_iter->second].functions.find(name);
|
||||||
|
if (method_iter == global_info_.namespaces_[variable_namespace_iter->second].functions.end()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return method_iter->second;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GlobalInfo::NamespaceVisitor::FindTypeId(
|
||||||
|
const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& type) {
|
||||||
|
return FindSomething<utils::IdType>(path,
|
||||||
|
[type, this] (utils::IdType current_namespace) -> std::optional<utils::IdType> {
|
||||||
|
|
||||||
|
auto type_info_iter = global_info_.namespaces_[current_namespace].types.find(type);
|
||||||
|
if (type_info_iter == global_info_.namespaces_[current_namespace].types.end()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_info_iter->second;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GlobalInfo::NamespaceVisitor::FindLocalTypeId(const std::string& type) {
|
||||||
|
auto type_id_iter = global_info_.namespaces_[namespace_stack_.back()].types.find(type);
|
||||||
|
|
||||||
|
if (type_id_iter != global_info_.namespaces_[namespace_stack_.back()].types.end()) {
|
||||||
|
return type_id_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GlobalInfo::NamespaceVisitor::FindAbstractTypeId(const std::string& abstract_type) {
|
||||||
|
auto abstract_type_id_iter = global_info_.name_to_abstract_type_.find(abstract_type);
|
||||||
|
|
||||||
|
if (abstract_type_id_iter != global_info_.name_to_abstract_type_.end()) {
|
||||||
|
return abstract_type_id_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GlobalInfo::NamespaceVisitor::FindTypeclassId(const std::string& typeclass) {
|
||||||
|
auto typeclass_id_iter = global_info_.name_to_typeclass_.find(typeclass);
|
||||||
|
|
||||||
|
if (typeclass_id_iter != global_info_.name_to_typeclass_.end()) {
|
||||||
|
return typeclass_id_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GlobalInfo::NamespaceVisitor::FindConstructorId(
|
||||||
|
const std::optional<std::vector<std::string>>& path,
|
||||||
|
const std::string& constructor) {
|
||||||
|
return FindSomething<utils::IdType>(path,
|
||||||
|
[constructor, this] (utils::IdType current_namespace) -> std::optional<utils::IdType> {
|
||||||
|
|
||||||
|
auto constructor_info_iter = global_info_.namespaces_[current_namespace].constructors.find(constructor);
|
||||||
|
if (constructor_info_iter == global_info_.namespaces_[current_namespace].constructors.end()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return constructor_info_iter->second;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T> GlobalInfo::NamespaceVisitor::FindSomething(
|
||||||
|
const std::optional<std::vector<std::string>>& path,
|
||||||
|
std::function<std::optional<T>(utils::IdType)> search_func) {
|
||||||
|
for (ssize_t i = (ssize_t)namespace_stack_.size() - 1; i >= 0; --i) {
|
||||||
|
utils::IdType current_namespace = 0;
|
||||||
|
if (path.has_value()) {
|
||||||
|
auto maybe_namespace = FindNamespaceIn(namespace_stack_[i], path.value());
|
||||||
|
|
||||||
|
if (!maybe_namespace.has_value()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_namespace = maybe_namespace.value();
|
||||||
|
} else {
|
||||||
|
current_namespace = namespace_stack_[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<T> result = search_func(current_namespace);
|
||||||
|
|
||||||
|
if (result.has_value()) {
|
||||||
|
return result.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GlobalInfo::NamespaceVisitor::FindNamespaceIn(
|
||||||
|
utils::IdType current_namespace,
|
||||||
|
const std::vector<std::string>& path) {
|
||||||
|
utils::IdType next_namespace = current_namespace;
|
||||||
|
for (auto& name : path) {
|
||||||
|
auto next_namespace_iter = global_info_.namespaces_[next_namespace].namespaces.find(name);
|
||||||
|
if (next_namespace_iter == global_info_.namespaces_[next_namespace].namespaces.end()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
next_namespace = next_namespace_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
std::optional<definition::Namespace*> GlobalInfo::GetTypeNamespace(utils::IdType id,
|
||||||
|
utils::ClassInternalsModifier modifier) {
|
||||||
|
auto maybe_type_info = GetTypeInfo<definition::AnyType>(id);
|
||||||
|
|
||||||
|
if (!maybe_type_info.has_value()) {
|
||||||
|
error_handling::HandleInternalError("Only AnyType is supported now",
|
||||||
|
"GlobalInfo.GetTypeNamespace",
|
||||||
|
std::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& name = maybe_type_info.value()->type.type;
|
||||||
|
|
||||||
|
auto namespaces = ChooseNamespaces(modifier, &GetNamespaceInfo(maybe_type_info.value()->parent_namespace));
|
||||||
|
|
||||||
|
auto namespace_iter = namespaces->find(name);
|
||||||
|
|
||||||
|
return namespace_iter == namespaces->end() ? std::optional<definition::Namespace*>(std::nullopt) : &GetNamespaceInfo(namespace_iter->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, utils::IdType>*
|
||||||
|
GlobalInfo::ChooseNamespaces(utils::ClassInternalsModifier modifier,
|
||||||
|
definition::Namespace* current_namespace) {
|
||||||
|
std::unordered_map<std::string, utils::IdType>* current_namespaces = nullptr;
|
||||||
|
switch (modifier) {
|
||||||
|
case utils::ClassInternalsModifier::Const:
|
||||||
|
current_namespaces = ¤t_namespace->const_namespaces;
|
||||||
|
break;
|
||||||
|
case utils::ClassInternalsModifier::Var:
|
||||||
|
current_namespaces = ¤t_namespace->var_namespaces;
|
||||||
|
break;
|
||||||
|
case utils::ClassInternalsModifier::Static:
|
||||||
|
current_namespaces = ¤t_namespace->namespaces;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current_namespaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GlobalInfo::AddTypeclassToGraph(utils::IdType typeclass) {
|
||||||
|
definition::Typeclass* typeclass_info = &GetTypeclassInfo(typeclass);
|
||||||
|
definition::Namespace* parent_namespace = &GetNamespaceInfo(typeclass_info->parent_namespace);
|
||||||
|
|
||||||
|
std::string name = typeclass_info->node->definition->type->type;
|
||||||
|
interpreter::tokens::BaseNode* base_node = &typeclass_info->node->base;
|
||||||
|
std::vector<std::string> dependencies;
|
||||||
|
std::vector<std::pair<std::string, std::pair<utils::ClassInternalsModifier, interpreter::tokens::FunctionDeclaration*>>> function_declarations;
|
||||||
|
std::vector<std::pair<std::string, interpreter::tokens::FunctionDefinitionStatement*>> function_definitions;
|
||||||
|
|
||||||
|
for (auto& dependency_node : typeclass_info->node->definition->type->typeclasses) {
|
||||||
|
std::string dependency = dependency_node->typeclass;
|
||||||
|
if (dependency_node->parameters.size() > 0) {
|
||||||
|
error_handling::HandleInternalError("Paramtrized typeclass requirements are not implemented yet",
|
||||||
|
"GlobalInfo.AddTypeclassToGraph",
|
||||||
|
std::nullopt);
|
||||||
|
}
|
||||||
|
dependencies.push_back(dependency);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto namespace_iter = parent_namespace->namespaces.find(name);
|
||||||
|
if (namespace_iter != parent_namespace->namespaces.end()) {
|
||||||
|
CollectFunctionInfo(namespace_iter->second,
|
||||||
|
utils::ClassInternalsModifier::Static,
|
||||||
|
function_declarations,
|
||||||
|
function_definitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const_namespace_iter = parent_namespace->const_namespaces.find(name);
|
||||||
|
if (const_namespace_iter != parent_namespace->const_namespaces.end()) {
|
||||||
|
CollectFunctionInfo(const_namespace_iter->second,
|
||||||
|
utils::ClassInternalsModifier::Const,
|
||||||
|
function_declarations,
|
||||||
|
function_definitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto var_namespace_iter = parent_namespace->var_namespaces.find(name);
|
||||||
|
if (var_namespace_iter != parent_namespace->var_namespaces.end()) {
|
||||||
|
CollectFunctionInfo(var_namespace_iter->second,
|
||||||
|
utils::ClassInternalsModifier::Var,
|
||||||
|
function_declarations,
|
||||||
|
function_definitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeclass_graph_.AddVertex(name,
|
||||||
|
dependencies,
|
||||||
|
function_declarations,
|
||||||
|
function_definitions,
|
||||||
|
base_node,
|
||||||
|
TypeclassGraph::Modifier::Typeclass);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> GlobalInfo::AddAnnotatedTypeToGraph(interpreter::tokens::AnnotatedType* node) {
|
||||||
|
std::string name = node->type;
|
||||||
|
interpreter::tokens::BaseNode* base_node = &node->base;
|
||||||
|
std::vector<std::string> dependencies;
|
||||||
|
|
||||||
|
for (auto& dependency_node : node->typeclasses) {
|
||||||
|
std::string dependency = dependency_node->typeclass;
|
||||||
|
if (dependency_node->parameters.size() > 0) {
|
||||||
|
error_handling::HandleInternalError("Paramtrized typeclass requirements are not implemented yet",
|
||||||
|
"GlobalInfo.AddAnnotatedTypeToGraph",
|
||||||
|
&node->base);
|
||||||
|
}
|
||||||
|
dependencies.push_back(dependency);
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeclass_graph_.AddVertex(name,
|
||||||
|
dependencies,
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
base_node,
|
||||||
|
TypeclassGraph::Modifier::Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalInfo::CollectFunctionInfo(
|
||||||
|
utils::IdType current_namespace,
|
||||||
|
utils::ClassInternalsModifier modifier,
|
||||||
|
std::vector<std::pair<std::string, std::pair<utils::ClassInternalsModifier, interpreter::tokens::FunctionDeclaration*>>>& function_declarations,
|
||||||
|
std::vector<std::pair<std::string, interpreter::tokens::FunctionDefinitionStatement*>>& function_definitions) {
|
||||||
|
for (auto& function : GetNamespaceInfo(current_namespace).functions) {
|
||||||
|
definition::Function function_info = GetFunctionInfo(function.second);
|
||||||
|
|
||||||
|
if (function_info.declaration.has_value()) {
|
||||||
|
function_declarations.push_back(
|
||||||
|
{function.first,
|
||||||
|
{modifier, function_info.declaration.value().node}});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_info.definition.has_value()) {
|
||||||
|
function_definitions.push_back({function.first, function_info.definition.value().node});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace info
|
||||||
218
src/link_symbols_visitor.cpp
Normal file
218
src/link_symbols_visitor.cpp
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
#include <bits/types/error_t.h>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "../include/link_symbols_visitor.hpp"
|
||||||
|
#include "../include/error_handling.hpp"
|
||||||
|
#include "../include/types.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
void LinkSymbolsVisitor::Visit(Namespace* node) {
|
||||||
|
// Visitor::Visit(&node->type); // not needed
|
||||||
|
|
||||||
|
std::optional<utils::IdType> maybe_type = namespace_visitor_.FindLocalTypeId(node->type);
|
||||||
|
|
||||||
|
std::optional<utils::IdType> maybe_typeclass;
|
||||||
|
if (namespace_visitor_.IsInGlobalNamespace()) {
|
||||||
|
maybe_typeclass = namespace_visitor_.FindTypeclassId(node->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maybe_type.has_value() && maybe_typeclass.has_value()) {
|
||||||
|
error_handling::HandleNamesError("Ambigious namespace name (typeclass or type)", node->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maybe_type.has_value()) {
|
||||||
|
node->link_type_id_ = maybe_type.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maybe_typeclass.has_value()) {
|
||||||
|
node->link_typeclass_id_ = maybe_typeclass.value();
|
||||||
|
if (!namespace_visitor_.IsInGlobalNamespace()) {
|
||||||
|
// other type of error??
|
||||||
|
error_handling::HandleParsingError("Can't use typeclass namespace in other namespace",
|
||||||
|
node->base.start_position,
|
||||||
|
node->base.end_position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace_visitor_.EnterNamespace(node->type, node->modifier);
|
||||||
|
|
||||||
|
Visitor::Visit(&node->scope);
|
||||||
|
|
||||||
|
namespace_visitor_.ExitNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
void LinkSymbolsVisitor::Visit(TypeDefinitionStatement* node) {
|
||||||
|
Visitor::Visit(node->definition.get());
|
||||||
|
Visitor::Visit(node->value);
|
||||||
|
|
||||||
|
utils::IdType graph_id = node->definition->type->graph_id_;
|
||||||
|
|
||||||
|
AddTypeFunctionsToTypeclassGraph(node->type_id_,
|
||||||
|
graph_id,
|
||||||
|
utils::ClassInternalsModifier::Static,
|
||||||
|
node->base);
|
||||||
|
|
||||||
|
AddTypeFunctionsToTypeclassGraph(node->type_id_,
|
||||||
|
graph_id,
|
||||||
|
utils::ClassInternalsModifier::Const,
|
||||||
|
node->base);
|
||||||
|
|
||||||
|
AddTypeFunctionsToTypeclassGraph(node->type_id_,
|
||||||
|
graph_id,
|
||||||
|
utils::ClassInternalsModifier::Var,
|
||||||
|
node->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkSymbolsVisitor::Visit(TypeclassDefinitionStatement* node) {
|
||||||
|
Visitor::Visit(node->definition.get());
|
||||||
|
for (auto& function_requirement : node->requirements) {
|
||||||
|
namespace_visitor_.EnterNamespace(node->definition->type->type, function_requirement.first);
|
||||||
|
Visitor::Visit(function_requirement.second.get());
|
||||||
|
namespace_visitor_.ExitNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto maybe_graph_id = global_info_.AddTypeclassToGraph(node->typeclass_id_);
|
||||||
|
if (!maybe_graph_id.has_value()) {
|
||||||
|
error_handling::HandleNamesError("Can't add typeclass to graph", node->base);
|
||||||
|
}
|
||||||
|
global_info_.GetTypeclassInfo(node->typeclass_id_).graph_id_ = maybe_graph_id.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
void LinkSymbolsVisitor::Visit(TypeExpression* node) {
|
||||||
|
std::vector<std::string> path;
|
||||||
|
path.reserve(node->path.size());
|
||||||
|
|
||||||
|
for (auto& path_type : node->path) {
|
||||||
|
path.push_back(path_type.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->type_id_ = namespace_visitor_.FindTypeId(path, node->type.type);
|
||||||
|
node->constructor_id_ = namespace_visitor_.FindConstructorId(path, node->type.type);
|
||||||
|
|
||||||
|
// internal type
|
||||||
|
if (info::type::ToInternalType(node->type.type).has_value()) {
|
||||||
|
if (!node->path.empty()) {
|
||||||
|
error_handling::HandleNamesError("Internal type is not in namespace", node->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node->type.parameters.empty()) {
|
||||||
|
error_handling::HandleNamesError("Can't parametrize internal type", node->base);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node->type_id_.has_value() && !node->constructor_id_.has_value()) {
|
||||||
|
// check made in typecheck visitor
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->constructor_id_.has_value()) {
|
||||||
|
utils::IdType constructor_type_id = global_info_.GetConstructorInfo(node->constructor_id_.value()).type_id;
|
||||||
|
|
||||||
|
if (node->type_id_.has_value() && node->type_id_.value() != constructor_type_id) {
|
||||||
|
error_handling::HandleNamesError("Contructor and type with same name have different types", node->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->type_id_ = constructor_type_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type_id_.has_value()) {
|
||||||
|
node->type.type_id_ = node->type_id_.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<info::definition::Namespace*> maybe_type_namespace = namespace_visitor_.FindNamespace(path);
|
||||||
|
if (maybe_type_namespace.has_value()) {
|
||||||
|
info::definition::Namespace* type_namespace = maybe_type_namespace.value();
|
||||||
|
|
||||||
|
for (ssize_t i = (ssize_t)node->path.size(); i >= 0; --i) {
|
||||||
|
info::definition::Namespace* parent_namespace = &global_info_.GetNamespaceInfo(type_namespace->parent_namespace);
|
||||||
|
|
||||||
|
auto type_iter = parent_namespace->types.find(type_namespace->type_name);
|
||||||
|
if (type_iter != parent_namespace->types.end()) {
|
||||||
|
node->path[i].type_id_ = type_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
type_namespace = parent_namespace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
void LinkSymbolsVisitor::Visit(ParametrizedTypeclass* node) {
|
||||||
|
std::optional<utils::IdType> maybe_typeclass = namespace_visitor_.FindTypeclassId(node->typeclass);
|
||||||
|
|
||||||
|
if (maybe_typeclass.has_value()) {
|
||||||
|
node->typeclass_id_ = maybe_typeclass.value();
|
||||||
|
} else {
|
||||||
|
error_handling::HandleNamesError("Typeclass not found", node->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->parameters.size() > 0) {
|
||||||
|
error_handling::HandleNamesError("Parametrized typeclasses not implemented yet", node->base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void LinkSymbolsVisitor::AddTypeFunctionsToTypeclassGraph(utils::IdType type_id,
|
||||||
|
utils::IdType graph_id,
|
||||||
|
utils::ClassInternalsModifier namespace_modifier,
|
||||||
|
const BaseNode& base_node) {
|
||||||
|
auto maybe_type_graph_info = typeclass_graph_.GetTypeVertex(graph_id);
|
||||||
|
if (!maybe_type_graph_info.has_value()) {
|
||||||
|
error_handling::HandleInternalError("Type in typeclass graph is not marked as type",
|
||||||
|
"LinkSymbolsVisitor.AddTypeFunctionsToTypeclassGraph",
|
||||||
|
&base_node);
|
||||||
|
}
|
||||||
|
auto type_graph_info = maybe_type_graph_info.value();
|
||||||
|
|
||||||
|
auto maybe_namespace =
|
||||||
|
global_info_.GetTypeNamespace(type_id, namespace_modifier);
|
||||||
|
|
||||||
|
if (maybe_namespace.has_value()) {
|
||||||
|
for (auto& function : maybe_namespace.value()->functions) {
|
||||||
|
auto function_info = global_info_.GetFunctionInfo(function.second);
|
||||||
|
|
||||||
|
auto function_graph_iter = type_graph_info->functions.find(function.first);
|
||||||
|
if (function_graph_iter == type_graph_info->functions.end()) {
|
||||||
|
info::TypeclassGraph::FunctionInfo function_graph_info;
|
||||||
|
|
||||||
|
// can be found after graph calculation
|
||||||
|
if (function_info.declaration.has_value()) {
|
||||||
|
function_graph_info.declaration = function_info.declaration.value().node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// can be found after graph calculation
|
||||||
|
if (function_info.definition.has_value()) {
|
||||||
|
function_graph_info.definition = function_info.definition.value().node;
|
||||||
|
function_graph_info.is_defined_in_owner = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function_graph_info.modifier = namespace_modifier;
|
||||||
|
|
||||||
|
type_graph_info->functions[function.first] = function_graph_info;
|
||||||
|
} else {
|
||||||
|
if (namespace_modifier != function_graph_iter->second.modifier) {
|
||||||
|
error_handling::HandleTypecheckError("Type function \"" + function.first + "\" has definitions / declarations with different modifiers (static / const /var)", base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_handling::HandleInternalError("This code should be unreachable",
|
||||||
|
"LinkSymbolsVisitor.AddTypeFunctionsToTypeclassGraph",
|
||||||
|
&base_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
85
src/main.cpp
Normal file
85
src/main.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "../include/parse_tree.hpp"
|
||||||
|
#include "../include/global_info.hpp"
|
||||||
|
#include "../include/interpreter_tree.hpp"
|
||||||
|
#include "../include/build_visitor.hpp"
|
||||||
|
#include "../include/print_visitor.hpp"
|
||||||
|
#include "../include/find_symbols_visitor.hpp"
|
||||||
|
#include "../include/link_symbols_visitor.hpp"
|
||||||
|
#include "../include/type_check_visitor.hpp"
|
||||||
|
#include "../include/typed_print_visitor.hpp"
|
||||||
|
#include "../include/execute_visitor.hpp"
|
||||||
|
#include "../include/error_handling.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char** argv) { // TODO, only test version
|
||||||
|
if (argc < 2 || argc > 2) {
|
||||||
|
std::cout << "Wrong argument count (provide one argument - source file)\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string filename = argv[1];
|
||||||
|
|
||||||
|
std::ifstream in;
|
||||||
|
in.open(filename); // TODO handle errors
|
||||||
|
|
||||||
|
std::stringstream source_stream;
|
||||||
|
|
||||||
|
source_stream << in.rdbuf();
|
||||||
|
|
||||||
|
in.close();
|
||||||
|
|
||||||
|
std::string source = source_stream.str();
|
||||||
|
|
||||||
|
parser::ParseTree parse_tree(source);
|
||||||
|
|
||||||
|
if (!parse_tree.IsProperlyParsed()) {
|
||||||
|
error_handling::HandleParsingError("There are some parsing errors in file", {0, 0}, {0, 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<interpreter::tokens::SourceFile> source_file =
|
||||||
|
std::make_unique<interpreter::tokens::SourceFile>();
|
||||||
|
|
||||||
|
info::GlobalInfo global_info;
|
||||||
|
info::ContextManager<info::type::Type, info::type::TypeManager> type_context_manager;
|
||||||
|
info::ContextManager<info::value::Value, info::value::ValueManager> context_manager;
|
||||||
|
|
||||||
|
interpreter::BuildVisitor build_visitor(parse_tree);
|
||||||
|
// interpreter::PrintVisitor print_visitor(std::cout);
|
||||||
|
interpreter::FindSymbolsVisitor find_symbols_visitor(global_info);
|
||||||
|
interpreter::LinkSymbolsVisitor link_symbols_visitor(global_info);
|
||||||
|
interpreter::TypeCheckVisitor type_check_visitor(global_info, type_context_manager);
|
||||||
|
// interpreter::TypedPrintVisitor typed_print_visitor(std::cout, type_context_manager);
|
||||||
|
|
||||||
|
build_visitor.VisitSourceFile(source_file.get());
|
||||||
|
|
||||||
|
// std::cout << "\n---------------------------------- Untyped -------------------------------------\n\n";
|
||||||
|
// print_visitor.VisitSourceFile(source_file.get());
|
||||||
|
|
||||||
|
find_symbols_visitor.VisitSourceFile(source_file.get());
|
||||||
|
link_symbols_visitor.VisitSourceFile(source_file.get());
|
||||||
|
type_check_visitor.VisitSourceFile(source_file.get());
|
||||||
|
|
||||||
|
std::optional<utils::IdType> maybe_main_partition_id = global_info.FindPartition({"main"});
|
||||||
|
|
||||||
|
if (!maybe_main_partition_id.has_value()) {
|
||||||
|
error_handling::HandleGeneralError("No main partition found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const info::GlobalInfo::PartitionInfo& main_partition =
|
||||||
|
global_info.GetPartitionInfo(maybe_main_partition_id.value());
|
||||||
|
|
||||||
|
std::cout << "\n---------------------------------- Execution -------------------------------------\n\n";
|
||||||
|
|
||||||
|
interpreter::ExecuteVisitor execute_visitor(global_info,
|
||||||
|
type_context_manager,
|
||||||
|
context_manager);
|
||||||
|
|
||||||
|
execute_visitor.ExecutePartition(main_partition.node);
|
||||||
|
|
||||||
|
// std::cout << "\n---------------------------------- Typed -------------------------------------\n\n";
|
||||||
|
// typed_print_visitor.VisitSourceFile(source_file.get());
|
||||||
|
}
|
||||||
746
src/print_visitor.cpp
Normal file
746
src/print_visitor.cpp
Normal file
|
|
@ -0,0 +1,746 @@
|
||||||
|
// for clangd
|
||||||
|
#include "../include/print_visitor.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(SourceFile* node) {
|
||||||
|
out_ << "[SourceFile] (\n\n";
|
||||||
|
for (auto& statement : node->statements) {
|
||||||
|
Visitor::Visit(statement);
|
||||||
|
}
|
||||||
|
out_ << "\n)\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(NamespaceSources* node) {
|
||||||
|
out_ << "[NamespaceSources](\n";
|
||||||
|
for (auto& statement : node->statements) {
|
||||||
|
Visitor::Visit(statement);
|
||||||
|
}
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(Namespace* node) {
|
||||||
|
out_ << "[Namespace] ";
|
||||||
|
switch (node->modifier) {
|
||||||
|
case utils::ClassInternalsModifier::Const:
|
||||||
|
out_ << "const ";
|
||||||
|
break;
|
||||||
|
case utils::ClassInternalsModifier::Var:
|
||||||
|
out_ << "var ";
|
||||||
|
break;
|
||||||
|
case utils::ClassInternalsModifier::Static:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Visit(&node->type);
|
||||||
|
out_ << "{\n";
|
||||||
|
Visit(&node->scope);
|
||||||
|
out_ << "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(ImportStatement* node) {
|
||||||
|
if (node->name.has_value()) {
|
||||||
|
out_ << "[Use " << node->name.value() << "] = ";
|
||||||
|
}
|
||||||
|
out_ << "[Import " << node->module_name << "]";
|
||||||
|
if (!node->symbols.empty()) {
|
||||||
|
out_ << " (\n";
|
||||||
|
for (auto& symbol : node->symbols) {
|
||||||
|
Visit(&symbol);
|
||||||
|
out_ << '\n';
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
out_ << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(AliasDefinitionStatement* node) {
|
||||||
|
out_ << "[Alias ";
|
||||||
|
switch (node->modifier) {
|
||||||
|
case utils::AliasModifier::Alias:
|
||||||
|
out_ << "alias";
|
||||||
|
break;
|
||||||
|
case utils::AliasModifier::Type:
|
||||||
|
out_ << "type";
|
||||||
|
break;
|
||||||
|
case utils::AliasModifier::Let:
|
||||||
|
out_ << "let";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out_ << ' ';
|
||||||
|
Visit(&node->type);
|
||||||
|
out_ << "] = (";
|
||||||
|
Visit(node->value.get());
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(VariableDefinitionStatement* node) {
|
||||||
|
out_ << "[Variable ";
|
||||||
|
switch (node->modifier) {
|
||||||
|
case utils::IsConstModifier::Const:
|
||||||
|
out_ << "const";
|
||||||
|
break;
|
||||||
|
case utils::IsConstModifier::Var:
|
||||||
|
out_ << "var";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out_ << ' ';
|
||||||
|
Visitor::Visit(node->name);
|
||||||
|
out_ << "] = (";
|
||||||
|
Visitor::Visit(node->value);
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(FunctionDeclaration* node) {
|
||||||
|
out_ << "[FunctionDeclaration ";
|
||||||
|
if (node->is_in_interface) {
|
||||||
|
out_ << "interface ";
|
||||||
|
}
|
||||||
|
Visit(&node->name);
|
||||||
|
out_ << "] (";
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
out_ << ") : (";
|
||||||
|
Visit(node->type.get());
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(FunctionDefinitionStatement* node) {
|
||||||
|
out_ << "[Function] (";
|
||||||
|
Visit(node->definition.get());
|
||||||
|
out_ << ") = (";
|
||||||
|
Visitor::Visit(node->value);
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(TypeDefinitionStatement* node) {
|
||||||
|
out_ << "[Type ";
|
||||||
|
switch (node->modifier) {
|
||||||
|
case utils::ClassModifier::Struct:
|
||||||
|
out_ << "struct";
|
||||||
|
break;
|
||||||
|
case utils::ClassModifier::Class:
|
||||||
|
out_ << "class";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (node->is_in_interface) {
|
||||||
|
out_ << " interface";
|
||||||
|
}
|
||||||
|
out_ << "] (";
|
||||||
|
Visit(node->definition.get());
|
||||||
|
out_ << ") = (";
|
||||||
|
Visitor::Visit(node->value);
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(AbstractTypeDefinitionStatement* node) {
|
||||||
|
out_ << "[AbstractType ";
|
||||||
|
switch (node->modifier) {
|
||||||
|
case utils::AbstractTypeModifier::Basic:
|
||||||
|
out_ << "basic";
|
||||||
|
break;
|
||||||
|
case utils::AbstractTypeModifier::Abstract:
|
||||||
|
out_ << "abstract";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out_ << "] (";
|
||||||
|
Visit(node->type.get());
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(TypeclassDefinitionStatement* node) {
|
||||||
|
out_ << "[Typeclass] (";
|
||||||
|
Visit(node->definition.get());
|
||||||
|
if (!node->requirements.empty()) {
|
||||||
|
out_ << ") : (\n";
|
||||||
|
}
|
||||||
|
for (auto& requirement : node->requirements) {
|
||||||
|
out_ << "& ";
|
||||||
|
switch (requirement.first) {
|
||||||
|
case utils::ClassInternalsModifier::Const:
|
||||||
|
out_ << "const ";
|
||||||
|
break;
|
||||||
|
case utils::ClassInternalsModifier::Var:
|
||||||
|
out_ << "var ";
|
||||||
|
break;
|
||||||
|
case utils::ClassInternalsModifier::Static:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Visit(requirement.second.get());
|
||||||
|
out_ << "\n";
|
||||||
|
}
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(PartitionStatement* node) {
|
||||||
|
out_ << "[Partition ";
|
||||||
|
switch (node->modifier) {
|
||||||
|
case utils::PartitionModifier::Exec:
|
||||||
|
out_ << "exec ";
|
||||||
|
break;
|
||||||
|
case utils::PartitionModifier::Test:
|
||||||
|
out_ << "test ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Visit(&node->name);
|
||||||
|
out_ << "] = (";
|
||||||
|
Visitor::Visit(node->value);
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(FunctionDefinition* node) {
|
||||||
|
out_ << "[FunctionDefinition ";
|
||||||
|
Visit(&node->name);
|
||||||
|
out_ << "]";
|
||||||
|
if (!node->arguments.empty()) {
|
||||||
|
out_ << " : (";
|
||||||
|
for (auto& argument : node->arguments) {
|
||||||
|
Visit(&argument);
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
out_ << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(TypeDefinition* node) {
|
||||||
|
out_ << "[TypeDefinition] (";
|
||||||
|
Visit(node->type.get());
|
||||||
|
out_ << ')';
|
||||||
|
if (!node->parameters.empty()) {
|
||||||
|
out_ << '(';
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
out_ << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(AnyAnnotatedType* node) {
|
||||||
|
out_ << "[Annotated (Abstract) Type ";
|
||||||
|
Visit(&node->type);
|
||||||
|
out_ << ']';
|
||||||
|
if (!node->typeclasses.empty()) {
|
||||||
|
out_ << " (";
|
||||||
|
for (auto& typeclass : node->typeclasses) {
|
||||||
|
Visit(typeclass.get());
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
out_ << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(TypeConstructorPatternParameter* node) {
|
||||||
|
out_ << "[TypeConstructorPatternParameter ";
|
||||||
|
if (node->name.has_value()) {
|
||||||
|
Visit(&node->name.value());
|
||||||
|
out_ << " = ";
|
||||||
|
}
|
||||||
|
Visitor::Visit(node->value);
|
||||||
|
out_ << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(TypeConstructorPattern* node) {
|
||||||
|
out_ << "[TypeConstructorPattern ";
|
||||||
|
Visit(node->constructor.get());
|
||||||
|
out_ << "]\n(";
|
||||||
|
|
||||||
|
bool is_first = true;
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
if (!is_first) {
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
is_first = false;
|
||||||
|
out_ << '(';
|
||||||
|
Visit(¶meter);
|
||||||
|
}
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(MatchCase* node) {
|
||||||
|
out_ << "[MatchCase | ";
|
||||||
|
Visitor::Visit(node->value);
|
||||||
|
if (node->condition.has_value()) {
|
||||||
|
out_ << " ? ";
|
||||||
|
Visitor::Visit(node->condition.value());
|
||||||
|
}
|
||||||
|
if (node->statement.has_value()) {
|
||||||
|
out_ << " -> ";
|
||||||
|
Visitor::Visit(node->statement.value());
|
||||||
|
}
|
||||||
|
out_ << "]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(Match* node) {
|
||||||
|
out_ << "[Match";
|
||||||
|
if (node->is_consuming_value) {
|
||||||
|
out_ << " <- ";
|
||||||
|
}
|
||||||
|
out_ << "] (";
|
||||||
|
Visitor::Visit(node->value);
|
||||||
|
out_ << ") [with] (\n";
|
||||||
|
for (auto& match_case : node->matches) {
|
||||||
|
Visit(&match_case);
|
||||||
|
}
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(Condition* node) {
|
||||||
|
out_ << "[If] (";
|
||||||
|
Visitor::Visit(node->conditions[0]);
|
||||||
|
out_ << ") [then] (\n";
|
||||||
|
Visitor::Visit(node->statements[0]);
|
||||||
|
out_ << ')';
|
||||||
|
for (size_t i = 1; i < node->conditions.size(); ++i) {
|
||||||
|
out_ << " [elif] (";
|
||||||
|
Visitor::Visit(node->conditions[i]);
|
||||||
|
out_ << ") [then] (\n";
|
||||||
|
Visitor::Visit(node->statements[i]);
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
if (node->statements.size() > node->conditions.size()) {
|
||||||
|
out_ << " [else] (\n";
|
||||||
|
Visitor::Visit(node->statements[node->conditions.size()]);
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
out_ << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(DoWhileLoop* node) {
|
||||||
|
out_ << "[Do] (\n";
|
||||||
|
Visitor::Visit(node->statement);
|
||||||
|
out_ << ") [while] (";
|
||||||
|
Visitor::Visit(node->condition);
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(WhileLoop* node) {
|
||||||
|
out_ << "[While] (";
|
||||||
|
Visitor::Visit(node->condition);
|
||||||
|
out_ << ") [do] (\n";
|
||||||
|
Visitor::Visit(node->statement);
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
void PrintVisitor::Visit(ForLoop* node) {
|
||||||
|
out_ << "[For ";
|
||||||
|
switch (node->variable_modifier) {
|
||||||
|
case utils::IsConstModifier::Const:
|
||||||
|
break;
|
||||||
|
case utils::IsConstModifier::Var:
|
||||||
|
out_ << "var";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out_ << "] (";
|
||||||
|
Visitor::Visit(node->variable);
|
||||||
|
out_ << ") [in] (";
|
||||||
|
Visitor::Visit(node->interval);
|
||||||
|
out_ << ") [do] (\n";
|
||||||
|
Visitor::Visit(node->statement);
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(LoopLoop* node) {
|
||||||
|
out_ << "[Loop] (\n";
|
||||||
|
Visitor::Visit(node->statement);
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(Block* node) {
|
||||||
|
out_ << "[Block] {\n";
|
||||||
|
for (auto& statement : node->statements) {
|
||||||
|
Visitor::Visit(statement);
|
||||||
|
}
|
||||||
|
out_ << "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(ScopedStatement* node) {
|
||||||
|
out_ << "[Scoped] ( ";
|
||||||
|
Visitor::Visit(node->statement);
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(LoopControlExpression& node) { // enum
|
||||||
|
switch (node) {
|
||||||
|
case LoopControlExpression::Break:
|
||||||
|
out_ << "[Break]\n";
|
||||||
|
break;
|
||||||
|
case LoopControlExpression::Continue:
|
||||||
|
out_ << "[Continue]\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(ReferenceExpression* node) {
|
||||||
|
out_ << "[ReferenceExpression ";
|
||||||
|
switch (node->reference) {
|
||||||
|
case utils::ReferenceModifier::Reference:
|
||||||
|
out_ << '^';
|
||||||
|
break;
|
||||||
|
case utils::ReferenceModifier::UniqueReference:
|
||||||
|
out_ << '@';
|
||||||
|
break;
|
||||||
|
case utils::ReferenceModifier::Dereference:
|
||||||
|
out_ << '~';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out_ << "] (";
|
||||||
|
Visit(node->expression.get());
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(AccessExpression* node) {
|
||||||
|
out_ << "[AccessExpression] (";
|
||||||
|
Visit(node->name.get());
|
||||||
|
out_ << ") ` (";
|
||||||
|
Visitor::Visit(node->id);
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other Expressions
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(FunctionCallExpression* node) {
|
||||||
|
out_ << "[FunctionCall ";
|
||||||
|
|
||||||
|
if (node->is_binary_operator_expression) {
|
||||||
|
out_ << "(binary operation) ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->prefix.has_value()) {
|
||||||
|
out_ << '(';
|
||||||
|
if (std::holds_alternative<std::unique_ptr<SubExpressionToken>>(node->prefix.value())) {
|
||||||
|
Visitor::Visit(*std::get<std::unique_ptr<SubExpressionToken>>(node->prefix.value()));
|
||||||
|
} else if (std::holds_alternative<std::unique_ptr<TypeExpression>>(node->prefix.value())) {
|
||||||
|
Visit(std::get<std::unique_ptr<TypeExpression>>(node->prefix.value()).get());
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
out_ << ").";
|
||||||
|
}
|
||||||
|
|
||||||
|
Visit(&node->name);
|
||||||
|
|
||||||
|
out_ << "] (";
|
||||||
|
|
||||||
|
bool is_first = true;
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
if (!is_first) {
|
||||||
|
out_ << ", ";
|
||||||
|
}
|
||||||
|
is_first = false;
|
||||||
|
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
out_ << ") : (";
|
||||||
|
|
||||||
|
is_first = true;
|
||||||
|
for (auto& argument : node->arguments) {
|
||||||
|
if (!is_first) {
|
||||||
|
out_ << ", ";
|
||||||
|
}
|
||||||
|
is_first = false;
|
||||||
|
|
||||||
|
Visitor::Visit(argument);
|
||||||
|
}
|
||||||
|
out_ << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(TupleExpression* node) {
|
||||||
|
out_ << "[TupleExpression] (";
|
||||||
|
for (auto& expression : node->expressions) {
|
||||||
|
out_ << "&";
|
||||||
|
Visitor::Visit(expression);
|
||||||
|
}
|
||||||
|
out_ << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(VariantExpression* node) {
|
||||||
|
out_ << "[VariantExpression] (";
|
||||||
|
for (auto& expression : node->expressions) {
|
||||||
|
out_ << "|";
|
||||||
|
Visitor::Visit(expression);
|
||||||
|
}
|
||||||
|
out_ << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(ReturnExpression* node) {
|
||||||
|
if (node->is_from_definition) {
|
||||||
|
out_ << "[Return] (";
|
||||||
|
} else {
|
||||||
|
out_ << "[Bring] (";
|
||||||
|
}
|
||||||
|
|
||||||
|
Visitor::Visit(node->expression);
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(TypeConstructorParameter* node) {
|
||||||
|
out_ << "[TypeConstructorParameter ";
|
||||||
|
if (node->name.has_value()) {
|
||||||
|
Visit(&node->name.value());
|
||||||
|
switch (node->asignment_modifier.value()) {
|
||||||
|
case utils::AssignmentModifier::Assign:
|
||||||
|
out_ << " = ";
|
||||||
|
break;
|
||||||
|
case utils::AssignmentModifier::Move:
|
||||||
|
out_ << " <- ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Visitor::Visit(node->value);
|
||||||
|
out_ << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(TypeConstructor* node) {
|
||||||
|
out_ << "[TypeConstructor ";
|
||||||
|
Visit(node->constructor.get());
|
||||||
|
out_ << "]\n(";
|
||||||
|
|
||||||
|
bool is_first = true;
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
if (!is_first) {
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
is_first = false;
|
||||||
|
out_ << '(';
|
||||||
|
Visit(¶meter);
|
||||||
|
}
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(LambdaFunction* node) {
|
||||||
|
out_ << "[LambdaFunction] (";
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
if (!node->parameters.empty()) {
|
||||||
|
out_ << ") : (";
|
||||||
|
}
|
||||||
|
for (auto& argument : node->arguments) {
|
||||||
|
Visit(&argument);
|
||||||
|
}
|
||||||
|
out_ << ") -> (\n";
|
||||||
|
Visitor::Visit(node->expression);
|
||||||
|
out_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(ArrayExpression* node) {
|
||||||
|
out_ << "[ArrayExpression] ( ,";
|
||||||
|
for (auto& element : node->elements) {
|
||||||
|
Visitor::Visit(element);
|
||||||
|
out_ << " ,";
|
||||||
|
}
|
||||||
|
out_ << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(PartitionName* node) {
|
||||||
|
out_ << "[PartitionName] (";
|
||||||
|
for (size_t i = 0; i < node->path.size(); ++i) {
|
||||||
|
Visit(&node->path[i]);
|
||||||
|
if (i + 1 < node->path.size()) {
|
||||||
|
out_ << "::";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(NameExpression* node) {
|
||||||
|
out_ << "[NameExpression] (";
|
||||||
|
for (size_t i = 0; i < node->names.size(); ++i) {
|
||||||
|
Visit(&node->names[i]);
|
||||||
|
if (i + 1 < node->names.size()) {
|
||||||
|
out_ << "::";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(TupleName* node) {
|
||||||
|
out_ << "[TupleName] (";
|
||||||
|
for (auto& name : node->names) {
|
||||||
|
out_ << "& ";
|
||||||
|
Visitor::Visit(name);
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(VariantName* node) {
|
||||||
|
out_ << "[VariantName] (";
|
||||||
|
for (auto& name : node->names) {
|
||||||
|
out_ << "| ";
|
||||||
|
Visitor::Visit(name);
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(AnnotatedName* node) {
|
||||||
|
out_ << "[AnnotatedName ";
|
||||||
|
Visit(&node->name);
|
||||||
|
out_ << ']';
|
||||||
|
if (node->type.has_value()) {
|
||||||
|
out_ << " : (";
|
||||||
|
Visitor::Visit(node->type.value());
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(FunctionType* node) {
|
||||||
|
out_ << "[FunctionType] (";
|
||||||
|
bool is_first = true;
|
||||||
|
for (auto& type : node->types) {
|
||||||
|
if (!is_first || node->types.size() == 1) {
|
||||||
|
out_ << " -> ";
|
||||||
|
}
|
||||||
|
is_first = false;
|
||||||
|
Visitor::Visit(type);
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(TupleType* node) {
|
||||||
|
out_ << "[TupleType ";
|
||||||
|
if (node->type.has_value()) {
|
||||||
|
Visit(&node->type.value());
|
||||||
|
}
|
||||||
|
out_ << "] (";
|
||||||
|
for (auto& entity : node->entities) {
|
||||||
|
out_ << "& ";
|
||||||
|
if (entity.first.has_value()) {
|
||||||
|
Visit(&entity.first.value());
|
||||||
|
out_ << " : ";
|
||||||
|
}
|
||||||
|
Visit(entity.second.get());
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(VariantType* node) {
|
||||||
|
out_ << "[VariantType ";
|
||||||
|
if (node->type.has_value()) {
|
||||||
|
Visit(&node->type.value());
|
||||||
|
}
|
||||||
|
out_ << "] (";
|
||||||
|
for (auto& constructor : node->constructors) {
|
||||||
|
out_ << "| ";
|
||||||
|
if (std::holds_alternative<Constructor>(constructor)) {
|
||||||
|
Visit(&std::get<Constructor>(constructor));
|
||||||
|
} else if (std::holds_alternative<std::unique_ptr<TupleType>>(constructor)) {
|
||||||
|
Visit(std::get<std::unique_ptr<TupleType>>(constructor).get());
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(TypeExpression* node) {
|
||||||
|
out_ << "[TypeExpression ";
|
||||||
|
|
||||||
|
if (node->array_size.has_value()) {
|
||||||
|
out_ << "[array size: " << node->array_size.value() << ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
out_ << "] (";
|
||||||
|
for (auto& type : node->path) {
|
||||||
|
Visit(&type);
|
||||||
|
out_ << "::";
|
||||||
|
}
|
||||||
|
Visit(&node->type);
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(ExtendedScopedAnyType* node) {
|
||||||
|
out_ << "[ExtendedScopedAnyType ";
|
||||||
|
for (auto& reference : node->references) {
|
||||||
|
switch (reference) {
|
||||||
|
case utils::ReferenceModifier::Reference:
|
||||||
|
out_ << '^';
|
||||||
|
break;
|
||||||
|
case utils::ReferenceModifier::UniqueReference:
|
||||||
|
out_ << '@';
|
||||||
|
break;
|
||||||
|
case utils::ReferenceModifier::Dereference:
|
||||||
|
out_ << '~';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_ << "] (";
|
||||||
|
Visitor::Visit(node->type);
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(ParametrizedTypeclass* node) {
|
||||||
|
out_ << "[ParametrizedTypeclass] (";
|
||||||
|
Visit(&node->typeclass);
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
out_ << ' ';
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typeclass & Type -----------------
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(ParametrizedType* node) {
|
||||||
|
out_ << "[ParametrizedType] (";
|
||||||
|
Visit(&node->type);
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
out_ << ' ';
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
out_ << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(std::string* node) { // std::string
|
||||||
|
out_ << "[Identifier " << *node << "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(FloatNumberLiteral* node) {
|
||||||
|
out_ << "[FloatNumber " << node->value << "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(NumberLiteral* node) {
|
||||||
|
out_ << "[Number " << node->value << "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(StringLiteral* node) {
|
||||||
|
out_ << "[String " << node->value << "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(CharLiteral* node) {
|
||||||
|
out_ << "[Char " << node->value << "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(UnitLiteral*) {
|
||||||
|
out_ << "[Unit ()] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintVisitor::Visit(BoolLiteral* node) {
|
||||||
|
out_ << "[Bool " << (node->value ? "true" : "false") << "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
1685
src/type_check_visitor.cpp
Normal file
1685
src/type_check_visitor.cpp
Normal file
File diff suppressed because it is too large
Load diff
162
src/typeclass_graph.cpp
Normal file
162
src/typeclass_graph.cpp
Normal file
|
|
@ -0,0 +1,162 @@
|
||||||
|
// for clangd
|
||||||
|
#include "../include/typeclass_graph.hpp"
|
||||||
|
#include "../include/error_handling.hpp"
|
||||||
|
|
||||||
|
namespace info {
|
||||||
|
|
||||||
|
utils::IdType TypeclassGraph::AddVertex(
|
||||||
|
const std::string& name,
|
||||||
|
const std::vector<std::string>& dependencies, // TODO: parameters
|
||||||
|
const std::vector<std::pair<std::string, std::pair<utils::ClassInternalsModifier, interpreter::tokens::FunctionDeclaration*>>>& function_declarations,
|
||||||
|
const std::vector<std::pair<std::string, interpreter::tokens::FunctionDefinitionStatement*>>& function_definitions,
|
||||||
|
interpreter::tokens::BaseNode* base_node,
|
||||||
|
Modifier modifier) {
|
||||||
|
|
||||||
|
if (name_to_typeclass_.count(name) != 0) {
|
||||||
|
error_handling::HandleTypecheckError("Typeclass \"" + name + "\" already defined (other type / typeclass can't have this name)", *base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modifier == Modifier::Typeclass) {
|
||||||
|
for (auto& method : function_declarations) {
|
||||||
|
if (method_to_vertex_.count(method.first) != 0) {
|
||||||
|
error_handling::HandleTypecheckError("Typeclass \"" + name + "\" method \"" + method.first + "\" already declaret in another typeclass", *base_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is_calculated_ = false;
|
||||||
|
|
||||||
|
utils::IdType id = verticles_.size();
|
||||||
|
|
||||||
|
verticles_.emplace_back();
|
||||||
|
Vertex& vertex = verticles_.back();
|
||||||
|
vertex.name = name;
|
||||||
|
vertex.base_node = base_node;
|
||||||
|
vertex.modifier = modifier;
|
||||||
|
|
||||||
|
for (auto& dependency : dependencies) {
|
||||||
|
vertex.dependencies.insert(dependency);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& method : function_declarations) {
|
||||||
|
FunctionInfo function_info;
|
||||||
|
function_info.modifier = method.second.first;
|
||||||
|
function_info.declaration = method.second.second;
|
||||||
|
|
||||||
|
vertex.functions[method.first] = function_info;
|
||||||
|
|
||||||
|
if (modifier == Modifier::Typeclass) {
|
||||||
|
method_to_vertex_[method.first] = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (modifier == Modifier::Typeclass) {
|
||||||
|
name_to_typeclass_[name] = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& method : function_definitions) {
|
||||||
|
FunctionInfo& function_info = vertex.functions[method.first];
|
||||||
|
function_info.definition = method.second;
|
||||||
|
function_info.is_defined_in_owner = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> TypeclassGraph::FindFunctionTypeclass(const std::string& name) {
|
||||||
|
auto function_iter = method_to_vertex_.find(name);
|
||||||
|
if (function_iter == method_to_vertex_.end()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return function_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<TypeclassGraph::FunctionInfo*> TypeclassGraph::GetFunctionInfo(const std::string& name,
|
||||||
|
std::optional<utils::IdType> vertex_id) {
|
||||||
|
if (vertex_id.has_value()) {
|
||||||
|
auto function_info_iter = verticles_[vertex_id.value()].functions.find(name);
|
||||||
|
return function_info_iter !=
|
||||||
|
verticles_[vertex_id.value()].functions.end()
|
||||||
|
? std::optional<TypeclassGraph::FunctionInfo*>(&function_info_iter->second)
|
||||||
|
: std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto maybe_function_typeclass_id = FindFunctionTypeclass(name);
|
||||||
|
|
||||||
|
if (!maybe_function_typeclass_id.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &verticles_[maybe_function_typeclass_id.value()].functions[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_set<utils::IdType> TypeclassGraph::GetDependenciesSet(utils::IdType id) {
|
||||||
|
std::unordered_set<utils::IdType> dependencies;
|
||||||
|
|
||||||
|
dependencies.reserve(verticles_.at(id).dependencies.size());
|
||||||
|
for (auto& dependency : verticles_[id].dependencies) {
|
||||||
|
dependencies.insert(name_to_typeclass_[dependency]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<utils::IdType> TypeclassGraph::GetDependenciesVector(utils::IdType id) {
|
||||||
|
std::vector<utils::IdType> dependencies;
|
||||||
|
|
||||||
|
dependencies.reserve(verticles_.at(id).dependencies.size());
|
||||||
|
for (auto& dependency : verticles_[id].dependencies) {
|
||||||
|
dependencies.push_back(name_to_typeclass_[dependency]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeclassGraph::CalculateGraph() {
|
||||||
|
if (is_calculated_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<size_t>> edges(verticles_.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < verticles_.size(); ++i) {
|
||||||
|
edges[i].reserve(verticles_[i].dependencies.size());
|
||||||
|
for (auto& dependency : verticles_[i].dependencies) {
|
||||||
|
auto dependency_iter = name_to_typeclass_.find(dependency);
|
||||||
|
|
||||||
|
if (dependency_iter == name_to_typeclass_.end()) {
|
||||||
|
error_handling::HandleTypecheckError("Dependency typeclass \"" + dependency + "\" not found", *verticles_[i].base_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
edges[i].push_back(dependency_iter->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> sorted_verticles = utils::BackTopSort(edges);
|
||||||
|
// std::reverse(sorted_verticles.begin(), sorted_verticles.end());
|
||||||
|
|
||||||
|
for (auto& id : sorted_verticles) {
|
||||||
|
for (auto& dependency : verticles_[id].dependencies) {
|
||||||
|
for (auto& method : verticles_[name_to_typeclass_[dependency]].functions) {
|
||||||
|
auto function_iter = verticles_[id].functions.find(method.first);
|
||||||
|
if (function_iter == verticles_[id].functions.end()) {
|
||||||
|
verticles_[id].functions[method.first] = method.second;
|
||||||
|
} else {
|
||||||
|
if (!function_iter->second.definition.has_value()) {
|
||||||
|
function_iter->second.definition = method.second.definition;
|
||||||
|
} else {
|
||||||
|
if (!function_iter->second.is_defined_in_owner) {
|
||||||
|
error_handling::HandleTypecheckError("Method \"" + method.first + "\" defined in more then one dependency of type / typeclass \"" + verticles_[id].name + "\"", *verticles_[id].base_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& inherited_dependency : verticles_[name_to_typeclass_[dependency]].dependencies) {
|
||||||
|
verticles_[id].dependencies.insert(inherited_dependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is_calculated_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace info
|
||||||
1059
src/typed_print_visitor.cpp
Normal file
1059
src/typed_print_visitor.cpp
Normal file
File diff suppressed because it is too large
Load diff
588
src/types.cpp
Normal file
588
src/types.cpp
Normal file
|
|
@ -0,0 +1,588 @@
|
||||||
|
// for clangd
|
||||||
|
#include "../include/types.hpp"
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
namespace info::type {
|
||||||
|
|
||||||
|
std::optional<utils::IdType> AbstractType::InContext(const std::unordered_map<std::string, utils::IdType>& context) {
|
||||||
|
auto type_iter = context.find(typeclass_graph_.GetVertex(graph_id_).name);
|
||||||
|
|
||||||
|
if (type_iter != context.end()) {
|
||||||
|
return type_iter->second;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractType::Same(const AbstractType& type) const {
|
||||||
|
return graph_id_ == type.graph_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractType::operator<(const AbstractType& type) const { // TODO: cache DependenciesSet
|
||||||
|
return typeclass_graph_.GetDependenciesSet(graph_id_).count(type.graph_id_) != 0 || graph_id_ == type.graph_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractType::operator>(const AbstractType& type) const {
|
||||||
|
return type < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> AbstractType::GetFieldType(const std::string&,
|
||||||
|
const std::unordered_set<utils::IdType>&) const {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
std::optional<utils::IdType> DefinedType::InContext(const std::unordered_map<std::string, utils::IdType>& context) {
|
||||||
|
std::optional<utils::IdType> maybe_type_replacement = type_manager_->GetAnyValue(type_)->InContext(context);
|
||||||
|
|
||||||
|
if (maybe_type_replacement.has_value()) {
|
||||||
|
type_ = maybe_type_replacement.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefinedType::Same(const DefinedType& type) const {
|
||||||
|
return type_id_ == type.type_id_
|
||||||
|
&& type_manager_->GetAnyValue(type_)->Same(*type_manager_->GetAnyValue(type.type_));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefinedType::operator<(const DefinedType& type) const {
|
||||||
|
return type_id_ == type.type_id_
|
||||||
|
&& *type_manager_->GetAnyValue(type_) < *type_manager_->GetAnyValue(type.type_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefinedType::operator>(const DefinedType& type) const {
|
||||||
|
return type < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> DefinedType::GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const {
|
||||||
|
if (class_modifier_ == utils::ClassModifier::Struct || type_namespaces.count(type_id_) != 0) {
|
||||||
|
return type_manager_->GetAnyValue(type_)->GetFieldType(name, type_namespaces);
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
std::optional<utils::IdType> TupleType::InContext(const std::unordered_map<std::string, utils::IdType>& context) {
|
||||||
|
for (size_t i = 0; i < fields_.size(); ++i) {
|
||||||
|
std::optional<utils::IdType> maybe_field_replacement = type_manager_->GetAnyValue(fields_[i].second)->InContext(context);
|
||||||
|
|
||||||
|
if (maybe_field_replacement.has_value()) {
|
||||||
|
fields_[i].second = maybe_field_replacement.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TupleType::Same(const TupleType& type) const {
|
||||||
|
if (fields_.size() != type.fields_.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fields_.size(); ++i) {
|
||||||
|
if (!type_manager_->GetAnyValue(fields_[i].second)->Same(*type_manager_->GetAnyValue(type.fields_[i].second))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TupleType::operator<(const TupleType& type) const {
|
||||||
|
if (fields_.size() != type.fields_.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fields_.size(); ++i) {
|
||||||
|
if (!(*type_manager_->GetAnyValue(fields_[i].second) < *type_manager_->GetAnyValue(type.fields_[i].second))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TupleType::operator>(const TupleType& type) const {
|
||||||
|
return type < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> TupleType::GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>&) const {
|
||||||
|
for (size_t i = 0; i < fields_.size(); ++i) { // TODO: optimize??
|
||||||
|
if (fields_[i].first.has_value() && fields_[i].first.value() == name) {
|
||||||
|
return fields_[i].second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TupleType::ToString() {
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
result += "(";
|
||||||
|
|
||||||
|
for (auto& field : fields_) {
|
||||||
|
result += "& ";
|
||||||
|
result += type_manager_->GetAnyValue(field.second)->ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
result += ")";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
std::optional<utils::IdType> VariantType::InContext(const std::unordered_map<std::string, utils::IdType>& context) {
|
||||||
|
for (size_t i = 0; i < constructors_.size(); ++i) {
|
||||||
|
constructors_[i].InContext(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VariantType::Same(const VariantType& type) const {
|
||||||
|
if (constructors_.size() != type.constructors_.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < constructors_.size(); ++i) {
|
||||||
|
if (!constructors_[i].Same(constructors_[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VariantType::operator<(const VariantType& type) const {
|
||||||
|
if (constructors_.size() != type.constructors_.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < constructors_.size(); ++i) {
|
||||||
|
if (!(constructors_[i] < constructors_[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VariantType::operator>(const VariantType& type) const {
|
||||||
|
return type < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> VariantType::GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const {
|
||||||
|
if (current_constructor_.has_value()) {
|
||||||
|
return constructors_.at(current_constructor_.value()).GetFieldType(name, type_namespaces);
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string VariantType::ToString() {
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
result += "(";
|
||||||
|
|
||||||
|
for (auto& constructor : constructors_) {
|
||||||
|
result += "& ";
|
||||||
|
result += constructor.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
result += ")";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
std::optional<utils::IdType> OptionalType::InContext(const std::unordered_map<std::string, utils::IdType>& context) {
|
||||||
|
std::optional<utils::IdType> maybe_type_replacement = type_manager_->GetAnyValue(type_)->InContext(context);
|
||||||
|
|
||||||
|
if (maybe_type_replacement.has_value()) {
|
||||||
|
type_ = maybe_type_replacement.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OptionalType::Same(const OptionalType& type) const {
|
||||||
|
return type_manager_->GetAnyValue(type_)->Same(*type_manager_->GetAnyValue(type.type_));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OptionalType::operator<(const OptionalType& type) const {
|
||||||
|
return *type_manager_->GetAnyValue(type_) < *type_manager_->GetAnyValue(type.type_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OptionalType::operator>(const OptionalType& type) const {
|
||||||
|
return type < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> OptionalType::GetFieldType(const std::string&,
|
||||||
|
const std::unordered_set<utils::IdType>&) const {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OptionalType::ToString() {
|
||||||
|
return "Optional " + type_manager_->GetAnyValue(type_)->ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
std::optional<utils::IdType> ReferenceToType::InContext(const std::unordered_map<std::string, utils::IdType>& context) {
|
||||||
|
std::optional<utils::IdType> maybe_type_replacement = type_manager_->GetAnyValue(type_)->InContext(context);
|
||||||
|
|
||||||
|
if (maybe_type_replacement.has_value()) {
|
||||||
|
type_ = maybe_type_replacement.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReferenceToType::Same(const ReferenceToType& type) const {
|
||||||
|
return references_ == type.references_ && type_manager_->GetAnyValue(type_)->Same(*type_manager_->GetAnyValue(type.type_));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReferenceToType::operator<(const ReferenceToType& type) const {
|
||||||
|
return references_ == type.references_ && *type_manager_->GetAnyValue(type_) < *type_manager_->GetAnyValue(type.type_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReferenceToType::operator>(const ReferenceToType& type) const {
|
||||||
|
return type < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> ReferenceToType::GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const {
|
||||||
|
return type_manager_->GetAnyValue(type_)->GetFieldType(name, type_namespaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string ReferenceToType::ToString() {
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
for (auto& reference : references_) {
|
||||||
|
switch (reference) {
|
||||||
|
case utils::ReferenceModifier::Dereference:
|
||||||
|
result += '~';
|
||||||
|
break;
|
||||||
|
case utils::ReferenceModifier::Reference:
|
||||||
|
result += '^';
|
||||||
|
break;
|
||||||
|
case utils::ReferenceModifier::UniqueReference:
|
||||||
|
result += '@';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result += type_manager_->GetAnyValue(type_)->ToString();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FunctionType::InContext(const std::unordered_map<std::string, utils::IdType>& context) {
|
||||||
|
for (size_t i = 0; i < argument_types_.size(); ++i) {
|
||||||
|
std::optional<utils::IdType> maybe_argument_type_replacement =
|
||||||
|
type_manager_->GetAnyValue(argument_types_[i])->InContext(context);
|
||||||
|
|
||||||
|
if (maybe_argument_type_replacement.has_value()) {
|
||||||
|
argument_types_[i] = maybe_argument_type_replacement.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FunctionType::Same(const FunctionType& type) const {
|
||||||
|
if (argument_types_.size() != type.argument_types_.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < argument_types_.size(); ++i) {
|
||||||
|
if (!type_manager_->GetAnyValue(argument_types_[i])->Same(*type_manager_->GetAnyValue(type.argument_types_[i]))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FunctionType::operator<(const FunctionType& type) const {
|
||||||
|
if (argument_types_.size() != type.argument_types_.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < argument_types_.size(); ++i) {
|
||||||
|
if (!(*type_manager_->GetAnyValue(argument_types_[i]) < *type_manager_->GetAnyValue(type.argument_types_[i]))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FunctionType::operator>(const FunctionType& type) const {
|
||||||
|
return type < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FunctionType::GetFieldType(const std::string&,
|
||||||
|
const std::unordered_set<utils::IdType>&) const {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FunctionType::ToString() {
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
result += "(";
|
||||||
|
|
||||||
|
bool is_first_argument = true;
|
||||||
|
for (auto& argument_type : argument_types_) {
|
||||||
|
if (is_first_argument) {
|
||||||
|
is_first_argument = false;
|
||||||
|
} else {
|
||||||
|
result += " -> ";
|
||||||
|
}
|
||||||
|
result += type_manager_->GetAnyValue(argument_type)->ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
result += " -> " + type_manager_->GetAnyValue(return_type_)->ToString() + ")";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
std::optional<utils::IdType> ArrayType::InContext(const std::unordered_map<std::string, utils::IdType>& context) {
|
||||||
|
std::optional<utils::IdType> maybe_elements_type_replacement =
|
||||||
|
type_manager_->GetAnyValue(elements_type_)->InContext(context);
|
||||||
|
|
||||||
|
if (maybe_elements_type_replacement.has_value()) {
|
||||||
|
elements_type_ = maybe_elements_type_replacement.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArrayType::Same(const ArrayType& type) const {
|
||||||
|
return size_ == type.size_ && type_manager_->GetAnyValue(elements_type_)->Same(*type_manager_->GetAnyValue(type.elements_type_));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArrayType::operator<(const ArrayType& type) const {
|
||||||
|
return size_ == type.size_ && *type_manager_->GetAnyValue(elements_type_) < *type_manager_->GetAnyValue(type.elements_type_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArrayType::operator>(const ArrayType& type) const {
|
||||||
|
return type < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> ArrayType::GetFieldType(const std::string&,
|
||||||
|
const std::unordered_set<utils::IdType>&) const {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ArrayType::ToString() {
|
||||||
|
return "Array (" + std::to_string(size_) + ") " + type_manager_->GetAnyValue(elements_type_)->ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
std::optional<utils::IdType> Type::InContext(const std::unordered_map<std::string, utils::IdType>& context) {
|
||||||
|
size_t this_index = type_.index();
|
||||||
|
|
||||||
|
switch (this_index) {
|
||||||
|
case 0:
|
||||||
|
return std::get<AbstractType>(type_).InContext(context);
|
||||||
|
case 1:
|
||||||
|
return std::get<DefinedType>(type_).InContext(context);
|
||||||
|
case 2:
|
||||||
|
return std::nullopt;
|
||||||
|
case 3:
|
||||||
|
return std::get<TupleType>(type_).InContext(context);
|
||||||
|
case 4:
|
||||||
|
return std::get<VariantType>(type_).InContext(context);
|
||||||
|
case 5:
|
||||||
|
return std::get<ReferenceToType>(type_).InContext(context);
|
||||||
|
case 6:
|
||||||
|
return std::get<FunctionType>(type_).InContext(context);
|
||||||
|
case 7:
|
||||||
|
return std::get<ArrayType>(type_).InContext(context);
|
||||||
|
case 8:
|
||||||
|
return std::get<OptionalType>(type_).InContext(context);
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::Same(const Type& type) const {
|
||||||
|
size_t this_index = type_.index();
|
||||||
|
size_t type_index = type.type_.index();
|
||||||
|
|
||||||
|
if (this_index == type_index) {
|
||||||
|
switch (this_index) {
|
||||||
|
case 0:
|
||||||
|
return std::get<AbstractType>(type_).Same(std::get<AbstractType>(type.type_));
|
||||||
|
case 1:
|
||||||
|
return std::get<DefinedType>(type_).Same(std::get<DefinedType>(type.type_));
|
||||||
|
case 2:
|
||||||
|
return std::get<InternalType>(type_) == std::get<InternalType>(type.type_);
|
||||||
|
case 3:
|
||||||
|
return std::get<TupleType>(type_).Same(std::get<TupleType>(type.type_));
|
||||||
|
case 4:
|
||||||
|
return std::get<VariantType>(type_).Same(std::get<VariantType>(type.type_));
|
||||||
|
case 5:
|
||||||
|
return std::get<ReferenceToType>(type_).Same(std::get<ReferenceToType>(type.type_));
|
||||||
|
case 6:
|
||||||
|
return std::get<FunctionType>(type_).Same(std::get<FunctionType>(type.type_));
|
||||||
|
case 7:
|
||||||
|
return std::get<ArrayType>(type_).Same(std::get<ArrayType>(type.type_));
|
||||||
|
case 8:
|
||||||
|
return std::get<OptionalType>(type_).Same(std::get<OptionalType>(type.type_));
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::operator<(const Type& type) const {
|
||||||
|
size_t this_index = type_.index();
|
||||||
|
size_t type_index = type.type_.index();
|
||||||
|
|
||||||
|
if (this_index == type_index) {
|
||||||
|
switch (this_index) {
|
||||||
|
case 0:
|
||||||
|
return std::get<AbstractType>(type_) < std::get<AbstractType>(type.type_);
|
||||||
|
case 1:
|
||||||
|
return std::get<DefinedType>(type_) < std::get<DefinedType>(type.type_);
|
||||||
|
case 2:
|
||||||
|
return std::get<InternalType>(type_) == std::get<InternalType>(type.type_);
|
||||||
|
case 3:
|
||||||
|
return std::get<TupleType>(type_) < std::get<TupleType>(type.type_);
|
||||||
|
case 4:
|
||||||
|
return std::get<VariantType>(type_) < std::get<VariantType>(type.type_);
|
||||||
|
case 5:
|
||||||
|
return std::get<ReferenceToType>(type_) < std::get<ReferenceToType>(type.type_);
|
||||||
|
case 6:
|
||||||
|
return std::get<FunctionType>(type_) < std::get<FunctionType>(type.type_);
|
||||||
|
case 7:
|
||||||
|
return std::get<ArrayType>(type_) < std::get<ArrayType>(type.type_);
|
||||||
|
case 8:
|
||||||
|
return std::get<OptionalType>(type_) < std::get<OptionalType>(type.type_);
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::operator>(const Type& type) const {
|
||||||
|
return type < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> Type::GetFieldType(const std::string& name,
|
||||||
|
const std::unordered_set<utils::IdType>& type_namespaces) const {
|
||||||
|
size_t index = type_.index();
|
||||||
|
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return std::get<AbstractType>(type_).GetFieldType(name, type_namespaces);
|
||||||
|
case 1:
|
||||||
|
return std::get<DefinedType>(type_).GetFieldType(name, type_namespaces);
|
||||||
|
case 2:
|
||||||
|
return std::nullopt;
|
||||||
|
case 3:
|
||||||
|
return std::get<TupleType>(type_).GetFieldType(name, type_namespaces);
|
||||||
|
case 4:
|
||||||
|
return std::get<VariantType>(type_).GetFieldType(name, type_namespaces);
|
||||||
|
case 5:
|
||||||
|
return std::get<ReferenceToType>(type_).GetFieldType(name, type_namespaces);
|
||||||
|
case 6:
|
||||||
|
return std::get<FunctionType>(type_).GetFieldType(name, type_namespaces);
|
||||||
|
case 7:
|
||||||
|
return std::get<ArrayType>(type_).GetFieldType(name, type_namespaces);
|
||||||
|
case 8:
|
||||||
|
return std::get<OptionalType>(type_).GetFieldType(name, type_namespaces);
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Type::GetTypeName() const {
|
||||||
|
size_t index = type_.index();
|
||||||
|
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return "AbstractType";
|
||||||
|
case 1:
|
||||||
|
return "DefinedType";
|
||||||
|
case 2:
|
||||||
|
return "Builtin";
|
||||||
|
case 3:
|
||||||
|
return "TupleType";
|
||||||
|
case 4:
|
||||||
|
return "VariantType";
|
||||||
|
case 5:
|
||||||
|
return "ReferenceToType";
|
||||||
|
case 6:
|
||||||
|
return "FunctionType";
|
||||||
|
case 7:
|
||||||
|
return "ArrayType";
|
||||||
|
case 8:
|
||||||
|
return "OptionalType";
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""; // ??
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Type::ToString() {
|
||||||
|
size_t index = type_.index();
|
||||||
|
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return std::get<AbstractType>(type_).ToString();
|
||||||
|
case 1:
|
||||||
|
return std::get<DefinedType>(type_).ToString();
|
||||||
|
case 2:
|
||||||
|
return ::info::type::ToString(std::get<InternalType>(type_));
|
||||||
|
case 3:
|
||||||
|
return std::get<TupleType>(type_).ToString();
|
||||||
|
case 4:
|
||||||
|
return std::get<VariantType>(type_).ToString();
|
||||||
|
case 5:
|
||||||
|
return std::get<ReferenceToType>(type_).ToString();
|
||||||
|
case 6:
|
||||||
|
return std::get<FunctionType>(type_).ToString();
|
||||||
|
case 7:
|
||||||
|
return std::get<ArrayType>(type_).ToString();
|
||||||
|
case 8:
|
||||||
|
return std::get<OptionalType>(type_).ToString();
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace info::type
|
||||||
|
|
||||||
92
src/utils.cpp
Normal file
92
src/utils.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
// for clangd
|
||||||
|
#include "../include/utils.hpp"
|
||||||
|
#include"../include/error_handling.hpp"
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
using std::size_t;
|
||||||
|
|
||||||
|
using IdType = size_t;
|
||||||
|
|
||||||
|
ValueType IsConstModifierToValueType(IsConstModifier modifier) {
|
||||||
|
switch (modifier) {
|
||||||
|
case IsConstModifier::Const:
|
||||||
|
return ValueType::Const;
|
||||||
|
case IsConstModifier::Var:
|
||||||
|
return ValueType::Var;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1); // unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueType ClassInternalsModifierToValueType(ClassInternalsModifier modifier) {
|
||||||
|
switch (modifier) {
|
||||||
|
case ClassInternalsModifier::Const:
|
||||||
|
return ValueType::Const;
|
||||||
|
case ClassInternalsModifier::Var:
|
||||||
|
return ValueType::Var;
|
||||||
|
case ClassInternalsModifier::Static:
|
||||||
|
throw std::bad_cast(); // ??
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1); // unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBuiltinFunction(const std::string& name) { // optimize ??
|
||||||
|
std::unordered_set<std::string> builtin_functions;
|
||||||
|
|
||||||
|
builtin_functions.insert("="); // TODO: for all types
|
||||||
|
// builtin_functions.insert("<-"); // TODO
|
||||||
|
builtin_functions.insert("==");
|
||||||
|
builtin_functions.insert("<");
|
||||||
|
builtin_functions.insert("+=");
|
||||||
|
builtin_functions.insert("-=");
|
||||||
|
builtin_functions.insert("*=");
|
||||||
|
builtin_functions.insert("div");
|
||||||
|
builtin_functions.insert("mod");
|
||||||
|
builtin_functions.insert("/=");
|
||||||
|
builtin_functions.insert("size");
|
||||||
|
builtin_functions.insert("random");
|
||||||
|
builtin_functions.insert("print");
|
||||||
|
builtin_functions.insert("scan");
|
||||||
|
builtin_functions.insert("zero");
|
||||||
|
builtin_functions.insert("one");
|
||||||
|
builtin_functions.insert("show");
|
||||||
|
builtin_functions.insert("read");
|
||||||
|
// builtin_functions.insert("debug_show"); // TODO
|
||||||
|
|
||||||
|
return builtin_functions.count(name) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackVisitDfs(size_t id,
|
||||||
|
std::vector<size_t>& verticles,
|
||||||
|
std::vector<size_t>& marks,
|
||||||
|
const std::vector<std::vector<size_t>>& edges,
|
||||||
|
size_t mark) {
|
||||||
|
if (marks[id] != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
marks[id] = mark;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < edges[id].size(); ++i) {
|
||||||
|
BackVisitDfs(edges[id][i], verticles, marks, edges, mark);
|
||||||
|
}
|
||||||
|
|
||||||
|
verticles.push_back(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> BackTopSort(const std::vector<std::vector<size_t>>& edges_) {
|
||||||
|
std::vector<size_t> sorted_verticles;
|
||||||
|
std::vector<size_t> marks(edges_.size(), 0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < edges_.size(); ++i) {
|
||||||
|
if (marks[i] == 0) {
|
||||||
|
BackVisitDfs(i, sorted_verticles, marks, edges_, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sorted_verticles;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
308
src/values.cpp
Normal file
308
src/values.cpp
Normal file
|
|
@ -0,0 +1,308 @@
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
// for clangd
|
||||||
|
#include "../include/values.hpp"
|
||||||
|
#include "../include/error_handling.hpp"
|
||||||
|
|
||||||
|
namespace info::value {
|
||||||
|
|
||||||
|
bool InternalValue::Same(const InternalValue& other_value) const {
|
||||||
|
size_t this_index = value.index();
|
||||||
|
size_t other_index = other_value.value.index();
|
||||||
|
|
||||||
|
if (this_index == other_index) {
|
||||||
|
switch (this_index) {
|
||||||
|
case 0:
|
||||||
|
return std::get<double>(value) == std::get<double>(other_value.value);
|
||||||
|
case 1:
|
||||||
|
return std::get<int64_t>(value) == std::get<int64_t>(other_value.value);
|
||||||
|
case 2:
|
||||||
|
return std::get<std::string>(value) == std::get<std::string>(other_value.value);
|
||||||
|
case 3:
|
||||||
|
return std::get<char>(value) == std::get<char>(other_value.value);
|
||||||
|
case 4:
|
||||||
|
return std::get<bool>(value) == std::get<bool>(other_value.value);
|
||||||
|
case 5: // Unit
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> InternalValue::GetFieldValue(const std::string&) const {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType InternalValue::DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type) {
|
||||||
|
return value_manager->ExplicitAddValue(InternalValue(value), new_value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
bool TupleValue::Same(const TupleValue& other_value) const {
|
||||||
|
// TODO: check, that type is same ?? (checked in typecheck ??)
|
||||||
|
if (fields.size() != other_value.fields.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < fields.size(); ++i) { // compare field names ?? (checked in typecheck ??)
|
||||||
|
if (!value_manager_->GetAnyValue(fields[i].second)->Same(*value_manager_->GetAnyValue(other_value.fields[i].second))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> TupleValue::GetFieldValue(const std::string& name) const {
|
||||||
|
for (size_t i = 0; i < fields.size(); ++i) { // TODO: optimize??
|
||||||
|
if (fields[i].first.has_value() && fields[i].first.value() == name) {
|
||||||
|
return fields[i].second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType TupleValue::DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type) {
|
||||||
|
std::vector<std::pair<std::optional<std::string>, utils::IdType>> fields_copy(fields.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fields.size(); ++i) {
|
||||||
|
fields_copy[i] = {fields[i].first, value_manager_->GetAnyValue(fields[i].second)->DeepCopy(value_manager, new_value_type)};
|
||||||
|
}
|
||||||
|
|
||||||
|
return value_manager->ExplicitAddValue(
|
||||||
|
TupleValue(std::move(fields_copy), value_manager),
|
||||||
|
new_value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
bool VariantValue::Same(const VariantValue& other_value) const {
|
||||||
|
// TODO: check, that type is same ?? (checked in typecheck ??)
|
||||||
|
if (current_constructor != other_value.current_constructor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.Same(other_value.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> VariantValue::GetFieldValue(const std::string& name) const {
|
||||||
|
return value.GetFieldValue(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType VariantValue::DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type) {
|
||||||
|
auto maybe_tuple_deep_copy = value_manager->GetValue<TupleValue>(value.DeepCopy(value_manager, new_value_type));
|
||||||
|
|
||||||
|
if (!maybe_tuple_deep_copy) {
|
||||||
|
error_handling::HandleInternalError("Deep copied TupleType in not TupleType",
|
||||||
|
"VariantValue.DeepCopy",
|
||||||
|
std::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value_manager->ExplicitAddValue(
|
||||||
|
VariantValue(TupleValue(*maybe_tuple_deep_copy.value()), current_constructor),
|
||||||
|
new_value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
bool ReferenceToValue::Same(const ReferenceToValue& other_value) const {
|
||||||
|
if (references.size() != other_value.references.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < references.size(); ++i) {
|
||||||
|
if (references[i] != other_value.references[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value_manager_->GetAnyValue(value)->Same(*value_manager_->GetAnyValue(other_value.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> ReferenceToValue::GetFieldValue(const std::string& name) const {
|
||||||
|
return value_manager_->GetAnyValue(value)->GetFieldValue(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType ReferenceToValue::DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type) {
|
||||||
|
return value_manager->ExplicitAddValue(
|
||||||
|
ReferenceToValue(references, value_manager_->GetAnyValue(value)->DeepCopy(value_manager, new_value_type), value_manager),
|
||||||
|
new_value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
bool FunctionValue::Same(const FunctionValue& other_value) const {
|
||||||
|
size_t this_index = function.index();
|
||||||
|
size_t other_index = other_value.function.index();
|
||||||
|
|
||||||
|
if (this_index == other_index) {
|
||||||
|
switch (this_index) {
|
||||||
|
case 0:
|
||||||
|
return std::get<interpreter::tokens::FunctionDeclaration*>(function) == std::get<interpreter::tokens::FunctionDeclaration*>(other_value.function);
|
||||||
|
case 1:
|
||||||
|
return std::get<interpreter::tokens::LambdaFunction*>(function) == std::get<interpreter::tokens::LambdaFunction*>(other_value.function);
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> FunctionValue::GetFieldValue(const std::string&) const {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType FunctionValue::DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type) {
|
||||||
|
return value_manager->ExplicitAddValue(
|
||||||
|
FunctionValue(function, value_manager),
|
||||||
|
new_value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
bool ArrayValue::Same(const ArrayValue& other_value) const {
|
||||||
|
if (is_constant_size != other_value.is_constant_size
|
||||||
|
|| elements.size() != other_value.elements.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < elements.size(); ++i) {
|
||||||
|
if (!value_manager_->GetAnyValue(elements[i])->Same(*value_manager_->GetAnyValue(other_value.elements[i]))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> ArrayValue::GetFieldValue(const std::string&) const {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType ArrayValue::DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type) {
|
||||||
|
std::vector<utils::IdType> elements_copy(elements.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < elements.size(); ++i) {
|
||||||
|
elements_copy[i] = value_manager_->GetAnyValue(elements[i])->DeepCopy(value_manager, new_value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value_manager->ExplicitAddValue(
|
||||||
|
ArrayValue(std::move(elements_copy), is_constant_size, value_manager),
|
||||||
|
new_value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
bool OptionalValue::Same(const OptionalValue& other_value) const {
|
||||||
|
if (value.has_value() != other_value.value.has_value()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (value.has_value()) { // => other_value.value.has_value()
|
||||||
|
return value_manager_->GetAnyValue(value.value())->Same(*value_manager_->GetAnyValue(other_value.value.value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> OptionalValue::GetFieldValue(const std::string&) const {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType OptionalValue::DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type) {
|
||||||
|
if (!value.has_value()) {
|
||||||
|
return value_manager->ExplicitAddValue(
|
||||||
|
OptionalValue(std::nullopt, value_manager),
|
||||||
|
utils::ValueType::Tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value_manager->ExplicitAddValue(
|
||||||
|
OptionalValue(value_manager_->GetAnyValue(value.value())->DeepCopy(value_manager, new_value_type), value_manager),
|
||||||
|
new_value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
bool Value::Same(const Value& other_value) const {
|
||||||
|
size_t this_index = value.index();
|
||||||
|
size_t other_index = other_value.value.index();
|
||||||
|
|
||||||
|
if (this_index == other_index) {
|
||||||
|
switch (this_index) {
|
||||||
|
case 0:
|
||||||
|
return std::get<InternalValue>(value).Same(std::get<InternalValue>(other_value.value));
|
||||||
|
case 1:
|
||||||
|
return std::get<TupleValue>(value).Same(std::get<TupleValue>(other_value.value));
|
||||||
|
case 2:
|
||||||
|
return std::get<VariantValue>(value).Same(std::get<VariantValue>(other_value.value));
|
||||||
|
case 3:
|
||||||
|
return std::get<ReferenceToValue>(value).Same(std::get<ReferenceToValue>(other_value.value));
|
||||||
|
case 4:
|
||||||
|
return std::get<FunctionValue>(value).Same(std::get<FunctionValue>(other_value.value));
|
||||||
|
case 5:
|
||||||
|
return std::get<ArrayValue>(value).Same(std::get<ArrayValue>(other_value.value));
|
||||||
|
case 6:
|
||||||
|
return std::get<OptionalValue>(value).Same(std::get<OptionalValue>(other_value.value));
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<utils::IdType> Value::GetFieldValue(const std::string& name) const {
|
||||||
|
size_t index = value.index();
|
||||||
|
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return std::get<InternalValue>(value).GetFieldValue(name);
|
||||||
|
case 1:
|
||||||
|
return std::get<TupleValue>(value).GetFieldValue(name);
|
||||||
|
case 2:
|
||||||
|
return std::get<VariantValue>(value).GetFieldValue(name);
|
||||||
|
case 3:
|
||||||
|
return std::get<ReferenceToValue>(value).GetFieldValue(name);
|
||||||
|
case 4:
|
||||||
|
return std::get<FunctionValue>(value).GetFieldValue(name);
|
||||||
|
case 5:
|
||||||
|
return std::get<ArrayValue>(value).GetFieldValue(name);
|
||||||
|
case 6:
|
||||||
|
return std::get<OptionalValue>(value).GetFieldValue(name);
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::IdType Value::DeepCopy(ValueManager* value_manager, utils::ValueType new_value_type) {
|
||||||
|
size_t index = value.index();
|
||||||
|
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return std::get<InternalValue>(value).DeepCopy(value_manager, new_value_type);
|
||||||
|
case 1:
|
||||||
|
return std::get<TupleValue>(value).DeepCopy(value_manager, new_value_type);
|
||||||
|
case 2:
|
||||||
|
return std::get<VariantValue>(value).DeepCopy(value_manager, new_value_type);
|
||||||
|
case 3:
|
||||||
|
return std::get<ReferenceToValue>(value).DeepCopy(value_manager, new_value_type);
|
||||||
|
case 4:
|
||||||
|
return std::get<FunctionValue>(value).DeepCopy(value_manager, new_value_type);
|
||||||
|
case 5:
|
||||||
|
return std::get<ArrayValue>(value).DeepCopy(value_manager, new_value_type);
|
||||||
|
case 6:
|
||||||
|
return std::get<OptionalValue>(value).DeepCopy(value_manager, new_value_type);
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1); // better error handling ??
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace info::value
|
||||||
663
src/visitor.cpp
Normal file
663
src/visitor.cpp
Normal file
|
|
@ -0,0 +1,663 @@
|
||||||
|
// for clangd
|
||||||
|
#include "../include/visitor.hpp"
|
||||||
|
|
||||||
|
namespace interpreter {
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
void Visitor::Visit(NamespaceStatement& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(std::get<std::unique_ptr<AliasDefinitionStatement>>(node).get());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(std::get<std::unique_ptr<FunctionDeclaration>>(node).get());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(std::get<std::unique_ptr<FunctionDefinitionStatement>>(node).get());
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Visit(std::get<std::unique_ptr<TypeDefinitionStatement>>(node).get());
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Visit(std::get<std::unique_ptr<PartitionStatement>>(node).get());
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
Visit(std::get<std::unique_ptr<Namespace>>(node).get());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(SourceStatement& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(std::get<std::unique_ptr<ImportStatement>>(node).get());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(std::get<std::unique_ptr<AbstractTypeDefinitionStatement>>(node).get());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(std::get<std::unique_ptr<TypeclassDefinitionStatement>>(node).get());
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Visit(*std::get<std::unique_ptr<NamespaceStatement>>(node));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
void Visitor::Visit(Pattern& node) { // <-> ScopedPattern
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(std::get<std::unique_ptr<NameIdentifier>>(node).get());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(*std::get<std::unique_ptr<Literal>>(node));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(std::get<std::unique_ptr<TypeConstructorPattern>>(node).get());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(FlowControl& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(std::get<std::unique_ptr<Match>>(node).get());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(std::get<std::unique_ptr<Condition>>(node).get());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(std::get<std::unique_ptr<DoWhileLoop>>(node).get());
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Visit(std::get<std::unique_ptr<WhileLoop>>(node).get());
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Visit(std::get<std::unique_ptr<ForLoop>>(node).get());
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
Visit(std::get<std::unique_ptr<LoopLoop>>(node).get());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
void Visitor::Visit(BlockStatement& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(*std::get<std::unique_ptr<Expression>>(node));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(std::get<std::unique_ptr<VariableDefinitionStatement>>(node).get());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(*std::get<std::unique_ptr<FlowControl>>(node));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Visit(*std::get<std::unique_ptr<PrefixedExpression>>(node));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void Visitor::Visit(SubExpressionToken& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(std::get<std::unique_ptr<NameExpression>>(node).get());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(std::get<std::unique_ptr<ScopedStatement>>(node).get());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(std::get<std::unique_ptr<AccessExpression>>(node).get());
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Visit(*std::get<std::unique_ptr<Literal>>(node));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Visit(std::get<std::unique_ptr<ReferenceExpression>>(node).get());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(SubExpression& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(std::get<std::unique_ptr<FunctionCallExpression>>(node).get());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(*std::get<std::unique_ptr<SubExpressionToken>>(node));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(PrefixedExpression& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(std::get<std::unique_ptr<ReturnExpression>>(node).get());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(*std::get<std::unique_ptr<LoopControlExpression>>(node));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(std::get<std::unique_ptr<Block>>(node).get());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(Expression& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(std::get<std::unique_ptr<LambdaFunction>>(node).get());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(std::get<std::unique_ptr<TypeConstructor>>(node).get());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(*std::get<std::unique_ptr<PrefixedExpression>>(node));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Visit(*std::get<std::unique_ptr<SubExpression>>(node));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(SuperExpression& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(*std::get<std::unique_ptr<FlowControl>>(node));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(std::get<std::unique_ptr<TupleExpression>>(node).get());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(std::get<std::unique_ptr<VariantExpression>>(node).get());
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Visit(std::get<std::unique_ptr<ArrayExpression>>(node).get());
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Visit(*std::get<std::unique_ptr<Expression>>(node));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
void Visitor::Visit(AnyName& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(std::get<std::unique_ptr<AnnotatedName>>(node).get());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(std::get<std::unique_ptr<TupleName>>(node).get());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(std::get<std::unique_ptr<VariantName>>(node).get());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
void Visitor::Visit(AnyType& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(std::get<std::unique_ptr<TypeExpression>>(node).get());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(std::get<std::unique_ptr<TupleType>>(node).get());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(std::get<std::unique_ptr<VariantType>>(node).get());
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Visit(std::get<std::unique_ptr<FunctionType>>(node).get());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
void Visitor::Visit(Literal& node) {
|
||||||
|
switch (node.index()) {
|
||||||
|
case 0:
|
||||||
|
Visit(std::get<std::unique_ptr<FloatNumberLiteral>>(node).get());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Visit(std::get<std::unique_ptr<NumberLiteral>>(node).get());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Visit(std::get<std::unique_ptr<StringLiteral>>(node).get());
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Visit(std::get<std::unique_ptr<CharLiteral>>(node).get());
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Visit(std::get<std::unique_ptr<UnitLiteral>>(node).get());
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
Visit(std::get<std::unique_ptr<BoolLiteral>>(node).get());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Sources -----------------
|
||||||
|
|
||||||
|
void Visitor::Visit(SourceFile* node) {
|
||||||
|
for (auto& statement : node->statements) {
|
||||||
|
Visit(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespaces, partitions -----------------
|
||||||
|
|
||||||
|
void Visitor::Visit(NamespaceSources* node) {
|
||||||
|
for (auto& statement : node->statements) {
|
||||||
|
Visit(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(Namespace* node) {
|
||||||
|
Visit(&node->type);
|
||||||
|
Visit(&node->scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Definitions -----------------
|
||||||
|
|
||||||
|
void Visitor::Visit(ImportStatement* node) {
|
||||||
|
for (auto& symbol : node->symbols) {
|
||||||
|
Visit(&symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(AliasDefinitionStatement* node) {
|
||||||
|
Visit(&node->type);
|
||||||
|
Visit(node->value.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(VariableDefinitionStatement* node) {
|
||||||
|
Visit(node->name);
|
||||||
|
Visit(node->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(FunctionDeclaration* node) {
|
||||||
|
Visit(&node->name);
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
Visit(node->type.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(FunctionDefinitionStatement* node) {
|
||||||
|
Visit(node->definition.get());
|
||||||
|
Visit(node->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(TypeDefinitionStatement* node) {
|
||||||
|
Visit(node->definition.get());
|
||||||
|
Visit(node->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(AbstractTypeDefinitionStatement* node) {
|
||||||
|
Visit(node->type.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(TypeclassDefinitionStatement* node) {
|
||||||
|
Visit(node->definition.get());
|
||||||
|
for (auto& function_requirement : node->requirements) {
|
||||||
|
Visit(function_requirement.second.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(PartitionStatement* node) {
|
||||||
|
Visit(&node->name);
|
||||||
|
Visit(node->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Definition parts
|
||||||
|
|
||||||
|
void Visitor::Visit(FunctionDefinition* node) {
|
||||||
|
Visit(&node->name);
|
||||||
|
for (auto& argument : node->arguments) {
|
||||||
|
Visit(&argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(TypeDefinition* node) {
|
||||||
|
Visit(node->type.get());
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(AnyAnnotatedType* node) {
|
||||||
|
Visit(&node->type);
|
||||||
|
for (auto& typeclass : node->typeclasses) {
|
||||||
|
Visit(typeclass.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flow control -----------------
|
||||||
|
|
||||||
|
void Visitor::Visit(TypeConstructorPatternParameter* node) {
|
||||||
|
if (node->name.has_value()) {
|
||||||
|
Visit(&node->name.value());
|
||||||
|
}
|
||||||
|
Visit(node->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(TypeConstructorPattern* node) {
|
||||||
|
Visit(node->constructor.get());
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
Visit(¶meter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(MatchCase* node) {
|
||||||
|
Visit(node->value);
|
||||||
|
if (node->condition.has_value()) {
|
||||||
|
Visit(node->condition.value());
|
||||||
|
}
|
||||||
|
if (node->statement.has_value()) {
|
||||||
|
Visit(node->statement.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(Match* node) {
|
||||||
|
Visit(node->value);
|
||||||
|
for (auto& match_case : node->matches) {
|
||||||
|
Visit(&match_case);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(Condition* node) {
|
||||||
|
for (size_t i = 0; i < node->conditions.size(); ++i) {
|
||||||
|
Visit(node->conditions[i]);
|
||||||
|
Visit(node->statements[i]);
|
||||||
|
}
|
||||||
|
if (node->statements.size() > node->conditions.size()) {
|
||||||
|
Visit(node->statements[node->conditions.size()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(DoWhileLoop* node) {
|
||||||
|
Visit(node->statement);
|
||||||
|
Visit(node->condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(WhileLoop* node) {
|
||||||
|
Visit(node->condition);
|
||||||
|
Visit(node->statement);
|
||||||
|
}
|
||||||
|
void Visitor::Visit(ForLoop* node) {
|
||||||
|
Visit(node->variable);
|
||||||
|
Visit(node->interval);
|
||||||
|
Visit(node->statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(LoopLoop* node) {
|
||||||
|
Visit(node->statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
|
void Visitor::Visit(Block* node) {
|
||||||
|
for (auto& statement : node->statements) {
|
||||||
|
Visit(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(ScopedStatement* node) {
|
||||||
|
Visit(node->statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(LoopControlExpression&) {} // enum
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
void Visitor::Visit(ReferenceExpression* node) {
|
||||||
|
Visit(node->expression.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(AccessExpression* node) {
|
||||||
|
Visit(node->name.get());
|
||||||
|
Visit(node->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other Expressions
|
||||||
|
|
||||||
|
void Visitor::Visit(FunctionCallExpression* node) {
|
||||||
|
if (node->prefix.has_value()) {
|
||||||
|
if (std::holds_alternative<std::unique_ptr<SubExpressionToken>>(node->prefix.value())) {
|
||||||
|
Visit(*std::get<std::unique_ptr<SubExpressionToken>>(node->prefix.value()));
|
||||||
|
} else if (std::holds_alternative<std::unique_ptr<TypeExpression>>(node->prefix.value())) {
|
||||||
|
Visit(std::get<std::unique_ptr<TypeExpression>>(node->prefix.value()).get());
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Visit(&node->name);
|
||||||
|
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& argument : node->arguments) {
|
||||||
|
Visit(argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(TupleExpression* node) {
|
||||||
|
for (auto& expression : node->expressions) {
|
||||||
|
Visit(expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(VariantExpression* node) {
|
||||||
|
for (auto& expression : node->expressions) {
|
||||||
|
Visit(expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(ReturnExpression* node) {
|
||||||
|
Visit(node->expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(TypeConstructorParameter* node) {
|
||||||
|
if (node->name.has_value()) {
|
||||||
|
Visit(&node->name.value());
|
||||||
|
}
|
||||||
|
Visit(node->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(TypeConstructor* node) {
|
||||||
|
Visit(node->constructor.get());
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
Visit(¶meter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(LambdaFunction* node) {
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
for (auto& argument : node->arguments) {
|
||||||
|
Visit(&argument);
|
||||||
|
}
|
||||||
|
Visit(node->expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(ArrayExpression* node) {
|
||||||
|
for (auto& element : node->elements) {
|
||||||
|
Visit(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name
|
||||||
|
|
||||||
|
void Visitor::Visit(PartitionName* node) {
|
||||||
|
for (auto& path_namespace : node->path) {
|
||||||
|
Visit(&path_namespace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(NameExpression* node) {
|
||||||
|
for (auto& name : node->names) {
|
||||||
|
Visit(&name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(TupleName* node) {
|
||||||
|
for (auto& name : node->names) {
|
||||||
|
Visit(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(VariantName* node) {
|
||||||
|
for (auto& name : node->names) {
|
||||||
|
Visit(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(AnnotatedName* node) {
|
||||||
|
Visit(&node->name);
|
||||||
|
if (node->type.has_value()) {
|
||||||
|
Visit(node->type.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type, typeclass, etc. -----------------
|
||||||
|
|
||||||
|
// Type
|
||||||
|
|
||||||
|
void Visitor::Visit(FunctionType* node) {
|
||||||
|
for (auto& type : node->types) {
|
||||||
|
Visit(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(TupleType* node) {
|
||||||
|
if (node->type.has_value()) {
|
||||||
|
Visit(&node->type.value());
|
||||||
|
}
|
||||||
|
for (auto& entity : node->entities) {
|
||||||
|
if (entity.first.has_value()) {
|
||||||
|
Visit(&entity.first.value());
|
||||||
|
}
|
||||||
|
Visit(entity.second.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(VariantType* node) {
|
||||||
|
if (node->type.has_value()) {
|
||||||
|
Visit(&node->type.value());
|
||||||
|
}
|
||||||
|
for (auto& constructor : node->constructors) {
|
||||||
|
if (std::holds_alternative<Constructor>(constructor)) {
|
||||||
|
Visit(&std::get<Constructor>(constructor));
|
||||||
|
} else if (std::holds_alternative<std::unique_ptr<TupleType>>(constructor)) {
|
||||||
|
Visit(std::get<std::unique_ptr<TupleType>>(constructor).get());
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(TypeExpression* node) {
|
||||||
|
for (auto& type : node->path) {
|
||||||
|
Visit(&type);
|
||||||
|
}
|
||||||
|
Visit(&node->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visitor::Visit(ExtendedScopedAnyType* node) {
|
||||||
|
Visit(node->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typeclass
|
||||||
|
|
||||||
|
void Visitor::Visit(ParametrizedTypeclass* node) {
|
||||||
|
Visit(&node->typeclass);
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typeclass & Type -----------------
|
||||||
|
|
||||||
|
void Visitor::Visit(ParametrizedType* node) {
|
||||||
|
Visit(&node->type);
|
||||||
|
for (auto& parameter : node->parameters) {
|
||||||
|
Visit(parameter.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identifiers, constants, etc. -----------------
|
||||||
|
|
||||||
|
void Visitor::Visit(std::string*) {} // std::string
|
||||||
|
|
||||||
|
void Visitor::Visit(FloatNumberLiteral*) {}
|
||||||
|
|
||||||
|
void Visitor::Visit(NumberLiteral*) {}
|
||||||
|
|
||||||
|
void Visitor::Visit(StringLiteral*) {}
|
||||||
|
|
||||||
|
void Visitor::Visit(CharLiteral*) {}
|
||||||
|
|
||||||
|
void Visitor::Visit(UnitLiteral*) {}
|
||||||
|
|
||||||
|
void Visitor::Visit(BoolLiteral*) {}
|
||||||
|
|
||||||
|
} // namespace interpreter
|
||||||
|
|
||||||
21
tests/arrays.lang
Normal file
21
tests/arrays.lang
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
decl test_arrays : -> Unit
|
||||||
|
def test_arrays = {
|
||||||
|
var arr1 = ,1 ,2 ,3
|
||||||
|
const arr2 = Int._array: 32
|
||||||
|
var arr3 = String._array: 11
|
||||||
|
const arr4 = 'a'--'z'
|
||||||
|
const n = 100
|
||||||
|
var arr5 <- Int._new_array: 10
|
||||||
|
|
||||||
|
var arr6 <- String._new_array: 10
|
||||||
|
var arr6_reference = ^arr6
|
||||||
|
|
||||||
|
const elem1 = arr1`0
|
||||||
|
var elem2 = arr1`2
|
||||||
|
const ref1 = ^arr1`1
|
||||||
|
var ref2 = ^arr1`3
|
||||||
|
; arr1`1 = 123
|
||||||
|
|
||||||
|
; ~ref1 = arr1`2 // set value
|
||||||
|
; ref1 = ref2 // set pointer / reference
|
||||||
|
}
|
||||||
59
tests/classes.lang
Normal file
59
tests/classes.lang
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
struct Fruit =
|
||||||
|
| Apple
|
||||||
|
| Orange
|
||||||
|
| Banana
|
||||||
|
|
||||||
|
struct Optional 'A =
|
||||||
|
| Some & 'A
|
||||||
|
| None
|
||||||
|
|
||||||
|
struct (Result : #Move) 'A 'B =
|
||||||
|
| & 'A
|
||||||
|
| Error & 'B
|
||||||
|
|
||||||
|
struct (Complex : #Value) =
|
||||||
|
& Float
|
||||||
|
& Float
|
||||||
|
|
||||||
|
struct Task =
|
||||||
|
& name : String
|
||||||
|
& duration : Float
|
||||||
|
|
||||||
|
class Employee =
|
||||||
|
& name : String
|
||||||
|
& role :
|
||||||
|
( | Director
|
||||||
|
& importance : Float
|
||||||
|
& share : Float
|
||||||
|
| Manager
|
||||||
|
& productivity :
|
||||||
|
( Productivity
|
||||||
|
| .Low
|
||||||
|
| .Average
|
||||||
|
| .High
|
||||||
|
& duration : Float
|
||||||
|
& sleep_on_work :
|
||||||
|
(SleepOnWork
|
||||||
|
| ..Yes
|
||||||
|
| ..No
|
||||||
|
))
|
||||||
|
& salary : Int
|
||||||
|
| Programmer
|
||||||
|
& skills : Float
|
||||||
|
& current_task : (Optional Task)
|
||||||
|
& salary : Int)
|
||||||
|
|
||||||
|
|
||||||
|
class Bag =
|
||||||
|
&
|
||||||
|
( | Apple
|
||||||
|
| Orange
|
||||||
|
| Banana)
|
||||||
|
& bag_type :
|
||||||
|
( | Small
|
||||||
|
| Medium
|
||||||
|
& weight_kg : Int
|
||||||
|
& weight_g : Int
|
||||||
|
& weight_g : Int
|
||||||
|
| Big)
|
||||||
|
& other_things : (Array Something)
|
||||||
44
tests/default_constructors.lang
Normal file
44
tests/default_constructors.lang
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
namespace Employee {
|
||||||
|
decl gen_employee : Unit -> Employee
|
||||||
|
def gen_employee = {
|
||||||
|
var x = $@Complex & 11.3 & 15.87 // construct on heap
|
||||||
|
return
|
||||||
|
$Employee // construct on stack
|
||||||
|
& name = "John"
|
||||||
|
& role =
|
||||||
|
($Manager
|
||||||
|
& "John"
|
||||||
|
& productivity =
|
||||||
|
($Productivity::High
|
||||||
|
& duration = 10.3
|
||||||
|
& sleep_on_work = ($Productivity::SleepOnWork::No))
|
||||||
|
& salary = 123)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
class Employee =
|
||||||
|
& name : String
|
||||||
|
& role :
|
||||||
|
( | Director
|
||||||
|
& importance : Float
|
||||||
|
& share : Float
|
||||||
|
| Manager
|
||||||
|
& productivity :
|
||||||
|
( Productivity
|
||||||
|
| .Low
|
||||||
|
| .Average
|
||||||
|
| .High
|
||||||
|
& duration : Float
|
||||||
|
& sleep_on_work :
|
||||||
|
(SleepOnWork
|
||||||
|
| ..Yes
|
||||||
|
| ..No
|
||||||
|
))
|
||||||
|
& salary : Int
|
||||||
|
| Programmer
|
||||||
|
& skills : Float
|
||||||
|
& current_task : Optional Task
|
||||||
|
& salary : Int)
|
||||||
|
*/
|
||||||
33
tests/flow_control.lang
Normal file
33
tests/flow_control.lang
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
decl flow_control_test : -> Unit
|
||||||
|
def flow_control_test = {
|
||||||
|
if (a < b ||. a == b) && (b < c) then IO.print: x
|
||||||
|
elif x < 0 then {
|
||||||
|
; x += 1
|
||||||
|
; IO.print: y
|
||||||
|
} else {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (a > 0) && not: (array.is_empty:) do {
|
||||||
|
; a -= 1
|
||||||
|
; array.pop:
|
||||||
|
}
|
||||||
|
|
||||||
|
while x < 10 do x +=. x + 3
|
||||||
|
|
||||||
|
for i in 0--y do {
|
||||||
|
; IO.print: i
|
||||||
|
}
|
||||||
|
|
||||||
|
for & i & j in (& 0--y & 0--k) do { // ??
|
||||||
|
; IO.print: 1
|
||||||
|
; IO.print: 2
|
||||||
|
; IO.print: 128
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
; y += 1
|
||||||
|
if y > 100 then
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
62
tests/functions.lang
Normal file
62
tests/functions.lang
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
decl sum ('A : #Add) : 'A -> 'A -> 'A
|
||||||
|
def sum : a b = a + b
|
||||||
|
|
||||||
|
decl fib : Int -> Int
|
||||||
|
def fib : n =
|
||||||
|
match n with
|
||||||
|
| 0 | 1 -> 1
|
||||||
|
| n ? n > 1 -> fib: (n - 1) + fib: n
|
||||||
|
| _ -> error: "n must be positive"
|
||||||
|
|
||||||
|
decl fact : Int -> Int
|
||||||
|
def fact : n =
|
||||||
|
match n with
|
||||||
|
| 0 -> 1
|
||||||
|
| n ? n > 0 -> n * fact: (n - 1)
|
||||||
|
| _ -> error: "n must be positive"
|
||||||
|
|
||||||
|
decl find_prefix_hashes ('H : (#AccHash Char)) : String -> (Array 'H)
|
||||||
|
def find_prefix_hashes : str = {
|
||||||
|
var hashes = (Array 'H).new: (str.size: + 1)
|
||||||
|
|
||||||
|
; hashes`0 = 'H.of: str`0
|
||||||
|
for i in 1--hashes.size: do {
|
||||||
|
; hashes`i = hashes`(i - 1)
|
||||||
|
; hashes`i.append: str`i
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashes
|
||||||
|
}
|
||||||
|
|
||||||
|
alias Hash = (AccHash Char)
|
||||||
|
|
||||||
|
decl find_substring : String -> String -> (Array Index)
|
||||||
|
def find_substring : str substr = {
|
||||||
|
var result = (Array Index).empty:
|
||||||
|
|
||||||
|
const str_hashes = find_prefix_hashes Hash: str
|
||||||
|
const substr_hash = Hash.of: substr
|
||||||
|
|
||||||
|
for i in 0--(str_hashes.size: - substr.size:) do {
|
||||||
|
const part_hash = Hash.diff: str_hashes`(i + substr.size:) str_hashes`i
|
||||||
|
|
||||||
|
if part_hash == substr_hash then {
|
||||||
|
; result.push: i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
decl is_empty : -> Bool
|
||||||
|
def is_empty = 0
|
||||||
|
|
||||||
|
decl do_something : -> Unit
|
||||||
|
def do_something =
|
||||||
|
IO.print: "Hello World!"
|
||||||
|
|
||||||
|
decl mul : Int -> Int -> Int
|
||||||
|
def mul : x y = x * y
|
||||||
|
|
||||||
|
decl mul_10 : Int -> Int
|
||||||
|
def mul_10 = mul: 10
|
||||||
16
tests/import.lang
Normal file
16
tests/import.lang
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import "module"
|
||||||
|
import "module" : func
|
||||||
|
import "module" :
|
||||||
|
Type1
|
||||||
|
func1
|
||||||
|
func2
|
||||||
|
func3
|
||||||
|
func4
|
||||||
|
|
||||||
|
use ModuleNamespace = import "module"
|
||||||
|
|
||||||
|
use PartOfModuleNamespace =
|
||||||
|
import "module" :
|
||||||
|
func1
|
||||||
|
func2
|
||||||
|
func3
|
||||||
12
tests/lambdas.lang
Normal file
12
tests/lambdas.lang
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
decl test_lambdas : -> Unit
|
||||||
|
def test_lambdas = {
|
||||||
|
const lambda1 = \x -> x * x
|
||||||
|
const lambda2 = \x -> x.hash:
|
||||||
|
const lambda3 = \x y -> x + y
|
||||||
|
|
||||||
|
const lambda4 = \x -> {
|
||||||
|
; IO.print: x
|
||||||
|
const y = x + x
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
}
|
||||||
18
tests/match.lang
Normal file
18
tests/match.lang
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
decl fruit_cost : Fruit -> Int
|
||||||
|
def fruit_cost : fruit = {
|
||||||
|
var fruit_copy = fruit
|
||||||
|
return (match <- fruit_copy with // consuming match
|
||||||
|
| $Banana -> 11
|
||||||
|
| $Apple | $Orange -> 7)
|
||||||
|
}
|
||||||
|
|
||||||
|
decl amount_to_string : Int -> Bool -> String
|
||||||
|
def amount_to_string : x is_zero_separated = {
|
||||||
|
const ans = match x with
|
||||||
|
| 0 ? is_zero_separated -> "Zero"
|
||||||
|
| 0 | 1 | 2 | 3 | 4 -> "Few"
|
||||||
|
| x ? (5--9).contains: x -> "Several"
|
||||||
|
| x ? (10--19).contains: x -> "Pack"
|
||||||
|
| _ -> "Lots"
|
||||||
|
return ans
|
||||||
|
}
|
||||||
8
tests/memory.lang
Normal file
8
tests/memory.lang
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
struct StructWithRef =
|
||||||
|
& @Int_0
|
||||||
|
|
||||||
|
decl test_memory : -> Unit
|
||||||
|
def test_memory = {
|
||||||
|
const unique_ref1 <- Int._new: 5
|
||||||
|
var unique_ref2 <- Array.of: 1 2 3
|
||||||
|
}
|
||||||
19
tests/namespaces.lang
Normal file
19
tests/namespaces.lang
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
namespace Namespace {
|
||||||
|
decl something : -> Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Array {
|
||||||
|
decl something : -> Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Array {
|
||||||
|
decl something : -> Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace var Array {
|
||||||
|
decl something : -> Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace const Array {
|
||||||
|
decl something : -> Unit
|
||||||
|
}
|
||||||
10
tests/partitions.lang
Normal file
10
tests/partitions.lang
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
test All::Dev::Syntax::testing {
|
||||||
|
const a = 31
|
||||||
|
; do_something: a
|
||||||
|
}
|
||||||
|
|
||||||
|
exec App::exe {
|
||||||
|
const b = true
|
||||||
|
const c = false
|
||||||
|
; do_something_different: b b c
|
||||||
|
}
|
||||||
0
tests/stdlib.lang
Normal file
0
tests/stdlib.lang
Normal file
229
tests/test_code.lang
Normal file
229
tests/test_code.lang
Normal file
|
|
@ -0,0 +1,229 @@
|
||||||
|
basic (Float : #Ord #Div #Str)
|
||||||
|
basic (Int : #Ord #IDiv #Str)
|
||||||
|
basic (String : #Ord #Str #CharContainer #Copy)
|
||||||
|
basic (Char : #Ord #Str #Copy)
|
||||||
|
basic (Bool : #Ord #Str #Copy)
|
||||||
|
basic (Unit : #Str #Copy)
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
decl not : Bool -> Bool
|
||||||
|
def not : x =
|
||||||
|
(match x with
|
||||||
|
| true -> false
|
||||||
|
| false -> true)
|
||||||
|
|
||||||
|
decl ( && ) : Bool -> Bool -> Bool
|
||||||
|
def ( && ) : x y =
|
||||||
|
match x with
|
||||||
|
| true -> (
|
||||||
|
match y with
|
||||||
|
| true -> true
|
||||||
|
| false -> false
|
||||||
|
)
|
||||||
|
| false -> false
|
||||||
|
|
||||||
|
decl ( || ) : Bool -> Bool -> Bool
|
||||||
|
def ( || ) : x y =
|
||||||
|
match x with
|
||||||
|
| true -> true
|
||||||
|
| false -> (
|
||||||
|
match y with
|
||||||
|
| true -> true
|
||||||
|
| false -> false
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
typeclass CharContainer =
|
||||||
|
& var size : -> Int
|
||||||
|
& var at : Int -> Char
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
typeclass Move =
|
||||||
|
& var ( <- ) : Move -> Unit // TODO
|
||||||
|
|
||||||
|
typeclass Copy =
|
||||||
|
& var ( = ) : Copy -> Unit
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
typeclass (Sum : #Copy) =
|
||||||
|
& var ( += ) : Sum -> Unit
|
||||||
|
& var ( -= ) : Sum -> Unit
|
||||||
|
& var ( + ) : Sum -> Sum
|
||||||
|
& var ( - ) : Sum -> Sum
|
||||||
|
& zero : -> Sum
|
||||||
|
|
||||||
|
namespace var Sum {
|
||||||
|
def ( + ) : x = {
|
||||||
|
var ans = self
|
||||||
|
; ans += x
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|
||||||
|
def ( - ) : x = {
|
||||||
|
var ans = self
|
||||||
|
; ans -= x
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typeclass (Mult : #Sum) =
|
||||||
|
& var ( *= ) : Mult -> Unit
|
||||||
|
& var ( * ) : Mult -> Mult
|
||||||
|
|
||||||
|
namespace var Mult {
|
||||||
|
def ( * ) : x = {
|
||||||
|
var ans = self
|
||||||
|
; ans *= x
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typeclass (IDiv : #Mult) =
|
||||||
|
& var div : IDiv -> IDiv
|
||||||
|
& var mod : IDiv -> IDiv
|
||||||
|
|
||||||
|
namespace var IDiv {
|
||||||
|
def mod : x = self -. x * self.div: x
|
||||||
|
}
|
||||||
|
|
||||||
|
typeclass (Div : #Mult) =
|
||||||
|
& var ( /= ) : Div -> Unit
|
||||||
|
& var ( / ) : Div -> Div
|
||||||
|
|
||||||
|
namespace var Div {
|
||||||
|
def ( / ) : x = {
|
||||||
|
var ans = self
|
||||||
|
; ans /= x
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
typeclass Eq =
|
||||||
|
& var ( == ) : Eq -> Bool
|
||||||
|
& var ( != ) : Eq -> Bool
|
||||||
|
|
||||||
|
namespace var Eq {
|
||||||
|
def ( != ) : x = not: (self == x)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
struct Order =
|
||||||
|
| EQ
|
||||||
|
| LT
|
||||||
|
| GT
|
||||||
|
|
||||||
|
typeclass (Ord : #Eq) =
|
||||||
|
& var compare : Ord -> Order
|
||||||
|
& var ( < ) : Ord -> Bool
|
||||||
|
& var ( >= ) : Ord -> Bool
|
||||||
|
& var ( > ) : Ord -> Bool
|
||||||
|
& var ( <= ) : Ord -> Bool
|
||||||
|
|
||||||
|
decl min ('A : #Ord) : 'A -> 'A -> 'A
|
||||||
|
def min : x y = if x < y then x else y
|
||||||
|
|
||||||
|
decl max ('A : #Ord) : 'A -> 'A -> 'A
|
||||||
|
def max : x y = if x < y then y else x
|
||||||
|
|
||||||
|
namespace var Ord {
|
||||||
|
def compare : x =
|
||||||
|
if self == x then $EQ
|
||||||
|
elif self < x then $LT
|
||||||
|
else $GT
|
||||||
|
|
||||||
|
def ( >= ) : x = not: (self < x)
|
||||||
|
def ( > ) : x = x < self
|
||||||
|
def ( <= ) : x = not: (x < self)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
typeclass Show =
|
||||||
|
& var show : -> String
|
||||||
|
|
||||||
|
typeclass Read =
|
||||||
|
& var read : String -> Read
|
||||||
|
|
||||||
|
typeclass (Str : #Show #Read)
|
||||||
|
|
||||||
|
// typeclass DebugShow = // TODO
|
||||||
|
// & debug_show : -> String
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
typeclass Default =
|
||||||
|
& default : -> Default
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
typeclass Bounded =
|
||||||
|
& min_bound : -> Bounded
|
||||||
|
& max_bound : -> Bounded
|
||||||
|
& var is_max_bound : -> Bool
|
||||||
|
& var is_min_bound : -> Bool
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
typeclass Enum =
|
||||||
|
& var succ : -> (Optional Enum)
|
||||||
|
& var pred : -> (Optional Enum)
|
||||||
|
& to_enum : Int -> Enum
|
||||||
|
& var from_enum : -> Int
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
decl print : String -> Unit
|
||||||
|
decl scan : -> String
|
||||||
|
decl random : -> Int // TODO
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
// // bad
|
||||||
|
// typeclass Functor 'A =
|
||||||
|
// & fmap 'B ('F : (#Functor 'B)) : ('A -> 'B) -> Functor -> 'F
|
||||||
|
|
||||||
|
// typeclass (Iterator : #Eq) =
|
||||||
|
// & next : -> Unit
|
||||||
|
// & prev : -> Unit
|
||||||
|
//
|
||||||
|
// typeclass Iterable ('Iter : #Iterable) =
|
||||||
|
// & begin : -> 'Iter
|
||||||
|
// & end : -> 'Iter
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
decl ret_one : -> Int
|
||||||
|
def ret_one = 1
|
||||||
|
|
||||||
|
decl ( -- ) : Int -> Int -> Int_0
|
||||||
|
def ( -- ) : begin end = {
|
||||||
|
var current = begin
|
||||||
|
return (while current < end do {
|
||||||
|
; current += 1
|
||||||
|
bring current - 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
decl func : String -> Int -> Int
|
||||||
|
def func : s i = {
|
||||||
|
; print: s
|
||||||
|
var x = s
|
||||||
|
; print: (i.show:)
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
|
||||||
|
exec main {
|
||||||
|
for i in 0--19 do func: "a" (i * 2 +. 3)
|
||||||
|
; print: ({
|
||||||
|
if true then bring scan: else { ; print: "aaa" }
|
||||||
|
bring "nothing"
|
||||||
|
; print: "aaa"
|
||||||
|
})
|
||||||
|
}
|
||||||
8
tests/tuples.lang
Normal file
8
tests/tuples.lang
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
decl test_tuples : -> Unit
|
||||||
|
def test_tuples = {
|
||||||
|
var tuple1 = & "a" & 2 & "hello"
|
||||||
|
const & t1 & t2 & t3 = f: x
|
||||||
|
|
||||||
|
; tuple1`0 = "b"
|
||||||
|
|
||||||
|
}
|
||||||
5
tests/type_casting.lang
Normal file
5
tests/type_casting.lang
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
decl test_type_casting : -> Unit
|
||||||
|
def test_type_casting = {
|
||||||
|
var x = y.as Int:
|
||||||
|
var k = (f: y x).as Float:
|
||||||
|
}
|
||||||
29
tests/typeclasses.lang
Normal file
29
tests/typeclasses.lang
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
typeclass Default =
|
||||||
|
& default : -> Copy
|
||||||
|
|
||||||
|
typeclass (Ord : #Eq) =
|
||||||
|
& var is_less_then : Ord -> Bool
|
||||||
|
|
||||||
|
typeclass (D : #A #B #C) 'A 'B =
|
||||||
|
& var do_something : -> (& 'A & 'B)
|
||||||
|
|
||||||
|
typeclass E 'A =
|
||||||
|
& var do_something : -> 'A
|
||||||
|
|
||||||
|
decl ( == ) ('A : #Ord) : 'A -> 'A -> Bool
|
||||||
|
def ( == ) : a b = a.is_equal_to: b
|
||||||
|
|
||||||
|
decl ( != ) ('A : #Ord) : 'A -> 'A -> Bool
|
||||||
|
def ( != ) : a b = not: (a == b)
|
||||||
|
|
||||||
|
decl ( < ) ('A : #Ord) : 'A -> 'A -> Bool
|
||||||
|
def ( < ) : a b = a.is_less_then: b
|
||||||
|
|
||||||
|
decl ( > ) ('A : #Ord) : 'A -> 'A -> Bool
|
||||||
|
def ( > ) : a b = not: (a <= b)
|
||||||
|
|
||||||
|
decl ( <= ) ('A : #Ord) : 'A -> 'A -> Bool
|
||||||
|
def ( <= ) : a b = a < b ||. a == b
|
||||||
|
|
||||||
|
decl ( >= ) ('A : #Ord) : 'A -> 'A -> Bool
|
||||||
|
def ( >= ) : a b = not: (a < b)
|
||||||
8
tests/types.lang
Normal file
8
tests/types.lang
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
alias T1 = Int
|
||||||
|
|
||||||
|
abstract (T2 : #A #B #C)
|
||||||
|
|
||||||
|
// Used to pre-compile module for some types
|
||||||
|
let T2 = Int
|
||||||
|
let T2 = Float
|
||||||
|
let T2 = Complex
|
||||||
15
tests/variants.lang
Normal file
15
tests/variants.lang
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
decl test_variants : -> Unit
|
||||||
|
def test_variants = {
|
||||||
|
var variant1 = | 'a' | 2 | "hello"
|
||||||
|
var | val | err = f: x
|
||||||
|
|
||||||
|
; val -?> "something" // open variant as value in expr
|
||||||
|
|
||||||
|
; val -!> "nothing" // open variant as None in expr
|
||||||
|
|
||||||
|
match variant1 with
|
||||||
|
| 'a' -> "something"
|
||||||
|
| 2 -> "nothing"
|
||||||
|
| "hello" -> "nothing"
|
||||||
|
| 11 -> "nothing"
|
||||||
|
}
|
||||||
1
tree-sitter
Submodule
1
tree-sitter
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 1b1c3974f789a9bfaa31f493e6eaa212f13bdfb9
|
||||||
Loading…
Add table
Add a link
Reference in a new issue