diff options
Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r-- | src/libexpr/eval.cc | 371 |
1 files changed, 230 insertions, 141 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index d61ee7e80795..5a6428ca6b6f 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -5,6 +5,7 @@ #include "derivations.hh" #include "globals.hh" #include "eval-inline.hh" +#include "download.hh" #include <algorithm> #include <cstring> @@ -55,14 +56,10 @@ static void * allocBytes(size_t n) } -void Bindings::sort() -{ - std::sort(begin(), end()); -} - - static void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v) { + checkInterrupt(); + if (active.find(&v) != active.end()) { str << "<CYCLE>"; return; @@ -96,8 +93,8 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con str << "{ "; typedef std::map<string, Value *> Sorted; Sorted sorted; - foreach (Bindings::iterator, i, *v.attrs) - sorted[i->name] = i->value; + for (auto & i : *v.attrs) + sorted[i.name] = i.value; for (auto & i : sorted) { str << i.first << " = "; printValue(str, active, *i.second); @@ -106,10 +103,12 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con str << "}"; break; } - case tList: + case tList1: + case tList2: + case tListN: str << "[ "; - for (unsigned int n = 0; n < v.list.length; ++n) { - printValue(str, active, *v.list.elems[n]); + for (unsigned int n = 0; n < v.listSize(); ++n) { + printValue(str, active, *v.listElems()[n]); str << " "; } str << "]"; @@ -130,6 +129,9 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con case tExternal: str << *v.external; break; + case tFloat: + str << v.fpoint; + break; default: throw Error("invalid value"); } @@ -155,7 +157,7 @@ string showType(const Value & v) case tPath: return "a path"; case tNull: return "null"; case tAttrs: return "a set"; - case tList: return "a list"; + case tList1: case tList2: case tListN: return "a list"; case tThunk: return "a thunk"; case tApp: return "a function application"; case tLambda: return "a function"; @@ -163,6 +165,7 @@ string showType(const Value & v) case tPrimOp: return "a built-in function"; case tPrimOpApp: return "a partially applied built-in function"; case tExternal: return v.external->showType(); + case tFloat: return "a float"; } abort(); } @@ -236,17 +239,43 @@ void initGC() /* Very hacky way to parse $NIX_PATH, which is colon-separated, but can contain URLs (e.g. "nixpkgs=https://bla...:foo=https://"). */ -static Strings parseNixPath(const string & in) +static Strings parseNixPath(const string & s) { - string marker = "\001//"; - auto res = tokenizeString<Strings>(replaceStrings(in, "://", marker), ":"); - for (auto & s : res) - s = replaceStrings(s, marker, "://"); + Strings res; + + auto p = s.begin(); + + while (p != s.end()) { + auto start = p; + auto start2 = p; + + while (p != s.end() && *p != ':') { + if (*p == '=') start2 = p + 1; + ++p; + } + + if (p == s.end()) { + if (p != start) res.push_back(std::string(start, p)); + break; + } + + if (*p == ':') { + if (isUri(std::string(start2, s.end()))) { + ++p; + while (p != s.end() && *p != ':') ++p; + } + res.push_back(std::string(start, p)); + if (p == s.end()) break; + } + + ++p; + } + return res; } -EvalState::EvalState(const Strings & _searchPath) +EvalState::EvalState(const Strings & _searchPath, ref<Store> store) : sWith(symbols.create("<with>")) , sOutPath(symbols.create("outPath")) , sDrvPath(symbols.create("drvPath")) @@ -263,14 +292,11 @@ EvalState::EvalState(const Strings & _searchPath) , sLine(symbols.create("line")) , sColumn(symbols.create("column")) , sFunctor(symbols.create("__functor")) - , repair(false) + , sToString(symbols.create("__toString")) + , store(store) , baseEnv(allocEnv(128)) , staticBaseEnv(false, 0) - , baseEnvDispl(0) { - nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0; - nrAttrsets = nrAttrsInAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0; - nrListConcats = nrPrimOpCalls = nrFunctionCalls = 0; countCalls = getEnv("NIX_COUNT_CALLS", "0") != "0"; restricted = settings.get("restrict-eval", false); @@ -279,10 +305,14 @@ EvalState::EvalState(const Strings & _searchPath) /* Initialise the Nix expression search path. */ Strings paths = parseNixPath(getEnv("NIX_PATH", "")); - for (auto & i : _searchPath) addToSearchPath(i, true); + for (auto & i : _searchPath) addToSearchPath(i); for (auto & i : paths) addToSearchPath(i); addToSearchPath("nix=" + settings.nixDataDir + "/nix/corepkgs"); + clearValue(vEmptySet); + vEmptySet.type = tAttrs; + vEmptySet.attrs = allocBindings(0); + createBaseEnv(); } @@ -298,11 +328,15 @@ Path EvalState::checkSourcePath(const Path & path_) if (!restricted) return path_; /* Resolve symlinks. */ + debug(format("checking access to ‘%s’") % path_); Path path = canonPath(path_, true); - for (auto & i : searchPath) - if (path == i.second || isInDir(path, i.second)) + for (auto & i : searchPath) { + auto r = resolveSearchPathElem(i); + if (!r.first) continue; + if (path == r.second || isInDir(path, r.second)) return path; + } /* To support import-from-derivation, allow access to anything in the store. FIXME: only allow access to paths that have been @@ -361,11 +395,6 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2)) throw EvalError(format(s) % s2); } -LocalNoInlineNoReturn(void throwEvalError(const char * s, const Pos & pos)) -{ - throw EvalError(format(s) % pos); -} - LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const Pos & pos)) { throw EvalError(format(s) % s2 % pos); @@ -440,8 +469,8 @@ void mkString(Value & v, const string & s, const PathSet & context) unsigned int n = 0; v.string.context = (const char * *) allocBytes((context.size() + 1) * sizeof(char *)); - foreach (PathSet::const_iterator, i, context) - v.string.context[n++] = dupString(i->c_str()); + for (auto & i : context) + v.string.context[n++] = dupString(i.c_str()); v.string.context[n] = 0; } } @@ -503,37 +532,19 @@ Env & EvalState::allocEnv(unsigned int size) } -Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name) -{ - Value * v = allocValue(); - vAttrs.attrs->push_back(Attr(name, v)); - return v; -} - - -Bindings * EvalState::allocBindings(Bindings::size_t capacity) -{ - return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings(capacity); -} - - -void EvalState::mkList(Value & v, unsigned int length) -{ - clearValue(v); - v.type = tList; - v.list.length = length; - v.list.elems = length ? (Value * *) allocBytes(length * sizeof(Value *)) : 0; - nrListElems += length; -} - - -void EvalState::mkAttrs(Value & v, unsigned int expected) +void EvalState::mkList(Value & v, unsigned int size) { clearValue(v); - v.type = tAttrs; - v.attrs = allocBindings(expected); - nrAttrsets++; - nrAttrsInAttrsets += expected; + if (size == 1) + v.type = tList1; + else if (size == 2) + v.type = tList2; + else { + v.type = tListN; + v.bigList.size = size; + v.bigList.elems = size ? (Value * *) allocBytes(size * sizeof(Value *)) : 0; + } + nrListElems += size; } @@ -603,6 +614,12 @@ Value * ExprInt::maybeThunk(EvalState & state, Env & env) return &v; } +Value * ExprFloat::maybeThunk(EvalState & state, Env & env) +{ + nrAvoided++; + return &v; +} + Value * ExprPath::maybeThunk(EvalState & state, Env & env) { nrAvoided++; @@ -624,7 +641,7 @@ void EvalState::evalFile(const Path & path, Value & v) return; } - startNest(nest, lvlTalkative, format("evaluating file ‘%1%’") % path2); + Activity act(*logger, lvlTalkative, format("evaluating file ‘%1%’") % path2); Expr * e = parseExprFromFile(checkSourcePath(path2)); try { eval(e, v); @@ -690,6 +707,11 @@ void ExprInt::eval(EvalState & state, Env & env, Value & v) } +void ExprFloat::eval(EvalState & state, Env & env, Value & v) +{ + v = this->v; +} + void ExprString::eval(EvalState & state, Env & env, Value & v) { v = this->v; @@ -721,15 +743,15 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) environment, while the inherited attributes are evaluated in the original environment. */ unsigned int displ = 0; - foreach (AttrDefs::iterator, i, attrs) { + for (auto & i : attrs) { Value * vAttr; - if (hasOverrides && !i->second.inherited) { + if (hasOverrides && !i.second.inherited) { vAttr = state.allocValue(); - mkThunk(*vAttr, env2, i->second.e); + mkThunk(*vAttr, env2, i.second.e); } else - vAttr = i->second.e->maybeThunk(state, i->second.inherited ? env : env2); + vAttr = i.second.e->maybeThunk(state, i.second.inherited ? env : env2); env2.values[displ++] = vAttr; - v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos)); + v.attrs->push_back(Attr(i.first, vAttr, &i.second.pos)); } /* If the rec contains an attribute called `__overrides', then @@ -760,25 +782,25 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) } else - foreach (AttrDefs::iterator, i, attrs) - v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos)); + for (auto & i : attrs) + v.attrs->push_back(Attr(i.first, i.second.e->maybeThunk(state, env), &i.second.pos)); /* Dynamic attrs apply *after* rec and __overrides. */ - foreach (DynamicAttrDefs::iterator, i, dynamicAttrs) { + for (auto & i : dynamicAttrs) { Value nameVal; - i->nameExpr->eval(state, *dynamicEnv, nameVal); - state.forceValue(nameVal); + i.nameExpr->eval(state, *dynamicEnv, nameVal); + state.forceValue(nameVal, i.pos); if (nameVal.type == tNull) continue; state.forceStringNoCtx(nameVal); Symbol nameSym = state.symbols.create(nameVal.string.s); Bindings::iterator j = v.attrs->find(nameSym); if (j != v.attrs->end()) - throwEvalError("dynamic attribute ‘%1%’ at %2% already defined at %3%", nameSym, i->pos, *j->pos); + throwEvalError("dynamic attribute ‘%1%’ at %2% already defined at %3%", nameSym, i.pos, *j->pos); - i->valueExpr->setName(nameSym); + i.valueExpr->setName(nameSym); /* Keep sorted order so find can catch duplicates */ - v.attrs->push_back(Attr(nameSym, i->valueExpr->maybeThunk(state, *dynamicEnv), &i->pos)); + v.attrs->push_back(Attr(nameSym, i.valueExpr->maybeThunk(state, *dynamicEnv), &i.pos)); v.attrs->sort(); // FIXME: inefficient } } @@ -795,8 +817,8 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v) while the inherited attributes are evaluated in the original environment. */ unsigned int displ = 0; - foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs) - env2.values[displ++] = i->second.e->maybeThunk(state, i->second.inherited ? env : env2); + for (auto & i : attrs->attrs) + env2.values[displ++] = i.second.e->maybeThunk(state, i.second.inherited ? env : env2); body->eval(state, env2, v); } @@ -805,15 +827,15 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v) void ExprList::eval(EvalState & state, Env & env, Value & v) { state.mkList(v, elems.size()); - for (unsigned int n = 0; n < v.list.length; ++n) - v.list.elems[n] = elems[n]->maybeThunk(state, env); + for (unsigned int n = 0; n < elems.size(); ++n) + v.listElems()[n] = elems[n]->maybeThunk(state, env); } void ExprVar::eval(EvalState & state, Env & env, Value & v) { Value * v2 = state.lookupVar(&env, *this, false); - state.forceValue(*v2); + state.forceValue(*v2, pos); v = *v2; } @@ -847,12 +869,12 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) try { - foreach (AttrPath::const_iterator, i, attrPath) { + for (auto & i : attrPath) { nrLookups++; Bindings::iterator j; - Symbol name = getName(*i, state, env); + Symbol name = getName(i, state, env); if (def) { - state.forceValue(*vAttrs); + state.forceValue(*vAttrs, pos); if (vAttrs->type != tAttrs || (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { @@ -869,7 +891,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) if (state.countCalls && pos2) state.attrSelects[*pos2]++; } - state.forceValue(*vAttrs); + state.forceValue(*vAttrs, ( pos2 != NULL ? *pos2 : this->pos ) ); } catch (Error & e) { if (pos2 && pos2->file != state.sDerivationNix) @@ -889,10 +911,10 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) e->eval(state, env, vTmp); - foreach (AttrPath::const_iterator, i, attrPath) { + for (auto & i : attrPath) { state.forceValue(*vAttrs); Bindings::iterator j; - Symbol name = getName(*i, state, env); + Symbol name = getName(i, state, env); if (vAttrs->type != tAttrs || (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { @@ -971,10 +993,10 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po if (fun.type == tAttrs) { auto found = fun.attrs->find(sFunctor); if (found != fun.attrs->end()) { - forceValue(*found->value); + forceValue(*found->value, pos); Value * v2 = allocValue(); callFunction(*found->value, fun, *v2, pos); - forceValue(*v2); + forceValue(*v2, pos); return callFunction(*v2, arg, v, pos); } } @@ -1005,12 +1027,12 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po there is no matching actual argument but the formal argument has a default, use the default. */ unsigned int attrsUsed = 0; - foreach (Formals::Formals_::iterator, i, lambda.formals->formals) { - Bindings::iterator j = arg.attrs->find(i->name); + for (auto & i : lambda.formals->formals) { + Bindings::iterator j = arg.attrs->find(i.name); if (j == arg.attrs->end()) { - if (!i->def) throwTypeError("%1% called without required argument ‘%2%’, at %3%", - lambda, i->name, pos); - env2.values[displ++] = i->def->maybeThunk(*this, env2); + if (!i.def) throwTypeError("%1% called without required argument ‘%2%’, at %3%", + lambda, i.name, pos); + env2.values[displ++] = i.def->maybeThunk(*this, env2); } else { attrsUsed++; env2.values[displ++] = j->value; @@ -1022,9 +1044,9 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po if (!lambda.formals->ellipsis && attrsUsed != arg.attrs->size()) { /* Nope, so show the first unexpected argument to the user. */ - foreach (Bindings::iterator, i, *arg.attrs) - if (lambda.formals->argNames.find(i->name) == lambda.formals->argNames.end()) - throwTypeError("%1% called with unexpected argument ‘%2%’, at %3%", lambda, i->name, pos); + for (auto & i : *arg.attrs) + if (lambda.formals->argNames.find(i.name) == lambda.formals->argNames.end()) + throwTypeError("%1% called with unexpected argument ‘%2%’, at %3%", lambda, i.name, pos); abort(); // can't happen } } @@ -1058,6 +1080,17 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) { forceValue(fun); + if (fun.type == tAttrs) { + auto found = fun.attrs->find(sFunctor); + if (found != fun.attrs->end()) { + forceValue(*found->value); + Value * v = allocValue(); + callFunction(*found->value, fun, *v, noPos); + forceValue(*v); + return autoCallFunction(args, *v, res); + } + } + if (fun.type != tLambda || !fun.lambda.fun->matchAttrs) { res = fun; return; @@ -1066,12 +1099,12 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) Value * actualArgs = allocValue(); mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size()); - foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) { - Bindings::iterator j = args.find(i->name); + for (auto & i : fun.lambda.fun->formals->formals) { + Bindings::iterator j = args.find(i.name); if (j != args.end()) actualArgs->attrs->push_back(*j); - else if (!i->def) - throwTypeError("cannot auto-call a function that has an argument without a default value (‘%1%’)", i->name); + else if (!i.def) + throwTypeError("cannot auto-call a function that has an argument without a default value (‘%1%’)", i.name); } actualArgs->attrs->sort(); @@ -1199,20 +1232,21 @@ void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists, co unsigned int len = 0; for (unsigned int n = 0; n < nrLists; ++n) { forceList(*lists[n], pos); - unsigned int l = lists[n]->list.length; + unsigned int l = lists[n]->listSize(); len += l; if (l) nonEmpty = lists[n]; } - if (nonEmpty && len == nonEmpty->list.length) { + if (nonEmpty && len == nonEmpty->listSize()) { v = *nonEmpty; return; } mkList(v, len); + auto out = v.listElems(); for (unsigned int n = 0, pos = 0; n < nrLists; ++n) { - unsigned int l = lists[n]->list.length; - memcpy(v.list.elems + pos, lists[n]->list.elems, l * sizeof(Value *)); + unsigned int l = lists[n]->listSize(); + memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *)); pos += l; } } @@ -1223,13 +1257,14 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) PathSet context; std::ostringstream s; NixInt n = 0; + NixFloat nf = 0; bool first = !forceString; ValueType firstType = tString; - foreach (vector<Expr *>::iterator, i, *es) { + for (auto & i : *es) { Value vTmp; - (*i)->eval(state, env, vTmp); + i->eval(state, env, vTmp); /* If the first element is a path, then the result will also be a path, we don't copy anything (yet - that's done later, @@ -1241,15 +1276,30 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) } if (firstType == tInt) { - if (vTmp.type != tInt) + if (vTmp.type == tInt) { + n += vTmp.integer; + } else if (vTmp.type == tFloat) { + // Upgrade the type from int to float; + firstType = tFloat; + nf = n; + nf += vTmp.fpoint; + } else throwEvalError("cannot add %1% to an integer, at %2%", showType(vTmp), pos); - n += vTmp.integer; + } else if (firstType == tFloat) { + if (vTmp.type == tInt) { + nf += vTmp.integer; + } else if (vTmp.type == tFloat) { + nf += vTmp.fpoint; + } else + throwEvalError("cannot add %1% to a float, at %2%", showType(vTmp), pos); } else s << state.coerceToString(pos, vTmp, context, false, firstType == tString); } if (firstType == tInt) mkInt(v, n); + else if (firstType == tFloat) + mkFloat(v, nf); else if (firstType == tPath) { if (!context.empty()) throwEvalError("a string that refers to a store path cannot be appended to a path, at %1%", pos); @@ -1288,9 +1338,9 @@ void EvalState::forceValueDeep(Value & v) } } - else if (v.type == tList) { - for (unsigned int n = 0; n < v.list.length; ++n) - recurse(*v.list.elems[n]); + else if (v.isList()) { + for (unsigned int n = 0; n < v.listSize(); ++n) + recurse(*v.listElems()[n]); } }; @@ -1300,13 +1350,24 @@ void EvalState::forceValueDeep(Value & v) NixInt EvalState::forceInt(Value & v, const Pos & pos) { - forceValue(v); + forceValue(v, pos); if (v.type != tInt) throwTypeError("value is %1% while an integer was expected, at %2%", v, pos); return v.integer; } +NixFloat EvalState::forceFloat(Value & v, const Pos & pos) +{ + forceValue(v, pos); + if (v.type == tInt) + return v.integer; + else if (v.type != tFloat) + throwTypeError("value is %1% while a float was expected, at %2%", v, pos); + return v.fpoint; +} + + bool EvalState::forceBool(Value & v) { forceValue(v); @@ -1316,17 +1377,23 @@ bool EvalState::forceBool(Value & v) } +bool EvalState::isFunctor(Value & fun) +{ + return fun.type == tAttrs && fun.attrs->find(sFunctor) != fun.attrs->end(); +} + + void EvalState::forceFunction(Value & v, const Pos & pos) { forceValue(v); - if (v.type != tLambda && v.type != tPrimOp && v.type != tPrimOpApp) + if (v.type != tLambda && v.type != tPrimOp && v.type != tPrimOpApp && !isFunctor(v)) throwTypeError("value is %1% while a function was expected, at %2%", v, pos); } string EvalState::forceString(Value & v, const Pos & pos) { - forceValue(v); + forceValue(v, pos); if (v.type != tString) { if (pos) throwTypeError("value is %1% while a string was expected, at %2%", v, pos); @@ -1397,7 +1464,14 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, } if (v.type == tAttrs) { - Bindings::iterator i = v.attrs->find(sOutPath); + auto i = v.attrs->find(sToString); + if (i != v.attrs->end()) { + forceValue(*i->value, pos); + Value v1; + callFunction(*i->value, v, v1, pos); + return coerceToString(pos, v1, context, coerceMore, copyToStore); + } + i = v.attrs->find(sOutPath); if (i == v.attrs->end()) throwTypeError("cannot coerce a set to a string, at %1%", pos); return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } @@ -1411,17 +1485,18 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, 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 == tInt) return std::to_string(v.integer); + if (v.type == tFloat) return std::to_string(v.fpoint); if (v.type == tNull) return ""; - if (v.type == tList) { + if (v.isList()) { string result; - for (unsigned int n = 0; n < v.list.length; ++n) { - result += coerceToString(pos, *v.list.elems[n], + for (unsigned int n = 0; n < v.listSize(); ++n) { + result += coerceToString(pos, *v.listElems()[n], context, coerceMore, copyToStore); - if (n < v.list.length - 1 + if (n < v.listSize() - 1 /* !!! not quite correct */ - && (v.list.elems[n]->type != tList || v.list.elems[n]->list.length != 0)) + && (!v.listElems()[n]->isList() || v.listElems()[n]->listSize() != 0)) result += " "; } return result; @@ -1473,6 +1548,13 @@ bool EvalState::eqValues(Value & v1, Value & v2) uniqList on a list of sets.) Will remove this eventually. */ if (&v1 == &v2) return true; + // Special case type-compatibility between float and int + if (v1.type == tInt && v2.type == tFloat) + return v1.integer == v2.fpoint; + if (v1.type == tFloat && v2.type == tInt) + return v1.fpoint == v2.integer; + + // All other types are not compatible with each other. if (v1.type != v2.type) return false; switch (v1.type) { @@ -1492,10 +1574,12 @@ bool EvalState::eqValues(Value & v1, Value & v2) case tNull: return true; - case tList: - if (v1.list.length != v2.list.length) return false; - for (unsigned int n = 0; n < v1.list.length; ++n) - if (!eqValues(*v1.list.elems[n], *v2.list.elems[n])) return false; + case tList1: + case tList2: + case tListN: + if (v1.listSize() != v2.listSize()) return false; + for (unsigned int n = 0; n < v1.listSize(); ++n) + if (!eqValues(*v1.listElems()[n], *v2.listElems()[n])) return false; return true; case tAttrs: { @@ -1528,6 +1612,9 @@ bool EvalState::eqValues(Value & v1, Value & v2) case tExternal: return *v1.external == *v2.external; + case tFloat: + return v1.fpoint == v2.fpoint; + default: throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2)); } @@ -1581,25 +1668,25 @@ void EvalState::printStats() printMsg(v, format("calls to %1% primops:") % primOpCalls.size()); typedef std::multimap<unsigned int, Symbol> PrimOpCalls_; PrimOpCalls_ primOpCalls_; - foreach (PrimOpCalls::iterator, i, primOpCalls) - primOpCalls_.insert(std::pair<unsigned int, Symbol>(i->second, i->first)); - foreach_reverse (PrimOpCalls_::reverse_iterator, i, primOpCalls_) + for (auto & i : primOpCalls) + primOpCalls_.insert(std::pair<unsigned int, Symbol>(i.second, i.first)); + for (auto i = primOpCalls_.rbegin(); i != primOpCalls_.rend(); ++i) printMsg(v, format("%1$10d %2%") % i->first % i->second); printMsg(v, format("calls to %1% functions:") % functionCalls.size()); typedef std::multimap<unsigned int, ExprLambda *> FunctionCalls_; FunctionCalls_ functionCalls_; - foreach (FunctionCalls::iterator, i, functionCalls) - functionCalls_.insert(std::pair<unsigned int, ExprLambda *>(i->second, i->first)); - foreach_reverse (FunctionCalls_::reverse_iterator, i, functionCalls_) + for (auto & i : functionCalls) + functionCalls_.insert(std::pair<unsigned int, ExprLambda *>(i.second, i.first)); + for (auto i = functionCalls_.rbegin(); i != functionCalls_.rend(); ++i) printMsg(v, format("%1$10d %2%") % i->first % i->second->showNamePos()); printMsg(v, format("evaluations of %1% attributes:") % attrSelects.size()); typedef std::multimap<unsigned int, Pos> AttrSelects_; AttrSelects_ attrSelects_; - foreach (AttrSelects::iterator, i, attrSelects) - attrSelects_.insert(std::pair<unsigned int, Pos>(i->second, i->first)); - foreach_reverse (AttrSelects_::reverse_iterator, i, attrSelects_) + for (auto & i : attrSelects) + attrSelects_.insert(std::pair<unsigned int, Pos>(i.second, i.first)); + for (auto i = attrSelects_.rbegin(); i != attrSelects_.rend(); ++i) printMsg(v, format("%1$10d %2%") % i->first % i->second); } @@ -1643,12 +1730,14 @@ size_t valueSize(Value & v) sz += doValue(*i.value); } break; - case tList: - if (seen.find(v.list.elems) == seen.end()) { - seen.insert(v.list.elems); - sz += v.list.length * sizeof(Value *); - for (unsigned int n = 0; n < v.list.length; ++n) - sz += doValue(*v.list.elems[n]); + case tList1: + case tList2: + case tListN: + if (seen.find(v.listElems()) == seen.end()) { + seen.insert(v.listElems()); + sz += v.listSize() * sizeof(Value *); + for (unsigned int n = 0; n < v.listSize(); ++n) + sz += doValue(*v.listElems()[n]); } break; case tThunk: |