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; } }