about summary refs log tree commit diff
path: root/src/libexpr
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2010-04-12T23·33+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2010-04-12T23·33+0000
commit10e8b1fd15d59dc541c15f6da56f8baf58eb3aa3 (patch)
tree42d4c5cb317d37a03bf01a5a7d2210af449d6f6f /src/libexpr
parent0d272fca799f7e6da955875b2935c19542cd6b4d (diff)
* Finished the ATerm-less parser.
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/eval-test.cc4
-rw-r--r--src/libexpr/eval.cc33
-rw-r--r--src/libexpr/nixexpr.cc2
-rw-r--r--src/libexpr/parser.y123
-rw-r--r--src/libexpr/primops.cc4
5 files changed, 66 insertions, 100 deletions
diff --git a/src/libexpr/eval-test.cc b/src/libexpr/eval-test.cc
index 782e36d386..ffadd41a7c 100644
--- a/src/libexpr/eval-test.cc
+++ b/src/libexpr/eval-test.cc
@@ -56,7 +56,7 @@ void run(Strings args)
     doTest(state, "let id = x: x; in [1 2] == [(id 1) (id 2)]");
     doTest(state, "let id = x: x; in [1 2] == [(id 1) (id 3)]");
     doTest(state, "[1 2] == [3 (let x = x; in x)]");
-    //doTest(state, "{ x = 1; y.z = 2; } == { y = { z = 2; }; x = 1; }");
+    doTest(state, "{ x = 1; y.z = 2; } == { y = { z = 2; }; x = 1; }");
     doTest(state, "{ x = 1; y = 2; } == { x = 2; }");
     doTest(state, "{ x = [ 1 2 ]; } == { x = [ 1 ] ++ [ 2 ]; }");
     doTest(state, "1 != 1");
@@ -84,7 +84,7 @@ void run(Strings args)
     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");
     doTest(state, "builtins.toXML 123");
-    //doTest(state, "builtins.toXML { a.b = \"x\" + \"y\"; c = [ 1 2 ] ++ [ 3 4 ]; }");
+    doTest(state, "builtins.toXML { a.b = \"x\" + \"y\"; c = [ 1 2 ] ++ [ 3 4 ]; }");
 
     state.printStats();
 }
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 62b493bbf6..99149fd7f9 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -54,6 +54,7 @@ std::ostream & operator << (std::ostream & str, Value & v)
         str << "]";
         break;
     case tThunk:
+    case tCopy:
         str << "<CODE>";
         break;
     case tLambda:
@@ -160,6 +161,16 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s2))
     throw TypeError(format(s) % s2);
 }
 
+LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos, const string & s2))
+{
+    throw TypeError(format(s) % pos % s2);
+}
+
+LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos))
+{
+    throw TypeError(format(s) % pos);
+}
+
 LocalNoInlineNoReturn(void throwAssertionError(const char * s, const Pos & pos))
 {
     throw AssertionError(format(s) % pos);
@@ -175,6 +186,11 @@ LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2))
     e.addPrefix(format(s) % s2);
 }
 
+LocalNoInline(void addErrorPrefix(Error & e, const char * s, const Pos & pos))
+{
+    e.addPrefix(format(s) % pos);
+}
+
 LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, const string & s3))
 {
     e.addPrefix(format(s) % s2 % s3);
@@ -424,6 +440,11 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
             Value & v2 = (*v.attrs)[i->first];
             mkThunk(v2, env, i->second);
         }
+
+        foreach (list<string>::iterator, i, inherited) {
+            Value & v2 = (*v.attrs)[*i];
+            mkCopy(v2, *lookupVar(&env, *i));
+        }
     }
 }
 
@@ -555,7 +576,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
             nrValues++;
                 
             if (j == arg.attrs->end()) {
-                if (!i->def) throwTypeError("the argument named `%1%' required by the function is missing", i->name);
+                if (!i->def) throwTypeError("function at %1% called without required argument `%2%'",
+                    fun.lambda.fun->pos, i->name);   
                 mkThunk(v, env2, i->def);
             } else {
                 attrsUsed++;
@@ -568,10 +590,15 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
            TODO: show the names of the expected/unexpected
            arguments. */
         if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size())
-            throwTypeError("function called with unexpected argument");
+            throwTypeError("function at %1% called with unexpected argument", fun.lambda.fun->pos);
     }
 
-    eval(env2, fun.lambda.fun->body, v);
+    try {
+        eval(env2, fun.lambda.fun->body, v);
+    } catch (Error & e) {
+        addErrorPrefix(e, "while evaluating the function at %1%:\n", fun.lambda.fun->pos);
+        throw;
+    }
 }
 
 
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 6ef996bdca..1902e23b00 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -55,7 +55,7 @@ void ExprAttrs::show(std::ostream & str)
     if (recursive) str << "rec ";
     str << "{ ";
     foreach (list<string>::iterator, i, inherited)
-        str << "inherited " << *i << "; ";
+        str << "inherit " << *i << "; ";
     foreach (Attrs::iterator, i, attrs)
         str << i->first << " = " << *i->second << "; ";
     str << "}";
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 22ce7e3f33..07bf56a1c9 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -44,99 +44,38 @@ struct ParseData
 };
 
 
-#if 0
-static string showAttrPath(ATermList attrPath)
+static string showAttrPath(const vector<string> & attrPath)
 {
     string s;
-    for (ATermIterator i(attrPath); i; ++i) {
+    foreach (vector<string>::const_iterator, i, attrPath) {
         if (!s.empty()) s += '.';
-        s += aterm2String(*i);
+        s += *i;
     }
     return s;
 }
  
 
-struct Tree
-{
-    Expr leaf; ATerm pos; bool recursive;
-    typedef std::map<ATerm, Tree> Children;
-    Children children;
-    Tree() { leaf = 0; recursive = true; }
-};
-
-
-static ATermList buildAttrs(const Tree & t, ATermList & nonrec)
+static void addAttr(ExprAttrs * attrs, const vector<string> & attrPath, Expr * e, const Pos & pos)
 {
-    ATermList res = ATempty;
-    for (Tree::Children::const_reverse_iterator i = t.children.rbegin();
-         i != t.children.rend(); ++i)
-        if (!i->second.recursive)
-            nonrec = ATinsert(nonrec, makeBind(i->first, i->second.leaf, i->second.pos));
-        else
-            res = ATinsert(res, i->second.leaf
-                ? makeBind(i->first, i->second.leaf, i->second.pos)
-                : makeBind(i->first, makeAttrs(buildAttrs(i->second, nonrec)), makeNoPos()));
-    return res;
-}
-#endif
- 
-
-static void fixAttrs(ExprAttrs & attrs)
-{
-#if 0
-    Tree attrs;
-
-    /* This ATermMap is needed to ensure that the `leaf' fields in the
-       Tree nodes are not garbage collected. */
-    ATermMap gcRoots;
-
-    for (ATermIterator i(as); i; ++i) {
-        ATermList names, attrPath; Expr src, e; ATerm name, pos;
-
-        if (matchInherit(*i, src, names, pos)) {
-            bool fromScope = matchScope(src);
-            for (ATermIterator j(names); j; ++j) {
-                if (attrs.children.find(*j) != attrs.children.end()) 
-                    throw ParseError(format("duplicate definition of attribute `%1%' at %2%")
-                        % showAttrPath(ATmakeList1(*j)) % showPos(pos));
-                Tree & t(attrs.children[*j]);
-                Expr leaf = fromScope ? makeVar(*j) : makeSelect(src, *j);
-                gcRoots.set(leaf, leaf);
-                t.leaf = leaf;
-                t.pos = pos;
-                if (recursive && fromScope) t.recursive = false;
+    unsigned int n = 0;
+    foreach (vector<string>::const_iterator, i, attrPath) {
+        n++;
+        if (attrs->attrs[*i]) {
+            ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(attrs->attrs[*i]);
+            if (!attrs2)
+                throw ParseError(format("attribute `%1%' at %2% already defined at <SOMEWHERE>")
+                    % showAttrPath(attrPath) % pos);
+            attrs = attrs2;
+        } else {
+            if (n == attrPath.size())
+                attrs->attrs[*i] = e;
+            else {
+                ExprAttrs * nested = new ExprAttrs;
+                attrs->attrs[*i] = nested;
+                attrs = nested;
             }
         }
-
-        else if (matchBindAttrPath(*i, attrPath, e, pos)) {
-
-            Tree * t(&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));
-                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));
-            if (!t->children.empty())
-                throw ParseError(format("duplicate definition of attribute `%1%' at %2%")
-                    % showAttrPath(attrPath) % showPos(pos));
-
-            t->leaf = e; t->pos = pos;
-        }
-
-        else abort(); /* can't happen */
     }
-
-    ATermList nonrec = ATempty;
-    ATermList rec = buildAttrs(attrs, nonrec);
-        
-    return recursive ? makeRec(rec, nonrec) : makeAttrs(rec);
-#endif
 }
 
 
@@ -307,7 +246,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
   char * id;
   char * path;
   char * uri;
-  std::list<std::string> * ids;
+  std::vector<std::string> * ids;
   std::vector<nix::Expr *> * string_parts;
 }
 
@@ -360,7 +299,7 @@ expr_function
   | WITH expr ';' expr_function
     { $$ = new ExprWith(CUR_POS, $2, $4); }
   | LET binds IN expr_function
-    { $2->attrs["<let-body>"] = $4; $2->recursive = true; fixAttrs(*$2); $$ = new ExprSelect($2, "<let-body>"); }
+    { $2->attrs["<let-body>"] = $4; $2->recursive = true; $$ = new ExprSelect($2, "<let-body>"); }
   | expr_if
   ;
 
@@ -418,11 +357,11 @@ expr_simple
   /* Let expressions `let {..., body = ...}' are just desugared
      into `(rec {..., body = ...}).body'. */
   | LET '{' binds '}'
-    { fixAttrs(*$3); $3->recursive = true; $$ = new ExprSelect($3, "body"); }
+    { $3->recursive = true; $$ = new ExprSelect($3, "body"); }
   | REC '{' binds '}'
-    { fixAttrs(*$3); $3->recursive = true; $$ = $3; }
+    { $3->recursive = true; $$ = $3; }
   | '{' binds '}'
-    { fixAttrs(*$2); $$ = $2; }
+    { $$ = $2; }
   | '[' expr_list ']' { $$ = $2; }
   ;
 
@@ -439,16 +378,16 @@ ind_string_parts
   ;
 
 binds
-  : binds ID '=' expr ';' { $$ = $1; $$->attrs[$2] = $4; }
+  : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, CUR_POS); }
   | binds INHERIT ids ';'
     { $$ = $1;
-      foreach (list<string>::iterator, i, *$3)
+      foreach (vector<string>::iterator, i, *$3)
         $$->inherited.push_back(*i);
     }
   | binds INHERIT '(' expr ')' ids ';'
     { $$ = $1;
       /* !!! Should ensure sharing of the expression in $4. */
-      foreach (list<string>::iterator, i, *$6)
+      foreach (vector<string>::iterator, i, *$6)
         $$->attrs[*i] = new ExprSelect($4, *i);
     }
   | { $$ = new ExprAttrs; }
@@ -456,12 +395,12 @@ binds
 
 ids
   : ids ID { $$ = $1; $1->push_back($2); /* !!! dangerous */ }
-  | { $$ = new list<string>; }
+  | { $$ = new vector<string>; }
   ;
 
 attrpath
-  : attrpath '.' ID { $$ = ATinsert($1, $3); }
-  | ID { $$ = ATmakeList1($1); }
+  : attrpath '.' ID { $$ = $1; $1->push_back($3); }
+  | ID { $$ = new vector<string>; $$->push_back($1); }
   ;
 
 expr_list
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index cd40ade008..e50034a047 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1023,8 +1023,8 @@ void EvalState::createBaseEnv()
     /* Add a wrapper around the derivation primop that computes the
        `drvPath' and `outPath' attributes lazily. */
     string s = "attrs: let res = derivationStrict attrs; in attrs // { drvPath = res.drvPath; outPath = res.outPath; type = \"derivation\"; }";
-    //mkThunk(v, baseEnv, parseExprFromString(s, "/"));
-    //addConstant("derivation", v);
+    mkThunk(v, baseEnv, parseExprFromString(s, "/"));
+    addConstant("derivation", v);
 
     // Miscellaneous
     addPrimOp("import", 1, prim_import);