* Make `import' work.
This commit is contained in:
		
							parent
							
								
									31428c3a06
								
							
						
					
					
						commit
						d78a05ab40
					
				
					 4 changed files with 141 additions and 62 deletions
				
			
		|  | @ -13,7 +13,7 @@ using namespace nix; | ||||||
| void doTest(string s) | void doTest(string s) | ||||||
| { | { | ||||||
|     EvalState state; |     EvalState state; | ||||||
|     Expr e = parseExprFromString(state, s, "/"); |     Expr e = parseExprFromString(state, s, absPath(".")); | ||||||
|     printMsg(lvlError, format(">>>>> %1%") % e); |     printMsg(lvlError, format(">>>>> %1%") % e); | ||||||
|     Value v; |     Value v; | ||||||
|     state.strictEval(e, v); |     state.strictEval(e, v); | ||||||
|  | @ -66,6 +66,8 @@ void run(Strings args) | ||||||
|     doTest("if false then 1 else 2"); |     doTest("if false then 1 else 2"); | ||||||
|     doTest("if false || true then 1 else 2"); |     doTest("if false || true then 1 else 2"); | ||||||
|     doTest("let x = x; in if true || x then 1 else 2"); |     doTest("let x = x; in if true || x then 1 else 2"); | ||||||
|  |     doTest("/etc/passwd"); | ||||||
|  |     doTest("import ./foo.nix"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -29,6 +29,9 @@ std::ostream & operator << (std::ostream & str, Value & v) | ||||||
|     case tString: |     case tString: | ||||||
|         str << "\"" << v.string.s << "\""; // !!! escaping
 |         str << "\"" << v.string.s << "\""; // !!! escaping
 | ||||||
|         break; |         break; | ||||||
|  |     case tPath: | ||||||
|  |         str << v.path; // !!! escaping?
 | ||||||
|  |         break; | ||||||
|     case tNull: |     case tNull: | ||||||
|         str << "true"; |         str << "true"; | ||||||
|         break; |         break; | ||||||
|  | @ -209,6 +212,20 @@ Env & EvalState::allocEnv() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | void EvalState::evalFile(const Path & path, Value & v) | ||||||
|  | { | ||||||
|  |     startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); | ||||||
|  |     Expr e = parseExprFromFile(*this, path); | ||||||
|  |     try { | ||||||
|  |         eval(e, v); | ||||||
|  |     } catch (Error & e) { | ||||||
|  |         e.addPrefix(format("while evaluating the file `%1%':\n") | ||||||
|  |             % path); | ||||||
|  |         throw; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| static char * deepestStack = (char *) -1; /* for measuring stack usage */ | static char * deepestStack = (char *) -1; /* for measuring stack usage */ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -241,7 +258,12 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|     ATerm s; ATermList context; |     ATerm s; ATermList context; | ||||||
|     if (matchStr(e, s, context)) { |     if (matchStr(e, s, context)) { | ||||||
|         assert(context == ATempty); |         assert(context == ATempty); | ||||||
|         mkString(v, ATgetName(ATgetAFun(s))); |         mkString(v, strdup(ATgetName(ATgetAFun(s)))); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (matchPath(e, s)) { | ||||||
|  |         mkPath(v, strdup(ATgetName(ATgetAFun(s)))); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -282,8 +304,14 @@ void EvalState::eval(Env & env, Expr e, Value & v) | ||||||
|         eval(env, e2, v); |         eval(env, e2, v); | ||||||
|         forceAttrs(v); // !!! eval followed by force is slightly inefficient
 |         forceAttrs(v); // !!! eval followed by force is slightly inefficient
 | ||||||
|         Bindings::iterator i = v.attrs->find(name); |         Bindings::iterator i = v.attrs->find(name); | ||||||
|         if (i == v.attrs->end()) throw TypeError("attribute not found"); |         if (i == v.attrs->end()) | ||||||
|         forceValue(i->second); |             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; |         v = i->second; | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  | @ -569,6 +597,80 @@ void EvalState::forceList(Value & v) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | string EvalState::coerceToString(Value & v, PathSet & context, | ||||||
|  |     bool coerceMore, bool copyToStore) | ||||||
|  | { | ||||||
|  |     forceValue(v); | ||||||
|  | 
 | ||||||
|  |     string s; | ||||||
|  | 
 | ||||||
|  |     if (v.type == tString) return v.string.s; | ||||||
|  | 
 | ||||||
|  |     if (v.type == tPath) { | ||||||
|  |         Path path(canonPath(v.path)); | ||||||
|  | 
 | ||||||
|  |         if (!copyToStore) return path; | ||||||
|  |          | ||||||
|  |         if (isDerivation(path)) | ||||||
|  |             throw EvalError(format("file names are not allowed to end in `%1%'") | ||||||
|  |                 % drvExtension); | ||||||
|  | 
 | ||||||
|  |         Path dstPath; | ||||||
|  |         if (srcToStore[path] != "") | ||||||
|  |             dstPath = srcToStore[path]; | ||||||
|  |         else { | ||||||
|  |             dstPath = readOnlyMode | ||||||
|  |                 ? computeStorePathForPath(path).first | ||||||
|  |                 : store->addToStore(path); | ||||||
|  |             srcToStore[path] = dstPath; | ||||||
|  |             printMsg(lvlChatty, format("copied source `%1%' -> `%2%'") | ||||||
|  |                 % path % dstPath); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         context.insert(dstPath); | ||||||
|  |         return dstPath; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (v.type == tAttrs) { | ||||||
|  |         Bindings::iterator i = v.attrs->find(toATerm("outPath")); | ||||||
|  |         if (i == v.attrs->end()) | ||||||
|  |             throwTypeError("cannot coerce an attribute set (except a derivation) to a string"); | ||||||
|  |         return coerceToString(i->second, context, coerceMore, copyToStore); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (coerceMore) { | ||||||
|  | 
 | ||||||
|  |         /* Note that `false' is represented as an empty string for
 | ||||||
|  |            shell scripting convenience, just like `null'. */ | ||||||
|  |         if (v.type == tBool && v.boolean) return "1"; | ||||||
|  |         if (v.type == tBool && !v.boolean) return ""; | ||||||
|  |         if (v.type == tInt) return int2String(v.integer); | ||||||
|  |         if (v.type == tNull) return ""; | ||||||
|  | 
 | ||||||
|  |         if (v.type == tList) { | ||||||
|  |             string result; | ||||||
|  |             for (unsigned int n = 0; n < v.list.length; ++n) { | ||||||
|  |                 if (n) result += " "; | ||||||
|  |                 result += coerceToString(v.list.elems[n], | ||||||
|  |                     context, coerceMore, copyToStore); | ||||||
|  |             } | ||||||
|  |             return result; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     throwTypeError("cannot coerce %1% to a string", showType(v)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Path EvalState::coerceToPath(Value & v, PathSet & context) | ||||||
|  | { | ||||||
|  |     string path = coerceToString(v, context, false, false); | ||||||
|  |     if (path == "" || path[0] != '/') | ||||||
|  |         throw EvalError(format("string `%1%' doesn't represent an absolute path") % path); | ||||||
|  |     return path; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| bool EvalState::eqValues(Value & v1, Value & v2) | bool EvalState::eqValues(Value & v1, Value & v2) | ||||||
| { | { | ||||||
|     forceValue(v1); |     forceValue(v1); | ||||||
|  | @ -1046,22 +1148,6 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| LocalNoInline(Expr evalSelect(EvalState & state, Expr e, ATerm name)) |  | ||||||
| { |  | ||||||
|     ATerm pos; |  | ||||||
|     string s = aterm2String(name); |  | ||||||
|     Expr a = queryAttr(evalExpr(state, e), s, pos); |  | ||||||
|     if (!a) throwEvalError("attribute `%1%' missing", s); |  | ||||||
|     try { |  | ||||||
|         return evalExpr(state, a); |  | ||||||
|     } catch (Error & e) { |  | ||||||
|         addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n", |  | ||||||
|             s, showPos(pos)); |  | ||||||
|         throw; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| LocalNoInline(Expr evalAssert(EvalState & state, Expr cond, Expr body, ATerm pos)) | LocalNoInline(Expr evalAssert(EvalState & state, Expr cond, Expr body, ATerm pos)) | ||||||
| { | { | ||||||
|     if (!evalBool(state, cond)) |     if (!evalBool(state, cond)) | ||||||
|  | @ -1352,20 +1438,6 @@ Expr evalExpr(EvalState & state, Expr e) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Expr evalFile(EvalState & state, const Path & path) |  | ||||||
| { |  | ||||||
|     startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); |  | ||||||
|     Expr e = parseExprFromFile(state, path); |  | ||||||
|     try { |  | ||||||
|         return evalExpr(state, e); |  | ||||||
|     } catch (Error & e) { |  | ||||||
|         e.addPrefix(format("while evaluating the file `%1%':\n") |  | ||||||
|             % path); |  | ||||||
|         throw; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static Expr strictEvalExpr(EvalState & state, Expr e, ATermMap & nfs); | static Expr strictEvalExpr(EvalState & state, Expr e, ATermMap & nfs); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -58,6 +58,7 @@ struct Value | ||||||
|             const char * s; |             const char * s; | ||||||
|             const char * * context; |             const char * * context; | ||||||
|         } string; |         } string; | ||||||
|  |         const char * path; | ||||||
|         Bindings * attrs; |         Bindings * attrs; | ||||||
|         struct { |         struct { | ||||||
|             unsigned int length; |             unsigned int length; | ||||||
|  | @ -107,6 +108,13 @@ static inline void mkString(Value & v, const char * s) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | static inline void mkPath(Value & v, const char * s) | ||||||
|  | { | ||||||
|  |     v.type = tPath; | ||||||
|  |     v.path = s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| typedef std::map<Path, PathSet> DrvRoots; | typedef std::map<Path, PathSet> DrvRoots; | ||||||
| typedef std::map<Path, Hash> DrvHashes; | typedef std::map<Path, Hash> DrvHashes; | ||||||
| 
 | 
 | ||||||
|  | @ -134,6 +142,10 @@ struct EvalState | ||||||
| 
 | 
 | ||||||
|     EvalState(); |     EvalState(); | ||||||
| 
 | 
 | ||||||
|  |     /* Evaluate an expression read from the given file to normal
 | ||||||
|  |        form. */ | ||||||
|  |     void evalFile(const Path & path, Value & v); | ||||||
|  | 
 | ||||||
|     /* 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); | ||||||
|  | @ -157,6 +169,18 @@ struct EvalState | ||||||
|     void forceAttrs(Value & v); |     void forceAttrs(Value & v); | ||||||
|     void forceList(Value & v); |     void forceList(Value & v); | ||||||
| 
 | 
 | ||||||
|  |     /* String coercion.  Converts strings, paths and derivations to a
 | ||||||
|  |        string.  If `coerceMore' is set, also converts nulls, integers, | ||||||
|  |        booleans and lists to a string.  If `copyToStore' is set, | ||||||
|  |        referenced paths are copied to the Nix store as a side effect.q */ | ||||||
|  |     string coerceToString(Value & v, PathSet & context, | ||||||
|  |         bool coerceMore = false, bool copyToStore = true); | ||||||
|  | 
 | ||||||
|  |     /* Path coercion.  Converts strings, paths and derivations to a
 | ||||||
|  |        path.  The result is guaranteed to be a canonicalised, absolute | ||||||
|  |        path.  Nothing is copied to the store. */ | ||||||
|  |     Path coerceToPath(Value & v, PathSet & context); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
| 
 | 
 | ||||||
|     /* The base environment, containing the builtin functions and
 |     /* The base environment, containing the builtin functions and
 | ||||||
|  | @ -182,9 +206,6 @@ private: | ||||||
| /* Evaluate an expression to normal form. */ | /* Evaluate an expression to normal form. */ | ||||||
| Expr evalExpr(EvalState & state, Expr e); | Expr evalExpr(EvalState & state, Expr e); | ||||||
| 
 | 
 | ||||||
| /* Evaluate an expression read from the given file to normal form. */ |  | ||||||
| Expr evalFile(EvalState & state, const Path & path); |  | ||||||
| 
 |  | ||||||
| /* Evaluate an expression, and recursively evaluate list elements and
 | /* Evaluate an expression, and recursively evaluate list elements and
 | ||||||
|    attributes.  If `canonicalise' is true, we remove things like |    attributes.  If `canonicalise' is true, we remove things like | ||||||
|    position information and make sure that attribute sets are in |    position information and make sure that attribute sets are in | ||||||
|  | @ -202,17 +223,6 @@ ATermList evalList(EvalState & state, Expr e); | ||||||
|    a list). */ |    a list). */ | ||||||
| ATermList flattenList(EvalState & state, Expr e); | ATermList flattenList(EvalState & state, Expr e); | ||||||
| 
 | 
 | ||||||
| /* String coercion.  Converts strings, paths and derivations to a
 |  | ||||||
|    string.  If `coerceMore' is set, also converts nulls, integers, |  | ||||||
|    booleans and lists to a string. */ |  | ||||||
| string coerceToString(EvalState & state, Expr e, PathSet & context, |  | ||||||
|     bool coerceMore = false, bool copyToStore = true); |  | ||||||
| 
 |  | ||||||
| /* Path coercion.  Converts strings, paths and derivations to a path.
 |  | ||||||
|    The result is guaranteed to be an canonicalised, absolute path. |  | ||||||
|    Nothing is copied to the store. */ |  | ||||||
| Path coerceToPath(EvalState & state, Expr e, PathSet & context); |  | ||||||
| 
 |  | ||||||
| /* Automatically call a function for which each argument has a default
 | /* Automatically call a function for which each argument has a default
 | ||||||
|    value or has a binding in the `args' map.  Note: result is a call, |    value or has a binding in the `args' map.  Note: result is a call, | ||||||
|    not a normal form; it should be evaluated by calling evalExpr(). */ |    not a normal form; it should be evaluated by calling evalExpr(). */ | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
|  | #include <cstring> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
|  | @ -69,20 +70,11 @@ static Expr prim_null(EvalState & state, const ATermVector & args) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Return a string constant representing the current platform.  Note!
 |  | ||||||
|    that differs between platforms, so Nix expressions using |  | ||||||
|    `__currentSystem' can evaluate to different values on different |  | ||||||
|    platforms. */ |  | ||||||
| static Expr prim_currentSystem(EvalState & state, const ATermVector & args) |  | ||||||
| { |  | ||||||
|     return makeStr(thisSystem); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static Expr prim_currentTime(EvalState & state, const ATermVector & args) | static Expr prim_currentTime(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|     return ATmake("Int(<int>)", time(0)); |     return ATmake("Int(<int>)", time(0)); | ||||||
| } | } | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /*************************************************************
 | /*************************************************************
 | ||||||
|  | @ -92,10 +84,10 @@ static Expr prim_currentTime(EvalState & state, const ATermVector & args) | ||||||
| 
 | 
 | ||||||
| /* Load and evaluate an expression from path specified by the
 | /* Load and evaluate an expression from path specified by the
 | ||||||
|    argument. */  |    argument. */  | ||||||
| static Expr prim_import(EvalState & state, const ATermVector & args) | static void prim_import(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     PathSet context; |     PathSet context; | ||||||
|     Path path = coerceToPath(state, args[0], context); |     Path path = state.coerceToPath(*args[0], context); | ||||||
| 
 | 
 | ||||||
|     for (PathSet::iterator i = context.begin(); i != context.end(); ++i) { |     for (PathSet::iterator i = context.begin(); i != context.end(); ++i) { | ||||||
|         assert(isStorePath(*i)); |         assert(isStorePath(*i)); | ||||||
|  | @ -106,10 +98,11 @@ static Expr prim_import(EvalState & state, const ATermVector & args) | ||||||
|             store->buildDerivations(singleton<PathSet>(*i)); |             store->buildDerivations(singleton<PathSet>(*i)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return evalFile(state, path); |     state.evalFile(path, v); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #if 0 | ||||||
| /* Determine whether the argument is the null value. */ | /* Determine whether the argument is the null value. */ | ||||||
| static Expr prim_isNull(EvalState & state, const ATermVector & args) | static Expr prim_isNull(EvalState & state, const ATermVector & args) | ||||||
| { | { | ||||||
|  | @ -1134,7 +1127,7 @@ void EvalState::createBaseEnv() | ||||||
|         v.type = tNull; |         v.type = tNull; | ||||||
|     } |     } | ||||||
|     {   Value & v = (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm("currentSystem")]; |     {   Value & v = (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm("currentSystem")]; | ||||||
|         mkString(v, thisSystem.c_str()); // !!! copy string
 |         mkString(v, strdup(thisSystem.c_str())); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #if 0    
 | #if 0    
 | ||||||
|  | @ -1143,7 +1136,9 @@ void EvalState::createBaseEnv() | ||||||
|     addPrimOp("__currentTime", 0, prim_currentTime); |     addPrimOp("__currentTime", 0, prim_currentTime); | ||||||
| 
 | 
 | ||||||
|     // Miscellaneous
 |     // Miscellaneous
 | ||||||
|  | #endif | ||||||
|     addPrimOp("import", 1, prim_import); |     addPrimOp("import", 1, prim_import); | ||||||
|  | #if 0 | ||||||
|     addPrimOp("isNull", 1, prim_isNull); |     addPrimOp("isNull", 1, prim_isNull); | ||||||
|     addPrimOp("__isFunction", 1, prim_isFunction); |     addPrimOp("__isFunction", 1, prim_isFunction); | ||||||
|     addPrimOp("__isString", 1, prim_isString); |     addPrimOp("__isString", 1, prim_isString); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue