#include <open-axiom/Lisp>
#include <typeinfo>
#include <ostream>
#include <sstream>
namespace OpenAxiom {
namespace Lisp {
UnboundSymbol::UnboundSymbol(const std::string& s)
: BasicError(s)
{ }
static void unbound_symbol_error(const std::string& s) {
throw UnboundSymbol(s + " has no value binding");
}
UnboundFunctionSymbol::UnboundFunctionSymbol(const std::string& s)
: BasicError(s)
{ }
static void unbound_function_symbol_error(const Symbol* sym) {
std::string s { sym->name->begin(), sym->name->end() };
throw UnboundFunctionSymbol(s + " has no function definition");
}
namespace {
template<typename T>
struct NamedConstant {
const char* const name;
const T value;
};
}
constexpr NamedConstant<Value> value_constants[] = {
{ "NIL", Value::nil },
{ "T", Value::t },
{ "MOST-NEGATIVE-FIXNUM", from_fixnum(Fixnum::minimum) },
{ "MOST-POSITIVE-FIXNUM", from_fixnum(Fixnum::maximum) },
};
static void define_special_constants(Evaluator* ctx) {
auto core = ctx->core_package();
for (auto& x : value_constants) {
auto sym = core->make_symbol(ctx->intern(x.name));
sym->value = x.value;
sym->attributes = SymbolAttribute::SpecialConstant;
}
}
Unimplemented::Unimplemented(const std::string& s)
: BasicError(s)
{ }
IntegerOverflow::IntegerOverflow(const std::string& s)
: BasicError(s)
{ }
std::string
show(Value v) {
std::ostringstream os;
format(v, os);
return os.str();
}
Fixnum
retract_to_fixnum(Value v) {
if (not is<Fixnum>(v))
throw Diagnostics::BasicError(show(v) + " is not a fixnum");
return to_fixnum(v);
}
Pair
retract_to_pair(Value v) {
if (not is<Pair>(v))
throw Diagnostics::BasicError(show(v) + " is not a pair");
return to_pair(v);
}
static void
unimplemented(const Sexpr::Syntax& x) {
std::string s = "unimplemented eval for ";
throw Unimplemented{ s + typeid(x).name() };
}
static void
integer_too_large(const Sexpr::IntegerSyntax& x) {
std::string s { x.lexeme().begin(), x.lexeme().end() };
throw IntegerOverflow{ s + " is too large for Fixnum; max value is "
+ std::to_string(FixnumBits(Fixnum::maximum)) };
}
constexpr auto fixmax_by_ten = FixnumBits(Fixnum::maximum) / 10;
constexpr auto fixmax_lsd = FixnumBits(Fixnum::maximum) % 10;
static Value
construct(Evaluator* ctx, const Sexpr::IntegerSyntax& x) {
bool neg = false;
auto cur = x.lexeme().begin();
FixnumBits val = 0;
switch (*cur) {
case '-': neg = true;
case '+': ++cur;
default:
for (; cur < x.lexeme().end(); ++cur) {
auto d = *cur - '0';
if (val < fixmax_by_ten)
val = 10 * val + d;
else if (val > fixmax_by_ten or d > fixmax_lsd)
integer_too_large(x);
else
val = 10 * val + d;
}
if (neg) {
if (val > FixnumBits(Fixnum::maximum))
integer_too_large(x);
val = -val;
}
}
return VM::from_fixnum(Fixnum(val));
}
static Value
construct(Evaluator* ctx, const Sexpr::ListSyntax& x) {
if (x.empty())
return Value::nil;
auto result = Value::nil;
auto p = x.rbegin();
if (x.dotted())
result = ctx->make_value(*p++);
while (p != x.rend())
result = from_pair(ctx->make_pair(ctx->make_value(*p++), result));
return result;
}
static Value
construct(Evaluator* ctx, const Sexpr::StringSyntax& x) {
auto s = ctx->intern(x.lexeme().begin(), x.lexeme().size());
return from_string(s);
}
static Value
construct(Evaluator* ctx, const Sexpr::SymbolSyntax& x) {
auto s = ctx->intern(x.lexeme().begin(), x.lexeme().size());
switch (x.kind()) {
case Sexpr::SymbolSyntax::uninterned:
return to_value(ctx->homeless_package()->make_symbol(s));
case Sexpr::SymbolSyntax::keyword:
return to_value(ctx->make_keyword(s));
default:
return to_value(ctx->current_package()->make_symbol(s));
}
}
VM::Value
Evaluator::make_value(const Sexpr::Syntax* x) {
using namespace Sexpr;
struct V : Sexpr::Syntax::Visitor {
Evaluator* ctx;
Value result;
V(Evaluator* e) : ctx(e), result(Value::nil) { }
void visit(const IntegerSyntax& x) { result = construct(ctx, x); }
void visit(const CharacterSyntax& x) { unimplemented(x); }
void visit(const StringSyntax& x) { result = construct(ctx, x); }
void visit(const SymbolSyntax& x) { result = construct(ctx, x); }
void visit(const ReferenceSyntax& x) {
auto p = ctx->anchor_map.find(x.tag());
if (p == ctx->anchor_map.end())
throw Diagnostics::BasicError{ "undefined anchor "
+ std::to_string(x.tag())
};
result = p->second;
}
void visit(const AnchorSyntax& x) {
auto& v = ctx->anchor_map[x.ref()];
if (v != Value::nil)
throw Diagnostics::BasicError{
"duplicate anchor " + std::to_string(x.ref())
};
result = v = ctx->make_value(x.value());
}
void visit(const QuoteSyntax& x) { unimplemented(x); }
void visit(const AntiquoteSyntax& x) { unimplemented(x); }
void visit(const Expand& x) { unimplemented(x); }
void visit(const Eval& x) { unimplemented(x); }
void visit(const Splice& x) { unimplemented(x); }
void visit(const Function& x) { unimplemented(x); }
void visit(const Include& x) { unimplemented(x); }
void visit(const Exclude& x) { unimplemented(x); }
void visit(const ListSyntax& x) { result = construct(ctx, x); }
void visit(const VectorSyntax& x) { unimplemented(x); }
};
if (x == nullptr)
return Value::nil;
V v { this };
x->accept(v);
return v.result;
}
static std::string
canonical_name(const Sexpr::SymbolSyntax& x) {
if (x.kind() & Sexpr::SymbolSyntax::absolute)
return { x.begin(), x.end() };
const auto sz = x.size();
std::string s(sz, char{ });
for (std::size_t i = 0; i < sz; ++i)
s[i] = toupper(x[i]);
return s;
}
static Symbol*
retrieve_symbol(Evaluator* ctx, const Sexpr::SymbolSyntax& x) {
const auto s = canonical_name(x);
auto name = ctx->intern(s.c_str());
if (x.kind() & Sexpr::SymbolSyntax::keyword)
return ctx->make_keyword(name);
else if (x.kind() & Sexpr::SymbolSyntax::uninterned)
unbound_symbol_error(s);
else if (auto symbol = ctx->current_package()->find_symbol(name))
return symbol;
unbound_symbol_error(s);
return nullptr;
}
static Value
evaluate(Evaluator* ctx, const Sexpr::SymbolSyntax& x) {
const auto s = canonical_name(x);
auto name = ctx->intern(s.c_str());
if (x.kind() & Sexpr::SymbolSyntax::keyword)
return to_value(ctx->make_keyword(name));
else if (x.kind() & Sexpr::SymbolSyntax::uninterned)
unbound_symbol_error(s);
else if (auto p = ctx->lexical_binding(name))
return *p;
auto symbol = ctx->current_package()->find_symbol(name);
if (symbol == nullptr or not symbol->has(SymbolAttribute::Special))
unbound_symbol_error(s);
return symbol->value;
}
static const Callable*
symbol_function(Evaluator* ctx, const Sexpr::SymbolSyntax& s) {
auto sym = retrieve_symbol(ctx, s);
if (sym->function == nullptr)
unbound_function_symbol_error(sym);
return sym->function;
}
static Value
evaluate(Evaluator* ctx, const Sexpr::Function& x) {
auto s = dynamic_cast<const Sexpr::SymbolSyntax*>(x.body());
if (s == nullptr)
throw Unimplemented("FUNCTION of non-symbol expression");
return to_value(symbol_function(ctx, *s));
}
static Value
evaluate(Evaluator* ctx, const Sexpr::QuoteSyntax& x) {
return ctx->make_value(x.body());
}
using SpecialOperator = Value (*)(Evaluator*, const Sexpr::Syntax&);
const NamedConstant<SpecialOperator> special_ops[] = {
};
static SpecialOperator
special_operator(const Sexpr::SymbolSyntax& s) {
auto name = canonical_name(s);
for (auto& x : special_ops) {
if (x.name == name)
return x.value;
}
return nullptr;
}
static Value
evaluate(Evaluator* ctx, const Sexpr::ListSyntax& x) {
if (x.empty())
return Value::nil;
auto s = dynamic_cast<const Sexpr::SymbolSyntax*>(x.front());
if (s == nullptr)
unimplemented(x);
if (auto op = special_operator(*s))
return op(ctx, x);
auto fun = symbol_function(ctx, *s);
}
Value
Evaluator::eval(const Sexpr::Syntax* x) {
using namespace Sexpr;
struct V : Syntax::Visitor {
Evaluator* ctx;
Value result;
V(Evaluator* e) : ctx(e), result(Value::nil) { }
void visit(const IntegerSyntax& x) { result = construct(ctx, x); }
void visit(const CharacterSyntax& x) { unimplemented(x); }
void visit(const StringSyntax& x) { result = construct(ctx, x); }
void visit(const SymbolSyntax& x) { result = evaluate(ctx, x); }
void visit(const ReferenceSyntax& x) { unimplemented(x); }
void visit(const AnchorSyntax& x) { unimplemented(x); }
void visit(const QuoteSyntax& x) { result = evaluate(ctx, x); }
void visit(const AntiquoteSyntax& x) { unimplemented(x); }
void visit(const Expand& x) { unimplemented(x); }
void visit(const Eval& x) { unimplemented(x); }
void visit(const Splice& x) { unimplemented(x); }
void visit(const Function& x) { result = evaluate(ctx, x); }
void visit(const Include& x) { unimplemented(x); }
void visit(const Exclude& x) { unimplemented(x); }
void visit(const ListSyntax& x) { result = evaluate(ctx, x); }
void visit(const VectorSyntax& x) { unimplemented(x); }
};
if (x == nullptr)
return Value::nil;
V v { this };
x->accept(v);
return v.result;
}
Value*
Evaluator::lexical_binding(String name) {
if (env_stack.empty())
return nullptr;
else if (auto b = env_stack.back().lookup(name))
return &b->value;
return nullptr;
}
Value
Evaluator::toplevel_form(const Sexpr::Syntax* x) {
auto anchors = std::move(anchor_map);
anchor_map = AnchorTable{ };
auto v = make_value(x);
anchor_map = std::move(anchors);
return v;
}
template<typename... Ts>
using Operation = Value (*)(Ts...);
template<Operation<Value> fun>
RuntimeOperation<Value> runtime() {
return [](BasicContext*, Value x) { return fun(x); };
}
const NamedConstant<UnaryCode> unary_builtins[] = {
{ "CONSP", runtime<consp>() },
{ "ATOM", runtime<atom>() },
{ "SYMBOLP", runtime<symbolp>() },
{ "KEYWORDP", runtime<keywordp>() },
};
template<typename T>
static void
define_builtin_operator(Evaluator* ctx, const char* s, T t) {
auto name = ctx->intern(s);
auto sym = ctx->current_package()->make_symbol(name);
sym->function = ctx->make_operator(sym, t);
}
static void
define_builtin_operators(Evaluator* ctx) {
for (auto& x : unary_builtins)
define_builtin_operator(ctx, x.name, x.value);
}
static Symbol*
make_special_symbol(Evaluator* ctx, const char* s) {
auto name = ctx->intern(s);
auto sym = ctx->current_package()->make_symbol(name);
sym->attributes = SymbolAttribute::Special;
return sym;
}
static Symbol*
define_features(Evaluator* ctx) {
auto sym = make_special_symbol(ctx, "*FEATURES*");
sym->value = Value::nil;
return sym;
}
static void
define_current_package(Evaluator* ctx) {
auto sym = make_special_symbol(ctx, "*PACKAGE*");
sym->value = to_value(ctx->current_package());
}
Evaluator::Evaluator()
: core(make_package(intern("AxiomCore"))),
ns(core),
feature_list(define_features(this))
{
define_special_constants(this);
define_builtin_operators(this);
define_current_package(this);
env_stack.push_back(Environment{ });
}
Environment*
Evaluator::global_environment() {
return &env_stack.front();
}
static void format(Pair p, std::ostream& os) {
os << '(';
while (true) {
format(p->head, os);
auto v = p->tail;
if (v == Value::nil)
break;
os << ' ';
if (auto q = to_pair_if_can(v)) {
p = q;
continue;
}
os << '.' << ' ';
format(v, os);
break;
}
os << ')';
}
static void format(String s, std::ostream& os) {
os << '"';
for (auto c : *s) {
if (c == '"')
os << '\\';
os << char(c);
}
os << '"';
}
static void format(const Dynamic*, std::ostream&);
void format(Value v, std::ostream& os) {
if (v == Value::nil)
os << "NIL";
else if (v == Value::t)
os << "T";
else if (is<Fixnum>(v))
os << FixnumBits(to_fixnum(v));
else if (is<Pair>(v))
format(to_pair(v), os);
else if (is<String>(v))
format(to_string(v), os);
else if (is<Dynamic>(v))
format(to_dynamic(v), os);
else
os << "#<unprintable>";
}
static void format(const Dynamic* x, std::ostream& os) {
struct V : Dynamic::Visitor {
std::ostream& os;
V(std::ostream& s) : os(s) { }
void visit(const Symbol& s) {
std::copy(s.name->begin(), s.name->end(),
std::ostream_iterator<char>(os));
}
void visit(const Package& p) {
os << "#<PACKAGE ";
std::copy(p.name->begin(), p.name->end(),
std::ostream_iterator<char>(os));
os << '>';
}
void visit(const FunctionBase& f) {
os << "#<FUNCTION ";
visit(*f.name);
os << '>';
}
void visit(const Binding& b) {
os << '(';
visit(*b.symbol);
os << ' ';
format(b.value, os);
os << ')';
}
};
V v { os };
x->accept(v);
}
Value assoc(Value key, Pair al) {
while (al != nullptr) {
auto entry = retract_to_pair(al->head);
if (entry->head == key)
return entry->tail;
else if (al->tail == Value::nil)
return Value::nil;
al = retract_to_pair(al->tail);
}
return Value::nil;
}
}
}