* Don't use ATerms for the abstract syntax trees anymore. Not
finished yet.
This commit is contained in:
		
							parent
							
								
									ed711f73bc
								
							
						
					
					
						commit
						4d6ad5be17
					
				
					 19 changed files with 693 additions and 579 deletions
				
			
		|  | @ -8,15 +8,15 @@ libexpr_la_SOURCES = \ | ||||||
| pkginclude_HEADERS = \ | pkginclude_HEADERS = \ | ||||||
|  nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \ |  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 \ |  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 \ | libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \ | ||||||
|  ../boost/format/libformat.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 |  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 = \ | AM_CXXFLAGS = \ | ||||||
|  -I$(srcdir)/.. ${aterm_include} \ |  -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  | 	$(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). | # SDF stuff (not built by default). | ||||||
| nix.tbl: nix.sdf | nix.tbl: nix.sdf | ||||||
| 	sdf2table -m Nix -s -i nix.sdf -o nix.tbl | 	sdf2table -m Nix -s -i nix.sdf -o nix.tbl | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| #include "attr-path.hh" | #include "attr-path.hh" | ||||||
| #include "nixexpr-ast.hh" |  | ||||||
| #include "util.hh" | #include "util.hh" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -7,7 +6,7 @@ namespace nix { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| void findAlongAttrPath(EvalState & state, const string & attrPath, | 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, "."); |     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%") |                     format("the expression selected by the selection path `%1%' should be an attribute set but is %2%") | ||||||
|                     % curPath % showType(v)); |                     % curPath % showType(v)); | ||||||
| 
 | 
 | ||||||
|             Bindings::iterator a = v.attrs->find(toATerm(attr)); |             Bindings::iterator a = v.attrs->find(attr); | ||||||
|             if (a == v.attrs->end()) |             if (a == v.attrs->end()) | ||||||
|                 throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); |                 throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); | ||||||
|             v = a->second; |             v = a->second; | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ namespace nix { | ||||||
| 
 | 
 | ||||||
|      |      | ||||||
| void findAlongAttrPath(EvalState & state, const string & attrPath, | void findAlongAttrPath(EvalState & state, const string & attrPath, | ||||||
|     const Bindings & autoArgs, Expr e, Value & v); |     const Bindings & autoArgs, Expr * e, Value & v); | ||||||
| 
 | 
 | ||||||
|      |      | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -20,10 +20,10 @@ bool parseOptionArg(const string & arg, Strings::iterator & i, | ||||||
|     if (i == argsEnd) throw error; |     if (i == argsEnd) throw error; | ||||||
|     string value = *i++; |     string value = *i++; | ||||||
| 
 | 
 | ||||||
|     Value & v(autoArgs[toATerm(name)]); |     Value & v(autoArgs[name]); | ||||||
| 
 | 
 | ||||||
|     if (arg == "--arg") |     if (arg == "--arg") | ||||||
|         state.mkThunk_(v, parseExprFromString(state, value, absPath("."))); |         state.mkThunk_(v, parseExprFromString(value, absPath("."))); | ||||||
|     else |     else | ||||||
|         mkString(v, value); |         mkString(v, value); | ||||||
|      |      | ||||||
|  |  | ||||||
|  | @ -2,8 +2,8 @@ | ||||||
| #include "parser.hh" | #include "parser.hh" | ||||||
| #include "hash.hh" | #include "hash.hh" | ||||||
| #include "util.hh" | #include "util.hh" | ||||||
| #include "nixexpr-ast.hh" |  | ||||||
| 
 | 
 | ||||||
|  | #include <iostream> | ||||||
| #include <cstdlib> | #include <cstdlib> | ||||||
| #include <cstring> | #include <cstring> | ||||||
| 
 | 
 | ||||||
|  | @ -12,8 +12,8 @@ using namespace nix; | ||||||
| 
 | 
 | ||||||
| void doTest(EvalState & state, string s) | void doTest(EvalState & state, string s) | ||||||
| { | { | ||||||
|     Expr e = parseExprFromString(state, s, absPath(".")); |     Expr * e = parseExprFromString(s, absPath(".")); | ||||||
|     printMsg(lvlError, format(">>>>> %1%") % e); |     std::cerr << ">>>>> " << *e << std::endl; | ||||||
|     Value v; |     Value v; | ||||||
|     state.eval(e, v); |     state.eval(e, v); | ||||||
|     state.strictForceValue(v); |     state.strictForceValue(v); | ||||||
|  | @ -26,6 +26,8 @@ void run(Strings args) | ||||||
|     EvalState state; |     EvalState state; | ||||||
| 
 | 
 | ||||||
|     printMsg(lvlError, format("size of value: %1% bytes") % sizeof(Value)); |     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, "123"); | ||||||
|     doTest(state, "{ x = 1; y = 2; }"); |     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 2)]"); | ||||||
|     doTest(state, "let id = x: x; in [1 2] == [(id 1) (id 3)]"); |     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, "[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; y = 2; } == { x = 2; }"); | ||||||
|     doTest(state, "{ x = [ 1 2 ]; } == { x = [ 1 ] ++ [ 2 ]; }"); |     doTest(state, "{ x = [ 1 2 ]; } == { x = [ 1 ] ++ [ 2 ]; }"); | ||||||
|     doTest(state, "1 != 1"); |     doTest(state, "1 != 1"); | ||||||
|  | @ -63,23 +65,23 @@ void run(Strings args) | ||||||
|     doTest(state, "__head [ 1 2 3 ]"); |     doTest(state, "__head [ 1 2 3 ]"); | ||||||
|     doTest(state, "__add 1 2"); |     doTest(state, "__add 1 2"); | ||||||
|     doTest(state, "null"); |     doTest(state, "null"); | ||||||
|     doTest(state, "null"); |     //doTest(state, "\"foo\"");
 | ||||||
|     doTest(state, "\"foo\""); |     //doTest(state, "let s = \"bar\"; in \"foo${s}\"");
 | ||||||
|     doTest(state, "let s = \"bar\"; in \"foo${s}\""); |  | ||||||
|     doTest(state, "if true then 1 else 2"); |     doTest(state, "if true then 1 else 2"); | ||||||
|     doTest(state, "if false then 1 else 2"); |     doTest(state, "if false then 1 else 2"); | ||||||
|     doTest(state, "if false || true 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, "let x = x; in if true || x then 1 else 2"); | ||||||
|  |     doTest(state, "http://nixos.org/"); | ||||||
|     doTest(state, "/etc/passwd"); |     doTest(state, "/etc/passwd"); | ||||||
|     //doTest(state, "import ./foo.nix");
 |     //doTest(state, "import ./foo.nix");
 | ||||||
|     doTest(state, "map (x: __add 1 x) [ 1 2 3 ]"); |     doTest(state, "map (x: __add 1 x) [ 1 2 3 ]"); | ||||||
|     doTest(state, "map (builtins.add 1) [ 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 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 = { 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, "let as = rec { inherit (y) x; y = { x = 1; }; }; in as.x"); | ||||||
|     doTest(state, "builtins.toXML 123"); |     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(); |     state.printStats(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,7 +4,6 @@ | ||||||
| #include "util.hh" | #include "util.hh" | ||||||
| #include "store-api.hh" | #include "store-api.hh" | ||||||
| #include "derivations.hh" | #include "derivations.hh" | ||||||
| #include "nixexpr-ast.hh" |  | ||||||
| #include "globals.hh" | #include "globals.hh" | ||||||
| 
 | 
 | ||||||
| #include <cstring> | #include <cstring> | ||||||
|  | @ -45,7 +44,7 @@ std::ostream & operator << (std::ostream & str, Value & v) | ||||||
|     case tAttrs: |     case tAttrs: | ||||||
|         str << "{ "; |         str << "{ "; | ||||||
|         foreach (Bindings::iterator, i, *v.attrs) |         foreach (Bindings::iterator, i, *v.attrs) | ||||||
|             str << aterm2String(i->first) << " = " << i->second << "; "; |             str << i->first << " = " << i->second << "; "; | ||||||
|         str << "}"; |         str << "}"; | ||||||
|         break; |         break; | ||||||
|     case tList: |     case tList: | ||||||
|  | @ -96,8 +95,6 @@ EvalState::EvalState() : baseEnv(allocEnv()) | ||||||
|     nrValues = nrEnvs = nrEvaluated = recursionDepth = maxRecursionDepth = 0; |     nrValues = nrEnvs = nrEvaluated = recursionDepth = maxRecursionDepth = 0; | ||||||
|     deepestStack = (char *) -1; |     deepestStack = (char *) -1; | ||||||
| 
 | 
 | ||||||
|     initNixExprHelpers(); |  | ||||||
| 
 |  | ||||||
|     createBaseEnv(); |     createBaseEnv(); | ||||||
|      |      | ||||||
|     allowUnsafeEquality = getEnv("NIX_NO_UNSAFE_EQ", "") == ""; |     allowUnsafeEquality = getEnv("NIX_NO_UNSAFE_EQ", "") == ""; | ||||||
|  | @ -112,9 +109,9 @@ EvalState::~EvalState() | ||||||
| 
 | 
 | ||||||
| void EvalState::addConstant(const string & name, Value & v) | 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; |     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; |     nrValues += 2; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -126,9 +123,9 @@ void EvalState::addPrimOp(const string & name, | ||||||
|     v.type = tPrimOp; |     v.type = tPrimOp; | ||||||
|     v.primOp.arity = arity; |     v.primOp.arity = arity; | ||||||
|     v.primOp.fun = primOp; |     v.primOp.fun = primOp; | ||||||
|     baseEnv.bindings[toATerm(name)] = v; |     baseEnv.bindings[name] = v; | ||||||
|     string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; |     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; |     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; |     if (!env) return 0; | ||||||
|     Value * v = lookupWith(env->up, name); |     Value * v = lookupWith(env->up, name); | ||||||
|     if (v) return v; |     if (v) return v; | ||||||
|     Bindings::iterator i = env->bindings.find(sWith); |     Bindings::iterator i = env->bindings.find("<with>"); | ||||||
|     if (i == env->bindings.end()) return 0; |     if (i == env->bindings.end()) return 0; | ||||||
|     Bindings::iterator j = i->second.attrs->find(name); |     Bindings::iterator j = i->second.attrs->find(name); | ||||||
|     if (j != i->second.attrs->end()) return &j->second; |     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'. */ |     /* First look for a regular variable binding for `name'. */ | ||||||
|     for (Env * env2 = env; env2; env2 = env2->up) { |     for (Env * env2 = env; env2; env2 = env2->up) { | ||||||
|  | @ -251,7 +248,7 @@ static Value * lookupVar(Env * env, Sym name) | ||||||
|     } |     } | ||||||
| #endif | #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); |     mkThunk(v, baseEnv, expr); | ||||||
| } | } | ||||||
|  | @ -302,11 +299,11 @@ void EvalState::evalFile(const Path & path, Value & v) | ||||||
| { | { | ||||||
|     startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); |     startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); | ||||||
| 
 | 
 | ||||||
|     Expr e = parseTrees.get(toATerm(path)); |     Expr * e = parseTrees[path]; | ||||||
| 
 | 
 | ||||||
|     if (!e) { |     if (!e) { | ||||||
|         e = parseExprFromFile(*this, path); |         e = parseExprFromFile(path); | ||||||
|         parseTrees.set(toATerm(path), e); |         parseTrees[path] = e; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     try { |     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
 |     /* When changing this function, make sure that you don't cause a
 | ||||||
|        (large) increase in stack consumption! */ |        (large) increase in stack consumption! */ | ||||||
|  | @ -350,6 +347,9 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
| 
 | 
 | ||||||
|     nrEvaluated++; |     nrEvaluated++; | ||||||
| 
 | 
 | ||||||
|  |     e->eval(*this, env, v); | ||||||
|  | 
 | ||||||
|  | #if 0 | ||||||
|     Sym name; |     Sym name; | ||||||
|     int n; |     int n; | ||||||
|     ATerm s; ATermList context, es; |     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; |     Expr e1, e2, e3, fun, arg, attrs; | ||||||
|     Pattern pat; Expr body; Pos pos; |     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)) { |     else if (matchConcatStrings(e, es)) { | ||||||
|         PathSet context; |         PathSet context; | ||||||
|         std::ostringstream s; |         std::ostringstream s; | ||||||
|  | @ -521,10 +389,6 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|             mkString(v, s.str(), context); |             mkString(v, s.str(), context); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Conditionals. */ |  | ||||||
|     else if (matchIf(e, e1, e2, e3)) |  | ||||||
|         eval(env, evalBool(env, e1) ? e2 : e3, v); |  | ||||||
| 
 |  | ||||||
|     /* Assertions. */ |     /* Assertions. */ | ||||||
|     else if (matchAssert(e, e1, e2, pos)) { |     else if (matchAssert(e, e1, e2, pos)) { | ||||||
|         if (!evalBool(env, e1)) |         if (!evalBool(env, e1)) | ||||||
|  | @ -536,30 +400,6 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|     else if (matchOpNot(e, e1)) |     else if (matchOpNot(e, e1)) | ||||||
|         mkBool(v, !evalBool(env, 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 (?). */ |     /* Attribute existence test (?). */ | ||||||
|     else if (matchOpHasAttr(e, e1, name)) { |     else if (matchOpHasAttr(e, e1, name)) { | ||||||
|         Value vAttrs; |         Value vAttrs; | ||||||
|  | @ -567,8 +407,130 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|         forceAttrs(vAttrs); |         forceAttrs(vAttrs); | ||||||
|         mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end()); |         mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end()); | ||||||
|     } |     } | ||||||
|  | #endif | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     else abort(); | 
 | ||||||
|  | void EvalState::eval(Expr * e, Value & v) | ||||||
|  | { | ||||||
|  |     eval(baseEnv, e, v); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 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<string>::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()); |     Env & env2(allocEnv()); | ||||||
|     env2.up = fun.lambda.env; |     env2.up = fun.lambda.env; | ||||||
| 
 | 
 | ||||||
|     ATermList formals; ATerm ellipsis, name; |     if (!fun.lambda.fun->matchAttrs) { | ||||||
| 
 |         Value & vArg = env2.bindings[fun.lambda.fun->arg]; | ||||||
|     if (matchVarPat(fun.lambda.pat, name)) { |  | ||||||
|         Value & vArg = env2.bindings[name]; |  | ||||||
|         nrValues++; |         nrValues++; | ||||||
|         vArg = arg; |         vArg = arg; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     else if (matchAttrsPat(fun.lambda.pat, formals, ellipsis, name)) { |     else { | ||||||
|         forceAttrs(arg); |         forceAttrs(arg); | ||||||
|          |          | ||||||
|         if (name != sNoAlias) { |         if (!fun.lambda.fun->arg.empty()) { | ||||||
|             env2.bindings[name] = arg; |             env2.bindings[fun.lambda.fun->arg] = arg; | ||||||
|             nrValues++; |             nrValues++; | ||||||
|         }                 |         }                 | ||||||
| 
 | 
 | ||||||
|  | @ -633,21 +593,15 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) | ||||||
|            there is no matching actual argument but the formal |            there is no matching actual argument but the formal | ||||||
|            argument has a default, use the default. */ |            argument has a default, use the default. */ | ||||||
|         unsigned int attrsUsed = 0; |         unsigned int attrsUsed = 0; | ||||||
|         for (ATermIterator i(formals); i; ++i) { |         foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) { | ||||||
|             Expr def; Sym name; |             Bindings::iterator j = arg.attrs->find(i->name); | ||||||
|             DefaultValue def2; |  | ||||||
|             if (!matchFormal(*i, name, def2)) abort(); /* can't happen */ |  | ||||||
|                  |                  | ||||||
|             Bindings::iterator j = arg.attrs->find(name); |             Value & v = env2.bindings[i->name]; | ||||||
|                  |  | ||||||
|             Value & v = env2.bindings[name]; |  | ||||||
|             nrValues++; |             nrValues++; | ||||||
|                  |                  | ||||||
|             if (j == arg.attrs->end()) { |             if (j == arg.attrs->end()) { | ||||||
|                 if (!matchDefaultValue(def2, def)) def = 0; |                 if (!i->def) throwTypeError("the argument named `%1%' required by the function is missing", i->name); | ||||||
|                 if (def == 0) throwTypeError("the argument named `%1%' required by the function is missing", |                 mkThunk(v, env2, i->def); | ||||||
|                     aterm2String(name)); |  | ||||||
|                 mkThunk(v, env2, def); |  | ||||||
|             } else { |             } else { | ||||||
|                 attrsUsed++; |                 attrsUsed++; | ||||||
|                 mkCopy(v, j->second); |                 mkCopy(v, j->second); | ||||||
|  | @ -658,13 +612,11 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) | ||||||
|            argument (unless the attribute match specifies a `...'). |            argument (unless the attribute match specifies a `...'). | ||||||
|            TODO: show the names of the expected/unexpected |            TODO: show the names of the expected/unexpected | ||||||
|            arguments. */ |            arguments. */ | ||||||
|         if (ellipsis == eFalse && attrsUsed != arg.attrs->size()) |         if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size()) | ||||||
|             throwTypeError("function called with unexpected argument"); |             throwTypeError("function called with unexpected argument"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     else abort(); |     eval(env2, fun.lambda.fun->body, v); | ||||||
|          |  | ||||||
|     eval(env2, fun.lambda.body, v); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -672,11 +624,7 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res | ||||||
| { | { | ||||||
|     forceValue(fun); |     forceValue(fun); | ||||||
| 
 | 
 | ||||||
|     ATerm name; |     if (fun.type != tLambda || !fun.lambda.fun->matchAttrs) { | ||||||
|     ATermList formals; |  | ||||||
|     ATermBool ellipsis; |  | ||||||
|      |  | ||||||
|     if (fun.type != tLambda || !matchAttrsPat(fun.lambda.pat, formals, ellipsis, name)) { |  | ||||||
|         res = fun; |         res = fun; | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  | @ -684,33 +632,106 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res | ||||||
|     Value actualArgs; |     Value actualArgs; | ||||||
|     mkAttrs(actualArgs); |     mkAttrs(actualArgs); | ||||||
| 
 | 
 | ||||||
|     for (ATermIterator i(formals); i; ++i) { |     foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) { | ||||||
|         Expr name, def; ATerm def2; |         Bindings::const_iterator j = args.find(i->name); | ||||||
|         if (!matchFormal(*i, name, def2)) abort(); |  | ||||||
|         Bindings::const_iterator j = args.find(name); |  | ||||||
|         if (j != args.end()) |         if (j != args.end()) | ||||||
|             (*actualArgs.attrs)[name] = j->second; |             (*actualArgs.attrs)[i->name] = j->second; | ||||||
|         else if (!matchDefaultValue(def2, def)) |         else if (!i->def) | ||||||
|             throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", aterm2String(name)); |             throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", i->name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     callFunction(fun, actualArgs, res); |     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["<with>"]; | ||||||
|  |     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; |     state.eval(env, state.evalBool(env, cond) ? then : else_, v); | ||||||
|     eval(env, e, v); | } | ||||||
|     if (v.type != tBool) | 
 | ||||||
|         throwTypeError("value is %1% while a Boolean was expected", showType(v)); |      | ||||||
|     return v.boolean; | 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) | bool EvalState::isDerivation(Value & v) | ||||||
| { | { | ||||||
|     if (v.type != tAttrs) return false; |     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"; |     return i != v.attrs->end() && forceStringNoCtx(i->second) == "derivation"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -871,7 +892,7 @@ string EvalState::coerceToString(Value & v, PathSet & context, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (v.type == tAttrs) { |     if (v.type == tAttrs) { | ||||||
|         Bindings::iterator i = v.attrs->find(toATerm("outPath")); |         Bindings::iterator i = v.attrs->find("outPath"); | ||||||
|         if (i == v.attrs->end()) |         if (i == v.attrs->end()) | ||||||
|             throwTypeError("cannot coerce an attribute set (except a derivation) to a string"); |             throwTypeError("cannot coerce an attribute set (except a derivation) to a string"); | ||||||
|         return coerceToString(i->second, context, coerceMore, copyToStore); |         return coerceToString(i->second, context, coerceMore, copyToStore); | ||||||
|  |  | ||||||
|  | @ -3,7 +3,6 @@ | ||||||
| 
 | 
 | ||||||
| #include <map> | #include <map> | ||||||
| 
 | 
 | ||||||
| #include "aterm.hh" |  | ||||||
| #include "nixexpr.hh" | #include "nixexpr.hh" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -15,7 +14,7 @@ class EvalState; | ||||||
| struct Env; | struct Env; | ||||||
| struct Value; | struct Value; | ||||||
| 
 | 
 | ||||||
| typedef ATerm Sym; | typedef string Sym; | ||||||
| 
 | 
 | ||||||
| typedef std::map<Sym, Value> Bindings; | typedef std::map<Sym, Value> Bindings; | ||||||
| 
 | 
 | ||||||
|  | @ -55,10 +54,32 @@ struct Value | ||||||
|     { |     { | ||||||
|         int integer; |         int integer; | ||||||
|         bool boolean; |         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 { |         struct { | ||||||
|             const char * s; |             const char * s; | ||||||
|             const char * * context; |             const char * * context; | ||||||
|         } string; |         } string; | ||||||
|  |          | ||||||
|         const char * path; |         const char * path; | ||||||
|         Bindings * attrs; |         Bindings * attrs; | ||||||
|         struct { |         struct { | ||||||
|  | @ -67,15 +88,14 @@ struct Value | ||||||
|         } list; |         } list; | ||||||
|         struct { |         struct { | ||||||
|             Env * env; |             Env * env; | ||||||
|             Expr expr; |             Expr * expr; | ||||||
|         } thunk; |         } thunk; | ||||||
|         struct { |         struct { | ||||||
|             Value * left, * right; |             Value * left, * right; | ||||||
|         } app; |         } app; | ||||||
|         struct { |         struct { | ||||||
|             Env * env; |             Env * env; | ||||||
|             Pattern pat; |             ExprLambda * fun; | ||||||
|             Expr body; |  | ||||||
|         } lambda; |         } lambda; | ||||||
|         Value * val; |         Value * val; | ||||||
|         struct { |         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.type = tThunk; | ||||||
|     v.thunk.env = &env; |     v.thunk.env = &env; | ||||||
|  | @ -146,7 +166,7 @@ private: | ||||||
| 
 | 
 | ||||||
|     bool allowUnsafeEquality; |     bool allowUnsafeEquality; | ||||||
| 
 | 
 | ||||||
|     ATermMap parseTrees; |     std::map<Path, Expr *> parseTrees; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|      |      | ||||||
|  | @ -159,12 +179,12 @@ public: | ||||||
| 
 | 
 | ||||||
|     /* Evaluate an expression to normal form, storing the result in
 |     /* Evaluate an expression to normal form, storing the result in
 | ||||||
|        value `v'. */ |        value `v'. */ | ||||||
|     void eval(Expr e, Value & v); |     void eval(Expr * e, Value & v); | ||||||
|     void eval(Env & env, Expr e, Value & v); |     void eval(Env & env, Expr * e, Value & v); | ||||||
| 
 | 
 | ||||||
|     /* Evaluation the expression, then verify that it has the expected
 |     /* Evaluation the expression, then verify that it has the expected
 | ||||||
|        type. */ |        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
 |     /* 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 |        of the evaluation of the thunk.  If `v' is a delayed function | ||||||
|  | @ -215,12 +235,12 @@ private: | ||||||
|     void addPrimOp(const string & name, |     void addPrimOp(const string & name, | ||||||
|         unsigned int arity, PrimOp primOp); |         unsigned int arity, PrimOp primOp); | ||||||
| 
 | 
 | ||||||
|  | public: | ||||||
|  |      | ||||||
|     /* Do a deep equality test between two values.  That is, list
 |     /* Do a deep equality test between two values.  That is, list
 | ||||||
|        elements and attributes are compared recursively. */ |        elements and attributes are compared recursively. */ | ||||||
|     bool eqValues(Value & v1, Value & v2); |     bool eqValues(Value & v1, Value & v2); | ||||||
| 
 | 
 | ||||||
| public: |  | ||||||
|      |  | ||||||
|     void callFunction(Value & fun, Value & arg, Value & v); |     void callFunction(Value & fun, Value & arg, Value & v); | ||||||
| 
 | 
 | ||||||
|     /* Automatically call a function for which each argument has a
 |     /* Automatically call a function for which each argument has a
 | ||||||
|  | @ -233,7 +253,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     void mkList(Value & v, unsigned int length); |     void mkList(Value & v, unsigned int length); | ||||||
|     void mkAttrs(Value & v); |     void mkAttrs(Value & v); | ||||||
|     void mkThunk_(Value & v, Expr expr); |     void mkThunk_(Value & v, Expr * expr); | ||||||
|      |      | ||||||
|     void cloneAttrs(Value & src, Value & dst); |     void cloneAttrs(Value & src, Value & dst); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| #include "get-drvs.hh" | #include "get-drvs.hh" | ||||||
| #include "nixexpr-ast.hh" |  | ||||||
| #include "util.hh" | #include "util.hh" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -9,7 +8,7 @@ namespace nix { | ||||||
| string DrvInfo::queryDrvPath(EvalState & state) const | string DrvInfo::queryDrvPath(EvalState & state) const | ||||||
| { | { | ||||||
|     if (drvPath == "") { |     if (drvPath == "") { | ||||||
|         Bindings::iterator i = attrs->find(toATerm("drvPath")); |         Bindings::iterator i = attrs->find("drvPath"); | ||||||
|         PathSet context; |         PathSet context; | ||||||
|         (string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, 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 | string DrvInfo::queryOutPath(EvalState & state) const | ||||||
| { | { | ||||||
|     if (outPath == "") { |     if (outPath == "") { | ||||||
|         Bindings::iterator i = attrs->find(toATerm("outPath")); |         Bindings::iterator i = attrs->find("outPath"); | ||||||
|         PathSet context; |         PathSet context; | ||||||
|         (string &) outPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; |         (string &) outPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; | ||||||
|     } |     } | ||||||
|  | @ -32,7 +31,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const | ||||||
| { | { | ||||||
|     MetaInfo meta; |     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 */ |     if (a == attrs->end()) return meta; /* fine, empty meta information */ | ||||||
| 
 | 
 | ||||||
|     state.forceAttrs(a->second); |     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) |             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; |         } else continue; | ||||||
|         meta[aterm2String(i->first)] = value; |         meta[i->first] = value; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return meta; |     return meta; | ||||||
|  | @ -114,12 +113,12 @@ static bool getDerivation(EvalState & state, Value & v, | ||||||
| 
 | 
 | ||||||
|         DrvInfo drv; |         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. */ |         /* !!! We really would like to have a decent back trace here. */ | ||||||
|         if (i == v.attrs->end()) throw TypeError("derivation name missing"); |         if (i == v.attrs->end()) throw TypeError("derivation name missing"); | ||||||
|         drv.name = state.forceStringNoCtx(i->second); |         drv.name = state.forceStringNoCtx(i->second); | ||||||
| 
 | 
 | ||||||
|         i = v.attrs->find(toATerm("system")); |         i = v.attrs->find("system"); | ||||||
|         if (i == v.attrs->end()) |         if (i == v.attrs->end()) | ||||||
|             drv.system = "unknown"; |             drv.system = "unknown"; | ||||||
|         else |         else | ||||||
|  | @ -171,7 +170,7 @@ static void getDerivations(EvalState & state, Value & vIn, | ||||||
| 
 | 
 | ||||||
|         /* !!! undocumented hackery to support combining channels in
 |         /* !!! undocumented hackery to support combining channels in
 | ||||||
|            nix-env.cc. */ |            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
 |         /* Consider the attributes in sorted order to get more
 | ||||||
|            deterministic behaviour in nix-env operations (e.g. when |            deterministic behaviour in nix-env operations (e.g. when | ||||||
|  | @ -180,12 +179,12 @@ static void getDerivations(EvalState & state, Value & vIn, | ||||||
|            precedence). */ |            precedence). */ | ||||||
|         StringSet attrs; |         StringSet attrs; | ||||||
|         foreach (Bindings::iterator, i, *v.attrs) |         foreach (Bindings::iterator, i, *v.attrs) | ||||||
|             attrs.insert(aterm2String(i->first)); |             attrs.insert(i->first); | ||||||
| 
 | 
 | ||||||
|         foreach (StringSet::iterator, i, attrs) { |         foreach (StringSet::iterator, i, attrs) { | ||||||
|             startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % *i); |             startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % *i); | ||||||
|             string pathPrefix2 = addToPath(pathPrefix, *i); |             string pathPrefix2 = addToPath(pathPrefix, *i); | ||||||
|             Value & v2((*v.attrs)[toATerm(*i)]); |             Value & v2((*v.attrs)[*i]); | ||||||
|             if (combineChannels) |             if (combineChannels) | ||||||
|                 getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); |                 getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); | ||||||
|             else if (getDerivation(state, v2, pathPrefix2, 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' |                    if it has a `recurseForDerivations = true' | ||||||
|                    attribute. */ |                    attribute. */ | ||||||
|                 if (v2.type == tAttrs) { |                 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)) |                     if (j != v2.attrs->end() && state.forceBool(j->second)) | ||||||
|                         getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); |                         getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  | @ -8,9 +8,7 @@ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| %{ | %{ | ||||||
| #include "aterm.hh" |  | ||||||
| #include "nixexpr.hh" | #include "nixexpr.hh" | ||||||
| #include "nixexpr-ast.hh" |  | ||||||
| #define BISON_HEADER_HACK | #define BISON_HEADER_HACK | ||||||
| #include "parser-tab.hh" | #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; |     string t; | ||||||
|     char c; |     char c; | ||||||
|     while ((c = *s++)) { |     while ((c = *s++)) { | ||||||
|  | @ -66,6 +65,7 @@ static Expr unescapeStr(const char * s) | ||||||
|         else t += c; |         else t += c; | ||||||
|     } |     } | ||||||
|     return makeStr(toATerm(t), ATempty); |     return makeStr(toATerm(t), ATempty); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|   |   | ||||||
|  | @ -105,7 +105,7 @@ inherit     { return INHERIT; } | ||||||
| \/\/        { return UPDATE; } | \/\/        { return UPDATE; } | ||||||
| \+\+        { return CONCAT; } | \+\+        { return CONCAT; } | ||||||
| 
 | 
 | ||||||
| {ID}        { yylval->t = toATerm(yytext); return ID; /* !!! alloc */ } | {ID}        { yylval->id = strdup(yytext); return ID; } | ||||||
| {INT}       { int n = atoi(yytext); /* !!! overflow */ | {INT}       { int n = atoi(yytext); /* !!! overflow */ | ||||||
|               yylval->n = n; |               yylval->n = n; | ||||||
|               return INT; |               return INT; | ||||||
|  | @ -117,7 +117,7 @@ inherit     { return INHERIT; } | ||||||
|    shouldn't be followed by a "{".  Right now "$\"" will be consumed |    shouldn't be followed by a "{".  Right now "$\"" will be consumed | ||||||
|    as part of a string, rather than a "$" followed by the string |    as part of a string, rather than a "$" followed by the string | ||||||
|    terminator.  Disallow "$\"" for now. */ |    terminator.  Disallow "$\"" for now. */ | ||||||
|               yylval->t = unescapeStr(yytext); /* !!! alloc */  |               yylval->e = unescapeStr(yytext); | ||||||
|               return STR; |               return STR; | ||||||
|             } |             } | ||||||
| <STRING>\$\{  { BEGIN(INITIAL); return DOLLAR_CURLY; } | <STRING>\$\{  { BEGIN(INITIAL); return DOLLAR_CURLY; } | ||||||
|  | @ -126,31 +126,31 @@ inherit     { return INHERIT; } | ||||||
| 
 | 
 | ||||||
| \'\'(\ *\n)?     { BEGIN(IND_STRING); return IND_STRING_OPEN; } | \'\'(\ *\n)?     { BEGIN(IND_STRING); return IND_STRING_OPEN; } | ||||||
| <IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ { | <IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ { | ||||||
|                    yylval->t = makeIndStr(toATerm(yytext)); |                    //yylval->t = makeIndStr(toATerm(yytext)); | ||||||
|                    return IND_STR; |                    return IND_STR; | ||||||
|                  } |                  } | ||||||
| <IND_STRING>\'\'\$ { | <IND_STRING>\'\'\$ { | ||||||
|                    yylval->t = makeIndStr(toATerm("$")); |                    //yylval->t = makeIndStr(toATerm("$")); | ||||||
|                    return IND_STR; |                    return IND_STR; | ||||||
|                  } |                  } | ||||||
| <IND_STRING>\'\'\' { | <IND_STRING>\'\'\' { | ||||||
|                    yylval->t = makeIndStr(toATerm("''")); |                    //yylval->t = makeIndStr(toATerm("''")); | ||||||
|                    return IND_STR; |                    return IND_STR; | ||||||
|                  } |                  } | ||||||
| <IND_STRING>\'\'\\. { | <IND_STRING>\'\'\\. { | ||||||
|                    yylval->t = unescapeStr(yytext + 2); |                    //yylval->t = unescapeStr(yytext + 2); | ||||||
|                    return IND_STR; |                    return IND_STR; | ||||||
|                  } |                  } | ||||||
| <IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; } | <IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; } | ||||||
| <IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; } | <IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; } | ||||||
| <IND_STRING>\'   { | <IND_STRING>\'   { | ||||||
|                    yylval->t = makeIndStr(toATerm("'")); |                    //yylval->t = makeIndStr(toATerm("'")); | ||||||
|                    return IND_STR; |                    return IND_STR; | ||||||
|                  } |                  } | ||||||
| <IND_STRING>.    return yytext[0]; /* just in case: shouldn't be reached */ | <IND_STRING>.    return yytext[0]; /* just in case: shouldn't be reached */ | ||||||
| 
 | 
 | ||||||
| {PATH}      { yylval->t = toATerm(yytext); return PATH; /* !!! alloc */ } | {PATH}      { yylval->path = strdup(yytext); return PATH; } | ||||||
| {URI}       { yylval->t = toATerm(yytext); return URI; /* !!! alloc */ } | {URI}       { yylval->uri = strdup(yytext); return URI; } | ||||||
| 
 | 
 | ||||||
| [ \t\r\n]+    /* eat up whitespace */ | [ \t\r\n]+    /* eat up whitespace */ | ||||||
| \#[^\r\n]*    /* single-line comments */ | \#[^\r\n]*    /* single-line comments */ | ||||||
|  |  | ||||||
|  | @ -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("<with>") |  | ||||||
|  | @ -1,10 +1,6 @@ | ||||||
| #include "nixexpr.hh" | #include "nixexpr.hh" | ||||||
| #include "derivations.hh" | #include "derivations.hh" | ||||||
| #include "util.hh" | #include "util.hh" | ||||||
| #include "aterm.hh" |  | ||||||
| 
 |  | ||||||
| #include "nixexpr-ast.hh" |  | ||||||
| #include "nixexpr-ast.cc" |  | ||||||
| 
 | 
 | ||||||
| #include <cstdlib> | #include <cstdlib> | ||||||
| 
 | 
 | ||||||
|  | @ -12,6 +8,87 @@ | ||||||
| namespace nix { | 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<string>::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<Expr *>::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) | string showPos(ATerm pos) | ||||||
| { | { | ||||||
|     ATerm path; |     ATerm path; | ||||||
|  | @ -159,28 +236,7 @@ void checkVarDefs(const ATermMap & defs, Expr e) | ||||||
|     set<Expr> done; |     set<Expr> done; | ||||||
|     checkVarDefs2(done, defs, e); |     checkVarDefs2(done, defs, e); | ||||||
| } | } | ||||||
| 
 | #endif | ||||||
| 
 |  | ||||||
| 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)); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,7 +3,6 @@ | ||||||
| 
 | 
 | ||||||
| #include <map> | #include <map> | ||||||
| 
 | 
 | ||||||
| #include "aterm-map.hh" |  | ||||||
| #include "types.hh" | #include "types.hh" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -18,22 +17,152 @@ MakeError(Abort, EvalError) | ||||||
| MakeError(TypeError, EvalError) | MakeError(TypeError, EvalError) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Nix expressions are represented as ATerms.  The maximal sharing
 | struct Pos | ||||||
|    property of the ATerm library allows us to implement caching of | { | ||||||
|    normals forms efficiently. */ |     string file; | ||||||
| typedef ATerm Expr; |     unsigned int line, column; | ||||||
| typedef ATerm DefaultValue; | }; | ||||||
| typedef ATerm Pos; |  | ||||||
| typedef ATerm Pattern; |  | ||||||
| typedef ATerm ATermBool; |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* A STL vector of ATerms.  Should be used with great care since it's
 | /* Abstract syntax of Nix expressions. */ | ||||||
|    stored on the heap, and the elements are therefore not roots to the | 
 | ||||||
|    ATerm garbage collector. */ | struct Env; | ||||||
| typedef vector<ATerm> ATermVector; | 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<string, Expr *> Attrs; | ||||||
|  |     Attrs attrs; | ||||||
|  |     list<string> inherited; | ||||||
|  |     ExprAttrs() : recursive(false) { }; | ||||||
|  |     COMMON_METHODS | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ExprList : Expr | ||||||
|  | { | ||||||
|  |     std::vector<Expr *> elems; | ||||||
|  |     ExprList() { }; | ||||||
|  |     COMMON_METHODS | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct Formal | ||||||
|  | { | ||||||
|  |     string name; | ||||||
|  |     Expr * def; | ||||||
|  |     Formal(const string & name, Expr * def) : name(name), def(def) { }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct Formals | ||||||
|  | { | ||||||
|  |     typedef std::list<Formal> 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. */ | /* Show a position. */ | ||||||
| string showPos(ATerm pos); | string showPos(ATerm pos); | ||||||
| 
 | 
 | ||||||
|  | @ -56,13 +185,7 @@ Expr makeAttrs(const ATermMap & attrs); | ||||||
| /* Check whether all variables are defined in the given expression.
 | /* Check whether all variables are defined in the given expression.
 | ||||||
|    Throw an exception if this isn't the case. */ |    Throw an exception if this isn't the case. */ | ||||||
| void checkVarDefs(const ATermMap & def, Expr e); | void checkVarDefs(const ATermMap & def, Expr e); | ||||||
| 
 | #endif | ||||||
| 
 |  | ||||||
| /* 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()); |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -9,11 +9,10 @@ namespace nix { | ||||||
| 
 | 
 | ||||||
| /* Parse a Nix expression from the specified file.  If `path' refers
 | /* Parse a Nix expression from the specified file.  If `path' refers
 | ||||||
|    to a directory, then "/default.nix" is appended. */ |    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. */ | /* Parse a Nix expression from the specified string. */ | ||||||
| Expr parseExprFromString(EvalState & state, const string & s, | Expr * parseExprFromString(const string & s, const Path & basePath); | ||||||
|     const Path & basePath); |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -23,13 +23,12 @@ | ||||||
| #include "aterm.hh" | #include "aterm.hh" | ||||||
| #include "util.hh" | #include "util.hh" | ||||||
|      |      | ||||||
|  | #include "nixexpr.hh" | ||||||
|  | 
 | ||||||
| #include "parser-tab.hh" | #include "parser-tab.hh" | ||||||
| #include "lexer-tab.hh" | #include "lexer-tab.hh" | ||||||
| #define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4 | #define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4 | ||||||
| 
 | 
 | ||||||
| #include "nixexpr.hh" |  | ||||||
| #include "nixexpr-ast.hh" |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| using namespace nix; | using namespace nix; | ||||||
| 
 | 
 | ||||||
|  | @ -39,13 +38,14 @@ namespace nix { | ||||||
|      |      | ||||||
| struct ParseData  | struct ParseData  | ||||||
| { | { | ||||||
|     Expr result; |     Expr * result; | ||||||
|     Path basePath; |     Path basePath; | ||||||
|     Path path; |     Path path; | ||||||
|     string error; |     string error; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #if 0 | ||||||
| static string showAttrPath(ATermList attrPath) | static string showAttrPath(ATermList attrPath) | ||||||
| { | { | ||||||
|     string s; |     string s; | ||||||
|  | @ -79,10 +79,12 @@ static ATermList buildAttrs(const Tree & t, ATermList & nonrec) | ||||||
|                 : makeBind(i->first, makeAttrs(buildAttrs(i->second, nonrec)), makeNoPos())); |                 : makeBind(i->first, makeAttrs(buildAttrs(i->second, nonrec)), makeNoPos())); | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
|  | #endif | ||||||
|   |   | ||||||
| 
 | 
 | ||||||
| static Expr fixAttrs(bool recursive, ATermList as) | static void fixAttrs(ExprAttrs & attrs) | ||||||
| { | { | ||||||
|  | #if 0 | ||||||
|     Tree attrs; |     Tree attrs; | ||||||
| 
 | 
 | ||||||
|     /* This ATermMap is needed to ensure that the `leaf' fields in the |     /* 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); |     ATermList rec = buildAttrs(attrs, nonrec); | ||||||
|          |          | ||||||
|     return recursive ? makeRec(rec, nonrec) : makeAttrs(rec); |     return recursive ? makeRec(rec, nonrec) : makeAttrs(rec); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #if 0 | ||||||
| static void checkPatternVars(ATerm pos, ATermMap & map, Pattern pat) | static void checkPatternVars(ATerm pos, ATermMap & map, Pattern pat) | ||||||
| { | { | ||||||
|     ATerm name = sNoAlias; |     ATerm name = sNoAlias; | ||||||
|  | @ -261,6 +265,7 @@ static Expr stripIndentation(ATermList es) | ||||||
| 
 | 
 | ||||||
|     return makeConcatStrings(ATreverse(es2)); |     return makeConcatStrings(ATreverse(es2)); | ||||||
| } | } | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| void backToString(yyscan_t scanner); | void backToString(yyscan_t scanner); | ||||||
|  | @ -269,8 +274,11 @@ void backToIndString(yyscan_t scanner); | ||||||
| 
 | 
 | ||||||
| static Pos makeCurPos(YYLTYPE * loc, ParseData * data) | static Pos makeCurPos(YYLTYPE * loc, ParseData * data) | ||||||
| { | { | ||||||
|     return makePos(toATerm(data->path), |     Pos pos; | ||||||
|         loc->first_line, loc->first_column); |     pos.file = data->path; | ||||||
|  |     pos.line = loc->first_line; | ||||||
|  |     pos.column = loc->first_column; | ||||||
|  |     return pos; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #define CUR_POS makeCurPos(yylocp, data) | #define CUR_POS makeCurPos(yylocp, data) | ||||||
|  | @ -311,22 +319,31 @@ static void freeAndUnprotect(void * p) | ||||||
| %} | %} | ||||||
| 
 | 
 | ||||||
| %union { | %union { | ||||||
|   ATerm t; |   nix::Expr * e; | ||||||
|   ATermList ts; |   nix::ExprList * list; | ||||||
|   struct { |   nix::ExprAttrs * attrs; | ||||||
|     ATermList formals; |   nix::Formals * formals; | ||||||
|     bool ellipsis; |   nix::Formal * formal; | ||||||
|   } formals; |  | ||||||
|   int n; |   int n; | ||||||
|  |   char * id; | ||||||
|  |   char * path; | ||||||
|  |   char * uri; | ||||||
|  |   std::list<std::string> * ids; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| %type <t> start expr expr_function expr_if expr_op | %type <e> start expr expr_function expr_if expr_op | ||||||
| %type <t> expr_app expr_select expr_simple bind inheritsrc formal | %type <e> expr_app expr_select expr_simple | ||||||
| %type <t> pattern | %type <list> expr_list | ||||||
| %type <ts> binds ids attrpath expr_list string_parts ind_string_parts | %type <attrs> binds | ||||||
|  | %type <ts> attrpath string_parts ind_string_parts | ||||||
| %type <formals> formals | %type <formals> formals | ||||||
| %token <t> ID STR IND_STR PATH URI | %type <formal> formal | ||||||
|  | %type <ids> ids | ||||||
|  | %token <id> ID ATTRPATH | ||||||
|  | %token <t> STR IND_STR | ||||||
| %token <n> INT | %token <n> INT | ||||||
|  | %token <path> PATH | ||||||
|  | %token <uri> URI | ||||||
| %token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL | %token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL | ||||||
| %token DOLLAR_CURLY /* == ${ */ | %token DOLLAR_CURLY /* == ${ */ | ||||||
| %token IND_STRING_OPEN IND_STRING_CLOSE | %token IND_STRING_OPEN IND_STRING_CLOSE | ||||||
|  | @ -350,52 +367,61 @@ start: expr { data->result = $1; }; | ||||||
| expr: expr_function; | expr: expr_function; | ||||||
| 
 | 
 | ||||||
| expr_function | expr_function | ||||||
|   : pattern ':' expr_function |   : ID ':' expr_function | ||||||
|     { checkPatternVars(CUR_POS, $1); $$ = makeFunction($1, $3, CUR_POS); } |     { $$ = new ExprLambda(CUR_POS, $1, false, 0, $3); /* checkPatternVars(CUR_POS, $1); $$ = makeFunction($1, $3, CUR_POS); */ } | ||||||
|   | ASSERT expr ';' expr_function |   | '{' 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); } |     { $$ = makeAssert($2, $4, CUR_POS); } | ||||||
|  |     */ | ||||||
|   | WITH expr ';' expr_function |   | WITH expr ';' expr_function | ||||||
|     { $$ = makeWith($2, $4, CUR_POS); } |     { $$ = new ExprWith(CUR_POS, $2, $4); } | ||||||
|   | LET binds IN expr_function |   | LET binds IN expr_function | ||||||
|     { $$ = makeSelect(fixAttrs(true, ATinsert($2, makeBindAttrPath(ATmakeList1(toATerm("<let-body>")), $4, CUR_POS))), toATerm("<let-body>")); } |     { $2->attrs["<let-body>"] = $4; $2->recursive = true; fixAttrs(*$2); $$ = new ExprSelect($2, "<let-body>"); } | ||||||
|   | expr_if |   | expr_if | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| expr_if | expr_if | ||||||
|   : IF expr THEN expr ELSE expr |   : IF expr THEN expr ELSE expr { $$ = new ExprIf($2, $4, $6); } | ||||||
|     { $$ = makeIf($2, $4, $6); } |  | ||||||
|   | expr_op |   | expr_op | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| expr_op | expr_op | ||||||
|   : '!' expr_op %prec NEG { $$ = makeOpNot($2); } |   : /* '!' expr_op %prec NEG { $$ = makeOpNot($2); } | ||||||
|   | expr_op EQ expr_op { $$ = makeOpEq($1, $3); } |        | */ | ||||||
|   | expr_op NEQ expr_op { $$ = makeOpNEq($1, $3); } |     expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); } | ||||||
|   | expr_op AND expr_op { $$ = makeOpAnd($1, $3); } |   | expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); } | ||||||
|   | expr_op OR expr_op { $$ = makeOpOr($1, $3); } |   | expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); } | ||||||
|   | expr_op IMPL expr_op { $$ = makeOpImpl($1, $3); } |   | expr_op OR expr_op { $$ = new ExprOpOr($1, $3); } | ||||||
|   | expr_op UPDATE expr_op { $$ = makeOpUpdate($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 '?' 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_app | ||||||
|   : expr_app expr_select |   : expr_app expr_select | ||||||
|     { $$ = makeCall($1, $2); } |     { $$ = new ExprApp($1, $2); } | ||||||
|   | expr_select { $$ = $1; } |   | expr_select { $$ = $1; } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| expr_select | expr_select | ||||||
|   : expr_select '.' ID |   : expr_select '.' ID | ||||||
|     { $$ = makeSelect($1, $3); } |     { $$ = new ExprSelect($1, $3); } | ||||||
|   | expr_simple { $$ = $1; } |   | expr_simple { $$ = $1; } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| expr_simple | expr_simple | ||||||
|   : ID { $$ = makeVar($1); } |   : ID { $$ = new ExprVar($1); } | ||||||
|   | INT { $$ = makeInt($1); } |   | INT { $$ = new ExprInt($1); } /* | ||||||
|   | '"' string_parts '"' { |   | '"' 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); |       if ($2 == ATempty) $$ = makeStr(toATerm(""), ATempty); | ||||||
|  | @ -405,18 +431,21 @@ expr_simple | ||||||
|   | IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE { |   | IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE { | ||||||
|       $$ = stripIndentation(ATreverse($2)); |       $$ = 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; } |   | '(' expr ')' { $$ = $2; } | ||||||
|  | /* | ||||||
|   /* Let expressions `let {..., body = ...}' are just desugared |   /* Let expressions `let {..., body = ...}' are just desugared | ||||||
|      into `(rec {..., body = ...}).body'. * / |      into `(rec {..., body = ...}).body'. * / | ||||||
|   | LET '{' binds '}' |   | LET '{' binds '}' | ||||||
|     { $$ = makeSelect(fixAttrs(true, $3), toATerm("body")); } |     { $$ = makeSelect(fixAttrs(true, $3), toATerm("body")); } | ||||||
|  |   */ | ||||||
|   | REC '{' binds '}' |   | REC '{' binds '}' | ||||||
|     { $$ = fixAttrs(true, $3); } |     { fixAttrs(*$3); $3->recursive = true; $$ = $3; } | ||||||
|   | '{' binds '}' |   | '{' binds '}' | ||||||
|     { $$ = fixAttrs(false, $2); } |     { fixAttrs(*$2); $$ = $2; } | ||||||
|   | '[' expr_list ']' { $$ = makeList(ATreverse($2)); } |   | '[' expr_list ']' { $$ = $2; } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| string_parts | string_parts | ||||||
|  | @ -431,63 +460,56 @@ ind_string_parts | ||||||
|   | { $$ = ATempty; } |   | { $$ = 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 | ||||||
|   : binds bind { $$ = ATinsert($1, $2); } |   : binds ID '=' expr ';' { $$ = $1; $$->attrs[$2] = $4; } | ||||||
|   | { $$ = ATempty; } |   | binds INHERIT ids ';' | ||||||
|  |     { $$ = $1; | ||||||
|  |       foreach (list<string>::iterator, i, *$3) | ||||||
|  |         $$->inherited.push_back(*i); | ||||||
|  |     } | ||||||
|  |   | binds INHERIT '(' expr ')' ids ';' | ||||||
|  |     { $$ = $1; | ||||||
|  |       /* !!! Should ensure sharing of the expression in $4. */ | ||||||
|  |       foreach (list<string>::iterator, i, *$6) | ||||||
|  |         $$->attrs[*i] = new ExprSelect($4, *i); | ||||||
|  |     } | ||||||
|  |   | { $$ = new ExprAttrs; } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| bind | ids | ||||||
|   : attrpath '=' expr ';' |   : ids ID { $$ = $1; $1->push_back($2); /* !!! dangerous */ } | ||||||
|     { $$ = makeBindAttrPath(ATreverse($1), $3, CUR_POS); } |   | { $$ = new list<string>; } | ||||||
|   | INHERIT inheritsrc ids ';' |  | ||||||
|     { $$ = makeInherit($2, $3, CUR_POS); } |  | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| inheritsrc |  | ||||||
|   : '(' expr ')' { $$ = $2; } |  | ||||||
|   | { $$ = makeScope(); } |  | ||||||
|   ; |  | ||||||
| 
 |  | ||||||
| ids: ids ID { $$ = ATinsert($1, $2); } | { $$ = ATempty; }; |  | ||||||
| 
 |  | ||||||
| attrpath | attrpath | ||||||
|   : attrpath '.' ID { $$ = ATinsert($1, $3); } |   : attrpath '.' ID { $$ = ATinsert($1, $3); } | ||||||
|   | ID { $$ = ATmakeList1($1); } |   | ID { $$ = ATmakeList1($1); } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| expr_list | expr_list | ||||||
|   : expr_list expr_select { $$ = ATinsert($1, $2); } |   : expr_list expr_select { $$ = $1; $1->elems.push_back($2); /* !!! dangerous */ } | ||||||
|   | { $$ = ATempty; } |   | { $$ = new ExprList; } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| formals | formals | ||||||
|   : formal ',' formals /* !!! right recursive */ |   : formal ',' formals | ||||||
|     { $$.formals = ATinsert($3.formals, $1); $$.ellipsis = $3.ellipsis; } |     { $$ = $3; $$->formals.push_front(*$1); /* !!! dangerous */ } | ||||||
|   | formal |   | formal | ||||||
|     { $$.formals = ATinsert(ATempty, $1); $$.ellipsis = false; } |     { $$ = new Formals; $$->formals.push_back(*$1); $$->ellipsis = false; } | ||||||
|   | |   | | ||||||
|     { $$.formals = ATempty; $$.ellipsis = false; } |     { $$ = new Formals; $$->ellipsis = false; } | ||||||
|   | ELLIPSIS |   | ELLIPSIS | ||||||
|     { $$.formals = ATempty; $$.ellipsis = true; } |     { $$ = new Formals; $$->ellipsis = true; } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| formal | formal | ||||||
|   : ID { $$ = makeFormal($1, makeNoDefaultValue()); } |   : ID { $$ = new Formal($1, 0); } | ||||||
|   | ID '?' expr { $$ = makeFormal($1, makeDefaultValue($3)); } |   | ID '?' expr { $$ = new Formal($1, $3); } | ||||||
|   ; |   ; | ||||||
|    |    | ||||||
| %% | %% | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #include "eval.hh"   |  | ||||||
| 
 |  | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
|  | @ -497,9 +519,7 @@ formal | ||||||
| namespace nix { | namespace nix { | ||||||
|        |        | ||||||
| 
 | 
 | ||||||
| static Expr parse(EvalState & state, | static Expr * parse(const char * text, const Path & path, const Path & basePath) | ||||||
|     const char * text, const Path & path, |  | ||||||
|     const Path & basePath) |  | ||||||
| { | { | ||||||
|     yyscan_t scanner; |     yyscan_t scanner; | ||||||
|     ParseData data; |     ParseData data; | ||||||
|  | @ -523,7 +543,7 @@ static Expr parse(EvalState & state, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Expr parseExprFromFile(EvalState & state, Path path) | Expr * parseExprFromFile(Path path) | ||||||
| { | { | ||||||
|     assert(path[0] == '/'); |     assert(path[0] == '/'); | ||||||
| 
 | 
 | ||||||
|  | @ -544,14 +564,13 @@ Expr parseExprFromFile(EvalState & state, Path path) | ||||||
|         path = canonPath(path + "/default.nix"); |         path = canonPath(path + "/default.nix"); | ||||||
| 
 | 
 | ||||||
|     /* Read and parse the input file. */ |     /* 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, | Expr * parseExprFromString(const string & s, const Path & basePath) | ||||||
|     const string & s, const Path & basePath) |  | ||||||
| { | { | ||||||
|     return parse(state, s.c_str(), "(string)", basePath); |     return parse(s.c_str(), "(string)", basePath); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|   |   | ||||||
|  |  | ||||||
|  | @ -5,7 +5,6 @@ | ||||||
| #include "util.hh" | #include "util.hh" | ||||||
| #include "archive.hh" | #include "archive.hh" | ||||||
| #include "value-to-xml.hh" | #include "value-to-xml.hh" | ||||||
| #include "nixexpr-ast.hh" |  | ||||||
| #include "parser.hh" | #include "parser.hh" | ||||||
| #include "names.hh" | #include "names.hh" | ||||||
| 
 | 
 | ||||||
|  | @ -281,7 +280,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) | ||||||
|     state.forceAttrs(*args[0]); |     state.forceAttrs(*args[0]); | ||||||
| 
 | 
 | ||||||
|     /* Figure out the name first (for stack backtraces). */ |     /* 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()) |     if (attr == args[0]->attrs->end()) | ||||||
|         throw EvalError("required attribute `name' missing"); |         throw EvalError("required attribute `name' missing"); | ||||||
|     string drvName; |     string drvName; | ||||||
|  | @ -302,7 +301,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) | ||||||
|     bool outputHashRecursive = false; |     bool outputHashRecursive = false; | ||||||
| 
 | 
 | ||||||
|     foreach (Bindings::iterator, i, *args[0]->attrs) { |     foreach (Bindings::iterator, i, *args[0]->attrs) { | ||||||
|         string key = aterm2String(i->first); |         string key = i->first; | ||||||
|         startNest(nest, lvlVomit, format("processing attribute `%1%'") % key); |         startNest(nest, lvlVomit, format("processing attribute `%1%'") % key); | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|  | @ -449,8 +448,8 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) | ||||||
| 
 | 
 | ||||||
|     /* !!! assumes a single output */ |     /* !!! assumes a single output */ | ||||||
|     state.mkAttrs(v); |     state.mkAttrs(v); | ||||||
|     mkString((*v.attrs)[toATerm("outPath")], outPath, singleton<PathSet>(drvPath)); |     mkString((*v.attrs)["outPath"], outPath, singleton<PathSet>(drvPath)); | ||||||
|     mkString((*v.attrs)[toATerm("drvPath")], drvPath, singleton<PathSet>("=" + drvPath)); |     mkString((*v.attrs)["drvPath"], drvPath, singleton<PathSet>("=" + drvPath)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -655,7 +654,7 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v) | ||||||
| 
 | 
 | ||||||
|     StringSet names; |     StringSet names; | ||||||
|     foreach (Bindings::iterator, i, *args[0]->attrs) |     foreach (Bindings::iterator, i, *args[0]->attrs) | ||||||
|         names.insert(aterm2String(i->first)); |         names.insert(i->first); | ||||||
| 
 | 
 | ||||||
|     unsigned int n = 0; |     unsigned int n = 0; | ||||||
|     foreach (StringSet::iterator, i, names) |     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]); |     string attr = state.forceStringNoCtx(*args[0]); | ||||||
|     state.forceAttrs(*args[1]); |     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()) |     if (i == args[1]->attrs->end()) | ||||||
|         throw EvalError(format("attribute `%1%' missing") % attr); |         throw EvalError(format("attribute `%1%' missing") % attr); | ||||||
|     state.forceValue(i->second); |     state.forceValue(i->second); | ||||||
|  | @ -681,7 +680,7 @@ static void prim_hasAttr(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     string attr = state.forceStringNoCtx(*args[0]); |     string attr = state.forceStringNoCtx(*args[0]); | ||||||
|     state.forceAttrs(*args[1]); |     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) { |     for (unsigned int i = 0; i < args[1]->list.length; ++i) { | ||||||
|         state.forceStringNoCtx(args[1]->list.elems[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]); |         Value & v2(args[0]->list.elems[i]); | ||||||
|         state.forceAttrs(v2); |         state.forceAttrs(v2); | ||||||
|          |          | ||||||
|         Bindings::iterator j = v2.attrs->find(toATerm("name")); |         Bindings::iterator j = v2.attrs->find("name"); | ||||||
|         if (j == v2.attrs->end()) |         if (j == v2.attrs->end()) | ||||||
|             throw TypeError("`name' attribute missing in a call to `listToAttrs'"); |             throw TypeError("`name' attribute missing in a call to `listToAttrs'"); | ||||||
|         string name = state.forceStringNoCtx(j->second); |         string name = state.forceStringNoCtx(j->second); | ||||||
|          |          | ||||||
|         j = v2.attrs->find(toATerm("value")); |         j = v2.attrs->find("value"); | ||||||
|         if (j == v2.attrs->end()) |         if (j == v2.attrs->end()) | ||||||
|             throw TypeError("`value' attribute missing in a call to `listToAttrs'"); |             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]); |     string name = state.forceStringNoCtx(*args[0]); | ||||||
|     DrvName parsed(name); |     DrvName parsed(name); | ||||||
|     state.mkAttrs(v); |     state.mkAttrs(v); | ||||||
|     mkString((*v.attrs)[toATerm("name")], parsed.name); |     mkString((*v.attrs)["name"], parsed.name); | ||||||
|     mkString((*v.attrs)[toATerm("version")], parsed.version); |     mkString((*v.attrs)["version"], parsed.version); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -999,10 +998,9 @@ void EvalState::createBaseEnv() | ||||||
| { | { | ||||||
|     baseEnv.up = 0; |     baseEnv.up = 0; | ||||||
| 
 | 
 | ||||||
|     {   Value & v = baseEnv.bindings[toATerm("builtins")]; |     Value & builtins = baseEnv.bindings["builtins"]; | ||||||
|         v.type = tAttrs; |     builtins.type = tAttrs; | ||||||
|         v.attrs = new Bindings; |     builtins.attrs = new Bindings; | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /* Add global constants such as `true' to the base environment. */ |     /* Add global constants such as `true' to the base environment. */ | ||||||
|     Value v; |     Value v; | ||||||
|  | @ -1025,8 +1023,8 @@ void EvalState::createBaseEnv() | ||||||
|     /* Add a wrapper around the derivation primop that computes the
 |     /* Add a wrapper around the derivation primop that computes the
 | ||||||
|        `drvPath' and `outPath' attributes lazily. */ |        `drvPath' and `outPath' attributes lazily. */ | ||||||
|     string s = "attrs: let res = derivationStrict attrs; in attrs // { drvPath = res.drvPath; outPath = res.outPath; type = \"derivation\"; }"; |     string s = "attrs: let res = derivationStrict attrs; in attrs // { drvPath = res.drvPath; outPath = res.outPath; type = \"derivation\"; }"; | ||||||
|     mkThunk(v, baseEnv, parseExprFromString(*this, s, "/")); |     //mkThunk(v, baseEnv, parseExprFromString(s, "/"));
 | ||||||
|     addConstant("derivation", v); |     //addConstant("derivation", v);
 | ||||||
| 
 | 
 | ||||||
|     // Miscellaneous
 |     // Miscellaneous
 | ||||||
|     addPrimOp("import", 1, prim_import); |     addPrimOp("import", 1, prim_import); | ||||||
|  |  | ||||||
|  | @ -1,7 +1,5 @@ | ||||||
| #include "value-to-xml.hh" | #include "value-to-xml.hh" | ||||||
| #include "xml-writer.hh" | #include "xml-writer.hh" | ||||||
| #include "nixexpr-ast.hh" |  | ||||||
| #include "aterm.hh" |  | ||||||
| #include "util.hh" | #include "util.hh" | ||||||
| 
 | 
 | ||||||
| #include <cstdlib> | #include <cstdlib> | ||||||
|  | @ -27,31 +25,10 @@ static void showAttrs(EvalState & state, bool strict, Bindings & attrs, | ||||||
| { | { | ||||||
|     StringSet names; |     StringSet names; | ||||||
|     foreach (Bindings::iterator, i, attrs) |     foreach (Bindings::iterator, i, attrs) | ||||||
|         names.insert(aterm2String(i->first)); |         names.insert(i->first); | ||||||
|     foreach (StringSet::iterator, i, names) { |     foreach (StringSet::iterator, i, names) { | ||||||
|         XMLOpenElement _(doc, "attr", singletonAttrs("name", *i)); |         XMLOpenElement _(doc, "attr", singletonAttrs("name", *i)); | ||||||
|         printValueAsXML(state, strict, attrs[toATerm(*i)], doc, context, drvsSeen); |         printValueAsXML(state, strict, attrs[*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))); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -90,14 +67,14 @@ static void printValueAsXML(EvalState & state, bool strict, Value & v, | ||||||
|             if (state.isDerivation(v)) { |             if (state.isDerivation(v)) { | ||||||
|                 XMLAttrs xmlAttrs; |                 XMLAttrs xmlAttrs; | ||||||
|              |              | ||||||
|                 Bindings::iterator a = v.attrs->find(toATerm("derivation")); |                 Bindings::iterator a = v.attrs->find("derivation"); | ||||||
| 
 | 
 | ||||||
|                 Path drvPath; |                 Path drvPath; | ||||||
|                 a = v.attrs->find(toATerm("drvPath")); |                 a = v.attrs->find("drvPath"); | ||||||
|                 if (a != v.attrs->end() && a->second.type == tString) |                 if (a != v.attrs->end() && a->second.type == tString) | ||||||
|                     xmlAttrs["drvPath"] = drvPath = a->second.string.s; |                     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) |                 if (a != v.attrs->end() && a->second.type == tString) | ||||||
|                     xmlAttrs["outPath"] = a->second.string.s; |                     xmlAttrs["outPath"] = a->second.string.s; | ||||||
| 
 | 
 | ||||||
|  | @ -126,7 +103,15 @@ static void printValueAsXML(EvalState & state, bool strict, Value & v, | ||||||
| 
 | 
 | ||||||
|         case tLambda: { |         case tLambda: { | ||||||
|             XMLOpenElement _(doc, "function"); |             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; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -177,7 +177,7 @@ static void initAndRun(int argc, char * * argv) | ||||||
|     if (lt != "") setLogType(lt); |     if (lt != "") setLogType(lt); | ||||||
| 
 | 
 | ||||||
|     /* ATerm stuff.  !!! find a better place to put this */ |     /* ATerm stuff.  !!! find a better place to put this */ | ||||||
|     initDerivationsHelpers(); |     //initDerivationsHelpers();
 | ||||||
|      |      | ||||||
|     /* Put the arguments in a vector. */ |     /* Put the arguments in a vector. */ | ||||||
|     Strings args, remaining; |     Strings args, remaining; | ||||||
|  | @ -335,7 +335,7 @@ int main(int argc, char * * argv) | ||||||
|      |      | ||||||
|     /* ATerm setup. */ |     /* ATerm setup. */ | ||||||
|     ATerm bottomOfStack; |     ATerm bottomOfStack; | ||||||
|     ATinit(argc, argv, &bottomOfStack); |     //ATinit(argc, argv, &bottomOfStack);
 | ||||||
| 
 | 
 | ||||||
|     /* Turn on buffering for cerr. */ |     /* Turn on buffering for cerr. */ | ||||||
| #if HAVE_PUBSETBUF | #if HAVE_PUBSETBUF | ||||||
|  |  | ||||||
|  | @ -6,7 +6,6 @@ | ||||||
| #include "parser.hh" | #include "parser.hh" | ||||||
| #include "eval.hh" | #include "eval.hh" | ||||||
| #include "help.txt.hh" | #include "help.txt.hh" | ||||||
| #include "nixexpr-ast.hh" |  | ||||||
| #include "get-drvs.hh" | #include "get-drvs.hh" | ||||||
| #include "attr-path.hh" | #include "attr-path.hh" | ||||||
| #include "pathlocks.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
 |     /* The path is a directory.  Put the Nix expressions in the
 | ||||||
|        directory in an attribute set, with the file name of each |        directory in an attribute set, with the file name of each | ||||||
|  |  | ||||||
|  | @ -23,12 +23,12 @@ void printHelp() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static Expr parseStdin(EvalState & state) | static Expr * parseStdin(EvalState & state) | ||||||
| { | { | ||||||
|     startNest(nest, lvlTalkative, format("parsing standard input")); |     startNest(nest, lvlTalkative, format("parsing standard input")); | ||||||
|     string s, s2; |     string s, s2; | ||||||
|     while (getline(std::cin, s2)) s += s2 + "\n"; |     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, | void processExpr(EvalState & state, const Strings & attrPaths, | ||||||
|     bool parseOnly, bool strict, const Bindings & autoArgs, |     bool parseOnly, bool strict, const Bindings & autoArgs, | ||||||
|     bool evalOnly, bool xmlOutput, Expr e) |     bool evalOnly, bool xmlOutput, Expr * e) | ||||||
| { | { | ||||||
|     if (parseOnly) |     if (parseOnly) | ||||||
|         std::cout << format("%1%\n"); |         std::cout << format("%1%\n"); | ||||||
|  | @ -129,14 +129,14 @@ void run(Strings args) | ||||||
|     store = openStore(); |     store = openStore(); | ||||||
| 
 | 
 | ||||||
|     if (readStdin) { |     if (readStdin) { | ||||||
|         Expr e = parseStdin(state); |         Expr * e = parseStdin(state); | ||||||
|         processExpr(state, attrPaths, parseOnly, strict, autoArgs, |         processExpr(state, attrPaths, parseOnly, strict, autoArgs, | ||||||
|             evalOnly, xmlOutput, e); |             evalOnly, xmlOutput, e); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     foreach (Strings::iterator, i, files) { |     foreach (Strings::iterator, i, files) { | ||||||
|         Path path = absPath(*i); |         Path path = absPath(*i); | ||||||
|         Expr e = parseExprFromFile(state, path); |         Expr * e = parseExprFromFile(path); | ||||||
|         processExpr(state, attrPaths, parseOnly, strict, autoArgs, |         processExpr(state, attrPaths, parseOnly, strict, autoArgs, | ||||||
|             evalOnly, xmlOutput, e); |             evalOnly, xmlOutput, e); | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue