Change list pattern matcher behavior for single element

match [1] {
  case [x]:
}
Before: x = [1]
After: x = 1

x will be the first (and single) value of an array
This commit is contained in:
aNNiMON 2023-09-07 19:27:47 +03:00 committed by Victor Melnik
parent 32bffaee86
commit cce75927b8
3 changed files with 58 additions and 19 deletions

View File

@ -36,7 +36,7 @@ println printArrayRecursive([1, 2, 3, 4, 5, 6, 7])
def printArrayRecursive(arr) = match arr { def printArrayRecursive(arr) = match arr {
case [head :: tail]: "[" + head + ", " + printArrayRecursive(tail) + "]" case [head :: tail]: "[" + head + ", " + printArrayRecursive(tail) + "]"
case []: "[]" case []: "[]"
case last: "[" + last + ", []]" case other: "[" + other + ", []]"
} }
println "\nPattern matching on arrays by value" println "\nPattern matching on arrays by value"

View File

@ -90,10 +90,14 @@ public final class MatchExpression extends InterruptableNode implements Expressi
case 0: // match [] { case []: ... } case 0: // match [] { case []: ... }
return (arraySize == 0) && optMatches(p); return (arraySize == 0) && optMatches(p);
case 1: // match arr { case [x]: x = arr ... } case 1: // match arr { case [x]: x = arr[0] ... }
if (arraySize == 1) {
final String variable = parts.get(0); final String variable = parts.get(0);
ScopeHandler.defineVariableInCurrentScope(variable, array); final var value = array.get(0);
ScopeHandler.defineVariableInCurrentScope(variable, value);
return optMatches(p); return optMatches(p);
}
return false;
default: { // match arr { case [...]: .. } default: { // match arr { case [...]: .. }
if (partsSize == arraySize) { if (partsSize == arraySize) {

View File

@ -43,7 +43,8 @@ def testMatchAdditionalCheckScope() {
def printArrayRecursive(arr) = match arr { def printArrayRecursive(arr) = match arr {
case [head :: tail]: "[" + head + ", " + printArrayRecursive(tail) + "]" case [head :: tail]: "[" + head + ", " + printArrayRecursive(tail) + "]"
case []: "[]" case []: "[]"
case last: "[" + last + ", []]" case [last]: "[" + last + ", []]"
case value: value
} }
def testMatchEmptyArray() { def testMatchEmptyArray() {
@ -53,17 +54,17 @@ def testMatchEmptyArray() {
def testMatchOneElementArray() { def testMatchOneElementArray() {
result = printArrayRecursive([1]) result = printArrayRecursive([1])
assertEquals("[[1], []]", result) assertEquals("[1, []]", result)
} }
def testMatchTwoElementsArray() { def testMatchTwoElementsArray() {
result = printArrayRecursive([1, 2]) result = printArrayRecursive([1, 2])
assertEquals("[1, [2, []]]", result) assertEquals("[1, 2]", result)
} }
def testMatchArray() { def testMatchArray() {
result = printArrayRecursive([1, 2, 3, 4]) result = printArrayRecursive([1, 2, 3, 4])
assertEquals("[1, [2, [3, [4, []]]]]", result) assertEquals("[1, [2, [3, 4]]]", result)
} }
def testMatchArray2() { def testMatchArray2() {
@ -73,9 +74,9 @@ def testMatchArray2() {
case [a :: b :: c]: 3 case [a :: b :: c]: 3
case [a :: b]: 2 case [a :: b]: 2
case (7): -7 // special case 1 case (7): -7 // special case 1
case [a] if a == [8]: -8 // special case 2 case [a] if a == 8: -8 // special case 2
case []: 0
case [a]: 1 case [a]: 1
case []: 0
} }
assertEquals(4, elementsCount([1, 2, 3, 4])) assertEquals(4, elementsCount([1, 2, 3, 4]))
assertEquals(3, elementsCount([1, 2, 3])) assertEquals(3, elementsCount([1, 2, 3]))
@ -86,6 +87,16 @@ def testMatchArray2() {
assertEquals(0, elementsCount([])) assertEquals(0, elementsCount([]))
} }
def testMatchArray3() {
def elementD(arr) = match arr {
case [a :: b :: c :: d]: d
case _: []
}
assertEquals(4, elementD([1, 2, 3, 4]))
assertEquals([4, 5, 6], elementD([1, 2, 3, 4, 5, 6]))
assertEquals([], elementD([1, 2]))
}
def testMatchOneElementArrayScope() { def testMatchOneElementArrayScope() {
head = 100 head = 100
tail = 200 tail = 200
@ -102,16 +113,16 @@ def testMatchOneElementArrayScope() {
def testMatchOneElementArrayDefinedVariableScope() { def testMatchOneElementArrayDefinedVariableScope() {
head = 100 head = 100
tail = 200 tail = 200
last = 300 rest = 300
result = match [1] { result = match [1] {
case [head :: tail]: fail("Multi-array") case [head :: tail]: fail("Multi-array")
case []: fail("Empty array") case []: fail("Empty array")
case last: fail("Array should not be equal " + last) case rest: fail("Array should not be equal " + rest)
case rest: assertEquals(1, rest[0]) case [last]: assertEquals(1, last)
} }
assertEquals(100, head) assertEquals(100, head)
assertEquals(200, tail) assertEquals(200, tail)
assertEquals(300, last) assertEquals(300, rest)
assertEquals(true, result) assertEquals(true, result)
} }
@ -121,7 +132,7 @@ def testMatchArrayScope() {
result = match [1, 2, 3] { result = match [1, 2, 3] {
case [head :: tail]: assertEquals(1, head) case [head :: tail]: assertEquals(1, head)
case []: fail("Empty array") case []: fail("Empty array")
case last: fail("One element") case [last]: fail("One element")
} }
assertEquals(100, head) assertEquals(100, head)
assertEquals(200, tail) assertEquals(200, tail)
@ -173,7 +184,31 @@ def testMatchTupleAny3() {
assertEquals("_", result) assertEquals("_", result)
} }
def testScope() { def testDestructuringArray() {
parsedData = [
["Kyiv", 839, 3017000, "Ukraine", "...", "..."],
["Shebekino", "N/A", "invalid"],
["New York", 783.8, 18937000, "USA", "..."],
["N/A"],
[]
]
cities = []
areas = []
for row : parsedData {
match row {
// Match fully parsed data
case [name :: area :: population :: country]: {
cities ::= name
areas ::= area
}
// Match partially parsed data, which contains a city name and some other unknown values
case [name :: rest]: {
cities ::= name
}
// Match other invalid data
case arr: /* skip */ 0
}
}
assertEquals(["Kyiv", "Shebekino", "New York"], cities)
assertEquals([839, 783.8], areas)
} }