diff options
author | Eelco Dolstra <e.dolstra@tudelft.nl> | 2010-04-22T11·02+0000 |
---|---|---|
committer | Eelco Dolstra <e.dolstra@tudelft.nl> | 2010-04-22T11·02+0000 |
commit | ebade9ff8b8557bdae7cdaf9f70c12ceeb3dc02c (patch) | |
tree | 32a2ea8441ed340fd2a0b3b8ab29f5e51950480f | |
parent | 2d7636529f782b552b634497fd8ac876aae72fcc (diff) |
* 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.)
-rw-r--r-- | src/libexpr/nixexpr.hh | 9 | ||||
-rw-r--r-- | src/libexpr/parser.y | 83 | ||||
-rw-r--r-- | tests/lang/eval-okay-context.exp | 2 | ||||
-rw-r--r-- | tests/lang/parse-fail-dup-attrs-7.nix | 9 | ||||
-rw-r--r-- | tests/lang/parse-okay-dup-attrs-5.nix (renamed from tests/lang/parse-fail-dup-attrs-5.nix) | 0 |
5 files changed, 58 insertions, 45 deletions
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 9e5a262d7f46..4da77ee5861a 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -128,6 +128,7 @@ struct ExprAttrs : Expr typedef std::map<Symbol, Expr *> Attrs; Attrs attrs; list<VarRef> inherited; + set<Symbol> attrNames; // used during parsing ExprAttrs() : recursive(false) { }; COMMON_METHODS }; @@ -150,6 +151,7 @@ struct Formals { typedef std::list<Formal> Formals_; Formals_ formals; + std::set<Symbol> argNames; // used during parsing bool ellipsis; }; @@ -161,7 +163,12 @@ struct ExprLambda : Expr 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 }; diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 06fcc72fc542..66da769402dc 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -59,6 +59,21 @@ static string showAttrPath(const vector<Symbol> & attrPath) } return s; } + + +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, @@ -69,11 +84,12 @@ static void addAttr(ExprAttrs * attrs, const vector<Symbol> & attrPath, n++; if (attrs->attrs[*i]) { ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(attrs->attrs[*i]); - if (!attrs2) - throw ParseError(format("attribute `%1%' at %2% already defined at <SOMEWHERE>") - % showAttrPath(attrPath) % pos); + if (!attrs2 || n == attrPath.size()) dupAttr(attrPath, pos); attrs = attrs2; } else { + if (attrs->attrNames.find(*i) != attrs->attrNames.end()) + dupAttr(attrPath, pos); + attrs->attrNames.insert(*i); if (n == attrPath.size()) attrs->attrs[*i] = e; else { @@ -86,43 +102,16 @@ static void addAttr(ExprAttrs * attrs, const vector<Symbol> & attrPath, } -#if 0 -static void checkPatternVars(ATerm pos, ATermMap & map, Pattern pat) +static void addFormal(const Pos & pos, Formals * formals, const Formal & formal) { - ATerm name = sNoAlias; - 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%") - % 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); - } + if (formals->argNames.find(formal.name) != formals->argNames.end()) + throw ParseError(format("duplicate formal function argument `%1%' at %2%") + % formal.name % pos); + formals->formals.push_front(formal); + formals->argNames.insert(formal.name); } -static void checkPatternVars(ATerm pos, Pattern pat) -{ - ATermMap map; - checkPatternVars(pos, map, pat); -} -#endif - - static Expr * stripIndentation(vector<Expr *> & es) { if (es.empty()) return new ExprString(""); @@ -294,7 +283,7 @@ expr: expr_function; 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 { $$ = new ExprLambda(CUR_POS, data->symbols.create(""), true, $2, $5); } | '{' formals '}' '@' ID ':' expr_function @@ -388,14 +377,22 @@ binds : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, CUR_POS); } | binds INHERIT ids ';' { $$ = $1; - foreach (vector<Symbol>::iterator, i, *$3) - $$->inherited.push_back(*i); + foreach (vector<Symbol>::iterator, i, *$3) { + if ($$->attrNames.find(*i) != $$->attrNames.end()) + dupAttr(*i, CUR_POS); + $$->inherited.push_back(*i); + $$->attrNames.insert(*i); + } } | binds INHERIT '(' expr ')' ids ';' { $$ = $1; /* !!! Should ensure sharing of the expression in $4. */ - foreach (vector<Symbol>::iterator, i, *$6) - $$->attrs[*i] = new ExprSelect($4, *i); + foreach (vector<Symbol>::iterator, i, *$6) { + if ($$->attrNames.find(*i) != $$->attrNames.end()) + dupAttr(*i, CUR_POS); + $$->attrs[*i] = new ExprSelect($4, *i); + $$->attrNames.insert(*i); + } } | { $$ = new ExprAttrs; } ; @@ -417,9 +414,9 @@ expr_list formals : formal ',' formals - { $$ = $3; $$->formals.push_front(*$1); /* !!! dangerous */ } + { $$ = $3; addFormal(CUR_POS, $$, *$1); } | formal - { $$ = new Formals; $$->formals.push_back(*$1); $$->ellipsis = false; } + { $$ = new Formals; addFormal(CUR_POS, $$, *$1); $$->ellipsis = false; } | { $$ = new Formals; $$->ellipsis = false; } | ELLIPSIS diff --git a/tests/lang/eval-okay-context.exp b/tests/lang/eval-okay-context.exp index 95a993654263..2f535bdbc454 100644 --- a/tests/lang/eval-okay-context.exp +++ b/tests/lang/eval-okay-context.exp @@ -1 +1 @@ -Str("foo eval-okay-context.nix bar",[]) +"foo eval-okay-context.nix bar" diff --git a/tests/lang/parse-fail-dup-attrs-7.nix b/tests/lang/parse-fail-dup-attrs-7.nix new file mode 100644 index 000000000000..bbc3eb08c0f6 --- /dev/null +++ b/tests/lang/parse-fail-dup-attrs-7.nix @@ -0,0 +1,9 @@ +rec { + + x = 1; + + as = { + inherit x; + inherit x; + }; +} \ No newline at end of file diff --git a/tests/lang/parse-fail-dup-attrs-5.nix b/tests/lang/parse-okay-dup-attrs-5.nix index f4b9efd0c596..f4b9efd0c596 100644 --- a/tests/lang/parse-fail-dup-attrs-5.nix +++ b/tests/lang/parse-okay-dup-attrs-5.nix |