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) |     void name_analysis_visitor::visit(type_declaration *definition) | ||||||
|     { |     { | ||||||
|         definition->body().accept(this); |         definition->body().accept(this); | ||||||
|         auto unresolved_declaration = this->bag.unresolved.at(definition->identifier.identifier); |         this->bag.resolve(definition->identifier.identifier, this->current_type); | ||||||
|  |  | ||||||
|         unresolved_declaration->reference = this->current_type; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void name_analysis_visitor::visit(named_type_expression *type_expression) |     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)) |         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) |         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, |     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; |             return false; | ||||||
|         } |         } | ||||||
|         path.push_back(alias->name); |         alias_path.push_back(alias->name); | ||||||
|  |  | ||||||
|         if (auto another_alias = alias->reference.get<alias_type>()) |         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; |         return true; | ||||||
|     } |     } | ||||||
| @@ -462,18 +464,18 @@ namespace elna::boot | |||||||
|         { |         { | ||||||
|             type->accept(this); |             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))); |                 auto info = std::make_shared<type_info>(type_info(type(unresolved.second))); | ||||||
|                 this->bag.enter(unresolved.first, info); |                 this->bag.enter(unresolved.first, info); | ||||||
|             } |             } | ||||||
|             else |             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) |         for (variable_declaration *const variable : unit->variables) | ||||||
|   | |||||||
| @@ -358,14 +358,20 @@ namespace elna::boot | |||||||
|         return result; |         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) |     forward_table::const_iterator symbol_bag::begin() | ||||||
|         : symbols(symbols), unresolved(unresolved) |  | ||||||
|     { |     { | ||||||
|  |         return unresolved.cbegin(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     forward_table::const_iterator symbol_bag::end() | ||||||
|  |     { | ||||||
|  |         return unresolved.cend(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     std::shared_ptr<info> symbol_bag::lookup(const std::string& name) |     std::shared_ptr<info> symbol_bag::lookup(const std::string& name) | ||||||
| @@ -396,18 +402,31 @@ namespace elna::boot | |||||||
|         this->symbols = child; |         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) |     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; |         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) |     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) |         for (auto& [symbol_name, symbol_info] : *info_table) | ||||||
| @@ -250,6 +261,10 @@ namespace elna::gcc | |||||||
|                     handle_symbol(symbol_name, alias_type, symbols); |                     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()) |             else if (auto procedure_info = symbol_info->is_procedure()) | ||||||
|             { |             { | ||||||
|                 declare_procedure(symbol_name, *procedure_info, symbols); |                 declare_procedure(symbol_name, *procedure_info, symbols); | ||||||
|   | |||||||
| @@ -747,15 +747,15 @@ namespace elna::gcc | |||||||
|     { |     { | ||||||
|         for (const auto& variable_identifier : declaration->identifiers) |         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()); |             location_t declaration_location = get_location(&declaration->position()); | ||||||
|             tree declaration_tree = build_decl(declaration_location, VAR_DECL, |             tree declaration_tree = this->symbols->lookup(variable_identifier.identifier); | ||||||
|                     get_identifier(variable_identifier.identifier.c_str()), this->current_expression); |  | ||||||
|             bool result = this->symbols->enter(variable_identifier.identifier, declaration_tree); |  | ||||||
|  |  | ||||||
|  |             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. |             // Set initializer if given. | ||||||
|             if (declaration->body != nullptr) |             if (declaration->body != nullptr) | ||||||
|             { |             { | ||||||
| @@ -771,19 +771,18 @@ namespace elna::gcc | |||||||
|                             print_type(TREE_TYPE(this->current_expression)).c_str()); |                             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_INITIAL(declaration_tree) = elna_pointer_nil_node; | ||||||
|             } |             } | ||||||
|             DECL_EXTERNAL(declaration_tree) = declaration->is_extern; |  | ||||||
|             TREE_PUBLIC(declaration_tree) = variable_identifier.exported; |             TREE_PUBLIC(declaration_tree) = variable_identifier.exported; | ||||||
|             this->current_expression = NULL_TREE; |             this->current_expression = NULL_TREE; | ||||||
|             if (!result) |  | ||||||
|             { |             if (lang_hooks.decls.global_bindings_p()) | ||||||
|                 error_at(declaration_location, "Variable '%s' already declared in this scope", |  | ||||||
|                         variable_identifier.identifier.c_str()); |  | ||||||
|             } |  | ||||||
|             else if (lang_hooks.decls.global_bindings_p()) |  | ||||||
|             { |             { | ||||||
|                 TREE_STATIC(declaration_tree) = 1; |                 TREE_STATIC(declaration_tree) = 1; | ||||||
|                 varpool_node::get_create(declaration_tree); |                 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) | 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 }; |     std::ifstream entry_point{ filename, std::ios::in }; | ||||||
|  |  | ||||||
|     if (!entry_point) |     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::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) |     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); |         elna::gcc::report_errors(semantic_errors); | ||||||
|     } |     } | ||||||
|     state.cache.insert({ filename, outcome_bag }); |     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); |     linemap_add(line_table, LC_LEAVE, 0, NULL, 0); | ||||||
|  |  | ||||||
|     return outcome; |     return outcome; | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see | |||||||
| #include <fstream> | #include <fstream> | ||||||
| #include "elna/boot/result.h" | #include "elna/boot/result.h" | ||||||
| #include "elna/boot/ast.h" | #include "elna/boot/ast.h" | ||||||
|  | #include "elna/boot/symbol.h" | ||||||
|  |  | ||||||
| namespace elna::boot | namespace elna::boot | ||||||
| { | { | ||||||
|   | |||||||
| @@ -175,7 +175,7 @@ namespace elna::boot | |||||||
|     class declaration_visitor final : public empty_visitor, public error_container |     class declaration_visitor final : public empty_visitor, public error_container | ||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|         std::unordered_map<std::string, std::shared_ptr<alias_type>> unresolved; |         forward_table unresolved; | ||||||
|  |  | ||||||
|         explicit declaration_visitor(const char *path); |         explicit declaration_visitor(const char *path); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -231,6 +231,7 @@ namespace elna::boot | |||||||
|          * can not be found. |          * can not be found. | ||||||
|          * |          * | ||||||
|          * \param name Symbol name. |          * \param name Symbol name. | ||||||
|  |          * | ||||||
|          * \return Symbol from the table if found. |          * \return Symbol from the table if found. | ||||||
|          */ |          */ | ||||||
|         symbol_ptr lookup(const std::string& name) |         symbol_ptr lookup(const std::string& name) | ||||||
| @@ -250,6 +251,7 @@ namespace elna::boot | |||||||
|  |  | ||||||
|         /** |         /** | ||||||
|          * \param name Symbol name. |          * \param name Symbol name. | ||||||
|  |          * | ||||||
|          * \return Whether the table contains a symbol with the given name. |          * \return Whether the table contains a symbol with the given name. | ||||||
|          */ |          */ | ||||||
|         bool contains(const std::string& name) |         bool contains(const std::string& name) | ||||||
| @@ -328,24 +330,101 @@ namespace elna::boot | |||||||
|  |  | ||||||
|     std::shared_ptr<symbol_table> builtin_symbol_table(); |     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 |     class symbol_bag | ||||||
|     { |     { | ||||||
|         std::shared_ptr<symbol_table> symbols; |         std::shared_ptr<symbol_table> symbols; | ||||||
|         std::forward_list<std::shared_ptr<symbol_table>> imports; |         std::forward_list<std::shared_ptr<symbol_table>> imports; | ||||||
|  |  | ||||||
|     public: |  | ||||||
|         forward_table unresolved; |         forward_table unresolved; | ||||||
|  |  | ||||||
|         symbol_bag(); |     public: | ||||||
|         symbol_bag(forward_table&& unresolved, std::shared_ptr<symbol_table> symbols); |  | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * \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); |         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); |         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); |     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, |     void declare_procedure(const std::string& name, const boot::procedure_info& info, | ||||||
|             std::shared_ptr<symbol_table> symbols); |             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