PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin.go

https://gitlab.com/akomba/ether-bot-wallet
Go | 353 lines | 308 code | 34 blank | 11 comment | 91 complexity | 49ef05865028ba6a3b3fcafecbbb28c4 MD5 | raw file
  1. package otto
  2. import (
  3. "encoding/hex"
  4. "math"
  5. "net/url"
  6. "regexp"
  7. "strconv"
  8. "strings"
  9. "unicode/utf16"
  10. "unicode/utf8"
  11. )
  12. // Global
  13. func builtinGlobal_eval(call FunctionCall) Value {
  14. src := call.Argument(0)
  15. if !src.IsString() {
  16. return src
  17. }
  18. runtime := call.runtime
  19. program := runtime.cmpl_parseOrThrow(src.string())
  20. if !call.eval {
  21. // Not a direct call to eval, so we enter the global ExecutionContext
  22. runtime.enterGlobalScope()
  23. defer runtime.leaveScope()
  24. }
  25. returnValue := runtime.cmpl_evaluate_nodeProgram(program, true)
  26. if returnValue.isEmpty() {
  27. return Value{}
  28. }
  29. return returnValue
  30. }
  31. func builtinGlobal_isNaN(call FunctionCall) Value {
  32. value := call.Argument(0).float64()
  33. return toValue_bool(math.IsNaN(value))
  34. }
  35. func builtinGlobal_isFinite(call FunctionCall) Value {
  36. value := call.Argument(0).float64()
  37. return toValue_bool(!math.IsNaN(value) && !math.IsInf(value, 0))
  38. }
  39. // radix 3 => 2 (ASCII 50) +47
  40. // radix 11 => A/a (ASCII 65/97) +54/+86
  41. var parseInt_alphabetTable = func() []string {
  42. table := []string{"", "", "01"}
  43. for radix := 3; radix <= 36; radix += 1 {
  44. alphabet := table[radix-1]
  45. if radix <= 10 {
  46. alphabet += string(radix + 47)
  47. } else {
  48. alphabet += string(radix+54) + string(radix+86)
  49. }
  50. table = append(table, alphabet)
  51. }
  52. return table
  53. }()
  54. func digitValue(chr rune) int {
  55. switch {
  56. case '0' <= chr && chr <= '9':
  57. return int(chr - '0')
  58. case 'a' <= chr && chr <= 'z':
  59. return int(chr - 'a' + 10)
  60. case 'A' <= chr && chr <= 'Z':
  61. return int(chr - 'A' + 10)
  62. }
  63. return 36 // Larger than any legal digit value
  64. }
  65. func builtinGlobal_parseInt(call FunctionCall) Value {
  66. input := strings.TrimSpace(call.Argument(0).string())
  67. if len(input) == 0 {
  68. return NaNValue()
  69. }
  70. radix := int(toInt32(call.Argument(1)))
  71. negative := false
  72. switch input[0] {
  73. case '+':
  74. input = input[1:]
  75. case '-':
  76. negative = true
  77. input = input[1:]
  78. }
  79. strip := true
  80. if radix == 0 {
  81. radix = 10
  82. } else {
  83. if radix < 2 || radix > 36 {
  84. return NaNValue()
  85. } else if radix != 16 {
  86. strip = false
  87. }
  88. }
  89. switch len(input) {
  90. case 0:
  91. return NaNValue()
  92. case 1:
  93. default:
  94. if strip {
  95. if input[0] == '0' && (input[1] == 'x' || input[1] == 'X') {
  96. input = input[2:]
  97. radix = 16
  98. }
  99. }
  100. }
  101. base := radix
  102. index := 0
  103. for ; index < len(input); index++ {
  104. digit := digitValue(rune(input[index])) // If not ASCII, then an error anyway
  105. if digit >= base {
  106. break
  107. }
  108. }
  109. input = input[0:index]
  110. value, err := strconv.ParseInt(input, radix, 64)
  111. if err != nil {
  112. if err.(*strconv.NumError).Err == strconv.ErrRange {
  113. base := float64(base)
  114. // Could just be a very large number (e.g. 0x8000000000000000)
  115. var value float64
  116. for _, chr := range input {
  117. digit := float64(digitValue(chr))
  118. if digit >= base {
  119. goto error
  120. }
  121. value = value*base + digit
  122. }
  123. if negative {
  124. value *= -1
  125. }
  126. return toValue_float64(value)
  127. }
  128. error:
  129. return NaNValue()
  130. }
  131. if negative {
  132. value *= -1
  133. }
  134. return toValue_int64(value)
  135. }
  136. var parseFloat_matchBadSpecial = regexp.MustCompile(`[\+\-]?(?:[Ii]nf$|infinity)`)
  137. var parseFloat_matchValid = regexp.MustCompile(`[0-9eE\+\-\.]|Infinity`)
  138. func builtinGlobal_parseFloat(call FunctionCall) Value {
  139. // Caveat emptor: This implementation does NOT match the specification
  140. input := strings.TrimSpace(call.Argument(0).string())
  141. if parseFloat_matchBadSpecial.MatchString(input) {
  142. return NaNValue()
  143. }
  144. value, err := strconv.ParseFloat(input, 64)
  145. if err != nil {
  146. for end := len(input); end > 0; end -= 1 {
  147. input := input[0:end]
  148. if !parseFloat_matchValid.MatchString(input) {
  149. return NaNValue()
  150. }
  151. value, err = strconv.ParseFloat(input, 64)
  152. if err == nil {
  153. break
  154. }
  155. }
  156. if err != nil {
  157. return NaNValue()
  158. }
  159. }
  160. return toValue_float64(value)
  161. }
  162. // encodeURI/decodeURI
  163. func _builtinGlobal_encodeURI(call FunctionCall, escape *regexp.Regexp) Value {
  164. value := call.Argument(0)
  165. var input []uint16
  166. switch vl := value.value.(type) {
  167. case []uint16:
  168. input = vl
  169. default:
  170. input = utf16.Encode([]rune(value.string()))
  171. }
  172. if len(input) == 0 {
  173. return toValue_string("")
  174. }
  175. output := []byte{}
  176. length := len(input)
  177. encode := make([]byte, 4)
  178. for index := 0; index < length; {
  179. value := input[index]
  180. decode := utf16.Decode(input[index : index+1])
  181. if value >= 0xDC00 && value <= 0xDFFF {
  182. panic(call.runtime.panicURIError("URI malformed"))
  183. }
  184. if value >= 0xD800 && value <= 0xDBFF {
  185. index += 1
  186. if index >= length {
  187. panic(call.runtime.panicURIError("URI malformed"))
  188. }
  189. // input = ..., value, value1, ...
  190. value1 := input[index]
  191. if value1 < 0xDC00 || value1 > 0xDFFF {
  192. panic(call.runtime.panicURIError("URI malformed"))
  193. }
  194. decode = []rune{((rune(value) - 0xD800) * 0x400) + (rune(value1) - 0xDC00) + 0x10000}
  195. }
  196. index += 1
  197. size := utf8.EncodeRune(encode, decode[0])
  198. encode := encode[0:size]
  199. output = append(output, encode...)
  200. }
  201. {
  202. value := escape.ReplaceAllFunc(output, func(target []byte) []byte {
  203. // Probably a better way of doing this
  204. if target[0] == ' ' {
  205. return []byte("%20")
  206. }
  207. return []byte(url.QueryEscape(string(target)))
  208. })
  209. return toValue_string(string(value))
  210. }
  211. }
  212. var encodeURI_Regexp = regexp.MustCompile(`([^~!@#$&*()=:/,;?+'])`)
  213. func builtinGlobal_encodeURI(call FunctionCall) Value {
  214. return _builtinGlobal_encodeURI(call, encodeURI_Regexp)
  215. }
  216. var encodeURIComponent_Regexp = regexp.MustCompile(`([^~!*()'])`)
  217. func builtinGlobal_encodeURIComponent(call FunctionCall) Value {
  218. return _builtinGlobal_encodeURI(call, encodeURIComponent_Regexp)
  219. }
  220. // 3B/2F/3F/3A/40/26/3D/2B/24/2C/23
  221. var decodeURI_guard = regexp.MustCompile(`(?i)(?:%)(3B|2F|3F|3A|40|26|3D|2B|24|2C|23)`)
  222. func _decodeURI(input string, reserve bool) (string, bool) {
  223. if reserve {
  224. input = decodeURI_guard.ReplaceAllString(input, "%25$1")
  225. }
  226. input = strings.Replace(input, "+", "%2B", -1) // Ugly hack to make QueryUnescape work with our use case
  227. output, err := url.QueryUnescape(input)
  228. if err != nil || !utf8.ValidString(output) {
  229. return "", true
  230. }
  231. return output, false
  232. }
  233. func builtinGlobal_decodeURI(call FunctionCall) Value {
  234. output, err := _decodeURI(call.Argument(0).string(), true)
  235. if err {
  236. panic(call.runtime.panicURIError("URI malformed"))
  237. }
  238. return toValue_string(output)
  239. }
  240. func builtinGlobal_decodeURIComponent(call FunctionCall) Value {
  241. output, err := _decodeURI(call.Argument(0).string(), false)
  242. if err {
  243. panic(call.runtime.panicURIError("URI malformed"))
  244. }
  245. return toValue_string(output)
  246. }
  247. // escape/unescape
  248. func builtin_shouldEscape(chr byte) bool {
  249. if 'A' <= chr && chr <= 'Z' || 'a' <= chr && chr <= 'z' || '0' <= chr && chr <= '9' {
  250. return false
  251. }
  252. return !strings.ContainsRune("*_+-./", rune(chr))
  253. }
  254. const escapeBase16 = "0123456789ABCDEF"
  255. func builtin_escape(input string) string {
  256. output := make([]byte, 0, len(input))
  257. length := len(input)
  258. for index := 0; index < length; {
  259. if builtin_shouldEscape(input[index]) {
  260. chr, width := utf8.DecodeRuneInString(input[index:])
  261. chr16 := utf16.Encode([]rune{chr})[0]
  262. if 256 > chr16 {
  263. output = append(output, '%',
  264. escapeBase16[chr16>>4],
  265. escapeBase16[chr16&15],
  266. )
  267. } else {
  268. output = append(output, '%', 'u',
  269. escapeBase16[chr16>>12],
  270. escapeBase16[(chr16>>8)&15],
  271. escapeBase16[(chr16>>4)&15],
  272. escapeBase16[chr16&15],
  273. )
  274. }
  275. index += width
  276. } else {
  277. output = append(output, input[index])
  278. index += 1
  279. }
  280. }
  281. return string(output)
  282. }
  283. func builtin_unescape(input string) string {
  284. output := make([]rune, 0, len(input))
  285. length := len(input)
  286. for index := 0; index < length; {
  287. if input[index] == '%' {
  288. if index <= length-6 && input[index+1] == 'u' {
  289. byte16, err := hex.DecodeString(input[index+2 : index+6])
  290. if err == nil {
  291. value := uint16(byte16[0])<<8 + uint16(byte16[1])
  292. chr := utf16.Decode([]uint16{value})[0]
  293. output = append(output, chr)
  294. index += 6
  295. continue
  296. }
  297. }
  298. if index <= length-3 {
  299. byte8, err := hex.DecodeString(input[index+1 : index+3])
  300. if err == nil {
  301. value := uint16(byte8[0])
  302. chr := utf16.Decode([]uint16{value})[0]
  303. output = append(output, chr)
  304. index += 3
  305. continue
  306. }
  307. }
  308. }
  309. output = append(output, rune(input[index]))
  310. index += 1
  311. }
  312. return string(output)
  313. }
  314. func builtinGlobal_escape(call FunctionCall) Value {
  315. return toValue_string(builtin_escape(call.Argument(0).string()))
  316. }
  317. func builtinGlobal_unescape(call FunctionCall) Value {
  318. return toValue_string(builtin_unescape(call.Argument(0).string()))
  319. }