* 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) | ||||
| { | ||||
|     EvalState state; | ||||
|     Expr e = parseExprFromString(state, s, "/"); | ||||
|     Expr e = parseExprFromString(state, s, absPath(".")); | ||||
|     printMsg(lvlError, format(">>>>> %1%") % e); | ||||
|     Value v; | ||||
|     state.strictEval(e, v); | ||||
|  | @ -66,6 +66,8 @@ void run(Strings args) | |||
|     doTest("if false 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("/etc/passwd"); | ||||
|     doTest("import ./foo.nix"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,6 +29,9 @@ std::ostream & operator << (std::ostream & str, Value & v) | |||
|     case tString: | ||||
|         str << "\"" << v.string.s << "\""; // !!! escaping
 | ||||
|         break; | ||||
|     case tPath: | ||||
|         str << v.path; // !!! escaping?
 | ||||
|         break; | ||||
|     case tNull: | ||||
|         str << "true"; | ||||
|         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 */ | ||||
| 
 | ||||
| 
 | ||||
|  | @ -241,7 +258,12 @@ void EvalState::eval(Env & env, Expr e, Value & v) | |||
|     ATerm s; ATermList context; | ||||
|     if (matchStr(e, s, context)) { | ||||
|         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; | ||||
|     } | ||||
| 
 | ||||
|  | @ -282,8 +304,14 @@ void EvalState::eval(Env & env, Expr e, Value & v) | |||
|         eval(env, e2, v); | ||||
|         forceAttrs(v); // !!! eval followed by force is slightly inefficient
 | ||||
|         Bindings::iterator i = v.attrs->find(name); | ||||
|         if (i == v.attrs->end()) throw TypeError("attribute not found"); | ||||
|         forceValue(i->second); | ||||
|         if (i == v.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; | ||||
|         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) | ||||
| { | ||||
|     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)) | ||||
| { | ||||
|     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); | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -58,6 +58,7 @@ struct Value | |||
|             const char * s; | ||||
|             const char * * context; | ||||
|         } string; | ||||
|         const char * path; | ||||
|         Bindings * attrs; | ||||
|         struct { | ||||
|             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, Hash> DrvHashes; | ||||
| 
 | ||||
|  | @ -134,6 +142,10 @@ struct 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
 | ||||
|        value `v'. */ | ||||
|     void eval(Expr e, Value & v); | ||||
|  | @ -157,6 +169,18 @@ struct EvalState | |||
|     void forceAttrs(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: | ||||
| 
 | ||||
|     /* The base environment, containing the builtin functions and
 | ||||
|  | @ -182,9 +206,6 @@ private: | |||
| /* Evaluate an expression to normal form. */ | ||||
| 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
 | ||||
|    attributes.  If `canonicalise' is true, we remove things like | ||||
|    position information and make sure that attribute sets are in | ||||
|  | @ -202,17 +223,6 @@ ATermList evalList(EvalState & state, Expr e); | |||
|    a list). */ | ||||
| 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
 | ||||
|    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(). */ | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| #include <unistd.h> | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <cstring> | ||||
| 
 | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|     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
 | ||||
|    argument. */  | ||||
| static Expr prim_import(EvalState & state, const ATermVector & args) | ||||
| static void prim_import(EvalState & state, Value * * args, Value & v) | ||||
| { | ||||
|     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) { | ||||
|         assert(isStorePath(*i)); | ||||
|  | @ -106,10 +98,11 @@ static Expr prim_import(EvalState & state, const ATermVector & args) | |||
|             store->buildDerivations(singleton<PathSet>(*i)); | ||||
|     } | ||||
| 
 | ||||
|     return evalFile(state, path); | ||||
|     state.evalFile(path, v); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #if 0 | ||||
| /* Determine whether the argument is the null value. */ | ||||
| static Expr prim_isNull(EvalState & state, const ATermVector & args) | ||||
| { | ||||
|  | @ -1134,7 +1127,7 @@ void EvalState::createBaseEnv() | |||
|         v.type = tNull; | ||||
|     } | ||||
|     {   Value & v = (*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm("currentSystem")]; | ||||
|         mkString(v, thisSystem.c_str()); // !!! copy string
 | ||||
|         mkString(v, strdup(thisSystem.c_str())); | ||||
|     } | ||||
| 
 | ||||
| #if 0    
 | ||||
|  | @ -1143,7 +1136,9 @@ void EvalState::createBaseEnv() | |||
|     addPrimOp("__currentTime", 0, prim_currentTime); | ||||
| 
 | ||||
|     // Miscellaneous
 | ||||
| #endif | ||||
|     addPrimOp("import", 1, prim_import); | ||||
| #if 0 | ||||
|     addPrimOp("isNull", 1, prim_isNull); | ||||
|     addPrimOp("__isFunction", 1, prim_isFunction); | ||||
|     addPrimOp("__isString", 1, prim_isString); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue