support.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package attl
  2. type Comparer func(v1, v2 Value) int
  3. func (data List) Sort(compare Comparer) List {
  4. if len(data) < 2 {
  5. return data
  6. }
  7. pivot := data[0]
  8. smaller := make(List, 0, len(data))
  9. equal := make(List, 1, len(data))
  10. larger := make(List, 0, len(data))
  11. equal[0] = pivot
  12. for i := 1; i < len(data); i++ {
  13. cmp := compare(data[i], pivot)
  14. if cmp > 0 {
  15. larger = append(larger, data[i])
  16. } else if cmp < 0 {
  17. smaller = append(smaller, data[i])
  18. } else {
  19. equal = append(equal, data[i])
  20. }
  21. }
  22. res := smaller.Sort(compare)
  23. res = append(res, equal...)
  24. res = append(res, larger.Sort(compare)...)
  25. return res
  26. }
  27. func (data List) SortStrings() List {
  28. return data.Sort(func(v1, v2 Value) int {
  29. s1 := v1.String()
  30. s2 := v2.String()
  31. if s1 > s2 {
  32. return 1
  33. } else if s1 < s2 {
  34. return -1
  35. }
  36. return 0
  37. })
  38. }
  39. // Converts an integer to a string
  40. func Itoa(i int) string {
  41. if i == 0 {
  42. return "0"
  43. }
  44. digits := "0123456789"
  45. res := ""
  46. neg := false
  47. if i < 0 {
  48. neg = true
  49. i = -i
  50. }
  51. for d := i % 10; i > 0; { // dumb digit by digit algorithm
  52. res = string(digits[d]) + res
  53. i = i / 10
  54. d = i % 10
  55. }
  56. if neg {
  57. res = "-" + res
  58. }
  59. return res
  60. }
  61. func Args(froms []Value, tos ...interface{}) *Error {
  62. for i, to := range tos {
  63. if i >= len(froms) {
  64. return ErrorFromString("Too few arguments: " +
  65. Itoa(len(froms)) + " in stead of " + Itoa(len(tos)))
  66. }
  67. from := froms[i]
  68. err := Convert(from, to)
  69. if err != nil {
  70. return err
  71. }
  72. }
  73. return nil
  74. }
  75. const (
  76. maxRune = '\U0010FFFF'
  77. surrogateMin = 0xD800
  78. surrogateMax = 0xDFFF
  79. rune1Max = 1<<7 - 1
  80. rune2Max = 1<<11 - 1
  81. rune3Max = 1<<16 - 1
  82. )
  83. func RuneLen(r rune) int {
  84. switch {
  85. case r < 0:
  86. return -1
  87. case r <= rune1Max:
  88. return 1
  89. case r <= rune2Max:
  90. return 2
  91. case surrogateMin <= r && r <= surrogateMax:
  92. return -1
  93. case r <= rune3Max:
  94. return 3
  95. case r <= maxRune:
  96. return 4
  97. }
  98. return -1
  99. }
  100. // WordCompleter is for use with liner
  101. func WordCompleter(env Environment, line string, pos int) (head string, c []string, tail string) {
  102. end := pos
  103. begin := pos - 1
  104. if begin < 0 {
  105. begin = 0
  106. }
  107. for ; begin > 0 && len(line[begin:]) > 0; begin-- {
  108. r := []rune(line[begin:])[0]
  109. if RuneLen(r) < 0 {
  110. continue
  111. }
  112. if !(IsLetter(r) || IsNumber(r)) {
  113. rl := RuneLen(r) // skip to next rune
  114. begin += rl
  115. break
  116. }
  117. }
  118. for end = pos; end < len(line); end++ {
  119. r := []rune(line[end:])[0]
  120. if RuneLen(r) < 0 {
  121. continue
  122. }
  123. if !(IsLetter(r) || IsNumber(r)) {
  124. break
  125. }
  126. }
  127. head = line[0:begin]
  128. tail = line[end:]
  129. word := line[begin:end]
  130. clist := env.Complete(String(word))
  131. return head, clist.ToStrings(), tail
  132. }