From 31428c3a0675f7223470af726bc697dc7a228927 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 29 Mar 2010 14:37:56 +0000 Subject: * Started integrating the new evaluator. --- src/libexpr/attr-path.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/libexpr/attr-path.cc') diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index e8e4c050cc84..5d81303fe3d0 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -6,6 +6,7 @@ namespace nix { +#if 0 bool isAttrs(EvalState & state, Expr e, ATermMap & attrs) { e = evalExpr(state, e); @@ -77,6 +78,7 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath, return e; } +#endif } -- cgit 1.4.1 From af2a372bb000d4d5aeec37e43ee0f6245c1bba54 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 7 Apr 2010 15:47:06 +0000 Subject: * Update autoCallFunction() and findAlongAttrPath(). --- src/libexpr/attr-path.cc | 54 +++++++---------- src/libexpr/attr-path.hh | 4 +- src/libexpr/common-opts.cc | 14 +++-- src/libexpr/common-opts.hh | 2 +- src/libexpr/eval.cc | 64 +++++++++++--------- src/libexpr/eval.hh | 34 ++--------- src/libexpr/get-drvs.cc | 9 +-- src/libexpr/get-drvs.hh | 2 +- src/nix-env/nix-env.cc | 22 +++---- src/nix-instantiate/nix-instantiate.cc | 103 ++++++++++----------------------- 10 files changed, 120 insertions(+), 188 deletions(-) (limited to 'src/libexpr/attr-path.cc') diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index 5d81303fe3d0..5f1c0ad7839d 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -6,19 +6,8 @@ namespace nix { -#if 0 -bool isAttrs(EvalState & state, Expr e, ATermMap & attrs) -{ - e = evalExpr(state, e); - ATermList dummy; - if (!matchAttrs(e, dummy)) return false; - queryAllAttrs(e, attrs, false); - return true; -} - - -Expr findAlongAttrPath(EvalState & state, const string & attrPath, - const ATermMap & autoArgs, Expr e) +void findAlongAttrPath(EvalState & state, const string & attrPath, + const Bindings & autoArgs, Expr e, Value & v) { Strings tokens = tokenizeString(attrPath, "."); @@ -26,8 +15,10 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath, Error(format("attribute selection path `%1%' does not match expression") % attrPath); string curPath; + + state.mkThunk_(v, e); - for (Strings::iterator i = tokens.begin(); i != tokens.end(); ++i) { + foreach (Strings::iterator, i, tokens) { if (!curPath.empty()) curPath += "."; curPath += *i; @@ -39,7 +30,10 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath, if (string2Int(attr, attrIndex)) apType = apIndex; /* Evaluate the expression. */ - e = evalExpr(state, autoCallFunction(evalExpr(state, e), autoArgs)); + Value vTmp; + state.autoCallFunction(autoArgs, v, vTmp); + v = vTmp; + state.forceValue(v); /* It should evaluate to either an attribute set or an expression, according to what is specified in the @@ -47,38 +41,32 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath, if (apType == apAttr) { - ATermMap attrs; - - if (!isAttrs(state, e, attrs)) + if (v.type != tAttrs) throw TypeError( format("the expression selected by the selection path `%1%' should be an attribute set but is %2%") - % curPath % showType(e)); - - e = attrs.get(toATerm(attr)); - if (!e) - throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); + % curPath % showType(v)); + Bindings::iterator a = v.attrs->find(toATerm(attr)); + if (a == v.attrs->end()) + throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); + v = a->second; } else if (apType == apIndex) { - ATermList es; - if (!matchList(e, es)) + if (v.type != tList) throw TypeError( format("the expression selected by the selection path `%1%' should be a list but is %2%") - % curPath % showType(e)); + % curPath % showType(v)); - e = ATelementAt(es, attrIndex); - if (!e) - throw Error(format("list index %1% in selection path `%2%' not found") % attrIndex % curPath); - + if (attrIndex >= v.list.length) + throw Error(format("list index %1% in selection path `%2%' is out of range") % attrIndex % curPath); + + v = v.list.elems[attrIndex]; } } - - return e; } -#endif } diff --git a/src/libexpr/attr-path.hh b/src/libexpr/attr-path.hh index 7abaa83a0167..518a7a95da09 100644 --- a/src/libexpr/attr-path.hh +++ b/src/libexpr/attr-path.hh @@ -10,8 +10,8 @@ namespace nix { -Expr findAlongAttrPath(EvalState & state, const string & attrPath, - const ATermMap & autoArgs, Expr e); +void findAlongAttrPath(EvalState & state, const string & attrPath, + const Bindings & autoArgs, Expr e, Value & v); } diff --git a/src/libexpr/common-opts.cc b/src/libexpr/common-opts.cc index 9e3f8f9614da..d5d3df40a9a9 100644 --- a/src/libexpr/common-opts.cc +++ b/src/libexpr/common-opts.cc @@ -9,7 +9,7 @@ namespace nix { bool parseOptionArg(const string & arg, Strings::iterator & i, const Strings::iterator & argsEnd, EvalState & state, - ATermMap & autoArgs) + Bindings & autoArgs) { if (arg != "--arg" && arg != "--argstr") return false; @@ -19,11 +19,13 @@ bool parseOptionArg(const string & arg, Strings::iterator & i, string name = *i++; if (i == argsEnd) throw error; string value = *i++; - - Expr e = arg == "--arg" - ? parseExprFromString(state, value, absPath(".")) - : makeStr(value); - autoArgs.set(toATerm(name), e); + + Value & v(autoArgs[toATerm(name)]); + + if (arg == "--arg") + state.mkThunk_(v, parseExprFromString(state, value, absPath("."))); + else + mkString(v, value); return true; } diff --git a/src/libexpr/common-opts.hh b/src/libexpr/common-opts.hh index fb9659cdc5a1..80298ce55d1b 100644 --- a/src/libexpr/common-opts.hh +++ b/src/libexpr/common-opts.hh @@ -9,7 +9,7 @@ namespace nix { /* Some common option parsing between nix-env and nix-instantiate. */ bool parseOptionArg(const string & arg, Strings::iterator & i, const Strings::iterator & argsEnd, EvalState & state, - ATermMap & autoArgs); + Bindings & autoArgs); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 0d18c552275a..98b6b7bdd150 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -260,6 +260,12 @@ void EvalState::mkAttrs(Value & v) } +void EvalState::mkThunk_(Value & v, Expr expr) +{ + mkThunk(v, baseEnv, expr); +} + + void EvalState::cloneAttrs(Value & src, Value & dst) { mkAttrs(dst); @@ -625,6 +631,37 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) } +void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res) +{ + forceValue(fun); + + ATerm name; + ATermList formals; + ATermBool ellipsis; + + if (fun.type != tLambda || !matchAttrsPat(fun.lambda.pat, formals, ellipsis, name)) { + res = fun; + return; + } + + Value actualArgs; + mkAttrs(actualArgs); + + for (ATermIterator i(formals); i; ++i) { + Expr name, def; ATerm def2; + if (!matchFormal(*i, name, def2)) abort(); + Bindings::const_iterator j = args.find(name); + if (j != args.end()) + (*actualArgs.attrs)[name] = j->second; + else if (!matchDefaultValue(def2, def)) + throw TypeError(format("cannot auto-call a function that has an argument without a default value (`%1% ')") + % aterm2String(name)); + } + + callFunction(fun, actualArgs, res); +} + + void EvalState::eval(Expr e, Value & v) { eval(baseEnv, e, v); @@ -1058,33 +1095,6 @@ ATermList flattenList(EvalState & state, Expr e) } -Expr autoCallFunction(Expr e, const ATermMap & args) -{ - Pattern pat; - ATerm body, pos, name; - ATermList formals; - ATermBool ellipsis; - - if (matchFunction(e, pat, body, pos) && matchAttrsPat(pat, formals, ellipsis, name)) { - ATermMap actualArgs(ATgetLength(formals)); - - for (ATermIterator i(formals); i; ++i) { - Expr name, def, value; ATerm def2; - if (!matchFormal(*i, name, def2)) abort(); - if ((value = args.get(name))) - actualArgs.set(name, makeAttrRHS(value, makeNoPos())); - else if (!matchDefaultValue(def2, def)) - throw TypeError(format("cannot auto-call a function that has an argument without a default value (`%1%')") - % aterm2String(name)); - } - - e = makeCall(e, makeAttrs(actualArgs)); - } - - return e; -} - - /* Evaluation of various language constructs. These have been taken out of evalExpr2 to reduce stack space usage. (GCC is really dumb about stack space: it just adds up all the local variables and diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index a42b9ebebaba..0ea474447f1f 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -226,13 +226,18 @@ public: void callFunction(Value & fun, Value & arg, Value & v); + /* Automatically call a function for which each argument has a + default value or has a binding in the `args' map. */ + void autoCallFunction(const Bindings & args, Value & fun, Value & res); + /* Allocation primitives. */ Value * allocValues(unsigned int count); Env & allocEnv(); void mkList(Value & v, unsigned int length); void mkAttrs(Value & v); - + void mkThunk_(Value & v, Expr expr); + void cloneAttrs(Value & src, Value & dst); /* Print statistics. */ @@ -244,33 +249,6 @@ public: string showType(Value & v); -#if 0 -/* Evaluate an expression to normal form. */ -Expr evalExpr(EvalState & state, Expr e); - -/* Evaluate an expression, and recursively evaluate list elements and - attributes. If `canonicalise' is true, we remove things like - position information and make sure that attribute sets are in - sorded order. */ -Expr strictEvalExpr(EvalState & state, Expr e); - -/* Specific results. */ -string evalString(EvalState & state, Expr e, PathSet & context); -int evalInt(EvalState & state, Expr e); -bool evalBool(EvalState & state, Expr e); -ATermList evalList(EvalState & state, Expr e); - -/* Flatten nested lists into a single list (or expand a singleton into - a list). */ -ATermList flattenList(EvalState & state, Expr e); - -/* Automatically call a function for which each argument has a default - value or has a binding in the `args' map. Note: result is a call, - not a normal form; it should be evaluated by calling evalExpr(). */ -Expr autoCallFunction(Expr e, const ATermMap & args); -#endif - - } diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 6e651d77f0cf..f5e7242f9f5a 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -155,11 +155,12 @@ static string addToPath(const string & s1, const string & s2) } -static void getDerivations(EvalState & state, Value & v, - const string & pathPrefix, const ATermMap & autoArgs, +static void getDerivations(EvalState & state, Value & vIn, + const string & pathPrefix, const Bindings & autoArgs, DrvInfos & drvs, Done & done) { - // !!! autoCallFunction(evalExpr(state, e), autoArgs) + Value v; + state.autoCallFunction(autoArgs, vIn, v); /* Process the expression. */ DrvInfo drv; @@ -216,7 +217,7 @@ static void getDerivations(EvalState & state, Value & v, void getDerivations(EvalState & state, Value & v, const string & pathPrefix, - const ATermMap & autoArgs, DrvInfos & drvs) + const Bindings & autoArgs, DrvInfos & drvs) { Done done; getDerivations(state, v, pathPrefix, autoArgs, drvs, done); diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh index 733f2020129b..f7d1987ea3b7 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -65,7 +65,7 @@ typedef list DrvInfos; bool getDerivation(EvalState & state, Value & v, DrvInfo & drv); void getDerivations(EvalState & state, Value & v, const string & pathPrefix, - const ATermMap & autoArgs, DrvInfos & drvs); + const Bindings & autoArgs, DrvInfos & drvs); } diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index ea85656a2bca..20affa83ddd0 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -47,7 +47,7 @@ struct InstallSourceInfo Path profile; /* for srcProfile */ string systemFilter; /* for srcNixExprDrvs */ bool prebuiltOnly; - ATermMap autoArgs; + Bindings autoArgs; InstallSourceInfo() : prebuiltOnly(false) { }; }; @@ -161,13 +161,11 @@ static Expr loadSourceExpr(EvalState & state, const Path & path) static void loadDerivations(EvalState & state, Path nixExprPath, - string systemFilter, const ATermMap & autoArgs, + string systemFilter, const Bindings & autoArgs, const string & pathPrefix, DrvInfos & elems) { Value v; - state.eval(loadSourceExpr(state, nixExprPath), v); - - // !!! findAlongAttrPath(state, pathPrefix, autoArgs, loadSourceExpr(state, nixExprPath)) + findAlongAttrPath(state, pathPrefix, autoArgs, loadSourceExpr(state, nixExprPath), v); getDerivations(state, v, pathPrefix, autoArgs, elems); @@ -579,14 +577,12 @@ static void queryInstSources(EvalState & state, } case srcAttrPath: { - throw Error("not implemented"); -#if 0 - foreach (Strings::const_iterator, i, args) - getDerivations(state, - findAlongAttrPath(state, *i, instSource.autoArgs, - loadSourceExpr(state, instSource.nixExprPath)), - "", instSource.autoArgs, elems); -#endif + foreach (Strings::const_iterator, i, args) { + Value v; + findAlongAttrPath(state, *i, instSource.autoArgs, + loadSourceExpr(state, instSource.nixExprPath), v); + getDerivations(state, v, "", instSource.autoArgs, elems); + } break; } } diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index ebf1be5b9649..ac405aa6601c 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -37,80 +37,41 @@ static int rootNr = 0; static bool indirectRoot = false; -#if 0 -static void printResult(EvalState & state, Expr e, - bool evalOnly, bool xmlOutput, const ATermMap & autoArgs) -{ - PathSet context; - - if (evalOnly) - if (xmlOutput) - printTermAsXML(e, std::cout, context); - else - std::cout << format("%1%\n") % canonicaliseExpr(e); - - else { - DrvInfos drvs; - getDerivations(state, e, "", autoArgs, drvs); - for (DrvInfos::iterator i = drvs.begin(); i != drvs.end(); ++i) { - Path drvPath = i->queryDrvPath(state); - if (gcRoot == "") - printGCWarning(); - else - drvPath = addPermRoot(drvPath, - makeRootName(gcRoot, rootNr), - indirectRoot); - std::cout << format("%1%\n") % drvPath; - } - } -} -#endif - - void processExpr(EvalState & state, const Strings & attrPaths, - bool parseOnly, bool strict, const ATermMap & autoArgs, + bool parseOnly, bool strict, const Bindings & autoArgs, bool evalOnly, bool xmlOutput, Expr e) { if (parseOnly) std::cout << format("%1%\n") % canonicaliseExpr(e); - else { - Value v; - PathSet context; - state.eval(e, v); - if (evalOnly) - if (xmlOutput) - printValueAsXML(state, strict, v, std::cout, context); + else + foreach (Strings::const_iterator, i, attrPaths) { + Value v; + findAlongAttrPath(state, *i, autoArgs, e, v); + state.forceValue(v); + + PathSet context; + if (evalOnly) + if (xmlOutput) + printValueAsXML(state, strict, v, std::cout, context); + else { + if (strict) state.strictForceValue(v); + std::cout << v << std::endl; + } else { - if (strict) state.strictForceValue(v); - std::cout << v << std::endl; - } - else { - DrvInfos drvs; - getDerivations(state, v, "", autoArgs, drvs); - foreach (DrvInfos::iterator, i, drvs) { - Path drvPath = i->queryDrvPath(state); - if (gcRoot == "") - printGCWarning(); - else - drvPath = addPermRoot(drvPath, - makeRootName(gcRoot, rootNr), - indirectRoot); - std::cout << format("%1%\n") % drvPath; + DrvInfos drvs; + getDerivations(state, v, "", autoArgs, drvs); + foreach (DrvInfos::iterator, i, drvs) { + Path drvPath = i->queryDrvPath(state); + if (gcRoot == "") + printGCWarning(); + else + drvPath = addPermRoot(drvPath, + makeRootName(gcRoot, rootNr), + indirectRoot); + std::cout << format("%1%\n") % drvPath; + } } } - } - -#if 0 - for (Strings::const_iterator i = attrPaths.begin(); i != attrPaths.end(); ++i) { - Expr e2 = findAlongAttrPath(state, *i, autoArgs, e); - if (!parseOnly) - if (strict) - e2 = state.strictEval(e2); - else - e2 = evalExpr(state, e2); - printResult(state, e2, evalOnly, xmlOutput, autoArgs); - } -#endif } @@ -124,11 +85,9 @@ void run(Strings args) bool xmlOutput = false; bool strict = false; Strings attrPaths; - ATermMap autoArgs(128); + Bindings autoArgs; - for (Strings::iterator i = args.begin(); - i != args.end(); ) - { + for (Strings::iterator i = args.begin(); i != args.end(); ) { string arg = *i++; if (arg == "-") @@ -175,9 +134,7 @@ void run(Strings args) evalOnly, xmlOutput, e); } - for (Strings::iterator i = files.begin(); - i != files.end(); i++) - { + foreach (Strings::iterator, i, files) { Path path = absPath(*i); Expr e = parseExprFromFile(state, path); processExpr(state, attrPaths, parseOnly, strict, autoArgs, -- cgit 1.4.1 From 4d6ad5be1738c64b1de4274cafbd4b8f23ca287c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 12 Apr 2010 18:30:11 +0000 Subject: * Don't use ATerms for the abstract syntax trees anymore. Not finished yet. --- src/libexpr/Makefile.am | 15 +- src/libexpr/attr-path.cc | 5 +- src/libexpr/attr-path.hh | 2 +- src/libexpr/common-opts.cc | 4 +- src/libexpr/eval-test.cc | 22 +- src/libexpr/eval.cc | 467 +++++++++++++++++---------------- src/libexpr/eval.hh | 46 +++- src/libexpr/get-drvs.cc | 21 +- src/libexpr/lexer.l | 24 +- src/libexpr/nixexpr-ast.def | 97 ------- src/libexpr/nixexpr.cc | 110 ++++++-- src/libexpr/nixexpr.hh | 163 ++++++++++-- src/libexpr/parser.hh | 5 +- src/libexpr/parser.y | 191 ++++++++------ src/libexpr/primops.cc | 38 ++- src/libexpr/value-to-xml.cc | 43 +-- src/libmain/shared.cc | 4 +- src/nix-env/nix-env.cc | 5 +- src/nix-instantiate/nix-instantiate.cc | 10 +- 19 files changed, 693 insertions(+), 579 deletions(-) delete mode 100644 src/libexpr/nixexpr-ast.def (limited to 'src/libexpr/attr-path.cc') diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am index 99f742ffec40..60b1815d9690 100644 --- a/src/libexpr/Makefile.am +++ b/src/libexpr/Makefile.am @@ -8,15 +8,15 @@ libexpr_la_SOURCES = \ pkginclude_HEADERS = \ nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \ get-drvs.hh attr-path.hh value-to-xml.hh common-opts.hh \ - names.hh nixexpr-ast.hh + names.hh libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \ ../boost/format/libformat.la -BUILT_SOURCES = nixexpr-ast.cc nixexpr-ast.hh \ +BUILT_SOURCES = \ parser-tab.hh lexer-tab.hh parser-tab.cc lexer-tab.cc -EXTRA_DIST = lexer.l parser.y nixexpr-ast.def nixexpr-ast.cc +EXTRA_DIST = lexer.l parser.y AM_CXXFLAGS = \ -I$(srcdir)/.. ${aterm_include} \ @@ -34,15 +34,6 @@ lexer-tab.cc lexer-tab.hh: lexer.l $(flex) --outfile lexer-tab.cc --header-file=lexer-tab.hh $(srcdir)/lexer.l -# ATerm helper function generation. - -nixexpr-ast.cc nixexpr-ast.hh: ../aterm-helper.pl nixexpr-ast.def - $(perl) $(srcdir)/../aterm-helper.pl nixexpr-ast.hh nixexpr-ast.cc < $(srcdir)/nixexpr-ast.def - - -CLEANFILES = - - # SDF stuff (not built by default). nix.tbl: nix.sdf sdf2table -m Nix -s -i nix.sdf -o nix.tbl diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index 5f1c0ad7839d..aa421ab431da 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -1,5 +1,4 @@ #include "attr-path.hh" -#include "nixexpr-ast.hh" #include "util.hh" @@ -7,7 +6,7 @@ namespace nix { void findAlongAttrPath(EvalState & state, const string & attrPath, - const Bindings & autoArgs, Expr e, Value & v) + const Bindings & autoArgs, Expr * e, Value & v) { Strings tokens = tokenizeString(attrPath, "."); @@ -46,7 +45,7 @@ void findAlongAttrPath(EvalState & state, const string & attrPath, format("the expression selected by the selection path `%1%' should be an attribute set but is %2%") % curPath % showType(v)); - Bindings::iterator a = v.attrs->find(toATerm(attr)); + Bindings::iterator a = v.attrs->find(attr); if (a == v.attrs->end()) throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); v = a->second; diff --git a/src/libexpr/attr-path.hh b/src/libexpr/attr-path.hh index 518a7a95da09..33587e5edee1 100644 --- a/src/libexpr/attr-path.hh +++ b/src/libexpr/attr-path.hh @@ -11,7 +11,7 @@ namespace nix { void findAlongAttrPath(EvalState & state, const string & attrPath, - const Bindings & autoArgs, Expr e, Value & v); + const Bindings & autoArgs, Expr * e, Value & v); } diff --git a/src/libexpr/common-opts.cc b/src/libexpr/common-opts.cc index d5d3df40a9a9..6171de0f0e84 100644 --- a/src/libexpr/common-opts.cc +++ b/src/libexpr/common-opts.cc @@ -20,10 +20,10 @@ bool parseOptionArg(const string & arg, Strings::iterator & i, if (i == argsEnd) throw error; string value = *i++; - Value & v(autoArgs[toATerm(name)]); + Value & v(autoArgs[name]); if (arg == "--arg") - state.mkThunk_(v, parseExprFromString(state, value, absPath("."))); + state.mkThunk_(v, parseExprFromString(value, absPath("."))); else mkString(v, value); diff --git a/src/libexpr/eval-test.cc b/src/libexpr/eval-test.cc index 77861dea95be..32f4940df90e 100644 --- a/src/libexpr/eval-test.cc +++ b/src/libexpr/eval-test.cc @@ -2,8 +2,8 @@ #include "parser.hh" #include "hash.hh" #include "util.hh" -#include "nixexpr-ast.hh" +#include #include #include @@ -12,8 +12,8 @@ using namespace nix; void doTest(EvalState & state, string s) { - Expr e = parseExprFromString(state, s, absPath(".")); - printMsg(lvlError, format(">>>>> %1%") % e); + Expr * e = parseExprFromString(s, absPath(".")); + std::cerr << ">>>>> " << *e << std::endl; Value v; state.eval(e, v); state.strictForceValue(v); @@ -24,8 +24,10 @@ void doTest(EvalState & state, string s) void run(Strings args) { EvalState state; - + printMsg(lvlError, format("size of value: %1% bytes") % sizeof(Value)); + printMsg(lvlError, format("size of int AST node: %1% bytes") % sizeof(ExprInt)); + printMsg(lvlError, format("size of attrset AST node: %1% bytes") % sizeof(ExprAttrs)); doTest(state, "123"); doTest(state, "{ x = 1; y = 2; }"); @@ -53,7 +55,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"); @@ -63,23 +65,23 @@ void run(Strings args) doTest(state, "__head [ 1 2 3 ]"); doTest(state, "__add 1 2"); doTest(state, "null"); - 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, "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"); 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 7434aa842242..8ead986b8125 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -4,7 +4,6 @@ #include "util.hh" #include "store-api.hh" #include "derivations.hh" -#include "nixexpr-ast.hh" #include "globals.hh" #include @@ -45,7 +44,7 @@ std::ostream & operator << (std::ostream & str, Value & v) case tAttrs: str << "{ "; foreach (Bindings::iterator, i, *v.attrs) - str << aterm2String(i->first) << " = " << i->second << "; "; + str << i->first << " = " << i->second << "; "; str << "}"; break; case tList: @@ -96,8 +95,6 @@ EvalState::EvalState() : baseEnv(allocEnv()) nrValues = nrEnvs = nrEvaluated = recursionDepth = maxRecursionDepth = 0; deepestStack = (char *) -1; - initNixExprHelpers(); - createBaseEnv(); allowUnsafeEquality = getEnv("NIX_NO_UNSAFE_EQ", "") == ""; @@ -112,9 +109,9 @@ EvalState::~EvalState() void EvalState::addConstant(const string & name, Value & v) { - baseEnv.bindings[toATerm(name)] = v; + baseEnv.bindings[name] = v; string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; - (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm(name2)] = v; + (*baseEnv.bindings["builtins"].attrs)[name2] = v; nrValues += 2; } @@ -126,9 +123,9 @@ void EvalState::addPrimOp(const string & name, v.type = tPrimOp; v.primOp.arity = arity; v.primOp.fun = primOp; - baseEnv.bindings[toATerm(name)] = v; + baseEnv.bindings[name] = v; string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; - (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm(name2)] = v; + (*baseEnv.bindings["builtins"].attrs)[name2] = v; nrValues += 2; } @@ -212,12 +209,12 @@ void mkPath(Value & v, const char * s) } -static Value * lookupWith(Env * env, Sym name) +static Value * lookupWith(Env * env, const Sym & name) { if (!env) return 0; Value * v = lookupWith(env->up, name); if (v) return v; - Bindings::iterator i = env->bindings.find(sWith); + Bindings::iterator i = env->bindings.find(""); if (i == env->bindings.end()) return 0; Bindings::iterator j = i->second.attrs->find(name); if (j != i->second.attrs->end()) return &j->second; @@ -225,7 +222,7 @@ static Value * lookupWith(Env * env, Sym name) } -static Value * lookupVar(Env * env, Sym name) +static Value * lookupVar(Env * env, const Sym & name) { /* First look for a regular variable binding for `name'. */ for (Env * env2 = env; env2; env2 = env2->up) { @@ -251,7 +248,7 @@ static Value * lookupVar(Env * env, Sym name) } #endif - throwEvalError("undefined variable `%1%'", aterm2String(name)); + throwEvalError("undefined variable `%1%'", name); } @@ -284,7 +281,7 @@ void EvalState::mkAttrs(Value & v) } -void EvalState::mkThunk_(Value & v, Expr expr) +void EvalState::mkThunk_(Value & v, Expr * expr) { mkThunk(v, baseEnv, expr); } @@ -302,11 +299,11 @@ void EvalState::evalFile(const Path & path, Value & v) { startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); - Expr e = parseTrees.get(toATerm(path)); + Expr * e = parseTrees[path]; if (!e) { - e = parseExprFromFile(*this, path); - parseTrees.set(toATerm(path), e); + e = parseExprFromFile(path); + parseTrees[path] = e; } try { @@ -334,7 +331,7 @@ struct RecursionCounter }; -void EvalState::eval(Env & env, Expr e, Value & v) +void EvalState::eval(Env & env, Expr * e, Value & v) { /* When changing this function, make sure that you don't cause a (large) increase in stack consumption! */ @@ -350,6 +347,9 @@ void EvalState::eval(Env & env, Expr e, Value & v) nrEvaluated++; + e->eval(*this, env, v); + +#if 0 Sym name; int n; ATerm s; ATermList context, es; @@ -357,138 +357,6 @@ void EvalState::eval(Env & env, Expr e, Value & v) Expr e1, e2, e3, fun, arg, attrs; Pattern pat; Expr body; Pos pos; - if (matchVar(e, name)) { - Value * v2 = lookupVar(&env, name); - forceValue(*v2); - v = *v2; - } - - else if (matchInt(e, n)) - mkInt(v, n); - - else if (matchStr(e, s, context)) { - assert(context == ATempty); - mkString(v, ATgetName(ATgetAFun(s))); - } - - else if (matchPath(e, s)) - mkPath(v, ATgetName(ATgetAFun(s))); - - else if (matchAttrs(e, es)) { - mkAttrs(v); - ATerm e2, pos; - for (ATermIterator i(es); i; ++i) { - if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ - Value & v2 = (*v.attrs)[name]; - nrValues++; - mkThunk(v2, env, e2); - } - } - - else if (matchRec(e, rbnds, nrbnds)) { - /* Create a new environment that contains the attributes in - this `rec'. */ - Env & env2(allocEnv()); - env2.up = &env; - - v.type = tAttrs; - v.attrs = &env2.bindings; - - /* The recursive attributes are evaluated in the new - environment. */ - ATerm name, e2, pos; - for (ATermIterator i(rbnds); i; ++i) { - if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ - Value & v2 = env2.bindings[name]; - nrValues++; - mkThunk(v2, env2, e2); - } - - /* The non-recursive attributes, on the other hand, are - evaluated in the original environment. */ - for (ATermIterator i(nrbnds); i; ++i) { - if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ - Value & v2 = env2.bindings[name]; - nrValues++; - mkThunk(v2, env, e2); - } - } - - else if (matchSelect(e, e2, name)) { - Value v2; - eval(env, e2, v2); - forceAttrs(v2); // !!! eval followed by force is slightly inefficient - Bindings::iterator i = v2.attrs->find(name); - if (i == v2.attrs->end()) - throwEvalError("attribute `%1%' missing", aterm2String(name)); - try { - forceValue(i->second); - } catch (Error & e) { - addErrorPrefix(e, "while evaluating the attribute `%1%':\n", aterm2String(name)); - throw; - } - v = i->second; - } - - else if (matchFunction(e, pat, body, pos)) { - v.type = tLambda; - v.lambda.env = &env; - v.lambda.pat = pat; - v.lambda.body = body; - } - - else if (matchCall(e, fun, arg)) { - Value vFun; - eval(env, fun, vFun); - Value vArg; - mkThunk(vArg, env, arg); // !!! should this be on the heap? - callFunction(vFun, vArg, v); - } - - else if (matchWith(e, attrs, body, pos)) { - Env & env2(allocEnv()); - env2.up = &env; - - Value & vAttrs = env2.bindings[sWith]; - nrValues++; - eval(env, attrs, vAttrs); - forceAttrs(vAttrs); - - eval(env2, body, v); - } - - else if (matchList(e, es)) { - mkList(v, ATgetLength(es)); - for (unsigned int n = 0; n < v.list.length; ++n, es = ATgetNext(es)) - mkThunk(v.list.elems[n], env, ATgetFirst(es)); - } - - else if (matchOpEq(e, e1, e2)) { - Value v1; eval(env, e1, v1); - Value v2; eval(env, e2, v2); - mkBool(v, eqValues(v1, v2)); - } - - else if (matchOpNEq(e, e1, e2)) { - Value v1; eval(env, e1, v1); - Value v2; eval(env, e2, v2); - mkBool(v, !eqValues(v1, v2)); - } - - else if (matchOpConcat(e, e1, e2)) { - Value v1; eval(env, e1, v1); - forceList(v1); - Value v2; eval(env, e2, v2); - forceList(v2); - mkList(v, v1.list.length + v2.list.length); - /* !!! This loses sharing with the original lists. We could - use a tCopy node, but that would use more memory. */ - for (unsigned int n = 0; n < v1.list.length; ++n) - v.list.elems[n] = v1.list.elems[n]; - for (unsigned int n = 0; n < v2.list.length; ++n) - v.list.elems[n + v1.list.length] = v2.list.elems[n]; - } - else if (matchConcatStrings(e, es)) { PathSet context; std::ostringstream s; @@ -521,10 +389,6 @@ void EvalState::eval(Env & env, Expr e, Value & v) mkString(v, s.str(), context); } - /* Conditionals. */ - else if (matchIf(e, e1, e2, e3)) - eval(env, evalBool(env, e1) ? e2 : e3, v); - /* Assertions. */ else if (matchAssert(e, e1, e2, pos)) { if (!evalBool(env, e1)) @@ -536,30 +400,6 @@ void EvalState::eval(Env & env, Expr e, Value & v) else if (matchOpNot(e, e1)) mkBool(v, !evalBool(env, e1)); - /* Implication. */ - else if (matchOpImpl(e, e1, e2)) - return mkBool(v, !evalBool(env, e1) || evalBool(env, e2)); - - /* Conjunction (logical AND). */ - else if (matchOpAnd(e, e1, e2)) - mkBool(v, evalBool(env, e1) && evalBool(env, e2)); - - /* Disjunction (logical OR). */ - else if (matchOpOr(e, e1, e2)) - mkBool(v, evalBool(env, e1) || evalBool(env, e2)); - - /* Attribute set update (//). */ - else if (matchOpUpdate(e, e1, e2)) { - Value v2; - eval(env, e1, v2); - - cloneAttrs(v2, v); - - eval(env, e2, v2); - foreach (Bindings::iterator, i, *v2.attrs) - (*v.attrs)[i->first] = i->second; // !!! sharing - } - /* Attribute existence test (?). */ else if (matchOpHasAttr(e, e1, name)) { Value vAttrs; @@ -567,8 +407,130 @@ void EvalState::eval(Env & env, Expr e, Value & v) forceAttrs(vAttrs); mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end()); } +#endif +} + + +void EvalState::eval(Expr * e, Value & v) +{ + eval(baseEnv, e, v); +} - else abort(); + +bool EvalState::evalBool(Env & env, Expr * e) +{ + Value v; + eval(env, e, v); + if (v.type != tBool) + throwTypeError("value is %1% while a Boolean was expected", showType(v)); + return v.boolean; +} + + +void ExprInt::eval(EvalState & state, Env & env, Value & v) +{ + mkInt(v, n); +} + + +void ExprString::eval(EvalState & state, Env & env, Value & v) +{ + mkString(v, s.c_str()); +} + + +void ExprPath::eval(EvalState & state, Env & env, Value & v) +{ + mkPath(v, s.c_str()); +} + + +void ExprAttrs::eval(EvalState & state, Env & env, Value & v) +{ + if (recursive) { + + /* Create a new environment that contains the attributes in + this `rec'. */ + Env & env2(state.allocEnv()); + env2.up = &env; + + v.type = tAttrs; + v.attrs = &env2.bindings; + + /* The recursive attributes are evaluated in the new + environment. */ + foreach (Attrs::iterator, i, attrs) { + Value & v2 = env2.bindings[i->first]; + mkThunk(v2, env2, i->second); + } + + /* The inherited attributes, on the other hand, are + evaluated in the original environment. */ + foreach (list::iterator, i, inherited) { + Value & v2 = env2.bindings[*i]; + mkCopy(v2, *lookupVar(&env, *i)); + } + } + + else { + state.mkAttrs(v); + foreach (Attrs::iterator, i, attrs) { + Value & v2 = (*v.attrs)[i->first]; + mkThunk(v2, env, i->second); + } + } +} + + +void ExprList::eval(EvalState & state, Env & env, Value & v) +{ + state.mkList(v, elems.size()); + for (unsigned int n = 0; n < v.list.length; ++n) + mkThunk(v.list.elems[n], env, elems[n]); +} + + +void ExprVar::eval(EvalState & state, Env & env, Value & v) +{ + Value * v2 = lookupVar(&env, name); + state.forceValue(*v2); + v = *v2; +} + + +void ExprSelect::eval(EvalState & state, Env & env, Value & v) +{ + Value v2; + state.eval(env, e, v2); + state.forceAttrs(v2); // !!! eval followed by force is slightly inefficient + Bindings::iterator i = v2.attrs->find(name); + if (i == v2.attrs->end()) + throwEvalError("attribute `%1%' missing", name); + try { + state.forceValue(i->second); + } catch (Error & e) { + addErrorPrefix(e, "while evaluating the attribute `%1%':\n", name); + throw; + } + v = i->second; +} + + +void ExprLambda::eval(EvalState & state, Env & env, Value & v) +{ + v.type = tLambda; + v.lambda.env = &env; + v.lambda.fun = this; +} + + +void ExprApp::eval(EvalState & state, Env & env, Value & v) +{ + Value vFun; + state.eval(env, e1, vFun); + Value vArg; + mkThunk(vArg, env, e2); // !!! should this be on the heap? + state.callFunction(vFun, vArg, v); } @@ -613,19 +575,17 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) Env & env2(allocEnv()); env2.up = fun.lambda.env; - ATermList formals; ATerm ellipsis, name; - - if (matchVarPat(fun.lambda.pat, name)) { - Value & vArg = env2.bindings[name]; + if (!fun.lambda.fun->matchAttrs) { + Value & vArg = env2.bindings[fun.lambda.fun->arg]; nrValues++; vArg = arg; } - else if (matchAttrsPat(fun.lambda.pat, formals, ellipsis, name)) { + else { forceAttrs(arg); - if (name != sNoAlias) { - env2.bindings[name] = arg; + if (!fun.lambda.fun->arg.empty()) { + env2.bindings[fun.lambda.fun->arg] = arg; nrValues++; } @@ -633,21 +593,15 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) there is no matching actual argument but the formal argument has a default, use the default. */ unsigned int attrsUsed = 0; - for (ATermIterator i(formals); i; ++i) { - Expr def; Sym name; - DefaultValue def2; - if (!matchFormal(*i, name, def2)) abort(); /* can't happen */ - - Bindings::iterator j = arg.attrs->find(name); + foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) { + Bindings::iterator j = arg.attrs->find(i->name); - Value & v = env2.bindings[name]; + Value & v = env2.bindings[i->name]; nrValues++; if (j == arg.attrs->end()) { - if (!matchDefaultValue(def2, def)) def = 0; - if (def == 0) throwTypeError("the argument named `%1%' required by the function is missing", - aterm2String(name)); - mkThunk(v, env2, def); + if (!i->def) throwTypeError("the argument named `%1%' required by the function is missing", i->name); + mkThunk(v, env2, i->def); } else { attrsUsed++; mkCopy(v, j->second); @@ -658,13 +612,11 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) argument (unless the attribute match specifies a `...'). TODO: show the names of the expected/unexpected arguments. */ - if (ellipsis == eFalse && attrsUsed != arg.attrs->size()) + if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size()) throwTypeError("function called with unexpected argument"); } - else abort(); - - eval(env2, fun.lambda.body, v); + eval(env2, fun.lambda.fun->body, v); } @@ -672,45 +624,114 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res { forceValue(fun); - ATerm name; - ATermList formals; - ATermBool ellipsis; - - if (fun.type != tLambda || !matchAttrsPat(fun.lambda.pat, formals, ellipsis, name)) { + if (fun.type != tLambda || !fun.lambda.fun->matchAttrs) { res = fun; return; } Value actualArgs; mkAttrs(actualArgs); - - for (ATermIterator i(formals); i; ++i) { - Expr name, def; ATerm def2; - if (!matchFormal(*i, name, def2)) abort(); - Bindings::const_iterator j = args.find(name); + + foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) { + Bindings::const_iterator j = args.find(i->name); if (j != args.end()) - (*actualArgs.attrs)[name] = j->second; - else if (!matchDefaultValue(def2, def)) - throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", aterm2String(name)); + (*actualArgs.attrs)[i->name] = j->second; + else if (!i->def) + throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", i->name); } callFunction(fun, actualArgs, res); } -void EvalState::eval(Expr e, Value & v) +void ExprWith::eval(EvalState & state, Env & env, Value & v) { - eval(baseEnv, e, v); + Env & env2(state.allocEnv()); + env2.up = &env; + + Value & vAttrs = env2.bindings[""]; + state.eval(env, attrs, vAttrs); + state.forceAttrs(vAttrs); + + state.eval(env2, body, v); } -bool EvalState::evalBool(Env & env, Expr e) +void ExprIf::eval(EvalState & state, Env & env, Value & v) { - Value v; - eval(env, e, v); - if (v.type != tBool) - throwTypeError("value is %1% while a Boolean was expected", showType(v)); - return v.boolean; + state.eval(env, state.evalBool(env, cond) ? then : else_, v); +} + + +void ExprOpEq::eval(EvalState & state, Env & env, Value & v) +{ + Value v1; state.eval(env, e1, v1); + Value v2; state.eval(env, e2, v2); + mkBool(v, state.eqValues(v1, v2)); +} + + +void ExprOpNEq::eval(EvalState & state, Env & env, Value & v) +{ + Value v1; state.eval(env, e1, v1); + Value v2; state.eval(env, e2, v2); + mkBool(v, !state.eqValues(v1, v2)); +} + + +void ExprOpAnd::eval(EvalState & state, Env & env, Value & v) +{ + mkBool(v, state.evalBool(env, e1) && state.evalBool(env, e2)); +} + + +void ExprOpOr::eval(EvalState & state, Env & env, Value & v) +{ + mkBool(v, state.evalBool(env, e1) || state.evalBool(env, e2)); +} + + +void ExprOpImpl::eval(EvalState & state, Env & env, Value & v) +{ + mkBool(v, !state.evalBool(env, e1) || state.evalBool(env, e2)); +} + + +void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) +{ + Value v2; + state.eval(env, e1, v2); + state.forceAttrs(v2); + + state.cloneAttrs(v2, v); + + state.eval(env, e2, v2); + state.forceAttrs(v2); + + foreach (Bindings::iterator, i, *v2.attrs) + (*v.attrs)[i->first] = i->second; // !!! sharing +} + + +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); + state.forceList(v1); + Value v2; state.eval(env, e2, v2); + state.forceList(v2); + state.mkList(v, v1.list.length + v2.list.length); + /* !!! This loses sharing with the original lists. We could use a + tCopy node, but that would use more memory. */ + for (unsigned int n = 0; n < v1.list.length; ++n) + v.list.elems[n] = v1.list.elems[n]; + for (unsigned int n = 0; n < v2.list.length; ++n) + v.list.elems[n + v1.list.length] = v2.list.elems[n]; } @@ -827,7 +848,7 @@ string EvalState::forceStringNoCtx(Value & v) bool EvalState::isDerivation(Value & v) { if (v.type != tAttrs) return false; - Bindings::iterator i = v.attrs->find(toATerm("type")); + Bindings::iterator i = v.attrs->find("type"); return i != v.attrs->end() && forceStringNoCtx(i->second) == "derivation"; } @@ -871,7 +892,7 @@ string EvalState::coerceToString(Value & v, PathSet & context, } if (v.type == tAttrs) { - Bindings::iterator i = v.attrs->find(toATerm("outPath")); + Bindings::iterator i = v.attrs->find("outPath"); if (i == v.attrs->end()) throwTypeError("cannot coerce an attribute set (except a derivation) to a string"); return coerceToString(i->second, context, coerceMore, copyToStore); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index fb4dd802e0b0..cbdd09085d7d 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -3,7 +3,6 @@ #include -#include "aterm.hh" #include "nixexpr.hh" @@ -15,7 +14,7 @@ class EvalState; struct Env; struct Value; -typedef ATerm Sym; +typedef string Sym; typedef std::map Bindings; @@ -55,10 +54,32 @@ struct Value { int integer; bool boolean; + + /* Strings in the evaluator carry a so-called `context' (the + ATermList) which is a list of strings representing store + paths. This is to allow users to write things like + + "--with-freetype2-library=" + freetype + "/lib" + + where `freetype' is a derivation (or a source to be copied + to the store). If we just concatenated the strings without + keeping track of the referenced store paths, then if the + string is used as a derivation attribute, the derivation + will not have the correct dependencies in its inputDrvs and + inputSrcs. + + The semantics of the context is as follows: when a string + with context C is used as a derivation attribute, then the + derivations in C will be added to the inputDrvs of the + derivation, and the other store paths in C will be added to + the inputSrcs of the derivations. + + For canonicity, the store paths should be in sorted order. */ struct { const char * s; const char * * context; } string; + const char * path; Bindings * attrs; struct { @@ -67,15 +88,14 @@ struct Value } list; struct { Env * env; - Expr expr; + Expr * expr; } thunk; struct { Value * left, * right; } app; struct { Env * env; - Pattern pat; - Expr body; + ExprLambda * fun; } lambda; Value * val; struct { @@ -104,7 +124,7 @@ static inline void mkBool(Value & v, bool b) } -static inline void mkThunk(Value & v, Env & env, Expr expr) +static inline void mkThunk(Value & v, Env & env, Expr * expr) { v.type = tThunk; v.thunk.env = &env; @@ -146,7 +166,7 @@ private: bool allowUnsafeEquality; - ATermMap parseTrees; + std::map parseTrees; public: @@ -159,12 +179,12 @@ public: /* Evaluate an expression to normal form, storing the result in value `v'. */ - void eval(Expr e, Value & v); - void eval(Env & env, Expr e, Value & v); + void eval(Expr * e, Value & v); + void eval(Env & env, Expr * e, Value & v); /* Evaluation the expression, then verify that it has the expected type. */ - bool evalBool(Env & env, Expr e); + bool evalBool(Env & env, Expr * e); /* If `v' is a thunk, enter it and overwrite `v' with the result of the evaluation of the thunk. If `v' is a delayed function @@ -215,12 +235,12 @@ private: void addPrimOp(const string & name, unsigned int arity, PrimOp primOp); +public: + /* Do a deep equality test between two values. That is, list elements and attributes are compared recursively. */ bool eqValues(Value & v1, Value & v2); -public: - void callFunction(Value & fun, Value & arg, Value & v); /* Automatically call a function for which each argument has a @@ -233,7 +253,7 @@ public: void mkList(Value & v, unsigned int length); void mkAttrs(Value & v); - void mkThunk_(Value & v, Expr expr); + void mkThunk_(Value & v, Expr * expr); void cloneAttrs(Value & src, Value & dst); diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index f5e7242f9f5a..95938d5c1fa7 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -1,5 +1,4 @@ #include "get-drvs.hh" -#include "nixexpr-ast.hh" #include "util.hh" @@ -9,7 +8,7 @@ namespace nix { string DrvInfo::queryDrvPath(EvalState & state) const { if (drvPath == "") { - Bindings::iterator i = attrs->find(toATerm("drvPath")); + Bindings::iterator i = attrs->find("drvPath"); PathSet context; (string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; } @@ -20,7 +19,7 @@ string DrvInfo::queryDrvPath(EvalState & state) const string DrvInfo::queryOutPath(EvalState & state) const { if (outPath == "") { - Bindings::iterator i = attrs->find(toATerm("outPath")); + Bindings::iterator i = attrs->find("outPath"); PathSet context; (string &) outPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; } @@ -32,7 +31,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const { MetaInfo meta; - Bindings::iterator a = attrs->find(toATerm("meta")); + Bindings::iterator a = attrs->find("meta"); if (a == attrs->end()) return meta; /* fine, empty meta information */ state.forceAttrs(a->second); @@ -51,7 +50,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const for (unsigned int j = 0; j < i->second.list.length; ++j) value.stringValues.push_back(state.forceStringNoCtx(i->second.list.elems[j])); } else continue; - meta[aterm2String(i->first)] = value; + meta[i->first] = value; } return meta; @@ -114,12 +113,12 @@ static bool getDerivation(EvalState & state, Value & v, DrvInfo drv; - Bindings::iterator i = v.attrs->find(toATerm("name")); + Bindings::iterator i = v.attrs->find("name"); /* !!! We really would like to have a decent back trace here. */ if (i == v.attrs->end()) throw TypeError("derivation name missing"); drv.name = state.forceStringNoCtx(i->second); - i = v.attrs->find(toATerm("system")); + i = v.attrs->find("system"); if (i == v.attrs->end()) drv.system = "unknown"; else @@ -171,7 +170,7 @@ static void getDerivations(EvalState & state, Value & vIn, /* !!! undocumented hackery to support combining channels in nix-env.cc. */ - bool combineChannels = v.attrs->find(toATerm("_combineChannels")) != v.attrs->end(); + bool combineChannels = v.attrs->find("_combineChannels") != v.attrs->end(); /* Consider the attributes in sorted order to get more deterministic behaviour in nix-env operations (e.g. when @@ -180,12 +179,12 @@ static void getDerivations(EvalState & state, Value & vIn, precedence). */ StringSet attrs; foreach (Bindings::iterator, i, *v.attrs) - attrs.insert(aterm2String(i->first)); + attrs.insert(i->first); foreach (StringSet::iterator, i, attrs) { startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % *i); string pathPrefix2 = addToPath(pathPrefix, *i); - Value & v2((*v.attrs)[toATerm(*i)]); + Value & v2((*v.attrs)[*i]); if (combineChannels) getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); else if (getDerivation(state, v2, pathPrefix2, drvs, done)) { @@ -194,7 +193,7 @@ static void getDerivations(EvalState & state, Value & vIn, if it has a `recurseForDerivations = true' attribute. */ if (v2.type == tAttrs) { - Bindings::iterator j = v2.attrs->find(toATerm("recurseForDerivations")); + Bindings::iterator j = v2.attrs->find("recurseForDerivations"); if (j != v2.attrs->end() && state.forceBool(j->second)) getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); } diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l index 82c3500202b0..f750cfd02d54 100644 --- a/src/libexpr/lexer.l +++ b/src/libexpr/lexer.l @@ -8,9 +8,7 @@ %{ -#include "aterm.hh" #include "nixexpr.hh" -#include "nixexpr-ast.hh" #define BISON_HEADER_HACK #include "parser-tab.hh" @@ -45,8 +43,9 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len) } -static Expr unescapeStr(const char * s) +static Expr * unescapeStr(const char * s) { +#if 0 string t; char c; while ((c = *s++)) { @@ -66,6 +65,7 @@ static Expr unescapeStr(const char * s) else t += c; } return makeStr(toATerm(t), ATempty); +#endif } @@ -105,7 +105,7 @@ inherit { return INHERIT; } \/\/ { return UPDATE; } \+\+ { return CONCAT; } -{ID} { yylval->t = toATerm(yytext); return ID; /* !!! alloc */ } +{ID} { yylval->id = strdup(yytext); return ID; } {INT} { int n = atoi(yytext); /* !!! overflow */ yylval->n = n; return INT; @@ -117,7 +117,7 @@ inherit { return INHERIT; } shouldn't be followed by a "{". Right now "$\"" will be consumed as part of a string, rather than a "$" followed by the string terminator. Disallow "$\"" for now. */ - yylval->t = unescapeStr(yytext); /* !!! alloc */ + yylval->e = unescapeStr(yytext); return STR; } \$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; } @@ -126,31 +126,31 @@ inherit { return INHERIT; } \'\'(\ *\n)? { BEGIN(IND_STRING); return IND_STRING_OPEN; } ([^\$\']|\$[^\{\']|\'[^\'\$])+ { - yylval->t = makeIndStr(toATerm(yytext)); + //yylval->t = makeIndStr(toATerm(yytext)); return IND_STR; } \'\'\$ { - yylval->t = makeIndStr(toATerm("$")); + //yylval->t = makeIndStr(toATerm("$")); return IND_STR; } \'\'\' { - yylval->t = makeIndStr(toATerm("''")); + //yylval->t = makeIndStr(toATerm("''")); return IND_STR; } \'\'\\. { - yylval->t = unescapeStr(yytext + 2); + //yylval->t = unescapeStr(yytext + 2); return IND_STR; } \$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; } \'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; } \' { - yylval->t = makeIndStr(toATerm("'")); + //yylval->t = makeIndStr(toATerm("'")); return IND_STR; } . return yytext[0]; /* just in case: shouldn't be reached */ -{PATH} { yylval->t = toATerm(yytext); return PATH; /* !!! alloc */ } -{URI} { yylval->t = toATerm(yytext); return URI; /* !!! alloc */ } +{PATH} { yylval->path = strdup(yytext); return PATH; } +{URI} { yylval->uri = strdup(yytext); return URI; } [ \t\r\n]+ /* eat up whitespace */ \#[^\r\n]* /* single-line comments */ diff --git a/src/libexpr/nixexpr-ast.def b/src/libexpr/nixexpr-ast.def deleted file mode 100644 index 36c25dcfe7a0..000000000000 --- a/src/libexpr/nixexpr-ast.def +++ /dev/null @@ -1,97 +0,0 @@ -init initNixExprHelpers - -Pos | string int int | Pos | -NoPos | | Pos | - -Function | Pattern Expr Pos | Expr | -Assert | Expr Expr Pos | Expr | -With | Expr Expr Pos | Expr | -If | Expr Expr Expr | Expr | -OpNot | Expr | Expr | -OpEq | Expr Expr | Expr | -OpNEq | Expr Expr | Expr | -OpAnd | Expr Expr | Expr | -OpOr | Expr Expr | Expr | -OpImpl | Expr Expr | Expr | -OpUpdate | Expr Expr | Expr | -OpHasAttr | Expr string | Expr | -OpPlus | Expr Expr | Expr | -OpConcat | Expr Expr | Expr | -ConcatStrings | ATermList | Expr | -Call | Expr Expr | Expr | -Select | Expr string | Expr | -Var | string | Expr | -Int | int | Expr | - -# Strings in the evaluator carry a so-called `context' (the ATermList) -# which is a list of strings representing store paths. This is to -# allow users to write things like -# -# "--with-freetype2-library=" + freetype + "/lib" -# -# where `freetype' is a derivation (or a source to be copied to the -# store). If we just concatenated the strings without keeping track -# of the referenced store paths, then if the string is used as a -# derivation attribute, the derivation will not have the correct -# dependencies in its inputDrvs and inputSrcs. -# -# The semantics of the context is as follows: when a string with -# context C is used as a derivation attribute, then the derivations in -# C will be added to the inputDrvs of the derivation, and the other -# store paths in C will be added to the inputSrcs of the derivations. -# -# For canonicity, the store paths should be in sorted order. -Str | string ATermList | Expr | -Str | string | Expr | ObsoleteStr - -# Internal to the parser, doesn't occur in ASTs. -IndStr | string | Expr | - -# A path is a reference to a file system object that is to be copied -# to the Nix store when used as a derivation attribute. When it is -# concatenated to a string (i.e., `str + path'), it is also copied and -# the resulting store path is concatenated to the string (with the -# store path in the context). If a string or path is concatenated to -# a path (i.e., `path + str' or `path + path'), the result is a new -# path (if the right-hand side is a string, the context must be -# empty). -Path | string | Expr | - -List | ATermList | Expr | -BlackHole | | Expr | -Undefined | | Expr | -Removed | | Expr | -PrimOp | int ATermBlob ATermList | Expr | -Attrs | ATermList | Expr | -Closed | Expr | Expr | -Rec | ATermList ATermList | Expr | -Bool | ATermBool | Expr | -Null | | Expr | - -Bind | string Expr Pos | ATerm | -BindAttrPath | ATermList Expr Pos | ATerm | # desugared during parsing -Bind | string Expr | ATerm | ObsoleteBind -Inherit | Expr ATermList Pos | ATerm | - -Scope | | Expr | - -VarPat | string | Pattern | -AttrsPat | ATermList ATermBool string | Pattern | # bool = `...' - -Formal | string DefaultValue | ATerm | - -DefaultValue | Expr | DefaultValue | -NoDefaultValue | | DefaultValue | - -True | | ATermBool | -False | | ATermBool | - -PrimOpDef | int ATermBlob | ATerm | - -AttrRHS | Expr Pos | ATerm | - -eTrue = makeBool(makeTrue()) -eFalse = makeBool(makeFalse()) -sOverrides = toATerm("__overrides") -sNoAlias = toATerm("") -sWith = toATerm("") diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 3c5d02b34f66..05dfbd3223e3 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -1,17 +1,94 @@ #include "nixexpr.hh" #include "derivations.hh" #include "util.hh" -#include "aterm.hh" - -#include "nixexpr-ast.hh" -#include "nixexpr-ast.cc" #include namespace nix { - + +std::ostream & operator << (std::ostream & str, Expr & e) +{ + e.show(str); + return str; +} + + +void ExprInt::show(std::ostream & str) +{ + str << n; +} + +void ExprString::show(std::ostream & str) +{ + str << "\"" << s << "\""; // !!! escaping +} + +void ExprPath::show(std::ostream & str) +{ + str << s; +} + +void ExprVar::show(std::ostream & str) +{ + str << name; +} + +void ExprSelect::show(std::ostream & str) +{ + str << "(" << *e << ")." << name; +} + +void ExprAttrs::show(std::ostream & str) +{ + if (recursive) str << "rec "; + str << "{ "; + foreach (list::iterator, i, inherited) + str << "inherited " << *i << "; "; + foreach (Attrs::iterator, i, attrs) + str << i->first << " = " << *i->second << "; "; + str << "}"; +} + +void ExprList::show(std::ostream & str) +{ + str << "[ "; + foreach (vector::iterator, i, elems) + str << "(" << **i << ") "; + str << "]"; +} + +void ExprLambda::show(std::ostream & str) +{ + str << "("; + if (matchAttrs) { + str << "{ "; + bool first = true; + foreach (Formals::Formals_::iterator, i, formals->formals) { + if (first) first = false; else str << ", "; + str << i->name; + if (i->def) str << " ? " << *i->def; + } + str << " }"; + if (arg != "") str << " @ "; + } + if (arg != "") str << arg; + str << ": " << *body << ")"; +} + +void ExprWith::show(std::ostream & str) +{ + str << "with " << *attrs << "; " << *body; +} + +void ExprIf::show(std::ostream & str) +{ + str << "if " << *cond << " then " << *then << " else " << *else_; +} + + +#if 0 string showPos(ATerm pos) { ATerm path; @@ -159,28 +236,7 @@ void checkVarDefs(const ATermMap & defs, Expr e) set done; checkVarDefs2(done, defs, e); } - - -bool matchStr(Expr e, string & s, PathSet & context) -{ - ATermList l; - ATerm s_; - - if (!matchStr(e, s_, l)) return false; - - s = aterm2String(s_); - - for (ATermIterator i(l); i; ++i) - context.insert(aterm2String(*i)); - - return true; -} - - -Expr makeStr(const string & s, const PathSet & context) -{ - return makeStr(toATerm(s), toATermList(context)); -} +#endif } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 9f1050d807d4..ebdfd0a152ca 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -3,7 +3,6 @@ #include -#include "aterm-map.hh" #include "types.hh" @@ -18,22 +17,152 @@ MakeError(Abort, EvalError) MakeError(TypeError, EvalError) -/* Nix expressions are represented as ATerms. The maximal sharing - property of the ATerm library allows us to implement caching of - normals forms efficiently. */ -typedef ATerm Expr; -typedef ATerm DefaultValue; -typedef ATerm Pos; -typedef ATerm Pattern; -typedef ATerm ATermBool; +struct Pos +{ + string file; + unsigned int line, column; +}; + + +/* Abstract syntax of Nix expressions. */ + +struct Env; +struct Value; +struct EvalState; + +struct Expr +{ + virtual void show(std::ostream & str) = 0; + virtual void eval(EvalState & state, Env & env, Value & v) + { + throw Error("not implemented"); + } +}; + +std::ostream & operator << (std::ostream & str, Expr & e); + +#define COMMON_METHODS \ + void show(std::ostream & str); \ + void eval(EvalState & state, Env & env, Value & v); + +struct ExprInt : Expr +{ + int n; + ExprInt(int n) : n(n) { }; + COMMON_METHODS +}; + +struct ExprString : Expr +{ + string s; + ExprString(const string & s) : s(s) { }; + COMMON_METHODS +}; + +struct ExprPath : Expr +{ + string s; + ExprPath(const string & s) : s(s) { }; + COMMON_METHODS +}; + +struct ExprVar : Expr +{ + string name; + ExprVar(const string & name) : name(name) { }; + COMMON_METHODS +}; + +struct ExprSelect : Expr +{ + Expr * e; + string name; + ExprSelect(Expr * e, const string & name) : e(e), name(name) { }; + COMMON_METHODS +}; + +struct ExprAttrs : Expr +{ + bool recursive; + typedef std::map Attrs; + Attrs attrs; + list inherited; + ExprAttrs() : recursive(false) { }; + COMMON_METHODS +}; +struct ExprList : Expr +{ + std::vector elems; + ExprList() { }; + COMMON_METHODS +}; -/* A STL vector of ATerms. Should be used with great care since it's - stored on the heap, and the elements are therefore not roots to the - ATerm garbage collector. */ -typedef vector ATermVector; +struct Formal +{ + string name; + Expr * def; + Formal(const string & name, Expr * def) : name(name), def(def) { }; +}; +struct Formals +{ + typedef std::list Formals_; + Formals_ formals; + bool ellipsis; +}; +struct ExprLambda : Expr +{ + Pos pos; + string arg; + bool matchAttrs; + Formals * formals; + Expr * body; + ExprLambda(const Pos & pos, const string & arg, bool matchAttrs, Formals * formals, Expr * body) + : pos(pos), arg(arg), matchAttrs(matchAttrs), formals(formals), body(body) { }; + COMMON_METHODS +}; + +struct ExprWith : Expr +{ + Pos pos; + Expr * attrs, * body; + ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { }; + COMMON_METHODS +}; + +struct ExprIf : Expr +{ + Expr * cond, * then, * else_; + ExprIf(Expr * cond, Expr * then, Expr * else_) : cond(cond), then(then), else_(else_) { }; + COMMON_METHODS +}; + +#define MakeBinOp(name, s) \ + struct Expr##name : Expr \ + { \ + Expr * e1, * e2; \ + Expr##name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \ + void show(std::ostream & str) \ + { \ + str << *e1 << " " s " " << *e2; \ + } \ + void eval(EvalState & state, Env & env, Value & v); \ + }; + +MakeBinOp(App, "") +MakeBinOp(OpEq, "==") +MakeBinOp(OpNEq, "!=") +MakeBinOp(OpAnd, "&&") +MakeBinOp(OpOr, "||") +MakeBinOp(OpImpl, "->") +MakeBinOp(OpUpdate, "//") +MakeBinOp(OpConcatStrings, "+") +MakeBinOp(OpConcatLists, "++") + + +#if 0 /* Show a position. */ string showPos(ATerm pos); @@ -56,13 +185,7 @@ Expr makeAttrs(const ATermMap & attrs); /* Check whether all variables are defined in the given expression. Throw an exception if this isn't the case. */ void checkVarDefs(const ATermMap & def, Expr e); - - -/* Manipulation of Str() nodes. Note: matchStr() does not clear - context! */ -bool matchStr(Expr e, string & s, PathSet & context); - -Expr makeStr(const string & s, const PathSet & context = PathSet()); +#endif } diff --git a/src/libexpr/parser.hh b/src/libexpr/parser.hh index 3f430eb32539..d1e531ca2921 100644 --- a/src/libexpr/parser.hh +++ b/src/libexpr/parser.hh @@ -9,11 +9,10 @@ namespace nix { /* Parse a Nix expression from the specified file. If `path' refers to a directory, then "/default.nix" is appended. */ -Expr parseExprFromFile(EvalState & state, Path path); +Expr * parseExprFromFile(Path path); /* Parse a Nix expression from the specified string. */ -Expr parseExprFromString(EvalState & state, const string & s, - const Path & basePath); +Expr * parseExprFromString(const string & s, const Path & basePath); } diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index a28d56d24f67..96fbe2cb4be2 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -23,13 +23,12 @@ #include "aterm.hh" #include "util.hh" +#include "nixexpr.hh" + #include "parser-tab.hh" #include "lexer-tab.hh" #define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4 -#include "nixexpr.hh" -#include "nixexpr-ast.hh" - using namespace nix; @@ -39,13 +38,14 @@ namespace nix { struct ParseData { - Expr result; + Expr * result; Path basePath; Path path; string error; }; - + +#if 0 static string showAttrPath(ATermList attrPath) { string s; @@ -79,10 +79,12 @@ static ATermList buildAttrs(const Tree & t, ATermList & nonrec) : makeBind(i->first, makeAttrs(buildAttrs(i->second, nonrec)), makeNoPos())); return res; } +#endif -static Expr fixAttrs(bool recursive, ATermList as) +static void fixAttrs(ExprAttrs & attrs) { +#if 0 Tree attrs; /* This ATermMap is needed to ensure that the `leaf' fields in the @@ -135,9 +137,11 @@ static Expr fixAttrs(bool recursive, ATermList as) ATermList rec = buildAttrs(attrs, nonrec); return recursive ? makeRec(rec, nonrec) : makeAttrs(rec); +#endif } +#if 0 static void checkPatternVars(ATerm pos, ATermMap & map, Pattern pat) { ATerm name = sNoAlias; @@ -261,6 +265,7 @@ static Expr stripIndentation(ATermList es) return makeConcatStrings(ATreverse(es2)); } +#endif void backToString(yyscan_t scanner); @@ -269,8 +274,11 @@ void backToIndString(yyscan_t scanner); static Pos makeCurPos(YYLTYPE * loc, ParseData * data) { - return makePos(toATerm(data->path), - loc->first_line, loc->first_column); + Pos pos; + pos.file = data->path; + pos.line = loc->first_line; + pos.column = loc->first_column; + return pos; } #define CUR_POS makeCurPos(yylocp, data) @@ -311,22 +319,31 @@ static void freeAndUnprotect(void * p) %} %union { - ATerm t; - ATermList ts; - struct { - ATermList formals; - bool ellipsis; - } formals; + nix::Expr * e; + nix::ExprList * list; + nix::ExprAttrs * attrs; + nix::Formals * formals; + nix::Formal * formal; int n; + char * id; + char * path; + char * uri; + std::list * ids; } -%type start expr expr_function expr_if expr_op -%type expr_app expr_select expr_simple bind inheritsrc formal -%type pattern -%type binds ids attrpath expr_list string_parts ind_string_parts +%type start expr expr_function expr_if expr_op +%type expr_app expr_select expr_simple +%type expr_list +%type binds +%type attrpath string_parts ind_string_parts %type formals -%token ID STR IND_STR PATH URI +%type formal +%type ids +%token ID ATTRPATH +%token STR IND_STR %token INT +%token PATH +%token URI %token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL %token DOLLAR_CURLY /* == ${ */ %token IND_STRING_OPEN IND_STRING_CLOSE @@ -350,54 +367,63 @@ start: expr { data->result = $1; }; expr: expr_function; expr_function - : pattern ':' expr_function - { checkPatternVars(CUR_POS, $1); $$ = makeFunction($1, $3, CUR_POS); } - | ASSERT expr ';' expr_function + : ID ':' expr_function + { $$ = new ExprLambda(CUR_POS, $1, false, 0, $3); /* checkPatternVars(CUR_POS, $1); $$ = makeFunction($1, $3, CUR_POS); */ } + | '{' formals '}' ':' expr_function + { $$ = new ExprLambda(CUR_POS, "", true, $2, $5); } + | '{' formals '}' '@' ID ':' 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); } + */ | WITH expr ';' expr_function - { $$ = makeWith($2, $4, CUR_POS); } + { $$ = new ExprWith(CUR_POS, $2, $4); } | LET binds IN expr_function - { $$ = makeSelect(fixAttrs(true, ATinsert($2, makeBindAttrPath(ATmakeList1(toATerm("")), $4, CUR_POS))), toATerm("")); } + { $2->attrs[""] = $4; $2->recursive = true; fixAttrs(*$2); $$ = new ExprSelect($2, ""); } | expr_if ; expr_if - : IF expr THEN expr ELSE expr - { $$ = makeIf($2, $4, $6); } + : IF expr THEN expr ELSE expr { $$ = new ExprIf($2, $4, $6); } | expr_op ; expr_op - : '!' expr_op %prec NEG { $$ = makeOpNot($2); } - | expr_op EQ expr_op { $$ = makeOpEq($1, $3); } - | expr_op NEQ expr_op { $$ = makeOpNEq($1, $3); } - | expr_op AND expr_op { $$ = makeOpAnd($1, $3); } - | expr_op OR expr_op { $$ = makeOpOr($1, $3); } - | expr_op IMPL expr_op { $$ = makeOpImpl($1, $3); } - | expr_op UPDATE expr_op { $$ = makeOpUpdate($1, $3); } + : /* '!' expr_op %prec NEG { $$ = makeOpNot($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 { $$ = makeConcatStrings(ATmakeList2($1, $3)); } - | expr_op CONCAT expr_op { $$ = makeOpConcat($1, $3); } + */ + | expr_op '+' expr_op { $$ = new ExprOpConcatStrings($1, $3); } + | expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); } | expr_app ; expr_app : expr_app expr_select - { $$ = makeCall($1, $2); } + { $$ = new ExprApp($1, $2); } | expr_select { $$ = $1; } ; expr_select : expr_select '.' ID - { $$ = makeSelect($1, $3); } + { $$ = new ExprSelect($1, $3); } | expr_simple { $$ = $1; } ; expr_simple - : ID { $$ = makeVar($1); } - | INT { $$ = makeInt($1); } + : ID { $$ = new ExprVar($1); } + | INT { $$ = new ExprInt($1); } /* | '"' string_parts '"' { - /* For efficiency, and to simplify parse trees a bit. */ + /* 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)); @@ -405,18 +431,21 @@ expr_simple | IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE { $$ = stripIndentation(ATreverse($2)); } - | PATH { $$ = makePath(toATerm(absPath(aterm2String($1), data->basePath))); } - | URI { $$ = makeStr($1, ATempty); } + */ + | 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")); } + */ | REC '{' binds '}' - { $$ = fixAttrs(true, $3); } + { fixAttrs(*$3); $3->recursive = true; $$ = $3; } | '{' binds '}' - { $$ = fixAttrs(false, $2); } - | '[' expr_list ']' { $$ = makeList(ATreverse($2)); } + { fixAttrs(*$2); $$ = $2; } + | '[' expr_list ']' { $$ = $2; } ; string_parts @@ -431,63 +460,56 @@ ind_string_parts | { $$ = ATempty; } ; -pattern - : ID { $$ = makeVarPat($1); } - | '{' formals '}' { $$ = makeAttrsPat($2.formals, $2.ellipsis ? eTrue : eFalse, sNoAlias); } - | '{' formals '}' '@' ID { $$ = makeAttrsPat($2.formals, $2.ellipsis ? eTrue : eFalse, $5); } - | ID '@' '{' formals '}' { $$ = makeAttrsPat($4.formals, $4.ellipsis ? eTrue : eFalse, $1); } - ; - binds - : binds bind { $$ = ATinsert($1, $2); } - | { $$ = ATempty; } - ; - -bind - : attrpath '=' expr ';' - { $$ = makeBindAttrPath(ATreverse($1), $3, CUR_POS); } - | INHERIT inheritsrc ids ';' - { $$ = makeInherit($2, $3, CUR_POS); } + : binds ID '=' expr ';' { $$ = $1; $$->attrs[$2] = $4; } + | binds INHERIT ids ';' + { $$ = $1; + foreach (list::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) + $$->attrs[*i] = new ExprSelect($4, *i); + } + | { $$ = new ExprAttrs; } ; -inheritsrc - : '(' expr ')' { $$ = $2; } - | { $$ = makeScope(); } +ids + : ids ID { $$ = $1; $1->push_back($2); /* !!! dangerous */ } + | { $$ = new list; } ; -ids: ids ID { $$ = ATinsert($1, $2); } | { $$ = ATempty; }; - attrpath : attrpath '.' ID { $$ = ATinsert($1, $3); } | ID { $$ = ATmakeList1($1); } ; expr_list - : expr_list expr_select { $$ = ATinsert($1, $2); } - | { $$ = ATempty; } + : expr_list expr_select { $$ = $1; $1->elems.push_back($2); /* !!! dangerous */ } + | { $$ = new ExprList; } ; formals - : formal ',' formals /* !!! right recursive */ - { $$.formals = ATinsert($3.formals, $1); $$.ellipsis = $3.ellipsis; } + : formal ',' formals + { $$ = $3; $$->formals.push_front(*$1); /* !!! dangerous */ } | formal - { $$.formals = ATinsert(ATempty, $1); $$.ellipsis = false; } + { $$ = new Formals; $$->formals.push_back(*$1); $$->ellipsis = false; } | - { $$.formals = ATempty; $$.ellipsis = false; } + { $$ = new Formals; $$->ellipsis = false; } | ELLIPSIS - { $$.formals = ATempty; $$.ellipsis = true; } + { $$ = new Formals; $$->ellipsis = true; } ; formal - : ID { $$ = makeFormal($1, makeNoDefaultValue()); } - | ID '?' expr { $$ = makeFormal($1, makeDefaultValue($3)); } + : ID { $$ = new Formal($1, 0); } + | ID '?' expr { $$ = new Formal($1, $3); } ; %% -#include "eval.hh" - #include #include #include @@ -497,9 +519,7 @@ formal namespace nix { -static Expr parse(EvalState & state, - const char * text, const Path & path, - const Path & basePath) +static Expr * parse(const char * text, const Path & path, const Path & basePath) { yyscan_t scanner; ParseData data; @@ -523,7 +543,7 @@ static Expr parse(EvalState & state, } -Expr parseExprFromFile(EvalState & state, Path path) +Expr * parseExprFromFile(Path path) { assert(path[0] == '/'); @@ -544,14 +564,13 @@ Expr parseExprFromFile(EvalState & state, Path path) path = canonPath(path + "/default.nix"); /* Read and parse the input file. */ - return parse(state, readFile(path).c_str(), path, dirOf(path)); + return parse(readFile(path).c_str(), path, dirOf(path)); } -Expr parseExprFromString(EvalState & state, - const string & s, const Path & basePath) +Expr * parseExprFromString(const string & s, const Path & basePath) { - return parse(state, s.c_str(), "(string)", basePath); + return parse(s.c_str(), "(string)", basePath); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 74eb2b26d068..cd40ade008cf 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -5,7 +5,6 @@ #include "util.hh" #include "archive.hh" #include "value-to-xml.hh" -#include "nixexpr-ast.hh" #include "parser.hh" #include "names.hh" @@ -281,7 +280,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) state.forceAttrs(*args[0]); /* Figure out the name first (for stack backtraces). */ - Bindings::iterator attr = args[0]->attrs->find(toATerm("name")); + Bindings::iterator attr = args[0]->attrs->find("name"); if (attr == args[0]->attrs->end()) throw EvalError("required attribute `name' missing"); string drvName; @@ -302,7 +301,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) bool outputHashRecursive = false; foreach (Bindings::iterator, i, *args[0]->attrs) { - string key = aterm2String(i->first); + string key = i->first; startNest(nest, lvlVomit, format("processing attribute `%1%'") % key); try { @@ -449,8 +448,8 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) /* !!! assumes a single output */ state.mkAttrs(v); - mkString((*v.attrs)[toATerm("outPath")], outPath, singleton(drvPath)); - mkString((*v.attrs)[toATerm("drvPath")], drvPath, singleton("=" + drvPath)); + mkString((*v.attrs)["outPath"], outPath, singleton(drvPath)); + mkString((*v.attrs)["drvPath"], drvPath, singleton("=" + drvPath)); } @@ -655,7 +654,7 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v) StringSet names; foreach (Bindings::iterator, i, *args[0]->attrs) - names.insert(aterm2String(i->first)); + names.insert(i->first); unsigned int n = 0; foreach (StringSet::iterator, i, names) @@ -668,7 +667,7 @@ static void prim_getAttr(EvalState & state, Value * * args, Value & v) { string attr = state.forceStringNoCtx(*args[0]); state.forceAttrs(*args[1]); - Bindings::iterator i = args[1]->attrs->find(toATerm(attr)); + Bindings::iterator i = args[1]->attrs->find(attr); if (i == args[1]->attrs->end()) throw EvalError(format("attribute `%1%' missing") % attr); state.forceValue(i->second); @@ -681,7 +680,7 @@ static void prim_hasAttr(EvalState & state, Value * * args, Value & v) { string attr = state.forceStringNoCtx(*args[0]); state.forceAttrs(*args[1]); - mkBool(v, args[1]->attrs->find(toATerm(attr)) != args[1]->attrs->end()); + mkBool(v, args[1]->attrs->find(attr) != args[1]->attrs->end()); } @@ -702,7 +701,7 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) for (unsigned int i = 0; i < args[1]->list.length; ++i) { state.forceStringNoCtx(args[1]->list.elems[i]); - v.attrs->erase(toATerm(args[1]->list.elems[i].string.s)); + v.attrs->erase(args[1]->list.elems[i].string.s); } } @@ -721,16 +720,16 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) Value & v2(args[0]->list.elems[i]); state.forceAttrs(v2); - Bindings::iterator j = v2.attrs->find(toATerm("name")); + Bindings::iterator j = v2.attrs->find("name"); if (j == v2.attrs->end()) throw TypeError("`name' attribute missing in a call to `listToAttrs'"); string name = state.forceStringNoCtx(j->second); - j = v2.attrs->find(toATerm("value")); + j = v2.attrs->find("value"); if (j == v2.attrs->end()) throw TypeError("`value' attribute missing in a call to `listToAttrs'"); - (*v.attrs)[toATerm(name)] = j->second; // !!! sharing? + (*v.attrs)[name] = j->second; // !!! sharing? } } @@ -977,8 +976,8 @@ static void prim_parseDrvName(EvalState & state, Value * * args, Value & v) string name = state.forceStringNoCtx(*args[0]); DrvName parsed(name); state.mkAttrs(v); - mkString((*v.attrs)[toATerm("name")], parsed.name); - mkString((*v.attrs)[toATerm("version")], parsed.version); + mkString((*v.attrs)["name"], parsed.name); + mkString((*v.attrs)["version"], parsed.version); } @@ -999,10 +998,9 @@ void EvalState::createBaseEnv() { baseEnv.up = 0; - { Value & v = baseEnv.bindings[toATerm("builtins")]; - v.type = tAttrs; - v.attrs = new Bindings; - } + Value & builtins = baseEnv.bindings["builtins"]; + builtins.type = tAttrs; + builtins.attrs = new Bindings; /* Add global constants such as `true' to the base environment. */ Value v; @@ -1025,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(*this, s, "/")); - addConstant("derivation", v); + //mkThunk(v, baseEnv, parseExprFromString(s, "/")); + //addConstant("derivation", v); // Miscellaneous addPrimOp("import", 1, prim_import); diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index eff414aba3b5..c8a067aacf77 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -1,7 +1,5 @@ #include "value-to-xml.hh" #include "xml-writer.hh" -#include "nixexpr-ast.hh" -#include "aterm.hh" #include "util.hh" #include @@ -27,31 +25,10 @@ static void showAttrs(EvalState & state, bool strict, Bindings & attrs, { StringSet names; foreach (Bindings::iterator, i, attrs) - names.insert(aterm2String(i->first)); + names.insert(i->first); foreach (StringSet::iterator, i, names) { XMLOpenElement _(doc, "attr", singletonAttrs("name", *i)); - printValueAsXML(state, strict, attrs[toATerm(*i)], doc, context, drvsSeen); - } -} - - -static void printPatternAsXML(Pattern pat, XMLWriter & doc) -{ - ATerm name; - ATermList formals; - ATermBool ellipsis; - if (matchVarPat(pat, name)) - doc.writeEmptyElement("varpat", singletonAttrs("name", aterm2String(name))); - else if (matchAttrsPat(pat, formals, ellipsis, name)) { - XMLAttrs attrs; - if (name != sNoAlias) attrs["name"] = aterm2String(name); - if (ellipsis == eTrue) attrs["ellipsis"] = "1"; - XMLOpenElement _(doc, "attrspat", attrs); - for (ATermIterator i(formals); i; ++i) { - Expr name; ATerm dummy; - if (!matchFormal(*i, name, dummy)) abort(); - doc.writeEmptyElement("attr", singletonAttrs("name", aterm2String(name))); - } + printValueAsXML(state, strict, attrs[*i], doc, context, drvsSeen); } } @@ -90,14 +67,14 @@ static void printValueAsXML(EvalState & state, bool strict, Value & v, if (state.isDerivation(v)) { XMLAttrs xmlAttrs; - Bindings::iterator a = v.attrs->find(toATerm("derivation")); + Bindings::iterator a = v.attrs->find("derivation"); Path drvPath; - a = v.attrs->find(toATerm("drvPath")); + a = v.attrs->find("drvPath"); if (a != v.attrs->end() && a->second.type == tString) xmlAttrs["drvPath"] = drvPath = a->second.string.s; - a = v.attrs->find(toATerm("outPath")); + a = v.attrs->find("outPath"); if (a != v.attrs->end() && a->second.type == tString) xmlAttrs["outPath"] = a->second.string.s; @@ -126,7 +103,15 @@ static void printValueAsXML(EvalState & state, bool strict, Value & v, case tLambda: { XMLOpenElement _(doc, "function"); - printPatternAsXML(v.lambda.pat, doc); + if (v.lambda.fun->matchAttrs) { + XMLAttrs attrs; + if (!v.lambda.fun->arg.empty()) attrs["name"] = v.lambda.fun->arg; + if (v.lambda.fun->formals->ellipsis) attrs["ellipsis"] = "1"; + XMLOpenElement _(doc, "attrspat", attrs); + foreach (Formals::Formals_::iterator, i, v.lambda.fun->formals->formals) + doc.writeEmptyElement("attr", singletonAttrs("name", i->name)); + } else + doc.writeEmptyElement("varpat", singletonAttrs("name", v.lambda.fun->arg)); break; } diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index d9cf9a86262a..c53c558c1cdd 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 diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 20affa83ddd0..6286648d14a0 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -6,7 +6,6 @@ #include "parser.hh" #include "eval.hh" #include "help.txt.hh" -#include "nixexpr-ast.hh" #include "get-drvs.hh" #include "attr-path.hh" #include "pathlocks.hh" @@ -143,9 +142,9 @@ static void getAllExprs(EvalState & state, } -static Expr loadSourceExpr(EvalState & state, const Path & path) +static Expr * loadSourceExpr(EvalState & state, const Path & path) { - if (isNixExpr(path)) return parseExprFromFile(state, absPath(path)); + if (isNixExpr(path)) return parseExprFromFile(absPath(path)); /* The path is a directory. Put the Nix expressions in the directory in an attribute set, with the file name of each diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 7931af6abd02..466c7b499e22 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -23,12 +23,12 @@ void printHelp() } -static Expr parseStdin(EvalState & state) +static Expr * parseStdin(EvalState & state) { startNest(nest, lvlTalkative, format("parsing standard input")); string s, s2; while (getline(std::cin, s2)) s += s2 + "\n"; - return parseExprFromString(state, s, absPath(".")); + return parseExprFromString(s, absPath(".")); } @@ -39,7 +39,7 @@ static bool indirectRoot = false; void processExpr(EvalState & state, const Strings & attrPaths, bool parseOnly, bool strict, const Bindings & autoArgs, - bool evalOnly, bool xmlOutput, Expr e) + bool evalOnly, bool xmlOutput, Expr * e) { if (parseOnly) std::cout << format("%1%\n"); @@ -129,14 +129,14 @@ void run(Strings args) store = openStore(); if (readStdin) { - Expr e = parseStdin(state); + Expr * e = parseStdin(state); processExpr(state, attrPaths, parseOnly, strict, autoArgs, evalOnly, xmlOutput, e); } foreach (Strings::iterator, i, files) { Path path = absPath(*i); - Expr e = parseExprFromFile(state, path); + Expr * e = parseExprFromFile(path); processExpr(state, attrPaths, parseOnly, strict, autoArgs, evalOnly, xmlOutput, e); } -- cgit 1.4.1 From ac1e8f40d4a5c380d68bb6f1c7cef6f1e7987c1a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 13 Apr 2010 12:25:42 +0000 Subject: * Use a symbol table to represent identifiers and attribute names efficiently. The symbol table ensures that there is only one copy of each symbol, thus allowing symbols to be compared efficiently using a pointer equality test. --- src/libexpr/Makefile.am | 2 +- src/libexpr/attr-path.cc | 2 +- src/libexpr/common-opts.cc | 4 +- src/libexpr/eval-test.cc | 25 +++++++++++- src/libexpr/eval.cc | 45 +++++++++++--------- src/libexpr/eval.hh | 16 ++++++-- src/libexpr/get-drvs.cc | 16 ++++---- src/libexpr/nixexpr.cc | 6 +-- src/libexpr/nixexpr.hh | 26 ++++++------ src/libexpr/parser.hh | 4 +- src/libexpr/parser.y | 69 ++++++++++++++++++------------- src/libexpr/primops.cc | 27 ++++++------ src/libexpr/symbol-table.hh | 75 ++++++++++++++++++++++++++++++++++ src/libexpr/value-to-xml.cc | 8 ++-- src/nix-instantiate/nix-instantiate.cc | 4 +- 15 files changed, 228 insertions(+), 101 deletions(-) create mode 100644 src/libexpr/symbol-table.hh (limited to 'src/libexpr/attr-path.cc') diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am index 60b1815d9690..39423394af69 100644 --- a/src/libexpr/Makefile.am +++ b/src/libexpr/Makefile.am @@ -8,7 +8,7 @@ libexpr_la_SOURCES = \ pkginclude_HEADERS = \ nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \ get-drvs.hh attr-path.hh value-to-xml.hh common-opts.hh \ - names.hh + names.hh symbol-table.hh libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \ ../boost/format/libformat.la diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index aa421ab431da..b53837781573 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -45,7 +45,7 @@ void findAlongAttrPath(EvalState & state, const string & attrPath, format("the expression selected by the selection path `%1%' should be an attribute set but is %2%") % curPath % showType(v)); - Bindings::iterator a = v.attrs->find(attr); + Bindings::iterator a = v.attrs->find(state.symbols.create(attr)); if (a == v.attrs->end()) throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); v = a->second; diff --git a/src/libexpr/common-opts.cc b/src/libexpr/common-opts.cc index 6171de0f0e84..a25317de1346 100644 --- a/src/libexpr/common-opts.cc +++ b/src/libexpr/common-opts.cc @@ -20,10 +20,10 @@ bool parseOptionArg(const string & arg, Strings::iterator & i, if (i == argsEnd) throw error; string value = *i++; - Value & v(autoArgs[name]); + Value & v(autoArgs[state.symbols.create(name)]); if (arg == "--arg") - state.mkThunk_(v, parseExprFromString(value, absPath("."))); + state.mkThunk_( v, parseExprFromString(state, value, absPath("."))); else mkString(v, value); diff --git a/src/libexpr/eval-test.cc b/src/libexpr/eval-test.cc index ffadd41a7c7a..d03d3bdeed1b 100644 --- a/src/libexpr/eval-test.cc +++ b/src/libexpr/eval-test.cc @@ -12,7 +12,7 @@ using namespace nix; void doTest(EvalState & state, string s) { - Expr * e = parseExprFromString(s, absPath(".")); + Expr * e = parseExprFromString(state, s, absPath(".")); std::cerr << ">>>>> " << *e << std::endl; Value v; state.eval(e, v); @@ -23,6 +23,29 @@ void doTest(EvalState & state, string s) void run(Strings args) { + SymbolTable t; + + printMsg(lvlError, format("size of symbol: %1% bytes") % sizeof(Symbol)); + + Symbol s1 = t.create("foo"); + Symbol s2 = t.create("foo"); + Symbol s3 = t.create("bar"); + Symbol s4 = t.create("foo"); + + assert(s1 == s2); + assert(s1 == s4); + assert(s1 != s3); + + std::map m; + + m[s1] = 123; + m[s3] = 456; + + std::cout << m[s1] << std::endl; + std::cout << m[s2] << std::endl; + std::cout << m[s3] << std::endl; + std::cout << m[s4] << std::endl; + EvalState state; printMsg(lvlError, format("size of value: %1% bytes") % sizeof(Value)); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 99149fd7f9fe..ffeae8d7311b 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -43,8 +43,8 @@ std::ostream & operator << (std::ostream & str, Value & v) break; case tAttrs: str << "{ "; - foreach (Bindings::iterator, i, *v.attrs) - str << i->first << " = " << i->second << "; "; + foreach (Bindings::iterator, i, *v.attrs) + str << (string) i->first << " = " << i->second << "; "; str << "}"; break; case tList: @@ -91,7 +91,14 @@ string showType(Value & v) } -EvalState::EvalState() : baseEnv(allocEnv()) +EvalState::EvalState() + : sWith(symbols.create("")) + , sOutPath(symbols.create("outPath")) + , sDrvPath(symbols.create("drvPath")) + , sType(symbols.create("type")) + , sMeta(symbols.create("meta")) + , sName(symbols.create("name")) + , baseEnv(allocEnv()) { nrValues = nrEnvs = nrEvaluated = recursionDepth = maxRecursionDepth = 0; deepestStack = (char *) -1; @@ -110,9 +117,9 @@ EvalState::~EvalState() void EvalState::addConstant(const string & name, Value & v) { - baseEnv.bindings[name] = v; + baseEnv.bindings[symbols.create(name)] = v; string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; - (*baseEnv.bindings["builtins"].attrs)[name2] = v; + (*baseEnv.bindings[symbols.create("builtins")].attrs)[symbols.create(name2)] = v; nrValues += 2; } @@ -124,9 +131,9 @@ void EvalState::addPrimOp(const string & name, v.type = tPrimOp; v.primOp.arity = arity; v.primOp.fun = primOp; - baseEnv.bindings[name] = v; + baseEnv.bindings[symbols.create(name)] = v; string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; - (*baseEnv.bindings["builtins"].attrs)[name2] = v; + (*baseEnv.bindings[symbols.create("builtins")].attrs)[symbols.create(name2)] = v; nrValues += 2; } @@ -225,12 +232,12 @@ void mkPath(Value & v, const char * s) } -static Value * lookupWith(Env * env, const Sym & name) +Value * EvalState::lookupWith(Env * env, const Symbol & name) { if (!env) return 0; Value * v = lookupWith(env->up, name); if (v) return v; - Bindings::iterator i = env->bindings.find(""); + Bindings::iterator i = env->bindings.find(sWith); if (i == env->bindings.end()) return 0; Bindings::iterator j = i->second.attrs->find(name); if (j != i->second.attrs->end()) return &j->second; @@ -238,7 +245,7 @@ static Value * lookupWith(Env * env, const Sym & name) } -static Value * lookupVar(Env * env, const Sym & name) +Value * EvalState::lookupVar(Env * env, const Symbol & name) { /* First look for a regular variable binding for `name'. */ for (Env * env2 = env; env2; env2 = env2->up) { @@ -318,7 +325,7 @@ void EvalState::evalFile(const Path & path, Value & v) Expr * e = parseTrees[path]; if (!e) { - e = parseExprFromFile(path); + e = parseExprFromFile(*this, path); parseTrees[path] = e; } @@ -428,9 +435,9 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) /* The inherited attributes, on the other hand, are evaluated in the original environment. */ - foreach (list::iterator, i, inherited) { + foreach (list::iterator, i, inherited) { Value & v2 = env2.bindings[*i]; - mkCopy(v2, *lookupVar(&env, *i)); + mkCopy(v2, *state.lookupVar(&env, *i)); } } @@ -441,9 +448,9 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) mkThunk(v2, env, i->second); } - foreach (list::iterator, i, inherited) { + foreach (list::iterator, i, inherited) { Value & v2 = (*v.attrs)[*i]; - mkCopy(v2, *lookupVar(&env, *i)); + mkCopy(v2, *state.lookupVar(&env, *i)); } } } @@ -459,7 +466,7 @@ void ExprList::eval(EvalState & state, Env & env, Value & v) void ExprVar::eval(EvalState & state, Env & env, Value & v) { - Value * v2 = lookupVar(&env, name); + Value * v2 = state.lookupVar(&env, name); state.forceValue(*v2); v = *v2; } @@ -631,7 +638,7 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) Env & env2(state.allocEnv()); env2.up = &env; - Value & vAttrs = env2.bindings[""]; + Value & vAttrs = env2.bindings[state.sWith]; state.eval(env, attrs, vAttrs); state.forceAttrs(vAttrs); @@ -871,7 +878,7 @@ string EvalState::forceStringNoCtx(Value & v) bool EvalState::isDerivation(Value & v) { if (v.type != tAttrs) return false; - Bindings::iterator i = v.attrs->find("type"); + Bindings::iterator i = v.attrs->find(sType); return i != v.attrs->end() && forceStringNoCtx(i->second) == "derivation"; } @@ -915,7 +922,7 @@ string EvalState::coerceToString(Value & v, PathSet & context, } if (v.type == tAttrs) { - Bindings::iterator i = v.attrs->find("outPath"); + Bindings::iterator i = v.attrs->find(sOutPath); if (i == v.attrs->end()) throwTypeError("cannot coerce an attribute set (except a derivation) to a string"); return coerceToString(i->second, context, coerceMore, copyToStore); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index cbdd09085d7d..fe91db2efd70 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -4,6 +4,7 @@ #include #include "nixexpr.hh" +#include "symbol-table.hh" namespace nix { @@ -14,9 +15,7 @@ class EvalState; struct Env; struct Value; -typedef string Sym; - -typedef std::map Bindings; +typedef std::map Bindings; struct Env @@ -161,6 +160,10 @@ class EvalState public: DrvHashes drvHashes; /* normalised derivation hashes */ + SymbolTable symbols; + + const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName; + private: SrcToStore srcToStore; @@ -235,6 +238,13 @@ private: void addPrimOp(const string & name, unsigned int arity, PrimOp primOp); + Value * lookupVar(Env * env, const Symbol & name); + + Value * lookupWith(Env * env, const Symbol & name); + + friend class ExprVar; + friend class ExprAttrs; + public: /* Do a deep equality test between two values. That is, list diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 95938d5c1fa7..3994701924ab 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -8,7 +8,7 @@ namespace nix { string DrvInfo::queryDrvPath(EvalState & state) const { if (drvPath == "") { - Bindings::iterator i = attrs->find("drvPath"); + Bindings::iterator i = attrs->find(state.sDrvPath); PathSet context; (string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; } @@ -19,7 +19,7 @@ string DrvInfo::queryDrvPath(EvalState & state) const string DrvInfo::queryOutPath(EvalState & state) const { if (outPath == "") { - Bindings::iterator i = attrs->find("outPath"); + Bindings::iterator i = attrs->find(state.sOutPath); PathSet context; (string &) outPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; } @@ -31,7 +31,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const { MetaInfo meta; - Bindings::iterator a = attrs->find("meta"); + Bindings::iterator a = attrs->find(state.sMeta); if (a == attrs->end()) return meta; /* fine, empty meta information */ state.forceAttrs(a->second); @@ -113,12 +113,12 @@ static bool getDerivation(EvalState & state, Value & v, DrvInfo drv; - Bindings::iterator i = v.attrs->find("name"); + Bindings::iterator i = v.attrs->find(state.sName); /* !!! We really would like to have a decent back trace here. */ if (i == v.attrs->end()) throw TypeError("derivation name missing"); drv.name = state.forceStringNoCtx(i->second); - i = v.attrs->find("system"); + i = v.attrs->find(state.symbols.create("system")); if (i == v.attrs->end()) drv.system = "unknown"; else @@ -170,7 +170,7 @@ static void getDerivations(EvalState & state, Value & vIn, /* !!! undocumented hackery to support combining channels in nix-env.cc. */ - bool combineChannels = v.attrs->find("_combineChannels") != v.attrs->end(); + bool combineChannels = v.attrs->find(state.symbols.create("_combineChannels")) != v.attrs->end(); /* Consider the attributes in sorted order to get more deterministic behaviour in nix-env operations (e.g. when @@ -184,7 +184,7 @@ static void getDerivations(EvalState & state, Value & vIn, foreach (StringSet::iterator, i, attrs) { startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % *i); string pathPrefix2 = addToPath(pathPrefix, *i); - Value & v2((*v.attrs)[*i]); + Value & v2((*v.attrs)[state.symbols.create(*i)]); if (combineChannels) getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); else if (getDerivation(state, v2, pathPrefix2, drvs, done)) { @@ -193,7 +193,7 @@ static void getDerivations(EvalState & state, Value & vIn, if it has a `recurseForDerivations = true' attribute. */ if (v2.type == tAttrs) { - Bindings::iterator j = v2.attrs->find("recurseForDerivations"); + Bindings::iterator j = v2.attrs->find(state.symbols.create("recurseForDerivations")); if (j != v2.attrs->end() && state.forceBool(j->second)) getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); } diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 1902e23b004a..922066c234a4 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -54,7 +54,7 @@ void ExprAttrs::show(std::ostream & str) { if (recursive) str << "rec "; str << "{ "; - foreach (list::iterator, i, inherited) + foreach (list::iterator, i, inherited) str << "inherit " << *i << "; "; foreach (Attrs::iterator, i, attrs) str << i->first << " = " << *i->second << "; "; @@ -81,9 +81,9 @@ void ExprLambda::show(std::ostream & str) if (i->def) str << " ? " << *i->def; } str << " }"; - if (arg != "") str << " @ "; + if (!arg.empty()) str << " @ "; } - if (arg != "") str << arg; + if (!arg.empty()) str << arg; str << ": " << *body << ")"; } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 725f9fe88e52..f0c05d4352ff 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -3,7 +3,7 @@ #include -#include "types.hh" +#include "symbol-table.hh" namespace nix { @@ -75,33 +75,33 @@ struct ExprPath : Expr struct ExprVar : Expr { - string name; - ExprVar(const string & name) : name(name) { }; + Symbol name; + ExprVar(const Symbol & name) : name(name) { }; COMMON_METHODS }; struct ExprSelect : Expr { Expr * e; - string name; - ExprSelect(Expr * e, const string & name) : e(e), name(name) { }; + Symbol name; + ExprSelect(Expr * e, const Symbol & name) : e(e), name(name) { }; COMMON_METHODS }; struct ExprOpHasAttr : Expr { Expr * e; - string name; - ExprOpHasAttr(Expr * e, const string & name) : e(e), name(name) { }; + Symbol name; + ExprOpHasAttr(Expr * e, const Symbol & name) : e(e), name(name) { }; COMMON_METHODS }; struct ExprAttrs : Expr { bool recursive; - typedef std::map Attrs; + typedef std::map Attrs; Attrs attrs; - list inherited; + list inherited; ExprAttrs() : recursive(false) { }; COMMON_METHODS }; @@ -115,9 +115,9 @@ struct ExprList : Expr struct Formal { - string name; + Symbol name; Expr * def; - Formal(const string & name, Expr * def) : name(name), def(def) { }; + Formal(const Symbol & name, Expr * def) : name(name), def(def) { }; }; struct Formals @@ -130,11 +130,11 @@ struct Formals struct ExprLambda : Expr { Pos pos; - string arg; + Symbol arg; bool matchAttrs; Formals * formals; Expr * body; - ExprLambda(const Pos & pos, const string & arg, bool matchAttrs, Formals * formals, Expr * body) + ExprLambda(const Pos & pos, const Symbol & arg, bool matchAttrs, Formals * formals, Expr * body) : pos(pos), arg(arg), matchAttrs(matchAttrs), formals(formals), body(body) { }; COMMON_METHODS }; diff --git a/src/libexpr/parser.hh b/src/libexpr/parser.hh index d1e531ca2921..c8c8ad8090be 100644 --- a/src/libexpr/parser.hh +++ b/src/libexpr/parser.hh @@ -9,10 +9,10 @@ namespace nix { /* Parse a Nix expression from the specified file. If `path' refers to a directory, then "/default.nix" is appended. */ -Expr * parseExprFromFile(Path path); +Expr * parseExprFromFile(EvalState & state, Path path); /* Parse a Nix expression from the specified string. */ -Expr * parseExprFromString(const string & s, const Path & basePath); +Expr * parseExprFromString(EvalState & state, const string & s, const Path & basePath); } diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 07bf56a1c964..c1c17e2b2648 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -37,17 +37,23 @@ namespace nix { struct ParseData { + SymbolTable & symbols; Expr * result; Path basePath; Path path; string error; + Symbol sLetBody; + ParseData(SymbolTable & symbols) + : symbols(symbols) + , sLetBody(symbols.create("")) + { }; }; -static string showAttrPath(const vector & attrPath) +static string showAttrPath(const vector & attrPath) { string s; - foreach (vector::const_iterator, i, attrPath) { + foreach (vector::const_iterator, i, attrPath) { if (!s.empty()) s += '.'; s += *i; } @@ -55,10 +61,11 @@ static string showAttrPath(const vector & attrPath) } -static void addAttr(ExprAttrs * attrs, const vector & attrPath, Expr * e, const Pos & pos) +static void addAttr(ExprAttrs * attrs, const vector & attrPath, + Expr * e, const Pos & pos) { unsigned int n = 0; - foreach (vector::const_iterator, i, attrPath) { + foreach (vector::const_iterator, i, attrPath) { n++; if (attrs->attrs[*i]) { ExprAttrs * attrs2 = dynamic_cast(attrs->attrs[*i]); @@ -243,10 +250,10 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err nix::Formals * formals; nix::Formal * formal; int n; - char * id; + char * id; // !!! -> Symbol char * path; char * uri; - std::vector * ids; + std::vector * ids; std::vector * string_parts; } @@ -287,19 +294,19 @@ expr: expr_function; expr_function : ID ':' expr_function - { $$ = new ExprLambda(CUR_POS, $1, false, 0, $3); /* checkPatternVars(CUR_POS, $1); $$ = makeFunction($1, $3, CUR_POS); */ } + { $$ = new ExprLambda(CUR_POS, data->symbols.create($1), false, 0, $3); /* checkPatternVars(CUR_POS, $1); */ } | '{' formals '}' ':' expr_function - { $$ = new ExprLambda(CUR_POS, "", true, $2, $5); } + { $$ = new ExprLambda(CUR_POS, data->symbols.create(""), true, $2, $5); } | '{' formals '}' '@' ID ':' expr_function - { $$ = new ExprLambda(CUR_POS, $5, true, $2, $7); } + { $$ = new ExprLambda(CUR_POS, data->symbols.create($5), true, $2, $7); } | ID '@' '{' formals '}' ':' expr_function - { $$ = new ExprLambda(CUR_POS, $1, true, $4, $7); } + { $$ = new ExprLambda(CUR_POS, data->symbols.create($1), true, $4, $7); } | 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 - { $2->attrs[""] = $4; $2->recursive = true; $$ = new ExprSelect($2, ""); } + { $2->attrs[data->sLetBody] = $4; $2->recursive = true; $$ = new ExprSelect($2, data->sLetBody); } | expr_if ; @@ -316,7 +323,7 @@ expr_op | 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 { $$ = new ExprOpHasAttr($1, $3); } + | expr_op '?' ID { $$ = new ExprOpHasAttr($1, data->symbols.create($3)); } | expr_op '+' expr_op { vector * l = new vector; l->push_back($1); @@ -335,12 +342,12 @@ expr_app expr_select : expr_select '.' ID - { $$ = new ExprSelect($1, $3); } + { $$ = new ExprSelect($1, data->symbols.create($3)); } | expr_simple { $$ = $1; } ; expr_simple - : ID { $$ = new ExprVar($1); } + : ID { $$ = new ExprVar(data->symbols.create($1)); } | INT { $$ = new ExprInt($1); } | '"' string_parts '"' { /* For efficiency, and to simplify parse trees a bit. */ @@ -357,7 +364,7 @@ expr_simple /* Let expressions `let {..., body = ...}' are just desugared into `(rec {..., body = ...}).body'. */ | LET '{' binds '}' - { $3->recursive = true; $$ = new ExprSelect($3, "body"); } + { $3->recursive = true; $$ = new ExprSelect($3, data->symbols.create("body")); } | REC '{' binds '}' { $3->recursive = true; $$ = $3; } | '{' binds '}' @@ -381,26 +388,26 @@ binds : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, CUR_POS); } | binds INHERIT ids ';' { $$ = $1; - foreach (vector::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 (vector::iterator, i, *$6) + foreach (vector::iterator, i, *$6) $$->attrs[*i] = new ExprSelect($4, *i); } | { $$ = new ExprAttrs; } ; ids - : ids ID { $$ = $1; $1->push_back($2); /* !!! dangerous */ } - | { $$ = new vector; } + : ids ID { $$ = $1; $1->push_back(data->symbols.create($2)); /* !!! dangerous */ } + | { $$ = new vector; } ; attrpath - : attrpath '.' ID { $$ = $1; $1->push_back($3); } - | ID { $$ = new vector; $$->push_back($1); } + : attrpath '.' ID { $$ = $1; $1->push_back(data->symbols.create($3)); } + | ID { $$ = new vector; $$->push_back(data->symbols.create($1)); } ; expr_list @@ -420,8 +427,8 @@ formals ; formal - : ID { $$ = new Formal($1, 0); } - | ID '?' expr { $$ = new Formal($1, $3); } + : ID { $$ = new Formal(data->symbols.create($1), 0); } + | ID '?' expr { $$ = new Formal(data->symbols.create($1), $3); } ; %% @@ -432,14 +439,17 @@ formal #include #include +#include + namespace nix { -static Expr * parse(const char * text, const Path & path, const Path & basePath) +static Expr * parse(EvalState & state, const char * text, + const Path & path, const Path & basePath) { yyscan_t scanner; - ParseData data; + ParseData data(state.symbols); data.basePath = basePath; data.path = path; @@ -460,7 +470,7 @@ static Expr * parse(const char * text, const Path & path, const Path & basePath) } -Expr * parseExprFromFile(Path path) +Expr * parseExprFromFile(EvalState & state, Path path) { assert(path[0] == '/'); @@ -481,13 +491,14 @@ Expr * parseExprFromFile(Path path) path = canonPath(path + "/default.nix"); /* Read and parse the input file. */ - return parse(readFile(path).c_str(), path, dirOf(path)); + return parse(state, readFile(path).c_str(), path, dirOf(path)); } -Expr * parseExprFromString(const string & s, const Path & basePath) +Expr * parseExprFromString(EvalState & state, + const string & s, const Path & basePath) { - return parse(s.c_str(), "(string)", basePath); + return parse(state, s.c_str(), "(string)", basePath); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index e50034a04704..257dcd2e9b79 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -280,7 +280,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) state.forceAttrs(*args[0]); /* Figure out the name first (for stack backtraces). */ - Bindings::iterator attr = args[0]->attrs->find("name"); + Bindings::iterator attr = args[0]->attrs->find(state.sName); if (attr == args[0]->attrs->end()) throw EvalError("required attribute `name' missing"); string drvName; @@ -448,8 +448,8 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) /* !!! assumes a single output */ state.mkAttrs(v); - mkString((*v.attrs)["outPath"], outPath, singleton(drvPath)); - mkString((*v.attrs)["drvPath"], drvPath, singleton("=" + drvPath)); + mkString((*v.attrs)[state.sOutPath], outPath, singleton(drvPath)); + mkString((*v.attrs)[state.sDrvPath], drvPath, singleton("=" + drvPath)); } @@ -667,7 +667,8 @@ static void prim_getAttr(EvalState & state, Value * * args, Value & v) { string attr = state.forceStringNoCtx(*args[0]); state.forceAttrs(*args[1]); - Bindings::iterator i = args[1]->attrs->find(attr); + // !!! Should we create a symbol here or just do a lookup? + Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); if (i == args[1]->attrs->end()) throw EvalError(format("attribute `%1%' missing") % attr); state.forceValue(i->second); @@ -680,7 +681,7 @@ static void prim_hasAttr(EvalState & state, Value * * args, Value & v) { string attr = state.forceStringNoCtx(*args[0]); state.forceAttrs(*args[1]); - mkBool(v, args[1]->attrs->find(attr) != args[1]->attrs->end()); + mkBool(v, args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end()); } @@ -701,7 +702,7 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) for (unsigned int i = 0; i < args[1]->list.length; ++i) { state.forceStringNoCtx(args[1]->list.elems[i]); - v.attrs->erase(args[1]->list.elems[i].string.s); + v.attrs->erase(state.symbols.create(args[1]->list.elems[i].string.s)); } } @@ -720,16 +721,16 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) Value & v2(args[0]->list.elems[i]); state.forceAttrs(v2); - Bindings::iterator j = v2.attrs->find("name"); + Bindings::iterator j = v2.attrs->find(state.sName); if (j == v2.attrs->end()) throw TypeError("`name' attribute missing in a call to `listToAttrs'"); string name = state.forceStringNoCtx(j->second); - j = v2.attrs->find("value"); + j = v2.attrs->find(state.symbols.create("value")); if (j == v2.attrs->end()) throw TypeError("`value' attribute missing in a call to `listToAttrs'"); - (*v.attrs)[name] = j->second; // !!! sharing? + (*v.attrs)[state.symbols.create(name)] = j->second; // !!! sharing? } } @@ -976,8 +977,8 @@ static void prim_parseDrvName(EvalState & state, Value * * args, Value & v) string name = state.forceStringNoCtx(*args[0]); DrvName parsed(name); state.mkAttrs(v); - mkString((*v.attrs)["name"], parsed.name); - mkString((*v.attrs)["version"], parsed.version); + mkString((*v.attrs)[state.sName], parsed.name); + mkString((*v.attrs)[state.symbols.create("version")], parsed.version); } @@ -998,7 +999,7 @@ void EvalState::createBaseEnv() { baseEnv.up = 0; - Value & builtins = baseEnv.bindings["builtins"]; + Value & builtins = baseEnv.bindings[symbols.create("builtins")]; builtins.type = tAttrs; builtins.attrs = new Bindings; @@ -1023,7 +1024,7 @@ 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, "/")); + mkThunk(v, baseEnv, parseExprFromString(*this, s, "/")); addConstant("derivation", v); // Miscellaneous diff --git a/src/libexpr/symbol-table.hh b/src/libexpr/symbol-table.hh new file mode 100644 index 000000000000..ae0751d11d3c --- /dev/null +++ b/src/libexpr/symbol-table.hh @@ -0,0 +1,75 @@ +#ifndef __SYMBOL_TABLE_H +#define __SYMBOL_TABLE_H + +#include + +#include "types.hh" + +namespace nix { + +/* Symbol table used by the parser and evaluator to represent and look + up identifiers and attribute sets efficiently. + SymbolTable::create() converts a string into a symbol. Symbols + have the property that they can be compared efficiently (using a + pointer equality test), because the symbol table stores only one + copy of each string. */ + +class Symbol +{ +private: + const string * s; // pointer into SymbolTable + Symbol(const string * s) : s(s) { }; + friend class SymbolTable; + +public: + bool operator == (const Symbol & s2) const + { + return s == s2.s; + } + + bool operator != (const Symbol & s2) const + { + return s != s2.s; + } + + bool operator < (const Symbol & s2) const + { + return s < s2.s; + } + + operator const string & () const + { + return *s; + } + + bool empty() const + { + return s->empty(); + } + + friend std::ostream & operator << (std::ostream & str, const Symbol & sym); +}; + +inline std::ostream & operator << (std::ostream & str, const Symbol & sym) +{ + str << *sym.s; + return str; +} + +class SymbolTable +{ +private: + typedef std::set Symbols; + Symbols symbols; + +public: + Symbol create(const string & s) + { + std::pair res = symbols.insert(s); + return Symbol(&*res.first); + } +}; + +} + +#endif /* !__SYMBOL_TABLE_H */ diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index c8a067aacf77..0c8fc143c36b 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -28,7 +28,7 @@ static void showAttrs(EvalState & state, bool strict, Bindings & attrs, names.insert(i->first); foreach (StringSet::iterator, i, names) { XMLOpenElement _(doc, "attr", singletonAttrs("name", *i)); - printValueAsXML(state, strict, attrs[*i], doc, context, drvsSeen); + printValueAsXML(state, strict, attrs[state.symbols.create(*i)], doc, context, drvsSeen); } } @@ -67,14 +67,14 @@ static void printValueAsXML(EvalState & state, bool strict, Value & v, if (state.isDerivation(v)) { XMLAttrs xmlAttrs; - Bindings::iterator a = v.attrs->find("derivation"); + Bindings::iterator a = v.attrs->find(state.symbols.create("derivation")); Path drvPath; - a = v.attrs->find("drvPath"); + a = v.attrs->find(state.sDrvPath); if (a != v.attrs->end() && a->second.type == tString) xmlAttrs["drvPath"] = drvPath = a->second.string.s; - a = v.attrs->find("outPath"); + a = v.attrs->find(state.sOutPath); if (a != v.attrs->end() && a->second.type == tString) xmlAttrs["outPath"] = a->second.string.s; diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index ba34fc63bd94..c61cf89c90e4 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -28,7 +28,7 @@ static Expr * parseStdin(EvalState & state) startNest(nest, lvlTalkative, format("parsing standard input")); string s, s2; while (getline(std::cin, s2)) s += s2 + "\n"; - return parseExprFromString(s, absPath(".")); + return parseExprFromString(state, s, absPath(".")); } @@ -136,7 +136,7 @@ void run(Strings args) foreach (Strings::iterator, i, files) { Path path = absPath(*i); - Expr * e = parseExprFromFile(path); + Expr * e = parseExprFromFile(state, path); processExpr(state, attrPaths, parseOnly, strict, autoArgs, evalOnly, xmlOutput, e); } -- cgit 1.4.1 From 04c4bd3624b094043ff0f2410c1e376a51f457f7 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 15 Apr 2010 00:37:36 +0000 Subject: * Store lists as lists of pointers to values rather than as lists of values. This improves sharing and gives another speed up. Evaluation of the NixOS system attribute is now almost 7 times faster than the old evaluator. --- src/libexpr/attr-path.cc | 2 +- src/libexpr/eval-test.cc | 1 + src/libexpr/eval.cc | 33 +++++++++++++++++---------------- src/libexpr/eval.hh | 4 ++-- src/libexpr/get-drvs.cc | 6 +++--- src/libexpr/primops.cc | 27 ++++++++++++++++----------- src/libexpr/value-to-xml.cc | 2 +- 7 files changed, 41 insertions(+), 34 deletions(-) (limited to 'src/libexpr/attr-path.cc') diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index b53837781573..769acb6b8c0f 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -61,7 +61,7 @@ void findAlongAttrPath(EvalState & state, const string & attrPath, if (attrIndex >= v.list.length) throw Error(format("list index %1% in selection path `%2%' is out of range") % attrIndex % curPath); - v = v.list.elems[attrIndex]; + v = *v.list.elems[attrIndex]; } } diff --git a/src/libexpr/eval-test.cc b/src/libexpr/eval-test.cc index a7786561e81e..f7f91f503d8c 100644 --- a/src/libexpr/eval-test.cc +++ b/src/libexpr/eval-test.cc @@ -113,6 +113,7 @@ void run(Strings args) doTest(state, "with { x = 1; }; let inherit x; y = x; in y"); doTest(state, "builtins.toXML 123"); doTest(state, "builtins.toXML { a.b = \"x\" + \"y\"; c = [ 1 2 ] ++ [ 3 4 ]; }"); + doTest(state, "builtins.attrNames { x = 1; y = 2; }"); state.printStats(); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index d6e39f3654c0..69e7bd8b3c88 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -50,7 +50,7 @@ std::ostream & operator << (std::ostream & str, Value & v) case tList: str << "[ "; for (unsigned int n = 0; n < v.list.length; ++n) - str << v.list.elems[n] << " "; + str << *v.list.elems[n] << " "; str << "]"; break; case tThunk: @@ -102,7 +102,7 @@ EvalState::EvalState() , baseEnvDispl(0) , staticBaseEnv(false, 0) { - nrEnvs = nrValuesInEnvs = nrValuesInLists = nrValues = 0; + nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0; nrEvaluated = recursionDepth = maxRecursionDepth = 0; deepestStack = (char *) -1; @@ -251,6 +251,7 @@ Value * EvalState::lookupVar(Env * env, const VarRef & var) Value * EvalState::allocValues(unsigned int count) { + nrValues += count; return new Value[count]; // !!! check destructor } @@ -268,8 +269,8 @@ void EvalState::mkList(Value & v, unsigned int length) { v.type = tList; v.list.length = length; - v.list.elems = allocValues(length); - nrValuesInLists += length; + v.list.elems = new Value *[length]; + nrListElems += length; } @@ -461,8 +462,11 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v) void ExprList::eval(EvalState & state, Env & env, Value & v) { state.mkList(v, elems.size()); - for (unsigned int n = 0; n < v.list.length; ++n) - mkThunk(v.list.elems[n], env, elems[n]); + Value * vs = state.allocValues(v.list.length); + for (unsigned int n = 0; n < v.list.length; ++n) { + v.list.elems[n] = &vs[n]; + mkThunk(vs[n], env, elems[n]); + } } @@ -543,7 +547,6 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) primOp->primOp.fun(*this, vArgs, v); } else { Value * v2 = allocValues(2); - nrValues += 2; v2[0] = fun; v2[1] = arg; v.type = tPrimOpApp; @@ -734,8 +737,6 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v) Value v2; state.eval(env, e2, v2); state.forceList(v2); state.mkList(v, v1.list.length + v2.list.length); - /* !!! This loses sharing with the original lists. We could use a - tCopy node, but that would use more memory. */ for (unsigned int n = 0; n < v1.list.length; ++n) v.list.elems[n] = v1.list.elems[n]; for (unsigned int n = 0; n < v2.list.length; ++n) @@ -810,7 +811,7 @@ void EvalState::strictForceValue(Value & v) else if (v.type == tList) { for (unsigned int n = 0; n < v.list.length; ++n) - strictForceValue(v.list.elems[n]); + strictForceValue(*v.list.elems[n]); } } @@ -951,11 +952,11 @@ string EvalState::coerceToString(Value & v, PathSet & context, if (v.type == tList) { string result; for (unsigned int n = 0; n < v.list.length; ++n) { - result += coerceToString(v.list.elems[n], + result += coerceToString(*v.list.elems[n], context, coerceMore, copyToStore); if (n < v.list.length - 1 /* !!! not quite correct */ - && (v.list.elems[n].type != tList || v.list.elems[n].list.length != 0)) + && (v.list.elems[n]->type != tList || v.list.elems[n]->list.length != 0)) result += " "; } return result; @@ -1009,14 +1010,14 @@ bool EvalState::eqValues(Value & v1, Value & v2) case tList: if (v2.type != tList || v1.list.length != v2.list.length) return false; for (unsigned int n = 0; n < v1.list.length; ++n) - if (!eqValues(v1.list.elems[n], v2.list.elems[n])) return false; + if (!eqValues(*v1.list.elems[n], *v2.list.elems[n])) return false; return true; case tAttrs: { if (v2.type != tAttrs || v1.attrs->size() != v2.attrs->size()) return false; Bindings::iterator i, j; for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end(); ++i, ++j) - if (!eqValues(i->second, j->second)) return false; + if (i->first != j->first || !eqValues(i->second, j->second)) return false; return true; } @@ -1046,8 +1047,8 @@ void EvalState::printStats() % nrEnvs % (nrEnvs * sizeof(Env))); printMsg(v, format(" values allocated in environments: %1% (%2% bytes)") % nrValuesInEnvs % (nrValuesInEnvs * sizeof(Value))); - printMsg(v, format(" values allocated in lists: %1% (%2% bytes)") - % nrValuesInLists % (nrValuesInLists * sizeof(Value))); + printMsg(v, format(" list elements: %1% (%2% bytes)") + % nrListElems % (nrListElems * sizeof(Value *))); printMsg(v, format(" misc. values allocated: %1% (%2% bytes) ") % nrValues % (nrValues * sizeof(Value))); printMsg(v, format(" symbols in symbol table: %1%") % symbols.size()); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 313a1d9b8e5f..7252cae4b5af 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -76,7 +76,7 @@ struct Value Bindings * attrs; struct { unsigned int length; - Value * elems; + Value * * elems; } list; struct { Env * env; @@ -282,8 +282,8 @@ private: unsigned long nrEnvs; unsigned long nrValuesInEnvs; - unsigned long nrValuesInLists; unsigned long nrValues; + unsigned long nrListElems; unsigned long nrEvaluated; unsigned int recursionDepth; unsigned int maxRecursionDepth; diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 3994701924ab..6964e3e3b71f 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -48,7 +48,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const } else if (i->second.type == tList) { value.type = MetaValue::tpStrings; for (unsigned int j = 0; j < i->second.list.length; ++j) - value.stringValues.push_back(state.forceStringNoCtx(i->second.list.elems[j])); + value.stringValues.push_back(state.forceStringNoCtx(*i->second.list.elems[j])); } else continue; meta[i->first] = value; } @@ -206,8 +206,8 @@ static void getDerivations(EvalState & state, Value & vIn, startNest(nest, lvlDebug, format("evaluating list element")); string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str()); - if (getDerivation(state, v.list.elems[n], pathPrefix2, drvs, done)) - getDerivations(state, v.list.elems[n], pathPrefix2, autoArgs, drvs, done); + if (getDerivation(state, *v.list.elems[n], pathPrefix2, drvs, done)) + getDerivations(state, *v.list.elems[n], pathPrefix2, autoArgs, drvs, done); } } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 0d7459feef46..ae17506ceed9 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -311,7 +311,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) if (key == "args") { state.forceList(i->second); for (unsigned int n = 0; n < i->second.list.length; ++n) { - string s = state.coerceToString(i->second.list.elems[n], context, true); + string s = state.coerceToString(*i->second.list.elems[n], context, true); drv.args.push_back(s); } } @@ -651,14 +651,17 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v) state.forceAttrs(*args[0]); state.mkList(v, args[0]->attrs->size()); + Value * vs = state.allocValues(v.list.length); StringSet names; foreach (Bindings::iterator, i, *args[0]->attrs) names.insert(i->first); unsigned int n = 0; - foreach (StringSet::iterator, i, names) - mkString(v.list.elems[n++], *i); + foreach (StringSet::iterator, i, names) { + v.list.elems[n] = &vs[n]; + mkString(vs[n++], *i); + } } @@ -701,8 +704,8 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) state.cloneAttrs(*args[0], v); for (unsigned int i = 0; i < args[1]->list.length; ++i) { - state.forceStringNoCtx(args[1]->list.elems[i]); - v.attrs->erase(state.symbols.create(args[1]->list.elems[i].string.s)); + state.forceStringNoCtx(*args[1]->list.elems[i]); + v.attrs->erase(state.symbols.create(args[1]->list.elems[i]->string.s)); } } @@ -718,7 +721,7 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) state.mkAttrs(v); for (unsigned int i = 0; i < args[0]->list.length; ++i) { - Value & v2(args[0]->list.elems[i]); + Value & v2(*args[0]->list.elems[i]); state.forceAttrs(v2); Bindings::iterator j = v2.attrs->find(state.sName); @@ -815,8 +818,8 @@ static void prim_head(EvalState & state, Value * * args, Value & v) state.forceList(*args[0]); if (args[0]->list.length == 0) throw Error("`head' called on an empty list"); - state.forceValue(args[0]->list.elems[0]); - v = args[0]->list.elems[0]; + state.forceValue(*args[0]->list.elems[0]); + v = *args[0]->list.elems[0]; } @@ -840,11 +843,13 @@ static void prim_map(EvalState & state, Value * * args, Value & v) state.forceList(*args[1]); state.mkList(v, args[1]->list.length); + Value * vs = state.allocValues(v.list.length); for (unsigned int n = 0; n < v.list.length; ++n) { - v.list.elems[n].type = tApp; - v.list.elems[n].app.left = args[0]; - v.list.elems[n].app.right = &args[1]->list.elems[n]; + v.list.elems[n] = &vs[n]; + vs[n].type = tApp; + vs[n].app.left = args[0]; + vs[n].app.right = args[1]->list.elems[n]; } } diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index 0c8fc143c36b..58e89925ce43 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -97,7 +97,7 @@ static void printValueAsXML(EvalState & state, bool strict, Value & v, case tList: { XMLOpenElement _(doc, "list"); for (unsigned int n = 0; n < v.list.length; ++n) - printValueAsXML(state, strict, v.list.elems[n], doc, context, drvsSeen); + printValueAsXML(state, strict, *v.list.elems[n], doc, context, drvsSeen); break; } -- cgit 1.4.1 From e2d5e40f4fdd98e5d2ad7b77c00fb97caa3aa259 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 7 May 2010 12:11:05 +0000 Subject: * Keep track of the source positions of attributes. --- src/libexpr/attr-path.cc | 2 +- src/libexpr/common-opts.cc | 2 +- src/libexpr/eval.cc | 59 +++++++++++++++++++++++++--------------- src/libexpr/eval.hh | 11 +++++++- src/libexpr/get-drvs.cc | 32 +++++++++++----------- src/libexpr/primops.cc | 66 ++++++++++++++++++++++++--------------------- src/libexpr/value-to-xml.cc | 11 ++++---- src/nix-env/user-env.cc | 20 +++++++------- 8 files changed, 117 insertions(+), 86 deletions(-) (limited to 'src/libexpr/attr-path.cc') diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index 769acb6b8c0f..0660ba1c1efc 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -48,7 +48,7 @@ void findAlongAttrPath(EvalState & state, const string & attrPath, Bindings::iterator a = v.attrs->find(state.symbols.create(attr)); if (a == v.attrs->end()) throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); - v = a->second; + v = a->second.value; } else if (apType == apIndex) { diff --git a/src/libexpr/common-opts.cc b/src/libexpr/common-opts.cc index a25317de1346..5a4856568b4b 100644 --- a/src/libexpr/common-opts.cc +++ b/src/libexpr/common-opts.cc @@ -20,7 +20,7 @@ bool parseOptionArg(const string & arg, Strings::iterator & i, if (i == argsEnd) throw error; string value = *i++; - Value & v(autoArgs[state.symbols.create(name)]); + Value & v(autoArgs[state.symbols.create(name)].value); if (arg == "--arg") state.mkThunk_( v, parseExprFromString(state, value, absPath("."))); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index cb124ab8ba44..b8ec410f3993 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -44,7 +44,7 @@ std::ostream & operator << (std::ostream & str, Value & v) case tAttrs: str << "{ "; foreach (Bindings::iterator, i, *v.attrs) - str << (string) i->first << " = " << i->second << "; "; + str << (string) i->first << " = " << i->second.value << "; "; str << "}"; break; case tList: @@ -128,7 +128,7 @@ void EvalState::addConstant(const string & name, Value & v) staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v; string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; - (*baseEnv.values[0].attrs)[symbols.create(name2)] = v; + (*baseEnv.values[0].attrs)[symbols.create(name2)].value = v; } @@ -143,7 +143,7 @@ void EvalState::addPrimOp(const string & name, v.primOp.name = strdup(name2.c_str()); staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v; - (*baseEnv.values[0].attrs)[symbols.create(name2)] = v; + (*baseEnv.values[0].attrs)[symbols.create(name2)].value = v; } @@ -202,6 +202,11 @@ 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 Pos & pos)) +{ + e.addPrefix(format(s) % s2 % pos); +} + void mkString(Value & v, const char * s) { @@ -239,7 +244,7 @@ Value * EvalState::lookupVar(Env * env, const VarRef & var) while (1) { Bindings::iterator j = env->values[0].attrs->find(var.name); if (j != env->values[0].attrs->end()) - return &j->second; + return &j->second.value; if (env->prevWith == 0) throwEvalError("undefined variable `%1%'", var.name); for (unsigned int l = env->prevWith; l; --l, env = env->up) ; @@ -290,8 +295,11 @@ void EvalState::mkThunk_(Value & v, Expr * expr) void EvalState::cloneAttrs(Value & src, Value & dst) { mkAttrs(dst); - foreach (Bindings::iterator, i, *src.attrs) - mkCopy((*dst.attrs)[i->first], i->second); + foreach (Bindings::iterator, i, *src.attrs) { + Attr & a = (*dst.attrs)[i->first]; + mkCopy(a.value, i->second.value); + a.pos = i->second.pos; + } } @@ -414,15 +422,16 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) /* The recursive attributes are evaluated in the new environment. */ foreach (Attrs::iterator, i, attrs) { - Value & v2 = (*v.attrs)[i->first]; - mkCopy(v2, env2.values[displ]); + nix::Attr & a = (*v.attrs)[i->first]; + mkCopy(a.value, env2.values[displ]); mkThunk(env2.values[displ++], env2, i->second.first); + a.pos = &i->second.second; } /* The inherited attributes, on the other hand, are evaluated in the original environment. */ foreach (list::iterator, i, inherited) { - Value & v2 = (*v.attrs)[i->name]; + Value & v2 = (*v.attrs)[i->name].value; Value * v3 = state.lookupVar(&env, *i); mkCopy(v2, *v3); mkCopy(env2.values[displ++], *v3); @@ -432,12 +441,13 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) else { foreach (Attrs::iterator, i, attrs) { - Value & v2 = (*v.attrs)[i->first]; - mkThunk(v2, env, i->second.first); + nix::Attr & a = (*v.attrs)[i->first]; + mkThunk(a.value, env, i->second.first); + a.pos = &i->second.second; } foreach (list::iterator, i, inherited) { - Value & v2 = (*v.attrs)[i->name]; + Value & v2 = (*v.attrs)[i->name].value; mkCopy(v2, *state.lookupVar(&env, *i)); } } @@ -494,12 +504,13 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) if (i == v2.attrs->end()) throwEvalError("attribute `%1%' missing", name); try { - state.forceValue(i->second); + state.forceValue(i->second.value); } catch (Error & e) { - addErrorPrefix(e, "while evaluating the attribute `%1%':\n", name); + addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n", + name, *i->second.pos); throw; } - v = i->second; + v = i->second.value; } @@ -601,7 +612,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) mkThunk(env2.values[displ++], env2, i->def); } else { attrsUsed++; - mkCopy(env2.values[displ++], j->second); + mkCopy(env2.values[displ++], j->second.value); } } @@ -721,8 +732,11 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) state.evalAttrs(env, e2, v2); - foreach (Bindings::iterator, i, *v2.attrs) - mkCopy((*v.attrs)[i->first], i->second); + foreach (Bindings::iterator, i, *v2.attrs) { + Attr & a = (*v.attrs)[i->first]; + mkCopy(a.value, i->second.value); + a.pos = i->second.pos; + } } @@ -802,7 +816,7 @@ void EvalState::strictForceValue(Value & v) if (v.type == tAttrs) { foreach (Bindings::iterator, i, *v.attrs) - strictForceValue(i->second); + strictForceValue(i->second.value); } else if (v.type == tList) { @@ -887,7 +901,7 @@ bool EvalState::isDerivation(Value & v) { if (v.type != tAttrs) return false; Bindings::iterator i = v.attrs->find(sType); - return i != v.attrs->end() && forceStringNoCtx(i->second) == "derivation"; + return i != v.attrs->end() && forceStringNoCtx(i->second.value) == "derivation"; } @@ -933,7 +947,7 @@ string EvalState::coerceToString(Value & v, PathSet & context, Bindings::iterator i = v.attrs->find(sOutPath); if (i == v.attrs->end()) throwTypeError("cannot coerce an attribute set (except a derivation) to a string"); - return coerceToString(i->second, context, coerceMore, copyToStore); + return coerceToString(i->second.value, context, coerceMore, copyToStore); } if (coerceMore) { @@ -1021,7 +1035,8 @@ bool EvalState::eqValues(Value & v1, Value & v2) if (v1.attrs->size() != v2.attrs->size()) return false; Bindings::iterator i, j; for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end(); ++i, ++j) - if (i->first != j->first || !eqValues(i->second, j->second)) return false; + if (i->first != j->first || !eqValues(i->second.value, j->second.value)) + return false; return true; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 6912e22887fd..1a9862c29533 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -14,8 +14,9 @@ class Hash; class EvalState; struct Env; struct Value; +struct Attr; -typedef std::map Bindings; +typedef std::map Bindings; typedef enum { @@ -111,6 +112,14 @@ struct Env }; +struct Attr +{ + Value value; + Pos * pos; + Attr() : pos(&noPos) { }; +}; + + static inline void mkInt(Value & v, int n) { v.type = tInt; diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index e0ad91d8a54f..82a92416bed6 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -10,7 +10,7 @@ string DrvInfo::queryDrvPath(EvalState & state) const if (drvPath == "" && attrs) { Bindings::iterator i = attrs->find(state.sDrvPath); PathSet context; - (string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; + (string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second.value, context) : ""; } return drvPath; } @@ -21,7 +21,7 @@ string DrvInfo::queryOutPath(EvalState & state) const if (outPath == "" && attrs) { Bindings::iterator i = attrs->find(state.sOutPath); PathSet context; - (string &) outPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; + (string &) outPath = i != attrs->end() ? state.coerceToPath(i->second.value, context) : ""; } return outPath; } @@ -36,21 +36,21 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const Bindings::iterator a = attrs->find(state.sMeta); if (a == attrs->end()) return meta; /* fine, empty meta information */ - state.forceAttrs(a->second); + state.forceAttrs(a->second.value); - foreach (Bindings::iterator, i, *a->second.attrs) { + foreach (Bindings::iterator, i, *a->second.value.attrs) { MetaValue value; - state.forceValue(i->second); - if (i->second.type == tString) { + state.forceValue(i->second.value); + if (i->second.value.type == tString) { value.type = MetaValue::tpString; - value.stringValue = i->second.string.s; - } else if (i->second.type == tInt) { + value.stringValue = i->second.value.string.s; + } else if (i->second.value.type == tInt) { value.type = MetaValue::tpInt; - value.intValue = i->second.integer; - } else if (i->second.type == tList) { + value.intValue = i->second.value.integer; + } else if (i->second.value.type == tList) { value.type = MetaValue::tpStrings; - for (unsigned int j = 0; j < i->second.list.length; ++j) - value.stringValues.push_back(state.forceStringNoCtx(*i->second.list.elems[j])); + for (unsigned int j = 0; j < i->second.value.list.length; ++j) + value.stringValues.push_back(state.forceStringNoCtx(*i->second.value.list.elems[j])); } else continue; ((MetaInfo &) meta)[i->first] = value; } @@ -99,13 +99,13 @@ static bool getDerivation(EvalState & state, Value & v, Bindings::iterator i = v.attrs->find(state.sName); /* !!! We really would like to have a decent back trace here. */ if (i == v.attrs->end()) throw TypeError("derivation name missing"); - drv.name = state.forceStringNoCtx(i->second); + drv.name = state.forceStringNoCtx(i->second.value); i = v.attrs->find(state.sSystem); if (i == v.attrs->end()) drv.system = "unknown"; else - drv.system = state.forceStringNoCtx(i->second); + drv.system = state.forceStringNoCtx(i->second.value); drv.attrs = v.attrs; @@ -168,7 +168,7 @@ static void getDerivations(EvalState & state, Value & vIn, foreach (SortedSymbols::iterator, i, attrs) { startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % i->first); string pathPrefix2 = addToPath(pathPrefix, i->first); - Value & v2((*v.attrs)[i->second]); + Value & v2((*v.attrs)[i->second].value); if (combineChannels) getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); else if (getDerivation(state, v2, pathPrefix2, drvs, done)) { @@ -178,7 +178,7 @@ static void getDerivations(EvalState & state, Value & vIn, attribute. */ if (v2.type == tAttrs) { Bindings::iterator j = v2.attrs->find(state.symbols.create("recurseForDerivations")); - if (j != v2.attrs->end() && state.forceBool(j->second)) + if (j != v2.attrs->end() && state.forceBool(j->second.value)) getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); } } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 9023d2b1beb4..981f87ce81e5 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -115,18 +115,18 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) args[0]->attrs->find(state.symbols.create("startSet")); if (startSet == args[0]->attrs->end()) throw EvalError("attribute `startSet' required"); - state.forceList(startSet->second); + state.forceList(startSet->second.value); list workSet; - for (unsigned int n = 0; n < startSet->second.list.length; ++n) - workSet.push_back(startSet->second.list.elems[n]); + for (unsigned int n = 0; n < startSet->second.value.list.length; ++n) + workSet.push_back(startSet->second.value.list.elems[n]); /* Get the operator. */ Bindings::iterator op = args[0]->attrs->find(state.symbols.create("operator")); if (op == args[0]->attrs->end()) throw EvalError("attribute `operator' required"); - state.forceValue(op->second); + state.forceValue(op->second.value); /* Construct the closure by applying the operator to element of `workSet', adding the result to `workSet', continuing until @@ -143,15 +143,15 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) e->attrs->find(state.symbols.create("key")); if (key == e->attrs->end()) throw EvalError("attribute `key' required"); - state.forceValue(key->second); + state.forceValue(key->second.value); - if (doneKeys.find(key->second) != doneKeys.end()) continue; - doneKeys.insert(key->second); + if (doneKeys.find(key->second.value) != doneKeys.end()) continue; + doneKeys.insert(key->second.value); res.push_back(*e); /* Call the `operator' function with `e' as argument. */ Value call; - mkApp(call, op->second, *e); + mkApp(call, op->second.value, *e); state.forceList(call); /* Add the values returned by the operator to the work set. */ @@ -323,11 +323,11 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) if (attr == args[0]->attrs->end()) throw EvalError("required attribute `name' missing"); string drvName; + Pos & posDrvName(*attr->second.pos); try { - drvName = state.forceStringNoCtx(attr->second); + drvName = state.forceStringNoCtx(attr->second.value); } catch (Error & e) { - e.addPrefix(format("while evaluating the derivation attribute `name' at :\n")); - // !!! % showPos(posDrvName)); + e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n") % posDrvName); throw; } @@ -348,9 +348,9 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) /* The `args' attribute is special: it supplies the command-line arguments to the builder. */ if (key == "args") { - state.forceList(i->second); - for (unsigned int n = 0; n < i->second.list.length; ++n) { - string s = state.coerceToString(*i->second.list.elems[n], context, true); + state.forceList(i->second.value); + for (unsigned int n = 0; n < i->second.value.list.length; ++n) { + string s = state.coerceToString(*i->second.value.list.elems[n], context, true); drv.args.push_back(s); } } @@ -358,7 +358,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) /* All other attributes are passed to the builder through the environment. */ else { - string s = state.coerceToString(i->second, context, true); + string s = state.coerceToString(i->second.value, context, true); drv.env[key] = s; if (key == "builder") drv.builder = s; else if (i->first == state.sSystem) drv.platform = s; @@ -373,10 +373,10 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) } } catch (Error & e) { - e.addPrefix(format("while evaluating the derivation attribute `%1%' at :\n") - % key /* !!! % showPos(pos) */); - e.addPrefix(format("while instantiating the derivation named `%1%' at :\n") - % drvName /* !!! % showPos(posDrvName) */); + e.addPrefix(format("while evaluating the derivation attribute `%1%' at %2%:\n") + % key % *i->second.pos); + e.addPrefix(format("while instantiating the derivation named `%1%' at %2%:\n") + % drvName % posDrvName); throw; } } @@ -487,8 +487,8 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) /* !!! assumes a single output */ state.mkAttrs(v); - mkString((*v.attrs)[state.sOutPath], outPath, singleton(drvPath)); - mkString((*v.attrs)[state.sDrvPath], drvPath, singleton("=" + drvPath)); + mkString((*v.attrs)[state.sOutPath].value, outPath, singleton(drvPath)); + mkString((*v.attrs)[state.sDrvPath].value, drvPath, singleton("=" + drvPath)); } @@ -711,8 +711,9 @@ static void prim_getAttr(EvalState & state, Value * * args, Value & v) Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); if (i == args[1]->attrs->end()) throw EvalError(format("attribute `%1%' missing") % attr); - state.forceValue(i->second); - v = i->second; + // !!! add to stack trace? + state.forceValue(i->second.value); + v = i->second.value; } @@ -764,13 +765,15 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) Bindings::iterator j = v2.attrs->find(state.sName); if (j == v2.attrs->end()) throw TypeError("`name' attribute missing in a call to `listToAttrs'"); - string name = state.forceStringNoCtx(j->second); + string name = state.forceStringNoCtx(j->second.value); j = v2.attrs->find(state.symbols.create("value")); if (j == v2.attrs->end()) throw TypeError("`value' attribute missing in a call to `listToAttrs'"); - mkCopy((*v.attrs)[state.symbols.create(name)], j->second); + Attr & a = (*v.attrs)[state.symbols.create(name)]; + mkCopy(a.value, j->second.value); + a.pos = j->second.pos; } } @@ -787,8 +790,11 @@ static void prim_intersectAttrs(EvalState & state, Value * * args, Value & v) foreach (Bindings::iterator, i, *args[1]->attrs) { Bindings::iterator j = args[0]->attrs->find(i->first); - if (j != args[0]->attrs->end()) - mkCopy((*v.attrs)[i->first], i->second); + if (j != args[0]->attrs->end()) { + Attr & a = (*v.attrs)[i->first]; + mkCopy(a.value, i->second.value); + a.pos = i->second.pos; + } } } @@ -817,7 +823,7 @@ static void prim_functionArgs(EvalState & state, Value * * args, Value & v) if (!args[0]->lambda.fun->matchAttrs) return; foreach (Formals::Formals_::iterator, i, args[0]->lambda.fun->formals->formals) - mkBool((*v.attrs)[i->name], i->def); + mkBool((*v.attrs)[i->name].value, i->def); } @@ -1000,8 +1006,8 @@ static void prim_parseDrvName(EvalState & state, Value * * args, Value & v) string name = state.forceStringNoCtx(*args[0]); DrvName parsed(name); state.mkAttrs(v); - mkString((*v.attrs)[state.sName], parsed.name); - mkString((*v.attrs)[state.symbols.create("version")], parsed.version); + mkString((*v.attrs)[state.sName].value, parsed.name); + mkString((*v.attrs)[state.symbols.create("version")].value, parsed.version); } diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index 58e89925ce43..821f715e23c8 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -28,7 +28,8 @@ static void showAttrs(EvalState & state, bool strict, Bindings & attrs, names.insert(i->first); foreach (StringSet::iterator, i, names) { XMLOpenElement _(doc, "attr", singletonAttrs("name", *i)); - printValueAsXML(state, strict, attrs[state.symbols.create(*i)], doc, context, drvsSeen); + printValueAsXML(state, strict, attrs[state.symbols.create(*i)].value, + doc, context, drvsSeen); } } @@ -71,12 +72,12 @@ static void printValueAsXML(EvalState & state, bool strict, Value & v, Path drvPath; a = v.attrs->find(state.sDrvPath); - if (a != v.attrs->end() && a->second.type == tString) - xmlAttrs["drvPath"] = drvPath = a->second.string.s; + if (a != v.attrs->end() && a->second.value.type == tString) + xmlAttrs["drvPath"] = drvPath = a->second.value.string.s; a = v.attrs->find(state.sOutPath); - if (a != v.attrs->end() && a->second.type == tString) - xmlAttrs["outPath"] = a->second.string.s; + if (a != v.attrs->end() && a->second.value.type == tString) + xmlAttrs["outPath"] = a->second.value.string.s; XMLOpenElement _(doc, "derivation", xmlAttrs); diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index a0e51cae19c3..72e13fceb191 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -62,19 +62,19 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, manifest.list.elems[n++] = &v; state.mkAttrs(v); - mkString((*v.attrs)[state.sType], "derivation"); - mkString((*v.attrs)[state.sName], i->name); - mkString((*v.attrs)[state.sSystem], i->system); - mkString((*v.attrs)[state.sOutPath], i->queryOutPath(state)); + mkString((*v.attrs)[state.sType].value, "derivation"); + mkString((*v.attrs)[state.sName].value, i->name); + mkString((*v.attrs)[state.sSystem].value, i->system); + mkString((*v.attrs)[state.sOutPath].value, i->queryOutPath(state)); if (drvPath != "") - mkString((*v.attrs)[state.sDrvPath], i->queryDrvPath(state)); + mkString((*v.attrs)[state.sDrvPath].value, i->queryDrvPath(state)); - state.mkAttrs((*v.attrs)[state.sMeta]); + state.mkAttrs((*v.attrs)[state.sMeta].value); MetaInfo meta = i->queryMetaInfo(state); foreach (MetaInfo::const_iterator, j, meta) { - Value & v2((*(*v.attrs)[state.sMeta].attrs)[state.symbols.create(j->first)]); + Value & v2((*(*v.attrs)[state.sMeta].value.attrs)[state.symbols.create(j->first)].value); switch (j->second.type) { case MetaValue::tpInt: mkInt(v2, j->second.intValue); break; case MetaValue::tpString: mkString(v2, j->second.stringValue); break; @@ -116,10 +116,10 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, builder with the manifest as argument. */ Value args, topLevel; state.mkAttrs(args); - mkString((*args.attrs)[state.sSystem], thisSystem); - mkString((*args.attrs)[state.symbols.create("manifest")], + mkString((*args.attrs)[state.sSystem].value, thisSystem); + mkString((*args.attrs)[state.symbols.create("manifest")].value, manifestFile, singleton(manifestFile)); - (*args.attrs)[state.symbols.create("derivations")] = manifest; + (*args.attrs)[state.symbols.create("derivations")].value = manifest; mkApp(topLevel, envBuilder, args); /* Evaluate it. */ -- cgit 1.4.1