* Refactoring: get the selection path stuff out of getDerivations()
and put it into a separate function findAlongAttrPath().
This commit is contained in:
		
							parent
							
								
									2317d8f671
								
							
						
					
					
						commit
						ca2238cf81
					
				
					 9 changed files with 170 additions and 119 deletions
				
			
		|  | @ -3,7 +3,8 @@ lib_LTLIBRARIES = libexpr.la | |||
| libexpr_la_SOURCES = nixexpr.cc nixexpr.hh parser.cc parser.hh \ | ||||
|  eval.cc eval.hh primops.cc \ | ||||
|  lexer-tab.c lexer-tab.h parser-tab.c parser-tab.h \ | ||||
|  get-drvs.cc get-drvs.hh | ||||
|  get-drvs.cc get-drvs.hh \ | ||||
|  attr-path.cc attr-path.hh | ||||
| 
 | ||||
| BUILT_SOURCES = nixexpr-ast.cc nixexpr-ast.hh \ | ||||
|  parser-tab.h lexer-tab.h parser-tab.c lexer-tab.c | ||||
|  |  | |||
							
								
								
									
										74
									
								
								src/libexpr/attr-path.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/libexpr/attr-path.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,74 @@ | |||
| #include "attr-path.hh" | ||||
| #include "nixexpr-ast.hh" | ||||
| 
 | ||||
| 
 | ||||
| bool isAttrs(EvalState & state, Expr e, ATermMap & attrs) | ||||
| { | ||||
|     e = evalExpr(state, e); | ||||
|     ATermList dummy; | ||||
|     if (!matchAttrs(e, dummy)) return false; | ||||
|     queryAllAttrs(e, attrs, false); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Expr findAlongAttrPath(EvalState & state, const string & attrPath, Expr e) | ||||
| { | ||||
|     Strings tokens = tokenizeString(attrPath, "."); | ||||
| 
 | ||||
|     Error attrError = | ||||
|         Error(format("attribute selection path `%1%' does not match expression") % attrPath); | ||||
| 
 | ||||
|     string curPath; | ||||
|      | ||||
|     for (Strings::iterator i = tokens.begin(); i != tokens.end(); ++i) { | ||||
| 
 | ||||
|         if (!curPath.empty()) curPath += "."; | ||||
|         curPath += *i; | ||||
| 
 | ||||
|         /* Is *i an index (integer) or a normal attribute name? */ | ||||
|         enum { apAttr, apIndex } apType = apAttr; | ||||
|         string attr = *i; | ||||
|         int attrIndex = -1; | ||||
|         if (string2Int(attr, attrIndex)) apType = apIndex; | ||||
| 
 | ||||
|         /* Evaluate the expression. */ | ||||
|         e = evalExpr(state, autoCallFunction(evalExpr(state, e))); | ||||
| 
 | ||||
|         /* It should evaluate to either an attribute set or an
 | ||||
|            expression, according to what is specified in the | ||||
|            attrPath. */ | ||||
| 
 | ||||
|         if (apType == apAttr) { | ||||
| 
 | ||||
|             ATermMap attrs(128); | ||||
| 
 | ||||
|             if (!isAttrs(state, e, attrs)) | ||||
|                 throw TypeError( | ||||
|                     format("the expression selected by the selection path `%1%' should be an attribute set but is %2%") | ||||
|                     % curPath % showType(e)); | ||||
|                  | ||||
|             e = attrs.get(toATerm(attr)); | ||||
|             if (!e) | ||||
|                 throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         else if (apType == apIndex) { | ||||
| 
 | ||||
|             ATermList es; | ||||
|             if (!matchList(e, es)) | ||||
|                 throw TypeError( | ||||
|                     format("the expression selected by the selection path `%1%' should be a list but is %2%") | ||||
|                     % curPath % showType(e)); | ||||
| 
 | ||||
|             e = ATelementAt(es, attrIndex); | ||||
|             if (!e) | ||||
|                 throw Error(format("list index %1% in selection path `%2%' not found") % attrIndex % curPath); | ||||
|              | ||||
|         } | ||||
|          | ||||
|     } | ||||
|      | ||||
|     return e; | ||||
| } | ||||
							
								
								
									
										13
									
								
								src/libexpr/attr-path.hh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/libexpr/attr-path.hh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| #ifndef __ATTR_PATH_H | ||||
| #define __ATTR_PATH_H | ||||
| 
 | ||||
| #include <string> | ||||
| #include <map> | ||||
| 
 | ||||
| #include "eval.hh" | ||||
| 
 | ||||
| 
 | ||||
| Expr findAlongAttrPath(EvalState & state, const string & attrPath, Expr e); | ||||
| 
 | ||||
| 
 | ||||
| #endif /* !__ATTR_PATH_H */ | ||||
|  | @ -287,6 +287,24 @@ static ATerm concatStrings(EvalState & state, const ATermVector & args) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| Expr autoCallFunction(Expr e) | ||||
| { | ||||
|     ATermList formals; | ||||
|     ATerm body, pos; | ||||
|     if (matchFunction(e, formals, body, pos)) { | ||||
|         for (ATermIterator i(formals); i; ++i) { | ||||
|             Expr name, def; ATerm values, def2; | ||||
|             if (!matchFormal(*i, name, values, def2)) abort(); | ||||
|             if (!matchDefaultValue(def2, def)) | ||||
|                 throw TypeError(format("cannot auto-call a function that has an argument without a default value (`%1%')") | ||||
|                     % aterm2String(name)); | ||||
|         } | ||||
|         e = makeCall(e, makeAttrs(ATermMap(0))); | ||||
|     } | ||||
|     return e; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Expr evalExpr2(EvalState & state, Expr e) | ||||
| { | ||||
|     Expr e1, e2, e3, e4; | ||||
|  | @ -380,7 +398,9 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|             } | ||||
|         } | ||||
|          | ||||
|         else throw TypeError("the left-hand side of the function call is neither a function nor a primop (built-in operation)"); | ||||
|         else throw TypeError( | ||||
|             format("the left-hand side of the function call is neither a function nor a primop (built-in operation) but %1%") | ||||
|             % showType(e1)); | ||||
|     } | ||||
| 
 | ||||
|     /* Attribute selection. */ | ||||
|  |  | |||
|  | @ -59,6 +59,11 @@ string coerceToStringWithContext(EvalState & state, | |||
|     ATermList & context, Expr e, bool & isPath); | ||||
| Expr wrapInContext(ATermList context, Expr e); | ||||
| 
 | ||||
| /* Automatically call a function for which each argument has a default
 | ||||
|    value.  Note: result is a call, not a normal form; it should be | ||||
|    evaluated by calling evalExpr(). */ | ||||
| Expr autoCallFunction(Expr e); | ||||
| 
 | ||||
| /* Print statistics. */ | ||||
| void printEvalStats(EvalState & state); | ||||
| 
 | ||||
|  |  | |||
|  | @ -58,7 +58,7 @@ typedef set<Expr> Exprs; | |||
|    it makes sense for the caller to recursively search for derivations | ||||
|    in `e'. */ | ||||
| static bool getDerivation(EvalState & state, Expr e, | ||||
|     DrvInfos & drvs, Exprs & doneExprs, string attributeName) | ||||
|     const string & attrPath, DrvInfos & drvs, Exprs & doneExprs) | ||||
| { | ||||
|     try { | ||||
|          | ||||
|  | @ -92,7 +92,7 @@ static bool getDerivation(EvalState & state, Expr e, | |||
| 
 | ||||
|         drv.attrs = attrs; | ||||
| 
 | ||||
|         drv.attrPath = attributeName; | ||||
|         drv.attrPath = attrPath; | ||||
| 
 | ||||
|         drvs.push_back(drv); | ||||
|         return false; | ||||
|  | @ -107,7 +107,7 @@ bool getDerivation(EvalState & state, Expr e, DrvInfo & drv) | |||
| { | ||||
|     Exprs doneExprs; | ||||
|     DrvInfos drvs; | ||||
|     getDerivation(state, e, drvs, doneExprs, ""); | ||||
|     getDerivation(state, e, "", drvs, doneExprs); | ||||
|     if (drvs.size() != 1) return false; | ||||
|     drv = drvs.front(); | ||||
|     return true; | ||||
|  | @ -121,118 +121,53 @@ static string addToPath(const string & s1, const string & s2) | |||
| 
 | ||||
| 
 | ||||
| static void getDerivations(EvalState & state, Expr e, | ||||
|     DrvInfos & drvs, Exprs & doneExprs, const string & attrPath, | ||||
|     const string & pathTaken) | ||||
|     const string & pathPrefix, DrvInfos & drvs, Exprs & doneExprs) | ||||
| { | ||||
|     /* Automatically call functions for which each argument has a
 | ||||
|        default value. */ | ||||
|     ATermList formals; | ||||
|     ATerm body, pos; | ||||
|     if (matchFunction(e, formals, body, pos)) { | ||||
|         for (ATermIterator i(formals); i; ++i) { | ||||
|             Expr name, def; ATerm values, def2; | ||||
|             if (!matchFormal(*i, name, values, def2)) abort(); | ||||
|             if (!matchDefaultValue(def2, def)) | ||||
|                 throw TypeError(format("cannot auto-call a function that has an argument without a default value (`%1%')") | ||||
|                     % aterm2String(name)); | ||||
|         } | ||||
|         getDerivations(state, | ||||
|             makeCall(e, makeAttrs(ATermMap(0))), | ||||
|             drvs, doneExprs, attrPath, pathTaken); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     /* Parse the start of attrPath. */ | ||||
|     enum { apNone, apAttr, apIndex } apType; | ||||
|     string attrPathRest; | ||||
|     string attr; | ||||
|     int attrIndex; | ||||
|     Error attrError = | ||||
|         Error(format("attribute selection path `%1%' does not match expression") % attrPath); | ||||
| 
 | ||||
|     if (attrPath.empty()) | ||||
|         apType = apNone; | ||||
|     else { | ||||
|         string::size_type dot = attrPath.find("."); | ||||
|         if (dot == string::npos) { | ||||
|             attrPathRest = ""; | ||||
|             attr = attrPath; | ||||
|         } else { | ||||
|             attrPathRest = string(attrPath, dot + 1); | ||||
|             attr = string(attrPath, 0, dot); | ||||
|         } | ||||
|         apType = apAttr; | ||||
|         if (string2Int(attr, attrIndex)) apType = apIndex; | ||||
|     } | ||||
|     e = evalExpr(state, autoCallFunction(evalExpr(state, e))); | ||||
| 
 | ||||
|     /* Process the expression. */ | ||||
|     ATermList es; | ||||
|     DrvInfo drv; | ||||
| 
 | ||||
|     if (!getDerivation(state, e, drvs, doneExprs, pathTaken)) { | ||||
|         if (apType != apNone) throw attrError; | ||||
|     if (!getDerivation(state, e, pathPrefix, drvs, doneExprs)) | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     e = evalExpr(state, e); | ||||
| 
 | ||||
|     if (matchAttrs(e, es)) { | ||||
|         if (apType != apNone && apType != apAttr) throw attrError; | ||||
|         ATermMap drvMap(ATgetLength(es)); | ||||
|         queryAllAttrs(e, drvMap); | ||||
|         if (apType == apNone) { | ||||
|             for (ATermMap::const_iterator i = drvMap.begin(); i != drvMap.end(); ++i) { | ||||
|                 startNest(nest, lvlDebug, | ||||
|                     format("evaluating attribute `%1%'") % aterm2String(i->key)); | ||||
|                 string pathTaken2 = addToPath(pathTaken, aterm2String(i->key)); | ||||
|                 if (getDerivation(state, i->value, drvs, doneExprs, pathTaken2)) { | ||||
|                     /* If the value of this attribute is itself an
 | ||||
|                        attribute set, should we recurse into it? | ||||
|                        => Only if it has a `recurseForDerivations = true' | ||||
|                        attribute. */ | ||||
|                     ATermList es; | ||||
|                     Expr e = evalExpr(state, i->value); | ||||
|                     if (matchAttrs(e, es)) { | ||||
|                         ATermMap attrs(ATgetLength(es)); | ||||
|                         queryAllAttrs(e, attrs, false); | ||||
|                         Expr e2 = attrs.get(toATerm("recurseForDerivations")); | ||||
|                         if (e2 && evalBool(state, e2)) | ||||
|                             getDerivations(state, e, drvs, doneExprs, attrPathRest, pathTaken2); | ||||
|                     } | ||||
|          | ||||
|         for (ATermMap::const_iterator i = drvMap.begin(); i != drvMap.end(); ++i) { | ||||
|             startNest(nest, lvlDebug, | ||||
|                 format("evaluating attribute `%1%'") % aterm2String(i->key)); | ||||
|             string pathPrefix2 = addToPath(pathPrefix, aterm2String(i->key)); | ||||
|             if (getDerivation(state, i->value, pathPrefix2, drvs, doneExprs)) { | ||||
|                 /* If the value of this attribute is itself an
 | ||||
|                    attribute set, should we recurse into it?  => Only | ||||
|                    if it has a `recurseForDerivations = true' | ||||
|                    attribute. */ | ||||
|                 ATermList es; | ||||
|                 Expr e = evalExpr(state, i->value); | ||||
|                 if (matchAttrs(e, es)) { | ||||
|                     ATermMap attrs(ATgetLength(es)); | ||||
|                     queryAllAttrs(e, attrs, false); | ||||
|                     Expr e2 = attrs.get(toATerm("recurseForDerivations")); | ||||
|                     if (e2 && evalBool(state, e2)) | ||||
|                         getDerivations(state, e, pathPrefix2, drvs, doneExprs); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             Expr e2 = drvMap.get(toATerm(attr)); | ||||
|             if (!e2) throw Error(format("attribute `%1%' in selection path not found") % attr); | ||||
|             startNest(nest, lvlDebug, | ||||
|                 format("evaluating attribute `%1%'") % attr); | ||||
|             string pathTaken2 = addToPath(pathTaken, attr); | ||||
|             getDerivation(state, e2, drvs, doneExprs, pathTaken2); | ||||
|             if (!attrPath.empty()) | ||||
|                 getDerivations(state, e2, drvs, doneExprs, attrPathRest, pathTaken2); | ||||
|         } | ||||
|          | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (matchList(e, es)) { | ||||
|         if (apType != apNone && apType != apIndex) throw attrError; | ||||
|         if (apType == apNone) { | ||||
|             int n = 0; | ||||
|             for (ATermIterator i(es); i; ++i, ++n) { | ||||
|                 startNest(nest, lvlDebug, | ||||
|                     format("evaluating list element")); | ||||
|                 string pathTaken2 = addToPath(pathTaken, (format("%1%") % n).str()); | ||||
|                 if (getDerivation(state, *i, drvs, doneExprs, pathTaken2)) | ||||
|                     getDerivations(state, *i, drvs, doneExprs, attrPathRest, pathTaken2); | ||||
|             } | ||||
|         } else { | ||||
|             Expr e2 = ATelementAt(es, attrIndex); | ||||
|             if (!e2) throw Error(format("list index %1% in selection path not found") % attrIndex); | ||||
|         int n = 0; | ||||
|         for (ATermIterator i(es); i; ++i, ++n) { | ||||
|             startNest(nest, lvlDebug, | ||||
|                 format("evaluating list element")); | ||||
|             string pathTaken2 = addToPath(pathTaken, (format("%1%") % attrIndex).str()); | ||||
|             if (getDerivation(state, e2, drvs, doneExprs, pathTaken2)) | ||||
|                 getDerivations(state, e2, drvs, doneExprs, attrPathRest, pathTaken2); | ||||
|             string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str()); | ||||
|             if (getDerivation(state, *i, pathPrefix2, drvs, doneExprs)) | ||||
|                 getDerivations(state, *i, pathPrefix2, drvs, doneExprs); | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
|  | @ -241,9 +176,9 @@ static void getDerivations(EvalState & state, Expr e, | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| void getDerivations(EvalState & state, Expr e, DrvInfos & drvs, | ||||
|     const string & attrPath) | ||||
| void getDerivations(EvalState & state, Expr e, const string & pathPrefix, | ||||
|     DrvInfos & drvs) | ||||
| { | ||||
|     Exprs doneExprs; | ||||
|     getDerivations(state, e, drvs, doneExprs, attrPath, ""); | ||||
|     getDerivations(state, e, pathPrefix, drvs, doneExprs); | ||||
| } | ||||
|  |  | |||
|  | @ -49,8 +49,8 @@ typedef list<DrvInfo> DrvInfos; | |||
|    Otherwise, return false. */ | ||||
| bool getDerivation(EvalState & state, Expr e, DrvInfo & drv); | ||||
| 
 | ||||
| void getDerivations(EvalState & state, Expr e, DrvInfos & drvs, | ||||
|     const string & attrPath = ""); | ||||
| void getDerivations(EvalState & state, Expr e, const string & pathPrefix, | ||||
|     DrvInfos & drvs); | ||||
| 
 | ||||
| 
 | ||||
| #endif /* !__GET_DRVS_H */ | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| #include "help.txt.hh" | ||||
| #include "nixexpr-ast.hh" | ||||
| #include "get-drvs.hh" | ||||
| #include "attr-path.hh" | ||||
| #include "pathlocks.hh" | ||||
| 
 | ||||
| #include <cerrno> | ||||
|  | @ -36,7 +37,6 @@ struct InstallSourceInfo | |||
|     Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */ | ||||
|     Path profile; /* for srcProfile */ | ||||
|     string systemFilter; /* for srcNixExprDrvs */ | ||||
|     string attrPath; /* srcAttrPath */ | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  | @ -65,7 +65,7 @@ static void loadDerivations(EvalState & state, Path nixExprPath, | |||
|     string systemFilter, DrvInfos & elems) | ||||
| { | ||||
|     getDerivations(state, | ||||
|         parseExprFromFile(state, absPath(nixExprPath)), elems); | ||||
|         parseExprFromFile(state, absPath(nixExprPath)), "", elems); | ||||
| 
 | ||||
|     /* Filter out all derivations not applicable to the current
 | ||||
|        system. */ | ||||
|  | @ -119,7 +119,7 @@ static DrvInfos queryInstalled(EvalState & state, const Path & userEnv) | |||
|     e = bottomupRewrite(addPos, e); | ||||
| 
 | ||||
|     DrvInfos elems; | ||||
|     getDerivations(state, e, elems); | ||||
|     getDerivations(state, e, "", elems); | ||||
|     return elems; | ||||
| } | ||||
| 
 | ||||
|  | @ -334,7 +334,7 @@ static void queryInstSources(EvalState & state, | |||
|             { | ||||
|                 Expr e2 = parseExprFromString(state, *i, absPath(".")); | ||||
|                 Expr call = makeCall(e2, e1); | ||||
|                 getDerivations(state, call, elems); | ||||
|                 getDerivations(state, call, "", elems); | ||||
|             } | ||||
|              | ||||
|             break; | ||||
|  | @ -388,7 +388,9 @@ static void queryInstSources(EvalState & state, | |||
|             for (Strings::const_iterator i = args.begin(); | ||||
|                  i != args.end(); ++i) | ||||
|                 getDerivations(state, | ||||
|                     parseExprFromFile(state, instSource.nixExprPath), elems, *i); | ||||
|                     findAlongAttrPath(state, *i,  | ||||
|                         parseExprFromFile(state, instSource.nixExprPath)), | ||||
|                     "", elems); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include "parser.hh" | ||||
| #include "nixexpr-ast.hh" | ||||
| #include "get-drvs.hh" | ||||
| #include "attr-path.hh" | ||||
| #include "help.txt.hh" | ||||
| 
 | ||||
| 
 | ||||
|  | @ -18,13 +19,12 @@ void printHelp() | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| static Expr evalStdin(EvalState & state, bool parseOnly) | ||||
| static Expr parseStdin(EvalState & state) | ||||
| { | ||||
|     startNest(nest, lvlTalkative, format("evaluating standard input")); | ||||
|     startNest(nest, lvlTalkative, format("parsing standard input")); | ||||
|     string s, s2; | ||||
|     while (getline(cin, s2)) s += s2 + "\n"; | ||||
|     Expr e = parseExprFromString(state, s, absPath(".")); | ||||
|     return parseOnly ? e : evalExpr(state, e); | ||||
|     return parseExprFromString(state, s, absPath(".")); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -34,7 +34,7 @@ static bool indirectRoot = false; | |||
| 
 | ||||
| 
 | ||||
| static void printResult(EvalState & state, Expr e, | ||||
|     bool evalOnly, bool printArgs, const string & attrPath) | ||||
|     bool evalOnly, bool printArgs) | ||||
| { | ||||
|     if (evalOnly) | ||||
|         cout << format("%1%\n") % e; | ||||
|  | @ -54,7 +54,7 @@ static void printResult(EvalState & state, Expr e, | |||
|      | ||||
|     else { | ||||
|         DrvInfos drvs; | ||||
|         getDerivations(state, e, drvs, attrPath); | ||||
|         getDerivations(state, e, "", drvs); | ||||
|         for (DrvInfos::iterator i = drvs.begin(); i != drvs.end(); ++i) { | ||||
|             Path drvPath = i->queryDrvPath(state); | ||||
|             if (gcRoot == "") | ||||
|  | @ -119,18 +119,19 @@ void run(Strings args) | |||
|     openDB(); | ||||
| 
 | ||||
|     if (readStdin) { | ||||
|         Expr e = evalStdin(state, parseOnly); | ||||
|         printResult(state, e, evalOnly, printArgs, attrPath); | ||||
|         Expr e = findAlongAttrPath(state, attrPath, parseStdin(state)); | ||||
|         if (!parseOnly) e = evalExpr(state, e); | ||||
|         printResult(state, e, evalOnly, printArgs); | ||||
|     } | ||||
| 
 | ||||
|     for (Strings::iterator i = files.begin(); | ||||
|          i != files.end(); i++) | ||||
|     { | ||||
|         Path path = absPath(*i); | ||||
|         Expr e = parseOnly | ||||
|             ? parseExprFromFile(state, path) | ||||
|             : evalFile(state, path); | ||||
|         printResult(state, e, evalOnly, printArgs, attrPath); | ||||
|         Expr e = findAlongAttrPath(state, attrPath, | ||||
|             parseExprFromFile(state, path)); | ||||
|         if (!parseOnly) e = evalExpr(state, e); | ||||
|         printResult(state, e, evalOnly, printArgs); | ||||
|     } | ||||
| 
 | ||||
|     printEvalStats(state); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue