aboutsummaryrefslogtreecommitdiffstats
path: root/src/expand.cpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-12-25 08:35:43 +0000
committerDavid Robillard <d@drobilla.net>2012-12-25 08:35:43 +0000
commit77d27b3495bfa98c5e13707903e4f885e8521ab6 (patch)
treeb2cadb927fd0ab8732001fc77a580f1dffcd0744 /src/expand.cpp
parent12314c754187ae246bc38aceb827bf51d1669d73 (diff)
downloadresp-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.cpp37
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
}