2015-01-23 23:15:10 +01:00
|
|
|
// Copyright 2014 Google Inc. All rights reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2015-01-09 04:35:10 +01:00
|
|
|
package parser
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sort"
|
|
|
|
"text/scanner"
|
|
|
|
)
|
|
|
|
|
|
|
|
func SortLists(file *File) {
|
|
|
|
for _, def := range file.Defs {
|
|
|
|
if assignment, ok := def.(*Assignment); ok {
|
|
|
|
sortListsInValue(assignment.Value, file)
|
|
|
|
} else if module, ok := def.(*Module); ok {
|
|
|
|
for _, prop := range module.Properties {
|
|
|
|
sortListsInValue(prop.Value, file)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort.Sort(commentsByOffset(file.Comments))
|
|
|
|
}
|
|
|
|
|
|
|
|
func SortList(file *File, value Value) {
|
|
|
|
for i := 0; i < len(value.ListValue); i++ {
|
|
|
|
// Find a set of values on contiguous lines
|
|
|
|
line := value.ListValue[i].Pos.Line
|
|
|
|
var j int
|
|
|
|
for j = i + 1; j < len(value.ListValue); j++ {
|
|
|
|
if value.ListValue[j].Pos.Line > line+1 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
line = value.ListValue[j].Pos.Line
|
|
|
|
}
|
|
|
|
|
|
|
|
nextPos := value.EndPos
|
|
|
|
if j < len(value.ListValue) {
|
|
|
|
nextPos = value.ListValue[j].Pos
|
|
|
|
}
|
|
|
|
sortSubList(value.ListValue[i:j], nextPos, file)
|
|
|
|
i = j - 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func ListIsSorted(value Value) bool {
|
|
|
|
for i := 0; i < len(value.ListValue); i++ {
|
|
|
|
// Find a set of values on contiguous lines
|
|
|
|
line := value.ListValue[i].Pos.Line
|
|
|
|
var j int
|
|
|
|
for j = i + 1; j < len(value.ListValue); j++ {
|
|
|
|
if value.ListValue[j].Pos.Line > line+1 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
line = value.ListValue[j].Pos.Line
|
|
|
|
}
|
|
|
|
|
|
|
|
if !subListIsSorted(value.ListValue[i:j]) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i = j - 1
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func sortListsInValue(value Value, file *File) {
|
|
|
|
if value.Variable != "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if value.Expression != nil {
|
|
|
|
sortListsInValue(value.Expression.Args[0], file)
|
|
|
|
sortListsInValue(value.Expression.Args[1], file)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if value.Type == Map {
|
|
|
|
for _, p := range value.MapValue {
|
|
|
|
sortListsInValue(p.Value, file)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
} else if value.Type != List {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
SortList(file, value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func sortSubList(values []Value, nextPos scanner.Position, file *File) {
|
|
|
|
l := make(elemList, len(values))
|
|
|
|
for i, v := range values {
|
|
|
|
if v.Type != String {
|
|
|
|
panic("list contains non-string element")
|
|
|
|
}
|
|
|
|
n := nextPos
|
|
|
|
if i < len(values)-1 {
|
|
|
|
n = values[i+1].Pos
|
|
|
|
}
|
|
|
|
l[i] = elem{v.StringValue, i, v.Pos, n}
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Sort(l)
|
|
|
|
|
|
|
|
copyValues := append([]Value{}, values...)
|
|
|
|
copyComments := append([]Comment{}, file.Comments...)
|
|
|
|
|
|
|
|
curPos := values[0].Pos
|
|
|
|
for i, e := range l {
|
|
|
|
values[i] = copyValues[e.i]
|
|
|
|
values[i].Pos = curPos
|
|
|
|
for j, c := range copyComments {
|
|
|
|
if c.Pos.Offset > e.pos.Offset && c.Pos.Offset < e.nextPos.Offset {
|
|
|
|
file.Comments[j].Pos.Line = curPos.Line
|
|
|
|
file.Comments[j].Pos.Offset += values[i].Pos.Offset - e.pos.Offset
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
curPos.Offset += e.nextPos.Offset - e.pos.Offset
|
|
|
|
curPos.Line++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func subListIsSorted(values []Value) bool {
|
|
|
|
prev := ""
|
|
|
|
for _, v := range values {
|
|
|
|
if v.Type != String {
|
|
|
|
panic("list contains non-string element")
|
|
|
|
}
|
|
|
|
if prev > v.StringValue {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
prev = v.StringValue
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
type elem struct {
|
|
|
|
s string
|
|
|
|
i int
|
|
|
|
pos scanner.Position
|
|
|
|
nextPos scanner.Position
|
|
|
|
}
|
|
|
|
|
|
|
|
type elemList []elem
|
|
|
|
|
|
|
|
func (l elemList) Len() int {
|
|
|
|
return len(l)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l elemList) Swap(i, j int) {
|
|
|
|
l[i], l[j] = l[j], l[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l elemList) Less(i, j int) bool {
|
|
|
|
return l[i].s < l[j].s
|
|
|
|
}
|
|
|
|
|
|
|
|
type commentsByOffset []Comment
|
|
|
|
|
|
|
|
func (l commentsByOffset) Len() int {
|
|
|
|
return len(l)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l commentsByOffset) Less(i, j int) bool {
|
|
|
|
return l[i].Pos.Offset < l[j].Pos.Offset
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l commentsByOffset) Swap(i, j int) {
|
|
|
|
l[i], l[j] = l[j], l[i]
|
|
|
|
}
|