* 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:
Eelco Dolstra 2010-04-22 11:02:24 +00:00
parent 2d7636529f
commit ebade9ff8b
5 changed files with 58 additions and 45 deletions

View file

@ -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
}; };

View file

@ -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,41 +102,14 @@ 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;
ATermBool ellipsis;
if (matchAttrsPat(pat, formals, ellipsis, 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%") throw ParseError(format("duplicate formal function argument `%1%' at %2%")
% aterm2String(name2) % showPos(pos)); % formal.name % pos);
map.set(name2, name2); formals->formals.push_front(formal);
formals->argNames.insert(formal.name);
} }
}
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)
@ -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) {
if ($$->attrNames.find(*i) != $$->attrNames.end())
dupAttr(*i, CUR_POS);
$$->inherited.push_back(*i); $$->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) {
if ($$->attrNames.find(*i) != $$->attrNames.end())
dupAttr(*i, CUR_POS);
$$->attrs[*i] = new ExprSelect($4, *i); $$->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

View file

@ -1 +1 @@
Str("foo eval-okay-context.nix bar",[]) "foo eval-okay-context.nix bar"

View file

@ -0,0 +1,9 @@
rec {
x = 1;
as = {
inherit x;
inherit x;
};
}