diff --git a/examples/quickstart/quickstart.cpp b/examples/quickstart/quickstart.cpp index 01b9f3c..0e2a60c 100644 --- a/examples/quickstart/quickstart.cpp +++ b/examples/quickstart/quickstart.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -6,11 +7,11 @@ namespace { auto run(std::string_view const text, bool verbose) -> bool { - auto kalcy = kalcy::Kalcy{}; - auto ast = std::string{}; try { - std::cout << kalcy.evaluate(text, &ast) << "\n"; - if (verbose) { std::cout << "expression\t: " << text << "\nAST\t\t: " << ast << "\n"; } + auto expr = kalcy::Parser{text}.parse(); + assert(expr != nullptr); + std::cout << kalcy::evaluate(*expr) << "\n"; + if (verbose) { std::cout << std::format("expression\t: {}\nAST\t\t: {}\n", text, kalcy::to_string(*expr)); } return true; } catch (kalcy::Error const& err) { std::cerr << err.what() << "\n"; diff --git a/kalcy/CMakeLists.txt b/kalcy/CMakeLists.txt index 85c0770..077bd2e 100644 --- a/kalcy/CMakeLists.txt +++ b/kalcy/CMakeLists.txt @@ -33,7 +33,6 @@ target_sources(${PROJECT_NAME} PRIVATE src/error.cpp src/eval.cpp src/expr.cpp - src/kalcy.cpp src/parser.cpp src/scanner.cpp ) diff --git a/kalcy/include/kalcy/env.hpp b/kalcy/include/kalcy/env.hpp index 625376f..ac32fed 100644 --- a/kalcy/include/kalcy/env.hpp +++ b/kalcy/include/kalcy/env.hpp @@ -21,6 +21,17 @@ class Env { /// struct Mismatch {}; + /// + /// \brief Get a default instance (singleton). + /// \returns const reference to a static default instance. + /// + static auto get_default() -> Env const&; + + /// + /// \brief Populate environment with builtins. + /// + explicit Env(); + /// /// \brief Define a function. /// diff --git a/kalcy/include/kalcy/eval.hpp b/kalcy/include/kalcy/eval.hpp index 0e102ad..7e17c99 100644 --- a/kalcy/include/kalcy/eval.hpp +++ b/kalcy/include/kalcy/eval.hpp @@ -20,4 +20,6 @@ struct Eval { /// [[nodiscard]] auto operator()(Expr const& expr) const noexcept(false) -> double; }; + +inline auto evaluate(Expr const& expr, Env const& env = Env::get_default()) { return Eval{env}(expr); } } // namespace kalcy diff --git a/kalcy/include/kalcy/kalcy.hpp b/kalcy/include/kalcy/kalcy.hpp index 50ca304..16fed93 100644 --- a/kalcy/include/kalcy/kalcy.hpp +++ b/kalcy/include/kalcy/kalcy.hpp @@ -2,31 +2,5 @@ #include #include #include - -namespace kalcy { -/// -/// \brief Expression evaluator with an owned environment. -/// -class Kalcy { - public: - /// - /// \brief Populate environment with builtins. - /// - explicit Kalcy(); - - /// - /// \brief Evaluate an expression. - /// \param expression expression to evaluate. - /// \param out_ast (optional) out parameter to build stringified AST to. - /// \throws sub-type of Error. - /// - [[nodiscard]] auto evaluate(std::string_view expression, std::string* out_ast = {}) const noexcept(false) -> double; - - /// - /// \brief Execution environment. - /// - /// The environment is read-only during evaluation of expressions. - /// - Env environment{}; -}; -} // namespace kalcy +#include +#include diff --git a/kalcy/src/env.cpp b/kalcy/src/env.cpp index 18d28e2..94ce5a0 100644 --- a/kalcy/src/env.cpp +++ b/kalcy/src/env.cpp @@ -1,8 +1,23 @@ #include #include #include +#include +#include namespace kalcy { +auto Env::get_default() -> Env const& { + static auto const ret{Env{}}; + return ret; +} + +Env::Env() { + define("pi", std::numbers::pi_v); + define("sqrt", [](std::span args) { + if (args.size() != 1) { throw Mismatch{}; } + return std::sqrt(args.front()); + }); +} + void Env::define(std::string_view name, Func func) { if (name.empty() || !func) { return; } m_table.insert_or_assign(name, std::move(func)); diff --git a/kalcy/src/error.cpp b/kalcy/src/error.cpp index 1942fbb..41df862 100644 --- a/kalcy/src/error.cpp +++ b/kalcy/src/error.cpp @@ -19,7 +19,7 @@ ParseError::ParseError(Token const token, Token::Type const expected) UndefinedSymbol::UndefinedSymbol(Token const token) : Error(token, std::format("undefined symbol: '{}'", token.lexeme)) {} ArgsMismatch::ArgsMismatch(Token const token, std::size_t argument_count) - : Error(token, std::format("{} does not take {} arguments", token.lexeme, argument_count)), argument_count(argument_count) {} + : Error(token, std::format("{} does not take {} argument(s)", token.lexeme, argument_count)), argument_count(argument_count) {} InvalidOperaor::InvalidOperaor(Token const token) : Error(token, std::format("invalid operator: '{}'", token.lexeme)) {} } // namespace kalcy diff --git a/kalcy/src/kalcy.cpp b/kalcy/src/kalcy.cpp deleted file mode 100644 index 7ff323c..0000000 --- a/kalcy/src/kalcy.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include -#include -#include -#include - -namespace kalcy { -Kalcy::Kalcy() { - environment.define("pi", std::numbers::pi_v); - environment.define("sqrt", [](std::span args) { - if (args.size() != 1) { throw Env::Mismatch{}; } - return std::sqrt(args.front()); - }); -} - -auto Kalcy::evaluate(std::string_view const expression, std::string* out_ast) const noexcept(false) -> double { - if (expression.empty()) { return {}; } - auto expr = Parser{expression}.parse(); - if (!expr) { return {}; } - if (out_ast != nullptr) { *out_ast = to_string(*expr); } - return Eval{environment}(*expr); -} -} // namespace kalcy