diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp index efddefd1a2081ee30fe26cb77cb16e95eb33c8d1..427e084e87ae89de498558fff98b7c246b1d4a68 100644 --- a/src/language/PugsParser.cpp +++ b/src/language/PugsParser.cpp @@ -32,18 +32,25 @@ #include <unordered_map> #include <variant> +const std::unique_ptr<ASTNode>* p_root_node = nullptr; + void parser(const std::string& filename) { const size_t grammar_issues = analyze<language::grammar>(); - std::cout << rang::fgB::yellow << "grammar_issues=" << rang::fg::reset << grammar_issues << '\n'; + if (grammar_issues != 0) { + std::ostringstream os; + os << "invalid grammar: " << rang::fgB::yellow << grammar_issues << rang::fg::reset << " were detected!"; + throw UnexpectedError(os.str()); + } std::cout << rang::style::bold << "Parsing file " << rang::style::reset << rang::style::underline << filename << rang::style::reset << " ...\n"; auto parse_and_execute = [](auto& input) { std::unique_ptr<ASTNode> root_node = ASTBuilder::build(input); + p_root_node = &root_node; ASTModulesImporter{*root_node}; ASTNodeTypeCleaner<language::import_instruction>{*root_node}; @@ -64,35 +71,17 @@ parser(const std::string& filename) ASTNodeTypeCleaner<language::var_declaration>{*root_node}; ASTNodeTypeCleaner<language::fct_declaration>{*root_node}; - { - std::string dot_filename{"parse_tree.dot"}; - std::ofstream fout(dot_filename); - ASTDotPrinter dot_printer{*root_node}; - fout << dot_printer; - std::cout << " AST dot file: " << dot_filename << '\n'; - } - ASTNodeEmptyBlockCleaner{*root_node}; ASTNodeExpressionBuilder{*root_node}; - - std::cout << ASTPrinter{*root_node} << '\n'; - - auto& function_table = root_node->m_symbol_table->functionTable(); - - for (size_t i_function = 0; i_function < function_table.size(); ++i_function) { - const auto& function_descriptor = function_table[i_function]; - std::cout << "function " << rang::fgB::magenta << function_descriptor.name() << rang::style::reset << '\n'; - std::cout << ASTPrinter(function_descriptor.domainMappingNode()); - std::cout << ASTPrinter(function_descriptor.definitionNode()); - std::cout << "--------\n"; - } + std::cout << "-------------------------------------------------------\n"; + std::cout << rang::style::bold << "Executing AST..." << rang::style::reset << '\n'; ExecutionPolicy exec_all; root_node->execute(exec_all); - std::cout << *(root_node->m_symbol_table) << '\n'; root_node->m_symbol_table->clearValues(); + p_root_node = nullptr; }; if (not SignalManager::pauseOnError()) { @@ -107,7 +96,7 @@ parser(const std::string& filename) << rang::fgB::red << "error: " << rang::fg::reset << rang::style::bold << e.what() << rang::style::reset << '\n' << input.line_at(p) << '\n' - << std::string(p.column, ' ') << rang::fgB::yellow << '^' << rang::fg::reset << '\n'; + << std::string(p.column - 1, ' ') << rang::fgB::yellow << '^' << rang::fg::reset << '\n'; finalize(); std::exit(1); } @@ -115,5 +104,4 @@ parser(const std::string& filename) read_input input(filename); parse_and_execute(input); } - std::cout << "Executed successfuly: " << filename << '\n'; } diff --git a/src/language/ast/ASTNodeDataTypeBuilder.cpp b/src/language/ast/ASTNodeDataTypeBuilder.cpp index 4a56bdae9cc854582e7e8df435ebbaea8e01a582..7cbeb6adfdc96f8c2a56796c32c83592f0839d40 100644 --- a/src/language/ast/ASTNodeDataTypeBuilder.cpp +++ b/src/language/ast/ASTNodeDataTypeBuilder.cpp @@ -16,8 +16,7 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo std::ostringstream message; message << "number of product spaces (" << type_node.children.size() << ") " << rang::fgB::yellow << type_node.string() << rang::style::reset << rang::style::bold << " differs from number of variables (" - << name_node.children.size() << ") " << rang::fgB::yellow << name_node.string() << rang::style::reset - << std::ends; + << name_node.children.size() << ") " << rang::fgB::yellow << name_node.string() << rang::style::reset; throw ParseError(message.str(), name_node.begin()); } @@ -55,7 +54,7 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo } else if (i_type_symbol->attributes().dataType() != ASTNodeDataType::type_name_id_t) { std::ostringstream os; os << "invalid type identifier, '" << type_name_id << "' was previously defined as a '" - << dataTypeName(i_type_symbol->attributes().dataType()) << "'" << std::ends; + << dataTypeName(i_type_symbol->attributes().dataType()) << '\''; throw ParseError(os.str(), std::vector{content_node->begin()}); } @@ -92,7 +91,7 @@ ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNo } else if (i_type_symbol->attributes().dataType() != ASTNodeDataType::type_name_id_t) { std::ostringstream os; os << "invalid type identifier, '" << type_name_id << "' was previously defined as a '" - << dataTypeName(i_type_symbol->attributes().dataType()) << "'" << std::ends; + << dataTypeName(i_type_symbol->attributes().dataType()) << '\''; throw ParseError(os.str(), std::vector{type_node.begin()}); } @@ -199,7 +198,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const message << "note: number of product spaces (" << nb_parameter_domains << ") " << rang::fgB::yellow << parameters_domain_node.string() << rang::style::reset << rang::style::bold << " differs from number of variables (" << nb_parameter_names << ") " << rang::fgB::yellow - << parameters_name_node.string() << rang::style::reset << std::ends; + << parameters_name_node.string() << rang::style::reset; throw ParseError(message.str(), parameters_domain_node.begin()); } @@ -247,8 +246,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const if (image_type.dimension() != nb_image_expressions) { std::ostringstream message; message << "expecting " << image_type.dimension() << " scalar expressions or an " - << dataTypeName(image_type) << ", found " << nb_image_expressions << " scalar expressions" - << std::ends; + << dataTypeName(image_type) << ", found " << nb_image_expressions << " scalar expressions"; throw ParseError(message.str(), image_domain_node.begin()); } } else { @@ -256,7 +254,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const message << "number of image spaces (" << nb_image_domains << ") " << rang::fgB::yellow << image_domain_node.string() << rang::style::reset << rang::style::bold << " differs from number of expressions (" << nb_image_expressions << ") " << rang::fgB::yellow - << image_expression_node.string() << rang::style::reset << std::ends; + << image_expression_node.string() << rang::style::reset; throw ParseError(message.str(), image_domain_node.begin()); } } @@ -396,7 +394,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const std::ostringstream message; message << "undefined binary operator\n" << "note: incompatible operand types " << n.children[0]->string() << " (" << dataTypeName(type_0) - << ") and " << n.children[1]->string() << " (" << dataTypeName(type_1) << ')' << std::ends; + << ") and " << n.children[1]->string() << " (" << dataTypeName(type_1) << ')'; throw ParseError(message.str(), n.begin()); } } else if (n.is_type<language::function_evaluation>()) { @@ -429,7 +427,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const std::ostringstream message; message << "invalid function call\n" << "note: '" << n.children[0]->string() << "' (type: " << dataTypeName(n.children[0]->m_data_type) - << ") is not a function!" << std::ends; + << ") is not a function!"; throw ParseError(message.str(), n.begin()); } } else if (n.is_type<language::subscript_expression>()) { @@ -442,7 +440,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const std::ostringstream message; message << "invalid types '" << rang::fgB::yellow << dataTypeName(array_expression.m_data_type) << rang::style::reset << '[' << dataTypeName(index_expression.m_data_type) << ']' - << "' for array subscript" << std::ends; + << "' for array subscript"; throw ParseError(message.str(), n.begin()); } else { diff --git a/src/language/ast/ASTSymbolInitializationChecker.cpp b/src/language/ast/ASTSymbolInitializationChecker.cpp index 0e4d441fe590fb16534987bc1683ee2aadf0e98e..c37d4ba6bbe45563a71c876c5d1b70e992762729 100644 --- a/src/language/ast/ASTSymbolInitializationChecker.cpp +++ b/src/language/ast/ASTSymbolInitializationChecker.cpp @@ -22,7 +22,7 @@ ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node) Assert(def_name_node.is_type<language::name>()); if (decl_name_node.string() != def_name_node.string()) { std::ostringstream os; - os << "invalid identifier, expecting '" << decl_name_node.string() << "'" << std::ends; + os << "invalid identifier, expecting '" << decl_name_node.string() << '\''; throw ParseError(os.str(), std::vector{def_name_node.begin()}); } }; @@ -45,7 +45,7 @@ ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node) if (decl_name_list_node.children.size() != def_name_list_node.children.size()) { std::ostringstream os; os << "invalid number of definition identifiers, expecting " << decl_name_list_node.children.size() - << " found " << def_name_list_node.children.size() << std::ends; + << " found " << def_name_list_node.children.size(); throw ParseError(os.str(), std::vector{def_name_list_node.begin()}); } diff --git a/src/language/modules/CMakeLists.txt b/src/language/modules/CMakeLists.txt index 0a996fd6764b4d2eed57c02e8682283f1e640901..cd4c99bd8fb9d8e354706020a4077bf0c8234057 100644 --- a/src/language/modules/CMakeLists.txt +++ b/src/language/modules/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(PugsLanguageModules MeshModule.cpp ModuleRepository.cpp SchemeModule.cpp + UtilsModule.cpp VTKModule.cpp ) diff --git a/src/language/modules/LinearSolverModule.cpp b/src/language/modules/LinearSolverModule.cpp index 9e626ba2b0e4707df0495de2057a00d81ea4b118..a5bb2cf90058b9232bd84e2f2bbdd71eb02ef3c7 100644 --- a/src/language/modules/LinearSolverModule.cpp +++ b/src/language/modules/LinearSolverModule.cpp @@ -57,29 +57,36 @@ LinearSolverModule::LinearSolverModule() )); - this->_addBuiltinFunction("printLSOptions", std::make_shared<BuiltinFunctionEmbedder<void()>>( + this->_addBuiltinFunction("getLSOptions", std::make_shared<BuiltinFunctionEmbedder<std::string()>>( + + []() -> std::string { + std::ostringstream os; + os << rang::fgB::yellow << "Linear solver options" << rang::style::reset + << '\n'; + os << LinearSolverOptions::default_options; + return os.str(); + } + + )); + + this->_addBuiltinFunction("getLSAvailable", std::make_shared<BuiltinFunctionEmbedder<std::string()>>( - []() -> void { - std::cout << rang::fgB::yellow << "Linear solver options" - << rang::style::reset << '\n'; - std::cout << LinearSolverOptions::default_options; + []() -> std::string { + std::ostringstream os; + + os << rang::fgB::yellow << "Available linear solver options" + << rang::style::reset << '\n'; + os << rang::fgB::blue << " libraries" << rang::style::reset << '\n'; + + printLSEnumListNames<LSLibrary>(os); + os << rang::fgB::blue << " methods" << rang::style::reset << '\n'; + printLSEnumListNames<LSMethod>(os); + os << rang::fgB::blue << " preconditioners" << rang::style::reset + << '\n'; + printLSEnumListNames<LSPrecond>(os); + + return os.str(); } )); - - this->_addBuiltinFunction("printLSAvailable", - std::make_shared<BuiltinFunctionEmbedder<void()>>( - - []() -> void { - std::cout << rang::fgB::yellow << "Available linear solver options" - << rang::style::reset << '\n'; - std::cout << rang::fgB::blue << " libraries" << rang::style::reset << '\n'; - printLSEnumListNames<LSLibrary>(std::cout); - std::cout << rang::fgB::blue << " methods" << rang::style::reset << '\n'; - printLSEnumListNames<LSMethod>(std::cout); - std::cout << rang::fgB::blue << " preconditioners" << rang::style::reset << '\n'; - printLSEnumListNames<LSPrecond>(std::cout); - } - - )); } diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp index df403fa87f0c0d39778414a92ec7aa991b3d8d5b..83d44b23ee90423f495144216f5244a9b40db482 100644 --- a/src/language/modules/ModuleRepository.cpp +++ b/src/language/modules/ModuleRepository.cpp @@ -5,6 +5,7 @@ #include <language/modules/MathModule.hpp> #include <language/modules/MeshModule.hpp> #include <language/modules/SchemeModule.hpp> +#include <language/modules/UtilsModule.hpp> #include <language/modules/VTKModule.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> #include <language/utils/ParseError.hpp> @@ -20,11 +21,12 @@ ModuleRepository::_subscribe(std::unique_ptr<IModule> m) ModuleRepository::ModuleRepository() { + this->_subscribe(std::make_unique<LinearSolverModule>()); this->_subscribe(std::make_unique<MathModule>()); this->_subscribe(std::make_unique<MeshModule>()); - this->_subscribe(std::make_unique<VTKModule>()); this->_subscribe(std::make_unique<SchemeModule>()); - this->_subscribe(std::make_unique<LinearSolverModule>()); + this->_subscribe(std::make_unique<UtilsModule>()); + this->_subscribe(std::make_unique<VTKModule>()); } template <typename NameEmbedderMapT, typename EmbedderTableT> diff --git a/src/language/modules/UtilsModule.cpp b/src/language/modules/UtilsModule.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c688e20768b5499549f88334deab4f2ac85a7a9 --- /dev/null +++ b/src/language/modules/UtilsModule.cpp @@ -0,0 +1,84 @@ +#include <language/modules/UtilsModule.hpp> + +#include <language/utils/ASTDotPrinter.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <language/utils/BuiltinFunctionEmbedder.hpp> +#include <language/utils/SymbolTable.hpp> +#include <utils/PugsUtils.hpp> + +extern const std::unique_ptr<ASTNode>* p_root_node; + +UtilsModule::UtilsModule() +{ + this->_addBuiltinFunction("getPugsVersion", std::make_shared<BuiltinFunctionEmbedder<std::string(void)>>( + + []() -> std::string { return pugsVersion(); } + + )); + + this->_addBuiltinFunction("getPugsBuildInfo", std::make_shared<BuiltinFunctionEmbedder<std::string(void)>>( + + []() -> std::string { return pugsBuildInfo(); } + + )); + + this->_addBuiltinFunction("getAST", std::make_shared<BuiltinFunctionEmbedder<std::string(void)>>( + + []() -> std::string { + Assert(p_root_node != nullptr, "unable to find AST's root node"); + + const auto& root_node = *p_root_node; + std::ostringstream os; + os << ASTPrinter{*root_node}; + + return os.str(); + } + + )); + + this->_addBuiltinFunction("saveASTDot", std::make_shared<BuiltinFunctionEmbedder<void(const std::string&)>>( + + [](const std::string& dot_filename) -> void { + Assert(p_root_node != nullptr, "unable to find AST's root node"); + + const auto& root_node = *p_root_node; + + std::ofstream fout(dot_filename); + + if (not fout) { + std::ostringstream os; + os << "could not create file '" << dot_filename << "'\n"; + throw NormalError(os.str()); + } + + ASTDotPrinter dot_printer{*root_node}; + fout << dot_printer; + + if (not fout) { + std::ostringstream os; + os << "could not write AST to '" << dot_filename << "'\n"; + throw NormalError(os.str()); + } + } + + )); + + this->_addBuiltinFunction("getFunctionAST", + std::make_shared<BuiltinFunctionEmbedder<std::string(const FunctionSymbolId&)>>( + + [](const FunctionSymbolId& function_symbol_id) -> std::string { + auto& function_table = function_symbol_id.symbolTable().functionTable(); + + const auto& function_descriptor = function_table[function_symbol_id.id()]; + + std::ostringstream os; + os << function_descriptor.name() << ": domain mapping\n"; + os << ASTPrinter(function_descriptor.domainMappingNode()); + os << function_descriptor.name() << ": definition\n"; + os << ASTPrinter(function_descriptor.definitionNode()); + + return os.str(); + } + + )); +} diff --git a/src/language/modules/UtilsModule.hpp b/src/language/modules/UtilsModule.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f7580a0422d3d8dabbd8c931b99dbfc7601f84da --- /dev/null +++ b/src/language/modules/UtilsModule.hpp @@ -0,0 +1,19 @@ +#ifndef UTILS_MODULE_HPP +#define UTILS_MODULE_HPP + +#include <language/modules/BuiltinModule.hpp> + +class UtilsModule : public BuiltinModule +{ + public: + std::string_view + name() const final + { + return "utils"; + } + + UtilsModule(); + ~UtilsModule() = default; +}; + +#endif // UTILS_MODULE_HPP diff --git a/src/language/node_processor/AffectationProcessor.hpp b/src/language/node_processor/AffectationProcessor.hpp index f3f8af44f38477007a0f85b2a3ee00738a5b82c9..6cdb19dfdd36359f6cd798149c7f2908770aadd0 100644 --- a/src/language/node_processor/AffectationProcessor.hpp +++ b/src/language/node_processor/AffectationProcessor.hpp @@ -105,7 +105,7 @@ class AffectationExecutor final : public IAffectationExecutor m_lhs = std::to_string(std::get<DataT>(rhs)); } else { std::ostringstream os; - os << std::get<DataT>(rhs) << std::ends; + os << std::get<DataT>(rhs); m_lhs = os.str(); } } else { @@ -115,7 +115,7 @@ class AffectationExecutor final : public IAffectationExecutor m_lhs += std::to_string(std::get<DataT>(rhs)); } else { std::ostringstream os; - os << std::get<DataT>(rhs) << std::ends; + os << std::get<DataT>(rhs); m_lhs += os.str(); } } @@ -418,7 +418,7 @@ class AffectationToTupleProcessor final : public INodeProcessor *m_lhs = std::vector{std::move(std::to_string(v))}; } else { std::ostringstream os; - os << v << std::ends; + os << v; *m_lhs = std::vector<std::string>{os.str()}; } } else if constexpr (std::is_same_v<ValueT, TinyVector<1>> and std::is_arithmetic_v<T>) { @@ -475,7 +475,7 @@ class AffectationToTupleFromListProcessor final : public INodeProcessor tuple_value[i] = std::to_string(child_value); } else { std::ostringstream os; - os << child_value << std::ends; + os << child_value; tuple_value[i] = os.str(); } } else if constexpr (is_tiny_vector_v<ValueT>) { @@ -544,7 +544,7 @@ class AffectationToTupleFromListProcessor final : public INodeProcessor } else { for (size_t i = 0; i < values.size(); ++i) { std::ostringstream sout; - sout << values[i] << std::ends; + sout << values[i]; v[i] = sout.str(); } } diff --git a/src/language/node_processor/FunctionArgumentConverter.hpp b/src/language/node_processor/FunctionArgumentConverter.hpp index 9e7eec757fb2c396125d6d299f5a7529ca420009..e226e5336f4add578c5df2abe102121d067f6402 100644 --- a/src/language/node_processor/FunctionArgumentConverter.hpp +++ b/src/language/node_processor/FunctionArgumentConverter.hpp @@ -40,7 +40,7 @@ class FunctionArgumentToStringConverter final : public IFunctionArgumentConverte exec_policy.currentContext()[m_argument_id] = v; } else { std::ostringstream sout; - sout << value << std::ends; + sout << value; exec_policy.currentContext()[m_argument_id] = sout.str(); } }, diff --git a/src/language/utils/PugsFunctionAdapter.hpp b/src/language/utils/PugsFunctionAdapter.hpp index 4890664880c6e9bd3ce018f03db67c97b0587020..17d97f509c2466b97d3a8ee46cc34ca8ee6b06fe 100644 --- a/src/language/utils/PugsFunctionAdapter.hpp +++ b/src/language/utils/PugsFunctionAdapter.hpp @@ -110,7 +110,7 @@ class PugsFunctionAdapter<OutputType(InputType...)> << _getInputDataTypeName() << " -> " << dataTypeName(ast_node_data_type_from<OutputType>) << rang::style::reset << '\n' << "note: provided function " << rang::fgB::magenta << function.name() << ": " - << function.domainMappingNode().string() << rang::style::reset << std::ends; + << function.domainMappingNode().string() << rang::style::reset; throw NormalError(error_message.str()); } } diff --git a/src/utils/BuildInfo.cpp b/src/utils/BuildInfo.cpp index 7162aeccf69a7b5e6420e23ae7dca6cea6ced9b1..38d46007ef6cfcf470051e8546714db7041a7852 100644 --- a/src/utils/BuildInfo.cpp +++ b/src/utils/BuildInfo.cpp @@ -22,7 +22,7 @@ std::string BuildInfo::compiler() { std::stringstream compiler_info; - compiler_info << PUGS_BUILD_COMPILER << " (" << PUGS_BUILD_COMPILER_VERSION << ")" << std::ends; + compiler_info << PUGS_BUILD_COMPILER << " (" << PUGS_BUILD_COMPILER_VERSION << ")"; return compiler_info.str(); } diff --git a/src/utils/ConsoleManager.cpp b/src/utils/ConsoleManager.cpp index 666caa1b17c5bb397e592132febeabab4846732f..f55004ac7dd2181256404b486ad1eaa0c05abd85 100644 --- a/src/utils/ConsoleManager.cpp +++ b/src/utils/ConsoleManager.cpp @@ -11,12 +11,9 @@ ConsoleManager::isTerminal(std::ostream& os) void ConsoleManager::init(bool colorize) { - std::cout << "Console management: color "; if (colorize) { rang::setControlMode(rang::control::Force); - std::cout << rang::style::bold << rang::fgB::green << "enabled" << rang::fg::reset << rang::style::reset << '\n'; } else { rang::setControlMode(rang::control::Off); - std::cout << "disabled\n"; } } diff --git a/src/utils/FPEManager.cpp b/src/utils/FPEManager.cpp index 7430b5bbcc8c17d31b3a9508a170bfb3ed525632..89a75d7c77e8649b6710e32f6d89ed5e9f85c1c0 100644 --- a/src/utils/FPEManager.cpp +++ b/src/utils/FPEManager.cpp @@ -62,16 +62,12 @@ fedisableexcept(unsigned int excepts) void FPEManager::enable() { - std::cout << "FE management: " << rang::style::bold << rang::fgB::green << "enabled" << rang::fg::reset - << rang::style::reset << '\n'; ::feenableexcept(MANAGED_FPE); } void FPEManager::disable() { - std::cout << "FE management: " << rang::style::bold << rang::fgB::red << "disabled" << rang::fg::reset - << rang::style::reset << '\n'; ::fedisableexcept(MANAGED_FPE); } @@ -79,15 +75,11 @@ FPEManager::disable() void FPEManager::enable() -{ - std::cout << "FE management: enabled " << rang::fg::red << "[not supported]" << rang::fg::reset << '\n'; -} +{} void FPEManager::disable() -{ - std::cout << "FE management: disable " << rang::fg::red << "[not supported]" << rang::fg::reset << '\n'; -} +{} #endif // PUGS_HAS_FENV_H diff --git a/src/utils/PugsUtils.cpp b/src/utils/PugsUtils.cpp index d54bd333f93107a1e093038764ebe7f088ace9df..ad9e12e7ec4cdd01305cf8701c327894c7942304 100644 --- a/src/utils/PugsUtils.cpp +++ b/src/utils/PugsUtils.cpp @@ -1,15 +1,13 @@ #include <utils/PugsUtils.hpp> +#include <algebra/PETScWrapper.hpp> #include <utils/BuildInfo.hpp> -#include <utils/RevisionInfo.hpp> - -#include <utils/Messenger.hpp> - #include <utils/ConsoleManager.hpp> #include <utils/FPEManager.hpp> +#include <utils/Messenger.hpp> +#include <utils/RevisionInfo.hpp> #include <utils/SignalManager.hpp> - -#include <algebra/PETScWrapper.hpp> +#include <utils/pugs_build_info.hpp> #include <rang.hpp> @@ -19,43 +17,79 @@ #include <iostream> -// LCOV_EXCL_START - -// This function cannot be unit-tested: run once when pugs starts - std::string -initialize(int& argc, char* argv[]) +pugsVersion() { - parallel::Messenger::create(argc, argv); + std::stringstream os; - std::cout << "Pugs version: " << rang::style::bold << RevisionInfo::version() << rang::style::reset << '\n'; + os << "pugs version: " << rang::style::bold << RevisionInfo::version() << rang::style::reset << '\n'; - std::cout << "-------------------- " << rang::fg::green << "git info" << rang::fg::reset - << " -------------------------" << '\n'; - std::cout << "tag: " << rang::style::bold << RevisionInfo::gitTag() << rang::style::reset << '\n'; - std::cout << "HEAD: " << rang::style::bold << RevisionInfo::gitHead() << rang::style::reset << '\n'; - std::cout << "hash: " << rang::style::bold << RevisionInfo::gitHash() << rang::style::reset << " ("; + os << "-------------------- " << rang::fg::green << "git info" << rang::fg::reset << " -------------------------" + << '\n'; + os << "tag: " << rang::style::bold << RevisionInfo::gitTag() << rang::style::reset << '\n'; + os << "HEAD: " << rang::style::bold << RevisionInfo::gitHead() << rang::style::reset << '\n'; + os << "hash: " << rang::style::bold << RevisionInfo::gitHash() << rang::style::reset << " ("; + // LCOV_EXCL_START Cannot cover both situations at same time if (RevisionInfo::gitIsClean()) { - std::cout << rang::fgB::green << "clean" << rang::fg::reset; + os << rang::fgB::green << "clean" << rang::fg::reset; } else { - std::cout << rang::fgB::red << "dirty" << rang::fg::reset; + os << rang::fgB::red << "dirty" << rang::fg::reset; } - std::cout << ")\n"; - std::cout << "-------------------- " << rang::fg::green << "build info" << rang::fg::reset - << " -----------------------" << '\n'; - std::cout << "type: " << rang::style::bold << BuildInfo::type() << rang::style::reset << '\n'; - std::cout << "compiler: " << rang::style::bold << BuildInfo::compiler() << rang::style::reset << '\n'; - std::cout << "kokkos: " << rang::style::bold << BuildInfo::kokkosDevices() << rang::style::reset << '\n'; - std::cout << "MPI: " << rang::style::bold << BuildInfo::mpiLibrary() << rang::style::reset << '\n'; - std::cout << "PETSc: " << rang::style::bold << BuildInfo::petscLibrary() << rang::style::reset << '\n'; - std::cout << "-------------------------------------------------------\n"; + // LCOV_EXCL_STOP + os << ")\n"; + os << "-------------------------------------------------------"; + + return os.str(); +} + +std::string +pugsBuildInfo() +{ + std::ostringstream os; + + os << "-------------------- " << rang::fg::green << "build info" << rang::fg::reset << " -----------------------" + << '\n'; + os << "type: " << rang::style::bold << BuildInfo::type() << rang::style::reset << '\n'; + os << "compiler: " << rang::style::bold << BuildInfo::compiler() << rang::style::reset << '\n'; + os << "kokkos: " << rang::style::bold << BuildInfo::kokkosDevices() << rang::style::reset << '\n'; + os << "MPI: " << rang::style::bold << BuildInfo::mpiLibrary() << rang::style::reset << '\n'; + os << "PETSc: " << rang::style::bold << BuildInfo::petscLibrary() << rang::style::reset << '\n'; + os << "-------------------------------------------------------"; + + return os.str(); +} + +void +setDefaultOMPEnvironment() +{ + if constexpr (std::string_view{PUGS_BUILD_KOKKOS_DEVICES} == std::string_view{"OpenMP"}) { + setenv("OMP_PROC_BIND", "spread", 0); + setenv("OMP_PLACES", "threads", 0); + } +} + +// LCOV_EXCL_START + +// This function cannot be unit-tested: run once when pugs starts + +std::string +initialize(int& argc, char* argv[]) +{ + parallel::Messenger::create(argc, argv); std::string filename; { - CLI::App app{"Pugs help"}; + CLI::App app{"pugs help"}; + + app.add_option("filename", filename, "pugs script file")->check(CLI::ExistingFile)->required(); - app.add_option("filename", filename, "pugs script file")->required()->check(CLI::ExistingFile); + app.set_version_flag("-v,--version", []() { + ConsoleManager::init(true); + std::stringstream os; + os << pugsVersion() << '\n' << pugsBuildInfo(); + return os.str(); + }); int threads = -1; app.add_option("--threads", threads, "Number of Kokkos threads") @@ -90,11 +124,17 @@ initialize(int& argc, char* argv[]) PETScWrapper::initialize(argc, argv); + setDefaultOMPEnvironment(); Kokkos::initialize(argc, argv); - std::cout << "-------------------- " << rang::fg::green << "exec info" << rang::fg::reset - << " ------------------------" << '\n'; + std::cout << "----------------- " << rang::fg::green << "pugs exec info" << rang::fg::reset + << " ----------------------" << '\n'; std::cout << rang::style::bold; +#ifdef PUGS_HAS_MPI + std::cout << "MPI number of ranks " << parallel::size() << '\n'; +#else // PUGS_HAS_MPI + std::cout << "Sequential build\n"; +#endif // PUGS_HAS_MPI Kokkos::DefaultExecutionSpace::print_configuration(std::cout); std::cout << rang::style::reset; std::cout << "-------------------------------------------------------\n"; diff --git a/src/utils/PugsUtils.hpp b/src/utils/PugsUtils.hpp index ef4eeb72c340b8a6ca654d001c32390973b63c55..7429a75b3be20ec3d62028cc9180a2017f7b4f15 100644 --- a/src/utils/PugsUtils.hpp +++ b/src/utils/PugsUtils.hpp @@ -21,6 +21,12 @@ parallel_reduce(size_t size, const ArrayType& array, ReturnType& value, const st Kokkos::parallel_reduce(label, size, array, value); } +void setDefaultOMPEnvironment(); + +std::string pugsBuildInfo(); + +std::string pugsVersion(); + std::string initialize(int& argc, char* argv[]); void finalize(); diff --git a/src/utils/SignalManager.cpp b/src/utils/SignalManager.cpp index ab08424fa2731bc62d84b461cea850878da9514b..399f3164c2046f4ec25a009160a6f01b11da85ef 100644 --- a/src/utils/SignalManager.cpp +++ b/src/utils/SignalManager.cpp @@ -114,11 +114,5 @@ SignalManager::init(bool enable) std::signal(SIGINT, SignalManager::handler); std::signal(SIGABRT, SignalManager::handler); std::signal(SIGPIPE, SignalManager::handler); - - std::cout << "Signal management: " << rang::style::bold << rang::fgB::green << "enabled" << rang::fg::reset - << rang::style::reset << '\n'; - } else { - std::cout << "Signal management: " << rang::style::bold << rang::fgB::red << "disabled" << rang::fg::reset - << rang::style::reset << '\n'; } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index aaf4bfbad904a6466b4442b0d99f35a41840ddb3..0502c414a76e536dc6d2a0d1d49bc260a930b84d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -80,8 +80,9 @@ add_executable (unit_tests test_NameProcessor.cpp test_OStreamProcessor.cpp test_ParseError.cpp - test_PugsFunctionAdapter.cpp test_PugsAssert.cpp + test_PugsFunctionAdapter.cpp + test_PugsUtils.cpp test_RevisionInfo.cpp test_SparseMatrixDescriptor.cpp test_SymbolTable.cpp @@ -104,11 +105,11 @@ add_library(test_Pugs_MeshDataBase target_link_libraries (unit_tests test_Pugs_MeshDataBase - PugsLanguage PugsLanguageAST PugsLanguageModules PugsLanguageAlgorithms PugsLanguageUtils + PugsLanguage PugsMesh PugsAlgebra PugsUtils diff --git a/tests/test_AffectationToStringProcessor.cpp b/tests/test_AffectationToStringProcessor.cpp index 4053e023187944c87333f0dd605404104d039aa2..c432cdd00ddcd41213720feb9217ad4f20dfac5e 100644 --- a/tests/test_AffectationToStringProcessor.cpp +++ b/tests/test_AffectationToStringProcessor.cpp @@ -55,17 +55,17 @@ TEST_CASE("ASTAffectationToStringProcessor", "[language]") CHECK_AFFECTATION_RESULT(R"(let s : string; s = 2.3;)", "s", std::to_string(2.3)); { std::ostringstream os; - os << TinyVector<1>{13} << std::ends; + os << TinyVector<1>{13}; CHECK_AFFECTATION_RESULT(R"(let x : R^1, x = 13; let s : string; s = x;)", "s", os.str()); } { std::ostringstream os; - os << TinyVector<2>{2, 3} << std::ends; + os << TinyVector<2>{2, 3}; CHECK_AFFECTATION_RESULT(R"(let x : R^2, x = (2,3); let s : string; s = x;)", "s", os.str()); } { std::ostringstream os; - os << TinyVector<3>{1, 2, 3} << std::ends; + os << TinyVector<3>{1, 2, 3}; CHECK_AFFECTATION_RESULT(R"(let x : R^3, x = (1,2,3); let s : string; s = x;)", "s", os.str()); } } @@ -82,17 +82,17 @@ TEST_CASE("ASTAffectationToStringProcessor", "[language]") (std::string("foo") + std::to_string(2.3))); { std::ostringstream os; - os << "foo" << TinyVector<1>{13} << std::ends; + os << "foo" << TinyVector<1>{13}; CHECK_AFFECTATION_RESULT(R"(let x : R^1, x = 13; let s : string, s="foo"; s += x;)", "s", os.str()); } { std::ostringstream os; - os << "foo" << TinyVector<2>{2, 3} << std::ends; + os << "foo" << TinyVector<2>{2, 3}; CHECK_AFFECTATION_RESULT(R"(let x : R^2, x = (2,3); let s : string, s="foo"; s += x;)", "s", os.str()); } { std::ostringstream os; - os << "foo" << TinyVector<3>{1, 2, 3} << std::ends; + os << "foo" << TinyVector<3>{1, 2, 3}; CHECK_AFFECTATION_RESULT(R"(let x : R^3, x = (1,2,3); let s : string, s="foo"; s += x;)", "s", os.str()); } } diff --git a/tests/test_AffectationToTupleProcessor.cpp b/tests/test_AffectationToTupleProcessor.cpp index 3720bc856b30fa39468e90a7a56cc0ce2d01058d..963e931bb0bba74e10063649896e0e11db109601 100644 --- a/tests/test_AffectationToTupleProcessor.cpp +++ b/tests/test_AffectationToTupleProcessor.cpp @@ -65,7 +65,7 @@ let s :(string); s = 2.; const std::string x_string = []() -> std::string { std::ostringstream os; - os << TinyVector<3, double>{1, 2, 3} << std::ends; + os << TinyVector<3, double>{1, 2, 3}; return os.str(); }(); @@ -101,7 +101,7 @@ let s :(string); s = (2.,3,"foo"); const std::string x_string = []() -> std::string { std::ostringstream os; - os << TinyVector<2, double>{1, 2} << std::ends; + os << TinyVector<2, double>{1, 2}; return os.str(); }(); @@ -143,7 +143,7 @@ let t :(R^1); t = (x,2); { const std::string x_string = []() -> std::string { std::ostringstream os; - os << TinyVector<3, double>{1, 2, 3} << std::ends; + os << TinyVector<3, double>{1, 2, 3}; return os.str(); }(); diff --git a/tests/test_BuildInfo.cpp b/tests/test_BuildInfo.cpp index 335cc74e420122f61a59067c0df89e416e55c2ba..b63d0eb9b22beab6d810b806284d6fc85f3c0df9 100644 --- a/tests/test_BuildInfo.cpp +++ b/tests/test_BuildInfo.cpp @@ -26,7 +26,7 @@ TEST_CASE("BuildInfo", "[utils]") SECTION("compiler") { std::stringstream compiler_info; - compiler_info << PUGS_BUILD_COMPILER << " (" << PUGS_BUILD_COMPILER_VERSION << ")" << std::ends; + compiler_info << PUGS_BUILD_COMPILER << " (" << PUGS_BUILD_COMPILER_VERSION << ")"; REQUIRE(BuildInfo::compiler() == compiler_info.str()); } diff --git a/tests/test_FunctionArgumentConverter.cpp b/tests/test_FunctionArgumentConverter.cpp index e3d2ee0939c306fb971274c782268b161125bee6..dfa637bf735c66e02dab8c4345ccbf74e7a1e069 100644 --- a/tests/test_FunctionArgumentConverter.cpp +++ b/tests/test_FunctionArgumentConverter.cpp @@ -20,7 +20,7 @@ TEST_CASE("FunctionArgumentConverter", "[language]") FunctionArgumentToStringConverter converter1{1}; converter1.convert(execution_policy, X); std::ostringstream os_X; - os_X << X << std::ends; + os_X << X; const double x = 3.2; FunctionArgumentToStringConverter converter2{2}; diff --git a/tests/test_ListAffectationProcessor.cpp b/tests/test_ListAffectationProcessor.cpp index e0f17e7f593f98a15457686e9e38b0bccfa34938..e2a0919952220b6ba6a2c723a31604674254357d 100644 --- a/tests/test_ListAffectationProcessor.cpp +++ b/tests/test_ListAffectationProcessor.cpp @@ -89,19 +89,19 @@ TEST_CASE("ListAffectationProcessor", "[language]") std::to_string(double{3})); { std::ostringstream os; - os << TinyVector<1>{7} << std::ends; + os << TinyVector<1>{7}; CHECK_AFFECTATION_RESULT(R"(let v:R^1, v = 7; let (x,u,s):R*R^2*string, (x,u,s) = (1.2, (2,3), v);)", "s", os.str()); } { std::ostringstream os; - os << TinyVector<2>{6, 3} << std::ends; + os << TinyVector<2>{6, 3}; CHECK_AFFECTATION_RESULT(R"(let v: R^2, v = (6,3); let (x,u,s):R*R^2*string, (x,u,s) = (1.2, (2,3), v);)", "s", os.str()); } { std::ostringstream os; - os << TinyVector<3>{1, 2, 3} << std::ends; + os << TinyVector<3>{1, 2, 3}; CHECK_AFFECTATION_RESULT(R"(let v:R^3, v = (1,2,3); let (x,u,s):R*R^2*string, (x,u,s) = (1.2, (2,3), v);)", "s", os.str()); } diff --git a/tests/test_PugsUtils.cpp b/tests/test_PugsUtils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b966ae8f0c0bab490c9f7e3e4441ffdd329aeec1 --- /dev/null +++ b/tests/test_PugsUtils.cpp @@ -0,0 +1,110 @@ +#include <catch2/catch.hpp> + +#include <utils/BuildInfo.hpp> +#include <utils/PugsUtils.hpp> +#include <utils/RevisionInfo.hpp> +#include <utils/pugs_build_info.hpp> + +#include <rang.hpp> + +#include <string> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("PugsUtils", "[utils]") +{ + SECTION("checking infos") + { + const std::string pugs_version = [] { + std::stringstream os; + + os << "pugs version: " << rang::style::bold << RevisionInfo::version() << rang::style::reset << '\n'; + + os << "-------------------- " << rang::fg::green << "git info" << rang::fg::reset << " -------------------------" + << '\n'; + os << "tag: " << rang::style::bold << RevisionInfo::gitTag() << rang::style::reset << '\n'; + os << "HEAD: " << rang::style::bold << RevisionInfo::gitHead() << rang::style::reset << '\n'; + os << "hash: " << rang::style::bold << RevisionInfo::gitHash() << rang::style::reset << " ("; + + if (RevisionInfo::gitIsClean()) { + os << rang::fgB::green << "clean" << rang::fg::reset; + } else { + os << rang::fgB::red << "dirty" << rang::fg::reset; + } + os << ")\n"; + os << "-------------------------------------------------------"; + + return os.str(); + }(); + + REQUIRE(pugsVersion() == pugs_version); + + const std::string build_info = [] { + std::ostringstream os; + + os << "-------------------- " << rang::fg::green << "build info" << rang::fg::reset << " -----------------------" + << '\n'; + os << "type: " << rang::style::bold << BuildInfo::type() << rang::style::reset << '\n'; + os << "compiler: " << rang::style::bold << BuildInfo::compiler() << rang::style::reset << '\n'; + os << "kokkos: " << rang::style::bold << BuildInfo::kokkosDevices() << rang::style::reset << '\n'; + os << "MPI: " << rang::style::bold << BuildInfo::mpiLibrary() << rang::style::reset << '\n'; + os << "PETSc: " << rang::style::bold << BuildInfo::petscLibrary() << rang::style::reset << '\n'; + os << "-------------------------------------------------------"; + + return os.str(); + }(); + + REQUIRE(pugsBuildInfo() == build_info); + } + + SECTION("checking OMP environment setting") + { + if constexpr (std::string_view{PUGS_BUILD_KOKKOS_DEVICES} == std::string_view{"OpenMP"}) { + const std::string saved_omp_proc_bind = []() { + char* value = getenv("OMP_PROC_BIND"); + if (value != nullptr) { + return std::string{value}; + } else { + return std::string{}; + } + }(); + + const std::string saved_omp_places = []() { + char* value = getenv("OMP_PLACES"); + if (value != nullptr) { + return std::string{value}; + } else { + return std::string{}; + } + }(); + + unsetenv("OMP_PROC_BIND"); + unsetenv("OMP_PLACES"); + + setDefaultOMPEnvironment(); + REQUIRE(std::string{getenv("OMP_PROC_BIND")} == std::string{"spread"}); + REQUIRE(std::string{getenv("OMP_PLACES")} == std::string{"threads"}); + + unsetenv("OMP_PROC_BIND"); + unsetenv("OMP_PLACES"); + + setenv("OMP_PROC_BIND", "foo", 1); + setenv("OMP_PLACES", "bar", 1); + + setDefaultOMPEnvironment(); + REQUIRE(std::string{getenv("OMP_PROC_BIND")} == std::string{"foo"}); + REQUIRE(std::string{getenv("OMP_PLACES")} == std::string{"bar"}); + + unsetenv("OMP_PROC_BIND"); + unsetenv("OMP_PLACES"); + + if (saved_omp_proc_bind.size() != 0) { + setenv("OMP_PROC_BIND", saved_omp_proc_bind.c_str(), 1); + } + + if (saved_omp_places.size() != 0) { + setenv("OMP_PLACES", saved_omp_places.c_str(), 1); + } + } + } +}