Support one hardcoded import

This commit is contained in:
2025-07-10 00:43:17 +02:00
parent 181b19eefe
commit f02b2c49e5
14 changed files with 210 additions and 111 deletions

View File

@ -17,31 +17,52 @@ along with GCC; see the file COPYING3. If not see
#include "elna/boot/dependency.h"
#include <fstream>
#include <sstream>
#include <string.h>
#include "elna/boot/driver.h"
#include "elna/boot/semantic.h"
#include "parser.hh"
namespace elna::boot
{
dependency_graph::dependency_graph()
source_path_error::source_path_error(const std::string& message, const char *path)
: error(path, { 0, 0 }), message(message)
{
}
dependency_graph::dependency_graph(error_list&& errors)
std::string source_path_error::what() const
{
std::stringstream output;
output << "Cannot open filename ";
output << this->path;
output << ": ";
output << this->message;
return output.str();
}
dependency::dependency()
{
}
dependency::dependency(error_list&& errors)
: m_errors(std::move(errors))
{
}
bool dependency_graph::has_errors() const
bool dependency::has_errors() const
{
return !errors().empty();
}
const error_list& dependency_graph::errors() const
const error_list& dependency::errors() const
{
return m_errors;
}
dependency_graph read_sources(std::istream& entry_point, const char *entry_path)
dependency parse_source(std::istream& entry_point, const char *entry_path)
{
driver parse_driver{ entry_path };
lexer tokenizer(entry_point);
@ -49,14 +70,52 @@ namespace elna::boot
if (parser())
{
return dependency_graph(std::move(parse_driver.errors()));
return dependency(std::move(parse_driver.errors()));
}
else
{
dependency_graph outcome;
outcome.modules.emplace_back(std::move(parse_driver.tree));
dependency outcome;
std::swap(outcome.tree, parse_driver.tree);
return outcome;
}
}
dependency read_sources(const char *entry_path, std::shared_ptr<symbol_table> info_table,
std::shared_ptr<symbol_table> imports)
{
std::ifstream entry_point{ entry_path, std::ios::in };
if (!entry_point)
{
error_list errors;
errors.push_back(std::make_unique<source_path_error>(strerror(errno), entry_path));
return dependency(std::move(errors));
}
auto outcome = parse_source(entry_point, entry_path);
declaration_visitor declaration_visitor(entry_path);
outcome.tree->accept(&declaration_visitor);
if (!declaration_visitor.errors().empty())
{
return dependency(std::move(declaration_visitor.errors()));
}
outcome.unresolved = declaration_visitor.unresolved;
outcome.bag = symbol_bag{ std::move(declaration_visitor.unresolved), info_table };
if (imports != nullptr)
{
outcome.bag.add_import(imports);
}
elna::boot::name_analysis_visitor name_analysis_visitor(entry_path, outcome.bag);
outcome.tree->accept(&name_analysis_visitor);
if (!name_analysis_visitor.errors().empty())
{
return dependency(std::move(declaration_visitor.errors()));
}
return outcome;
}
}

View File

@ -182,7 +182,7 @@ program:
}
| "module" ";" import_part constant_part type_part variable_part procedure_part "end" "."
{
auto tree = new boot::program(boot::make_position(@1));
auto tree = new boot::unit(boot::make_position(@1));
std::swap(tree->imports, $3);
std::swap(tree->constants, $4);

View File

@ -74,9 +74,8 @@ namespace elna::boot
return message;
}
name_analysis_visitor::name_analysis_visitor(const char *path, std::shared_ptr<symbol_table> symbols,
std::unordered_map<std::string, std::shared_ptr<alias_type>>&& unresolved)
: error_container(path), symbols(symbols), unresolved(std::move(unresolved))
name_analysis_visitor::name_analysis_visitor(const char *path, symbol_bag bag)
: error_container(path), bag(bag)
{
}
@ -120,20 +119,20 @@ namespace elna::boot
void name_analysis_visitor::visit(type_declaration *definition)
{
definition->body().accept(this);
auto unresolved_declaration = this->unresolved.at(definition->identifier.identifier);
auto unresolved_declaration = this->bag.unresolved.at(definition->identifier.identifier);
unresolved_declaration->reference = this->current_type;
}
void name_analysis_visitor::visit(named_type_expression *type_expression)
{
auto unresolved_alias = this->unresolved.find(type_expression->name);
auto unresolved_alias = this->bag.unresolved.find(type_expression->name);
if (unresolved_alias != this->unresolved.end())
if (unresolved_alias != this->bag.unresolved.end())
{
this->current_type = type(unresolved_alias->second);
}
else if (auto from_symbol_table = this->symbols->lookup(type_expression->name))
else if (auto from_symbol_table = this->bag.lookup(type_expression->name))
{
this->current_type = from_symbol_table->is_type()->symbol;
}
@ -214,28 +213,24 @@ namespace elna::boot
{
declaration->variable_type().accept(this);
this->symbols->enter(declaration->identifier.identifier,
std::make_shared<variable_info>(this->current_type));
this->bag.enter(declaration->identifier.identifier, std::make_shared<variable_info>(this->current_type));
}
void name_analysis_visitor::visit(constant_declaration *definition)
{
definition->body().accept(this);
this->symbols->enter(definition->identifier.identifier,
std::make_shared<constant_info>(this->current_literal));
this->bag.enter(definition->identifier.identifier, std::make_shared<constant_info>(this->current_literal));
}
void name_analysis_visitor::visit(procedure_declaration *definition)
{
std::shared_ptr<procedure_info> info;
auto heading = build_procedure(definition->heading());
if (definition->body.has_value())
{
info = std::make_shared<procedure_info>(build_procedure(definition->heading()),
definition->parameter_names, this->symbols);
this->symbols = info->symbols;
info = std::make_shared<procedure_info>(heading, definition->parameter_names, this->bag.enter());
for (constant_declaration *const constant : definition->body.value().constants())
{
@ -249,14 +244,13 @@ namespace elna::boot
{
statement->accept(this);
}
this->symbols = this->symbols->scope();
this->bag.leave();
}
else
{
info = std::make_shared<procedure_info>(build_procedure(definition->heading()),
definition->parameter_names);
info = std::make_shared<procedure_info>(heading, definition->parameter_names);
}
this->symbols->enter(definition->identifier.identifier, info);
this->bag.enter(definition->identifier.identifier, info);
}
void name_analysis_visitor::visit(assign_statement *statement)
@ -379,14 +373,14 @@ namespace elna::boot
{
type->accept(this);
}
for (auto& unresolved : this->unresolved)
for (auto& unresolved : this->bag.unresolved)
{
std::vector<std::string> path;
if (check_unresolved_symbol(unresolved.second, path))
{
auto info = std::make_shared<type_info>(type_info(type(unresolved.second)));
this->symbols->enter(std::move(unresolved.first), info);
this->bag.enter(unresolved.first, info);
}
else
{

View File

@ -313,13 +313,9 @@ namespace elna::boot
}
procedure_info::procedure_info(const procedure_type symbol, const std::vector<std::string> names,
std::shared_ptr<symbol_table> parent_table)
: symbol(symbol), names(names)
std::shared_ptr<symbol_table> scope)
: symbol(symbol), names(names), symbols(scope)
{
if (parent_table != nullptr)
{
this->symbols = std::make_shared<symbol_table>(parent_table);
}
}
std::shared_ptr<procedure_info> procedure_info::is_procedure()
@ -361,4 +357,51 @@ namespace elna::boot
return result;
}
symbol_bag::symbol_bag()
{
this->symbols = std::make_shared<symbol_table>();
this->imports = std::make_shared<symbol_table>();
}
symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr<symbol_table> symbols)
: symbols(symbols), unresolved(unresolved)
{
this->imports = std::make_shared<symbol_table>();
}
std::shared_ptr<info> symbol_bag::lookup(const std::string& name)
{
if (auto result = this->imports->lookup(name))
{
return result;
}
return this->symbols->lookup(name);
}
bool symbol_bag::enter(const std::string& name, std::shared_ptr<info> entry)
{
return this->symbols->enter(name, entry);
}
std::shared_ptr<symbol_table> symbol_bag::enter()
{
this->symbols = std::make_shared<symbol_table>(this->symbols);
return this->symbols;
}
void symbol_bag::enter(std::shared_ptr<symbol_table> child)
{
this->symbols = child;
}
void symbol_bag::leave()
{
this->symbols = this->symbols->scope();
}
void symbol_bag::add_import(std::shared_ptr<symbol_table> table)
{
this->imports = table;
}
}