#include #include #include #include "error.h" #include "prelude.h" #include "sugar.h" using namespace std; Environment prelude; const AST afterBootstrap=AST(R"RAW( (do (def '. \f \g \x (f (g x))) (def 'flip \f \a \b (f b a)) (def 'id \x x) (def 'const \x \y x) (def 'print (. putstr repr)) (def '$ \f \x (f x)) (def 'last \l (if (nil (tail l)) (head l) (last (tail l)))) (def 'init \l (if (nil (tail l)) '() (cons (head l) (init (tail l)))))) )RAW"); static AST dofunction(const AST&); const AST doNative=AST::makeNative(dofunction); static AST dofunction(const AST&){ return doNative; } const AST chooseFirstLambda=AST::makeLambda("",AST::makeLambda("",AST::makeIndex(2))); const AST chooseSecondLambda=AST::makeLambda("",AST::makeLambda("",AST::makeIndex(1))); class PreludeInit{ public: PreludeInit(Environment &intoEnv){ intoEnv.define("repr",AST::makeNative([](const AST &ast) -> AST { stringstream ss; ss< AST {cout< AST { env.define(arg1.nameval,arg2); return AST(); })); intoEnv.define("do",doNative); intoEnv.define("unquote",AST::makeNative([](const AST &ast) -> AST { AST res(ast); res.quoted=false; return res; })); intoEnv.define("head",checkedHook("head",{AST::Type::tuple}, [](Environment&,const AST &arg) -> AST { if(arg.terms.size()==0){ throw FormError("Empty tuple in 'head'"); } AST res=arg.terms[0]; if(arg.quoted){ res.quoted=true; } return res; })); intoEnv.define("tail",checkedHook("tail",{AST::Type::tuple}, [](Environment&,const AST &arg) -> AST { if(arg.terms.size()==0){ throw FormError("Empty tuple in 'tail'"); } AST res=AST::makeTuple(Terms(arg.terms.begin()+1,arg.terms.end())); if(arg.quoted){ res.quoted=true; } return res; })); intoEnv.define("cons",checkedHook("cons",{},{AST::Type::tuple}, [](Environment&,const AST &arg1,const AST &arg2) -> AST { AST res(arg2); res.terms.insert(res.terms.begin(),arg1); return res; })); intoEnv.define("nil",checkedHook("nil",{AST::Type::tuple}, [](Environment&,const AST &arg) -> AST { return AST::makeNumber(arg.terms.size()==0); })); intoEnv.define("not",checkedHook("not",{AST::Type::number}, [](Environment&,const AST &arg) -> AST { return AST::makeNumber(arg.numval==0); })); intoEnv.define("if",checkedHook("if",{AST::Type::number}, [](Environment&,const AST &arg) -> AST { if(arg.numval!=0){ return chooseFirstLambda; } else { return chooseSecondLambda; } })); intoEnv.define("+",checkedHook("+",{AST::Type::number,AST::Type::string}, {AST::Type::number,AST::Type::string}, [](Environment&,const AST &arg1,const AST &arg2) -> AST { if(arg1.type!=arg2.type){ throw TypeError("Unequal types in '+'"); } if(arg1.type==AST::Type::number){ return AST::makeNumber(arg1.numval+arg2.numval); } else { return AST::makeString(arg1.strval+arg2.strval); } })); intoEnv.define("-",checkedHook("-",{AST::Type::number},{AST::Type::number}, [](Environment&,const AST &arg1,const AST &arg2) -> AST { return AST::makeNumber(arg1.numval-arg2.numval); })); intoEnv.define("*",checkedHook("*",{AST::Type::number},{AST::Type::number}, [](Environment&,const AST &arg1,const AST &arg2) -> AST { return AST::makeNumber(arg1.numval*arg2.numval); })); intoEnv.define("/",checkedHook("/",{AST::Type::number},{AST::Type::number}, [](Environment&,const AST &arg1,const AST &arg2) -> AST { return AST::makeNumber(arg1.numval/arg2.numval); })); intoEnv.define("%",checkedHook("%",{AST::Type::number},{AST::Type::number}, [](Environment&,const AST &arg1,const AST &arg2) -> AST { return AST::makeNumber(arg1.numval%arg2.numval); })); intoEnv.define("=",checkedHook("=",{AST::Type::number,AST::Type::string}, {AST::Type::number,AST::Type::string}, [](Environment&,const AST &arg1,const AST &arg2) -> AST { return AST::makeNumber(arg1.type==arg2.type&&arg1.numval==arg2.numval); })); intoEnv.run(afterBootstrap); } } preludeInit(prelude);