/* Crafter® Build Copyright (C) 2025 Catcrafts® Catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3.0 as published by the Free Software Foundation; This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #include "../lib/json.hpp" #include module Crafter.Build:Configuration_impl; import :Configuration; import std; //import :Dependency; import :Shader; import :Module; namespace fs = std::filesystem; namespace Crafter { Configuration::Configuration(std::string&& name) : name(std::move(name)) { } Configuration::Configuration(const nlohmann::json& configs, const nlohmann::json& config, fs::path workingDir) { SetDataFromJson(configs, config, workingDir); } void Configuration::SetDataFromJson(const nlohmann::json& configs, const nlohmann::json& config, fs::path workingDir) { if(config.contains("extends")) { const std::vector extends = config["extends"].get>(); for(const std::string& extendName : extends) { for (auto it : configs) { if(it["name"].get() == extendName) { SetDataFromJson(configs, it, workingDir); } } } } if(config.contains("name")) { name = config["name"].get(); } else { throw std::runtime_error("Invalid config json, name field is missing"); } if(config.contains("standard")) { standard = config["standard"].get(); } if(config.contains("target")) { target = config["target"].get(); } if(config.contains("debug")) { debug = config["debug"].get(); } if(config.contains("type")) { std::string typeString = config["type"].get(); if(typeString == "executable") { type = CRAFTER_CONFIGURATION_TYPE_EXECUTABLE; } else if(typeString == "library") { type = CRAFTER_CONFIGURATION_TYPE_LIBRARY; } else if(typeString == "shared-library") { type = CRAFTER_CONFIGURATION_TYPE_SHARED_LIBRARY; } else { throw std::invalid_argument("Unknown type: " + typeString); } } if(config.contains("march")) { march = config["march"].get(); } if(config.contains("libs")) { for (auto it : config["libs"]) { libs.push_back(it.get()); } } if(config.contains("interfaces")) { const std::vector tempModuleFiles = config["interfaces"].get>(); std::vector> tempModulePaths = std::vector>(tempModuleFiles.size()); for(std::uint_fast32_t i = 0; i < tempModuleFiles.size(); i++){ const std::filesystem::path file = workingDir / (tempModuleFiles[i]+".cppm"); std::ifstream t(file); std::stringstream buffer; buffer << t.rdbuf(); std::string fileContent = buffer.str(); fileContent = std::regex_replace(fileContent, std::regex(R"(//[^\n]*)"), ""); fileContent = std::regex_replace(fileContent, std::regex(R"(/\*.*?\*/)"), ""); tempModulePaths[i] = {file, fileContent, nullptr, nullptr}; } std::erase_if(tempModulePaths, [this](std::tuple& file) { std::smatch match; if (std::regex_search(std::get<1>(file), match, std::regex(R"(export module ([a-zA-Z0-9_\.\-]+);)"))) { std::get<0>(file).replace_extension(""); interfaces.push_back(std::make_unique(std::move(match[1].str()), std::move(std::get<0>(file)))); return true; } else { return false; } }); for(uint_fast32_t i = 0; i < tempModulePaths.size(); i++) { std::smatch match; if (std::regex_search(std::get<1>(tempModulePaths[i]), match, std::regex(R"(export module ([a-zA-Z_0-9\.\-]+):([a-zA-Z_0-9\.\-]+);)"))) { for(const std::unique_ptr& modulee : interfaces) { if(modulee->name == match[1]) { std::string name = match[2].str(); fs::path pthCpy = std::get<0>(tempModulePaths[i]); pthCpy.replace_extension(""); std::unique_ptr partition = std::make_unique(std::move(name), std::move(pthCpy)); std::get<2>(tempModulePaths[i]) = partition.get(); modulee->partitions.push_back(std::move(partition)); std::get<3>(tempModulePaths[i]) = modulee.get(); goto next; } } throw std::runtime_error(std::format("Module {} not found, referenced in {}", match[1].str(), std::get<0>(tempModulePaths[i]).string())); } else { throw std::runtime_error(std::format("No module declaration found in {}", std::get<0>(tempModulePaths[i]).string())); } next:; } for(std::tuple& file : tempModulePaths) { std::regex pattern(R"(import :([a-zA-Z_\-0-9\.]+);)"); std::sregex_iterator currentMatch(std::get<1>(file).begin(), std::get<1>(file).end(), pattern); std::sregex_iterator lastMatch; while (currentMatch != lastMatch) { std::smatch match = *currentMatch; for(std::unique_ptr& partition2 : std::get<3>(file)->partitions) { if(partition2->name == match[1]) { std::get<2>(file)->partitionDependencies.push_back(partition2.get()); goto next2; } } throw std::runtime_error(std::format("imported partition {}:{} not found, referenced in {}", std::get<3>(file)->name, match[1].str(), std::get<0>(file).string())); next2: ++currentMatch; } } } if(config.contains("implementations")) { const std::vector tempFiles = config["implementations"].get>(); for(const std::string& tempFile : tempFiles) { const std::filesystem::path file = workingDir / (tempFile + ".cpp"); std::ifstream t(file); std::stringstream buffer; buffer << t.rdbuf(); std::string fileContent = buffer.str(); fileContent = std::regex_replace(fileContent, std::regex(R"(//[^\n]*)"), ""); fileContent = std::regex_replace(fileContent, std::regex(R"(/\*.*?\*/)"), ""); std::smatch match; fs::path fileCopy = file; fileCopy.replace_extension(""); Implementation& implementation = implementations.emplace_back(std::move(fileCopy)); if (std::regex_search(fileContent, match, std::regex(R"(module ([a-zA-Z0-9_\.\-]+))"))) { for(const std::unique_ptr& interface : interfaces) { if(interface->name == match[1]) { std::regex pattern(R"(import :([a-zA-Z_\-0-9\.]*);)"); std::sregex_iterator currentMatch(fileContent.begin(), fileContent.end(), pattern); std::sregex_iterator lastMatch; while (currentMatch != lastMatch) { std::smatch match2 = *currentMatch; for(const std::unique_ptr& partition : interface->partitions) { if(partition->name == match2[1]) { implementation.partitionDependencies.push_back(partition.get()); goto next3; } } throw std::runtime_error(std::format("imported partition {}:{} not found, referenced in {}", match[1].str(), match2[1].str(), file.string())); next3: ++currentMatch; } goto next4; } } throw std::runtime_error(std::format("Module {} not found not found, referenced in {}", match[1].str(), file.string())); next4:; } else { std::regex pattern(R"(import ([a-zA-Z_\-0-9\.]*);)"); std::sregex_iterator currentMatch(fileContent.begin(), fileContent.end(), pattern); std::sregex_iterator lastMatch; while (currentMatch != lastMatch) { std::smatch match = *currentMatch; for(const std::unique_ptr& interface : interfaces) { if(interface->name == match[1]) { implementation.moduleDependencies.push_back(interface.get()); goto next5; } } //throw std::runtime_error(std::format("imported module {} not found, referenced in {}", match[1].str(), file.string())); next5: ++currentMatch; } } } } if(config.contains("shaders")) { for (auto it : config["shaders"]) { shaders.emplace_back(workingDir / it["path"].get(), it["entrypoint"].get(), static_cast(it["type"].get())); } } if(config.contains("defines")) { for (auto it : config["defines"]) { defines.emplace_back(it["name"].get(), it["value"].get()); } } if(config.contains("additional_files")) { const std::vector tempAdditionalFiles = config["additional_files"].get>(); for (const std::string& file : tempAdditionalFiles) { additionalFiles.push_back( workingDir / file); } } if(config.contains("build_dir")) { buildDir = workingDir / config["build_dir"].get(); } if(config.contains("output_dir")) { outputDir = workingDir / config["output_dir"].get(); } if(config.contains("dependencies")) { for (auto it : config["dependencies"]) { std::string commit; std::string branch; if(it.contains("commit")){ commit = it["commit"].get(); } if(it.contains("branch")){ branch = it["branch"].get(); } dependencies.emplace_back(it["path"].get(), it["configuration"].get(), std::move(commit), std::move(branch)); } } } }