type.go 5.8 KB

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