* Use a symbol table to represent identifiers and attribute names
efficiently. The symbol table ensures that there is only one copy of each symbol, thus allowing symbols to be compared efficiently using a pointer equality test.
This commit is contained in:
		
							parent
							
								
									10e8b1fd15
								
							
						
					
					
						commit
						ac1e8f40d4
					
				
					 15 changed files with 228 additions and 101 deletions
				
			
		|  | @ -8,7 +8,7 @@ libexpr_la_SOURCES = \ | ||||||
| pkginclude_HEADERS = \ | pkginclude_HEADERS = \ | ||||||
|  nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \ |  nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \ | ||||||
|  get-drvs.hh attr-path.hh value-to-xml.hh common-opts.hh \ |  get-drvs.hh attr-path.hh value-to-xml.hh common-opts.hh \ | ||||||
|  names.hh |  names.hh symbol-table.hh | ||||||
| 
 | 
 | ||||||
| libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \ | libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \ | ||||||
|  ../boost/format/libformat.la |  ../boost/format/libformat.la | ||||||
|  |  | ||||||
|  | @ -45,7 +45,7 @@ void findAlongAttrPath(EvalState & state, const string & attrPath, | ||||||
|                     format("the expression selected by the selection path `%1%' should be an attribute set but is %2%") |                     format("the expression selected by the selection path `%1%' should be an attribute set but is %2%") | ||||||
|                     % curPath % showType(v)); |                     % curPath % showType(v)); | ||||||
| 
 | 
 | ||||||
|             Bindings::iterator a = v.attrs->find(attr); |             Bindings::iterator a = v.attrs->find(state.symbols.create(attr)); | ||||||
|             if (a == v.attrs->end()) |             if (a == v.attrs->end()) | ||||||
|                 throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); |                 throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); | ||||||
|             v = a->second; |             v = a->second; | ||||||
|  |  | ||||||
|  | @ -20,10 +20,10 @@ bool parseOptionArg(const string & arg, Strings::iterator & i, | ||||||
|     if (i == argsEnd) throw error; |     if (i == argsEnd) throw error; | ||||||
|     string value = *i++; |     string value = *i++; | ||||||
| 
 | 
 | ||||||
|     Value & v(autoArgs[name]); |     Value & v(autoArgs[state.symbols.create(name)]); | ||||||
| 
 | 
 | ||||||
|     if (arg == "--arg") |     if (arg == "--arg") | ||||||
|         state.mkThunk_(v, parseExprFromString(value, absPath("."))); |         state.mkThunk_( v, parseExprFromString(state, value, absPath("."))); | ||||||
|     else |     else | ||||||
|         mkString(v, value); |         mkString(v, value); | ||||||
|      |      | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ using namespace nix; | ||||||
| 
 | 
 | ||||||
| void doTest(EvalState & state, string s) | void doTest(EvalState & state, string s) | ||||||
| { | { | ||||||
|     Expr * e = parseExprFromString(s, absPath(".")); |     Expr * e = parseExprFromString(state, s, absPath(".")); | ||||||
|     std::cerr << ">>>>> " << *e << std::endl; |     std::cerr << ">>>>> " << *e << std::endl; | ||||||
|     Value v; |     Value v; | ||||||
|     state.eval(e, v); |     state.eval(e, v); | ||||||
|  | @ -23,6 +23,29 @@ void doTest(EvalState & state, string s) | ||||||
| 
 | 
 | ||||||
| void run(Strings args) | void run(Strings args) | ||||||
| { | { | ||||||
|  |     SymbolTable t; | ||||||
|  | 
 | ||||||
|  |     printMsg(lvlError, format("size of symbol: %1% bytes") % sizeof(Symbol)); | ||||||
|  |      | ||||||
|  |     Symbol s1 = t.create("foo"); | ||||||
|  |     Symbol s2 = t.create("foo"); | ||||||
|  |     Symbol s3 = t.create("bar"); | ||||||
|  |     Symbol s4 = t.create("foo"); | ||||||
|  | 
 | ||||||
|  |     assert(s1 == s2); | ||||||
|  |     assert(s1 == s4); | ||||||
|  |     assert(s1 != s3); | ||||||
|  | 
 | ||||||
|  |     std::map<Symbol, int> m; | ||||||
|  | 
 | ||||||
|  |     m[s1] = 123; | ||||||
|  |     m[s3] = 456; | ||||||
|  | 
 | ||||||
|  |     std::cout << m[s1] << std::endl; | ||||||
|  |     std::cout << m[s2] << std::endl; | ||||||
|  |     std::cout << m[s3] << std::endl; | ||||||
|  |     std::cout << m[s4] << std::endl; | ||||||
|  | 
 | ||||||
|     EvalState state; |     EvalState state; | ||||||
| 
 | 
 | ||||||
|     printMsg(lvlError, format("size of value: %1% bytes") % sizeof(Value)); |     printMsg(lvlError, format("size of value: %1% bytes") % sizeof(Value)); | ||||||
|  |  | ||||||
|  | @ -44,7 +44,7 @@ std::ostream & operator << (std::ostream & str, Value & v) | ||||||
|     case tAttrs: |     case tAttrs: | ||||||
|         str << "{ "; |         str << "{ "; | ||||||
|         foreach (Bindings::iterator, i, *v.attrs)  |         foreach (Bindings::iterator, i, *v.attrs)  | ||||||
|             str << i->first << " = " << i->second << "; "; |             str << (string) i->first << " = " << i->second << "; "; | ||||||
|         str << "}"; |         str << "}"; | ||||||
|         break; |         break; | ||||||
|     case tList: |     case tList: | ||||||
|  | @ -91,7 +91,14 @@ string showType(Value & v) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| EvalState::EvalState() : baseEnv(allocEnv()) | EvalState::EvalState() | ||||||
|  |     : sWith(symbols.create("<with>")) | ||||||
|  |     , sOutPath(symbols.create("outPath")) | ||||||
|  |     , sDrvPath(symbols.create("drvPath")) | ||||||
|  |     , sType(symbols.create("type")) | ||||||
|  |     , sMeta(symbols.create("meta")) | ||||||
|  |     , sName(symbols.create("name")) | ||||||
|  |     , baseEnv(allocEnv()) | ||||||
| { | { | ||||||
|     nrValues = nrEnvs = nrEvaluated = recursionDepth = maxRecursionDepth = 0; |     nrValues = nrEnvs = nrEvaluated = recursionDepth = maxRecursionDepth = 0; | ||||||
|     deepestStack = (char *) -1; |     deepestStack = (char *) -1; | ||||||
|  | @ -110,9 +117,9 @@ EvalState::~EvalState() | ||||||
| 
 | 
 | ||||||
| void EvalState::addConstant(const string & name, Value & v) | void EvalState::addConstant(const string & name, Value & v) | ||||||
| { | { | ||||||
|     baseEnv.bindings[name] = v; |     baseEnv.bindings[symbols.create(name)] = v; | ||||||
|     string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; |     string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; | ||||||
|     (*baseEnv.bindings["builtins"].attrs)[name2] = v; |     (*baseEnv.bindings[symbols.create("builtins")].attrs)[symbols.create(name2)] = v; | ||||||
|     nrValues += 2; |     nrValues += 2; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -124,9 +131,9 @@ void EvalState::addPrimOp(const string & name, | ||||||
|     v.type = tPrimOp; |     v.type = tPrimOp; | ||||||
|     v.primOp.arity = arity; |     v.primOp.arity = arity; | ||||||
|     v.primOp.fun = primOp; |     v.primOp.fun = primOp; | ||||||
|     baseEnv.bindings[name] = v; |     baseEnv.bindings[symbols.create(name)] = v; | ||||||
|     string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; |     string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; | ||||||
|     (*baseEnv.bindings["builtins"].attrs)[name2] = v; |     (*baseEnv.bindings[symbols.create("builtins")].attrs)[symbols.create(name2)] = v; | ||||||
|     nrValues += 2; |     nrValues += 2; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -225,12 +232,12 @@ void mkPath(Value & v, const char * s) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static Value * lookupWith(Env * env, const Sym & name) | Value * EvalState::lookupWith(Env * env, const Symbol & name) | ||||||
| { | { | ||||||
|     if (!env) return 0; |     if (!env) return 0; | ||||||
|     Value * v = lookupWith(env->up, name); |     Value * v = lookupWith(env->up, name); | ||||||
|     if (v) return v; |     if (v) return v; | ||||||
|     Bindings::iterator i = env->bindings.find("<with>"); |     Bindings::iterator i = env->bindings.find(sWith); | ||||||
|     if (i == env->bindings.end()) return 0; |     if (i == env->bindings.end()) return 0; | ||||||
|     Bindings::iterator j = i->second.attrs->find(name); |     Bindings::iterator j = i->second.attrs->find(name); | ||||||
|     if (j != i->second.attrs->end()) return &j->second; |     if (j != i->second.attrs->end()) return &j->second; | ||||||
|  | @ -238,7 +245,7 @@ static Value * lookupWith(Env * env, const Sym & name) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static Value * lookupVar(Env * env, const Sym & name) | Value * EvalState::lookupVar(Env * env, const Symbol & name) | ||||||
| { | { | ||||||
|     /* First look for a regular variable binding for `name'. */ |     /* First look for a regular variable binding for `name'. */ | ||||||
|     for (Env * env2 = env; env2; env2 = env2->up) { |     for (Env * env2 = env; env2; env2 = env2->up) { | ||||||
|  | @ -318,7 +325,7 @@ void EvalState::evalFile(const Path & path, Value & v) | ||||||
|     Expr * e = parseTrees[path]; |     Expr * e = parseTrees[path]; | ||||||
| 
 | 
 | ||||||
|     if (!e) { |     if (!e) { | ||||||
|         e = parseExprFromFile(path); |         e = parseExprFromFile(*this, path); | ||||||
|         parseTrees[path] = e; |         parseTrees[path] = e; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  | @ -428,9 +435,9 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) | ||||||
| 
 | 
 | ||||||
|         /* The inherited attributes, on the other hand, are
 |         /* The inherited attributes, on the other hand, are
 | ||||||
|            evaluated in the original environment. */ |            evaluated in the original environment. */ | ||||||
|         foreach (list<string>::iterator, i, inherited) { |         foreach (list<Symbol>::iterator, i, inherited) { | ||||||
|             Value & v2 = env2.bindings[*i]; |             Value & v2 = env2.bindings[*i]; | ||||||
|             mkCopy(v2, *lookupVar(&env, *i)); |             mkCopy(v2, *state.lookupVar(&env, *i)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -441,9 +448,9 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) | ||||||
|             mkThunk(v2, env, i->second); |             mkThunk(v2, env, i->second); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         foreach (list<string>::iterator, i, inherited) { |         foreach (list<Symbol>::iterator, i, inherited) { | ||||||
|             Value & v2 = (*v.attrs)[*i]; |             Value & v2 = (*v.attrs)[*i]; | ||||||
|             mkCopy(v2, *lookupVar(&env, *i)); |             mkCopy(v2, *state.lookupVar(&env, *i)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -459,7 +466,7 @@ void ExprList::eval(EvalState & state, Env & env, Value & v) | ||||||
| 
 | 
 | ||||||
| void ExprVar::eval(EvalState & state, Env & env, Value & v) | void ExprVar::eval(EvalState & state, Env & env, Value & v) | ||||||
| { | { | ||||||
|     Value * v2 = lookupVar(&env, name); |     Value * v2 = state.lookupVar(&env, name); | ||||||
|     state.forceValue(*v2); |     state.forceValue(*v2); | ||||||
|     v = *v2; |     v = *v2; | ||||||
| } | } | ||||||
|  | @ -631,7 +638,7 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) | ||||||
|     Env & env2(state.allocEnv()); |     Env & env2(state.allocEnv()); | ||||||
|     env2.up = &env; |     env2.up = &env; | ||||||
| 
 | 
 | ||||||
|     Value & vAttrs = env2.bindings["<with>"]; |     Value & vAttrs = env2.bindings[state.sWith]; | ||||||
|     state.eval(env, attrs, vAttrs); |     state.eval(env, attrs, vAttrs); | ||||||
|     state.forceAttrs(vAttrs); |     state.forceAttrs(vAttrs); | ||||||
|          |          | ||||||
|  | @ -871,7 +878,7 @@ string EvalState::forceStringNoCtx(Value & v) | ||||||
| bool EvalState::isDerivation(Value & v) | bool EvalState::isDerivation(Value & v) | ||||||
| { | { | ||||||
|     if (v.type != tAttrs) return false; |     if (v.type != tAttrs) return false; | ||||||
|     Bindings::iterator i = v.attrs->find("type"); |     Bindings::iterator i = v.attrs->find(sType); | ||||||
|     return i != v.attrs->end() && forceStringNoCtx(i->second) == "derivation"; |     return i != v.attrs->end() && forceStringNoCtx(i->second) == "derivation"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -915,7 +922,7 @@ string EvalState::coerceToString(Value & v, PathSet & context, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (v.type == tAttrs) { |     if (v.type == tAttrs) { | ||||||
|         Bindings::iterator i = v.attrs->find("outPath"); |         Bindings::iterator i = v.attrs->find(sOutPath); | ||||||
|         if (i == v.attrs->end()) |         if (i == v.attrs->end()) | ||||||
|             throwTypeError("cannot coerce an attribute set (except a derivation) to a string"); |             throwTypeError("cannot coerce an attribute set (except a derivation) to a string"); | ||||||
|         return coerceToString(i->second, context, coerceMore, copyToStore); |         return coerceToString(i->second, context, coerceMore, copyToStore); | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ | ||||||
| #include <map> | #include <map> | ||||||
| 
 | 
 | ||||||
| #include "nixexpr.hh" | #include "nixexpr.hh" | ||||||
|  | #include "symbol-table.hh" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
|  | @ -14,9 +15,7 @@ class EvalState; | ||||||
| struct Env; | struct Env; | ||||||
| struct Value; | struct Value; | ||||||
| 
 | 
 | ||||||
| typedef string Sym; | typedef std::map<Symbol, Value> Bindings; | ||||||
| 
 |  | ||||||
| typedef std::map<Sym, Value> Bindings; |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| struct Env | struct Env | ||||||
|  | @ -161,6 +160,10 @@ class EvalState | ||||||
| public: | public: | ||||||
|     DrvHashes drvHashes; /* normalised derivation hashes */ |     DrvHashes drvHashes; /* normalised derivation hashes */ | ||||||
| 
 | 
 | ||||||
|  |     SymbolTable symbols; | ||||||
|  | 
 | ||||||
|  |     const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     SrcToStore srcToStore;  |     SrcToStore srcToStore;  | ||||||
| 
 | 
 | ||||||
|  | @ -235,6 +238,13 @@ private: | ||||||
|     void addPrimOp(const string & name, |     void addPrimOp(const string & name, | ||||||
|         unsigned int arity, PrimOp primOp); |         unsigned int arity, PrimOp primOp); | ||||||
| 
 | 
 | ||||||
|  |     Value * lookupVar(Env * env, const Symbol & name); | ||||||
|  |      | ||||||
|  |     Value * lookupWith(Env * env, const Symbol & name); | ||||||
|  | 
 | ||||||
|  |     friend class ExprVar; | ||||||
|  |     friend class ExprAttrs; | ||||||
|  | 
 | ||||||
| public: | public: | ||||||
|      |      | ||||||
|     /* Do a deep equality test between two values.  That is, list
 |     /* Do a deep equality test between two values.  That is, list
 | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ namespace nix { | ||||||
| string DrvInfo::queryDrvPath(EvalState & state) const | string DrvInfo::queryDrvPath(EvalState & state) const | ||||||
| { | { | ||||||
|     if (drvPath == "") { |     if (drvPath == "") { | ||||||
|         Bindings::iterator i = attrs->find("drvPath"); |         Bindings::iterator i = attrs->find(state.sDrvPath); | ||||||
|         PathSet context; |         PathSet context; | ||||||
|         (string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; |         (string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; | ||||||
|     } |     } | ||||||
|  | @ -19,7 +19,7 @@ string DrvInfo::queryDrvPath(EvalState & state) const | ||||||
| string DrvInfo::queryOutPath(EvalState & state) const | string DrvInfo::queryOutPath(EvalState & state) const | ||||||
| { | { | ||||||
|     if (outPath == "") { |     if (outPath == "") { | ||||||
|         Bindings::iterator i = attrs->find("outPath"); |         Bindings::iterator i = attrs->find(state.sOutPath); | ||||||
|         PathSet context; |         PathSet context; | ||||||
|         (string &) outPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; |         (string &) outPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; | ||||||
|     } |     } | ||||||
|  | @ -31,7 +31,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const | ||||||
| { | { | ||||||
|     MetaInfo meta; |     MetaInfo meta; | ||||||
|      |      | ||||||
|     Bindings::iterator a = attrs->find("meta"); |     Bindings::iterator a = attrs->find(state.sMeta); | ||||||
|     if (a == attrs->end()) return meta; /* fine, empty meta information */ |     if (a == attrs->end()) return meta; /* fine, empty meta information */ | ||||||
| 
 | 
 | ||||||
|     state.forceAttrs(a->second); |     state.forceAttrs(a->second); | ||||||
|  | @ -113,12 +113,12 @@ static bool getDerivation(EvalState & state, Value & v, | ||||||
| 
 | 
 | ||||||
|         DrvInfo drv; |         DrvInfo drv; | ||||||
|      |      | ||||||
|         Bindings::iterator i = v.attrs->find("name"); |         Bindings::iterator i = v.attrs->find(state.sName); | ||||||
|         /* !!! We really would like to have a decent back trace here. */ |         /* !!! We really would like to have a decent back trace here. */ | ||||||
|         if (i == v.attrs->end()) throw TypeError("derivation name missing"); |         if (i == v.attrs->end()) throw TypeError("derivation name missing"); | ||||||
|         drv.name = state.forceStringNoCtx(i->second); |         drv.name = state.forceStringNoCtx(i->second); | ||||||
| 
 | 
 | ||||||
|         i = v.attrs->find("system"); |         i = v.attrs->find(state.symbols.create("system")); | ||||||
|         if (i == v.attrs->end()) |         if (i == v.attrs->end()) | ||||||
|             drv.system = "unknown"; |             drv.system = "unknown"; | ||||||
|         else |         else | ||||||
|  | @ -170,7 +170,7 @@ static void getDerivations(EvalState & state, Value & vIn, | ||||||
| 
 | 
 | ||||||
|         /* !!! undocumented hackery to support combining channels in
 |         /* !!! undocumented hackery to support combining channels in
 | ||||||
|            nix-env.cc. */ |            nix-env.cc. */ | ||||||
|         bool combineChannels = v.attrs->find("_combineChannels") != v.attrs->end(); |         bool combineChannels = v.attrs->find(state.symbols.create("_combineChannels")) != v.attrs->end(); | ||||||
| 
 | 
 | ||||||
|         /* Consider the attributes in sorted order to get more
 |         /* Consider the attributes in sorted order to get more
 | ||||||
|            deterministic behaviour in nix-env operations (e.g. when |            deterministic behaviour in nix-env operations (e.g. when | ||||||
|  | @ -184,7 +184,7 @@ static void getDerivations(EvalState & state, Value & vIn, | ||||||
|         foreach (StringSet::iterator, i, attrs) { |         foreach (StringSet::iterator, i, attrs) { | ||||||
|             startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % *i); |             startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % *i); | ||||||
|             string pathPrefix2 = addToPath(pathPrefix, *i); |             string pathPrefix2 = addToPath(pathPrefix, *i); | ||||||
|             Value & v2((*v.attrs)[*i]); |             Value & v2((*v.attrs)[state.symbols.create(*i)]); | ||||||
|             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)) { | ||||||
|  | @ -193,7 +193,7 @@ static void getDerivations(EvalState & state, Value & vIn, | ||||||
|                    if it has a `recurseForDerivations = true' |                    if it has a `recurseForDerivations = true' | ||||||
|                    attribute. */ |                    attribute. */ | ||||||
|                 if (v2.type == tAttrs) { |                 if (v2.type == tAttrs) { | ||||||
|                     Bindings::iterator j = v2.attrs->find("recurseForDerivations"); |                     Bindings::iterator j = v2.attrs->find(state.symbols.create("recurseForDerivations")); | ||||||
|                     if (j != v2.attrs->end() && state.forceBool(j->second)) |                     if (j != v2.attrs->end() && state.forceBool(j->second)) | ||||||
|                         getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); |                         getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  | @ -54,7 +54,7 @@ void ExprAttrs::show(std::ostream & str) | ||||||
| { | { | ||||||
|     if (recursive) str << "rec "; |     if (recursive) str << "rec "; | ||||||
|     str << "{ "; |     str << "{ "; | ||||||
|     foreach (list<string>::iterator, i, inherited) |     foreach (list<Symbol>::iterator, i, inherited) | ||||||
|         str << "inherit " << *i << "; "; |         str << "inherit " << *i << "; "; | ||||||
|     foreach (Attrs::iterator, i, attrs) |     foreach (Attrs::iterator, i, attrs) | ||||||
|         str << i->first << " = " << *i->second << "; "; |         str << i->first << " = " << *i->second << "; "; | ||||||
|  | @ -81,9 +81,9 @@ void ExprLambda::show(std::ostream & str) | ||||||
|             if (i->def) str << " ? " << *i->def; |             if (i->def) str << " ? " << *i->def; | ||||||
|         } |         } | ||||||
|         str << " }"; |         str << " }"; | ||||||
|         if (arg != "") str << " @ "; |         if (!arg.empty()) str << " @ "; | ||||||
|     } |     } | ||||||
|     if (arg != "") str << arg; |     if (!arg.empty()) str << arg; | ||||||
|     str << ": " << *body << ")"; |     str << ": " << *body << ")"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <map> | #include <map> | ||||||
| 
 | 
 | ||||||
| #include "types.hh" | #include "symbol-table.hh" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
|  | @ -75,33 +75,33 @@ struct ExprPath : Expr | ||||||
| 
 | 
 | ||||||
| struct ExprVar : Expr | struct ExprVar : Expr | ||||||
| { | { | ||||||
|     string name; |     Symbol name; | ||||||
|     ExprVar(const string & name) : name(name) { }; |     ExprVar(const Symbol & name) : name(name) { }; | ||||||
|     COMMON_METHODS |     COMMON_METHODS | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct ExprSelect : Expr | struct ExprSelect : Expr | ||||||
| { | { | ||||||
|     Expr * e; |     Expr * e; | ||||||
|     string name; |     Symbol name; | ||||||
|     ExprSelect(Expr * e, const string & name) : e(e), name(name) { }; |     ExprSelect(Expr * e, const Symbol & name) : e(e), name(name) { }; | ||||||
|     COMMON_METHODS |     COMMON_METHODS | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct ExprOpHasAttr : Expr | struct ExprOpHasAttr : Expr | ||||||
| { | { | ||||||
|     Expr * e; |     Expr * e; | ||||||
|     string name; |     Symbol name; | ||||||
|     ExprOpHasAttr(Expr * e, const string & name) : e(e), name(name) { }; |     ExprOpHasAttr(Expr * e, const Symbol & name) : e(e), name(name) { }; | ||||||
|     COMMON_METHODS |     COMMON_METHODS | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct ExprAttrs : Expr | struct ExprAttrs : Expr | ||||||
| { | { | ||||||
|     bool recursive; |     bool recursive; | ||||||
|     typedef std::map<string, Expr *> Attrs; |     typedef std::map<Symbol, Expr *> Attrs; | ||||||
|     Attrs attrs; |     Attrs attrs; | ||||||
|     list<string> inherited; |     list<Symbol> inherited; | ||||||
|     ExprAttrs() : recursive(false) { }; |     ExprAttrs() : recursive(false) { }; | ||||||
|     COMMON_METHODS |     COMMON_METHODS | ||||||
| }; | }; | ||||||
|  | @ -115,9 +115,9 @@ struct ExprList : Expr | ||||||
| 
 | 
 | ||||||
| struct Formal | struct Formal | ||||||
| { | { | ||||||
|     string name; |     Symbol name; | ||||||
|     Expr * def; |     Expr * def; | ||||||
|     Formal(const string & name, Expr * def) : name(name), def(def) { }; |     Formal(const Symbol & name, Expr * def) : name(name), def(def) { }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct Formals | struct Formals | ||||||
|  | @ -130,11 +130,11 @@ struct Formals | ||||||
| struct ExprLambda : Expr | struct ExprLambda : Expr | ||||||
| { | { | ||||||
|     Pos pos; |     Pos pos; | ||||||
|     string arg; |     Symbol arg; | ||||||
|     bool matchAttrs; |     bool matchAttrs; | ||||||
|     Formals * formals; |     Formals * formals; | ||||||
|     Expr * body; |     Expr * body; | ||||||
|     ExprLambda(const Pos & pos, const string & arg, bool matchAttrs, Formals * formals, Expr * body) |     ExprLambda(const Pos & pos, const Symbol & arg, bool matchAttrs, Formals * formals, Expr * body) | ||||||
|         : pos(pos), arg(arg), matchAttrs(matchAttrs), formals(formals), body(body) { }; |         : pos(pos), arg(arg), matchAttrs(matchAttrs), formals(formals), body(body) { }; | ||||||
|     COMMON_METHODS |     COMMON_METHODS | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -9,10 +9,10 @@ namespace nix { | ||||||
| 
 | 
 | ||||||
| /* Parse a Nix expression from the specified file.  If `path' refers
 | /* Parse a Nix expression from the specified file.  If `path' refers
 | ||||||
|    to a directory, then "/default.nix" is appended. */ |    to a directory, then "/default.nix" is appended. */ | ||||||
| Expr * parseExprFromFile(Path path); | Expr * parseExprFromFile(EvalState & state, Path path); | ||||||
| 
 | 
 | ||||||
| /* Parse a Nix expression from the specified string. */ | /* Parse a Nix expression from the specified string. */ | ||||||
| Expr * parseExprFromString(const string & s, const Path & basePath); | Expr * parseExprFromString(EvalState & state, const string & s, const Path & basePath); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -37,17 +37,23 @@ namespace nix { | ||||||
|      |      | ||||||
| struct ParseData  | struct ParseData  | ||||||
| { | { | ||||||
|  |     SymbolTable & symbols; | ||||||
|     Expr * result; |     Expr * result; | ||||||
|     Path basePath; |     Path basePath; | ||||||
|     Path path; |     Path path; | ||||||
|     string error; |     string error; | ||||||
|  |     Symbol sLetBody; | ||||||
|  |     ParseData(SymbolTable & symbols) | ||||||
|  |         : symbols(symbols) | ||||||
|  |         , sLetBody(symbols.create("<let-body>")) | ||||||
|  |     { }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static string showAttrPath(const vector<string> & attrPath) | static string showAttrPath(const vector<Symbol> & attrPath) | ||||||
| { | { | ||||||
|     string s; |     string s; | ||||||
|     foreach (vector<string>::const_iterator, i, attrPath) { |     foreach (vector<Symbol>::const_iterator, i, attrPath) { | ||||||
|         if (!s.empty()) s += '.'; |         if (!s.empty()) s += '.'; | ||||||
|         s += *i; |         s += *i; | ||||||
|     } |     } | ||||||
|  | @ -55,10 +61,11 @@ static string showAttrPath(const vector<string> & attrPath) | ||||||
| } | } | ||||||
|   |   | ||||||
| 
 | 
 | ||||||
| static void addAttr(ExprAttrs * attrs, const vector<string> & attrPath, Expr * e, const Pos & pos) | static void addAttr(ExprAttrs * attrs, const vector<Symbol> & attrPath, | ||||||
|  |     Expr * e, const Pos & pos) | ||||||
| { | { | ||||||
|     unsigned int n = 0; |     unsigned int n = 0; | ||||||
|     foreach (vector<string>::const_iterator, i, attrPath) { |     foreach (vector<Symbol>::const_iterator, i, attrPath) { | ||||||
|         n++; |         n++; | ||||||
|         if (attrs->attrs[*i]) { |         if (attrs->attrs[*i]) { | ||||||
|             ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(attrs->attrs[*i]); |             ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(attrs->attrs[*i]); | ||||||
|  | @ -243,10 +250,10 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err | ||||||
|   nix::Formals * formals; |   nix::Formals * formals; | ||||||
|   nix::Formal * formal; |   nix::Formal * formal; | ||||||
|   int n; |   int n; | ||||||
|   char * id; |   char * id; // !!! -> Symbol | ||||||
|   char * path; |   char * path; | ||||||
|   char * uri; |   char * uri; | ||||||
|   std::vector<std::string> * ids; |   std::vector<nix::Symbol> * ids; | ||||||
|   std::vector<nix::Expr *> * string_parts; |   std::vector<nix::Expr *> * string_parts; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -287,19 +294,19 @@ expr: expr_function; | ||||||
| 
 | 
 | ||||||
| expr_function | expr_function | ||||||
|   : ID ':' expr_function |   : ID ':' expr_function | ||||||
|     { $$ = new ExprLambda(CUR_POS, $1, false, 0, $3); /* checkPatternVars(CUR_POS, $1); $$ = makeFunction($1, $3, CUR_POS); */ } |     { $$ = new ExprLambda(CUR_POS, data->symbols.create($1), false, 0, $3); /* checkPatternVars(CUR_POS, $1); */ } | ||||||
|   | '{' formals '}' ':' expr_function |   | '{' formals '}' ':' expr_function | ||||||
|     { $$ = new ExprLambda(CUR_POS, "", true, $2, $5); } |     { $$ = new ExprLambda(CUR_POS, data->symbols.create(""), true, $2, $5); } | ||||||
|   | '{' formals '}' '@' ID ':' expr_function |   | '{' formals '}' '@' ID ':' expr_function | ||||||
|     { $$ = new ExprLambda(CUR_POS, $5, true, $2, $7); } |     { $$ = new ExprLambda(CUR_POS, data->symbols.create($5), true, $2, $7); } | ||||||
|   | ID '@' '{' formals '}' ':' expr_function |   | ID '@' '{' formals '}' ':' expr_function | ||||||
|     { $$ = new ExprLambda(CUR_POS, $1, true, $4, $7); } |     { $$ = new ExprLambda(CUR_POS, data->symbols.create($1), true, $4, $7); } | ||||||
|   | ASSERT expr ';' expr_function |   | ASSERT expr ';' expr_function | ||||||
|     { $$ = new ExprAssert(CUR_POS, $2, $4); } |     { $$ = new ExprAssert(CUR_POS, $2, $4); } | ||||||
|   | WITH expr ';' expr_function |   | WITH expr ';' expr_function | ||||||
|     { $$ = new ExprWith(CUR_POS, $2, $4); } |     { $$ = new ExprWith(CUR_POS, $2, $4); } | ||||||
|   | LET binds IN expr_function |   | LET binds IN expr_function | ||||||
|     { $2->attrs["<let-body>"] = $4; $2->recursive = true; $$ = new ExprSelect($2, "<let-body>"); } |     { $2->attrs[data->sLetBody] = $4; $2->recursive = true; $$ = new ExprSelect($2, data->sLetBody); } | ||||||
|   | expr_if |   | expr_if | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
|  | @ -316,7 +323,7 @@ expr_op | ||||||
|   | expr_op OR expr_op { $$ = new ExprOpOr($1, $3); } |   | expr_op OR expr_op { $$ = new ExprOpOr($1, $3); } | ||||||
|   | expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); } |   | expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); } | ||||||
|   | expr_op UPDATE expr_op { $$ = new ExprOpUpdate($1, $3); } |   | expr_op UPDATE expr_op { $$ = new ExprOpUpdate($1, $3); } | ||||||
|   | expr_op '?' ID { $$ = new ExprOpHasAttr($1, $3); } |   | expr_op '?' ID { $$ = new ExprOpHasAttr($1, data->symbols.create($3)); } | ||||||
|   | expr_op '+' expr_op |   | expr_op '+' expr_op | ||||||
|     { vector<Expr *> * l = new vector<Expr *>; |     { vector<Expr *> * l = new vector<Expr *>; | ||||||
|       l->push_back($1); |       l->push_back($1); | ||||||
|  | @ -335,12 +342,12 @@ expr_app | ||||||
| 
 | 
 | ||||||
| expr_select | expr_select | ||||||
|   : expr_select '.' ID |   : expr_select '.' ID | ||||||
|     { $$ = new ExprSelect($1, $3); } |     { $$ = new ExprSelect($1, data->symbols.create($3)); } | ||||||
|   | expr_simple { $$ = $1; } |   | expr_simple { $$ = $1; } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| expr_simple | expr_simple | ||||||
|   : ID { $$ = new ExprVar($1); } |   : ID { $$ = new ExprVar(data->symbols.create($1)); } | ||||||
|   | INT { $$ = new ExprInt($1); } |   | INT { $$ = new ExprInt($1); } | ||||||
|   | '"' string_parts '"' { |   | '"' string_parts '"' { | ||||||
|       /* For efficiency, and to simplify parse trees a bit. */ |       /* For efficiency, and to simplify parse trees a bit. */ | ||||||
|  | @ -357,7 +364,7 @@ expr_simple | ||||||
|   /* Let expressions `let {..., body = ...}' are just desugared |   /* Let expressions `let {..., body = ...}' are just desugared | ||||||
|      into `(rec {..., body = ...}).body'. */ |      into `(rec {..., body = ...}).body'. */ | ||||||
|   | LET '{' binds '}' |   | LET '{' binds '}' | ||||||
|     { $3->recursive = true; $$ = new ExprSelect($3, "body"); } |     { $3->recursive = true; $$ = new ExprSelect($3, data->symbols.create("body")); } | ||||||
|   | REC '{' binds '}' |   | REC '{' binds '}' | ||||||
|     { $3->recursive = true; $$ = $3; } |     { $3->recursive = true; $$ = $3; } | ||||||
|   | '{' binds '}' |   | '{' binds '}' | ||||||
|  | @ -381,26 +388,26 @@ binds | ||||||
|   : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, CUR_POS); } |   : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, CUR_POS); } | ||||||
|   | binds INHERIT ids ';' |   | binds INHERIT ids ';' | ||||||
|     { $$ = $1; |     { $$ = $1; | ||||||
|       foreach (vector<string>::iterator, i, *$3) |       foreach (vector<Symbol>::iterator, i, *$3) | ||||||
|         $$->inherited.push_back(*i); |         $$->inherited.push_back(*i); | ||||||
|     } |     } | ||||||
|   | 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<string>::iterator, i, *$6) |       foreach (vector<Symbol>::iterator, i, *$6) | ||||||
|         $$->attrs[*i] = new ExprSelect($4, *i); |         $$->attrs[*i] = new ExprSelect($4, *i); | ||||||
|     } |     } | ||||||
|   | { $$ = new ExprAttrs; } |   | { $$ = new ExprAttrs; } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| ids | ids | ||||||
|   : ids ID { $$ = $1; $1->push_back($2); /* !!! dangerous */ } |   : ids ID { $$ = $1; $1->push_back(data->symbols.create($2)); /* !!! dangerous */ } | ||||||
|   | { $$ = new vector<string>; } |   | { $$ = new vector<Symbol>; } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| attrpath | attrpath | ||||||
|   : attrpath '.' ID { $$ = $1; $1->push_back($3); } |   : attrpath '.' ID { $$ = $1; $1->push_back(data->symbols.create($3)); } | ||||||
|   | ID { $$ = new vector<string>; $$->push_back($1); } |   | ID { $$ = new vector<Symbol>; $$->push_back(data->symbols.create($1)); } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| expr_list | expr_list | ||||||
|  | @ -420,8 +427,8 @@ formals | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
| formal | formal | ||||||
|   : ID { $$ = new Formal($1, 0); } |   : ID { $$ = new Formal(data->symbols.create($1), 0); } | ||||||
|   | ID '?' expr { $$ = new Formal($1, $3); } |   | ID '?' expr { $$ = new Formal(data->symbols.create($1), $3); } | ||||||
|   ; |   ; | ||||||
|    |    | ||||||
| %% | %% | ||||||
|  | @ -432,14 +439,17 @@ formal | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
|  | #include <eval.hh> | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
|        |        | ||||||
| 
 | 
 | ||||||
| static Expr * parse(const char * text, const Path & path, const Path & basePath) | static Expr * parse(EvalState & state, const char * text, | ||||||
|  |     const Path & path, const Path & basePath) | ||||||
| { | { | ||||||
|     yyscan_t scanner; |     yyscan_t scanner; | ||||||
|     ParseData data; |     ParseData data(state.symbols); | ||||||
|     data.basePath = basePath; |     data.basePath = basePath; | ||||||
|     data.path = path; |     data.path = path; | ||||||
| 
 | 
 | ||||||
|  | @ -460,7 +470,7 @@ static Expr * parse(const char * text, const Path & path, const Path & basePath) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Expr * parseExprFromFile(Path path) | Expr * parseExprFromFile(EvalState & state, Path path) | ||||||
| { | { | ||||||
|     assert(path[0] == '/'); |     assert(path[0] == '/'); | ||||||
| 
 | 
 | ||||||
|  | @ -481,13 +491,14 @@ Expr * parseExprFromFile(Path path) | ||||||
|         path = canonPath(path + "/default.nix"); |         path = canonPath(path + "/default.nix"); | ||||||
| 
 | 
 | ||||||
|     /* Read and parse the input file. */ |     /* Read and parse the input file. */ | ||||||
|     return parse(readFile(path).c_str(), path, dirOf(path)); |     return parse(state, readFile(path).c_str(), path, dirOf(path)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Expr * parseExprFromString(const string & s, const Path & basePath) | Expr * parseExprFromString(EvalState & state, | ||||||
|  |     const string & s, const Path & basePath) | ||||||
| { | { | ||||||
|     return parse(s.c_str(), "(string)", basePath); |     return parse(state, s.c_str(), "(string)", basePath); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|   |   | ||||||
|  |  | ||||||
|  | @ -280,7 +280,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) | ||||||
|     state.forceAttrs(*args[0]); |     state.forceAttrs(*args[0]); | ||||||
| 
 | 
 | ||||||
|     /* Figure out the name first (for stack backtraces). */ |     /* Figure out the name first (for stack backtraces). */ | ||||||
|     Bindings::iterator attr = args[0]->attrs->find("name"); |     Bindings::iterator attr = args[0]->attrs->find(state.sName); | ||||||
|     if (attr == args[0]->attrs->end()) |     if (attr == args[0]->attrs->end()) | ||||||
|         throw EvalError("required attribute `name' missing"); |         throw EvalError("required attribute `name' missing"); | ||||||
|     string drvName; |     string drvName; | ||||||
|  | @ -448,8 +448,8 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) | ||||||
| 
 | 
 | ||||||
|     /* !!! assumes a single output */ |     /* !!! assumes a single output */ | ||||||
|     state.mkAttrs(v); |     state.mkAttrs(v); | ||||||
|     mkString((*v.attrs)["outPath"], outPath, singleton<PathSet>(drvPath)); |     mkString((*v.attrs)[state.sOutPath], outPath, singleton<PathSet>(drvPath)); | ||||||
|     mkString((*v.attrs)["drvPath"], drvPath, singleton<PathSet>("=" + drvPath)); |     mkString((*v.attrs)[state.sDrvPath], drvPath, singleton<PathSet>("=" + drvPath)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -667,7 +667,8 @@ static void prim_getAttr(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     string attr = state.forceStringNoCtx(*args[0]); |     string attr = state.forceStringNoCtx(*args[0]); | ||||||
|     state.forceAttrs(*args[1]); |     state.forceAttrs(*args[1]); | ||||||
|     Bindings::iterator i = args[1]->attrs->find(attr); |     // !!! Should we create a symbol here or just do a lookup?
 | ||||||
|  |     Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); | ||||||
|     if (i == args[1]->attrs->end()) |     if (i == args[1]->attrs->end()) | ||||||
|         throw EvalError(format("attribute `%1%' missing") % attr); |         throw EvalError(format("attribute `%1%' missing") % attr); | ||||||
|     state.forceValue(i->second); |     state.forceValue(i->second); | ||||||
|  | @ -680,7 +681,7 @@ static void prim_hasAttr(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     string attr = state.forceStringNoCtx(*args[0]); |     string attr = state.forceStringNoCtx(*args[0]); | ||||||
|     state.forceAttrs(*args[1]); |     state.forceAttrs(*args[1]); | ||||||
|     mkBool(v, args[1]->attrs->find(attr) != args[1]->attrs->end()); |     mkBool(v, args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -701,7 +702,7 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) | ||||||
| 
 | 
 | ||||||
|     for (unsigned int i = 0; i < args[1]->list.length; ++i) { |     for (unsigned int i = 0; i < args[1]->list.length; ++i) { | ||||||
|         state.forceStringNoCtx(args[1]->list.elems[i]); |         state.forceStringNoCtx(args[1]->list.elems[i]); | ||||||
|         v.attrs->erase(args[1]->list.elems[i].string.s); |         v.attrs->erase(state.symbols.create(args[1]->list.elems[i].string.s)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -720,16 +721,16 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) | ||||||
|         Value & v2(args[0]->list.elems[i]); |         Value & v2(args[0]->list.elems[i]); | ||||||
|         state.forceAttrs(v2); |         state.forceAttrs(v2); | ||||||
|          |          | ||||||
|         Bindings::iterator j = v2.attrs->find("name"); |         Bindings::iterator j = v2.attrs->find(state.sName); | ||||||
|         if (j == v2.attrs->end()) |         if (j == v2.attrs->end()) | ||||||
|             throw TypeError("`name' attribute missing in a call to `listToAttrs'"); |             throw TypeError("`name' attribute missing in a call to `listToAttrs'"); | ||||||
|         string name = state.forceStringNoCtx(j->second); |         string name = state.forceStringNoCtx(j->second); | ||||||
|          |          | ||||||
|         j = v2.attrs->find("value"); |         j = v2.attrs->find(state.symbols.create("value")); | ||||||
|         if (j == v2.attrs->end()) |         if (j == v2.attrs->end()) | ||||||
|             throw TypeError("`value' attribute missing in a call to `listToAttrs'"); |             throw TypeError("`value' attribute missing in a call to `listToAttrs'"); | ||||||
| 
 | 
 | ||||||
|         (*v.attrs)[name] = j->second; // !!! sharing?
 |         (*v.attrs)[state.symbols.create(name)] = j->second; // !!! sharing?
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -976,8 +977,8 @@ static void prim_parseDrvName(EvalState & state, Value * * args, Value & v) | ||||||
|     string name = state.forceStringNoCtx(*args[0]); |     string name = state.forceStringNoCtx(*args[0]); | ||||||
|     DrvName parsed(name); |     DrvName parsed(name); | ||||||
|     state.mkAttrs(v); |     state.mkAttrs(v); | ||||||
|     mkString((*v.attrs)["name"], parsed.name); |     mkString((*v.attrs)[state.sName], parsed.name); | ||||||
|     mkString((*v.attrs)["version"], parsed.version); |     mkString((*v.attrs)[state.symbols.create("version")], parsed.version); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -998,7 +999,7 @@ void EvalState::createBaseEnv() | ||||||
| { | { | ||||||
|     baseEnv.up = 0; |     baseEnv.up = 0; | ||||||
| 
 | 
 | ||||||
|     Value & builtins = baseEnv.bindings["builtins"]; |     Value & builtins = baseEnv.bindings[symbols.create("builtins")]; | ||||||
|     builtins.type = tAttrs; |     builtins.type = tAttrs; | ||||||
|     builtins.attrs = new Bindings; |     builtins.attrs = new Bindings; | ||||||
| 
 | 
 | ||||||
|  | @ -1023,7 +1024,7 @@ void EvalState::createBaseEnv() | ||||||
|     /* Add a wrapper around the derivation primop that computes the
 |     /* Add a wrapper around the derivation primop that computes the
 | ||||||
|        `drvPath' and `outPath' attributes lazily. */ |        `drvPath' and `outPath' attributes lazily. */ | ||||||
|     string s = "attrs: let res = derivationStrict attrs; in attrs // { drvPath = res.drvPath; outPath = res.outPath; type = \"derivation\"; }"; |     string s = "attrs: let res = derivationStrict attrs; in attrs // { drvPath = res.drvPath; outPath = res.outPath; type = \"derivation\"; }"; | ||||||
|     mkThunk(v, baseEnv, parseExprFromString(s, "/")); |     mkThunk(v, baseEnv, parseExprFromString(*this, s, "/")); | ||||||
|     addConstant("derivation", v); |     addConstant("derivation", v); | ||||||
| 
 | 
 | ||||||
|     // Miscellaneous
 |     // Miscellaneous
 | ||||||
|  |  | ||||||
							
								
								
									
										75
									
								
								src/libexpr/symbol-table.hh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/libexpr/symbol-table.hh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,75 @@ | ||||||
|  | #ifndef __SYMBOL_TABLE_H | ||||||
|  | #define __SYMBOL_TABLE_H | ||||||
|  | 
 | ||||||
|  | #include <map> | ||||||
|  | 
 | ||||||
|  | #include "types.hh" | ||||||
|  | 
 | ||||||
|  | namespace nix { | ||||||
|  | 
 | ||||||
|  | /* Symbol table used by the parser and evaluator to represent and look
 | ||||||
|  |    up identifiers and attribute sets efficiently. | ||||||
|  |    SymbolTable::create() converts a string into a symbol.  Symbols | ||||||
|  |    have the property that they can be compared efficiently (using a | ||||||
|  |    pointer equality test), because the symbol table stores only one | ||||||
|  |    copy of each string. */ | ||||||
|  | 
 | ||||||
|  | class Symbol | ||||||
|  | { | ||||||
|  | private: | ||||||
|  |     const string * s; // pointer into SymbolTable
 | ||||||
|  |     Symbol(const string * s) : s(s) { }; | ||||||
|  |     friend class SymbolTable; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     bool operator == (const Symbol & s2) const | ||||||
|  |     { | ||||||
|  |         return s == s2.s; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     bool operator != (const Symbol & s2) const | ||||||
|  |     { | ||||||
|  |         return s != s2.s; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     bool operator < (const Symbol & s2) const | ||||||
|  |     { | ||||||
|  |         return s < s2.s; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     operator const string & () const | ||||||
|  |     { | ||||||
|  |         return *s; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool empty() const | ||||||
|  |     { | ||||||
|  |         return s->empty(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     friend std::ostream & operator << (std::ostream & str, const Symbol & sym); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | inline std::ostream & operator << (std::ostream & str, const Symbol & sym) | ||||||
|  | { | ||||||
|  |     str << *sym.s; | ||||||
|  |     return str; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class SymbolTable | ||||||
|  | { | ||||||
|  | private: | ||||||
|  |     typedef std::set<string> Symbols; | ||||||
|  |     Symbols symbols; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     Symbol create(const string & s) | ||||||
|  |     { | ||||||
|  |         std::pair<Symbols::iterator, bool> res = symbols.insert(s); | ||||||
|  |         return Symbol(&*res.first); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif /* !__SYMBOL_TABLE_H */ | ||||||
|  | @ -28,7 +28,7 @@ static void showAttrs(EvalState & state, bool strict, Bindings & attrs, | ||||||
|         names.insert(i->first); |         names.insert(i->first); | ||||||
|     foreach (StringSet::iterator, i, names) { |     foreach (StringSet::iterator, i, names) { | ||||||
|         XMLOpenElement _(doc, "attr", singletonAttrs("name", *i)); |         XMLOpenElement _(doc, "attr", singletonAttrs("name", *i)); | ||||||
|         printValueAsXML(state, strict, attrs[*i], doc, context, drvsSeen); |         printValueAsXML(state, strict, attrs[state.symbols.create(*i)], doc, context, drvsSeen); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -67,14 +67,14 @@ static void printValueAsXML(EvalState & state, bool strict, Value & v, | ||||||
|             if (state.isDerivation(v)) { |             if (state.isDerivation(v)) { | ||||||
|                 XMLAttrs xmlAttrs; |                 XMLAttrs xmlAttrs; | ||||||
|              |              | ||||||
|                 Bindings::iterator a = v.attrs->find("derivation"); |                 Bindings::iterator a = v.attrs->find(state.symbols.create("derivation")); | ||||||
| 
 | 
 | ||||||
|                 Path drvPath; |                 Path drvPath; | ||||||
|                 a = v.attrs->find("drvPath"); |                 a = v.attrs->find(state.sDrvPath); | ||||||
|                 if (a != v.attrs->end() && a->second.type == tString) |                 if (a != v.attrs->end() && a->second.type == tString) | ||||||
|                     xmlAttrs["drvPath"] = drvPath = a->second.string.s; |                     xmlAttrs["drvPath"] = drvPath = a->second.string.s; | ||||||
|          |          | ||||||
|                 a = v.attrs->find("outPath"); |                 a = v.attrs->find(state.sOutPath); | ||||||
|                 if (a != v.attrs->end() && a->second.type == tString) |                 if (a != v.attrs->end() && a->second.type == tString) | ||||||
|                     xmlAttrs["outPath"] = a->second.string.s; |                     xmlAttrs["outPath"] = a->second.string.s; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ static Expr * parseStdin(EvalState & state) | ||||||
|     startNest(nest, lvlTalkative, format("parsing standard input")); |     startNest(nest, lvlTalkative, format("parsing standard input")); | ||||||
|     string s, s2; |     string s, s2; | ||||||
|     while (getline(std::cin, s2)) s += s2 + "\n"; |     while (getline(std::cin, s2)) s += s2 + "\n"; | ||||||
|     return parseExprFromString(s, absPath(".")); |     return parseExprFromString(state, s, absPath(".")); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -136,7 +136,7 @@ void run(Strings args) | ||||||
| 
 | 
 | ||||||
|     foreach (Strings::iterator, i, files) { |     foreach (Strings::iterator, i, files) { | ||||||
|         Path path = absPath(*i); |         Path path = absPath(*i); | ||||||
|         Expr * e = parseExprFromFile(path); |         Expr * e = parseExprFromFile(state, path); | ||||||
|         processExpr(state, attrPaths, parseOnly, strict, autoArgs, |         processExpr(state, attrPaths, parseOnly, strict, autoArgs, | ||||||
|             evalOnly, xmlOutput, e); |             evalOnly, xmlOutput, e); | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue