package attl type Comparer func(v1, v2 Value) int func (data List) Sort(compare Comparer) List { if len(data) < 2 { return data } pivot := data[0] smaller := make(List, 0, len(data)) equal := make(List, 1, len(data)) larger := make(List, 0, len(data)) equal[0] = pivot for i := 1; i < len(data); i++ { cmp := compare(data[i], pivot) if cmp > 0 { larger = append(larger, data[i]) } else if cmp < 0 { smaller = append(smaller, data[i]) } else { equal = append(equal, data[i]) } } res := smaller.Sort(compare) res = append(res, equal...) res = append(res, larger.Sort(compare)...) return res } func (data List) SortStrings() List { return data.Sort(func(v1, v2 Value) int { s1 := v1.String() s2 := v2.String() if s1 > s2 { return 1 } else if s1 < s2 { return -1 } return 0 }) } // Converts an integer to a string func Itoa(i int) string { if i == 0 { return "0" } digits := "0123456789" res := "" neg := false if i < 0 { neg = true i = -i } for d := i % 10; i > 0; { // dumb digit by digit algorithm res = string(digits[d]) + res i = i / 10 d = i % 10 } if neg { res = "-" + res } return res } func Args(froms []Value, tos ...interface{}) *Error { for i, to := range tos { if i >= len(froms) { return ErrorFromString("Too few arguments: " + Itoa(len(froms)) + " in stead of " + Itoa(len(tos))) } from := froms[i] err := Convert(from, to) if err != nil { return err } } return nil } const ( maxRune = '\U0010FFFF' surrogateMin = 0xD800 surrogateMax = 0xDFFF rune1Max = 1<<7 - 1 rune2Max = 1<<11 - 1 rune3Max = 1<<16 - 1 ) func RuneLen(r rune) int { switch { case r < 0: return -1 case r <= rune1Max: return 1 case r <= rune2Max: return 2 case surrogateMin <= r && r <= surrogateMax: return -1 case r <= rune3Max: return 3 case r <= maxRune: return 4 } return -1 } // WordCompleter is for use with liner func WordCompleter(env Environment, line string, pos int) (head string, c []string, tail string) { end := pos begin := pos - 1 if begin < 0 { begin = 0 } for ; begin > 0 && len(line[begin:]) > 0; begin-- { r := []rune(line[begin:])[0] if RuneLen(r) < 0 { continue } if !(IsLetter(r) || IsNumber(r)) { rl := RuneLen(r) // skip to next rune begin += rl break } } for end = pos; end < len(line); end++ { r := []rune(line[end:])[0] if RuneLen(r) < 0 { continue } if !(IsLetter(r) || IsNumber(r)) { break } } head = line[0:begin] tail = line[end:] word := line[begin:end] clist := env.Complete(String(word)) return head, clist.ToStrings(), tail }