Pattern matching по значениям списка

This commit is contained in:
Victor 2016-06-25 19:36:07 +03:00
parent b957569759
commit 726e96488a
3 changed files with 146 additions and 22 deletions

View File

@ -38,3 +38,28 @@ def printArrayRecursive(arr) = match arr {
case []: "[]" case []: "[]"
case last: "[" + last + ", []]" case last: "[" + last + ", []]"
} }
println "\nPattern matching on arrays by value"
def tupleMatch(x) = match x {
case (0, 0): "00"
case (1, 0): "10"
case (0, 1): "01"
case (1, 1): "11"
case (2, _): "2?"
case _: "unknown"
}
println tupleMatch([0, 1])
println tupleMatch([1, 1])
println tupleMatch([2, 1])
println tupleMatch([3, 9])
println "\nFizzBuzz with pattern matching"
for i = 1, i <= 100, i++ {
println match [i % 3 == 0, i % 5 == 0] {
case (true, false): "Fizz"
case (false, true): "Buzz"
case (true, true): "FizzBuzz"
case _: i
}
}

View File

@ -368,6 +368,19 @@ public final class Parser {
match(TokenType.COLONCOLON); match(TokenType.COLONCOLON);
} }
pattern = listPattern; pattern = listPattern;
} else if (match(TokenType.LPAREN)) {
// case (1, 2):
final MatchExpression.TuplePattern tuplePattern = new MatchExpression.TuplePattern();
while (!match(TokenType.RPAREN)) {
if ("_".equals(get(0).getText())) {
tuplePattern.addAny();
consume(TokenType.WORD);
} else {
tuplePattern.add(expression());
}
match(TokenType.COMMA);
}
pattern = tuplePattern;
} }
if (pattern == null) { if (pattern == null) {

View File

@ -7,6 +7,7 @@ import com.annimon.ownlang.lib.Types;
import com.annimon.ownlang.lib.Value; import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.Variables; import com.annimon.ownlang.lib.Variables;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
/** /**
@ -14,7 +15,7 @@ import java.util.List;
* @author aNNiMON * @author aNNiMON
*/ */
public final class MatchExpression implements Expression, Statement { public final class MatchExpression implements Expression, Statement {
public final Expression expression; public final Expression expression;
public final List<Pattern> patterns; public final List<Pattern> patterns;
@ -22,12 +23,12 @@ public final class MatchExpression implements Expression, Statement {
this.expression = expression; this.expression = expression;
this.patterns = patterns; this.patterns = patterns;
} }
@Override @Override
public void execute() { public void execute() {
eval(); eval();
} }
@Override @Override
public Value eval() { public Value eval() {
final Value value = expression.eval(); final Value value = expression.eval();
@ -41,7 +42,7 @@ public final class MatchExpression implements Expression, Statement {
if (p instanceof VariablePattern) { if (p instanceof VariablePattern) {
final VariablePattern pattern = (VariablePattern) p; final VariablePattern pattern = (VariablePattern) p;
if (pattern.variable.equals("_")) return evalResult(p.result); if (pattern.variable.equals("_")) return evalResult(p.result);
if (Variables.isExists(pattern.variable)) { if (Variables.isExists(pattern.variable)) {
if (match(value, Variables.get(pattern.variable)) && optMatches(p)) { if (match(value, Variables.get(pattern.variable)) && optMatches(p)) {
return evalResult(p.result); return evalResult(p.result);
@ -49,7 +50,7 @@ public final class MatchExpression implements Expression, Statement {
} else { } else {
Variables.define(pattern.variable, value); Variables.define(pattern.variable, value);
if (optMatches(p)) { if (optMatches(p)) {
final Value result = evalResult(p.result);; final Value result = evalResult(p.result);
Variables.remove(pattern.variable); Variables.remove(pattern.variable);
return result; return result;
} }
@ -67,10 +68,29 @@ public final class MatchExpression implements Expression, Statement {
return result; return result;
} }
} }
if ((value.type() == Types.ARRAY) && (p instanceof TuplePattern)) {
final TuplePattern pattern = (TuplePattern) p;
if (matchTuplePattern((ArrayValue) value, pattern) && optMatches(p)) {
return evalResult(p.result);
}
}
} }
throw new PatternMatchingException("No pattern were matched"); throw new PatternMatchingException("No pattern were matched");
} }
private boolean matchTuplePattern(ArrayValue array, TuplePattern p) {
if (p.values.size() != array.size()) return false;
final int size = array.size();
for (int i = 0; i < size; i++) {
final Expression expr = p.values.get(i);
if ( (expr != TuplePattern.ANY) && (expr.eval().compareTo(array.get(i)) != 0) ) {
return false;
}
}
return true;
}
private boolean matchListPattern(ArrayValue array, ListPattern p) { private boolean matchListPattern(ArrayValue array, ListPattern p) {
final List<String> parts = p.parts; final List<String> parts = p.parts;
final int partsSize = parts.size(); final int partsSize = parts.size();
@ -90,7 +110,7 @@ public final class MatchExpression implements Expression, Statement {
} }
Variables.remove(variable); Variables.remove(variable);
return false; return false;
default: { // match arr { case [...]: .. } default: { // match arr { case [...]: .. }
if (partsSize == arraySize) { if (partsSize == arraySize) {
// match [0, 1, 2] { case [a::b::c]: a=0, b=1, c=2 ... } // match [0, 1, 2] { case [a::b::c]: a=0, b=1, c=2 ... }
@ -102,7 +122,7 @@ public final class MatchExpression implements Expression, Statement {
return false; return false;
} }
} }
} }
private boolean matchListPatternEqualsSize(ListPattern p, List<String> parts, int partsSize, ArrayValue array) { private boolean matchListPatternEqualsSize(ListPattern p, List<String> parts, int partsSize, ArrayValue array) {
// Set variables // Set variables
@ -119,7 +139,7 @@ public final class MatchExpression implements Expression, Statement {
} }
return false; return false;
} }
private boolean matchListPatternWithTail(ListPattern p, List<String> parts, int partsSize, ArrayValue array, int arraySize) { private boolean matchListPatternWithTail(ListPattern p, List<String> parts, int partsSize, ArrayValue array, int arraySize) {
// Set element variables // Set element variables
final int lastPart = partsSize - 1; final int lastPart = partsSize - 1;
@ -143,17 +163,17 @@ public final class MatchExpression implements Expression, Statement {
} }
return false; return false;
} }
private boolean match(Value value, Value constant) { private boolean match(Value value, Value constant) {
if (value.type() != constant.type()) return false; if (value.type() != constant.type()) return false;
return value.equals(constant); return value.equals(constant);
} }
private boolean optMatches(Pattern pattern) { private boolean optMatches(Pattern pattern) {
if (pattern.optCondition == null) return true; if (pattern.optCondition == null) return true;
return pattern.optCondition.eval() != NumberValue.ZERO; return pattern.optCondition.eval() != NumberValue.ZERO;
} }
private Value evalResult(Statement s) { private Value evalResult(Statement s) {
try { try {
s.execute(); s.execute();
@ -162,7 +182,7 @@ public final class MatchExpression implements Expression, Statement {
} }
return NumberValue.ZERO; return NumberValue.ZERO;
} }
@Override @Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);
@ -183,15 +203,15 @@ public final class MatchExpression implements Expression, Statement {
sb.append("\n}"); sb.append("\n}");
return sb.toString(); return sb.toString();
} }
public static abstract class Pattern { public static abstract class Pattern {
public Statement result; public Statement result;
public Expression optCondition; public Expression optCondition;
} }
public static class ConstantPattern extends Pattern { public static class ConstantPattern extends Pattern {
public Value constant; public Value constant;
public ConstantPattern(Value pattern) { public ConstantPattern(Value pattern) {
this.constant = pattern; this.constant = pattern;
} }
@ -201,10 +221,10 @@ public final class MatchExpression implements Expression, Statement {
return constant + ": " + result; return constant + ": " + result;
} }
} }
public static class VariablePattern extends Pattern { public static class VariablePattern extends Pattern {
public String variable; public String variable;
public VariablePattern(String pattern) { public VariablePattern(String pattern) {
this.variable = pattern; this.variable = pattern;
} }
@ -214,14 +234,14 @@ public final class MatchExpression implements Expression, Statement {
return variable + ": " + result; return variable + ": " + result;
} }
} }
public static class ListPattern extends Pattern { public static class ListPattern extends Pattern {
public List<String> parts; public List<String> parts;
public ListPattern() { public ListPattern() {
this(new ArrayList<String>()); this(new ArrayList<String>());
} }
public ListPattern(List<String> parts) { public ListPattern(List<String> parts) {
this.parts = parts; this.parts = parts;
} }
@ -232,7 +252,73 @@ public final class MatchExpression implements Expression, Statement {
@Override @Override
public String toString() { public String toString() {
return parts + ": " + result; final Iterator<String> it = parts.iterator();
if (it.hasNext()) {
final StringBuilder sb = new StringBuilder();
sb.append("[").append(it.next());
while (it.hasNext()) {
sb.append(" :: ").append(it.next());
}
sb.append("]: ").append(result);
return sb.toString();
}
return "[]: " + result;
} }
} }
public static class TuplePattern extends Pattern {
public List<Expression> values;
public TuplePattern() {
this(new ArrayList<Expression>());
}
public TuplePattern(List<Expression> parts) {
this.values = parts;
}
public void addAny() {
values.add(ANY);
}
public void add(Expression value) {
values.add(value);
}
@Override
public String toString() {
final Iterator<Expression> it = values.iterator();
if (it.hasNext()) {
final StringBuilder sb = new StringBuilder();
sb.append("(").append(it.next());
while (it.hasNext()) {
sb.append(", ").append(it.next());
}
sb.append("): ").append(result);
return sb.toString();
}
return "(): " + result;
}
private static final Expression ANY = new Expression() {
@Override
public Value eval() {
return NumberValue.ONE;
}
@Override
public void accept(Visitor visitor) {
}
@Override
public <R, T> R accept(ResultVisitor<R, T> visitor, T input) {
return null;
}
@Override
public String toString() {
return "_";
}
};
}
} }