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