• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package parser
16
17import (
18	"sort"
19	"text/scanner"
20)
21
22func SortLists(file *File) {
23	for _, def := range file.Defs {
24		if assignment, ok := def.(*Assignment); ok {
25			sortListsInValue(assignment.Value, file)
26		} else if module, ok := def.(*Module); ok {
27			for _, prop := range module.Properties {
28				sortListsInValue(prop.Value, file)
29			}
30		}
31	}
32	sort.Sort(commentsByOffset(file.Comments))
33}
34
35func SortList(file *File, list *List) {
36	for i := 0; i < len(list.Values); i++ {
37		// Find a set of values on contiguous lines
38		line := list.Values[i].Pos().Line
39		var j int
40		for j = i + 1; j < len(list.Values); j++ {
41			if list.Values[j].Pos().Line > line+1 {
42				break
43			}
44			line = list.Values[j].Pos().Line
45		}
46
47		nextPos := list.End()
48		if j < len(list.Values) {
49			nextPos = list.Values[j].Pos()
50		}
51		sortSubList(list.Values[i:j], nextPos, file)
52		i = j - 1
53	}
54}
55
56func ListIsSorted(list *List) bool {
57	for i := 0; i < len(list.Values); i++ {
58		// Find a set of values on contiguous lines
59		line := list.Values[i].Pos().Line
60		var j int
61		for j = i + 1; j < len(list.Values); j++ {
62			if list.Values[j].Pos().Line > line+1 {
63				break
64			}
65			line = list.Values[j].Pos().Line
66		}
67
68		if !subListIsSorted(list.Values[i:j]) {
69			return false
70		}
71		i = j - 1
72	}
73
74	return true
75}
76
77func sortListsInValue(value Expression, file *File) {
78	switch v := value.(type) {
79	case *Variable:
80		// Nothing
81	case *Operator:
82		sortListsInValue(v.Args[0], file)
83		sortListsInValue(v.Args[1], file)
84	case *Map:
85		for _, p := range v.Properties {
86			sortListsInValue(p.Value, file)
87		}
88	case *List:
89		SortList(file, v)
90	}
91}
92
93func sortSubList(values []Expression, nextPos scanner.Position, file *File) {
94	l := make(elemList, len(values))
95	for i, v := range values {
96		s, ok := v.(*String)
97		if !ok {
98			panic("list contains non-string element")
99		}
100		n := nextPos
101		if i < len(values)-1 {
102			n = values[i+1].Pos()
103		}
104		l[i] = elem{s.Value, i, v.Pos(), n}
105	}
106
107	sort.Sort(l)
108
109	copyValues := append([]Expression{}, values...)
110	copyComments := make([]*CommentGroup, len(file.Comments))
111	for i := range file.Comments {
112		cg := *file.Comments[i]
113		cg.Comments = make([]*Comment, len(cg.Comments))
114		for j := range file.Comments[i].Comments {
115			c := *file.Comments[i].Comments[j]
116			cg.Comments[j] = &c
117		}
118		copyComments[i] = &cg
119	}
120
121	curPos := values[0].Pos()
122	for i, e := range l {
123		values[i] = copyValues[e.i]
124		values[i].(*String).LiteralPos = curPos
125		for j, c := range copyComments {
126			if c.Pos().Offset > e.pos.Offset && c.Pos().Offset < e.nextPos.Offset {
127				file.Comments[j].Comments[0].Slash.Line = curPos.Line
128				file.Comments[j].Comments[0].Slash.Offset += values[i].Pos().Offset - e.pos.Offset
129			}
130		}
131
132		curPos.Offset += e.nextPos.Offset - e.pos.Offset
133		curPos.Line++
134	}
135}
136
137func subListIsSorted(values []Expression) bool {
138	prev := ""
139	for _, v := range values {
140		s, ok := v.(*String)
141		if !ok {
142			panic("list contains non-string element")
143		}
144		if prev > s.Value {
145			return false
146		}
147		prev = s.Value
148	}
149
150	return true
151}
152
153type elem struct {
154	s       string
155	i       int
156	pos     scanner.Position
157	nextPos scanner.Position
158}
159
160type elemList []elem
161
162func (l elemList) Len() int {
163	return len(l)
164}
165
166func (l elemList) Swap(i, j int) {
167	l[i], l[j] = l[j], l[i]
168}
169
170func (l elemList) Less(i, j int) bool {
171	return l[i].s < l[j].s
172}
173
174type commentsByOffset []*CommentGroup
175
176func (l commentsByOffset) Len() int {
177	return len(l)
178}
179
180func (l commentsByOffset) Less(i, j int) bool {
181	return l[i].Pos().Offset < l[j].Pos().Offset
182}
183
184func (l commentsByOffset) Swap(i, j int) {
185	l[i], l[j] = l[j], l[i]
186}
187