mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44:20 +03:00
Pattern Matching для списков
This commit is contained in:
parent
32d40d9d04
commit
f5c19e06d1
@ -205,3 +205,10 @@ println object1.arr
|
|||||||
println object1.arr[0][1]
|
println object1.arr[0][1]
|
||||||
object1.arr[0][1] = "str"
|
object1.arr[0][1] = "str"
|
||||||
println object1.arr[0][1]
|
println object1.arr[0][1]
|
||||||
|
|
||||||
|
println arrayRecursive([1, 2, 3, 4, 5, 6, 7])
|
||||||
|
def arrayRecursive(arr) = match arr {
|
||||||
|
case [head :: tail]: "[" + head + ", " + arrayRecursive(tail) + "]"
|
||||||
|
case []: "[]"
|
||||||
|
case last: "[" + last + ", []]"
|
||||||
|
}
|
@ -264,25 +264,38 @@ public final class Parser {
|
|||||||
MatchExpression.Pattern pattern = null;
|
MatchExpression.Pattern pattern = null;
|
||||||
final Token current = get(0);
|
final Token current = get(0);
|
||||||
if (match(TokenType.NUMBER)) {
|
if (match(TokenType.NUMBER)) {
|
||||||
|
// case 0.5:
|
||||||
pattern = new MatchExpression.ConstantPattern(
|
pattern = new MatchExpression.ConstantPattern(
|
||||||
new NumberValue(Double.parseDouble(current.getText()))
|
new NumberValue(Double.parseDouble(current.getText()))
|
||||||
);
|
);
|
||||||
} else if (match(TokenType.HEX_NUMBER)) {
|
} else if (match(TokenType.HEX_NUMBER)) {
|
||||||
|
// case #FF:
|
||||||
pattern = new MatchExpression.ConstantPattern(
|
pattern = new MatchExpression.ConstantPattern(
|
||||||
new NumberValue(Long.parseLong(current.getText(), 16))
|
new NumberValue(Long.parseLong(current.getText(), 16))
|
||||||
);
|
);
|
||||||
} else if (match(TokenType.TEXT)) {
|
} else if (match(TokenType.TEXT)) {
|
||||||
|
// case "text":
|
||||||
pattern = new MatchExpression.ConstantPattern(
|
pattern = new MatchExpression.ConstantPattern(
|
||||||
new StringValue(current.getText())
|
new StringValue(current.getText())
|
||||||
);
|
);
|
||||||
} else if (match(TokenType.WORD)) {
|
} else if (match(TokenType.WORD)) {
|
||||||
|
// case value:
|
||||||
pattern = new MatchExpression.VariablePattern(current.getText());
|
pattern = new MatchExpression.VariablePattern(current.getText());
|
||||||
|
} else if (match(TokenType.LBRACKET)) {
|
||||||
|
// case [x :: xs]:
|
||||||
|
final MatchExpression.ListPattern listPattern = new MatchExpression.ListPattern();
|
||||||
|
while (!match(TokenType.RBRACKET)) {
|
||||||
|
listPattern.add(consume(TokenType.WORD).getText());
|
||||||
|
match(TokenType.COLONCOLON);
|
||||||
|
}
|
||||||
|
pattern = listPattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pattern == null) {
|
if (pattern == null) {
|
||||||
throw new ParseException("Wrong pattern in match expression: " + current);
|
throw new ParseException("Wrong pattern in match expression: " + current);
|
||||||
}
|
}
|
||||||
if (match(TokenType.IF)) {
|
if (match(TokenType.IF)) {
|
||||||
|
// case e if e > 0:
|
||||||
pattern.optCondition = expression();
|
pattern.optCondition = expression();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package com.annimon.ownlang.parser.ast;
|
package com.annimon.ownlang.parser.ast;
|
||||||
|
|
||||||
import com.annimon.ownlang.exceptions.PatternMatchingException;
|
import com.annimon.ownlang.exceptions.PatternMatchingException;
|
||||||
|
import com.annimon.ownlang.lib.ArrayValue;
|
||||||
import com.annimon.ownlang.lib.NumberValue;
|
import com.annimon.ownlang.lib.NumberValue;
|
||||||
|
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.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,10 +51,94 @@ public final class MatchExpression implements Expression {
|
|||||||
Variables.remove(pattern.variable);
|
Variables.remove(pattern.variable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((value.type() == Types.ARRAY) && (p instanceof ListPattern)) {
|
||||||
|
final ListPattern pattern = (ListPattern) p;
|
||||||
|
if (matchListPattern((ArrayValue) value, pattern)) {
|
||||||
|
// Clean up variables if matched
|
||||||
|
final Value result = evalResult(p.result);
|
||||||
|
for (String var : pattern.parts) {
|
||||||
|
Variables.remove(var);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw new PatternMatchingException("No pattern were matched");
|
throw new PatternMatchingException("No pattern were matched");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean matchListPattern(ArrayValue array, ListPattern p) {
|
||||||
|
final List<String> parts = p.parts;
|
||||||
|
final int partsSize = parts.size();
|
||||||
|
final int arraySize = array.size();
|
||||||
|
switch (partsSize) {
|
||||||
|
case 0: // match [] { case []: ... }
|
||||||
|
if ((arraySize == 0) && optMatches(p)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 1: // match arr { case [x]: x = arr ... }
|
||||||
|
final String variable = parts.get(0);
|
||||||
|
Variables.set(variable, array);
|
||||||
|
if (optMatches(p)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Variables.remove(variable);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default: { // match arr { case [...]: .. }
|
||||||
|
if (partsSize == arraySize) {
|
||||||
|
// match [0, 1, 2] { case [a::b::c]: a=0, b=1, c=2 ... }
|
||||||
|
return matchListPatternEqualsSize(p, parts, partsSize, array);
|
||||||
|
} else if (partsSize < arraySize) {
|
||||||
|
// match [1, 2, 3] { case [head :: tail]: ... }
|
||||||
|
return matchListPatternWithTail(p, parts, partsSize, array, arraySize);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchListPatternEqualsSize(ListPattern p, List<String> parts, int partsSize, ArrayValue array) {
|
||||||
|
// Set variables
|
||||||
|
for (int i = 0; i < partsSize; i++) {
|
||||||
|
Variables.set(parts.get(i), array.get(i));
|
||||||
|
}
|
||||||
|
if (optMatches(p)) {
|
||||||
|
// Clean up will be provided after evaluate result
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Clean up variables if no match
|
||||||
|
for (String var : parts) {
|
||||||
|
Variables.remove(var);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchListPatternWithTail(ListPattern p, List<String> parts, int partsSize, ArrayValue array, int arraySize) {
|
||||||
|
// Set element variables
|
||||||
|
final int lastPart = partsSize - 1;
|
||||||
|
for (int i = 0; i < lastPart; i++) {
|
||||||
|
Variables.set(parts.get(i), array.get(i));
|
||||||
|
}
|
||||||
|
// Set tail variable
|
||||||
|
final ArrayValue tail = new ArrayValue(arraySize - partsSize + 1);
|
||||||
|
for (int i = lastPart; i < arraySize; i++) {
|
||||||
|
tail.set(i - lastPart, array.get(i));
|
||||||
|
}
|
||||||
|
Variables.set(parts.get(lastPart), tail);
|
||||||
|
// Check optional condition
|
||||||
|
if (optMatches(p)) {
|
||||||
|
// Clean up will be provided after evaluate result
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Clean up variables
|
||||||
|
for (String var : parts) {
|
||||||
|
Variables.remove(var);
|
||||||
|
}
|
||||||
|
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);
|
||||||
@ -117,4 +204,25 @@ public final class MatchExpression implements Expression {
|
|||||||
return variable + ": " + result;
|
return variable + ": " + result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ListPattern extends Pattern {
|
||||||
|
public List<String> parts;
|
||||||
|
|
||||||
|
public ListPattern() {
|
||||||
|
this(new ArrayList<String>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListPattern(List<String> parts) {
|
||||||
|
this.parts = parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(String part) {
|
||||||
|
parts.add(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return parts + ": " + result;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user