swissChili | 7babd92 | 2021-12-02 22:46:48 -0800 | [diff] [blame] | 1 | #include "Matcher.h" |
| 2 | |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 3 | #include <QDebug> |
| 4 | |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 5 | MatchResult match(QList<Token> data, QList<Token> pattern, VarContext context) |
| 6 | { |
| 7 | if (data.empty() && pattern.empty()) |
| 8 | { |
swissChili | 7babd92 | 2021-12-02 22:46:48 -0800 | [diff] [blame] | 9 | return MatchResult{true, context}; |
| 10 | } |
| 11 | |
swissChili | 07d325f | 2021-12-08 20:02:05 -0800 | [diff] [blame] | 12 | if ((pattern.empty() && !data.empty()) || (data.empty() && !pattern.empty())) |
swissChili | 682e7bc | 2021-12-07 09:04:54 -0800 | [diff] [blame] | 13 | { |
| 14 | return MatchResult{false, context}; |
| 15 | } |
| 16 | |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 17 | Token ph = pattern.first(); |
swissChili | 7babd92 | 2021-12-02 22:46:48 -0800 | [diff] [blame] | 18 | Token dataHead = data.first(); |
| 19 | pattern.removeFirst(); |
| 20 | |
swissChili | 9dddbf7 | 2021-12-08 23:03:25 -0800 | [diff] [blame] | 21 | if (ph.isSym() || ph.isIdent() || ph.isInteger()) |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 22 | { |
| 23 | if (ph == data.first()) |
| 24 | { |
swissChili | 7babd92 | 2021-12-02 22:46:48 -0800 | [diff] [blame] | 25 | data.removeFirst(); |
| 26 | return match(data, pattern, context); |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 27 | } |
| 28 | else |
| 29 | { |
swissChili | 7babd92 | 2021-12-02 22:46:48 -0800 | [diff] [blame] | 30 | return MatchResult{false, context}; |
| 31 | } |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 32 | } |
| 33 | else if (ph.isParen()) |
| 34 | { |
swissChili | 7babd92 | 2021-12-02 22:46:48 -0800 | [diff] [blame] | 35 | data.removeFirst(); |
swissChili | d17b5a1 | 2021-12-05 20:46:42 -0800 | [diff] [blame] | 36 | |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 37 | auto result = match(dataHead.parenContent(), ph.parenContent(), context); |
swissChili | 7babd92 | 2021-12-02 22:46:48 -0800 | [diff] [blame] | 38 | |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 39 | if (result.success) |
| 40 | { |
swissChili | 7babd92 | 2021-12-02 22:46:48 -0800 | [diff] [blame] | 41 | return match(data, pattern, result.context); |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 42 | } |
| 43 | else |
| 44 | { |
swissChili | 7babd92 | 2021-12-02 22:46:48 -0800 | [diff] [blame] | 45 | return MatchResult{false, result.context}; |
| 46 | } |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 47 | } |
| 48 | else if (ph.isVar()) |
| 49 | { |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 50 | // is var bound? |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 51 | if (context.exists(ph.name())) |
| 52 | { |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 53 | // TODO: handle error elegantly if types don't match up (let's just assume the user isn't stupid) |
| 54 | |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 55 | switch (ph.varType()) |
| 56 | { |
| 57 | case 's': |
| 58 | case 't': |
| 59 | if (context.singleVar(ph.name()) == dataHead) |
| 60 | { |
| 61 | data.removeFirst(); |
| 62 | return match(data, pattern, context); |
| 63 | } |
| 64 | else |
| 65 | { |
| 66 | return MatchResult{false, context}; |
| 67 | } |
| 68 | case 'e': |
| 69 | QList<Token> expected = context.expressionVar(ph.name()); |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 70 | |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 71 | if (listStartsWith(data, expected)) |
| 72 | { |
| 73 | listDrop(data, expected.length()); |
| 74 | return match(data, pattern, context); |
| 75 | } |
| 76 | else |
| 77 | { |
| 78 | return MatchResult{false, context}; |
| 79 | } |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 80 | } |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 81 | } |
| 82 | else |
| 83 | { |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 84 | bool typeIsOk = false; |
| 85 | |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 86 | switch (ph.varType()) |
| 87 | { |
| 88 | case 't': |
| 89 | if (dataHead.isParen()) |
| 90 | typeIsOk = true; |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 91 | |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 92 | case 's': |
swissChili | 9dddbf7 | 2021-12-08 23:03:25 -0800 | [diff] [blame] | 93 | if (dataHead.isSym() || dataHead.isIdent() || dataHead.isInteger()) |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 94 | typeIsOk = true; |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 95 | |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 96 | if (!typeIsOk) |
| 97 | { |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 98 | return MatchResult{false, context}; |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 99 | } |
swissChili | d17b5a1 | 2021-12-05 20:46:42 -0800 | [diff] [blame] | 100 | |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 101 | context.add(ph.varType(), ph.name(), dataHead); |
| 102 | data.removeFirst(); |
| 103 | |
| 104 | return match(data, pattern, context); |
| 105 | |
| 106 | case 'e': |
swissChili | 923bd53 | 2021-12-08 22:48:58 -0800 | [diff] [blame] | 107 | // Now this is tricky TODO: Optimize this to check if |
| 108 | // there is an obvious length that this expression has |
| 109 | // to be |
| 110 | for (int matchSyms = 0; matchSyms <= data.length(); matchSyms++) |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 111 | { |
| 112 | QList<Token> slice = listSlice(data, 0, matchSyms); |
| 113 | VarContext newContext = context; |
| 114 | newContext.add(ph.varType(), ph.name(), slice); |
| 115 | |
swissChili | 923bd53 | 2021-12-08 22:48:58 -0800 | [diff] [blame] | 116 | MatchResult tryMatch = match( |
| 117 | listSlice(data, matchSyms, data.length()), |
| 118 | pattern, newContext); |
| 119 | |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 120 | if (tryMatch.success) |
| 121 | { |
| 122 | return tryMatch; |
| 123 | } |
swissChili | c71acc6 | 2021-12-07 08:03:37 -0800 | [diff] [blame] | 124 | } |
| 125 | // If this worked we would have returned already |
| 126 | return MatchResult{false, context}; |
| 127 | |
| 128 | default: |
| 129 | qDebug() << "#TYPE_ERROR"; |
| 130 | return MatchResult{false, context}; |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 131 | } |
| 132 | } |
swissChili | 7babd92 | 2021-12-02 22:46:48 -0800 | [diff] [blame] | 133 | } |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 134 | |
swissChili | 923bd53 | 2021-12-08 22:48:58 -0800 | [diff] [blame] | 135 | qFatal("FALLING THROUGH, THIS SHOULD NOT HAPPEN"); |
swissChili | 3e98c06 | 2021-12-04 22:07:38 -0800 | [diff] [blame] | 136 | // Fallthrough |
| 137 | return MatchResult{false, context}; |
swissChili | 7babd92 | 2021-12-02 22:46:48 -0800 | [diff] [blame] | 138 | } |