* Keep attribute sets in sorted order to speed up attribute lookups.
* Simplify the representation of attributes in the AST. * Change the behaviour of listToAttrs() in case of duplicate names.
This commit is contained in:
		
							parent
							
								
									2dc6d50941
								
							
						
					
					
						commit
						e0b7fb8f27
					
				
					 12 changed files with 186 additions and 148 deletions
				
			
		|  | @ -20,14 +20,17 @@ bool parseOptionArg(const string & arg, Strings::iterator & i, | ||||||
|     if (i == argsEnd) throw error; |     if (i == argsEnd) throw error; | ||||||
|     string value = *i++; |     string value = *i++; | ||||||
| 
 | 
 | ||||||
|  |     /* !!! check for duplicates! */ | ||||||
|     Value * v = state.allocValue(); |     Value * v = state.allocValue(); | ||||||
|     autoArgs[state.symbols.create(name)].value = v; |     autoArgs.push_back(Attr(state.symbols.create(name), v)); | ||||||
| 
 | 
 | ||||||
|     if (arg == "--arg") |     if (arg == "--arg") | ||||||
|         state.mkThunk_(*v, parseExprFromString(state, value, absPath("."))); |         state.mkThunk_(*v, parseExprFromString(state, value, absPath("."))); | ||||||
|     else |     else | ||||||
|         mkString(*v, value); |         mkString(*v, value); | ||||||
| 
 | 
 | ||||||
|  |     autoArgs.sort(); // !!! inefficient
 | ||||||
|  | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -34,18 +34,16 @@ namespace nix { | ||||||
| 
 | 
 | ||||||
| Bindings::iterator Bindings::find(const Symbol & name) | Bindings::iterator Bindings::find(const Symbol & name) | ||||||
| { | { | ||||||
|     iterator i = begin(); |     Attr key(name, 0); | ||||||
|     for ( ; i != end() && i->name != name; ++i) ; |     iterator i = lower_bound(begin(), end(), key); | ||||||
|     return i; |     if (i != end() && i->name == name) return i; | ||||||
|  |     return end(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Attr & Bindings::operator [] (const Symbol & name) | void Bindings::sort() | ||||||
| { | { | ||||||
|     iterator i = find(name); |     std::sort(begin(), end()); | ||||||
|     if (i != end()) return *i; |  | ||||||
|     push_back(Attr(name, 0)); |  | ||||||
|     return back(); |  | ||||||
| } | } | ||||||
|      |      | ||||||
| 
 | 
 | ||||||
|  | @ -178,12 +176,12 @@ void EvalState::addPrimOp(const string & name, | ||||||
| { | { | ||||||
|     Value * v = allocValue(); |     Value * v = allocValue(); | ||||||
|     string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; |     string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; | ||||||
|     Symbol sym = symbols.create(name); |     Symbol sym = symbols.create(name2); | ||||||
|     v->type = tPrimOp; |     v->type = tPrimOp; | ||||||
|     v->primOp = NEW PrimOp(primOp, arity, sym); |     v->primOp = NEW PrimOp(primOp, arity, sym); | ||||||
|     staticBaseEnv.vars[sym] = baseEnvDispl; |     staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl; | ||||||
|     baseEnv.values[baseEnvDispl++] = v; |     baseEnv.values[baseEnvDispl++] = v; | ||||||
|     baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v)); |     baseEnv.values[0]->attrs->push_back(Attr(sym, v)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -506,30 +504,36 @@ void ExprPath::eval(EvalState & state, Env & env, Value & v) | ||||||
| 
 | 
 | ||||||
| void ExprAttrs::eval(EvalState & state, Env & env, Value & v) | void ExprAttrs::eval(EvalState & state, Env & env, Value & v) | ||||||
| { | { | ||||||
|     state.mkAttrs(v); |     state.mkAttrs(v); // !!! reserve size
 | ||||||
| 
 | 
 | ||||||
|     if (recursive) { |     if (recursive) { | ||||||
|         /* Create a new environment that contains the attributes in
 |         /* Create a new environment that contains the attributes in
 | ||||||
|            this `rec'. */ |            this `rec'. */ | ||||||
|         Env & env2(state.allocEnv(attrs.size() + inherited.size())); |         Env & env2(state.allocEnv(attrs.size())); | ||||||
|         env2.up = &env; |         env2.up = &env; | ||||||
| 
 | 
 | ||||||
|         unsigned int displ = 0; |         AttrDefs::iterator overrides = attrs.find(state.sOverrides); | ||||||
|  |         bool hasOverrides = overrides != attrs.end(); | ||||||
| 
 | 
 | ||||||
|         /* The recursive attributes are evaluated in the new
 |         /* The recursive attributes are evaluated in the new
 | ||||||
|            environment. */ |            environment, while the inherited attributes are evaluated | ||||||
|         foreach (Attrs::iterator, i, attrs) { |            in the original environment. */ | ||||||
|             Value * vAttr = state.maybeThunk(env2, i->second.first); |         unsigned int displ = 0; | ||||||
|  |         foreach (AttrDefs::iterator, i, attrs) | ||||||
|  |             if (i->second.inherited) { | ||||||
|  |                 /* !!! handle overrides? */ | ||||||
|  |                 Value * vAttr = state.lookupVar(&env, i->second.var); | ||||||
|                 env2.values[displ++] = vAttr; |                 env2.values[displ++] = vAttr; | ||||||
|             v.attrs->push_back(nix::Attr(i->first, vAttr, &i->second.second)); |                 v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos)); | ||||||
|         } |             } else { | ||||||
| 
 |                 Value * vAttr; | ||||||
|         /* The inherited attributes, on the other hand, are
 |                 if (hasOverrides) { | ||||||
|            evaluated in the original environment. */ |                     vAttr = state.allocValue(); | ||||||
|         foreach (list<Inherited>::iterator, i, inherited) { |                     mkThunk(*vAttr, env2, i->second.e); | ||||||
|             Value * vAttr = state.lookupVar(&env, i->first); |                 } else | ||||||
|  |                     vAttr = state.maybeThunk(env2, i->second.e); | ||||||
|                 env2.values[displ++] = vAttr; |                 env2.values[displ++] = vAttr; | ||||||
|             v.attrs->push_back(nix::Attr(i->first.name, vAttr, &i->second)); |                 v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos)); | ||||||
|             } |             } | ||||||
|          |          | ||||||
|         /* If the rec contains an attribute called `__overrides', then
 |         /* If the rec contains an attribute called `__overrides', then
 | ||||||
|  | @ -540,30 +544,27 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) | ||||||
|            still reference the original value, because that value has |            still reference the original value, because that value has | ||||||
|            been substituted into the bodies of the other attributes. |            been substituted into the bodies of the other attributes. | ||||||
|            Hence we need __overrides.) */ |            Hence we need __overrides.) */ | ||||||
|         Bindings::iterator overrides = v.attrs->find(state.sOverrides); |         if (hasOverrides) { | ||||||
|         if (overrides != v.attrs->end()) { |             Value * vOverrides = (*v.attrs)[overrides->second.displ].value; | ||||||
|             state.forceAttrs(*overrides->value); |             state.forceAttrs(*vOverrides); | ||||||
|             foreach (Bindings::iterator, i, *overrides->value->attrs) { |             foreach (Bindings::iterator, i, *vOverrides->attrs) { | ||||||
|                 nix::Attr & a = (*v.attrs)[i->name]; |                 AttrDefs::iterator j = attrs.find(i->name); | ||||||
|                 if (a.value) |                 if (j != attrs.end()) { | ||||||
|                     env2.values[displs[i->name]] = i->value; |                     (*v.attrs)[j->second.displ] = *i; | ||||||
|                 a = *i; |                     env2.values[j->second.displ] = i->value; | ||||||
|  |                 } else | ||||||
|  |                     v.attrs->push_back(*i); | ||||||
|             } |             } | ||||||
|  |             v.attrs->sort(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     else { |     else { | ||||||
|         foreach (Attrs::iterator, i, attrs) { |         foreach (AttrDefs::iterator, i, attrs) | ||||||
|             nix::Attr & a = (*v.attrs)[i->first]; |             if (i->second.inherited) | ||||||
|             a.value = state.maybeThunk(env, i->second.first); |                 v.attrs->push_back(Attr(i->first, state.lookupVar(&env, i->second.var), &i->second.pos)); | ||||||
|             a.pos = &i->second.second; |             else | ||||||
|         } |                 v.attrs->push_back(Attr(i->first, state.maybeThunk(env, i->second.e), &i->second.pos)); | ||||||
| 
 |  | ||||||
|         foreach (list<Inherited>::iterator, i, inherited) { |  | ||||||
|             nix::Attr & a = (*v.attrs)[i->first.name]; |  | ||||||
|             a.value = state.lookupVar(&env, i->first); |  | ||||||
|             a.pos = &i->second; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -572,20 +573,18 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v) | ||||||
| { | { | ||||||
|     /* Create a new environment that contains the attributes in this
 |     /* Create a new environment that contains the attributes in this
 | ||||||
|        `let'. */ |        `let'. */ | ||||||
|     Env & env2(state.allocEnv(attrs->attrs.size() + attrs->inherited.size())); |     Env & env2(state.allocEnv(attrs->attrs.size())); | ||||||
|     env2.up = &env; |     env2.up = &env; | ||||||
| 
 | 
 | ||||||
|     unsigned int displ = 0; |     /* The recursive attributes are evaluated in the new environment,
 | ||||||
| 
 |        while the inherited attributes are evaluated in the original | ||||||
|     /* The recursive attributes are evaluated in the new
 |  | ||||||
|        environment. */ |        environment. */ | ||||||
|     foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs) |     unsigned int displ = 0; | ||||||
|         env2.values[displ++] = state.maybeThunk(env2, i->second.first); |     foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs) | ||||||
| 
 |         if (i->second.inherited) | ||||||
|     /* The inherited attributes, on the other hand, are evaluated in
 |             env2.values[displ++] = state.lookupVar(&env, i->second.var); | ||||||
|        the original environment. */ |         else | ||||||
|     foreach (list<ExprAttrs::Inherited>::iterator, i, attrs->inherited) |             env2.values[displ++] = state.maybeThunk(env2, i->second.e); | ||||||
|         env2.values[displ++] = state.lookupVar(&env, i->first); |  | ||||||
| 
 | 
 | ||||||
|     state.eval(env2, body, v); |     state.eval(env2, body, v); | ||||||
| } | } | ||||||
|  | @ -764,11 +763,13 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) | ||||||
|     foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) { |     foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) { | ||||||
|         Bindings::iterator j = args.find(i->name); |         Bindings::iterator j = args.find(i->name); | ||||||
|         if (j != args.end()) |         if (j != args.end()) | ||||||
|             (*actualArgs.attrs)[i->name] = *j; |             actualArgs.attrs->push_back(*j); | ||||||
|         else if (!i->def) |         else if (!i->def) | ||||||
|             throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", i->name); |             throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", i->name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     actualArgs.attrs->sort(); | ||||||
|  | 
 | ||||||
|     callFunction(fun, actualArgs, res); |     callFunction(fun, actualArgs, res); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -851,11 +852,27 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) | ||||||
|     if (v1.attrs->size() == 0) { v = v2; return; } |     if (v1.attrs->size() == 0) { v = v2; return; } | ||||||
|     if (v2.attrs->size() == 0) { v = v1; return; } |     if (v2.attrs->size() == 0) { v = v1; return; } | ||||||
| 
 | 
 | ||||||
|     state.cloneAttrs(v1, v); |     state.mkAttrs(v); | ||||||
| 
 | 
 | ||||||
|     /* !!! fix */ |     /* Merge the attribute sets, preferring values from the second
 | ||||||
|     foreach (Bindings::iterator, i, *v2.attrs) |        set.  Make sure to keep the resulting vector in sorted | ||||||
|         (*v.attrs)[i->name] = *i; |        order. */ | ||||||
|  |     Bindings::iterator i = v1.attrs->begin(); | ||||||
|  |     Bindings::iterator j = v2.attrs->begin(); | ||||||
|  | 
 | ||||||
|  |     while (i != v1.attrs->end() && j != v2.attrs->end()) { | ||||||
|  |         if (i->name == j->name) { | ||||||
|  |             v.attrs->push_back(*j); | ||||||
|  |             ++i; ++j; | ||||||
|  |         } | ||||||
|  |         else if (i->name < j->name) | ||||||
|  |             v.attrs->push_back(*i++); | ||||||
|  |         else | ||||||
|  |             v.attrs->push_back(*j++); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     while (i != v1.attrs->end()) v.attrs->push_back(*i++); | ||||||
|  |     while (j != v2.attrs->end()) v.attrs->push_back(*j++); | ||||||
|      |      | ||||||
|     state.nrOpUpdateValuesCopied += v.attrs->size(); |     state.nrOpUpdateValuesCopied += v.attrs->size(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -34,7 +34,7 @@ class Bindings : public BindingsBase | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     iterator find(const Symbol & name); |     iterator find(const Symbol & name); | ||||||
|     Attr & operator [] (const Symbol & name); |     void sort(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -142,6 +142,10 @@ struct Attr | ||||||
|     Attr(Symbol name, Value * value, Pos * pos = &noPos) |     Attr(Symbol name, Value * value, Pos * pos = &noPos) | ||||||
|         : name(name), value(value), pos(pos) { }; |         : name(name), value(value), pos(pos) { }; | ||||||
|     Attr() : pos(&noPos) { }; |     Attr() : pos(&noPos) { }; | ||||||
|  |     bool operator < (const Attr & a) const | ||||||
|  |     { | ||||||
|  |         return name < a.name; | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -168,7 +168,7 @@ static void getDerivations(EvalState & state, Value & vIn, | ||||||
|         foreach (SortedSymbols::iterator, i, attrs) { |         foreach (SortedSymbols::iterator, i, attrs) { | ||||||
|             startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % i->first); |             startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % i->first); | ||||||
|             string pathPrefix2 = addToPath(pathPrefix, i->first); |             string pathPrefix2 = addToPath(pathPrefix, i->first); | ||||||
|             Value & v2(*(*v.attrs)[i->second].value); |             Value & v2(*v.attrs->find(i->second)->value); | ||||||
|             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)) { | ||||||
|  |  | ||||||
|  | @ -55,10 +55,11 @@ void ExprAttrs::show(std::ostream & str) | ||||||
| { | { | ||||||
|     if (recursive) str << "rec "; |     if (recursive) str << "rec "; | ||||||
|     str << "{ "; |     str << "{ "; | ||||||
|     foreach (list<Inherited>::iterator, i, inherited) |     foreach (AttrDefs::iterator, i, attrs) | ||||||
|         str << "inherit " << i->first.name << "; "; |         if (i->second.inherited) | ||||||
|     foreach (Attrs::iterator, i, attrs) |             str << "inherit " << i->first << " " << "; "; | ||||||
|         str << i->first << " = " << *i->second.first << "; "; |         else | ||||||
|  |             str << i->first << " = " << *i->second.e << "; "; | ||||||
|     str << "}"; |     str << "}"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -91,10 +92,11 @@ void ExprLambda::show(std::ostream & str) | ||||||
| void ExprLet::show(std::ostream & str) | void ExprLet::show(std::ostream & str) | ||||||
| { | { | ||||||
|     str << "let "; |     str << "let "; | ||||||
|     foreach (list<ExprAttrs::Inherited>::iterator, i, attrs->inherited) |     foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs) | ||||||
|         str << "inherit " << i->first.name << "; "; |         if (i->second.inherited) | ||||||
|     foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs) |             str << "inherit " << i->first << "; "; | ||||||
|         str << i->first << " = " << *i->second.first << "; "; |         else | ||||||
|  |             str << i->first << " = " << *i->second.e << "; "; | ||||||
|     str << "in " << *body; |     str << "in " << *body; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -211,26 +213,18 @@ void ExprAttrs::bindVars(const StaticEnv & env) | ||||||
|         StaticEnv newEnv(false, &env); |         StaticEnv newEnv(false, &env); | ||||||
|      |      | ||||||
|         unsigned int displ = 0; |         unsigned int displ = 0; | ||||||
|  |         foreach (AttrDefs::iterator, i, attrs) | ||||||
|  |             newEnv.vars[i->first] = i->second.displ = displ++; | ||||||
|          |          | ||||||
|         foreach (ExprAttrs::Attrs::iterator, i, attrs) |         foreach (AttrDefs::iterator, i, attrs) | ||||||
|             displs[i->first] = newEnv.vars[i->first] = displ++; |             if (i->second.inherited) i->second.var.bind(env); | ||||||
| 
 |             else i->second.e->bindVars(newEnv); | ||||||
|         foreach (list<Inherited>::iterator, i, inherited) { |  | ||||||
|             displs[i->first.name] = newEnv.vars[i->first.name] = displ++; |  | ||||||
|             i->first.bind(env); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|         foreach (ExprAttrs::Attrs::iterator, i, attrs) |     else | ||||||
|             i->second.first->bindVars(newEnv); |         foreach (AttrDefs::iterator, i, attrs) | ||||||
|     } |             if (i->second.inherited) i->second.var.bind(env); | ||||||
| 
 |             else i->second.e->bindVars(env); | ||||||
|     else { |  | ||||||
|         foreach (ExprAttrs::Attrs::iterator, i, attrs) |  | ||||||
|             i->second.first->bindVars(env); |  | ||||||
| 
 |  | ||||||
|         foreach (list<Inherited>::iterator, i, inherited) |  | ||||||
|             i->first.bind(env); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ExprList::bindVars(const StaticEnv & env) | void ExprList::bindVars(const StaticEnv & env) | ||||||
|  | @ -263,17 +257,12 @@ void ExprLet::bindVars(const StaticEnv & env) | ||||||
|     StaticEnv newEnv(false, &env); |     StaticEnv newEnv(false, &env); | ||||||
|      |      | ||||||
|     unsigned int displ = 0; |     unsigned int displ = 0; | ||||||
|  |     foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs) | ||||||
|  |         newEnv.vars[i->first] = i->second.displ = displ++; | ||||||
|      |      | ||||||
|     foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs) |     foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs) | ||||||
|         newEnv.vars[i->first] = displ++; |         if (i->second.inherited) i->second.var.bind(env); | ||||||
| 
 |         else i->second.e->bindVars(newEnv); | ||||||
|     foreach (list<ExprAttrs::Inherited>::iterator, i, attrs->inherited) { |  | ||||||
|         newEnv.vars[i->first.name] = displ++; |  | ||||||
|         i->first.bind(env); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs) |  | ||||||
|         i->second.first->bindVars(newEnv); |  | ||||||
|      |      | ||||||
|     body->bindVars(newEnv); |     body->bindVars(newEnv); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -101,6 +101,7 @@ struct VarRef | ||||||
|     unsigned int level; |     unsigned int level; | ||||||
|     unsigned int displ; |     unsigned int displ; | ||||||
| 
 | 
 | ||||||
|  |     VarRef() { }; | ||||||
|     VarRef(const Symbol & name) : name(name) { }; |     VarRef(const Symbol & name) : name(name) { }; | ||||||
|     void bind(const StaticEnv & env); |     void bind(const StaticEnv & env); | ||||||
| }; | }; | ||||||
|  | @ -131,13 +132,18 @@ struct ExprOpHasAttr : Expr | ||||||
| struct ExprAttrs : Expr | struct ExprAttrs : Expr | ||||||
| { | { | ||||||
|     bool recursive; |     bool recursive; | ||||||
|     typedef std::pair<Expr *, Pos> Attr; |     struct AttrDef { | ||||||
|     typedef std::pair<VarRef, Pos> Inherited; |         bool inherited; | ||||||
|     typedef std::map<Symbol, Attr> Attrs; |         Expr * e; // if not inherited
 | ||||||
|     Attrs attrs; |         VarRef var; // if inherited
 | ||||||
|     list<Inherited> inherited; |         Pos pos; | ||||||
|     std::map<Symbol, Pos> attrNames; // used during parsing
 |         unsigned int displ; // displacement
 | ||||||
|     std::map<Symbol, unsigned int> displs; |         AttrDef(Expr * e, const Pos & pos) : inherited(false), e(e), pos(pos) { }; | ||||||
|  |         AttrDef(const Symbol & name, const Pos & pos) : inherited(true), var(name), pos(pos) { }; | ||||||
|  |         AttrDef() { }; | ||||||
|  |     }; | ||||||
|  |     typedef std::map<Symbol, AttrDef> AttrDefs; | ||||||
|  |     AttrDefs attrs; | ||||||
|     ExprAttrs() : recursive(false) { }; |     ExprAttrs() : recursive(false) { }; | ||||||
|     COMMON_METHODS |     COMMON_METHODS | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -93,20 +93,20 @@ static void addAttr(ExprAttrs * attrs, const vector<Symbol> & attrPath, | ||||||
|     unsigned int n = 0; |     unsigned int n = 0; | ||||||
|     foreach (vector<Symbol>::const_iterator, i, attrPath) { |     foreach (vector<Symbol>::const_iterator, i, attrPath) { | ||||||
|         n++; |         n++; | ||||||
|         ExprAttrs::Attrs::iterator j = attrs->attrs.find(*i); |         ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(*i); | ||||||
|         if (j != attrs->attrs.end()) { |         if (j != attrs->attrs.end()) { | ||||||
|             ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.first); |             if (!j->second.inherited) { | ||||||
|             if (!attrs2 || n == attrPath.size()) dupAttr(attrPath, pos, j->second.second); |                 ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.e); | ||||||
|  |                 if (!attrs2 || n == attrPath.size()) dupAttr(attrPath, pos, j->second.pos); | ||||||
|                 attrs = attrs2; |                 attrs = attrs2; | ||||||
|  |             } else | ||||||
|  |                 dupAttr(attrPath, pos, j->second.pos); | ||||||
|         } else { |         } else { | ||||||
|             if (attrs->attrNames.find(*i) != attrs->attrNames.end()) |  | ||||||
|                 dupAttr(attrPath, pos, attrs->attrNames[*i]); |  | ||||||
|             attrs->attrNames[*i] = pos; |  | ||||||
|             if (n == attrPath.size()) |             if (n == attrPath.size()) | ||||||
|                 attrs->attrs[*i] = ExprAttrs::Attr(e, pos); |                 attrs->attrs[*i] = ExprAttrs::AttrDef(e, pos); | ||||||
|             else { |             else { | ||||||
|                 ExprAttrs * nested = new ExprAttrs; |                 ExprAttrs * nested = new ExprAttrs; | ||||||
|                 attrs->attrs[*i] = ExprAttrs::Attr(nested, pos); |                 attrs->attrs[*i] = ExprAttrs::AttrDef(nested, pos); | ||||||
|                 attrs = nested; |                 attrs = nested; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -383,21 +383,19 @@ binds | ||||||
|   | binds INHERIT ids ';' |   | binds INHERIT ids ';' | ||||||
|     { $$ = $1; |     { $$ = $1; | ||||||
|       foreach (vector<Symbol>::iterator, i, *$3) { |       foreach (vector<Symbol>::iterator, i, *$3) { | ||||||
|           if ($$->attrNames.find(*i) != $$->attrNames.end()) |           if ($$->attrs.find(*i) != $$->attrs.end()) | ||||||
|               dupAttr(*i, makeCurPos(@3, data), $$->attrNames[*i]); |               dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos); | ||||||
|           Pos pos = makeCurPos(@3, data); |           Pos pos = makeCurPos(@3, data); | ||||||
|           $$->inherited.push_back(ExprAttrs::Inherited(*i, pos)); |           $$->attrs[*i] = ExprAttrs::AttrDef(*i, pos); | ||||||
|           $$->attrNames[*i] = pos; |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   | binds INHERIT '(' expr ')' ids ';' |   | binds INHERIT '(' expr ')' ids ';' | ||||||
|     { $$ = $1; |     { $$ = $1; | ||||||
|       /* !!! Should ensure sharing of the expression in $4. */ |       /* !!! Should ensure sharing of the expression in $4. */ | ||||||
|       foreach (vector<Symbol>::iterator, i, *$6) { |       foreach (vector<Symbol>::iterator, i, *$6) { | ||||||
|           if ($$->attrNames.find(*i) != $$->attrNames.end()) |           if ($$->attrs.find(*i) != $$->attrs.end()) | ||||||
|               dupAttr(*i, makeCurPos(@6, data), $$->attrNames[*i]); |               dupAttr(*i, makeCurPos(@6, data), $$->attrs[*i].pos); | ||||||
|           $$->attrs[*i] = ExprAttrs::Attr(new ExprSelect($4, *i), makeCurPos(@6, data)); |           $$->attrs[*i] = ExprAttrs::AttrDef(new ExprSelect($4, *i), makeCurPos(@6, data)); | ||||||
|           $$->attrNames[*i] = makeCurPos(@6, data); |  | ||||||
|       }} |       }} | ||||||
| 
 | 
 | ||||||
|   | { $$ = new ExprAttrs; } |   | { $$ = new ExprAttrs; } | ||||||
|  |  | ||||||
|  | @ -209,14 +209,13 @@ static void prim_tryEval(EvalState & state, Value * * args, Value & v) | ||||||
|     state.mkAttrs(v); |     state.mkAttrs(v); | ||||||
|     try { |     try { | ||||||
|         state.forceValue(*args[0]); |         state.forceValue(*args[0]); | ||||||
|         printMsg(lvlError, format("%1%") % *args[0]); |         v.attrs->push_back(Attr(state.symbols.create("value"), args[0])); | ||||||
|         (*v.attrs)[state.symbols.create("value")].value = args[0]; |  | ||||||
|         mkBool(*state.allocAttr(v, state.symbols.create("success")), true); |         mkBool(*state.allocAttr(v, state.symbols.create("success")), true); | ||||||
|         printMsg(lvlError, format("%1%") % v); |  | ||||||
|     } catch (AssertionError & e) { |     } catch (AssertionError & e) { | ||||||
|         mkBool(*state.allocAttr(v, state.symbols.create("value")), false); |         mkBool(*state.allocAttr(v, state.symbols.create("value")), false); | ||||||
|         mkBool(*state.allocAttr(v, state.symbols.create("success")), false); |         mkBool(*state.allocAttr(v, state.symbols.create("success")), false); | ||||||
|     } |     } | ||||||
|  |     v.attrs->sort(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -488,6 +487,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) | ||||||
|     state.mkAttrs(v); |     state.mkAttrs(v); | ||||||
|     mkString(*state.allocAttr(v, state.sOutPath), outPath, singleton<PathSet>(drvPath)); |     mkString(*state.allocAttr(v, state.sOutPath), outPath, singleton<PathSet>(drvPath)); | ||||||
|     mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton<PathSet>("=" + drvPath)); |     mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton<PathSet>("=" + drvPath)); | ||||||
|  |     v.attrs->sort(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -742,7 +742,9 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) | ||||||
|         names.insert(state.symbols.create(args[1]->list.elems[i]->string.s)); |         names.insert(state.symbols.create(args[1]->list.elems[i]->string.s)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Copy all attributes not in that set. */ |     /* Copy all attributes not in that set.  Note that we don't need
 | ||||||
|  |        to sort v.attrs because it's a subset of an already sorted | ||||||
|  |        vector. */ | ||||||
|     state.mkAttrs(v); |     state.mkAttrs(v); | ||||||
|     foreach (Bindings::iterator, i, *args[0]->attrs) { |     foreach (Bindings::iterator, i, *args[0]->attrs) { | ||||||
|         if (names.find(i->name) == names.end()) |         if (names.find(i->name) == names.end()) | ||||||
|  | @ -761,6 +763,8 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) | ||||||
| 
 | 
 | ||||||
|     state.mkAttrs(v); |     state.mkAttrs(v); | ||||||
| 
 | 
 | ||||||
|  |     std::set<Symbol> seen; | ||||||
|  | 
 | ||||||
|     for (unsigned int i = 0; i < args[0]->list.length; ++i) { |     for (unsigned int i = 0; i < args[0]->list.length; ++i) { | ||||||
|         Value & v2(*args[0]->list.elems[i]); |         Value & v2(*args[0]->list.elems[i]); | ||||||
|         state.forceAttrs(v2); |         state.forceAttrs(v2); | ||||||
|  | @ -774,10 +778,15 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) | ||||||
|         if (j2 == v2.attrs->end()) |         if (j2 == v2.attrs->end()) | ||||||
|             throw TypeError("`value' attribute missing in a call to `listToAttrs'"); |             throw TypeError("`value' attribute missing in a call to `listToAttrs'"); | ||||||
| 
 | 
 | ||||||
|         Attr & a = (*v.attrs)[state.symbols.create(name)]; |         Symbol sym = state.symbols.create(name); | ||||||
|         a.value = j2->value; |         if (seen.find(sym) == seen.end()) { | ||||||
|         a.pos = j2->pos; |             v.attrs->push_back(Attr(sym, j2->value, j2->pos)); | ||||||
|  |             seen.insert(sym); | ||||||
|         } |         } | ||||||
|  |         /* !!! Throw an error if `name' already exists? */ | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     v.attrs->sort(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -825,6 +834,8 @@ static void prim_functionArgs(EvalState & state, Value * * args, Value & v) | ||||||
|     foreach (Formals::Formals_::iterator, i, args[0]->lambda.fun->formals->formals) |     foreach (Formals::Formals_::iterator, i, args[0]->lambda.fun->formals->formals) | ||||||
|         // !!! should optimise booleans (allocate only once)
 |         // !!! should optimise booleans (allocate only once)
 | ||||||
|         mkBool(*state.allocAttr(v, i->name), i->def); |         mkBool(*state.allocAttr(v, i->name), i->def); | ||||||
|  | 
 | ||||||
|  |     v.attrs->sort(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -1007,6 +1018,7 @@ static void prim_parseDrvName(EvalState & state, Value * * args, Value & v) | ||||||
|     state.mkAttrs(v); |     state.mkAttrs(v); | ||||||
|     mkString(*state.allocAttr(v, state.sName), parsed.name); |     mkString(*state.allocAttr(v, state.sName), parsed.name); | ||||||
|     mkString(*state.allocAttr(v, state.symbols.create("version")), parsed.version); |     mkString(*state.allocAttr(v, state.symbols.create("version")), parsed.version); | ||||||
|  |     v.attrs->sort(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -1120,6 +1132,10 @@ void EvalState::createBaseEnv() | ||||||
|     // Versions
 |     // Versions
 | ||||||
|     addPrimOp("__parseDrvName", 1, prim_parseDrvName); |     addPrimOp("__parseDrvName", 1, prim_parseDrvName); | ||||||
|     addPrimOp("__compareVersions", 2, prim_compareVersions); |     addPrimOp("__compareVersions", 2, prim_compareVersions); | ||||||
|  | 
 | ||||||
|  |     /* Now that we've added all primops, sort the `builtins' attribute
 | ||||||
|  |        set, because attribute lookups expect it to be sorted. */ | ||||||
|  |     baseEnv.values[0]->attrs->sort(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -37,7 +37,7 @@ static void showAttrs(EvalState & state, bool strict, bool location, | ||||||
|         names.insert(i->name); |         names.insert(i->name); | ||||||
|      |      | ||||||
|     foreach (StringSet::iterator, i, names) { |     foreach (StringSet::iterator, i, names) { | ||||||
|         Attr & a(attrs[state.symbols.create(*i)]); |         Attr & a(*attrs.find(state.symbols.create(*i))); | ||||||
|          |          | ||||||
|         XMLAttrs xmlAttrs; |         XMLAttrs xmlAttrs; | ||||||
|         xmlAttrs["name"] = *i; |         xmlAttrs["name"] = *i; | ||||||
|  |  | ||||||
|  | @ -132,7 +132,7 @@ static void getAllExprs(EvalState & state, | ||||||
|             if (hasSuffix(attrName, ".nix")) |             if (hasSuffix(attrName, ".nix")) | ||||||
|                 attrName = string(attrName, 0, attrName.size() - 4); |                 attrName = string(attrName, 0, attrName.size() - 4); | ||||||
|             attrs.attrs[state.symbols.create(attrName)] = |             attrs.attrs[state.symbols.create(attrName)] = | ||||||
|                 ExprAttrs::Attr(parseExprFromFile(state, absPath(path2)), noPos); |                 ExprAttrs::AttrDef(parseExprFromFile(state, absPath(path2)), noPos); | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|             /* `path2' is a directory (with no default.nix in it);
 |             /* `path2' is a directory (with no default.nix in it);
 | ||||||
|  | @ -154,7 +154,7 @@ static Expr * loadSourceExpr(EvalState & state, const Path & path) | ||||||
|        some system-wide directory). */ |        some system-wide directory). */ | ||||||
|     ExprAttrs * attrs = new ExprAttrs; |     ExprAttrs * attrs = new ExprAttrs; | ||||||
|     attrs->attrs[state.symbols.create("_combineChannels")] = |     attrs->attrs[state.symbols.create("_combineChannels")] = | ||||||
|         ExprAttrs::Attr(new ExprList(), noPos); |         ExprAttrs::AttrDef(new ExprList(), noPos); | ||||||
|     getAllExprs(state, path, *attrs); |     getAllExprs(state, path, *attrs); | ||||||
|     return attrs; |     return attrs; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -70,12 +70,13 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, | ||||||
|         if (drvPath != "") |         if (drvPath != "") | ||||||
|             mkString(*state.allocAttr(v, state.sDrvPath), i->queryDrvPath(state)); |             mkString(*state.allocAttr(v, state.sDrvPath), i->queryDrvPath(state)); | ||||||
| 
 | 
 | ||||||
|         state.mkAttrs(*state.allocAttr(v, state.sMeta)); |         Value & vMeta = *state.allocAttr(v, state.sMeta); | ||||||
|  |         state.mkAttrs(vMeta); | ||||||
| 
 | 
 | ||||||
|         MetaInfo meta = i->queryMetaInfo(state); |         MetaInfo meta = i->queryMetaInfo(state); | ||||||
| 
 | 
 | ||||||
|         foreach (MetaInfo::const_iterator, j, meta) { |         foreach (MetaInfo::const_iterator, j, meta) { | ||||||
|             Value & v2(*state.allocAttr(*(*v.attrs)[state.sMeta].value, state.symbols.create(j->first))); |             Value & v2(*state.allocAttr(vMeta, state.symbols.create(j->first))); | ||||||
|             switch (j->second.type) { |             switch (j->second.type) { | ||||||
|                 case MetaValue::tpInt: mkInt(v2, j->second.intValue); break; |                 case MetaValue::tpInt: mkInt(v2, j->second.intValue); break; | ||||||
|                 case MetaValue::tpString: mkString(v2, j->second.stringValue); break; |                 case MetaValue::tpString: mkString(v2, j->second.stringValue); break; | ||||||
|  | @ -92,6 +93,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|      |      | ||||||
|  |         vMeta.attrs->sort(); | ||||||
|  |         v.attrs->sort(); | ||||||
|  |          | ||||||
|         /* This is only necessary when installing store paths, e.g.,
 |         /* This is only necessary when installing store paths, e.g.,
 | ||||||
|            `nix-env -i /nix/store/abcd...-foo'. */ |            `nix-env -i /nix/store/abcd...-foo'. */ | ||||||
|         store->addTempRoot(i->queryOutPath(state)); |         store->addTempRoot(i->queryOutPath(state)); | ||||||
|  | @ -118,7 +122,8 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, | ||||||
|     mkString(*state.allocAttr(args, state.sSystem), thisSystem); |     mkString(*state.allocAttr(args, state.sSystem), thisSystem); | ||||||
|     mkString(*state.allocAttr(args, state.symbols.create("manifest")), |     mkString(*state.allocAttr(args, state.symbols.create("manifest")), | ||||||
|         manifestFile, singleton<PathSet>(manifestFile)); |         manifestFile, singleton<PathSet>(manifestFile)); | ||||||
|     (*args.attrs)[state.symbols.create("derivations")].value = &manifest; |     args.attrs->push_back(Attr(state.symbols.create("derivations"), &manifest)); | ||||||
|  |     args.attrs->sort(); | ||||||
|     mkApp(topLevel, envBuilder, args); |     mkApp(topLevel, envBuilder, args); | ||||||
|          |          | ||||||
|     /* Evaluate it. */ |     /* Evaluate it. */ | ||||||
|  |  | ||||||
|  | @ -7,5 +7,5 @@ let | ||||||
|   a = builtins.listToAttrs list; |   a = builtins.listToAttrs list; | ||||||
|   b = builtins.listToAttrs ( list ++ list ); |   b = builtins.listToAttrs ( list ++ list ); | ||||||
|   r = builtins.listToAttrs [ (asi "result" [ a b ]) ( asi "throw" (throw "this should not be thrown")) ]; |   r = builtins.listToAttrs [ (asi "result" [ a b ]) ( asi "throw" (throw "this should not be thrown")) ]; | ||||||
|   x = builtins.listToAttrs [ (asi "foo" "bla") (asi "foo" "bar") ]; |   x = builtins.listToAttrs [ (asi "foo" "bar") (asi "foo" "bla") ]; | ||||||
| in concat (map (x: x.a) r.result) + x.foo | in concat (map (x: x.a) r.result) + x.foo | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue