Merge branch 'dynamic-attrs-no-sugar' of github.com:shlevy/nix
This commit is contained in:
commit
7a61c88dbb
|
@ -129,6 +129,18 @@ string showType(const Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Symbol getName(const AttrName & name, EvalState & state, Env & env) {
|
||||||
|
if (name.symbol.set()) {
|
||||||
|
return name.symbol;
|
||||||
|
} else {
|
||||||
|
Value nameValue;
|
||||||
|
name.expr->eval(state, env, nameValue);
|
||||||
|
state.forceStringNoCtx(nameValue);
|
||||||
|
return state.symbols.create(nameValue.string.s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
EvalState::EvalState()
|
EvalState::EvalState()
|
||||||
: sWith(symbols.create("<with>"))
|
: sWith(symbols.create("<with>"))
|
||||||
, sOutPath(symbols.create("outPath"))
|
, sOutPath(symbols.create("outPath"))
|
||||||
|
@ -247,6 +259,11 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, con
|
||||||
throw EvalError(format(s) % s2 % s3);
|
throw EvalError(format(s) % s2 % s3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocalNoInlineNoReturn(void throwEvalError(const char * s, const Symbol & sym, const Pos & p1, const Pos & p2))
|
||||||
|
{
|
||||||
|
throw EvalError(format(s) % sym % p1 % p2);
|
||||||
|
}
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwTypeError(const char * s))
|
LocalNoInlineNoReturn(void throwTypeError(const char * s))
|
||||||
{
|
{
|
||||||
throw TypeError(s);
|
throw TypeError(s);
|
||||||
|
@ -557,12 +574,14 @@ void ExprPath::eval(EvalState & state, Env & env, Value & v)
|
||||||
void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
state.mkAttrs(v, attrs.size());
|
state.mkAttrs(v, attrs.size());
|
||||||
|
Env *dynamicEnv = &env;
|
||||||
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
/* Create a new environment that contains the attributes in
|
/* Create a new environment that contains the attributes in
|
||||||
this `rec'. */
|
this `rec'. */
|
||||||
Env & env2(state.allocEnv(attrs.size()));
|
Env & env2(state.allocEnv(attrs.size()));
|
||||||
env2.up = &env;
|
env2.up = &env;
|
||||||
|
dynamicEnv = &env2;
|
||||||
|
|
||||||
AttrDefs::iterator overrides = attrs.find(state.sOverrides);
|
AttrDefs::iterator overrides = attrs.find(state.sOverrides);
|
||||||
bool hasOverrides = overrides != attrs.end();
|
bool hasOverrides = overrides != attrs.end();
|
||||||
|
@ -605,9 +624,24 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
foreach (AttrDefs::iterator, i, attrs)
|
||||||
v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
|
v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
|
||||||
|
|
||||||
|
/* dynamic attrs apply *after* rec and __overrides */
|
||||||
|
foreach (DynamicAttrDefs::iterator, i, dynamicAttrs) {
|
||||||
|
Value nameVal;
|
||||||
|
i->nameExpr->eval(state, *dynamicEnv, nameVal);
|
||||||
|
state.forceStringNoCtx(nameVal);
|
||||||
|
Symbol nameSym = state.symbols.create(nameVal.string.s);
|
||||||
|
Bindings::iterator j = v.attrs->find(nameSym);
|
||||||
|
if (j != v.attrs->end())
|
||||||
|
throwEvalError("dynamic attribute `%1%' at %2% already defined at %3%", nameSym, i->pos, *j->pos);
|
||||||
|
|
||||||
|
i->valueExpr->setName(nameSym);
|
||||||
|
/* Keep sorted order so find can catch duplicates */
|
||||||
|
v.attrs->insert(lower_bound(v.attrs->begin(), v.attrs->end(), Attr(nameSym, 0)),
|
||||||
|
Attr(nameSym, i->valueExpr->maybeThunk(state, *dynamicEnv), &i->pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,17 +695,18 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||||
foreach (AttrPath::const_iterator, i, attrPath) {
|
foreach (AttrPath::const_iterator, i, attrPath) {
|
||||||
nrLookups++;
|
nrLookups++;
|
||||||
Bindings::iterator j;
|
Bindings::iterator j;
|
||||||
|
Symbol name = getName(*i, state, env);
|
||||||
if (def) {
|
if (def) {
|
||||||
state.forceValue(*vAttrs);
|
state.forceValue(*vAttrs);
|
||||||
if (vAttrs->type != tAttrs ||
|
if (vAttrs->type != tAttrs ||
|
||||||
(j = vAttrs->attrs->find(*i)) == vAttrs->attrs->end())
|
(j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
|
||||||
{
|
{
|
||||||
def->eval(state, env, v);
|
def->eval(state, env, v);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state.forceAttrs(*vAttrs);
|
state.forceAttrs(*vAttrs);
|
||||||
if ((j = vAttrs->attrs->find(*i)) == vAttrs->attrs->end())
|
if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
|
||||||
throwEvalError("attribute `%1%' missing", showAttrPath(attrPath));
|
throwEvalError("attribute `%1%' missing", showAttrPath(attrPath));
|
||||||
}
|
}
|
||||||
vAttrs = j->value;
|
vAttrs = j->value;
|
||||||
|
@ -702,8 +737,9 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
|
||||||
foreach (AttrPath::const_iterator, i, attrPath) {
|
foreach (AttrPath::const_iterator, i, attrPath) {
|
||||||
state.forceValue(*vAttrs);
|
state.forceValue(*vAttrs);
|
||||||
Bindings::iterator j;
|
Bindings::iterator j;
|
||||||
|
Symbol name = getName(*i, state, env);
|
||||||
if (vAttrs->type != tAttrs ||
|
if (vAttrs->type != tAttrs ||
|
||||||
(j = vAttrs->attrs->find(*i)) == vAttrs->attrs->end())
|
(j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
|
||||||
{
|
{
|
||||||
mkBool(v, false);
|
mkBool(v, false);
|
||||||
return;
|
return;
|
||||||
|
@ -908,6 +944,17 @@ void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprBuiltin::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
// Not a hot path at all, but would be nice to access state.baseEnv directly
|
||||||
|
Env *baseEnv = &env;
|
||||||
|
while (baseEnv->up) baseEnv = baseEnv->up;
|
||||||
|
Bindings::iterator binding = baseEnv->values[0]->attrs->find(name);
|
||||||
|
assert(binding != baseEnv->values[0]->attrs->end());
|
||||||
|
v = *binding->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprOpEq::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpEq::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value v1; e1->eval(state, env, v1);
|
Value v1; e1->eval(state, env, v1);
|
||||||
|
|
|
@ -61,6 +61,8 @@ void ExprAttrs::show(std::ostream & str)
|
||||||
str << "inherit " << i->first << " " << "; ";
|
str << "inherit " << i->first << " " << "; ";
|
||||||
else
|
else
|
||||||
str << i->first << " = " << *i->second.e << "; ";
|
str << i->first << " = " << *i->second.e << "; ";
|
||||||
|
foreach (DynamicAttrDefs::iterator, i, dynamicAttrs)
|
||||||
|
str << "\"${" << *i->nameExpr << "}\" = " << *i->valueExpr << "; ";
|
||||||
str << "}";
|
str << "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +123,11 @@ void ExprOpNot::show(std::ostream & str)
|
||||||
str << "! " << *e;
|
str << "! " << *e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExprBuiltin::show(std::ostream & str)
|
||||||
|
{
|
||||||
|
str << "builtins." << name;
|
||||||
|
}
|
||||||
|
|
||||||
void ExprConcatStrings::show(std::ostream & str)
|
void ExprConcatStrings::show(std::ostream & str)
|
||||||
{
|
{
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
@ -148,12 +155,19 @@ std::ostream & operator << (std::ostream & str, const Pos & pos)
|
||||||
|
|
||||||
string showAttrPath(const AttrPath & attrPath)
|
string showAttrPath(const AttrPath & attrPath)
|
||||||
{
|
{
|
||||||
string s;
|
std::ostringstream out;
|
||||||
|
bool first = true;
|
||||||
foreach (AttrPath::const_iterator, i, attrPath) {
|
foreach (AttrPath::const_iterator, i, attrPath) {
|
||||||
if (!s.empty()) s += '.';
|
if (!first)
|
||||||
s += *i;
|
out << '.';
|
||||||
|
else
|
||||||
|
first = false;
|
||||||
|
if (i->symbol.set())
|
||||||
|
out << i->symbol;
|
||||||
|
else
|
||||||
|
out << "\"${" << *i->expr << "}\"";
|
||||||
}
|
}
|
||||||
return s;
|
return out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -213,17 +227,25 @@ void ExprSelect::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
e->bindVars(env);
|
e->bindVars(env);
|
||||||
if (def) def->bindVars(env);
|
if (def) def->bindVars(env);
|
||||||
|
foreach (AttrPath::iterator, i, attrPath)
|
||||||
|
if (!i->symbol.set())
|
||||||
|
i->expr->bindVars(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprOpHasAttr::bindVars(const StaticEnv & env)
|
void ExprOpHasAttr::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
e->bindVars(env);
|
e->bindVars(env);
|
||||||
|
foreach (AttrPath::iterator, i, attrPath)
|
||||||
|
if (!i->symbol.set())
|
||||||
|
i->expr->bindVars(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprAttrs::bindVars(const StaticEnv & env)
|
void ExprAttrs::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
|
const StaticEnv *dynamicEnv = &env;
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
StaticEnv newEnv(false, &env);
|
StaticEnv newEnv(false, &env);
|
||||||
|
dynamicEnv = &newEnv;
|
||||||
|
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
foreach (AttrDefs::iterator, i, attrs)
|
||||||
|
@ -236,6 +258,11 @@ void ExprAttrs::bindVars(const StaticEnv & env)
|
||||||
else
|
else
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
foreach (AttrDefs::iterator, i, attrs)
|
||||||
i->second.e->bindVars(env);
|
i->second.e->bindVars(env);
|
||||||
|
|
||||||
|
foreach (DynamicAttrDefs::iterator, i, dynamicAttrs) {
|
||||||
|
i->nameExpr->bindVars(*dynamicEnv);
|
||||||
|
i->valueExpr->bindVars(*dynamicEnv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprList::bindVars(const StaticEnv & env)
|
void ExprList::bindVars(const StaticEnv & env)
|
||||||
|
@ -314,6 +341,10 @@ void ExprOpNot::bindVars(const StaticEnv & env)
|
||||||
e->bindVars(env);
|
e->bindVars(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExprBuiltin::bindVars(const StaticEnv & env)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void ExprConcatStrings::bindVars(const StaticEnv & env)
|
void ExprConcatStrings::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
foreach (vector<Expr *>::iterator, i, *es)
|
foreach (vector<Expr *>::iterator, i, *es)
|
||||||
|
|
|
@ -50,10 +50,19 @@ struct Env;
|
||||||
struct Value;
|
struct Value;
|
||||||
struct EvalState;
|
struct EvalState;
|
||||||
struct StaticEnv;
|
struct StaticEnv;
|
||||||
|
struct Expr;
|
||||||
|
|
||||||
|
|
||||||
/* An attribute path is a sequence of attribute names. */
|
/* An attribute path is a sequence of attribute names. */
|
||||||
typedef vector<Symbol> AttrPath;
|
struct AttrName
|
||||||
|
{
|
||||||
|
Symbol symbol;
|
||||||
|
Expr *expr;
|
||||||
|
AttrName(const Symbol & s) : symbol(s) {};
|
||||||
|
AttrName(Expr *e) : expr(e) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<AttrName> AttrPath;
|
||||||
|
|
||||||
string showAttrPath(const AttrPath & attrPath);
|
string showAttrPath(const AttrPath & attrPath);
|
||||||
|
|
||||||
|
@ -138,7 +147,7 @@ struct ExprSelect : Expr
|
||||||
Expr * e, * def;
|
Expr * e, * def;
|
||||||
AttrPath attrPath;
|
AttrPath attrPath;
|
||||||
ExprSelect(Expr * e, const AttrPath & attrPath, Expr * def) : e(e), def(def), attrPath(attrPath) { };
|
ExprSelect(Expr * e, const AttrPath & attrPath, Expr * def) : e(e), def(def), attrPath(attrPath) { };
|
||||||
ExprSelect(Expr * e, const Symbol & name) : e(e), def(0) { attrPath.push_back(name); };
|
ExprSelect(Expr * e, const Symbol & name) : e(e), def(0) { attrPath.push_back(AttrName(name)); };
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -163,6 +172,14 @@ struct ExprAttrs : Expr
|
||||||
};
|
};
|
||||||
typedef std::map<Symbol, AttrDef> AttrDefs;
|
typedef std::map<Symbol, AttrDef> AttrDefs;
|
||||||
AttrDefs attrs;
|
AttrDefs attrs;
|
||||||
|
struct DynamicAttrDef {
|
||||||
|
Expr * nameExpr;
|
||||||
|
Expr * valueExpr;
|
||||||
|
Pos pos;
|
||||||
|
DynamicAttrDef(Expr * nameExpr, Expr * valueExpr, const Pos & pos) : nameExpr(nameExpr), valueExpr(valueExpr), pos(pos) { };
|
||||||
|
};
|
||||||
|
typedef std::vector<DynamicAttrDef> DynamicAttrDefs;
|
||||||
|
DynamicAttrDefs dynamicAttrs;
|
||||||
ExprAttrs() : recursive(false) { };
|
ExprAttrs() : recursive(false) { };
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
};
|
};
|
||||||
|
@ -248,6 +265,13 @@ struct ExprOpNot : Expr
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ExprBuiltin : Expr
|
||||||
|
{
|
||||||
|
Symbol name;
|
||||||
|
ExprBuiltin(const Symbol & name) : name(name) { };
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
#define MakeBinOp(name, s) \
|
#define MakeBinOp(name, s) \
|
||||||
struct Expr##name : Expr \
|
struct Expr##name : Expr \
|
||||||
{ \
|
{ \
|
||||||
|
|
|
@ -74,37 +74,49 @@ static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & prev
|
||||||
|
|
||||||
static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
|
static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
|
||||||
{
|
{
|
||||||
AttrPath attrPath; attrPath.push_back(attr);
|
|
||||||
throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
|
throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
|
||||||
% showAttrPath(attrPath) % pos % prevPos);
|
% attr % pos % prevPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
|
static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
|
||||||
Expr * e, const Pos & pos)
|
Expr * e, const Pos & pos)
|
||||||
{
|
{
|
||||||
unsigned int n = 0;
|
AttrPath::iterator i;
|
||||||
foreach (AttrPath::const_iterator, i, attrPath) {
|
// All attrpaths have at least one attr
|
||||||
n++;
|
assert(!attrPath.empty());
|
||||||
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(*i);
|
for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
|
||||||
|
if (i->symbol.set()) {
|
||||||
|
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
|
||||||
if (j != attrs->attrs.end()) {
|
if (j != attrs->attrs.end()) {
|
||||||
if (!j->second.inherited) {
|
if (!j->second.inherited) {
|
||||||
ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.e);
|
ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.e);
|
||||||
if (!attrs2 || n == attrPath.size()) dupAttr(attrPath, pos, j->second.pos);
|
if (!attrs2) dupAttr(attrPath, pos, j->second.pos);
|
||||||
attrs = attrs2;
|
attrs = attrs2;
|
||||||
} else
|
} else
|
||||||
dupAttr(attrPath, pos, j->second.pos);
|
dupAttr(attrPath, pos, j->second.pos);
|
||||||
} else {
|
} else {
|
||||||
if (n == attrPath.size())
|
|
||||||
attrs->attrs[*i] = ExprAttrs::AttrDef(e, pos);
|
|
||||||
else {
|
|
||||||
ExprAttrs * nested = new ExprAttrs;
|
ExprAttrs * nested = new ExprAttrs;
|
||||||
attrs->attrs[*i] = ExprAttrs::AttrDef(nested, pos);
|
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(nested, pos);
|
||||||
|
attrs = nested;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ExprAttrs *nested = new ExprAttrs;
|
||||||
|
attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, nested, pos));
|
||||||
attrs = nested;
|
attrs = nested;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (i->symbol.set()) {
|
||||||
|
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
|
||||||
|
if (j != attrs->attrs.end()) {
|
||||||
|
dupAttr(attrPath, pos, j->second.pos);
|
||||||
|
} else {
|
||||||
|
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(e, pos);
|
||||||
|
e->setName(i->symbol);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, e, pos));
|
||||||
}
|
}
|
||||||
e->setName(attrPath.back());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -243,7 +255,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
|
||||||
char * id; // !!! -> Symbol
|
char * id; // !!! -> Symbol
|
||||||
char * path;
|
char * path;
|
||||||
char * uri;
|
char * uri;
|
||||||
std::vector<nix::Symbol> * attrNames;
|
std::vector<nix::AttrName> * attrNames;
|
||||||
std::vector<nix::Expr *> * string_parts;
|
std::vector<nix::Expr *> * string_parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +266,8 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
|
||||||
%type <formals> formals
|
%type <formals> formals
|
||||||
%type <formal> formal
|
%type <formal> formal
|
||||||
%type <attrNames> attrs attrpath
|
%type <attrNames> attrs attrpath
|
||||||
%type <string_parts> string_parts ind_string_parts
|
%type <string_parts> string_parts_interpolated ind_string_parts
|
||||||
|
%type <e> string_parts string_attr
|
||||||
%type <id> attr
|
%type <id> attr
|
||||||
%token <id> ID ATTRPATH
|
%token <id> ID ATTRPATH
|
||||||
%token <e> STR IND_STR
|
%token <e> STR IND_STR
|
||||||
|
@ -300,7 +313,11 @@ expr_function
|
||||||
| 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
|
||||||
{ $$ = new ExprLet($2, $4); }
|
{ if (!$2->dynamicAttrs.empty())
|
||||||
|
throw ParseError(format("dynamic attributes not allowed in let at %1%")
|
||||||
|
% CUR_POS);
|
||||||
|
$$ = new ExprLet($2, $4);
|
||||||
|
}
|
||||||
| expr_if
|
| expr_if
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -311,13 +328,13 @@ expr_if
|
||||||
|
|
||||||
expr_op
|
expr_op
|
||||||
: '!' expr_op %prec NOT { $$ = new ExprOpNot($2); }
|
: '!' expr_op %prec NOT { $$ = new ExprOpNot($2); }
|
||||||
| '-' expr_op %prec NEGATE { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__sub")), new ExprInt(0)), $2); }
|
| '-' expr_op %prec NEGATE { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("sub")), new ExprInt(0)), $2); }
|
||||||
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
|
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
|
||||||
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
|
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
|
||||||
| expr_op '<' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $1), $3); }
|
| expr_op '<' expr_op { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $1), $3); }
|
||||||
| expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $3), $1)); }
|
| expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $3), $1)); }
|
||||||
| expr_op '>' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $3), $1); }
|
| expr_op '>' expr_op { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $3), $1); }
|
||||||
| expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $1), $3)); }
|
| expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $1), $3)); }
|
||||||
| expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); }
|
| expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); }
|
||||||
| 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); }
|
||||||
|
@ -329,9 +346,9 @@ expr_op
|
||||||
l->push_back($3);
|
l->push_back($3);
|
||||||
$$ = new ExprConcatStrings(false, l);
|
$$ = new ExprConcatStrings(false, l);
|
||||||
}
|
}
|
||||||
| expr_op '-' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__sub")), $1), $3); }
|
| expr_op '-' expr_op { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("sub")), $1), $3); }
|
||||||
| expr_op '*' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__mul")), $1), $3); }
|
| expr_op '*' expr_op { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("mul")), $1), $3); }
|
||||||
| expr_op '/' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__div")), $1), $3); }
|
| expr_op '/' expr_op { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("div")), $1), $3); }
|
||||||
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
|
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
|
||||||
| expr_app
|
| expr_app
|
||||||
;
|
;
|
||||||
|
@ -362,12 +379,7 @@ expr_simple
|
||||||
$$ = new ExprVar(CUR_POS, data->symbols.create($1));
|
$$ = new ExprVar(CUR_POS, data->symbols.create($1));
|
||||||
}
|
}
|
||||||
| INT { $$ = new ExprInt($1); }
|
| INT { $$ = new ExprInt($1); }
|
||||||
| '"' string_parts '"' {
|
| '"' string_parts '"' { $$ = $2; }
|
||||||
/* For efficiency, and to simplify parse trees a bit. */
|
|
||||||
if ($2->empty()) $$ = new ExprString(data->symbols.create(""));
|
|
||||||
else if ($2->size() == 1 && dynamic_cast<ExprString *>($2->front())) $$ = $2->front();
|
|
||||||
else $$ = new ExprConcatStrings(true, $2);
|
|
||||||
}
|
|
||||||
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
||||||
$$ = stripIndentation(data->symbols, *$2);
|
$$ = stripIndentation(data->symbols, *$2);
|
||||||
}
|
}
|
||||||
|
@ -381,7 +393,7 @@ expr_simple
|
||||||
‘throw’. */
|
‘throw’. */
|
||||||
$$ = path2 == ""
|
$$ = path2 == ""
|
||||||
? (Expr * ) new ExprApp(
|
? (Expr * ) new ExprApp(
|
||||||
new ExprVar(noPos, data->symbols.create("throw")),
|
new ExprBuiltin(data->symbols.create("throw")),
|
||||||
new ExprString(data->symbols.create(
|
new ExprString(data->symbols.create(
|
||||||
(format("file `%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)") % path).str())))
|
(format("file `%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)") % path).str())))
|
||||||
: (Expr * ) new ExprPath(path2);
|
: (Expr * ) new ExprPath(path2);
|
||||||
|
@ -400,9 +412,27 @@ expr_simple
|
||||||
;
|
;
|
||||||
|
|
||||||
string_parts
|
string_parts
|
||||||
: string_parts STR { $$ = $1; $1->push_back($2); }
|
: STR
|
||||||
| string_parts DOLLAR_CURLY expr '}' { backToString(scanner); $$ = $1; $1->push_back($3); }
|
| string_parts_interpolated { $$ = new ExprConcatStrings(true, $1); }
|
||||||
| { $$ = new vector<Expr *>; }
|
| { $$ = new ExprString(data->symbols.create("")) }
|
||||||
|
;
|
||||||
|
|
||||||
|
string_parts_interpolated
|
||||||
|
: string_parts_interpolated STR { $$ = $1; $1->push_back($2); }
|
||||||
|
| string_parts_interpolated DOLLAR_CURLY expr '}' { backToString(scanner); $$ = $1; $1->push_back($3); }
|
||||||
|
| STR DOLLAR_CURLY expr '}'
|
||||||
|
{
|
||||||
|
backToString(scanner);
|
||||||
|
$$ = new vector<Expr *>;
|
||||||
|
$$->push_back($1);
|
||||||
|
$$->push_back($3);
|
||||||
|
}
|
||||||
|
| DOLLAR_CURLY expr '}'
|
||||||
|
{
|
||||||
|
backToString(scanner);
|
||||||
|
$$ = new vector<Expr *>;
|
||||||
|
$$->push_back($2);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
ind_string_parts
|
ind_string_parts
|
||||||
|
@ -416,39 +446,69 @@ binds
|
||||||
| binds INHERIT attrs ';'
|
| binds INHERIT attrs ';'
|
||||||
{ $$ = $1;
|
{ $$ = $1;
|
||||||
foreach (AttrPath::iterator, i, *$3) {
|
foreach (AttrPath::iterator, i, *$3) {
|
||||||
if ($$->attrs.find(*i) != $$->attrs.end())
|
if ($$->attrs.find(i->symbol) != $$->attrs.end())
|
||||||
dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos);
|
dupAttr(i->symbol, makeCurPos(@3, data), $$->attrs[i->symbol].pos);
|
||||||
Pos pos = makeCurPos(@3, data);
|
Pos pos = makeCurPos(@3, data);
|
||||||
$$->attrs[*i] = ExprAttrs::AttrDef(new ExprVar(CUR_POS, *i), pos, true);
|
$$->attrs[i->symbol] = ExprAttrs::AttrDef(new ExprVar(CUR_POS, i->symbol), pos, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| binds INHERIT '(' expr ')' attrs ';'
|
| binds INHERIT '(' expr ')' attrs ';'
|
||||||
{ $$ = $1;
|
{ $$ = $1;
|
||||||
/* !!! Should ensure sharing of the expression in $4. */
|
/* !!! Should ensure sharing of the expression in $4. */
|
||||||
foreach (vector<Symbol>::iterator, i, *$6) {
|
foreach (AttrPath::iterator, i, *$6) {
|
||||||
if ($$->attrs.find(*i) != $$->attrs.end())
|
if ($$->attrs.find(i->symbol) != $$->attrs.end())
|
||||||
dupAttr(*i, makeCurPos(@6, data), $$->attrs[*i].pos);
|
dupAttr(i->symbol, makeCurPos(@6, data), $$->attrs[i->symbol].pos);
|
||||||
$$->attrs[*i] = ExprAttrs::AttrDef(new ExprSelect($4, *i), makeCurPos(@6, data));
|
$$->attrs[i->symbol] = ExprAttrs::AttrDef(new ExprSelect($4, i->symbol), makeCurPos(@6, data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| { $$ = new ExprAttrs; }
|
| { $$ = new ExprAttrs; }
|
||||||
;
|
;
|
||||||
|
|
||||||
attrs
|
attrs
|
||||||
: attrs attr { $$ = $1; $1->push_back(data->symbols.create($2)); /* !!! dangerous */ }
|
: attrs attr { $$ = $1; $1->push_back(AttrName(data->symbols.create($2))); }
|
||||||
| { $$ = new vector<Symbol>; }
|
| attrs string_attr
|
||||||
|
{ $$ = $1;
|
||||||
|
ExprString *str = dynamic_cast<ExprString *>($2);
|
||||||
|
if (str) {
|
||||||
|
$$->push_back(AttrName(str->s));
|
||||||
|
delete str;
|
||||||
|
} else
|
||||||
|
throw ParseError(format("dynamic attributes not allowed in inherit at %1%")
|
||||||
|
% makeCurPos(@2, data));
|
||||||
|
}
|
||||||
|
| { $$ = new AttrPath; }
|
||||||
;
|
;
|
||||||
|
|
||||||
attrpath
|
attrpath
|
||||||
: attrpath '.' attr { $$ = $1; $1->push_back(data->symbols.create($3)); }
|
: attrpath '.' attr { $$ = $1; $1->push_back(AttrName(data->symbols.create($3))); }
|
||||||
| attr { $$ = new vector<Symbol>; $$->push_back(data->symbols.create($1)); }
|
| attrpath '.' string_attr
|
||||||
|
{ $$ = $1;
|
||||||
|
ExprString *str = dynamic_cast<ExprString *>($3);
|
||||||
|
if (str) {
|
||||||
|
$$->push_back(AttrName(str->s));
|
||||||
|
delete str;
|
||||||
|
} else
|
||||||
|
$$->push_back(AttrName($3));
|
||||||
|
}
|
||||||
|
| attr { $$ = new vector<AttrName>; $$->push_back(AttrName(data->symbols.create($1))); }
|
||||||
|
| string_attr
|
||||||
|
{ $$ = new vector<AttrName>;
|
||||||
|
ExprString *str = dynamic_cast<ExprString *>($1);
|
||||||
|
if (str) {
|
||||||
|
$$->push_back(AttrName(str->s));
|
||||||
|
delete str;
|
||||||
|
} else
|
||||||
|
$$->push_back(AttrName($1));
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
attr
|
attr
|
||||||
: ID { $$ = $1; }
|
: ID { $$ = $1; }
|
||||||
| OR_KW { $$ = "or"; }
|
| OR_KW { $$ = "or"; }
|
||||||
| '"' STR '"'
|
;
|
||||||
{ $$ = strdup(((string) ((ExprString *) $2)->s).c_str()); delete $2; }
|
|
||||||
|
string_attr
|
||||||
|
: '"' string_parts '"' { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
expr_list
|
expr_list
|
||||||
|
|
1
tests/lang/eval-okay-dynamic-attrs-2.exp
Normal file
1
tests/lang/eval-okay-dynamic-attrs-2.exp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
true
|
1
tests/lang/eval-okay-dynamic-attrs-2.nix
Normal file
1
tests/lang/eval-okay-dynamic-attrs-2.nix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{ a."${"b"}" = true; a."${"c"}" = false; }.a.b
|
1
tests/lang/eval-okay-dynamic-attrs.exp
Normal file
1
tests/lang/eval-okay-dynamic-attrs.exp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{ binds = true; hasAttrs = true; multiAttrs = true; recBinds = true; selectAttrs = true; selectOrAttrs = true; }
|
17
tests/lang/eval-okay-dynamic-attrs.nix
Normal file
17
tests/lang/eval-okay-dynamic-attrs.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
let
|
||||||
|
aString = "a";
|
||||||
|
|
||||||
|
bString = "b";
|
||||||
|
in {
|
||||||
|
hasAttrs = { a.b = null; } ? "${aString}".b;
|
||||||
|
|
||||||
|
selectAttrs = { a.b = true; }.a."${bString}";
|
||||||
|
|
||||||
|
selectOrAttrs = { }."${aString}" or true;
|
||||||
|
|
||||||
|
binds = { "${aString}"."${bString}c" = true; }.a.bc;
|
||||||
|
|
||||||
|
recBinds = rec { "${bString}" = a; a = true; }.b;
|
||||||
|
|
||||||
|
multiAttrs = { "${aString}" = true; "${bString}" = false; }.a;
|
||||||
|
}
|
1
tests/lang/eval-okay-redefine-builtin.exp
Normal file
1
tests/lang/eval-okay-redefine-builtin.exp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
false
|
3
tests/lang/eval-okay-redefine-builtin.nix
Normal file
3
tests/lang/eval-okay-redefine-builtin.nix
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
let
|
||||||
|
throw = abort "Error!";
|
||||||
|
in (builtins.tryEval <foobaz>).success
|
Loading…
Reference in a new issue