Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

open-axiom repository from github

24005 views
1
// Copyright (C) 2013-2014, Gabriel Dos Reis.
2
// All rights reserved.
3
// Written by Gabriel Dos Reis.
4
//
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions are
7
// met:
8
//
9
// - Redistributions of source code must retain the above copyright
10
// notice, this list of conditions and the following disclaimer.
11
//
12
// - Redistributions in binary form must reproduce the above copyright
13
// notice, this list of conditions and the following disclaimer in
14
// the documentation and/or other materials provided with the
15
// distribution.
16
//
17
// - Neither the name of OpenAxiom nor the names of its contributors
18
// may be used to endorse or promote products derived from this
19
// software without specific prior written permission.
20
//
21
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33
#include <open-axiom/Lisp>
34
#include <typeinfo>
35
#include <ostream>
36
#include <sstream>
37
38
namespace OpenAxiom {
39
namespace Lisp {
40
// -- UnboundSymbol
41
UnboundSymbol::UnboundSymbol(const std::string& s)
42
: BasicError(s)
43
{ }
44
45
static void unbound_symbol_error(const std::string& s) {
46
throw UnboundSymbol(s + " has no value binding");
47
}
48
49
50
// -- UnboundFunctiom
51
UnboundFunctionSymbol::UnboundFunctionSymbol(const std::string& s)
52
: BasicError(s)
53
{ }
54
55
static void unbound_function_symbol_error(const Symbol* sym) {
56
std::string s { sym->name->begin(), sym->name->end() };
57
throw UnboundFunctionSymbol(s + " has no function definition");
58
}
59
60
namespace {
61
template<typename T>
62
struct NamedConstant {
63
const char* const name;
64
const T value;
65
};
66
}
67
68
constexpr NamedConstant<Value> value_constants[] = {
69
{ "NIL", Value::nil },
70
{ "T", Value::t },
71
{ "MOST-NEGATIVE-FIXNUM", from_fixnum(Fixnum::minimum) },
72
{ "MOST-POSITIVE-FIXNUM", from_fixnum(Fixnum::maximum) },
73
};
74
75
static void define_special_constants(Evaluator* ctx) {
76
auto core = ctx->core_package();
77
for (auto& x : value_constants) {
78
auto sym = core->make_symbol(ctx->intern(x.name));
79
sym->value = x.value;
80
sym->attributes = SymbolAttribute::SpecialConstant;
81
}
82
}
83
84
Unimplemented::Unimplemented(const std::string& s)
85
: BasicError(s)
86
{ }
87
88
IntegerOverflow::IntegerOverflow(const std::string& s)
89
: BasicError(s)
90
{ }
91
92
std::string
93
show(Value v) {
94
std::ostringstream os;
95
format(v, os);
96
return os.str();
97
}
98
99
Fixnum
100
retract_to_fixnum(Value v) {
101
if (not is<Fixnum>(v))
102
throw Diagnostics::BasicError(show(v) + " is not a fixnum");
103
return to_fixnum(v);
104
}
105
106
Pair
107
retract_to_pair(Value v) {
108
if (not is<Pair>(v))
109
throw Diagnostics::BasicError(show(v) + " is not a pair");
110
return to_pair(v);
111
}
112
113
114
static void
115
unimplemented(const Sexpr::Syntax& x) {
116
std::string s = "unimplemented eval for ";
117
throw Unimplemented{ s + typeid(x).name() };
118
}
119
120
static void
121
integer_too_large(const Sexpr::IntegerSyntax& x) {
122
std::string s { x.lexeme().begin(), x.lexeme().end() };
123
throw IntegerOverflow{ s + " is too large for Fixnum; max value is "
124
+ std::to_string(FixnumBits(Fixnum::maximum)) };
125
}
126
127
constexpr auto fixmax_by_ten = FixnumBits(Fixnum::maximum) / 10;
128
constexpr auto fixmax_lsd = FixnumBits(Fixnum::maximum) % 10;
129
130
static Value
131
construct(Evaluator* ctx, const Sexpr::IntegerSyntax& x) {
132
bool neg = false;
133
auto cur = x.lexeme().begin();
134
FixnumBits val = 0;
135
switch (*cur) {
136
case '-': neg = true;
137
case '+': ++cur;
138
default:
139
for (; cur < x.lexeme().end(); ++cur) {
140
auto d = *cur - '0';
141
if (val < fixmax_by_ten)
142
val = 10 * val + d;
143
else if (val > fixmax_by_ten or d > fixmax_lsd)
144
integer_too_large(x);
145
else
146
val = 10 * val + d;
147
}
148
if (neg) {
149
if (val > FixnumBits(Fixnum::maximum))
150
integer_too_large(x);
151
val = -val;
152
}
153
}
154
return VM::from_fixnum(Fixnum(val));
155
}
156
157
static Value
158
construct(Evaluator* ctx, const Sexpr::ListSyntax& x) {
159
if (x.empty())
160
return Value::nil;
161
auto result = Value::nil;
162
auto p = x.rbegin();
163
if (x.dotted())
164
result = ctx->make_value(*p++);
165
while (p != x.rend())
166
result = from_pair(ctx->make_pair(ctx->make_value(*p++), result));
167
return result;
168
}
169
170
static Value
171
construct(Evaluator* ctx, const Sexpr::StringSyntax& x) {
172
auto s = ctx->intern(x.lexeme().begin(), x.lexeme().size());
173
return from_string(s);
174
}
175
176
static Value
177
construct(Evaluator* ctx, const Sexpr::SymbolSyntax& x) {
178
auto s = ctx->intern(x.lexeme().begin(), x.lexeme().size());
179
switch (x.kind()) {
180
case Sexpr::SymbolSyntax::uninterned:
181
return to_value(ctx->homeless_package()->make_symbol(s));
182
183
case Sexpr::SymbolSyntax::keyword:
184
return to_value(ctx->make_keyword(s));
185
186
default:
187
return to_value(ctx->current_package()->make_symbol(s));
188
}
189
}
190
191
VM::Value
192
Evaluator::make_value(const Sexpr::Syntax* x) {
193
using namespace Sexpr;
194
struct V : Sexpr::Syntax::Visitor {
195
Evaluator* ctx;
196
Value result;
197
V(Evaluator* e) : ctx(e), result(Value::nil) { }
198
void visit(const IntegerSyntax& x) { result = construct(ctx, x); }
199
void visit(const CharacterSyntax& x) { unimplemented(x); }
200
void visit(const StringSyntax& x) { result = construct(ctx, x); }
201
void visit(const SymbolSyntax& x) { result = construct(ctx, x); }
202
void visit(const ReferenceSyntax& x) {
203
auto p = ctx->anchor_map.find(x.tag());
204
if (p == ctx->anchor_map.end())
205
throw Diagnostics::BasicError{ "undefined anchor "
206
+ std::to_string(x.tag())
207
};
208
result = p->second;
209
}
210
void visit(const AnchorSyntax& x) {
211
auto& v = ctx->anchor_map[x.ref()];
212
if (v != Value::nil)
213
throw Diagnostics::BasicError{
214
"duplicate anchor " + std::to_string(x.ref())
215
};
216
result = v = ctx->make_value(x.value());
217
}
218
void visit(const QuoteSyntax& x) { unimplemented(x); }
219
void visit(const AntiquoteSyntax& x) { unimplemented(x); }
220
void visit(const Expand& x) { unimplemented(x); }
221
void visit(const Eval& x) { unimplemented(x); }
222
void visit(const Splice& x) { unimplemented(x); }
223
void visit(const Function& x) { unimplemented(x); }
224
void visit(const Include& x) { unimplemented(x); }
225
void visit(const Exclude& x) { unimplemented(x); }
226
void visit(const ListSyntax& x) { result = construct(ctx, x); }
227
void visit(const VectorSyntax& x) { unimplemented(x); }
228
};
229
230
if (x == nullptr)
231
return Value::nil;
232
V v { this };
233
x->accept(v);
234
return v.result;
235
}
236
237
static std::string
238
canonical_name(const Sexpr::SymbolSyntax& x) {
239
if (x.kind() & Sexpr::SymbolSyntax::absolute)
240
return { x.begin(), x.end() };
241
const auto sz = x.size();
242
std::string s(sz, char{ });
243
for (std::size_t i = 0; i < sz; ++i)
244
s[i] = toupper(x[i]);
245
return s;
246
}
247
248
// Return the (global) symbol value
249
static Symbol*
250
retrieve_symbol(Evaluator* ctx, const Sexpr::SymbolSyntax& x) {
251
const auto s = canonical_name(x);
252
auto name = ctx->intern(s.c_str());
253
if (x.kind() & Sexpr::SymbolSyntax::keyword)
254
return ctx->make_keyword(name);
255
// Note: Uninterned symbols are always distincts;
256
else if (x.kind() & Sexpr::SymbolSyntax::uninterned)
257
unbound_symbol_error(s);
258
// FIXME: if this is a qualified symbol, lookup in its home.
259
else if (auto symbol = ctx->current_package()->find_symbol(name))
260
return symbol;
261
unbound_symbol_error(s);
262
return nullptr;
263
}
264
265
// Return the value designated by this symbol.
266
static Value
267
evaluate(Evaluator* ctx, const Sexpr::SymbolSyntax& x) {
268
const auto s = canonical_name(x);
269
auto name = ctx->intern(s.c_str());
270
if (x.kind() & Sexpr::SymbolSyntax::keyword)
271
return to_value(ctx->make_keyword(name));
272
else if (x.kind() & Sexpr::SymbolSyntax::uninterned)
273
unbound_symbol_error(s);
274
else if (auto p = ctx->lexical_binding(name))
275
return *p;
276
auto symbol = ctx->current_package()->find_symbol(name);
277
if (symbol == nullptr or not symbol->has(SymbolAttribute::Special))
278
unbound_symbol_error(s);
279
return symbol->value;
280
}
281
282
// Return the denotation of a sharp-apostrophe syntax.
283
284
static const Callable*
285
symbol_function(Evaluator* ctx, const Sexpr::SymbolSyntax& s) {
286
auto sym = retrieve_symbol(ctx, s);
287
if (sym->function == nullptr)
288
unbound_function_symbol_error(sym);
289
return sym->function;
290
}
291
292
static Value
293
evaluate(Evaluator* ctx, const Sexpr::Function& x) {
294
auto s = dynamic_cast<const Sexpr::SymbolSyntax*>(x.body());
295
if (s == nullptr)
296
throw Unimplemented("FUNCTION of non-symbol expression");
297
return to_value(symbol_function(ctx, *s));
298
}
299
300
static Value
301
evaluate(Evaluator* ctx, const Sexpr::QuoteSyntax& x) {
302
return ctx->make_value(x.body());
303
}
304
305
// -- special operators
306
using SpecialOperator = Value (*)(Evaluator*, const Sexpr::Syntax&);
307
const NamedConstant<SpecialOperator> special_ops[] = {
308
};
309
310
static SpecialOperator
311
special_operator(const Sexpr::SymbolSyntax& s) {
312
auto name = canonical_name(s);
313
for (auto& x : special_ops) {
314
if (x.name == name)
315
return x.value;
316
}
317
return nullptr;
318
}
319
320
static Value
321
evaluate(Evaluator* ctx, const Sexpr::ListSyntax& x) {
322
if (x.empty())
323
return Value::nil;
324
auto s = dynamic_cast<const Sexpr::SymbolSyntax*>(x.front());
325
if (s == nullptr)
326
// FIXME: real error
327
unimplemented(x);
328
if (auto op = special_operator(*s))
329
return op(ctx, x);
330
auto fun = symbol_function(ctx, *s);
331
}
332
333
Value
334
Evaluator::eval(const Sexpr::Syntax* x) {
335
using namespace Sexpr;
336
struct V : Syntax::Visitor {
337
Evaluator* ctx;
338
Value result;
339
V(Evaluator* e) : ctx(e), result(Value::nil) { }
340
void visit(const IntegerSyntax& x) { result = construct(ctx, x); }
341
void visit(const CharacterSyntax& x) { unimplemented(x); }
342
void visit(const StringSyntax& x) { result = construct(ctx, x); }
343
void visit(const SymbolSyntax& x) { result = evaluate(ctx, x); }
344
void visit(const ReferenceSyntax& x) { unimplemented(x); }
345
void visit(const AnchorSyntax& x) { unimplemented(x); }
346
void visit(const QuoteSyntax& x) { result = evaluate(ctx, x); }
347
void visit(const AntiquoteSyntax& x) { unimplemented(x); }
348
void visit(const Expand& x) { unimplemented(x); }
349
void visit(const Eval& x) { unimplemented(x); }
350
void visit(const Splice& x) { unimplemented(x); }
351
void visit(const Function& x) { result = evaluate(ctx, x); }
352
void visit(const Include& x) { unimplemented(x); }
353
void visit(const Exclude& x) { unimplemented(x); }
354
void visit(const ListSyntax& x) { result = evaluate(ctx, x); }
355
void visit(const VectorSyntax& x) { unimplemented(x); }
356
};
357
358
if (x == nullptr)
359
return Value::nil;
360
V v { this };
361
x->accept(v);
362
return v.result;
363
}
364
365
Value*
366
Evaluator::lexical_binding(String name) {
367
if (env_stack.empty())
368
return nullptr;
369
else if (auto b = env_stack.back().lookup(name))
370
return &b->value;
371
return nullptr;
372
}
373
374
Value
375
Evaluator::toplevel_form(const Sexpr::Syntax* x) {
376
auto anchors = std::move(anchor_map);
377
anchor_map = AnchorTable{ };
378
auto v = make_value(x);
379
anchor_map = std::move(anchors);
380
return v;
381
}
382
383
template<typename... Ts>
384
using Operation = Value (*)(Ts...);
385
386
template<Operation<Value> fun>
387
RuntimeOperation<Value> runtime() {
388
return [](BasicContext*, Value x) { return fun(x); };
389
}
390
391
const NamedConstant<UnaryCode> unary_builtins[] = {
392
{ "CONSP", runtime<consp>() },
393
{ "ATOM", runtime<atom>() },
394
{ "SYMBOLP", runtime<symbolp>() },
395
{ "KEYWORDP", runtime<keywordp>() },
396
};
397
398
template<typename T>
399
static void
400
define_builtin_operator(Evaluator* ctx, const char* s, T t) {
401
auto name = ctx->intern(s);
402
auto sym = ctx->current_package()->make_symbol(name);
403
sym->function = ctx->make_operator(sym, t);
404
}
405
406
static void
407
define_builtin_operators(Evaluator* ctx) {
408
for (auto& x : unary_builtins)
409
define_builtin_operator(ctx, x.name, x.value);
410
}
411
412
static Symbol*
413
make_special_symbol(Evaluator* ctx, const char* s) {
414
auto name = ctx->intern(s);
415
auto sym = ctx->current_package()->make_symbol(name);
416
sym->attributes = SymbolAttribute::Special;
417
return sym;
418
}
419
420
static Symbol*
421
define_features(Evaluator* ctx) {
422
auto sym = make_special_symbol(ctx, "*FEATURES*");
423
sym->value = Value::nil;
424
return sym;
425
}
426
427
static void
428
define_current_package(Evaluator* ctx) {
429
auto sym = make_special_symbol(ctx, "*PACKAGE*");
430
sym->value = to_value(ctx->current_package());
431
}
432
433
Evaluator::Evaluator()
434
: core(make_package(intern("AxiomCore"))),
435
ns(core),
436
feature_list(define_features(this))
437
{
438
define_special_constants(this);
439
define_builtin_operators(this);
440
define_current_package(this);
441
env_stack.push_back(Environment{ });
442
}
443
444
Environment*
445
Evaluator::global_environment() {
446
return &env_stack.front();
447
}
448
449
450
// -- Formatting
451
452
static void format(Pair p, std::ostream& os) {
453
os << '(';
454
while (true) {
455
format(p->head, os);
456
auto v = p->tail;
457
if (v == Value::nil)
458
break;
459
os << ' ';
460
if (auto q = to_pair_if_can(v)) {
461
p = q;
462
continue;
463
}
464
os << '.' << ' ';
465
format(v, os);
466
break;
467
}
468
os << ')';
469
}
470
471
static void format(String s, std::ostream& os) {
472
os << '"';
473
for (auto c : *s) {
474
if (c == '"')
475
os << '\\';
476
os << char(c);
477
}
478
os << '"';
479
}
480
481
static void format(const Dynamic*, std::ostream&);
482
483
void format(Value v, std::ostream& os) {
484
if (v == Value::nil)
485
os << "NIL";
486
else if (v == Value::t)
487
os << "T";
488
else if (is<Fixnum>(v))
489
os << FixnumBits(to_fixnum(v));
490
else if (is<Pair>(v))
491
format(to_pair(v), os);
492
else if (is<String>(v))
493
format(to_string(v), os);
494
else if (is<Dynamic>(v))
495
format(to_dynamic(v), os);
496
else
497
os << "#<unprintable>";
498
}
499
500
static void format(const Dynamic* x, std::ostream& os) {
501
struct V : Dynamic::Visitor {
502
std::ostream& os;
503
V(std::ostream& s) : os(s) { }
504
void visit(const Symbol& s) {
505
// FIXME: handle escapes.
506
std::copy(s.name->begin(), s.name->end(),
507
std::ostream_iterator<char>(os));
508
}
509
void visit(const Package& p) {
510
os << "#<PACKAGE ";
511
std::copy(p.name->begin(), p.name->end(),
512
std::ostream_iterator<char>(os));
513
os << '>';
514
}
515
void visit(const FunctionBase& f) {
516
os << "#<FUNCTION ";
517
visit(*f.name);
518
os << '>';
519
}
520
void visit(const Binding& b) {
521
os << '(';
522
visit(*b.symbol);
523
os << ' ';
524
format(b.value, os);
525
os << ')';
526
}
527
};
528
529
V v { os };
530
x->accept(v);
531
}
532
533
// -- assoc: (T, List Pair(T, S)) -> S
534
Value assoc(Value key, Pair al) {
535
while (al != nullptr) {
536
auto entry = retract_to_pair(al->head);
537
if (entry->head == key)
538
return entry->tail;
539
else if (al->tail == Value::nil)
540
return Value::nil;
541
al = retract_to_pair(al->tail);
542
}
543
return Value::nil;
544
}
545
}
546
}
547
548