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.
65 lines
1.9 KiB
65 lines
1.9 KiB
3 years ago
|
import { DataTypes, Cons, Nil } from './datatypes.js';
|
||
|
import { Env } from './env.js';
|
||
|
|
||
|
export class Evaluator {
|
||
|
static async expand(sexp, macros) {
|
||
|
if (sexp.type === DataTypes.Cons) {
|
||
|
const op = await Evaluator.expand(sexp.car, macros)
|
||
|
if (op.type === DataTypes.SpecialForm) {
|
||
|
return await op.value(sexp.cdr, macros, macros);
|
||
|
} else if (op.type === DataTypes.Macro) {
|
||
|
return await op.value(
|
||
|
await Cons.map(sexp.cdr,
|
||
|
async o => await Evaluator.expand(o, macros)));
|
||
|
// return (sexp.cdr.type === DataTypes.Nil
|
||
|
// ? sexp.cdr
|
||
|
// : Cons.reverse(await Cons.reduce(
|
||
|
// sexp.cdr,
|
||
|
// (p, o) => new Cons(await Evaluator.expand(o, macros), p),
|
||
|
// new Nil())))
|
||
|
// .then(opts => op.value(opts));
|
||
|
} else if (sexp.type === DataTypes.Symbol) {
|
||
|
return Env.find(macros, sexp.value) || sexp;
|
||
|
}
|
||
|
|
||
|
return sexp;
|
||
|
}
|
||
|
|
||
|
if (sexp.type === DataTypes.Symbol) {
|
||
|
return Env.find(macros, sexp.value) || sexp;
|
||
|
}
|
||
|
|
||
|
return sexp;
|
||
|
}
|
||
|
|
||
|
static async eval(sexp, env, macros) {
|
||
|
sexp = await Evaluator.expand(sexp, macros)
|
||
|
if (sexp.type === DataTypes.Cons) {
|
||
|
const op = await Evaluator.eval(sexp.car, env, macros)
|
||
|
if (op.type === DataTypes.SpecialForm) {
|
||
|
return await op.value(sexp.cdr, env, macros);
|
||
|
} else if (op.type === DataTypes.Function) {
|
||
|
return await op.value(await Cons.map(sexp.cdr, async o => Evaluator.eval(o, env, macros)));
|
||
|
// return (sexp.cdr.type === DataTypes.Nil
|
||
|
// ? Promise.resolve(sexp.cdr)
|
||
|
// : Cons.reduce(
|
||
|
// sexp.cdr,
|
||
|
// (p, o) => p.then(v => Evaluator.eval(o, env, macros)
|
||
|
// .then(ve => new Cons(ve, v))),
|
||
|
// Promise.resolve(new Nil()))
|
||
|
// .then(v => Cons.reverse(v)))
|
||
|
// .then(opts => op.value(opts));
|
||
|
}
|
||
|
|
||
|
throw 'Illegal function call';
|
||
|
}
|
||
|
|
||
|
if (sexp.type === DataTypes.Symbol) {
|
||
|
return Env.get(env, sexp.value);
|
||
|
}
|
||
|
|
||
|
return sexp;
|
||
|
|
||
|
}
|
||
|
}
|