diff options
author | David Robillard <d@drobilla.net> | 2012-12-25 20:14:15 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2012-12-25 20:14:15 +0000 |
commit | 32e3bdba4abbd63d7f2a1def7f7000b75c5165fe (patch) | |
tree | 1a83776a4673c3c620ed37d890fa17b56d013640 /src/expand.cpp | |
parent | 77d27b3495bfa98c5e13707903e4f885e8521ab6 (diff) | |
download | resp-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.cpp | 47 |
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 |