diff options
-rw-r--r-- | environment.cpp | 25 | ||||
-rw-r--r-- | environment.h | 1 | ||||
-rw-r--r-- | prelude.cpp | 30 |
3 files changed, 40 insertions, 16 deletions
diff --git a/environment.cpp b/environment.cpp index b38d73b..e375353 100644 --- a/environment.cpp +++ b/environment.cpp @@ -146,6 +146,11 @@ static void singlify(AST &ast){ } bool Environment::resolve(AST &ast){ + unordered_set<Name> avoid; + return resolve(ast,avoid); +} + +bool Environment::resolve(AST &ast,unordered_set<Name> &avoid){ if(ast.quoted){ return false; } @@ -160,23 +165,26 @@ bool Environment::resolve(AST &ast){ break; case AST::Type::name: - try { - ast=get(ast.nameval); - resolve(ast); - ret=true; - } catch(NameError){ - // just leave an unknown name as it is + if(avoid.find(ast.nameval)==avoid.end()){ + try { + avoid.insert(ast.nameval); + ast=get(ast.nameval); + resolve(ast,avoid); + ret=true; + } catch(NameError){ + // just leave an unknown name as it is + } } break; case AST::Type::tuple: for(AST &term : ast.terms){ - ret=resolve(term)||ret; + ret=resolve(term,avoid)||ret; } break; case AST::Type::lambda: - ret=resolve(*ast.lambdaval.body)||ret; + ret=resolve(*ast.lambdaval.body,avoid)||ret; break; } @@ -409,6 +417,7 @@ bool Environment::reduce(AST &ast,i64 depth){ ret=reduce(ast.terms[1],depth+1)||ret; if(!hasFree(ast.terms[1],1)){ ast=ast.terms[0].nativeval(ast.terms[1]); + reduce(ast,depth+1); ret=true; } else { cerr<<indent(depth+1)<<"Argument contained free indices, not calling"<<endl; diff --git a/environment.h b/environment.h index d3f3031..e892207 100644 --- a/environment.h +++ b/environment.h @@ -21,6 +21,7 @@ private: bool reduce(AST &ast,i64 depth=0); bool betareduce(AST &ast,i64 depth); bool resolve(AST &ast); + bool resolve(AST &ast,unordered_set<Name> &avoid); public: void load(const Environment &other); diff --git a/prelude.cpp b/prelude.cpp index 5738844..8fc9d8a 100644 --- a/prelude.cpp +++ b/prelude.cpp @@ -17,7 +17,9 @@ const AST afterBootstrap=AST(R"RAW( (def 'id \x x) (def 'const \x \y x) (def 'print (. putstr repr)) - (def '$ \f \x (f x))) + (def '$ \f \x (f x)) + (def 'if \c \t \f (__if c (() t) (() f))) + (def 'last \l (if (nil (tail l)) (head l) (last (tail l))))) )RAW"); static AST dofunction(const AST&); @@ -60,7 +62,11 @@ public: if(arg.terms.size()==0){ throw FormError("Empty tuple in 'head'"); } - return arg.terms[0]; + AST res=arg.terms[0]; + if(arg.quoted){ + res.quoted=true; + } + return res; })); intoEnv.define("tail",checkedHook("tail",{AST::Type::tuple}, @@ -68,7 +74,11 @@ public: if(arg.terms.size()==0){ throw FormError("Empty tuple in 'tail'"); } - return AST::makeTuple(Terms(arg.terms.begin()+1,arg.terms.end())); + AST res=AST::makeTuple(Terms(arg.terms.begin()+1,arg.terms.end())); + if(arg.quoted){ + res.quoted=true; + } + return res; })); intoEnv.define("nil",checkedHook("nil",{AST::Type::tuple}, @@ -81,13 +91,17 @@ public: return AST::makeNumber(arg.numval==0); })); - intoEnv.define("if",checkedHook("if",{AST::Type::number},{},{}, + intoEnv.define("__if",checkedHook("__if",{AST::Type::number},{AST::Type::tuple},{AST::Type::tuple}, [](Environment&,const AST &arg1,const AST &arg2,const AST &arg3) -> AST { - if(arg1.numval!=0){ - return arg2; - } else { - return arg3; + if(arg2.terms.size()!=2||arg3.terms.size()!=2){ + throw FormError("Then and else arguments to '__if' should be 2-tuples with value in second element"); + } + const AST &choice=arg1.numval!=0?arg2:arg3; + AST res=choice.terms[1]; + if(choice.quoted){ + res.quoted=true; } + return res; })); intoEnv.define("+",checkedHook("+",{AST::Type::number,AST::Type::string}, |