blob: b4dda6d5c1e7bbd14ca3bf0d4d366044133660fc [file] [log] [blame]
#include "Matcher.h"
#include <QDebug>
MatchResult match(QList<Token> data, QList<Token> pattern, VarContext context) {
if (data.empty() && pattern.empty()) {
return MatchResult{true, context};
}
Token ph = pattern.first();
Token dataHead = data.first();
pattern.removeFirst();
if (ph.isSym() || ph.isIdent()) {
if (ph == data.first()) {
data.removeFirst();
return match(data, pattern, context);
} else {
return MatchResult{false, context};
}
} else if (ph.isParen() && dataHead.isParen()) {
data.removeFirst();
auto result = match(dataHead.parenContent(), ph.parenContent(), context);
if (result.success) {
return match(data, pattern, result.context);
} else {
return MatchResult{false, result.context};
}
} else if (ph.isVar()) {
// is var bound?
if (context.exists(ph.name())) {
// TODO: handle error elegantly if types don't match up (let's just assume the user isn't stupid)
switch (ph.varType()) {
case 's':
case 't':
if (context.singleVar(ph.name()) == dataHead) {
data.removeFirst();
return match(data, pattern, context);
} else {
return MatchResult{false, context};
}
case 'e':
QList<Token> expected = context.expressionVar(ph.name());
if (listStartsWith(data, expected)) {
listDrop(data, expected.length());
return match(data, pattern, context);
} else {
return MatchResult{false, context};
}
}
} else {
bool typeIsOk = false;
switch (ph.varType()) {
case 't':
if (dataHead.isParen())
typeIsOk = true;
case 's':
if (dataHead.isSym() || dataHead.isIdent())
typeIsOk = true;
if (!typeIsOk) {
return MatchResult{false, context};
}
context.add(ph.varType(), ph.name(), dataHead);
data.removeFirst();
return match(data, pattern, context);
case 'e':
// Now this is tricky
for (int matchSyms = 1; matchSyms < data.length(); matchSyms++) {
QList<Token> slice = listSlice(data, 0, matchSyms);
VarContext newContext = context;
newContext.add(ph.varType(), ph.name(), slice);
MatchResult tryMatch = match(listSlice(data, matchSyms, data.length()), pattern, newContext);
if (tryMatch.success) {
return tryMatch;
}
// else matchSyms ++
}
// If this worked we would have returned already
return MatchResult{false, context};
}
}
}
qDebug() << "FALLING THROUGH, THIS SHOULD NOT HAPPEN";
// Fallthrough
return MatchResult{false, context};
}