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