Document symbol bag class and methods
This commit is contained in:
		| @@ -205,18 +205,16 @@ namespace elna::boot | ||||
|     void name_analysis_visitor::visit(type_declaration *definition) | ||||
|     { | ||||
|         definition->body().accept(this); | ||||
|         auto unresolved_declaration = this->bag.unresolved.at(definition->identifier.identifier); | ||||
|  | ||||
|         unresolved_declaration->reference = this->current_type; | ||||
|         this->bag.resolve(definition->identifier.identifier, this->current_type); | ||||
|     } | ||||
|  | ||||
|     void name_analysis_visitor::visit(named_type_expression *type_expression) | ||||
|     { | ||||
|         auto unresolved_alias = this->bag.unresolved.find(type_expression->name); | ||||
|         auto unresolved_alias = this->bag.declared(type_expression->name); | ||||
|  | ||||
|         if (unresolved_alias != this->bag.unresolved.end()) | ||||
|         if (unresolved_alias != nullptr) | ||||
|         { | ||||
|             this->current_type = type(unresolved_alias->second); | ||||
|             this->current_type = type(unresolved_alias); | ||||
|         } | ||||
|         else if (auto from_symbol_table = this->bag.lookup(type_expression->name)) | ||||
|         { | ||||
| @@ -301,7 +299,11 @@ namespace elna::boot | ||||
|  | ||||
|         for (const auto& variable_identifier : declaration->identifiers) | ||||
|         { | ||||
|             this->bag.enter(variable_identifier.identifier, std::make_shared<variable_info>(this->current_type)); | ||||
|             if (!this->bag.enter(variable_identifier.identifier, std::make_shared<variable_info>(this->current_type))) | ||||
|             { | ||||
|                 add_error<already_declared_error>(variable_identifier.identifier, this->input_file, | ||||
|                         declaration->position()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -441,17 +443,17 @@ namespace elna::boot | ||||
|     } | ||||
|  | ||||
|     bool name_analysis_visitor::check_unresolved_symbol(std::shared_ptr<alias_type> alias, | ||||
|             std::vector<std::string>& path) | ||||
|             std::vector<std::string>& alias_path) | ||||
|     { | ||||
|         if (std::find(std::cbegin(path), std::cend(path), alias->name) != std::cend(path)) | ||||
|         if (std::find(std::cbegin(alias_path), std::cend(alias_path), alias->name) != std::cend(alias_path)) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         path.push_back(alias->name); | ||||
|         alias_path.push_back(alias->name); | ||||
|  | ||||
|         if (auto another_alias = alias->reference.get<alias_type>()) | ||||
|         { | ||||
|             return check_unresolved_symbol(another_alias, path); | ||||
|             return check_unresolved_symbol(another_alias, alias_path); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| @@ -462,18 +464,18 @@ namespace elna::boot | ||||
|         { | ||||
|             type->accept(this); | ||||
|         } | ||||
|         for (auto& unresolved : this->bag.unresolved) | ||||
|         for (auto& unresolved : this->bag) | ||||
|         { | ||||
|             std::vector<std::string> path; | ||||
|             std::vector<std::string> alias_path; | ||||
|  | ||||
|             if (check_unresolved_symbol(unresolved.second, path)) | ||||
|             if (check_unresolved_symbol(unresolved.second, alias_path)) | ||||
|             { | ||||
|                 auto info = std::make_shared<type_info>(type_info(type(unresolved.second))); | ||||
|                 this->bag.enter(unresolved.first, info); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 add_error<cyclic_declaration_error>(path, this->input_file, position{ 0, 0 }); | ||||
|                 add_error<cyclic_declaration_error>(alias_path, this->input_file, position{ 0, 0 }); | ||||
|             } | ||||
|         } | ||||
|         for (variable_declaration *const variable : unit->variables) | ||||
|   | ||||
| @@ -358,14 +358,20 @@ namespace elna::boot | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     symbol_bag::symbol_bag() | ||||
|     symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr<symbol_table> global_table) | ||||
|         : unresolved(unresolved) | ||||
|     { | ||||
|         this->symbols = std::make_shared<symbol_table>(); | ||||
|         this->symbols = std::make_shared<symbol_table>(global_table); | ||||
|     } | ||||
|  | ||||
|     symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr<symbol_table> symbols) | ||||
|         : symbols(symbols), unresolved(unresolved) | ||||
|     forward_table::const_iterator symbol_bag::begin() | ||||
|     { | ||||
|         return unresolved.cbegin(); | ||||
|     } | ||||
|  | ||||
|     forward_table::const_iterator symbol_bag::end() | ||||
|     { | ||||
|         return unresolved.cend(); | ||||
|     } | ||||
|  | ||||
|     std::shared_ptr<info> symbol_bag::lookup(const std::string& name) | ||||
| @@ -396,18 +402,31 @@ namespace elna::boot | ||||
|         this->symbols = child; | ||||
|     } | ||||
|  | ||||
|     void symbol_bag::leave() | ||||
|     std::shared_ptr<symbol_table> symbol_bag::leave() | ||||
|     { | ||||
|         this->symbols = this->symbols->scope(); | ||||
|         std::shared_ptr<symbol_table> result = this->symbols; | ||||
|  | ||||
|         this->symbols = result->scope(); | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     void symbol_bag::add_import(std::shared_ptr<symbol_table> table) | ||||
|     std::shared_ptr<alias_type> symbol_bag::declared(const std::string& symbol_name) | ||||
|     { | ||||
|         this->imports.push_front(table); | ||||
|         auto unresolved_alias = this->unresolved.find(symbol_name); | ||||
|  | ||||
|         return unresolved_alias == this->unresolved.end() ? std::shared_ptr<alias_type>() : unresolved_alias->second; | ||||
|     } | ||||
|  | ||||
|     std::shared_ptr<alias_type> symbol_bag::resolve(const std::string& symbol_name, type& resolution) | ||||
|     { | ||||
|         auto unresolved_declaration = this->unresolved.at(symbol_name); | ||||
|  | ||||
|         unresolved_declaration->reference = resolution; | ||||
|         return unresolved_declaration; | ||||
|     } | ||||
|  | ||||
|     void symbol_bag::add_import(const symbol_bag& bag) | ||||
|     { | ||||
|         add_import(bag.symbols); | ||||
|         this->imports.push_front(bag.symbols); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -238,6 +238,17 @@ namespace elna::gcc | ||||
|         DECL_EXTERNAL(fndecl) = info.symbols == nullptr; | ||||
|     } | ||||
|  | ||||
|     tree declare_variable(const std::string& name, const boot::variable_info& info, | ||||
|             std::shared_ptr<symbol_table> symbols) | ||||
|     { | ||||
|         auto variable_type = get_inner_alias(info.symbol, symbols); | ||||
|         tree declaration_tree = build_decl(UNKNOWN_LOCATION, VAR_DECL, get_identifier(name.c_str()), variable_type); | ||||
|  | ||||
|         symbols->enter(name, declaration_tree); | ||||
|  | ||||
|         return declaration_tree; | ||||
|     } | ||||
|  | ||||
|     void rewrite_symbol_table(std::shared_ptr<boot::symbol_table> info_table, std::shared_ptr<symbol_table> symbols) | ||||
|     { | ||||
|         for (auto& [symbol_name, symbol_info] : *info_table) | ||||
| @@ -250,6 +261,10 @@ namespace elna::gcc | ||||
|                     handle_symbol(symbol_name, alias_type, symbols); | ||||
|                 } | ||||
|             } | ||||
|             else if (auto variable_info = symbol_info->is_variable()) | ||||
|             { | ||||
|                 declare_variable(symbol_name, *variable_info, symbols); | ||||
|             } | ||||
|             else if (auto procedure_info = symbol_info->is_procedure()) | ||||
|             { | ||||
|                 declare_procedure(symbol_name, *procedure_info, symbols); | ||||
|   | ||||
| @@ -747,15 +747,15 @@ namespace elna::gcc | ||||
|     { | ||||
|         for (const auto& variable_identifier : declaration->identifiers) | ||||
|         { | ||||
|             this->current_expression = get_inner_alias( | ||||
|                     this->bag.lookup(variable_identifier.identifier)->is_variable()->symbol, | ||||
|                     this->symbols); | ||||
|  | ||||
|             location_t declaration_location = get_location(&declaration->position()); | ||||
|             tree declaration_tree = build_decl(declaration_location, VAR_DECL, | ||||
|                     get_identifier(variable_identifier.identifier.c_str()), this->current_expression); | ||||
|             bool result = this->symbols->enter(variable_identifier.identifier, declaration_tree); | ||||
|             tree declaration_tree = this->symbols->lookup(variable_identifier.identifier); | ||||
|  | ||||
|             if (declaration_tree == NULL_TREE) | ||||
|             { | ||||
|                 auto variable_symbol = this->bag.lookup(variable_identifier.identifier)->is_variable(); | ||||
|  | ||||
|                 declaration_tree = declare_variable(variable_identifier.identifier, *variable_symbol, this->symbols); | ||||
|             } | ||||
|             // Set initializer if given. | ||||
|             if (declaration->body != nullptr) | ||||
|             { | ||||
| @@ -771,19 +771,18 @@ namespace elna::gcc | ||||
|                             print_type(TREE_TYPE(this->current_expression)).c_str()); | ||||
|                 } | ||||
|             } | ||||
|             else if (POINTER_TYPE_P(this->current_expression)) | ||||
|             else if (declaration->is_extern) | ||||
|             { | ||||
|                 DECL_EXTERNAL(declaration_tree) = declaration->is_extern; | ||||
|             } | ||||
|             else if (POINTER_TYPE_P(TREE_TYPE(declaration_tree))) | ||||
|             { | ||||
|                 DECL_INITIAL(declaration_tree) = elna_pointer_nil_node; | ||||
|             } | ||||
|             DECL_EXTERNAL(declaration_tree) = declaration->is_extern; | ||||
|             TREE_PUBLIC(declaration_tree) = variable_identifier.exported; | ||||
|             this->current_expression = NULL_TREE; | ||||
|             if (!result) | ||||
|             { | ||||
|                 error_at(declaration_location, "Variable '%s' already declared in this scope", | ||||
|                         variable_identifier.identifier.c_str()); | ||||
|             } | ||||
|             else if (lang_hooks.decls.global_bindings_p()) | ||||
|  | ||||
|             if (lang_hooks.decls.global_bindings_p()) | ||||
|             { | ||||
|                 TREE_STATIC(declaration_tree) = 1; | ||||
|                 varpool_node::get_create(declaration_tree); | ||||
|   | ||||
| @@ -66,7 +66,6 @@ using dependency_state = elna::boot::dependency_state<std::shared_ptr<elna::gcc: | ||||
|  | ||||
| static elna::boot::dependency elna_parse_file(dependency_state& state, const char *filename) | ||||
| { | ||||
|     auto module_table = std::make_shared<elna::boot::symbol_table>(state.globals); | ||||
|     std::ifstream entry_point{ filename, std::ios::in }; | ||||
|  | ||||
|     if (!entry_point) | ||||
| @@ -80,7 +79,7 @@ static elna::boot::dependency elna_parse_file(dependency_state& state, const cha | ||||
|     { | ||||
|         elna::gcc::report_errors(outcome.errors()); | ||||
|     } | ||||
|     elna::boot::symbol_bag outcome_bag = elna::boot::symbol_bag{ std::move(outcome.unresolved), module_table }; | ||||
|     elna::boot::symbol_bag outcome_bag = elna::boot::symbol_bag{ std::move(outcome.unresolved), state.globals }; | ||||
|  | ||||
|     for (const auto& sub_tree : outcome.tree->imports) | ||||
|     { | ||||
| @@ -102,7 +101,7 @@ static elna::boot::dependency elna_parse_file(dependency_state& state, const cha | ||||
|         elna::gcc::report_errors(semantic_errors); | ||||
|     } | ||||
|     state.cache.insert({ filename, outcome_bag }); | ||||
|     elna::gcc::rewrite_symbol_table(module_table, state.custom); | ||||
|     elna::gcc::rewrite_symbol_table(outcome_bag.leave(), state.custom); | ||||
|     linemap_add(line_table, LC_LEAVE, 0, NULL, 0); | ||||
|  | ||||
|     return outcome; | ||||
|   | ||||
| @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see | ||||
| #include <fstream> | ||||
| #include "elna/boot/result.h" | ||||
| #include "elna/boot/ast.h" | ||||
| #include "elna/boot/symbol.h" | ||||
|  | ||||
| namespace elna::boot | ||||
| { | ||||
|   | ||||
| @@ -175,7 +175,7 @@ namespace elna::boot | ||||
|     class declaration_visitor final : public empty_visitor, public error_container | ||||
|     { | ||||
|     public: | ||||
|         std::unordered_map<std::string, std::shared_ptr<alias_type>> unresolved; | ||||
|         forward_table unresolved; | ||||
|  | ||||
|         explicit declaration_visitor(const char *path); | ||||
|  | ||||
|   | ||||
| @@ -231,6 +231,7 @@ namespace elna::boot | ||||
|          * can not be found. | ||||
|          * | ||||
|          * \param name Symbol name. | ||||
|          * | ||||
|          * \return Symbol from the table if found. | ||||
|          */ | ||||
|         symbol_ptr lookup(const std::string& name) | ||||
| @@ -250,6 +251,7 @@ namespace elna::boot | ||||
|  | ||||
|         /** | ||||
|          * \param name Symbol name. | ||||
|          * | ||||
|          * \return Whether the table contains a symbol with the given name. | ||||
|          */ | ||||
|         bool contains(const std::string& name) | ||||
| @@ -328,24 +330,101 @@ namespace elna::boot | ||||
|  | ||||
|     std::shared_ptr<symbol_table> builtin_symbol_table(); | ||||
|  | ||||
|     /** | ||||
|      * Symbol bag contains: | ||||
|      * | ||||
|      * - the symbol table of a module itself | ||||
|      * - symbol tables of imported modules | ||||
|      * - forward declarations | ||||
|      */ | ||||
|     class symbol_bag | ||||
|     { | ||||
|         std::shared_ptr<symbol_table> symbols; | ||||
|         std::forward_list<std::shared_ptr<symbol_table>> imports; | ||||
|  | ||||
|     public: | ||||
|         forward_table unresolved; | ||||
|  | ||||
|         symbol_bag(); | ||||
|         symbol_bag(forward_table&& unresolved, std::shared_ptr<symbol_table> symbols); | ||||
|     public: | ||||
|  | ||||
|         /** | ||||
|          * \param unresolved Forward declarations collected in the previous step. | ||||
|          * \param global_table Global symbols. | ||||
|          */ | ||||
|         symbol_bag(forward_table&& unresolved, std::shared_ptr<symbol_table> global_table); | ||||
|  | ||||
|         /** | ||||
|          * \return Iterator pointing to the first forward declaration. | ||||
|          */ | ||||
|         forward_table::const_iterator begin(); | ||||
|  | ||||
|         /** | ||||
|          * \return Iterator pointing past the last forward declaration. | ||||
|          */ | ||||
|         forward_table::const_iterator end(); | ||||
|  | ||||
|         /** | ||||
|          * Looks up a symbol in the current and imported modules. | ||||
|          * | ||||
|          * \param name Symbol name to look up. | ||||
|          * | ||||
|          * \return Symbol from one of the symbol tables if found. | ||||
|          */ | ||||
|         std::shared_ptr<info> lookup(const std::string& name); | ||||
|         bool enter(const std::string& name, std::shared_ptr<info> entry); | ||||
|         std::shared_ptr<symbol_table> enter(); | ||||
|         void enter(std::shared_ptr<symbol_table> child); | ||||
|         void leave(); | ||||
|  | ||||
|         void add_import(std::shared_ptr<symbol_table> table); | ||||
|         /** | ||||
|          * Inserts a symbol into the current scope. | ||||
|          * | ||||
|          * \param name Symbol name. | ||||
|          * \param entry Symbol info. | ||||
|          * | ||||
|          * \return Whether the insertion took place. | ||||
|          */ | ||||
|         bool enter(const std::string& name, std::shared_ptr<info> entry); | ||||
|  | ||||
|         /** | ||||
|          * Enters a new scope. | ||||
|          * | ||||
|          * \return Reference to the allocated scope. | ||||
|          */ | ||||
|         std::shared_ptr<symbol_table> enter(); | ||||
|  | ||||
|         /** | ||||
|          * Sets the current scope to \a child. | ||||
|          * | ||||
|          * \param child New scope. | ||||
|          */ | ||||
|         void enter(std::shared_ptr<symbol_table> child); | ||||
|  | ||||
|         /** | ||||
|          * Leave the current scope. | ||||
|          * | ||||
|          * \return Left scope. | ||||
|          */ | ||||
|         std::shared_ptr<symbol_table> leave(); | ||||
|  | ||||
|         /** | ||||
|          * Checks whether there is a forward declaration \a symbol_name and | ||||
|          * returns it if so. | ||||
|          * | ||||
|          * \param symbol_name Type name to look up. | ||||
|          * \return Forward declaration or `nullptr` if the symbol is not declared. | ||||
|          */ | ||||
|         std::shared_ptr<alias_type> declared(const std::string& symbol_name); | ||||
|  | ||||
|         /** | ||||
|          * Completes the forward-declared type \a symbol_name and defines it to | ||||
|          * be \a resolution. | ||||
|          * | ||||
|          * \param symbol_name Type name. | ||||
|          * \param resolution Type definition. | ||||
|          * \return Alias to the defined type. | ||||
|          */ | ||||
|         std::shared_ptr<alias_type> resolve(const std::string& symbol_name, type& resolution); | ||||
|  | ||||
|         /** | ||||
|          * Add imported symbols to the scope. | ||||
|          * | ||||
|          * \param bag Symbol bag of another module. | ||||
|          */ | ||||
|         void add_import(const symbol_bag& bag); | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -36,4 +36,6 @@ namespace elna::gcc | ||||
|     tree get_inner_alias(const boot::type& type, std::shared_ptr<symbol_table> symbols); | ||||
|     void declare_procedure(const std::string& name, const boot::procedure_info& info, | ||||
|             std::shared_ptr<symbol_table> symbols); | ||||
|     tree declare_variable(const std::string& name, const boot::variable_info& info, | ||||
|             std::shared_ptr<symbol_table> symbols); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user