From c4f7ae4aa5fc7071cfa853ec5d75aaf00e7a97fc Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 3 Feb 2004 14:45:34 +0000 Subject: * Verify that all variables in a Nix expression are defined. --- src/libexpr/nixexpr.cc | 75 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 12 deletions(-) (limited to 'src/libexpr/nixexpr.cc') diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index b0f506e65d6f..92027a70ebd7 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -156,10 +156,10 @@ Expr substitute(const ATermMap & subs, Expr e) checkInterrupt(); ATMatcher m; - string s; + ATerm name; - if (atMatch(m, e) >> "Var" >> s) { - Expr sub = subs.get(s); + if (atMatch(m, e) >> "Var" >> name) { + Expr sub = subs.get(name); return sub ? sub : e; } @@ -170,11 +170,10 @@ Expr substitute(const ATermMap & subs, Expr e) if (atMatch(m, e) >> "Function" >> formals >> body) { ATermMap subs2(subs); for (ATermIterator i(formals); i; ++i) { - Expr def; - if (!(atMatch(m, *i) >> "NoDefFormal" >> s) && - !(atMatch(m, *i) >> "DefFormal" >> s >> def)) + if (!(atMatch(m, *i) >> "NoDefFormal" >> name) && + !(atMatch(m, *i) >> "DefFormal" >> name)) abort(); - subs2.remove(s); + subs2.remove(name); } return ATmake("Function(, )", formals, substitute(subs2, body)); @@ -184,12 +183,11 @@ Expr substitute(const ATermMap & subs, Expr e) ATermList rbnds, nrbnds; if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) { ATermMap subs2(subs); - for (ATermIterator i(rbnds); i; ++i) { - Expr e; - if (!(atMatch(m, *i) >> "Bind" >> s >> e)) + for (ATermIterator i(rbnds); i; ++i) + if (atMatch(m, *i) >> "Bind" >> name) + subs2.remove(name); + else abort(); /* can't happen */ - subs2.remove(s); - } return ATmake("Rec(, )", substitute(subs2, (ATerm) rbnds), substitute(subs, (ATerm) nrbnds)); @@ -217,6 +215,59 @@ Expr substitute(const ATermMap & subs, Expr e) } +void checkVarDefs(const ATermMap & defs, Expr e) +{ + ATMatcher m; + ATerm name; + ATermList formals; + ATerm body; + ATermList rbnds, nrbnds; + + if (atMatch(m, e) >> "Var" >> name) { + if (!defs.get(name)) + throw Error(format("undefined variable `%1%'") + % aterm2String(name)); + return; + } + + else if (atMatch(m, e) >> "Function" >> formals >> body) { + ATermMap defs2(defs); + for (ATermIterator i(formals); i; ++i) { + Expr deflt; + if (!(atMatch(m, *i) >> "NoDefFormal" >> name)) + if (atMatch(m, *i) >> "DefFormal" >> name >> deflt) + checkVarDefs(defs, deflt); + else + abort(); + defs2.set(name, (ATerm) ATempty); + } + return checkVarDefs(defs2, body); + } + + else if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) { + checkVarDefs(defs + , (ATerm) nrbnds); + ATermMap defs2(defs); + for (ATermIterator i(rbnds); i; ++i) { + if (!(atMatch(m, *i) >> "Bind" >> name)) + abort(); /* can't happen */ + defs2.set(name, (ATerm) ATempty); + } + checkVarDefs(defs2, (ATerm) rbnds); + } + + else if (ATgetType(e) == AT_APPL) { + int arity = ATgetArity(ATgetAFun(e)); + for (int i = 0; i < arity; ++i) + checkVarDefs(defs, ATgetArgument(e, i)); + } + + else if (ATgetType(e) == AT_LIST) + for (ATermIterator i((ATermList) e); i; ++i) + checkVarDefs(defs, *i); +} + + Expr makeBool(bool b) { return b ? ATmake("Bool(True)") : ATmake("Bool(False)"); -- cgit 1.4.1