summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2016-11-20 22:29:29 +0100
committertomsmeding <tom.smeding@gmail.com>2016-11-20 22:30:08 +0100
commit83bdc306f781204dfb4094247932d13cc40edded (patch)
tree4be7082726ec7823df3c2dae27d92bdd1f4d4a27
parent979325946b938be7cbe51f8c20c44e457107979f (diff)
Make `last` work
-rw-r--r--environment.cpp25
-rw-r--r--environment.h1
-rw-r--r--prelude.cpp30
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},