From 826af24561713c348fa3b51005f0f15d4dd69593 Mon Sep 17 00:00:00 2001 From: Riyyi Date: Sun, 2 Apr 2023 21:06:32 +0200 Subject: [PATCH] Main+Env+Printer: Remove the GlobalEnvironment subclass --- src/ast.cpp | 5 +- src/ast.h | 4 +- src/environment.cpp | 31 +---- src/environment.h | 34 +---- src/forward.h | 8 ++ src/functions.cpp | 277 ++++++++++++++++++----------------------- src/printer.cpp | 4 +- src/step4_if_fn_do.cpp | 115 ++++++++++------- 8 files changed, 208 insertions(+), 270 deletions(-) diff --git a/src/ast.cpp b/src/ast.cpp index dd32077..53232ad 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -65,8 +65,9 @@ Value::Value(State state) // ----------------------------------------- -Function::Function(FunctionType function) - : m_function(function) +Function::Function(const std::string& name, FunctionType function) + : m_name(name) + , m_function(function) { } diff --git a/src/ast.h b/src/ast.h index 7774298..038f86e 100644 --- a/src/ast.h +++ b/src/ast.h @@ -202,14 +202,16 @@ using FunctionType = std::function)>; class Function final : public ASTNode { public: - explicit Function(FunctionType function); + explicit Function(const std::string& name, FunctionType function); virtual ~Function() = default; virtual bool isFunction() const override { return true; } + const std::string& name() const { return m_name; } FunctionType function() const { return m_function; } private: + const std::string m_name; FunctionType m_function; }; diff --git a/src/environment.cpp b/src/environment.cpp index 964fb8d..056d9b9 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -6,7 +6,7 @@ #include // std::static_pointer_cast -#include "ruc/format/print.h" +#include "ruc/format/format.h" #include "ast.h" #include "environment.h" @@ -88,8 +88,6 @@ ASTNodePtr Environment::set(const std::string& symbol, ASTNodePtr value) ASTNodePtr Environment::get(const std::string& symbol) { - m_current_key = symbol; - if (exists(symbol)) { return m_values[symbol]; } @@ -101,31 +99,4 @@ ASTNodePtr Environment::get(const std::string& symbol) return nullptr; } -// ----------------------------------------- - -GlobalEnvironment::GlobalEnvironment() -{ - add(); - sub(); - mul(); - div(); - - lt(); - lte(); - gt(); - gte(); - - list(); - isList(); - isEmpty(); - count(); - - str(); - prStr(); - prn(); - println(); - - equal(); -} - } // namespace blaze diff --git a/src/environment.h b/src/environment.h index aad1486..e16ba88 100644 --- a/src/environment.h +++ b/src/environment.h @@ -9,9 +9,7 @@ #include #include #include -#include -#include "badge.h" #include "forward.h" namespace blaze { @@ -32,38 +30,8 @@ public: protected: Environment() {} - std::string m_current_key; - std::unordered_map m_values; EnvironmentPtr m_outer { nullptr }; -}; - -class GlobalEnvironment final : public Environment { -public: - GlobalEnvironment(); - virtual ~GlobalEnvironment() = default; - -private: - void add(); // + - void sub(); // - - void mul(); // * - void div(); // / - - void lt(); // < - void lte(); // <= - void gt(); // > - void gte(); // >= - - void list(); // list - void isList(); // list? - void isEmpty(); // empty? - void count(); // count - - void str(); // str - void prStr(); // pr-str - void prn(); // prn - void println(); // println - - void equal(); // = + std::unordered_map m_values; }; } // namespace blaze diff --git a/src/forward.h b/src/forward.h index c6045b4..ae778fb 100644 --- a/src/forward.h +++ b/src/forward.h @@ -10,10 +10,18 @@ namespace blaze { +// ----------------------------------------- +// Types + class ASTNode; typedef std::shared_ptr ASTNodePtr; class Environment; typedef std::shared_ptr EnvironmentPtr; +// ----------------------------------------- +// Functions + +extern void installFunctions(EnvironmentPtr env); + } // namespace blaze diff --git a/src/functions.cpp b/src/functions.cpp index 13c9aa1..d670f43 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -7,7 +7,6 @@ #include // std::static_pointer_cast #include -#include "ruc/format/color.h" #include "ruc/format/format.h" #include "ast.h" @@ -18,11 +17,34 @@ #include "types.h" #include "util.h" +// At the top-level you cant invoke any function, but you can create variables. +// Using a struct's constructor you can work around this limitation. +// Also the line number in the file is used to make the struct names unique. + +#define FUNCTION_STRUCT_NAME(unique) __functionStruct##unique + +#define ADD_FUNCTION_IMPL(unique, symbol, lambda) \ + struct FUNCTION_STRUCT_NAME(unique) { \ + FUNCTION_STRUCT_NAME(unique) \ + (std::string __symbol, FunctionType __lambda) \ + { \ + s_functions.emplace(__symbol, __lambda); \ + } \ + }; \ + static struct FUNCTION_STRUCT_NAME(unique) \ + FUNCTION_STRUCT_NAME(unique)( \ + symbol, \ + [](std::list nodes) -> ASTNodePtr lambda); + +#define ADD_FUNCTION(symbol, lambda) ADD_FUNCTION_IMPL(__LINE__, symbol, lambda); + namespace blaze { -void GlobalEnvironment::add() -{ - auto add = [](std::list nodes) -> ASTNodePtr { +static std::unordered_map s_functions; + +ADD_FUNCTION( + "+", + { int64_t result = 0; for (auto node : nodes) { @@ -35,14 +57,11 @@ void GlobalEnvironment::add() } return makePtr(result); - }; - - m_values.emplace("+", makePtr(add)); -} + }); -void GlobalEnvironment::sub() -{ - auto sub = [](std::list nodes) -> ASTNodePtr { +ADD_FUNCTION( + "-", + { if (nodes.size() == 0) { return makePtr(0); } @@ -63,14 +82,11 @@ void GlobalEnvironment::sub() } return makePtr(result); - }; - - m_values.emplace("-", makePtr(sub)); -} + }); -void GlobalEnvironment::mul() -{ - auto mul = [](std::list nodes) -> ASTNodePtr { +ADD_FUNCTION( + "*", + { int64_t result = 1; for (auto node : nodes) { @@ -83,16 +99,13 @@ void GlobalEnvironment::mul() } return makePtr(result); - }; + }); - m_values.emplace("*", makePtr(mul)); -} - -void GlobalEnvironment::div() -{ - auto div = [this](std::list nodes) -> ASTNodePtr { +ADD_FUNCTION( + "/", + { if (nodes.size() == 0) { - Error::the().add(format("wrong number of arguments: {}, 0", m_current_key)); + Error::the().add(format("wrong number of arguments: /, 0")); return nullptr; } @@ -112,72 +125,52 @@ void GlobalEnvironment::div() } return makePtr((int64_t)result); - }; - - m_values.emplace("/", makePtr(div)); -} + }); + +// // ----------------------------------------- + +#define NUMBER_COMPARE(operator) \ + { \ + bool result = true; \ + \ + if (nodes.size() < 2) { \ + Error::the().add(format("wrong number of arguments: {}, {}", #operator, nodes.size() - 1)); \ + return nullptr; \ + } \ + \ + for (auto node : nodes) { \ + if (!is(node.get())) { \ + Error::the().add(format("wrong argument type: number, '{}'", node)); \ + return nullptr; \ + } \ + } \ + \ + /* Start with the first number */ \ + int64_t number = std::static_pointer_cast(nodes.front())->number(); \ + \ + /* Skip the first node */ \ + for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { \ + int64_t current_number = std::static_pointer_cast(*it)->number(); \ + if (!(number operator current_number)) { \ + result = false; \ + break; \ + } \ + number = current_number; \ + } \ + \ + return makePtr((result) ? Value::True : Value::False); \ + } + +ADD_FUNCTION("<", NUMBER_COMPARE(<)); +ADD_FUNCTION("<=", NUMBER_COMPARE(<=)); +ADD_FUNCTION(">", NUMBER_COMPARE(>)); +ADD_FUNCTION(">=", NUMBER_COMPARE(>=)); // ----------------------------------------- -#define NUMBER_COMPARE(symbol, comparison_symbol) \ - auto lambda = [this](std::list nodes) -> ASTNodePtr { \ - bool result = true; \ - \ - if (nodes.size() < 2) { \ - Error::the().add(format("wrong number of arguments: {}, {}", m_current_key, nodes.size() - 1)); \ - return nullptr; \ - } \ - \ - for (auto node : nodes) { \ - if (!is(node.get())) { \ - Error::the().add(format("wrong argument type: number, '{}'", node)); \ - return nullptr; \ - } \ - } \ - \ - /* Start with the first number */ \ - int64_t number = std::static_pointer_cast(nodes.front())->number(); \ - \ - /* Skip the first node */ \ - for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { \ - int64_t current_number = std::static_pointer_cast(*it)->number(); \ - if (number comparison_symbol current_number) { \ - result = false; \ - break; \ - } \ - number = current_number; \ - } \ - \ - return makePtr((result) ? Value::True : Value::False); \ - }; \ - \ - m_values.emplace(symbol, makePtr(lambda)); - -void GlobalEnvironment::lt() -{ - NUMBER_COMPARE("<", >=); -} - -void GlobalEnvironment::lte() -{ - NUMBER_COMPARE("<=", >); -} - -void GlobalEnvironment::gt() -{ - NUMBER_COMPARE(">", <=); -} - -void GlobalEnvironment::gte() -{ - NUMBER_COMPARE(">=", <); -} - -// ----------------------------------------- - -void GlobalEnvironment::list() -{ - auto list = [](std::list nodes) -> ASTNodePtr { +ADD_FUNCTION( + "list", + { auto list = makePtr(); for (auto node : nodes) { @@ -185,14 +178,11 @@ void GlobalEnvironment::list() } return list; - }; + }); - m_values.emplace("list", makePtr(list)); -} - -void GlobalEnvironment::isList() -{ - auto is_list = [](std::list nodes) -> ASTNodePtr { +ADD_FUNCTION( + "list?", + { bool result = true; for (auto node : nodes) { @@ -203,14 +193,11 @@ void GlobalEnvironment::isList() } return makePtr((result) ? Value::True : Value::False); - }; - - m_values.emplace("list?", makePtr(is_list)); -} + }); -void GlobalEnvironment::isEmpty() -{ - auto is_empty = [](std::list nodes) -> ASTNodePtr { +ADD_FUNCTION( + "empty?", + { bool result = true; for (auto node : nodes) { @@ -226,16 +213,13 @@ void GlobalEnvironment::isEmpty() } return makePtr((result) ? Value::True : Value::False); - }; - - m_values.emplace("empty?", makePtr(is_empty)); -} + }); -void GlobalEnvironment::count() -{ - auto count = [this](std::list nodes) -> ASTNodePtr { +ADD_FUNCTION( + "count", + { if (nodes.size() != 1) { - Error::the().add(format("wrong number of arguments: {}, {}", m_current_key, nodes.size() - 1)); + Error::the().add(format("wrong number of arguments: count, {}", nodes.size() - 1)); return nullptr; } @@ -255,15 +239,12 @@ void GlobalEnvironment::count() // FIXME: Add numeric_limits check for implicit cast: size_t > int64_t return makePtr((int64_t)result); - }; - - m_values.emplace("count", makePtr(count)); -} + }); // ----------------------------------------- -#define PRINTER_STRING(symbol, concatenation, print_readably) \ - auto lambda = [](std::list nodes) -> ASTNodePtr { \ +#define PRINTER_STRING(print_readably, concatenation) \ + { \ std::string result; \ \ Printer printer; \ @@ -276,22 +257,13 @@ void GlobalEnvironment::count() } \ \ return makePtr(result); \ - }; \ - \ - m_values.emplace(symbol, makePtr(lambda)); + } -void GlobalEnvironment::str() -{ - PRINTER_STRING("str", "", false); -} +ADD_FUNCTION("str", PRINTER_STRING(false, "")); +ADD_FUNCTION("pr-str", PRINTER_STRING(true, " ")); -void GlobalEnvironment::prStr() -{ - PRINTER_STRING("pr-str", " ", true); -} - -#define PRINTER_PRINT(symbol, print_readably) \ - auto lambda = [](std::list nodes) -> ASTNodePtr { \ +#define PRINTER_PRINT(print_readably) \ + { \ Printer printer; \ for (auto it = nodes.begin(); it != nodes.end(); ++it) { \ print("{}", printer.printNoErrorCheck(*it, print_readably)); \ @@ -303,34 +275,25 @@ void GlobalEnvironment::prStr() print("\n"); \ \ return makePtr(Value::Nil); \ - }; \ - \ - m_values.emplace(symbol, makePtr(lambda)); + } -void GlobalEnvironment::prn() -{ - PRINTER_PRINT("prn", true); -} - -void GlobalEnvironment::println() -{ - PRINTER_PRINT("println", false); -} +ADD_FUNCTION("prn", PRINTER_PRINT(true)); +ADD_FUNCTION("println", PRINTER_PRINT(false)); // ----------------------------------------- -void GlobalEnvironment::equal() -{ - auto lambda = [this](std::list nodes) -> ASTNodePtr { +ADD_FUNCTION( + "=", + { if (nodes.size() < 2) { - Error::the().add(format("wrong number of arguments: {}, {}", m_current_key, nodes.size() - 1)); + Error::the().add(format("wrong number of arguments: =, {}", nodes.size() - 1)); return nullptr; } std::function equal = [&equal](ASTNodePtr lhs, ASTNodePtr rhs) -> bool { if ((is(lhs.get()) || is(lhs.get())) - && (is(rhs.get()) || is(rhs.get()))) { + && (is(rhs.get()) || is(rhs.get()))) { auto lhs_nodes = std::static_pointer_cast(lhs)->nodes(); auto rhs_nodes = std::static_pointer_cast(rhs)->nodes(); @@ -368,23 +331,23 @@ void GlobalEnvironment::equal() } if (is(lhs.get()) && is(rhs.get()) - && std::static_pointer_cast(lhs)->data() == std::static_pointer_cast(rhs)->data()) { + && std::static_pointer_cast(lhs)->data() == std::static_pointer_cast(rhs)->data()) { return true; } if (is(lhs.get()) && is(rhs.get()) - && std::static_pointer_cast(lhs)->keyword() == std::static_pointer_cast(rhs)->keyword()) { + && std::static_pointer_cast(lhs)->keyword() == std::static_pointer_cast(rhs)->keyword()) { return true; } if (is(lhs.get()) && is(rhs.get()) - && std::static_pointer_cast(lhs)->number() == std::static_pointer_cast(rhs)->number()) { + && std::static_pointer_cast(lhs)->number() == std::static_pointer_cast(rhs)->number()) { return true; } if (is(lhs.get()) && is(rhs.get()) - && std::static_pointer_cast(lhs)->state() == std::static_pointer_cast(rhs)->state()) { + && std::static_pointer_cast(lhs)->state() == std::static_pointer_cast(rhs)->state()) { return true; } if (is(lhs.get()) && is(rhs.get()) - && std::static_pointer_cast(lhs)->symbol() == std::static_pointer_cast(rhs)->symbol()) { + && std::static_pointer_cast(lhs)->symbol() == std::static_pointer_cast(rhs)->symbol()) { return true; } @@ -402,9 +365,13 @@ void GlobalEnvironment::equal() } return makePtr((result) ? Value::True : Value::False); - }; + }); - m_values.emplace("=", makePtr(lambda)); +void installFunctions(EnvironmentPtr env) +{ + for (const auto& [name, lambda] : s_functions) { + env->set(name, makePtr(name, lambda)); + } } } // namespace blaze diff --git a/src/printer.cpp b/src/printer.cpp index 7ec7dae..57330ea 100644 --- a/src/printer.cpp +++ b/src/printer.cpp @@ -135,11 +135,11 @@ void Printer::printImpl(ASTNodePtr node, bool print_readably) } else if (is(node_raw_ptr)) { printSpacing(); - m_print += format("#"); + m_print += format("#({})", std::static_pointer_cast(node)->name()); } else if (is(node_raw_ptr)) { printSpacing(); - m_print += format("#"); + m_print += format("#({:p})", node_raw_ptr); } } diff --git a/src/step4_if_fn_do.cpp b/src/step4_if_fn_do.cpp index d9c6419..85b548a 100644 --- a/src/step4_if_fn_do.cpp +++ b/src/step4_if_fn_do.cpp @@ -18,53 +18,14 @@ #include "settings.h" #if 1 -static blaze::EnvironmentPtr env = blaze::makePtr(); +static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create(); -auto read(std::string_view input) -> blaze::ASTNodePtr -{ - blaze::Lexer lexer(input); - lexer.tokenize(); - if (blaze::Settings::the().get("dump-lexer") == "1") { - lexer.dump(); - } - - blaze::Reader reader(std::move(lexer.tokens())); - reader.read(); - if (blaze::Settings::the().get("dump-reader") == "1") { - reader.dump(); - } - - return reader.node(); -} - -auto eval(blaze::ASTNodePtr ast) -> blaze::ASTNodePtr -{ - blaze::Eval eval(ast, env); - eval.eval(); - - return eval.ast(); -} - -auto print(blaze::ASTNodePtr exp) -> std::string -{ - blaze::Printer printer; - - return printer.print(exp, true); -} - -auto rep(std::string_view input) -> std::string -{ - blaze::Error::the().clearErrors(); - blaze::Error::the().setInput(input); - - return print(eval(read(input))); -} - -static auto cleanup(int signal) -> void -{ - print("\033[0m\n"); - std::exit(signal); -} +static auto cleanup(int signal) -> void; +static auto installLambdas(blaze::EnvironmentPtr env) -> void; +static auto rep(std::string_view input, blaze::EnvironmentPtr env) -> std::string; +static auto read(std::string_view input) -> blaze::ASTNodePtr; +static auto eval(blaze::ASTNodePtr ast, blaze::EnvironmentPtr env) -> blaze::ASTNodePtr; +static auto print(blaze::ASTNodePtr exp) -> std::string; auto main(int argc, char* argv[]) -> int { @@ -90,6 +51,9 @@ auto main(int argc, char* argv[]) -> int std::signal(SIGINT, cleanup); std::signal(SIGTERM, cleanup); + installFunctions(s_outer_env); + installLambdas(s_outer_env); + blaze::Readline readline(pretty_print, history_path); std::string input; @@ -97,7 +61,7 @@ auto main(int argc, char* argv[]) -> int if (pretty_print) { print("\033[0m"); } - print("{}\n", rep(input)); + print("{}\n", rep(input, s_outer_env)); } if (pretty_print) { @@ -106,4 +70,61 @@ auto main(int argc, char* argv[]) -> int return 0; } + +static auto cleanup(int signal) -> void +{ + print("\033[0m\n"); + std::exit(signal); +} + +static std::string_view lambdaTable[] = { + "(def! not (fn* (cond) (if cond false true)))", +}; + +static auto installLambdas(blaze::EnvironmentPtr env) -> void +{ + for (auto function : lambdaTable) { + rep(function, env); + } +} + +static auto rep(std::string_view input, blaze::EnvironmentPtr env) -> std::string +{ + blaze::Error::the().clearErrors(); + blaze::Error::the().setInput(input); + + return print(eval(read(input), env)); +} + +static auto read(std::string_view input) -> blaze::ASTNodePtr +{ + blaze::Lexer lexer(input); + lexer.tokenize(); + if (blaze::Settings::the().get("dump-lexer") == "1") { + lexer.dump(); + } + + blaze::Reader reader(std::move(lexer.tokens())); + reader.read(); + if (blaze::Settings::the().get("dump-reader") == "1") { + reader.dump(); + } + + return reader.node(); +} + +static auto eval(blaze::ASTNodePtr ast, blaze::EnvironmentPtr env) -> blaze::ASTNodePtr +{ + blaze::Eval eval(ast, env); + eval.eval(); + + return eval.ast(); +} + +static auto print(blaze::ASTNodePtr exp) -> std::string +{ + blaze::Printer printer; + + return printer.print(exp, true); +} #endif