mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-25 00:08:45 +00:00
combine functions for statements part done
This commit is contained in:
parent
437c9692ec
commit
263b58a17c
7 changed files with 515 additions and 120 deletions
179
src/name_tree.cpp
Normal file
179
src/name_tree.cpp
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
#include "name_tree.hpp"
|
||||
|
||||
namespace names {
|
||||
|
||||
// --- public
|
||||
|
||||
bool NameTree::insert(const std::string &path, nodes::Statement &&statement) {
|
||||
auto name_ids = slice_path_to_name_ids(path);
|
||||
|
||||
size_t node_id = add_node(get_root(), name_ids);
|
||||
|
||||
if (nodes_[node_id].get_statement().has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nodes_[node_id].set_statement(std::move(statement));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<nodes::Statement *> NameTree::find(const std::string &path) {
|
||||
auto name_ids = slice_path_to_existing_name_ids(path);
|
||||
|
||||
if (!name_ids.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto node_id = find_node(get_root(), name_ids.value());
|
||||
|
||||
if (node_id.has_value()) {
|
||||
return nodes_[node_id.value()].get_statement();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<const nodes::Statement *>
|
||||
NameTree::find(const std::string &path) const {
|
||||
auto name_ids = slice_path_to_existing_name_ids(path);
|
||||
|
||||
if (!name_ids.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto node_id = find_node(get_root(), name_ids.value());
|
||||
|
||||
if (node_id.has_value()) {
|
||||
return nodes_[node_id.value()].get_statement();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// --- private
|
||||
|
||||
size_t NameTree::add_node(size_t current_node,
|
||||
const std::vector<size_t> &name_ids,
|
||||
size_t current_name) {
|
||||
if (current_name >= name_ids.size()) {
|
||||
return current_node;
|
||||
}
|
||||
|
||||
auto next_node = nodes_[current_node].find(name_ids[current_name]);
|
||||
|
||||
if (!next_node.has_value()) {
|
||||
next_node = nodes_.size();
|
||||
nodes_[current_node].insert(name_ids[current_name], next_node.value());
|
||||
nodes_.emplace_back();
|
||||
}
|
||||
|
||||
return add_node(next_node.value(), name_ids, current_name + 1);
|
||||
}
|
||||
|
||||
std::optional<size_t> NameTree::find_node(size_t current_node,
|
||||
const std::vector<size_t> &name_ids,
|
||||
size_t current_name) const {
|
||||
if (current_name >= name_ids.size()) {
|
||||
return current_node;
|
||||
}
|
||||
|
||||
auto next_node = nodes_[current_node].find(name_ids[current_name]);
|
||||
|
||||
if (!next_node.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return find_node(next_node.value(), name_ids, current_name + 1);
|
||||
}
|
||||
|
||||
std::vector<size_t> NameTree::slice_path_to_name_ids(const std::string &path) {
|
||||
// check that path is / is not points only operator
|
||||
bool points_only = true;
|
||||
for (size_t i = 0; i < path.size(); ++i) {
|
||||
if (path[i] != '.') {
|
||||
points_only = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (points_only) {
|
||||
return {add_name_id(path)};
|
||||
}
|
||||
|
||||
std::vector<size_t> name_ids;
|
||||
|
||||
size_t last_name_start = 0;
|
||||
for (size_t i = 0; i < path.size() + 1; ++i) {
|
||||
if (path[i] == '.' || i == path.size()) { // name separator
|
||||
name_ids.push_back(
|
||||
add_name_id(path.substr(last_name_start, i - last_name_start)));
|
||||
last_name_start = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return name_ids;
|
||||
}
|
||||
|
||||
std::optional<std::vector<size_t>>
|
||||
NameTree::slice_path_to_existing_name_ids(const std::string &path) const {
|
||||
// check that path is / is not points only operator
|
||||
bool points_only = true;
|
||||
for (size_t i = 0; i < path.size(); ++i) {
|
||||
if (path[i] != '.') {
|
||||
points_only = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (points_only) {
|
||||
auto maybe_id = find_name_id(path);
|
||||
|
||||
if (maybe_id.has_value()) {
|
||||
return std::vector<size_t>{maybe_id.value()};
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<size_t> name_ids;
|
||||
|
||||
size_t last_name_start = 0;
|
||||
for (size_t i = 0; i < path.size() + 1; ++i) {
|
||||
if (path[i] == '.' || i == path.size()) { // name separator
|
||||
auto maybe_id =
|
||||
find_name_id(path.substr(last_name_start, i - last_name_start));
|
||||
|
||||
if (!maybe_id.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
name_ids.push_back(maybe_id.value());
|
||||
last_name_start = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return name_ids;
|
||||
}
|
||||
|
||||
size_t NameTree::add_name_id(const std::string &name) {
|
||||
auto name_iter = name_to_id_.find(name);
|
||||
|
||||
if (name_iter == name_to_id_.end()) {
|
||||
size_t name_id = name_to_id_.size();
|
||||
return name_to_id_[name] = name_id;
|
||||
}
|
||||
|
||||
return name_iter->second;
|
||||
}
|
||||
|
||||
std::optional<size_t> NameTree::find_name_id(const std::string &name) const {
|
||||
auto name_iter = name_to_id_.find(name);
|
||||
|
||||
if (name_iter == name_to_id_.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return name_iter->second;
|
||||
}
|
||||
|
||||
} // namespace names
|
||||
|
|
@ -1,42 +1,55 @@
|
|||
#include "statement_nodes.hpp"
|
||||
|
||||
#include "error_handling.hpp"
|
||||
#include "utils.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace nodes {
|
||||
|
||||
// TODO: return error type instead of bool ??
|
||||
bool FunctionDefinition::combine(
|
||||
FunctionDefinition &&other_function_definition) {
|
||||
// should be same in all definitions of one function
|
||||
// TODO: function overloading, etc. ??
|
||||
bool FunctionDefinition::is_same_to(
|
||||
const FunctionDefinition &other_function_definition) const {
|
||||
if (*name_.get() != *other_function_definition.name_.get()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: function overloading, etc. ??
|
||||
CombineResult
|
||||
FunctionDefinition::combine(FunctionDefinition &&other_function_definition) {
|
||||
// should be same in all definitions of one function
|
||||
if (*name_.get() != *other_function_definition.name_.get()) {
|
||||
return CombineResult::DIFFERENT_NAME_ERROR;
|
||||
}
|
||||
if (modifier_ != other_function_definition.modifier_) {
|
||||
return false;
|
||||
return CombineResult::DIFFERNENT_MODIFIER_ERROR;
|
||||
}
|
||||
if (are_annotations_same_to_names_ !=
|
||||
other_function_definition.are_annotations_same_to_names_) {
|
||||
return false;
|
||||
return CombineResult::ARGUMENTS_ERROR;
|
||||
}
|
||||
|
||||
// only one definition should have constraints
|
||||
if (!constraints_.empty() &&
|
||||
!other_function_definition.constraints_.empty()) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_CONSTRAINTS_ERROR;
|
||||
}
|
||||
|
||||
// only one definition should have expression
|
||||
if (expression_.has_value() &&
|
||||
other_function_definition.expression_.has_value()) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_DEFINITION_BODY_ERROR;
|
||||
}
|
||||
|
||||
// only one definition should have documentation
|
||||
if (docs_.get_description().has_value() &&
|
||||
other_function_definition.docs_.get_description().has_value()) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_DOCS_ERROR;
|
||||
}
|
||||
if (docs_.get_annotations_info_size() > 0 &&
|
||||
other_function_definition.docs_.get_annotations_info_size() > 0) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_DOCS_ERROR;
|
||||
}
|
||||
|
||||
// TODO: think about required checks
|
||||
|
|
@ -60,7 +73,7 @@ bool FunctionDefinition::combine(
|
|||
*other_function_definition.arguments_[i]
|
||||
.get_annotation()
|
||||
.value())) {
|
||||
return false;
|
||||
return CombineResult::ARGUMENTS_ERROR;
|
||||
}
|
||||
|
||||
// check that all argument names are the same
|
||||
|
|
@ -73,14 +86,14 @@ bool FunctionDefinition::combine(
|
|||
.get_name()
|
||||
.value()
|
||||
->get())) {
|
||||
return false;
|
||||
return CombineResult::ARGUMENTS_ERROR;
|
||||
}
|
||||
|
||||
// check that types are are in zero or one set of arguments (TODO: can be
|
||||
// same and in two sets ??)
|
||||
if (arguments_[i].get_type().has_value() &&
|
||||
other_function_definition.arguments_[i].get_type().has_value()) {
|
||||
return false;
|
||||
return CombineResult::ARGUMENTS_ERROR;
|
||||
}
|
||||
|
||||
// argument modifiers should be same
|
||||
|
|
@ -88,21 +101,18 @@ bool FunctionDefinition::combine(
|
|||
other_function_definition.arguments_[i].get_before_modifier() ||
|
||||
arguments_[i].get_after_modifier() !=
|
||||
other_function_definition.arguments_[i].get_after_modifier()) {
|
||||
return false;
|
||||
return CombineResult::ARGUMENTS_ERROR;
|
||||
}
|
||||
|
||||
// TODO: other checks (annotations, ...)
|
||||
|
||||
} else if (i < arguments_.size()) {
|
||||
// last arguments shouldn't be annotated (because they are not annotated
|
||||
// in other function definition statement)
|
||||
if (arguments_[i].get_annotation().has_value()) {
|
||||
return false;
|
||||
return CombineResult::ARGUMENTS_ERROR;
|
||||
}
|
||||
|
||||
// last arguments can only be unnamed arguments (returned values)
|
||||
if (arguments_[i].get_name().has_value()) {
|
||||
return false;
|
||||
return CombineResult::ARGUMENTS_ERROR;
|
||||
}
|
||||
} else { // i < other_function_definition.size()
|
||||
// last arguments shouldn't be annotated (because they are not annotated
|
||||
|
|
@ -110,12 +120,12 @@ bool FunctionDefinition::combine(
|
|||
if (other_function_definition.arguments_[i]
|
||||
.get_annotation()
|
||||
.has_value()) {
|
||||
return false;
|
||||
return CombineResult::ARGUMENTS_ERROR;
|
||||
}
|
||||
|
||||
// last arguments can only be unnamed arguments (returned values)
|
||||
if (other_function_definition.arguments_[i].get_name().has_value()) {
|
||||
return false;
|
||||
return CombineResult::ARGUMENTS_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -126,7 +136,7 @@ bool FunctionDefinition::combine(
|
|||
other_function_definition.docs_.get_annotations_info_size() > 0) {
|
||||
if (docs_.get_annotations_info_size() > 0 ||
|
||||
docs_.get_description().has_value()) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_DOCS_ERROR;
|
||||
}
|
||||
|
||||
docs_ = std::move(other_function_definition.docs_);
|
||||
|
|
@ -140,28 +150,50 @@ bool FunctionDefinition::combine(
|
|||
expression_ = other_function_definition.expression_;
|
||||
}
|
||||
|
||||
// TODO: arguments: check and merge
|
||||
for (size_t i = 0; i < other_function_definition.arguments_.size(); ++i) {
|
||||
if (i < arguments_.size()) {
|
||||
if (other_function_definition.arguments_[i].get_type().has_value()) {
|
||||
if (arguments_[i].update_type_from(
|
||||
other_function_definition.arguments_[i])) {
|
||||
error_handling::handle_internal_error(
|
||||
"Function arguments are not properly checked before merging "
|
||||
"during combination",
|
||||
this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
arguments_.push_back(std::move(other_function_definition.arguments_[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return CombineResult::OK;
|
||||
}
|
||||
|
||||
bool TypeDefinition::combine(TypeDefinition &&other_type_definition) {
|
||||
// should be same in all definitions of one type
|
||||
bool TypeDefinition::is_same_to(
|
||||
const TypeDefinition &other_type_definition) const {
|
||||
if (*name_.get() != *other_type_definition.name_.get()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CombineResult TypeDefinition::combine(TypeDefinition &&other_type_definition) {
|
||||
// should be same in all definitions of one type
|
||||
if (*name_.get() != *other_type_definition.name_.get()) {
|
||||
return CombineResult::DIFFERENT_NAME_ERROR;
|
||||
}
|
||||
if (is_on_heap_ != other_type_definition.is_on_heap_) {
|
||||
return false;
|
||||
return CombineResult::DIFFERNENT_MODIFIER_ERROR;
|
||||
}
|
||||
|
||||
// only one definition should have documentation
|
||||
if (docs_.get_description().has_value() &&
|
||||
other_type_definition.docs_.get_description().has_value()) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_DOCS_ERROR;
|
||||
}
|
||||
if (docs_.get_annotations_info_size() > 0 &&
|
||||
other_type_definition.docs_.get_annotations_info_size() > 0) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_DOCS_ERROR;
|
||||
}
|
||||
|
||||
// only one definition should define type and arguments (they should be
|
||||
|
|
@ -169,7 +201,7 @@ bool TypeDefinition::combine(TypeDefinition &&other_type_definition) {
|
|||
if ((other_type_definition.type_.has_value() ||
|
||||
!other_type_definition.arguments_.empty()) &&
|
||||
(type_.has_value() || !arguments_.empty())) {
|
||||
return false;
|
||||
return CombineResult::ARGUMENTS_ERROR;
|
||||
}
|
||||
|
||||
// combine docs
|
||||
|
|
@ -178,7 +210,7 @@ bool TypeDefinition::combine(TypeDefinition &&other_type_definition) {
|
|||
other_type_definition.docs_.get_annotations_info_size() > 0) {
|
||||
if (docs_.get_annotations_info_size() > 0 ||
|
||||
docs_.get_description().has_value()) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_DOCS_ERROR;
|
||||
}
|
||||
|
||||
docs_ = std::move(other_type_definition.docs_);
|
||||
|
|
@ -192,38 +224,58 @@ bool TypeDefinition::combine(TypeDefinition &&other_type_definition) {
|
|||
type_ = std::move(other_type_definition.type_);
|
||||
}
|
||||
|
||||
// TODO: can be in incorrect state if error occure here
|
||||
// combine methods ??
|
||||
methods_.reserve(methods_.size() + other_type_definition.methods_.size());
|
||||
|
||||
for (size_t i = 0; i < other_type_definition.methods_.size(); ++i) {
|
||||
methods_.push_back(std::move(other_type_definition.methods_[i]));
|
||||
auto method_iter = methods_by_name_.find(
|
||||
*other_type_definition.methods_[i].get_name()->get());
|
||||
|
||||
if (method_iter == methods_by_name_.end()) {
|
||||
methods_by_name_[*other_type_definition.methods_[i].get_name()->get()] =
|
||||
methods_.size();
|
||||
methods_.push_back(std::move(other_type_definition.methods_[i]));
|
||||
} else {
|
||||
auto method_combine_result = methods_[method_iter->second].combine(
|
||||
std::move(other_type_definition.methods_[i]));
|
||||
if (method_combine_result != CombineResult::OK) {
|
||||
return method_combine_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: combine methods ??
|
||||
return CombineResult::OK;
|
||||
}
|
||||
|
||||
bool TypeclassDefinition::is_same_to(
|
||||
const TypeclassDefinition &other_typeclass_definition) const {
|
||||
if (*name_.get() != *other_typeclass_definition.name_.get()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeclassDefinition::combine(
|
||||
TypeclassDefinition &&other_typeclass_definition) {
|
||||
CombineResult
|
||||
TypeclassDefinition::combine(TypeclassDefinition &&other_typeclass_definition) {
|
||||
// should be same in all definitions of one typeclass
|
||||
if (*name_.get() != *other_typeclass_definition.name_.get()) {
|
||||
return false;
|
||||
return CombineResult::DIFFERENT_NAME_ERROR;
|
||||
}
|
||||
|
||||
// only one definition should have documentation
|
||||
if (docs_.get_description().has_value() &&
|
||||
other_typeclass_definition.docs_.get_description().has_value()) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_DOCS_ERROR;
|
||||
}
|
||||
if (docs_.get_annotations_info_size() > 0 &&
|
||||
other_typeclass_definition.docs_.get_annotations_info_size() > 0) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_DOCS_ERROR;
|
||||
}
|
||||
|
||||
// only one definition should define base typeclasses
|
||||
if (!base_typeclasses_.empty() &&
|
||||
!other_typeclass_definition.base_typeclasses_.empty()) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_DEFINITION_BODY_ERROR;
|
||||
}
|
||||
|
||||
// combine docs
|
||||
|
|
@ -232,7 +284,7 @@ bool TypeclassDefinition::combine(
|
|||
other_typeclass_definition.docs_.get_annotations_info_size() > 0) {
|
||||
if (docs_.get_annotations_info_size() > 0 ||
|
||||
docs_.get_description().has_value()) {
|
||||
return false;
|
||||
return CombineResult::MORE_THEN_ONE_DOCS_ERROR;
|
||||
}
|
||||
|
||||
docs_ = std::move(other_typeclass_definition.docs_);
|
||||
|
|
@ -242,15 +294,89 @@ bool TypeclassDefinition::combine(
|
|||
base_typeclasses_ = std::move(other_typeclass_definition.base_typeclasses_);
|
||||
}
|
||||
|
||||
// TODO: can be in incorrect state if error occure here
|
||||
// combine methods ??
|
||||
methods_.reserve(methods_.size() +
|
||||
other_typeclass_definition.methods_.size());
|
||||
for (size_t i = 0; i < other_typeclass_definition.methods_.size(); ++i) {
|
||||
methods_.push_back(std::move(other_typeclass_definition.methods_[i]));
|
||||
auto method_iter = methods_by_name_.find(
|
||||
*other_typeclass_definition.methods_[i].get_name()->get());
|
||||
|
||||
if (method_iter == methods_by_name_.end()) {
|
||||
methods_by_name_
|
||||
[*other_typeclass_definition.methods_[i].get_name()->get()] =
|
||||
methods_.size();
|
||||
methods_.push_back(std::move(other_typeclass_definition.methods_[i]));
|
||||
} else {
|
||||
auto method_combine_result = methods_[method_iter->second].combine(
|
||||
std::move(other_typeclass_definition.methods_[i]));
|
||||
if (method_combine_result != CombineResult::OK) {
|
||||
return method_combine_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: combine methods ??
|
||||
return CombineResult::OK;
|
||||
}
|
||||
|
||||
return true;
|
||||
bool Statement::is_same_to(const Statement &other_statement) const {
|
||||
if (expression_.index() != other_statement.expression_.index()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (expression_.index()) {
|
||||
case 0: // Import
|
||||
return false;
|
||||
case 1: // TypeDefinition
|
||||
return std::get<TypeDefinition>(expression_)
|
||||
.is_same_to(
|
||||
std::move(std::get<TypeDefinition>(other_statement.expression_)));
|
||||
case 2: // FunctionDefinition
|
||||
return std::get<FunctionDefinition>(expression_)
|
||||
.is_same_to(std::move(
|
||||
std::get<FunctionDefinition>(other_statement.expression_)));
|
||||
case 3: // TypeclassDefinition
|
||||
return std::get<TypeclassDefinition>(expression_)
|
||||
.is_same_to(std::move(
|
||||
std::get<TypeclassDefinition>(other_statement.expression_)));
|
||||
case 4: // EmptyLines
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
error_handling::handle_general_error("Unreachable");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
CombineResult Statement::combine(Statement &&other_statement) {
|
||||
if (expression_.index() != other_statement.expression_.index()) {
|
||||
return CombineResult::DIFFERENT_STATEMENT_TYPES;
|
||||
}
|
||||
|
||||
switch (expression_.index()) {
|
||||
case 0: // Import
|
||||
return CombineResult::STATEMENTS_CANT_BE_COMBINED_ERROR;
|
||||
case 1: // TypeDefinition
|
||||
return std::get<TypeDefinition>(expression_)
|
||||
.combine(
|
||||
std::move(std::get<TypeDefinition>(other_statement.expression_)));
|
||||
case 2: // FunctionDefinition
|
||||
return std::get<FunctionDefinition>(expression_)
|
||||
.combine(std::move(
|
||||
std::get<FunctionDefinition>(other_statement.expression_)));
|
||||
case 3: // TypeclassDefinition
|
||||
return std::get<TypeclassDefinition>(expression_)
|
||||
.combine(std::move(
|
||||
std::get<TypeclassDefinition>(other_statement.expression_)));
|
||||
case 4: // EmptyLines
|
||||
return CombineResult::STATEMENTS_CANT_BE_COMBINED_ERROR;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
error_handling::handle_general_error("Unreachable");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
} // namespace nodes
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue