forked from lix-project/lix
* 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
|
@ -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));
|
||||||
|
|
|
@ -43,8 +43,8 @@ std::ostream & operator << (std::ostream & str, Value & v)
|
||||||
break;
|
break;
|
||||||
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…
Reference in a new issue