mirror of https://github.com/RainMark/lispoo.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
4.9 KiB
167 lines
4.9 KiB
#pragma once
|
|
|
|
#include <lispoo.h>
|
|
|
|
namespace lispoo {
|
|
|
|
inline std::shared_ptr<Expr> sum(const std::shared_ptr<Expr>& a,
|
|
const std::shared_ptr<Expr>& b) {
|
|
if (a->type() == Type::Float
|
|
&& b->type() == Type::Float) {
|
|
return std::make_shared<Float>(get_value<Float>(a) + get_value<Float>(b));
|
|
}
|
|
if (a->type() == Type::Integer
|
|
&& b->type() == Type::Integer) {
|
|
return std::make_shared<Integer>(get_value<Integer>(a) + get_value<Integer>(b));
|
|
}
|
|
if (a->type() == Type::Float) {
|
|
return std::make_shared<Float>(get_value<Float>(a) + get_value<Integer>(b));
|
|
}
|
|
if (b->type() == Type::Float) {
|
|
return std::make_shared<Float>(get_value<Integer>(a) + get_value<Float>(b));
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
inline std::shared_ptr<Expr> message(const std::shared_ptr<Expr>& expr) {
|
|
auto type = expr->type();
|
|
switch (type) {
|
|
case Type::Null: {
|
|
std::cout << "nil";
|
|
break;
|
|
}
|
|
case Type::Integer: {
|
|
std::cout << get_value<Integer>(expr);
|
|
break;
|
|
}
|
|
case Type::Float: {
|
|
std::cout << get_value<Float>(expr);
|
|
break;
|
|
}
|
|
case Type::Symbol: {
|
|
std::cout << get_value<Symbol>(expr);
|
|
break;
|
|
}
|
|
case Type::Callable: {
|
|
std::cout << "<fn>: " << expr.get();
|
|
break;
|
|
}
|
|
case Type::List: {
|
|
auto value = get_value<List>(expr);
|
|
std::cout << "(";
|
|
for (auto i = 0; i < value.size(); ++i) {
|
|
if (i > 0) {
|
|
std::cout << " ";
|
|
}
|
|
message(value[i]);
|
|
}
|
|
std::cout << ")";
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
inline void init() {
|
|
// syntax
|
|
putenv("quote",
|
|
[](auto expr, auto env) {
|
|
assert_len(expr, 2);
|
|
auto value = get_value<List>(expr);
|
|
return value[1];
|
|
});
|
|
putenv("define",
|
|
[](auto expr, auto env) {
|
|
assert_len(expr, 3);
|
|
auto value = get_value<List>(expr);
|
|
assert_type<Type::Symbol>(value[1]);
|
|
auto symbol = get_value<Symbol>(value[1]);
|
|
if (!is_nil(env->get(symbol))) {
|
|
oops("symbol defined: " + symbol);
|
|
}
|
|
env->put(symbol, eval(value[2], env));
|
|
return nil;
|
|
});
|
|
putenv("set!",
|
|
[](auto expr, auto env) {
|
|
assert_len(expr, 3);
|
|
auto value = get_value<List>(expr);
|
|
assert_type<Type::Symbol>(value[1]);
|
|
auto symbol = get_value<Symbol>(value[1]);
|
|
env->put(symbol, eval(value[2], env));
|
|
return nil;
|
|
});
|
|
putenv("progn",
|
|
[](auto expr, auto env) {
|
|
auto val = nil;
|
|
auto value = get_value<List>(expr);
|
|
for (auto i = 1; i < value.size(); ++i) {
|
|
val = eval(value[i], env);
|
|
}
|
|
return val;
|
|
});
|
|
putenv("if",
|
|
[](auto expr, auto env) {
|
|
// (if (cond) (then body) (else body))
|
|
assert_len(expr, 4);
|
|
auto value = get_value<List>(expr);
|
|
if (is_true(eval(value[1], env))) {
|
|
return eval(value[2], env);
|
|
} else {
|
|
return eval(value[3], env);
|
|
}
|
|
});
|
|
putenv("while",
|
|
[](auto expr, auto env) {
|
|
// (while (cond) (loop body))
|
|
assert_len(expr, 3);
|
|
auto value = get_value<List>(expr);
|
|
while (is_true(eval(value[1], env))) {
|
|
eval(value[2], env);
|
|
}
|
|
return nil;
|
|
});
|
|
putenv("lambda",
|
|
[](auto expr, auto env) {
|
|
// (lambda (args) (body))
|
|
assert_len(expr, 3);
|
|
auto lambda =
|
|
[expr, parent = env](auto args, auto) {
|
|
auto value = get_value<List>(expr);
|
|
auto symbols = get_value<List>(value[1]);
|
|
// arguments bind
|
|
auto args_value = get_value<List>(args);
|
|
if (symbols.size() != args_value.size() - 1) {
|
|
oops("arguments error");
|
|
}
|
|
auto env = std::make_shared<Env>(parent);
|
|
for (auto i = 0; i < symbols.size(); ++i) {
|
|
auto symbol = get_value<Symbol>(symbols[i]);
|
|
env->put(symbol, eval(args_value[i + 1], parent));
|
|
}
|
|
// eval body
|
|
return eval(value[2], env);
|
|
};
|
|
return std::make_shared<Callable>(std::move(lambda));
|
|
});
|
|
|
|
// normal builtin function
|
|
putenv("+",
|
|
[](auto expr, auto env) {
|
|
assert_len(expr, 3);
|
|
auto value = get_value<List>(expr);
|
|
return sum(eval(value[1], env), eval(value[2], env));
|
|
});
|
|
putenv("message",
|
|
[](auto expr, auto env) {
|
|
auto value = get_value<List>(expr);
|
|
for (auto i = 1; i < value.size(); ++i) {
|
|
message(eval(value[i], env));
|
|
std::cout << std::endl;
|
|
}
|
|
return nil;
|
|
});
|
|
}
|
|
|
|
} // namespace lispoo
|
|
|