diff --git a/doc/userdoc.org b/doc/userdoc.org index b50768b072d372e1d462508343aaed9e2acff75b..eaac7da46edb913aff2df4d527d7c9ac20456cfe 100644 --- a/doc/userdoc.org +++ b/doc/userdoc.org @@ -2540,11 +2540,16 @@ to files for instance) as we will see below. **** ~core~ provided functions +***** ~exit: Z -> void~ + +This function interrupts the execution of the script. The integer (~Z~) +value is the code that is returned when ~pugs~ exits. + ***** ~getAvailableModules: void -> string~ This function that is used in the preamble of this section is a function that returns a ~string~ that contains the list of modules that -are available in the current version of pugs. +are available in the current version of ~pugs~. ***** ~getModuleInfo: string -> string~ diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp index fbf7b60a21d0ea6aed9e9609d2b4c733a56fbcbc..603367fd66889d62511950d2b42176ada090222b 100644 --- a/src/language/PugsParser.cpp +++ b/src/language/PugsParser.cpp @@ -17,9 +17,11 @@ #include <language/utils/ASTDotPrinter.hpp> #include <language/utils/ASTExecutionInfo.hpp> #include <language/utils/ASTPrinter.hpp> +#include <language/utils/Exit.hpp> #include <language/utils/OperatorRepository.hpp> #include <language/utils/SymbolTable.hpp> #include <utils/ConsoleManager.hpp> +#include <utils/ExecutionStatManager.hpp> #include <utils/PugsAssert.hpp> #include <utils/PugsUtils.hpp> #include <utils/SignalManager.hpp> @@ -89,8 +91,12 @@ parser(const std::string& filename) ASTExecutionInfo execution_info{*root_node, module_importer.moduleRepository()}; ExecutionPolicy exec_all; - root_node->execute(exec_all); - + try { + root_node->execute(exec_all); + } + catch (language::Exit& e) { + ExecutionStatManager::getInstance().setExitCode(e.code()); + } root_node->m_symbol_table->clearValues(); OperatorRepository::destroy(); diff --git a/src/language/modules/CoreModule.cpp b/src/language/modules/CoreModule.cpp index ff07fc9da15f52f67a03e632503c4d62bf9af439..e9be93f3c1cc96af47d7665317d5a364cd54f17e 100644 --- a/src/language/modules/CoreModule.cpp +++ b/src/language/modules/CoreModule.cpp @@ -19,6 +19,7 @@ #include <language/utils/BinaryOperatorRegisterForString.hpp> #include <language/utils/BinaryOperatorRegisterForZ.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> +#include <language/utils/Exit.hpp> #include <language/utils/IncDecOperatorRegisterForN.hpp> #include <language/utils/IncDecOperatorRegisterForZ.hpp> #include <language/utils/OFStream.hpp> @@ -95,6 +96,21 @@ CoreModule::CoreModule() : BuiltinModule(true) )); + this->_addBuiltinFunction("exit", std::function( + + [](const int64_t& exit_code) -> void { + const auto& location = ASTBacktrace::getInstance().sourceLocation(); + std::cout << "\n** " << rang::fgB::yellow << "exit" << rang::fg::reset + << " explicitly called with code " << rang::fgB::cyan << exit_code + << rang::fg::reset << "\n from " << rang::style::underline + << location.filename() << rang::style::reset << ':' + << rang::fgB::yellow << location.line() << rang::fg::reset << '\n'; + + throw language::Exit(exit_code); + } + + )); + this->_addNameValue("cout", ast_node_data_type_from<std::shared_ptr<const OStream>>, EmbeddedData{std::make_shared<DataHandler<const OStream>>(std::make_shared<OStream>(std::cout))}); diff --git a/src/language/utils/Exit.hpp b/src/language/utils/Exit.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ec24402e86c01494f1453b1d6dcbcd7d33300db4 --- /dev/null +++ b/src/language/utils/Exit.hpp @@ -0,0 +1,29 @@ +#ifndef EXIT_HPP +#define EXIT_HPP + +namespace language +{ + +class Exit +{ + private: + int m_code = 0; + + public: + int + code() const + { + return m_code; + } + + Exit(int code) : m_code{code} {} + + Exit(const Exit&) = default; + Exit(Exit&&) = default; + + ~Exit() = default; +}; + +} // namespace language + +#endif // EXIT_HPP diff --git a/src/main.cpp b/src/main.cpp index 7ee38e518aba13655318300e2ac53442ad4e8f49..7d0112c80715b3cd0b69ea91b874527134b6a2ed 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,7 +42,9 @@ main(int argc, char* argv[]) finalize(); ParallelChecker::destroy(); + + int return_code = ExecutionStatManager::getInstance().exitCode(); ExecutionStatManager::destroy(); - return 0; + return return_code; } diff --git a/src/utils/ExecutionStatManager.hpp b/src/utils/ExecutionStatManager.hpp index 6f7c333561147ab3fede6c534a9c2680a29bd4cd..3738492a1741c7ee7a4e4a45edf4139b579a022e 100644 --- a/src/utils/ExecutionStatManager.hpp +++ b/src/utils/ExecutionStatManager.hpp @@ -11,6 +11,7 @@ class ExecutionStatManager Timer m_elapse_time; bool m_do_print = true; + int m_exit_code = 0; std::string _prettyPrintTime(double seconds) const; @@ -38,6 +39,20 @@ class ExecutionStatManager m_do_print = do_print; } + PUGS_INLINE + int + exitCode() const + { + return m_exit_code; + } + + PUGS_INLINE + void + setExitCode(int exit_code) + { + m_exit_code = exit_code; + } + PUGS_INLINE static ExecutionStatManager& getInstance()