This repository has been archived by the owner on Jan 26, 2018. It is now read-only.
/
code.go
123 lines (100 loc) · 2.18 KB
/
code.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package gopush
import (
"math"
"reflect"
)
// Code is the internal list representation of a (partial) Push program.
type Code struct {
Length int
Literal string
List []Code
}
func (c Code) String() string {
if c.Literal != "" {
return c.Literal
}
s := "( "
for _, v := range c.List {
s += v.String() + " "
}
return s + ")"
}
// ParseCode takes the provided Push program and parses it into the internal
// list representation (type Code).
func ParseCode(program string) (c Code, err error) {
t := ""
p := program
for len(p) > 0 {
p = ignoreWhiteSpace(p, true)
t, p = getToken(p)
if t == "" {
break
}
if t == "(" {
t, p, err = getToParen(p)
if err != nil {
return Code{}, err
}
sublist, err := ParseCode(t)
if err != nil {
return Code{}, err
}
c.List = append(c.List, sublist)
c.Length += 1 + sublist.Length
} else {
c.List = append(c.List, Code{Length: 1, Literal: t})
c.Length++
}
}
return c, nil
}
// Container returns the "container" of the given Code c2 in c. That is, it
// returns the smallest sublist of c which contains c2, or the empty list if
// none of the sublists in c contain c2.
func (c Code) Container(c2 Code) (container Code) {
container.Length = math.MaxInt32
if c.Literal != "" {
return
}
for _, sl := range c.List {
if reflect.DeepEqual(sl, c2) && c.Length < container.Length {
container = c
} else {
candidate := sl.Container(c2)
if candidate.Length < container.Length {
container = candidate
}
}
}
if container.Length == math.MaxInt32 {
return Code{}
}
return container
}
// Contains returns whether the Code c is equal to c2 or contains it in any
// sublist
func (c Code) Contains(c2 Code) bool {
if reflect.DeepEqual(c, c2) {
return true
}
for _, sl := range c.List {
if sl.Contains(c2) {
return true
}
}
return false
}
// UniqueItems returns a map with the count of all unique items in the Code list
func (c Code) UniqueItems() map[string]int64 {
result := make(map[string]int64)
if c.Literal != "" {
result[c.Literal]++
return result
}
for _, sl := range c.List {
for k, v := range sl.UniqueItems() {
result[k] += v
}
}
return result
}