Skip to content

Commit 726e964

Browse files
committed
Pattern matching по значениям списка
1 parent b957569 commit 726e964

File tree

3 files changed

+146
-22
lines changed

3 files changed

+146
-22
lines changed

examples/basics/pattern_matching.own

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,28 @@ def printArrayRecursive(arr) = match arr {
3838
case []: "[]"
3939
case last: "[" + last + ", []]"
4040
}
41+
42+
println "\nPattern matching on arrays by value"
43+
def tupleMatch(x) = match x {
44+
case (0, 0): "00"
45+
case (1, 0): "10"
46+
case (0, 1): "01"
47+
case (1, 1): "11"
48+
case (2, _): "2?"
49+
case _: "unknown"
50+
}
51+
println tupleMatch([0, 1])
52+
println tupleMatch([1, 1])
53+
println tupleMatch([2, 1])
54+
println tupleMatch([3, 9])
55+
56+
57+
println "\nFizzBuzz with pattern matching"
58+
for i = 1, i <= 100, i++ {
59+
println match [i % 3 == 0, i % 5 == 0] {
60+
case (true, false): "Fizz"
61+
case (false, true): "Buzz"
62+
case (true, true): "FizzBuzz"
63+
case _: i
64+
}
65+
}

src/com/annimon/ownlang/parser/Parser.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,19 @@ private MatchExpression match() {
368368
match(TokenType.COLONCOLON);
369369
}
370370
pattern = listPattern;
371+
} else if (match(TokenType.LPAREN)) {
372+
// case (1, 2):
373+
final MatchExpression.TuplePattern tuplePattern = new MatchExpression.TuplePattern();
374+
while (!match(TokenType.RPAREN)) {
375+
if ("_".equals(get(0).getText())) {
376+
tuplePattern.addAny();
377+
consume(TokenType.WORD);
378+
} else {
379+
tuplePattern.add(expression());
380+
}
381+
match(TokenType.COMMA);
382+
}
383+
pattern = tuplePattern;
371384
}
372385

373386
if (pattern == null) {

src/com/annimon/ownlang/parser/ast/MatchExpression.java

Lines changed: 108 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,28 @@
77
import com.annimon.ownlang.lib.Value;
88
import com.annimon.ownlang.lib.Variables;
99
import java.util.ArrayList;
10+
import java.util.Iterator;
1011
import java.util.List;
1112

1213
/**
1314
*
1415
* @author aNNiMON
1516
*/
1617
public final class MatchExpression implements Expression, Statement {
17-
18+
1819
public final Expression expression;
1920
public final List<Pattern> patterns;
2021

2122
public MatchExpression(Expression expression, List<Pattern> patterns) {
2223
this.expression = expression;
2324
this.patterns = patterns;
2425
}
25-
26+
2627
@Override
2728
public void execute() {
2829
eval();
2930
}
30-
31+
3132
@Override
3233
public Value eval() {
3334
final Value value = expression.eval();
@@ -41,15 +42,15 @@ public Value eval() {
4142
if (p instanceof VariablePattern) {
4243
final VariablePattern pattern = (VariablePattern) p;
4344
if (pattern.variable.equals("_")) return evalResult(p.result);
44-
45+
4546
if (Variables.isExists(pattern.variable)) {
4647
if (match(value, Variables.get(pattern.variable)) && optMatches(p)) {
4748
return evalResult(p.result);
4849
}
4950
} else {
5051
Variables.define(pattern.variable, value);
5152
if (optMatches(p)) {
52-
final Value result = evalResult(p.result);;
53+
final Value result = evalResult(p.result);
5354
Variables.remove(pattern.variable);
5455
return result;
5556
}
@@ -67,10 +68,29 @@ public Value eval() {
6768
return result;
6869
}
6970
}
71+
if ((value.type() == Types.ARRAY) && (p instanceof TuplePattern)) {
72+
final TuplePattern pattern = (TuplePattern) p;
73+
if (matchTuplePattern((ArrayValue) value, pattern) && optMatches(p)) {
74+
return evalResult(p.result);
75+
}
76+
}
7077
}
7178
throw new PatternMatchingException("No pattern were matched");
7279
}
73-
80+
81+
private boolean matchTuplePattern(ArrayValue array, TuplePattern p) {
82+
if (p.values.size() != array.size()) return false;
83+
84+
final int size = array.size();
85+
for (int i = 0; i < size; i++) {
86+
final Expression expr = p.values.get(i);
87+
if ( (expr != TuplePattern.ANY) && (expr.eval().compareTo(array.get(i)) != 0) ) {
88+
return false;
89+
}
90+
}
91+
return true;
92+
}
93+
7494
private boolean matchListPattern(ArrayValue array, ListPattern p) {
7595
final List<String> parts = p.parts;
7696
final int partsSize = parts.size();
@@ -90,7 +110,7 @@ private boolean matchListPattern(ArrayValue array, ListPattern p) {
90110
}
91111
Variables.remove(variable);
92112
return false;
93-
113+
94114
default: { // match arr { case [...]: .. }
95115
if (partsSize == arraySize) {
96116
// match [0, 1, 2] { case [a::b::c]: a=0, b=1, c=2 ... }
@@ -102,7 +122,7 @@ private boolean matchListPattern(ArrayValue array, ListPattern p) {
102122
return false;
103123
}
104124
}
105-
}
125+
}
106126

107127
private boolean matchListPatternEqualsSize(ListPattern p, List<String> parts, int partsSize, ArrayValue array) {
108128
// Set variables
@@ -119,7 +139,7 @@ private boolean matchListPatternEqualsSize(ListPattern p, List<String> parts, in
119139
}
120140
return false;
121141
}
122-
142+
123143
private boolean matchListPatternWithTail(ListPattern p, List<String> parts, int partsSize, ArrayValue array, int arraySize) {
124144
// Set element variables
125145
final int lastPart = partsSize - 1;
@@ -143,17 +163,17 @@ private boolean matchListPatternWithTail(ListPattern p, List<String> parts, int
143163
}
144164
return false;
145165
}
146-
166+
147167
private boolean match(Value value, Value constant) {
148168
if (value.type() != constant.type()) return false;
149169
return value.equals(constant);
150170
}
151-
171+
152172
private boolean optMatches(Pattern pattern) {
153173
if (pattern.optCondition == null) return true;
154174
return pattern.optCondition.eval() != NumberValue.ZERO;
155175
}
156-
176+
157177
private Value evalResult(Statement s) {
158178
try {
159179
s.execute();
@@ -162,7 +182,7 @@ private Value evalResult(Statement s) {
162182
}
163183
return NumberValue.ZERO;
164184
}
165-
185+
166186
@Override
167187
public void accept(Visitor visitor) {
168188
visitor.visit(this);
@@ -183,15 +203,15 @@ public String toString() {
183203
sb.append("\n}");
184204
return sb.toString();
185205
}
186-
206+
187207
public static abstract class Pattern {
188208
public Statement result;
189209
public Expression optCondition;
190210
}
191-
211+
192212
public static class ConstantPattern extends Pattern {
193213
public Value constant;
194-
214+
195215
public ConstantPattern(Value pattern) {
196216
this.constant = pattern;
197217
}
@@ -201,10 +221,10 @@ public String toString() {
201221
return constant + ": " + result;
202222
}
203223
}
204-
224+
205225
public static class VariablePattern extends Pattern {
206226
public String variable;
207-
227+
208228
public VariablePattern(String pattern) {
209229
this.variable = pattern;
210230
}
@@ -214,14 +234,14 @@ public String toString() {
214234
return variable + ": " + result;
215235
}
216236
}
217-
237+
218238
public static class ListPattern extends Pattern {
219239
public List<String> parts;
220-
240+
221241
public ListPattern() {
222242
this(new ArrayList<String>());
223243
}
224-
244+
225245
public ListPattern(List<String> parts) {
226246
this.parts = parts;
227247
}
@@ -232,7 +252,73 @@ public void add(String part) {
232252

233253
@Override
234254
public String toString() {
235-
return parts + ": " + result;
255+
final Iterator<String> it = parts.iterator();
256+
if (it.hasNext()) {
257+
final StringBuilder sb = new StringBuilder();
258+
sb.append("[").append(it.next());
259+
while (it.hasNext()) {
260+
sb.append(" :: ").append(it.next());
261+
}
262+
sb.append("]: ").append(result);
263+
return sb.toString();
264+
}
265+
return "[]: " + result;
266+
}
267+
}
268+
269+
public static class TuplePattern extends Pattern {
270+
public List<Expression> values;
271+
272+
public TuplePattern() {
273+
this(new ArrayList<Expression>());
236274
}
275+
276+
public TuplePattern(List<Expression> parts) {
277+
this.values = parts;
278+
}
279+
280+
public void addAny() {
281+
values.add(ANY);
282+
}
283+
284+
public void add(Expression value) {
285+
values.add(value);
286+
}
287+
288+
@Override
289+
public String toString() {
290+
final Iterator<Expression> it = values.iterator();
291+
if (it.hasNext()) {
292+
final StringBuilder sb = new StringBuilder();
293+
sb.append("(").append(it.next());
294+
while (it.hasNext()) {
295+
sb.append(", ").append(it.next());
296+
}
297+
sb.append("): ").append(result);
298+
return sb.toString();
299+
}
300+
return "(): " + result;
301+
}
302+
303+
private static final Expression ANY = new Expression() {
304+
@Override
305+
public Value eval() {
306+
return NumberValue.ONE;
307+
}
308+
309+
@Override
310+
public void accept(Visitor visitor) {
311+
}
312+
313+
@Override
314+
public <R, T> R accept(ResultVisitor<R, T> visitor, T input) {
315+
return null;
316+
}
317+
318+
@Override
319+
public String toString() {
320+
return "_";
321+
}
322+
};
237323
}
238324
}

0 commit comments

Comments
 (0)