a8/a8/lisp.cc
aozhiwei bb2f76674d 1
2023-03-03 22:05:15 +08:00

283 lines
9.0 KiB
C++

#include <a8/a8.h>
#include <ctype.h>
#include <a8/lisp.h>
#include <a8/mutable_xobject.h>
namespace a8
{
namespace lisp
{
Value::Value(Atom atom)
{
type = ValueType::kAtom;
value = atom;
}
Value::Value(List list)
{
type = ValueType::kList;
value = list;
}
Value::Value(Symbol symbol)
{
type = ValueType::kSymbol;
value = symbol;
}
Value::Value(const std::string& proc_name, CProc cproc)
{
type = ValueType::kCProc;
name = proc_name;
value = cproc;
}
a8::XObject Value::ToXObject()
{
switch (type) {
case ValueType::kAtom:
{
Atom&& atom = std::any_cast<Atom>(value);
a8::XValue v(atom.val);
return a8::XObject(v);
}
break;
case ValueType::kList:
{
auto arr = a8::MutableXObject::CreateArray();
List list = std::any_cast<List>(value);
for (auto ele : *list) {
a8::XObject xobj = ele->ToXObject();
arr->Push(xobj);
}
return *arr;
}
break;
case ValueType::kSymbol:
{
Symbol&& symbol = std::any_cast<Symbol>(value);
auto obj = a8::MutableXObject::CreateObject();
obj->SetVal("name", symbol.name);
return *obj;
}
break;
case ValueType::kCProc:
{
auto obj = a8::MutableXObject::CreateObject();
obj->SetVal("type", "lambda");
obj->SetVal("name", name);
return *obj;
}
break;
default:
{
abort();
}
break;
}
}
std::shared_ptr<Value> Scope::Find(const std::string& name)
{
auto itr = vars_.find(name);
return itr != vars_.end() ? itr->second : nullptr;
}
void Scope::RegisterCProc(const std::string& name, CProc proc)
{
vars_[name] = std::make_shared<Value>(name, proc);
}
GlobalScope::GlobalScope()
{
RegisterCProc
(
"+",
[] (const List& params) -> std::shared_ptr<Value>
{
Atom result;
for (auto param : *params) {
Atom&& atom = std::any_cast<Atom>(param->value);
result.val += atom.val;
}
return std::make_shared<Value>(result);
});
RegisterCProc
(
"-",
[] (const List& params) -> std::shared_ptr<Value>
{
Atom result;
for (auto param : *params) {
Atom&& atom = std::any_cast<Atom>(param->value);
result.val -= atom.val;
}
return std::make_shared<Value>(result);
});
RegisterCProc
(
"*",
[] (const List& params) -> std::shared_ptr<Value>
{
Atom result;
for (auto param : *params) {
Atom&& atom = std::any_cast<Atom>(param->value);
result.val *= atom.val;
}
return std::make_shared<Value>(result);
});
RegisterCProc
(
"/",
[] (const List& params) -> std::shared_ptr<Value>
{
Atom result;
for (auto param : *params) {
Atom&& atom = std::any_cast<Atom>(param->value);
result.val /= atom.val;
}
return std::make_shared<Value>(result);
});
}
std::shared_ptr<Value> Expr::Compile(const std::string& script, std::shared_ptr<Scope> env)
{
std::vector<List> stack;
int pos = 0;
int depth = -1;
while (true) {
std::string token;
int n = GetToken(script, pos, token);
if (n != 1) {
break;
}
if (token == "(") {
List new_list = std::make_shared<std::vector<std::shared_ptr<Value>>>();
stack.push_back(new_list);
++depth;
} else if (token == ")") {
--depth;
} else {
if (depth < 0) {
abort();
}
double val = 0.0f;
if (sscanf(token.c_str(), "%lf", &val) == 1) {
Atom atom;
atom.val = val;
stack.at(depth)->push_back(std::make_shared<Value>(atom));
} else {
auto symbol = env->Find(token);
if (symbol) {
if (!symbol->IsType(ValueType::kCProc)) {
abort();
}
stack.at(depth)->push_back(symbol);
} else {
abort();
}
}
}
}
if (depth != -1) {
abort();
}
if (stack.empty()) {
abort();
}
return std::make_shared<Value>(stack[0]);
}
/*
1: token
-1: end
*/
int Expr::GetToken(const std::string& script, int& pos, std::string& token)
{
if (pos >= script.size()) {
return -1;
}
while (pos < script.size() && isspace(script[pos])) {
++pos;
}
if (pos >= script.size()) {
return -1;
}
if (script[pos] == '(') {
++pos;
token = "(";
return 1;
}
if (script[pos] == ')') {
++pos;
token = ")";
return 1;
}
while (pos < script.size() &&
!isspace(script[pos]) &&
script[pos] != ')' &&
script[pos] != '(') {
token += script[pos];
++pos;
}
if (token.empty()) {
return -1;
} else {
return 1;
}
}
std::shared_ptr<Value> Expr::Eval(std::shared_ptr<Value> x, std::shared_ptr<Scope> env)
{
while (true) {
switch (x->type) {
case ValueType::kAtom:
{
return x;
}
break;
case ValueType::kSymbol:
{
Symbol&& symbol = std::any_cast<Symbol>(x->value);
return env->Find(symbol.name);
}
break;
case ValueType::kList:
{
List list = std::any_cast<List>(x->value);
auto leader = list->at(0);
if (leader->type == ValueType::kCProc) {
CProc&& cproc = std::any_cast<CProc>(leader->value);
List exps = std::make_shared<std::vector<std::shared_ptr<Value>>>();
for (auto itr = list->begin() + 1; itr != list->end(); ++itr) {
exps->push_back(Eval(*itr, env));
}
return cproc(exps);
} else {
CProc&& cproc = std::any_cast<CProc>(Eval(leader, env)->value);
List exps = std::make_shared<std::vector<std::shared_ptr<Value>>>();
for (auto itr = list->begin() + 1; itr != list->end(); ++itr) {
exps->push_back(Eval(*itr, env));
}
return cproc(exps);
}
}
break;
default:
{
abort();
return nullptr;
}
break;
}
}
}
}
}