forked from lix-project/lix
* Check for duplicate attribute names / function arguments. `make
check' now succeeds :-) * An attribute set such as `{ foo = { enable = true; }; foo.port = 23; }' now parses. It was previously rejected, but I'm too lazy to implement the check. (The only reason to reject it is that the reverse, `{ foo.port = 23; foo = { enable = true; }; }', is rejected, which is kind of ugly.)
This commit is contained in:
parent
2d7636529f
commit
ebade9ff8b
|
@ -128,6 +128,7 @@ struct ExprAttrs : Expr
|
||||||
typedef std::map<Symbol, Expr *> Attrs;
|
typedef std::map<Symbol, Expr *> Attrs;
|
||||||
Attrs attrs;
|
Attrs attrs;
|
||||||
list<VarRef> inherited;
|
list<VarRef> inherited;
|
||||||
|
set<Symbol> attrNames; // used during parsing
|
||||||
ExprAttrs() : recursive(false) { };
|
ExprAttrs() : recursive(false) { };
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
};
|
};
|
||||||
|
@ -150,6 +151,7 @@ struct Formals
|
||||||
{
|
{
|
||||||
typedef std::list<Formal> Formals_;
|
typedef std::list<Formal> Formals_;
|
||||||
Formals_ formals;
|
Formals_ formals;
|
||||||
|
std::set<Symbol> argNames; // used during parsing
|
||||||
bool ellipsis;
|
bool ellipsis;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -161,7 +163,12 @@ struct ExprLambda : Expr
|
||||||
Formals * formals;
|
Formals * formals;
|
||||||
Expr * body;
|
Expr * body;
|
||||||
ExprLambda(const Pos & pos, const Symbol & 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)
|
||||||
|
{
|
||||||
|
if (!arg.empty() && formals && formals->argNames.find(arg) != formals->argNames.end())
|
||||||
|
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
|
||||||
|
% arg % pos);
|
||||||
|
};
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,21 @@ static string showAttrPath(const vector<Symbol> & attrPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dupAttr(const vector<Symbol> & attrPath, const Pos & pos)
|
||||||
|
{
|
||||||
|
throw ParseError(format("attribute `%1%' at %2% already defined at <SOMEWHERE>")
|
||||||
|
% showAttrPath(attrPath) % pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dupAttr(Symbol attr, const Pos & pos)
|
||||||
|
{
|
||||||
|
vector<Symbol> attrPath; attrPath.push_back(attr);
|
||||||
|
throw ParseError(format("attribute `%1%' at %2% already defined at <SOMEWHERE>")
|
||||||
|
% showAttrPath(attrPath) % pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void addAttr(ExprAttrs * attrs, const vector<Symbol> & attrPath,
|
static void addAttr(ExprAttrs * attrs, const vector<Symbol> & attrPath,
|
||||||
Expr * e, const Pos & pos)
|
Expr * e, const Pos & pos)
|
||||||
{
|
{
|
||||||
|
@ -69,11 +84,12 @@ static void addAttr(ExprAttrs * attrs, const vector<Symbol> & 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]);
|
||||||
if (!attrs2)
|
if (!attrs2 || n == attrPath.size()) dupAttr(attrPath, pos);
|
||||||
throw ParseError(format("attribute `%1%' at %2% already defined at <SOMEWHERE>")
|
|
||||||
% showAttrPath(attrPath) % pos);
|
|
||||||
attrs = attrs2;
|
attrs = attrs2;
|
||||||
} else {
|
} else {
|
||||||
|
if (attrs->attrNames.find(*i) != attrs->attrNames.end())
|
||||||
|
dupAttr(attrPath, pos);
|
||||||
|
attrs->attrNames.insert(*i);
|
||||||
if (n == attrPath.size())
|
if (n == attrPath.size())
|
||||||
attrs->attrs[*i] = e;
|
attrs->attrs[*i] = e;
|
||||||
else {
|
else {
|
||||||
|
@ -86,43 +102,16 @@ static void addAttr(ExprAttrs * attrs, const vector<Symbol> & attrPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
static void addFormal(const Pos & pos, Formals * formals, const Formal & formal)
|
||||||
static void checkPatternVars(ATerm pos, ATermMap & map, Pattern pat)
|
|
||||||
{
|
{
|
||||||
ATerm name = sNoAlias;
|
if (formals->argNames.find(formal.name) != formals->argNames.end())
|
||||||
ATermList formals;
|
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
|
||||||
ATermBool ellipsis;
|
% formal.name % pos);
|
||||||
|
formals->formals.push_front(formal);
|
||||||
if (matchAttrsPat(pat, formals, ellipsis, name)) {
|
formals->argNames.insert(formal.name);
|
||||||
for (ATermIterator i(formals); i; ++i) {
|
|
||||||
ATerm d1, name2;
|
|
||||||
if (!matchFormal(*i, name2, d1)) abort();
|
|
||||||
if (map.get(name2))
|
|
||||||
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
|
|
||||||
% aterm2String(name2) % showPos(pos));
|
|
||||||
map.set(name2, name2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else matchVarPat(pat, name);
|
|
||||||
|
|
||||||
if (name != sNoAlias) {
|
|
||||||
if (map.get(name))
|
|
||||||
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
|
|
||||||
% aterm2String(name) % showPos(pos));
|
|
||||||
map.set(name, name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void checkPatternVars(ATerm pos, Pattern pat)
|
|
||||||
{
|
|
||||||
ATermMap map;
|
|
||||||
checkPatternVars(pos, map, pat);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static Expr * stripIndentation(vector<Expr *> & es)
|
static Expr * stripIndentation(vector<Expr *> & es)
|
||||||
{
|
{
|
||||||
if (es.empty()) return new ExprString("");
|
if (es.empty()) return new ExprString("");
|
||||||
|
@ -294,7 +283,7 @@ expr: expr_function;
|
||||||
|
|
||||||
expr_function
|
expr_function
|
||||||
: ID ':' expr_function
|
: ID ':' expr_function
|
||||||
{ $$ = new ExprLambda(CUR_POS, data->symbols.create($1), false, 0, $3); /* checkPatternVars(CUR_POS, $1); */ }
|
{ $$ = new ExprLambda(CUR_POS, data->symbols.create($1), false, 0, $3); }
|
||||||
| '{' formals '}' ':' expr_function
|
| '{' formals '}' ':' expr_function
|
||||||
{ $$ = new ExprLambda(CUR_POS, data->symbols.create(""), true, $2, $5); }
|
{ $$ = new ExprLambda(CUR_POS, data->symbols.create(""), true, $2, $5); }
|
||||||
| '{' formals '}' '@' ID ':' expr_function
|
| '{' formals '}' '@' ID ':' expr_function
|
||||||
|
@ -388,14 +377,22 @@ 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<Symbol>::iterator, i, *$3)
|
foreach (vector<Symbol>::iterator, i, *$3) {
|
||||||
$$->inherited.push_back(*i);
|
if ($$->attrNames.find(*i) != $$->attrNames.end())
|
||||||
|
dupAttr(*i, CUR_POS);
|
||||||
|
$$->inherited.push_back(*i);
|
||||||
|
$$->attrNames.insert(*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<Symbol>::iterator, i, *$6)
|
foreach (vector<Symbol>::iterator, i, *$6) {
|
||||||
$$->attrs[*i] = new ExprSelect($4, *i);
|
if ($$->attrNames.find(*i) != $$->attrNames.end())
|
||||||
|
dupAttr(*i, CUR_POS);
|
||||||
|
$$->attrs[*i] = new ExprSelect($4, *i);
|
||||||
|
$$->attrNames.insert(*i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
| { $$ = new ExprAttrs; }
|
| { $$ = new ExprAttrs; }
|
||||||
;
|
;
|
||||||
|
@ -417,9 +414,9 @@ expr_list
|
||||||
|
|
||||||
formals
|
formals
|
||||||
: formal ',' formals
|
: formal ',' formals
|
||||||
{ $$ = $3; $$->formals.push_front(*$1); /* !!! dangerous */ }
|
{ $$ = $3; addFormal(CUR_POS, $$, *$1); }
|
||||||
| formal
|
| formal
|
||||||
{ $$ = new Formals; $$->formals.push_back(*$1); $$->ellipsis = false; }
|
{ $$ = new Formals; addFormal(CUR_POS, $$, *$1); $$->ellipsis = false; }
|
||||||
|
|
|
|
||||||
{ $$ = new Formals; $$->ellipsis = false; }
|
{ $$ = new Formals; $$->ellipsis = false; }
|
||||||
| ELLIPSIS
|
| ELLIPSIS
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Str("foo eval-okay-context.nix bar",[])
|
"foo eval-okay-context.nix bar"
|
||||||
|
|
9
tests/lang/parse-fail-dup-attrs-7.nix
Normal file
9
tests/lang/parse-fail-dup-attrs-7.nix
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
rec {
|
||||||
|
|
||||||
|
x = 1;
|
||||||
|
|
||||||
|
as = {
|
||||||
|
inherit x;
|
||||||
|
inherit x;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue