aboutsummaryrefslogtreecommitdiffstats
path: root/src/expand.cpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-12-25 20:14:15 +0000
committerDavid Robillard <d@drobilla.net>2012-12-25 20:14:15 +0000
commit32e3bdba4abbd63d7f2a1def7f7000b75c5165fe (patch)
tree1a83776a4673c3c620ed37d890fa17b56d013640 /src/expand.cpp
parent77d27b3495bfa98c5e13707903e4f885e8521ab6 (diff)
downloadresp-32e3bdba4abbd63d7f2a1def7f7000b75c5165fe.tar.gz
resp-32e3bdba4abbd63d7f2a1def7f7000b75c5165fe.tar.bz2
resp-32e3bdba4abbd63d7f2a1def7f7000b75c5165fe.zip
Implement ellipses as in R*RS.
Let macro is now the one from R7RS, but missing the second clause (no letrec yet). git-svn-id: http://svn.drobilla.net/resp/trunk@446 ad02d1e2-f140-0410-9f75-f8b11f17cedd
Diffstat (limited to 'src/expand.cpp')
-rw-r--r--src/expand.cpp47
1 files changed, 30 insertions, 17 deletions
diff --git a/src/expand.cpp b/src/expand.cpp
index 658eafd..5ede0dd 100644
--- a/src/expand.cpp
+++ b/src/expand.cpp
@@ -35,34 +35,47 @@ match(PEnv& penv,
bool bind)
{
if (p->to_tuple() && e->to_tuple()) {
- ATuple::const_iterator pi = p->as_tuple()->begin();
- ATuple::const_iterator ei = e->as_tuple()->begin();
- ATuple::const_iterator prev_pi = pi;
- if (!match(penv, subst, keywords, *pi++, *ei++, true)) {
- return false; // Mismatch
+ ATuple::const_iterator pi = p->as_tuple()->begin();
+ ATuple::const_iterator ei = e->as_tuple()->begin();
+ ATuple::const_iterator next = pi;
+ if (next != p->as_tuple()->end()) {
+ ++next;
}
for (; pi != p->as_tuple()->end() && ei != e->as_tuple()->end();
- ++pi, ++ei, ++prev_pi) {
- if (is_dots(*pi)) {
- 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); // Element matches prev, append
+ ++pi, ++ei) {
+ if (next != p->as_tuple()->end() && is_dots(*next)) {
+ if ((*pi)->to_tuple()) {
+ /* We have something like "(foo bar) ..."
+ Add a new ellipsis list for each element (foo and bar)
+ so they can be used in templates like "foo ..." */
+ for (auto elem : *(*pi)->as_tuple()) {
+ subst.add(elem, new ATuple(NULL, NULL, (*pi)->loc));
+ }
+ }
+
+ List out; // The list that dots after *pi will be mapped to
+ for (; ei != e->as_tuple()->end() && !is_dots(*ei); ++ei) {
+ if (match(penv, subst, keywords, *pi, *ei, false)) {
+ out.push_back(*ei); // Element matches, append
} else {
- return false; // Element doesn't match prev, mismatch
+ return false; // Element doesn't match, mismatch
}
}
- subst.add(new AEllipsis(*prev_pi, (*pi++)->loc), out);
+ if (out) {
+ subst.add(new AEllipsis(*pi, (*pi++)->loc), out);
+ }
break;
} else if (!match(penv, subst, keywords, *pi, *ei, true)) {
return false; // Pattern element doesn't match
}
+ if (next != p->as_tuple()->end()) {
+ ++next;
+ }
}
- if ((pi == p->as_tuple()->end() || is_dots(*pi)) &&
- ei != e->as_tuple()->end()) {
+ if ((pi == p->as_tuple()->end() && ei != e->as_tuple()->end())) {
return false; // Reached end of pattern but not expression
}
- } else if (p->to_symbol()) {
+ } else if (p->to_symbol() && !is_dots(p) && !is_dots(e)) {
if (keywords.count(p->str())) {
if (!e->to_symbol() || e->str() != p->str()) {
return false; // Keyword mismatch
@@ -71,7 +84,7 @@ match(PEnv& penv,
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
+ // Already an ellipsis list for this element, 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