/
immSlice.go
116 lines (90 loc) · 1.87 KB
/
immSlice.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
package main
import (
"go/ast"
"go/types"
"text/template"
"myitcv.io/immutable"
"myitcv.io/immutable/util"
)
type immSlice struct {
commonImm
// the name of the type to generate; not the pointer version
name string
syn *ast.ArrayType
typ *types.Slice
}
func (o *output) genImmSlices(slices []*immSlice) {
for _, s := range slices {
blanks := struct {
Name string
Type string
}{
Name: s.name,
Type: o.exprString(s.syn.Elt),
}
exp := exporter(s.name)
o.printCommentGroup(s.dec.Doc)
o.printImmPreamble(s.name, s.syn)
// start of struct
o.pfln("type %v struct {", s.name)
o.pln("")
o.pfln("theSlice []%v", blanks.Type)
o.pln("mutable bool")
o.pfln("__tmpl *%v%v", immutable.ImmTypeTmplPrefix, s.name)
// end of struct
o.pfln("}")
tmpl := template.New("immslice")
tmpl.Funcs(exp)
_, err := tmpl.Parse(immSliceTmpl)
if err != nil {
fatalf("failed to parse immutable slice template: %v", err)
}
err = tmpl.Execute(o.output, blanks)
if err != nil {
fatalf("failed to execute immutable slice template: %v", err)
}
o.pt(`
func (s *{{.}}) IsDeeplyNonMutable(seen map[interface{}]bool) bool {
if s == nil {
return true
}
if s.Mutable() {
return false
}
`, exp, s.name)
valIsImm := o.isImm(s.typ.Elem(), o.exprString(s.syn.Elt))
valIsImmOk := false
switch valIsImm.(type) {
case nil, util.ImmTypeBasic:
default:
valIsImmOk = true
}
if valIsImmOk {
o.pt(`
if s.Len() == 0 {
return true
}
if seen == nil {
return s.IsDeeplyNonMutable(make(map[interface{}]bool))
}
if seen[s] {
return true
}
seen[s] = true
for _, v := range s.theSlice {
`, exp, s.name)
o.pt(`
if v != nil && !v.IsDeeplyNonMutable(seen) {
return false
}
`, exp, s.name)
o.pt(`
}
`, exp, s.name)
}
o.pt(`
return true
}
`, exp, s.name)
}
}