-
Notifications
You must be signed in to change notification settings - Fork 15
/
pattern_array.go
87 lines (76 loc) · 1.97 KB
/
pattern_array.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package rel
import (
"bytes"
"fmt"
)
type ArrayPattern struct {
items []Pattern
}
func NewArrayPattern(elements ...Pattern) ArrayPattern {
return ArrayPattern{elements}
}
func (p ArrayPattern) Bind(local Scope, value Value) (Scope, error) {
if s, is := value.(GenericSet); is {
if s.set.IsEmpty() {
if len(p.items) == 0 {
return EmptyScope, nil
}
return EmptyScope, fmt.Errorf("value [] is empty but pattern %s is not", p)
}
return EmptyScope, fmt.Errorf("value %s is not an array", value)
}
array, is := value.(Array)
if !is {
return EmptyScope, fmt.Errorf("value %s is not an array", value)
}
extraElements := make(map[int]int)
for i, item := range p.items {
if _, is := item.(ExtraElementPattern); is {
if len(extraElements) == 1 {
return EmptyScope, fmt.Errorf("non-deterministic pattern is not supported yet")
}
extraElements[i] = array.Count() - len(p.items)
}
}
if len(p.items) > array.Count()+len(extraElements) {
return EmptyScope, fmt.Errorf("length of array %s shorter than array pattern %s", array, p)
}
if len(extraElements) == 0 && len(p.items) < array.Count() {
return EmptyScope, fmt.Errorf("length of array %s longer than array pattern %s", array, p)
}
result := EmptyScope
offset := 0
for i, item := range p.items {
if _, is := item.(ExtraElementPattern); is {
offset = extraElements[i]
arr := NewArray()
if offset >= 0 {
arr = NewArray(array.Values()[i : i+offset+1]...)
}
scope, err := item.Bind(local, arr)
if err != nil {
return EmptyScope, err
}
result = result.MatchedUpdate(scope)
continue
}
scope, err := item.Bind(local, array.Values()[i+offset])
if err != nil {
return EmptyScope, err
}
result = result.MatchedUpdate(scope)
}
return result, nil
}
func (p ArrayPattern) String() string {
var b bytes.Buffer
b.WriteByte('[')
for i, item := range p.items {
if i > 0 {
b.WriteString(", ")
}
b.WriteString(item.String())
}
b.WriteByte(']')
return b.String()
}