Main+Env+Printer: Remove the GlobalEnvironment subclass
This commit is contained in:
+3
-2
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -202,14 +202,16 @@ using FunctionType = std::function<ASTNodePtr(std::list<ASTNodePtr>)>;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
+1
-30
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <memory> // 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
|
||||
|
||||
+1
-33
@@ -9,9 +9,7 @@
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "badge.h"
|
||||
#include "forward.h"
|
||||
|
||||
namespace blaze {
|
||||
@@ -32,38 +30,8 @@ public:
|
||||
protected:
|
||||
Environment() {}
|
||||
|
||||
std::string m_current_key;
|
||||
std::unordered_map<std::string, ASTNodePtr> 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<std::string, ASTNodePtr> m_values;
|
||||
};
|
||||
|
||||
} // namespace blaze
|
||||
|
||||
@@ -10,10 +10,18 @@
|
||||
|
||||
namespace blaze {
|
||||
|
||||
// -----------------------------------------
|
||||
// Types
|
||||
|
||||
class ASTNode;
|
||||
typedef std::shared_ptr<ASTNode> ASTNodePtr;
|
||||
|
||||
class Environment;
|
||||
typedef std::shared_ptr<Environment> EnvironmentPtr;
|
||||
|
||||
// -----------------------------------------
|
||||
// Functions
|
||||
|
||||
extern void installFunctions(EnvironmentPtr env);
|
||||
|
||||
} // namespace blaze
|
||||
|
||||
+87
-120
@@ -7,7 +7,6 @@
|
||||
#include <memory> // std::static_pointer_cast
|
||||
#include <string>
|
||||
|
||||
#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<ASTNodePtr> nodes) -> ASTNodePtr lambda);
|
||||
|
||||
#define ADD_FUNCTION(symbol, lambda) ADD_FUNCTION_IMPL(__LINE__, symbol, lambda);
|
||||
|
||||
namespace blaze {
|
||||
|
||||
void GlobalEnvironment::add()
|
||||
{
|
||||
auto add = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
||||
static std::unordered_map<std::string, FunctionType> s_functions;
|
||||
|
||||
ADD_FUNCTION(
|
||||
"+",
|
||||
{
|
||||
int64_t result = 0;
|
||||
|
||||
for (auto node : nodes) {
|
||||
@@ -35,14 +57,11 @@ void GlobalEnvironment::add()
|
||||
}
|
||||
|
||||
return makePtr<Number>(result);
|
||||
};
|
||||
});
|
||||
|
||||
m_values.emplace("+", makePtr<Function>(add));
|
||||
}
|
||||
|
||||
void GlobalEnvironment::sub()
|
||||
{
|
||||
auto sub = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
||||
ADD_FUNCTION(
|
||||
"-",
|
||||
{
|
||||
if (nodes.size() == 0) {
|
||||
return makePtr<Number>(0);
|
||||
}
|
||||
@@ -63,14 +82,11 @@ void GlobalEnvironment::sub()
|
||||
}
|
||||
|
||||
return makePtr<Number>(result);
|
||||
};
|
||||
});
|
||||
|
||||
m_values.emplace("-", makePtr<Function>(sub));
|
||||
}
|
||||
|
||||
void GlobalEnvironment::mul()
|
||||
{
|
||||
auto mul = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
||||
ADD_FUNCTION(
|
||||
"*",
|
||||
{
|
||||
int64_t result = 1;
|
||||
|
||||
for (auto node : nodes) {
|
||||
@@ -83,16 +99,13 @@ void GlobalEnvironment::mul()
|
||||
}
|
||||
|
||||
return makePtr<Number>(result);
|
||||
};
|
||||
});
|
||||
|
||||
m_values.emplace("*", makePtr<Function>(mul));
|
||||
}
|
||||
|
||||
void GlobalEnvironment::div()
|
||||
{
|
||||
auto div = [this](std::list<ASTNodePtr> 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,19 +125,16 @@ void GlobalEnvironment::div()
|
||||
}
|
||||
|
||||
return makePtr<Number>((int64_t)result);
|
||||
};
|
||||
});
|
||||
|
||||
m_values.emplace("/", makePtr<Function>(div));
|
||||
}
|
||||
// // -----------------------------------------
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
#define NUMBER_COMPARE(symbol, comparison_symbol) \
|
||||
auto lambda = [this](std::list<ASTNodePtr> nodes) -> ASTNodePtr { \
|
||||
#define NUMBER_COMPARE(operator) \
|
||||
{ \
|
||||
bool result = true; \
|
||||
\
|
||||
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: {}, {}", #operator, nodes.size() - 1)); \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
@@ -141,7 +151,7 @@ void GlobalEnvironment::div()
|
||||
/* Skip the first node */ \
|
||||
for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { \
|
||||
int64_t current_number = std::static_pointer_cast<Number>(*it)->number(); \
|
||||
if (number comparison_symbol current_number) { \
|
||||
if (!(number operator current_number)) { \
|
||||
result = false; \
|
||||
break; \
|
||||
} \
|
||||
@@ -149,35 +159,18 @@ void GlobalEnvironment::div()
|
||||
} \
|
||||
\
|
||||
return makePtr<Value>((result) ? Value::True : Value::False); \
|
||||
}; \
|
||||
\
|
||||
m_values.emplace(symbol, makePtr<Function>(lambda));
|
||||
}
|
||||
|
||||
void GlobalEnvironment::lt()
|
||||
{
|
||||
NUMBER_COMPARE("<", >=);
|
||||
}
|
||||
|
||||
void GlobalEnvironment::lte()
|
||||
{
|
||||
NUMBER_COMPARE("<=", >);
|
||||
}
|
||||
|
||||
void GlobalEnvironment::gt()
|
||||
{
|
||||
NUMBER_COMPARE(">", <=);
|
||||
}
|
||||
|
||||
void GlobalEnvironment::gte()
|
||||
{
|
||||
NUMBER_COMPARE(">=", <);
|
||||
}
|
||||
ADD_FUNCTION("<", NUMBER_COMPARE(<));
|
||||
ADD_FUNCTION("<=", NUMBER_COMPARE(<=));
|
||||
ADD_FUNCTION(">", NUMBER_COMPARE(>));
|
||||
ADD_FUNCTION(">=", NUMBER_COMPARE(>=));
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void GlobalEnvironment::list()
|
||||
{
|
||||
auto list = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
||||
ADD_FUNCTION(
|
||||
"list",
|
||||
{
|
||||
auto list = makePtr<List>();
|
||||
|
||||
for (auto node : nodes) {
|
||||
@@ -185,14 +178,11 @@ void GlobalEnvironment::list()
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
});
|
||||
|
||||
m_values.emplace("list", makePtr<Function>(list));
|
||||
}
|
||||
|
||||
void GlobalEnvironment::isList()
|
||||
{
|
||||
auto is_list = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
||||
ADD_FUNCTION(
|
||||
"list?",
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
for (auto node : nodes) {
|
||||
@@ -203,14 +193,11 @@ void GlobalEnvironment::isList()
|
||||
}
|
||||
|
||||
return makePtr<Value>((result) ? Value::True : Value::False);
|
||||
};
|
||||
});
|
||||
|
||||
m_values.emplace("list?", makePtr<Function>(is_list));
|
||||
}
|
||||
|
||||
void GlobalEnvironment::isEmpty()
|
||||
{
|
||||
auto is_empty = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
||||
ADD_FUNCTION(
|
||||
"empty?",
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
for (auto node : nodes) {
|
||||
@@ -226,16 +213,13 @@ void GlobalEnvironment::isEmpty()
|
||||
}
|
||||
|
||||
return makePtr<Value>((result) ? Value::True : Value::False);
|
||||
};
|
||||
});
|
||||
|
||||
m_values.emplace("empty?", makePtr<Function>(is_empty));
|
||||
}
|
||||
|
||||
void GlobalEnvironment::count()
|
||||
{
|
||||
auto count = [this](std::list<ASTNodePtr> 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<Number>((int64_t)result);
|
||||
};
|
||||
|
||||
m_values.emplace("count", makePtr<Function>(count));
|
||||
}
|
||||
});
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
#define PRINTER_STRING(symbol, concatenation, print_readably) \
|
||||
auto lambda = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr { \
|
||||
#define PRINTER_STRING(print_readably, concatenation) \
|
||||
{ \
|
||||
std::string result; \
|
||||
\
|
||||
Printer printer; \
|
||||
@@ -276,22 +257,13 @@ void GlobalEnvironment::count()
|
||||
} \
|
||||
\
|
||||
return makePtr<String>(result); \
|
||||
}; \
|
||||
\
|
||||
m_values.emplace(symbol, makePtr<Function>(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<ASTNodePtr> 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,27 +275,18 @@ void GlobalEnvironment::prStr()
|
||||
print("\n"); \
|
||||
\
|
||||
return makePtr<Value>(Value::Nil); \
|
||||
}; \
|
||||
\
|
||||
m_values.emplace(symbol, makePtr<Function>(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<ASTNodePtr> 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;
|
||||
}
|
||||
|
||||
@@ -402,9 +365,13 @@ void GlobalEnvironment::equal()
|
||||
}
|
||||
|
||||
return makePtr<Value>((result) ? Value::True : Value::False);
|
||||
};
|
||||
});
|
||||
|
||||
m_values.emplace("=", makePtr<Function>(lambda));
|
||||
void installFunctions(EnvironmentPtr env)
|
||||
{
|
||||
for (const auto& [name, lambda] : s_functions) {
|
||||
env->set(name, makePtr<Function>(name, lambda));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blaze
|
||||
|
||||
+2
-2
@@ -135,11 +135,11 @@ void Printer::printImpl(ASTNodePtr node, bool print_readably)
|
||||
}
|
||||
else if (is<Function>(node_raw_ptr)) {
|
||||
printSpacing();
|
||||
m_print += format("#<builtin-function>");
|
||||
m_print += format("#<builtin-function>({})", std::static_pointer_cast<Function>(node)->name());
|
||||
}
|
||||
else if (is<Lambda>(node_raw_ptr)) {
|
||||
printSpacing();
|
||||
m_print += format("#<user-function>");
|
||||
m_print += format("#<user-function>({:p})", node_raw_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+68
-47
@@ -18,53 +18,14 @@
|
||||
#include "settings.h"
|
||||
|
||||
#if 1
|
||||
static blaze::EnvironmentPtr env = blaze::makePtr<blaze::GlobalEnvironment>();
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user