-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMatcher.cpp
138 lines (119 loc) · 3.8 KB
/
Matcher.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#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};
}