type.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. "regexp"
  6. "strconv"
  7. "strings"
  8. )
  9. const (
  10. typeUnknown = iota
  11. typeNumber
  12. typeWord
  13. typeList
  14. typeBool
  15. )
  16. const (
  17. _name = `([A-Za-z]\w*)`
  18. _nameOrInt = "(" + _name + `|\d+)`
  19. _index = "(" + _nameOrInt + "|:|" + _nameOrInt + ":|:" + _nameOrInt + "|" + _nameOrInt + ":" + _nameOrInt + ")"
  20. )
  21. var nameExp = regexp.MustCompile(`^"` + _name + "$")
  22. var nameWithIndexExp = regexp.MustCompile(`^"` + _name + `((\[` + _index + `])*\[` + _index + `\\])?$`)
  23. func isName(val value) bool {
  24. return nameExp.MatchString(val.word)
  25. }
  26. func toName(val value) string {
  27. if !isName(val) {
  28. panic(fmt.Errorf("name: %s", errInvalidName))
  29. }
  30. return val.word[1:]
  31. }
  32. func isNameWithIndex(val value) bool {
  33. return nameWithIndexExp.MatchString(val.word)
  34. }
  35. func toNameWithIndex(val value) (string, []string) {
  36. if !isNameWithIndex(val) {
  37. panic(fmt.Errorf("name: %s", errInvalidName))
  38. }
  39. index := strings.Split(val.word, "[")
  40. name, cnt := index[0][1:], len(index)-1
  41. for i := 1; i < cnt; i++ {
  42. index[i] = index[i][:len(index[i])-1]
  43. }
  44. index[cnt] = index[cnt][:len(index[cnt])-2]
  45. return name, index[1:]
  46. }
  47. func isNumber(val value) bool {
  48. if val.tp == typeNumber {
  49. return true
  50. }
  51. if isWord(val) {
  52. val.word = val.word[1:]
  53. }
  54. _, err := strconv.ParseFloat(val.word, 64)
  55. return err == nil
  56. }
  57. func toNumber(val value) float64 {
  58. if val.tp == typeNumber {
  59. return val.num
  60. }
  61. if isWord(val) {
  62. val.word = val.word[1:]
  63. }
  64. num, err := strconv.ParseFloat(val.word, 64)
  65. if err != nil {
  66. panic(fmt.Errorf("number: %s", errInvalidNumber))
  67. }
  68. return num
  69. }
  70. func toInt(val value, envs []environ) int {
  71. if isName(value{word: `"` + val.word}) {
  72. newVal, err := getValue(`"`+val.word, envs)
  73. if err == nil {
  74. val = newVal
  75. if val.tp == typeNumber {
  76. if val.num != math.Floor(val.num) {
  77. panic(fmt.Errorf("int: %s", errInvalidInteger))
  78. }
  79. return int(val.num)
  80. }
  81. }
  82. }
  83. if isWord(val) {
  84. val.word = val.word[1:]
  85. }
  86. num, err := strconv.ParseInt(val.word, 10, 64)
  87. if err != nil {
  88. panic(fmt.Errorf("int: %s", errInvalidInteger))
  89. }
  90. return int(num)
  91. }
  92. func isWord(val value) bool {
  93. if val.tp == typeWord {
  94. return true
  95. }
  96. return val.word != "" && val.word[0] == '"'
  97. }
  98. func parseWord(s string) value {
  99. if len(s) > 1 {
  100. if s[1] == '[' {
  101. s = `"\[` + s[2:]
  102. }
  103. if s[len(s)-1] == ']' {
  104. s = s[:len(s)-1]
  105. escape := len(s) - len(strings.TrimRight(s, `\`))
  106. if (escape & 1) == 0 {
  107. s += `\`
  108. }
  109. s += "]"
  110. }
  111. }
  112. return value{tp: typeWord, word: s}
  113. }
  114. func escapeWord(s string) string {
  115. for i := 0; i < len(s); i++ {
  116. if s[i] == '\\' {
  117. s = s[:i] + s[i+1:]
  118. }
  119. }
  120. return s
  121. }
  122. func isList(val value) bool {
  123. if val.tp == typeList {
  124. return true
  125. }
  126. return val.word != "" && val.word[0] == '['
  127. }
  128. func parseFunc(s string, env environ) value {
  129. list, split := parseList(s)
  130. if len(list) != 2 || !isList(value{word: list[0]}) || !isList(value{word: list[1]}) {
  131. return value{tp: typeList, list: list, split: split}
  132. }
  133. param, _ := parseList(list[0])
  134. for _, name := range param {
  135. if !isName(value{word: `"` + name}) {
  136. return value{tp: typeList, list: list, split: split}
  137. }
  138. }
  139. local := environ{}
  140. for name, val := range env {
  141. local[name] = val
  142. }
  143. return value{tp: typeList, list: list, split: split, param: param, body: strings.Split(list[1], " "), env: local}
  144. }
  145. func isBool(val value) bool {
  146. if val.tp == typeBool {
  147. return true
  148. }
  149. if val.tp == typeNumber && (val.num == 0 || val.num == 1) {
  150. return true
  151. }
  152. if isWord(val) {
  153. val.word = val.word[1:]
  154. }
  155. _, err := strconv.ParseBool(val.word)
  156. return err == nil
  157. }
  158. func toBool(val value) bool {
  159. if val.tp == typeBool {
  160. return val.b
  161. }
  162. if val.tp == typeNumber && (val.num == 0 || val.num == 1) {
  163. return val.num == 1
  164. }
  165. if isWord(val) {
  166. val.word = val.word[1:]
  167. }
  168. b, err := strconv.ParseBool(val.word)
  169. if err != nil {
  170. panic(fmt.Errorf("bool: %s", errInvalidBool))
  171. }
  172. return b
  173. }
  174. func isEmpty(val value) bool {
  175. if val.tp == typeWord {
  176. return val.word == `"`
  177. }
  178. if val.tp == typeList {
  179. return len(val.list) == 0
  180. }
  181. panic(fmt.Errorf("empty: %s", errWordOrListExpected))
  182. }
  183. func toValue(val value, env environ) value {
  184. if val.tp != typeUnknown {
  185. return val
  186. }
  187. if isNumber(val) {
  188. return value{tp: typeNumber, num: toNumber(val)}
  189. }
  190. if isWord(val) {
  191. return parseWord(val.word)
  192. }
  193. if isList(val) {
  194. return parseFunc(val.word, env)
  195. }
  196. if isBool(val) {
  197. return value{tp: typeBool, b: toBool(val)}
  198. }
  199. panic(fmt.Errorf("value: %s", errValueExpected))
  200. }
  201. func toString(val value) string {
  202. if val.tp == typeNumber {
  203. return strconv.FormatFloat(val.num, 'g', -1, 64)
  204. }
  205. if val.tp == typeWord {
  206. return val.word[1:]
  207. }
  208. if val.tp == typeList {
  209. return makeList(val.list)
  210. }
  211. if val.tp == typeBool {
  212. return strconv.FormatBool(val.b)
  213. }
  214. panic(fmt.Errorf("string: %s", errValueExpected))
  215. }
  216. func opIsName(val1 value) value {
  217. return value{tp: typeBool, b: isName(val1)}
  218. }
  219. func opIsNumber(val1 value) value {
  220. return value{tp: typeBool, b: isNumber(val1)}
  221. }
  222. func opIsWord(val1 value) value {
  223. return value{tp: typeBool, b: isWord(val1)}
  224. }
  225. func opIsList(val1 value) value {
  226. return value{tp: typeBool, b: isList(val1)}
  227. }
  228. func opIsBool(val1 value) value {
  229. return value{tp: typeBool, b: isBool(val1)}
  230. }
  231. func opIsEmpty(val1 value) value {
  232. return value{tp: typeBool, b: isEmpty(val1)}
  233. }