diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d20224..fb62bc4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,3 +115,7 @@ add_dependencies(test7 ${PROJECT}) add_custom_target(test8 COMMAND env STEP=step_env MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step8_macros.mal -- ./${PROJECT}) add_dependencies(test8 ${PROJECT}) + +add_custom_target(test9 + COMMAND env STEP=step_env MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step9_try.mal -- ./${PROJECT}) +add_dependencies(test9 ${PROJECT}) diff --git a/src/step8_macros.cpp b/src/step8_macros.cpp index 20fbb4f..819e818 100644 --- a/src/step8_macros.cpp +++ b/src/step8_macros.cpp @@ -24,7 +24,7 @@ #include "readline.h" #include "settings.h" -#if 1 +#if 0 namespace blaze { static EnvironmentPtr s_outer_env = Environment::create(); diff --git a/src/step9_try.cpp b/src/step9_try.cpp new file mode 100644 index 0000000..20fbb4f --- /dev/null +++ b/src/step9_try.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2023 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#include // std::signal +#include // std::exit +#include +#include +#include + +#include "ruc/argparser.h" +#include "ruc/format/color.h" + +#include "ast.h" +#include "environment.h" +#include "error.h" +#include "eval.h" +#include "forward.h" +#include "lexer.h" +#include "printer.h" +#include "reader.h" +#include "readline.h" +#include "settings.h" + +#if 1 +namespace blaze { + +static EnvironmentPtr s_outer_env = Environment::create(); + +static auto cleanup(int signal) -> void +{ + print("\033[0m\n"); + std::exit(signal); +} + +auto read(std::string_view input) -> ValuePtr +{ + Lexer lexer(input); + lexer.tokenize(); + if (Settings::the().get("dump-lexer") == "1") { + lexer.dump(); + } + + Reader reader(std::move(lexer.tokens())); + reader.read(); + if (Settings::the().get("dump-reader") == "1") { + reader.dump(); + } + + return reader.node(); +} + +auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr +{ + if (env == nullptr) { + env = s_outer_env; + } + + Eval eval(ast, env); + eval.eval(); + + return eval.ast(); +} + +static auto print(ValuePtr exp) -> std::string +{ + Printer printer; + + return printer.print(exp, true); +} + +static auto rep(std::string_view input, EnvironmentPtr env) -> std::string +{ + Error::the().clearErrors(); + Error::the().setInput(input); + + return print(eval(read(input), env)); +} + +static std::string_view lambdaTable[] = { + "(def! not (fn* (cond) (if cond false true)))", + "(def! load-file (fn* (filename) \ + (eval (read-string (str \"(do \" (slurp filename) \"\nnil)\")))))", + "(defmacro! cond (fn* (& xs) \ + (if (> (count xs) 0) \ + (list 'if (first xs) \ + (if (> (count xs) 1) \ + (nth xs 1) \ + (throw \"odd number of forms to cond\")) \ + (cons 'cond (rest (rest xs)))))))", +}; + +static auto installLambdas(EnvironmentPtr env) -> void +{ + for (auto function : lambdaTable) { + rep(function, env); + } +} + +static auto makeArgv(EnvironmentPtr env, std::vector arguments) -> void +{ + auto list = makePtr(); + if (arguments.size() > 1) { + for (auto it = arguments.begin() + 1; it != arguments.end(); ++it) { + list->add(makePtr(*it)); + } + } + env->set("*ARGV*", list); +} + +} // namespace blaze + +auto main(int argc, char* argv[]) -> int +{ + bool dump_lexer = false; + bool dump_reader = false; + bool pretty_print = false; + std::string_view history_path = "~/.blaze-history"; + std::vector arguments; + + // CLI arguments + ruc::ArgParser arg_parser; + arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); + arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); + arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); + arg_parser.addOption(history_path, 'h', "history-path", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); + // TODO: Add overload for addArgument(std::vector) + arg_parser.addArgument(arguments, "arguments", nullptr, nullptr, ruc::ArgParser::Required::No); + arg_parser.parse(argc, argv); + + // Set settings + blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0"); + blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0"); + blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0"); + + // Signal callbacks + std::signal(SIGINT, blaze::cleanup); + std::signal(SIGTERM, blaze::cleanup); + + installFunctions(blaze::s_outer_env); + installLambdas(blaze::s_outer_env); + makeArgv(blaze::s_outer_env, arguments); + + if (arguments.size() > 0) { + rep(format("(load-file \"{}\")", arguments.front()), blaze::s_outer_env); + return 0; + } + + blaze::Readline readline(pretty_print, history_path); + + std::string input; + while (readline.get(input)) { + if (pretty_print) { + print("\033[0m"); + } + print("{}\n", rep(input, blaze::s_outer_env)); + } + + if (pretty_print) { + print("\033[0m"); + } + + return 0; +} +#endif