/* 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; } }