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 << ""; 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::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::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 & attrPath) { string s; - for (ATermIterator i(attrPath); i; ++i) { + foreach (vector::const_iterator, i, attrPath) { if (!s.empty()) s += '.'; - s += aterm2String(*i); + s += *i; } return s; } -struct Tree +static void addAttr(ExprAttrs * attrs, const vector & attrPath, Expr * e, const Pos & pos) { - Expr leaf; ATerm pos; bool recursive; - typedef std::map Children; - Children children; - Tree() { leaf = 0; recursive = true; } -}; - - -static ATermList buildAttrs(const Tree & t, ATermList & nonrec) -{ - 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::const_iterator, i, attrPath) { + n++; + if (attrs->attrs[*i]) { + ExprAttrs * attrs2 = dynamic_cast(attrs->attrs[*i]); + if (!attrs2) + throw ParseError(format("attribute `%1%' at %2% already defined at ") + % 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 * ids; + std::vector * ids; std::vector * 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[""] = $4; $2->recursive = true; fixAttrs(*$2); $$ = new ExprSelect($2, ""); } + { $2->attrs[""] = $4; $2->recursive = true; $$ = new ExprSelect($2, ""); } | 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::iterator, i, *$3) + foreach (vector::iterator, i, *$3) $$->inherited.push_back(*i); } | binds INHERIT '(' expr ')' ids ';' { $$ = $1; /* !!! Should ensure sharing of the expression in $4. */ - foreach (list::iterator, i, *$6) + foreach (vector::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; } + | { $$ = new vector; } ; attrpath - : attrpath '.' ID { $$ = ATinsert($1, $3); } - | ID { $$ = ATmakeList1($1); } + : attrpath '.' ID { $$ = $1; $1->push_back($3); } + | ID { $$ = new vector; $$->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); diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index c53c558c1c..d9cf9a8626 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -177,7 +177,7 @@ static void initAndRun(int argc, char * * argv) if (lt != "") setLogType(lt); /* ATerm stuff. !!! find a better place to put this */ - //initDerivationsHelpers(); + initDerivationsHelpers(); /* Put the arguments in a vector. */ Strings args, remaining; @@ -335,7 +335,7 @@ int main(int argc, char * * argv) /* ATerm setup. */ ATerm bottomOfStack; - //ATinit(argc, argv, &bottomOfStack); + ATinit(argc, argv, &bottomOfStack); /* Turn on buffering for cerr. */ #if HAVE_PUBSETBUF