/* Dependency graph analysis.
Copyright (C) 2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
. */
#include "elna/boot/dependency.h"
#include "elna/boot/driver.h"
#include "elna/boot/materialization.h"
#include "elna/boot/name_analysis.h"
#include "elna/boot/type_check.h"
#include "elna/boot/validation.h"
#include "parser.hh"
namespace elna::boot
{
circular_import_error::circular_import_error(const source_position position,
const std::string& module_name)
: diagnostic(position), module_name(module_name)
{
}
std::string circular_import_error::what() const
{
return "Circular import of module '" + this->module_name + "'";
}
read_result read_source(std::istream& entry_point, const target_info& target)
{
driver parse_driver;
lexer tokenizer(entry_point);
yy::parser parser(tokenizer, parse_driver);
if (parser() != 0)
{
diagnostic_list errors;
std::swap(errors, parse_driver.errors());
return read_result{ std::in_place_type, std::move(errors) };
}
std::unique_ptr tree;
std::swap(tree, parse_driver.tree);
materialization_visitor materialization_visitor(target);
tree->accept(&materialization_visitor);
if (materialization_visitor.has_errors())
{
diagnostic_list errors;
std::swap(errors, materialization_visitor.errors());
return read_result{ std::in_place_type, std::move(errors) };
}
return read_result{ std::in_place_type>, std::move(tree) };
}
analysis_result analyze_semantics(std::unique_ptr& tree,
const std::vector>& imports,
const std::shared_ptr& globals, const target_info& target,
const std::filesystem::path& module_path)
{
forward_declaration_visitor forward_declarer;
tree->accept(&forward_declarer);
analysis_result result{
.value = symbol_bag(std::move(forward_declarer.unresolved), globals),
.errors = std::move(forward_declarer.errors())
};
if (!result.errors.empty())
{
return result;
}
for (const auto& import : imports)
{
result.value.add_import(import);
}
declaration_visitor declarations(result.value, target, module_path);
tree->accept(&declarations);
if (declarations.has_errors())
{
std::swap(result.errors, declarations.errors());
return result;
}
name_analysis_visitor name_analyser(result.value, target, module_path);
tree->accept(&name_analyser);
if (name_analyser.has_errors())
{
std::swap(result.errors, name_analyser.errors());
return result;
}
type_analysis_visitor type_analyzer(result.value, target);
tree->accept(&type_analyzer);
if (type_analyzer.has_errors())
{
std::swap(result.errors, type_analyzer.errors());
return result;
}
validation_visitor validator(result.value, target);
tree->accept(&validator);
if (validator.has_errors())
{
std::swap(result.errors, validator.errors());
return result;
}
return result;
}
std::filesystem::path build_path(const std::vector& segments)
{
std::filesystem::path result;
std::vector::const_iterator segment_iterator = std::cbegin(segments);
if (segment_iterator == std::cend(segments))
{
return result;
}
result = *segment_iterator;
++segment_iterator;
for (; segment_iterator != std::cend(segments); ++segment_iterator)
{
result /= *segment_iterator;
}
result.replace_extension(".elna");
return result;
}
}