evaluate.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. package otto
  2. import (
  3. "fmt"
  4. "math"
  5. "strings"
  6. "github.com/robertkrimen/otto/token"
  7. )
  8. func (self *_runtime) evaluateMultiply(left float64, right float64) Value {
  9. // TODO 11.5.1
  10. return Value{}
  11. }
  12. func (self *_runtime) evaluateDivide(left float64, right float64) Value {
  13. if math.IsNaN(left) || math.IsNaN(right) {
  14. return NaNValue()
  15. }
  16. if math.IsInf(left, 0) && math.IsInf(right, 0) {
  17. return NaNValue()
  18. }
  19. if left == 0 && right == 0 {
  20. return NaNValue()
  21. }
  22. if math.IsInf(left, 0) {
  23. if math.Signbit(left) == math.Signbit(right) {
  24. return positiveInfinityValue()
  25. } else {
  26. return negativeInfinityValue()
  27. }
  28. }
  29. if math.IsInf(right, 0) {
  30. if math.Signbit(left) == math.Signbit(right) {
  31. return positiveZeroValue()
  32. } else {
  33. return negativeZeroValue()
  34. }
  35. }
  36. if right == 0 {
  37. if math.Signbit(left) == math.Signbit(right) {
  38. return positiveInfinityValue()
  39. } else {
  40. return negativeInfinityValue()
  41. }
  42. }
  43. return toValue_float64(left / right)
  44. }
  45. func (self *_runtime) evaluateModulo(left float64, right float64) Value {
  46. // TODO 11.5.3
  47. return Value{}
  48. }
  49. func (self *_runtime) calculateBinaryExpression(operator token.Token, left Value, right Value) Value {
  50. leftValue := left.resolve()
  51. switch operator {
  52. // Additive
  53. case token.PLUS:
  54. leftValue = toPrimitive(leftValue)
  55. rightValue := right.resolve()
  56. rightValue = toPrimitive(rightValue)
  57. if leftValue.IsString() || rightValue.IsString() {
  58. return toValue_string(strings.Join([]string{leftValue.string(), rightValue.string()}, ""))
  59. } else {
  60. return toValue_float64(leftValue.float64() + rightValue.float64())
  61. }
  62. case token.MINUS:
  63. rightValue := right.resolve()
  64. return toValue_float64(leftValue.float64() - rightValue.float64())
  65. // Multiplicative
  66. case token.MULTIPLY:
  67. rightValue := right.resolve()
  68. return toValue_float64(leftValue.float64() * rightValue.float64())
  69. case token.SLASH:
  70. rightValue := right.resolve()
  71. return self.evaluateDivide(leftValue.float64(), rightValue.float64())
  72. case token.REMAINDER:
  73. rightValue := right.resolve()
  74. return toValue_float64(math.Mod(leftValue.float64(), rightValue.float64()))
  75. // Logical
  76. case token.LOGICAL_AND:
  77. left := leftValue.bool()
  78. if !left {
  79. return falseValue
  80. }
  81. return toValue_bool(right.resolve().bool())
  82. case token.LOGICAL_OR:
  83. left := leftValue.bool()
  84. if left {
  85. return trueValue
  86. }
  87. return toValue_bool(right.resolve().bool())
  88. // Bitwise
  89. case token.AND:
  90. rightValue := right.resolve()
  91. return toValue_int32(toInt32(leftValue) & toInt32(rightValue))
  92. case token.OR:
  93. rightValue := right.resolve()
  94. return toValue_int32(toInt32(leftValue) | toInt32(rightValue))
  95. case token.EXCLUSIVE_OR:
  96. rightValue := right.resolve()
  97. return toValue_int32(toInt32(leftValue) ^ toInt32(rightValue))
  98. // Shift
  99. // (Masking of 0x1f is to restrict the shift to a maximum of 31 places)
  100. case token.SHIFT_LEFT:
  101. rightValue := right.resolve()
  102. return toValue_int32(toInt32(leftValue) << (toUint32(rightValue) & 0x1f))
  103. case token.SHIFT_RIGHT:
  104. rightValue := right.resolve()
  105. return toValue_int32(toInt32(leftValue) >> (toUint32(rightValue) & 0x1f))
  106. case token.UNSIGNED_SHIFT_RIGHT:
  107. rightValue := right.resolve()
  108. // Shifting an unsigned integer is a logical shift
  109. return toValue_uint32(toUint32(leftValue) >> (toUint32(rightValue) & 0x1f))
  110. case token.INSTANCEOF:
  111. rightValue := right.resolve()
  112. if !rightValue.IsObject() {
  113. panic(self.panicTypeError("Expecting a function in instanceof check, but got: %v", rightValue))
  114. }
  115. return toValue_bool(rightValue._object().hasInstance(leftValue))
  116. case token.IN:
  117. rightValue := right.resolve()
  118. if !rightValue.IsObject() {
  119. panic(self.panicTypeError())
  120. }
  121. return toValue_bool(rightValue._object().hasProperty(leftValue.string()))
  122. }
  123. panic(hereBeDragons(operator))
  124. }
  125. func valueKindDispatchKey(left _valueKind, right _valueKind) int {
  126. return (int(left) << 2) + int(right)
  127. }
  128. var equalDispatch map[int](func(Value, Value) bool) = makeEqualDispatch()
  129. func makeEqualDispatch() map[int](func(Value, Value) bool) {
  130. key := valueKindDispatchKey
  131. return map[int](func(Value, Value) bool){
  132. key(valueNumber, valueObject): func(x Value, y Value) bool { return x.float64() == y.float64() },
  133. key(valueString, valueObject): func(x Value, y Value) bool { return x.float64() == y.float64() },
  134. key(valueObject, valueNumber): func(x Value, y Value) bool { return x.float64() == y.float64() },
  135. key(valueObject, valueString): func(x Value, y Value) bool { return x.float64() == y.float64() },
  136. }
  137. }
  138. type _lessThanResult int
  139. const (
  140. lessThanFalse _lessThanResult = iota
  141. lessThanTrue
  142. lessThanUndefined
  143. )
  144. func calculateLessThan(left Value, right Value, leftFirst bool) _lessThanResult {
  145. x := Value{}
  146. y := x
  147. if leftFirst {
  148. x = toNumberPrimitive(left)
  149. y = toNumberPrimitive(right)
  150. } else {
  151. y = toNumberPrimitive(right)
  152. x = toNumberPrimitive(left)
  153. }
  154. result := false
  155. if x.kind != valueString || y.kind != valueString {
  156. x, y := x.float64(), y.float64()
  157. if math.IsNaN(x) || math.IsNaN(y) {
  158. return lessThanUndefined
  159. }
  160. result = x < y
  161. } else {
  162. x, y := x.string(), y.string()
  163. result = x < y
  164. }
  165. if result {
  166. return lessThanTrue
  167. }
  168. return lessThanFalse
  169. }
  170. // FIXME Probably a map is not the most efficient way to do this
  171. var lessThanTable [4](map[_lessThanResult]bool) = [4](map[_lessThanResult]bool){
  172. // <
  173. map[_lessThanResult]bool{
  174. lessThanFalse: false,
  175. lessThanTrue: true,
  176. lessThanUndefined: false,
  177. },
  178. // >
  179. map[_lessThanResult]bool{
  180. lessThanFalse: false,
  181. lessThanTrue: true,
  182. lessThanUndefined: false,
  183. },
  184. // <=
  185. map[_lessThanResult]bool{
  186. lessThanFalse: true,
  187. lessThanTrue: false,
  188. lessThanUndefined: false,
  189. },
  190. // >=
  191. map[_lessThanResult]bool{
  192. lessThanFalse: true,
  193. lessThanTrue: false,
  194. lessThanUndefined: false,
  195. },
  196. }
  197. func (self *_runtime) calculateComparison(comparator token.Token, left Value, right Value) bool {
  198. // FIXME Use strictEqualityComparison?
  199. // TODO This might be redundant now (with regards to evaluateComparison)
  200. x := left.resolve()
  201. y := right.resolve()
  202. kindEqualKind := false
  203. result := true
  204. negate := false
  205. switch comparator {
  206. case token.LESS:
  207. result = lessThanTable[0][calculateLessThan(x, y, true)]
  208. case token.GREATER:
  209. result = lessThanTable[1][calculateLessThan(y, x, false)]
  210. case token.LESS_OR_EQUAL:
  211. result = lessThanTable[2][calculateLessThan(y, x, false)]
  212. case token.GREATER_OR_EQUAL:
  213. result = lessThanTable[3][calculateLessThan(x, y, true)]
  214. case token.STRICT_NOT_EQUAL:
  215. negate = true
  216. fallthrough
  217. case token.STRICT_EQUAL:
  218. if x.kind != y.kind {
  219. result = false
  220. } else {
  221. kindEqualKind = true
  222. }
  223. case token.NOT_EQUAL:
  224. negate = true
  225. fallthrough
  226. case token.EQUAL:
  227. if x.kind == y.kind {
  228. kindEqualKind = true
  229. } else if x.kind <= valueNull && y.kind <= valueNull {
  230. result = true
  231. } else if x.kind <= valueNull || y.kind <= valueNull {
  232. result = false
  233. } else if x.kind <= valueString && y.kind <= valueString {
  234. result = x.float64() == y.float64()
  235. } else if x.kind == valueBoolean {
  236. result = self.calculateComparison(token.EQUAL, toValue_float64(x.float64()), y)
  237. } else if y.kind == valueBoolean {
  238. result = self.calculateComparison(token.EQUAL, x, toValue_float64(y.float64()))
  239. } else if x.kind == valueObject {
  240. result = self.calculateComparison(token.EQUAL, toPrimitive(x), y)
  241. } else if y.kind == valueObject {
  242. result = self.calculateComparison(token.EQUAL, x, toPrimitive(y))
  243. } else {
  244. panic(hereBeDragons("Unable to test for equality: %v ==? %v", x, y))
  245. }
  246. default:
  247. panic(fmt.Errorf("Unknown comparator %s", comparator.String()))
  248. }
  249. if kindEqualKind {
  250. switch x.kind {
  251. case valueUndefined, valueNull:
  252. result = true
  253. case valueNumber:
  254. x := x.float64()
  255. y := y.float64()
  256. if math.IsNaN(x) || math.IsNaN(y) {
  257. result = false
  258. } else {
  259. result = x == y
  260. }
  261. case valueString:
  262. result = x.string() == y.string()
  263. case valueBoolean:
  264. result = x.bool() == y.bool()
  265. case valueObject:
  266. result = x._object() == y._object()
  267. default:
  268. goto ERROR
  269. }
  270. }
  271. if negate {
  272. result = !result
  273. }
  274. return result
  275. ERROR:
  276. panic(hereBeDragons("%v (%v) %s %v (%v)", x, x.kind, comparator, y, y.kind))
  277. }