1
2 package ast
3
4 import (
5 "fmt"
6 "sort"
7 "strconv"
8 "strings"
9 )
10
11
12
13
14
15
16
17
18
19 type Position struct {
20 Byte uint32
21 Line int32
22 Column int32
23 }
24
25
26 type Node struct {
27
28
29
30
31
32 Start Position
33
34
35 PreComments []string
36
37
38
39
40 Name string
41
42 Values []*Value
43
44 Children []*Node
45
46 Deleted bool
47
48
49 SkipColon bool
50
51
52 ChildrenSameLine bool
53
54 ClosingBraceComment string
55
56
57
58
59 End Position
60
61 ValuesAsList bool
62
63 ChildrenAsList bool
64
65
66
67
68
69
70
71 PostValuesComments []string
72
73 IsAngleBracket bool
74 }
75
76
77
78 type NodeLess func(parent, a, b *Node, isWholeSlice bool) bool
79
80
81
82 func ChainNodeLess(first, second NodeLess) NodeLess {
83 if first == nil {
84 return second
85 }
86 if second == nil {
87 return first
88 }
89 return func(parent, a, b *Node, isWholeSlice bool) bool {
90 if isALess := first(parent, a, b, isWholeSlice); isALess {
91 return true
92 }
93 if isBLess := first(parent, b, a, isWholeSlice); isBLess {
94 return false
95 }
96 return second(parent, a, b, isWholeSlice)
97 }
98 }
99
100
101 func SortNodes(parent *Node, ns []*Node, less NodeLess) {
102 sort.Stable(sortableNodes(parent, ns, less, true ))
103 end := 0
104 for begin := 0; begin < len(ns); begin = end {
105 for end = begin + 1; end < len(ns) && ns[begin].Name == ns[end].Name; end++ {
106 }
107 sort.Stable(sortableNodes(parent, ns[begin:end], less, false ))
108 }
109 }
110
111
112 func sortableNodes(parent *Node, ns []*Node, less NodeLess, isWholeSlice bool) sort.Interface {
113 return sortable{parent, ns, less, isWholeSlice}
114 }
115
116 type sortable struct {
117 parent *Node
118 ns []*Node
119 less NodeLess
120 isWholeSlice bool
121 }
122
123 func (s sortable) Len() int {
124 return len(s.ns)
125 }
126
127 func (s sortable) Swap(i, j int) {
128 s.ns[i], s.ns[j] = s.ns[j], s.ns[i]
129 }
130
131 func (s sortable) Less(i, j int) bool {
132 if s.less == nil {
133 return false
134 }
135 return s.less(s.parent, s.ns[i], s.ns[j], s.isWholeSlice)
136 }
137
138
139 func ByFieldName(_, ni, nj *Node, isWholeSlice bool) bool {
140 return ni.Name < nj.Name
141 }
142
143 func getFieldValueForByFieldValue(n *Node) *Value {
144 if len(n.Values) != 1 {
145 return nil
146 }
147 return n.Values[0]
148 }
149
150
151
152 func ByFieldValue(_, ni, nj *Node, isWholeSlice bool) bool {
153 if isWholeSlice {
154 return false
155 }
156 vi := getFieldValueForByFieldValue(ni)
157 vj := getFieldValueForByFieldValue(nj)
158 if vi == nil {
159 return vj != nil
160 }
161 if vj == nil {
162 return false
163 }
164 return vi.Value < vj.Value
165 }
166
167 func getChildValueByFieldSubfield(field, subfield string, n *Node) *Value {
168 if field != "" {
169 if n.Name != field {
170 return nil
171 }
172 }
173 return n.getChildValue(subfield)
174 }
175
176
177
178
179 func ByFieldSubfield(field, subfield string) NodeLess {
180 return func(_, ni, nj *Node, isWholeSlice bool) bool {
181 if isWholeSlice {
182 return false
183 }
184 vi := getChildValueByFieldSubfield(field, subfield, ni)
185 vj := getChildValueByFieldSubfield(field, subfield, nj)
186 if vi == nil {
187 return vj != nil
188 }
189 if vj == nil {
190 return false
191 }
192 return vi.Value < vj.Value
193 }
194 }
195
196
197
198 func (n *Node) getChildValue(field string) *Value {
199 for _, c := range n.Children {
200 if c.Name == field {
201 if len(c.Values) != 1 {
202 return nil
203 }
204 return c.Values[0]
205 }
206 }
207 return nil
208 }
209
210
211 func (n *Node) IsCommentOnly() bool {
212 return n.Name == "" && n.Children == nil
213 }
214
215 type fixData struct {
216 inline bool
217 }
218
219
220
221
222
223 func (n *Node) Fix() {
224 n.fix()
225 }
226
227 func isRealPosition(p Position) bool {
228 return p.Byte != 0 || p.Line != 0 || p.Column != 0
229 }
230
231 func (n *Node) fix() fixData {
232 isEmptyAndWasOriginallyInline := !(isRealPosition(n.Start) && isRealPosition(n.End) && n.End.Line-n.Start.Line > 0)
233 d := fixData{
234
235
236 inline: n.ChildrenSameLine || (len(n.Children) == 0 && isEmptyAndWasOriginallyInline && len(n.Values) <= 1),
237 }
238
239 for _, c := range n.Children {
240 if c.Deleted {
241 continue
242 }
243
244 cd := c.fix()
245 if !cd.inline {
246 d.inline = false
247 }
248 }
249
250 for _, v := range n.Values {
251 vd := v.fix()
252 if !vd.inline {
253 d.inline = false
254 }
255 }
256
257 n.ChildrenSameLine = d.inline
258
259
260
261 if len(n.PreComments) > 0 || len(n.ClosingBraceComment) > 0 {
262 d.inline = false
263 }
264
265 return d
266 }
267
268
269 func StringNode(name, unquoted string) *Node {
270 return &Node{Name: name, Values: []*Value{{Value: strconv.Quote(unquoted)}}}
271 }
272
273
274 type Value struct {
275
276
277 PreComments []string
278
279 Value string
280
281 InlineComment string
282 }
283
284 func (v *Value) String() string {
285 return fmt.Sprintf("{Value: %q, PreComments: %q, InlineComment: %q}", v.Value, strings.Join(v.PreComments, "\n"), v.InlineComment)
286 }
287
288 func (v *Value) fix() fixData {
289 return fixData{
290 inline: len(v.PreComments) == 0 && v.InlineComment == "",
291 }
292 }
293
294
295 func GetFromPath(nodes []*Node, path []string) []*Node {
296 if len(path) == 0 {
297 return nil
298 }
299 res := []*Node{}
300 for _, node := range nodes {
301 if node.Name == path[0] {
302 if len(path) == 1 {
303 res = append(res, node)
304 } else {
305 res = append(res, GetFromPath(node.Children, path[1:])...)
306 }
307 }
308 }
309 return res
310 }
311
View as plain text