blob: 54cd9d9243e6df10bdd8090aff61bb7d414961a8 [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};
}
if ((pattern.empty() && !data.empty()) || (data.empty() && !pattern.empty()))
{
return MatchResult{false, context};
}
Token ph = pattern.first();
Token dataHead = data.first();
pattern.removeFirst();
if (ph.isSym() || ph.isIdent() || ph.isInteger())
{
if (ph == data.first())
{
data.removeFirst();
return match(data, pattern, context);
}
else
{
return MatchResult{false, context};
}
}
else if (ph.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() || dataHead.isInteger())
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 TODO: Optimize this to check if
// there is an obvious length that this expression has
// to be
for (int matchSyms = 0; 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;
}
}
// If this worked we would have returned already
return MatchResult{false, context};
default:
qDebug() << "#TYPE_ERROR";
return MatchResult{false, context};
}
}
}
qFatal("FALLING THROUGH, THIS SHOULD NOT HAPPEN");
// Fallthrough
return MatchResult{false, context};
}