about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval-test.cc8
-rw-r--r--src/libexpr/eval.cc128
-rw-r--r--src/libexpr/lexer.l4
-rw-r--r--src/libexpr/nixexpr.cc39
-rw-r--r--src/libexpr/nixexpr.hh38
-rw-r--r--src/libexpr/parser.y80
6 files changed, 160 insertions, 137 deletions
diff --git a/src/libexpr/eval-test.cc b/src/libexpr/eval-test.cc
index 32f4940df9..dd8ead04a6 100644
--- a/src/libexpr/eval-test.cc
+++ b/src/libexpr/eval-test.cc
@@ -45,6 +45,7 @@ void run(Strings args)
     doTest(state, "({x, y, ...}@args: args.z) { x = 1; y = 2; z = 3; }");
     //doTest(state, "({x ? y, y ? x}: y) { }");
     doTest(state, "let x = 1; in x");
+    doTest(state, "let { x = 1; body = x; }");
     doTest(state, "with { x = 1; }; x");
     doTest(state, "let x = 2; in with { x = 1; }; x"); // => 2
     doTest(state, "with { x = 1; }; with { x = 2; }; x"); // => 1
@@ -65,18 +66,19 @@ void run(Strings args)
     doTest(state, "__head [ 1 2 3 ]");
     doTest(state, "__add 1 2");
     doTest(state, "null");
-    //doTest(state, "\"foo\"");
-    //doTest(state, "let s = \"bar\"; in \"foo${s}\"");
+    doTest(state, "\"foo\"");
+    doTest(state, "let s = \"bar\"; in \"foo${s}\"");
     doTest(state, "if true then 1 else 2");
     doTest(state, "if false then 1 else 2");
     doTest(state, "if false || true then 1 else 2");
+    doTest(state, "!(true || false)");
     doTest(state, "let x = x; in if true || x then 1 else 2");
     doTest(state, "http://nixos.org/");
     doTest(state, "/etc/passwd");
     //doTest(state, "import ./foo.nix");
     doTest(state, "map (x: __add 1 x) [ 1 2 3 ]");
     doTest(state, "map (builtins.add 1) [ 1 2 3 ]");
-    //doTest(state, "builtins.hasAttr \"x\" { x = 1; }");
+    doTest(state, "builtins.hasAttr \"x\" { x = 1; }");
     doTest(state, "let x = 1; as = rec { inherit x; y = as.x; }; in as.y");
     doTest(state, "let as = { x = 1; }; bs = rec { inherit (as) x; y = x; }; in bs.y");
     doTest(state, "let as = rec { inherit (y) x; y = { x = 1; }; }; in as.x");
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 8ead986b81..21c22333bf 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -160,9 +160,9 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s2))
     throw TypeError(format(s) % s2);
 }
 
-LocalNoInlineNoReturn(void throwAssertionError(const char * s, const string & s2))
+LocalNoInlineNoReturn(void throwAssertionError(const char * s, const Pos & pos))
 {
-    throw AssertionError(format(s) % s2);
+    throw AssertionError(format(s) % pos);
 }
 
 LocalNoInline(void addErrorPrefix(Error & e, const char * s))
@@ -341,73 +341,13 @@ void EvalState::eval(Env & env, Expr * e, Value & v)
     char x;
     if (&x < deepestStack) deepestStack = &x;
     
-    //debug(format("eval: %1%") % e);
+    //debug(format("eval: %1%") % *e);
 
     checkInterrupt();
 
     nrEvaluated++;
 
     e->eval(*this, env, v);
-
-#if 0
-    Sym name;
-    int n;
-    ATerm s; ATermList context, es;
-    ATermList rbnds, nrbnds;
-    Expr e1, e2, e3, fun, arg, attrs;
-    Pattern pat; Expr body; Pos pos;
-    
-    else if (matchConcatStrings(e, es)) {
-        PathSet context;
-        std::ostringstream s;
-        
-        bool first = true, isPath = false;
-        Value vStr;
-        
-        for (ATermIterator i(es); i; ++i) {
-            eval(env, *i, vStr);
-
-            /* If the first element is a path, then the result will
-               also be a path, we don't copy anything (yet - that's
-               done later, since paths are copied when they are used
-               in a derivation), and none of the strings are allowed
-               to have contexts. */
-            if (first) {
-                isPath = vStr.type == tPath;
-                first = false;
-            }
-            
-            s << coerceToString(vStr, context, false, !isPath);
-        }
-        
-        if (isPath && !context.empty())
-            throwEvalError("a string that refers to a store path cannot be appended to a path, in `%1%'", s.str());
-
-        if (isPath)
-            mkPath(v, s.str().c_str());
-        else
-            mkString(v, s.str(), context);
-    }
-
-    /* Assertions. */
-    else if (matchAssert(e, e1, e2, pos)) {
-        if (!evalBool(env, e1))
-            throwAssertionError("assertion failed at %1%", showPos(pos));
-        eval(env, e2, v);
-    }
-
-    /* Negation. */
-    else if (matchOpNot(e, e1))
-        mkBool(v, !evalBool(env, e1));
-
-    /* Attribute existence test (?). */
-    else if (matchOpHasAttr(e, e1, name)) {
-        Value vAttrs;
-        eval(env, e1, vAttrs);
-        forceAttrs(vAttrs);
-        mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end());
-    }
-#endif
 }
 
 
@@ -516,6 +456,15 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
 }
 
 
+void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
+{
+    Value vAttrs;
+    state.eval(env, e, vAttrs);
+    state.forceAttrs(vAttrs);
+    mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end());
+}
+
+
 void ExprLambda::eval(EvalState & state, Env & env, Value & v)
 {
     v.type = tLambda;
@@ -663,6 +612,20 @@ void ExprIf::eval(EvalState & state, Env & env, Value & v)
 }
 
     
+void ExprAssert::eval(EvalState & state, Env & env, Value & v)
+{
+    if (!state.evalBool(env, cond))
+        throwAssertionError("assertion failed at %1%", pos);
+    state.eval(env, body, v);
+}
+
+    
+void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
+{
+    mkBool(v, !state.evalBool(env, e));
+}
+
+
 void ExprOpEq::eval(EvalState & state, Env & env, Value & v)
 {
     Value v1; state.eval(env, e1, v1);
@@ -713,12 +676,6 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
 }
 
 
-void ExprOpConcatStrings::eval(EvalState & state, Env & env, Value & v)
-{
-    abort();
-}
-
-
 void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
 {
     Value v1; state.eval(env, e1, v1);
@@ -735,6 +692,39 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
 }
 
 
+void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
+{
+    PathSet context;
+    std::ostringstream s;
+        
+    bool first = true, isPath = false;
+    Value vStr;
+
+    foreach (vector<Expr *>::iterator, i, *es) {
+        state.eval(env, *i, vStr);
+
+        /* If the first element is a path, then the result will also
+           be a path, we don't copy anything (yet - that's done later,
+           since paths are copied when they are used in a derivation),
+           and none of the strings are allowed to have contexts. */
+        if (first) {
+            isPath = vStr.type == tPath;
+            first = false;
+        }
+            
+        s << state.coerceToString(vStr, context, false, !isPath);
+    }
+        
+    if (isPath && !context.empty())
+        throwEvalError("a string that refers to a store path cannot be appended to a path, in `%1%'", s.str());
+
+    if (isPath)
+        mkPath(v, s.str().c_str());
+    else
+        mkString(v, s.str(), context);
+}
+
+
 void EvalState::forceValue(Value & v)
 {
     if (v.type == tThunk) {
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index f750cfd02d..e905700fde 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -45,7 +45,6 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
 
 static Expr * unescapeStr(const char * s)
 {
-#if 0
     string t;
     char c;
     while ((c = *s++)) {
@@ -64,8 +63,7 @@ static Expr * unescapeStr(const char * s)
         }
         else t += c;
     }
-    return makeStr(toATerm(t), ATempty);
-#endif
+    return new ExprString(t);
 }
 
  
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 05dfbd3223..b044aaa943 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -40,6 +40,11 @@ void ExprSelect::show(std::ostream & str)
     str << "(" << *e << ")." << name;
 }
 
+void ExprOpHasAttr::show(std::ostream & str)
+{
+    str << "(" << *e << ") ? " << name;
+}
+
 void ExprAttrs::show(std::ostream & str)
 {
     if (recursive) str << "rec ";
@@ -87,19 +92,37 @@ void ExprIf::show(std::ostream & str)
     str << "if " << *cond << " then " << *then << " else " << *else_;
 }
 
+void ExprAssert::show(std::ostream & str)
+{
+    str << "assert " << *cond << "; " << *body;
+}
 
-#if 0
-string showPos(ATerm pos)
+void ExprOpNot::show(std::ostream & str)
+{
+    str << "! " << *e;
+}
+
+void ExprConcatStrings::show(std::ostream & str)
+{
+    bool first = true;
+    foreach (vector<Expr *>::iterator, i, *es) {
+        if (first) first = false; else str << " + ";
+        str << **i;
+    }
+}
+
+
+std::ostream & operator << (std::ostream & str, const Pos & pos)
 {
-    ATerm path;
-    int line, column;
-    if (matchNoPos(pos)) return "undefined position";
-    if (!matchPos(pos, path, line, column))
-        throw badTerm("position expected", pos);
-    return (format("`%1%:%2%:%3%'") % aterm2String(path) % line % column).str();
+    if (!pos.line)
+        str << "undefined position";
+    else
+        str << (format("`%1%:%2%:%3%'") % pos.file % pos.line % pos.column).str();
+    return str;
 }
     
 
+#if 0
 ATerm bottomupRewrite(TermFun & f, ATerm e)
 {
     checkInterrupt();
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index ebdfd0a152..d6e088c416 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -24,6 +24,9 @@ struct Pos
 };
 
 
+std::ostream & operator << (std::ostream & str, const Pos & pos);
+
+
 /* Abstract syntax of Nix expressions. */
 
 struct Env;
@@ -81,6 +84,14 @@ struct ExprSelect : Expr
     COMMON_METHODS
 };
 
+struct ExprOpHasAttr : Expr
+{
+    Expr * e;
+    string name;
+    ExprOpHasAttr(Expr * e, const string & name) : e(e), name(name) { };
+    COMMON_METHODS
+};
+
 struct ExprAttrs : Expr
 {
     bool recursive;
@@ -139,6 +150,21 @@ struct ExprIf : Expr
     COMMON_METHODS
 };
 
+struct ExprAssert : Expr
+{
+    Pos pos;
+    Expr * cond, * body;
+    ExprAssert(const Pos & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { };
+    COMMON_METHODS
+};
+
+struct ExprOpNot : Expr
+{
+    Expr * e;
+    ExprOpNot(Expr * e) : e(e) { };
+    COMMON_METHODS
+};
+
 #define MakeBinOp(name, s) \
     struct Expr##name : Expr \
     { \
@@ -158,15 +184,17 @@ MakeBinOp(OpAnd, "&&")
 MakeBinOp(OpOr, "||")
 MakeBinOp(OpImpl, "->")
 MakeBinOp(OpUpdate, "//")
-MakeBinOp(OpConcatStrings, "+")
 MakeBinOp(OpConcatLists, "++")
 
-
-#if 0
-/* Show a position. */
-string showPos(ATerm pos);
+struct ExprConcatStrings : Expr
+{
+    vector<Expr *> * es;
+    ExprConcatStrings(vector<Expr *> * es) : es(es) { };
+    COMMON_METHODS
+};
 
 
+#if 0
 /* Generic bottomup traversal over ATerms.  The traversal first
    recursively descends into subterms, and then applies the given term
    function to the resulting term. */
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 96fbe2cb4b..83f454845d 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -20,7 +20,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "aterm.hh"
 #include "util.hh"
     
 #include "nixexpr.hh"
@@ -116,13 +115,13 @@ static void fixAttrs(ExprAttrs & attrs)
             for (ATermIterator j(attrPath); j; ) {
                 name = *j; ++j;
                 if (t->leaf) throw ParseError(format("attribute set containing `%1%' at %2% already defined at %3%")
-                    % showAttrPath(attrPath) % showPos(pos) % showPos (t->pos));
+                    % showAttrPath(attrPath) % showPos(pos) % showPos(t->pos));
                 t = &(t->children[name]);
             }
 
             if (t->leaf)
                 throw ParseError(format("duplicate definition of attribute `%1%' at %2% and %3%")
-                    % showAttrPath(attrPath) % showPos(pos) % showPos (t->pos));
+                    % showAttrPath(attrPath) % showPos(pos) % showPos(t->pos));
             if (!t->children.empty())
                 throw ParseError(format("duplicate definition of attribute `%1%' at %2%")
                     % showAttrPath(attrPath) % showPos(pos));
@@ -289,30 +288,11 @@ static Pos makeCurPos(YYLTYPE * loc, ParseData * data)
 
 void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * error)
 {
-    data->error = (format("%1%, at `%2%':%3%:%4%")
-        % error % data->path % loc->first_line % loc->first_column).str();
+    data->error = (format("%1%, at %2%")
+        % error % makeCurPos(loc, data)).str();
 }
 
 
-/* Make sure that the parse stack is scanned by the ATerm garbage
-   collector. */
-static void * mallocAndProtect(size_t size)
-{
-    void * p = malloc(size);
-    if (p) ATprotectMemory(p, size);
-    return p;
-}
-
-static void freeAndUnprotect(void * p)
-{
-    ATunprotectMemory(p);
-    free(p);
-}
-
-#define YYMALLOC mallocAndProtect
-#define YYFREE freeAndUnprotect
-
-
 #endif
 
 
@@ -329,18 +309,20 @@ static void freeAndUnprotect(void * p)
   char * path;
   char * uri;
   std::list<std::string> * ids;
+  std::vector<nix::Expr *> * string_parts;
 }
 
 %type <e> start expr expr_function expr_if expr_op
 %type <e> expr_app expr_select expr_simple
 %type <list> expr_list
 %type <attrs> binds
-%type <ts> attrpath string_parts ind_string_parts
+%type <ts> attrpath ind_string_parts
 %type <formals> formals
 %type <formal> formal
 %type <ids> ids
+%type <string_parts> string_parts
 %token <id> ID ATTRPATH
-%token <t> STR IND_STR
+%token <e> STR IND_STR
 %token <n> INT
 %token <path> PATH
 %token <uri> URI
@@ -375,9 +357,8 @@ expr_function
     { $$ = new ExprLambda(CUR_POS, $5, true, $2, $7); }
   | ID '@' '{' formals '}' ':' expr_function
     { $$ = new ExprLambda(CUR_POS, $1, true, $4, $7); }
-  /* | ASSERT expr ';' expr_function
-    { $$ = makeAssert($2, $4, CUR_POS); }
-    */
+  | ASSERT expr ';' expr_function
+    { $$ = new ExprAssert(CUR_POS, $2, $4); }
   | WITH expr ';' expr_function
     { $$ = new ExprWith(CUR_POS, $2, $4); }
   | LET binds IN expr_function
@@ -391,18 +372,20 @@ expr_if
   ;
 
 expr_op
-  : /* '!' expr_op %prec NEG { $$ = makeOpNot($2); }
-       | */
-    expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
+  : '!' expr_op %prec NEG { $$ = new ExprOpNot($2); }
+  | expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
   | expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
   | expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); }
   | expr_op OR expr_op { $$ = new ExprOpOr($1, $3); }
   | expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); }
   | expr_op UPDATE expr_op { $$ = new ExprOpUpdate($1, $3); }
-  /*
-  | expr_op '?' ID { $$ = makeOpHasAttr($1, $3); }
-  */
-  | expr_op '+' expr_op { $$ = new ExprOpConcatStrings($1, $3); }
+  | expr_op '?' ID { $$ = new ExprOpHasAttr($1, $3); }
+  | expr_op '+' expr_op
+    { vector<Expr *> * l = new vector<Expr *>;
+      l->push_back($1);
+      l->push_back($3);
+      $$ = new ExprConcatStrings(l);
+    }
   | expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
   | expr_app
   ;
@@ -421,26 +404,25 @@ expr_select
 
 expr_simple
   : ID { $$ = new ExprVar($1); }
-  | INT { $$ = new ExprInt($1); } /*
+  | INT { $$ = new ExprInt($1); }
   | '"' string_parts '"' {
-      /* For efficiency, and to simplify parse trees a bit. * /
-      if ($2 == ATempty) $$ = makeStr(toATerm(""), ATempty);
-      else if (ATgetNext($2) == ATempty) $$ = ATgetFirst($2);
-      else $$ = makeConcatStrings(ATreverse($2));
+      /* For efficiency, and to simplify parse trees a bit. */
+      if ($2->empty()) $$ = new ExprString("");
+      else if ($2->size() == 1) $$ = $2->front();
+      else $$ = new ExprConcatStrings($2);
   }
+  /*
   | IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
       $$ = stripIndentation(ATreverse($2));
   }
-                                  */
+  */
   | PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
   | URI { $$ = new ExprString($1); }
   | '(' expr ')' { $$ = $2; }
-/*
   /* Let expressions `let {..., body = ...}' are just desugared
-     into `(rec {..., body = ...}).body'. * /
+     into `(rec {..., body = ...}).body'. */
   | LET '{' binds '}'
-    { $$ = makeSelect(fixAttrs(true, $3), toATerm("body")); }
-  */
+    { fixAttrs(*$3); $3->recursive = true; $$ = new ExprSelect($3, "body"); }
   | REC '{' binds '}'
     { fixAttrs(*$3); $3->recursive = true; $$ = $3; }
   | '{' binds '}'
@@ -449,9 +431,9 @@ expr_simple
   ;
 
 string_parts
-  : string_parts STR { $$ = ATinsert($1, $2); }
-  | string_parts DOLLAR_CURLY expr '}' { backToString(scanner); $$ = ATinsert($1, $3); }
-  | { $$ = ATempty; }
+  : string_parts STR { $$ = $1; $1->push_back($2); }
+  | string_parts DOLLAR_CURLY expr '}' { backToString(scanner); $$ = $1; $1->push_back($3); }
+  | { $$ = new vector<Expr *>; }
   ;
 
 ind_string_parts