diff options
author | David Robillard <d@drobilla.net> | 2012-12-25 08:35:43 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2012-12-25 08:35:43 +0000 |
commit | 77d27b3495bfa98c5e13707903e4f885e8521ab6 (patch) | |
tree | b2cadb927fd0ab8732001fc77a580f1dffcd0744 /src/expand.cpp | |
parent | 12314c754187ae246bc38aceb827bf51d1669d73 (diff) | |
download | resp-77d27b3495bfa98c5e13707903e4f885e8521ab6.tar.gz resp-77d27b3495bfa98c5e13707903e4f885e8521ab6.tar.bz2 resp-77d27b3495bfa98c5e13707903e4f885e8521ab6.zip |
Support multiple ellipses in macros.
Support lambda expressions with empty argument lists.
git-svn-id: http://svn.drobilla.net/resp/trunk@445 ad02d1e2-f140-0410-9f75-f8b11f17cedd
Diffstat (limited to 'src/expand.cpp')
-rw-r--r-- | src/expand.cpp | 37 |
1 files changed, 25 insertions, 12 deletions
diff --git a/src/expand.cpp b/src/expand.cpp index c0f2f64..658eafd 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -23,6 +23,9 @@ using namespace std; +/** Try to match pattern @a p with @p e and build a Subst in the process. + * @return true iff @e matches @p. + */ static bool match(PEnv& penv, Subst& subst, @@ -36,38 +39,48 @@ match(PEnv& penv, ATuple::const_iterator ei = e->as_tuple()->begin(); ATuple::const_iterator prev_pi = pi; if (!match(penv, subst, keywords, *pi++, *ei++, true)) { - return false; + return false; // Mismatch } for (; pi != p->as_tuple()->end() && ei != e->as_tuple()->end(); ++pi, ++ei, ++prev_pi) { if (is_dots(*pi)) { - List out; + List out; // The list that dots after prev will be mapped to for (; ei != e->as_tuple()->end(); ++ei) { if (match(penv, subst, keywords, *prev_pi, *ei, false)) { - out.push_back(*ei); + out.push_back(*ei); // Element matches prev, append } else { - return false; + return false; // Element doesn't match prev, mismatch } } - subst.add(*pi, out); - ++pi; + subst.add(new AEllipsis(*prev_pi, (*pi++)->loc), out); break; } else if (!match(penv, subst, keywords, *pi, *ei, true)) { - return false; + return false; // Pattern element doesn't match } } - if ((pi != p->as_tuple()->end()) || (ei != e->as_tuple()->end())) - return false; + if ((pi == p->as_tuple()->end() || is_dots(*pi)) && + ei != e->as_tuple()->end()) { + return false; // Reached end of pattern but not expression + } } else if (p->to_symbol()) { if (keywords.count(p->str())) { if (!e->to_symbol() || e->str() != p->str()) { return false; // Keyword mismatch } } else if (p->as_symbol()->str() != "_" && bind) { - subst.add(p, e); // Symbol p match with symbol e - } // else _, ... matches with everything but creates no bindings + AEllipsis* ellipsis = new AEllipsis(p, e->loc); + Subst::const_iterator s = subst.find_ellipsis(p); + if (s != subst.end()) { + // Already an ellipsis list for after this prev, append to it + list_append(const_cast<ATuple*>(s->second->as_tuple()), e); + } else if ((s = subst.find(p)) != subst.end()) { + // Prev is mapped, but no ellipsis list yet, add a new one + subst.add(ellipsis, tup(s->second->loc, e, NULL)); + } else { + subst.add(p, e); // Symbol p match with symbol e + } + } // else _ matches with everything but creates no bindings } else { - THROW_IF(p->tag() != e->tag(), e->loc, "expr type mismatch"); return false; // Recursive list p mismatch with list e } |