evaluate.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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. type _lessThanResult int
  126. const (
  127. lessThanFalse _lessThanResult = iota
  128. lessThanTrue
  129. lessThanUndefined
  130. )
  131. func calculateLessThan(left Value, right Value, leftFirst bool) _lessThanResult {
  132. var x, y Value
  133. if leftFirst {
  134. x = toNumberPrimitive(left)
  135. y = toNumberPrimitive(right)
  136. } else {
  137. y = toNumberPrimitive(right)
  138. x = toNumberPrimitive(left)
  139. }
  140. var result bool
  141. if x.kind != valueString || y.kind != valueString {
  142. x, y := x.float64(), y.float64()
  143. if math.IsNaN(x) || math.IsNaN(y) {
  144. return lessThanUndefined
  145. }
  146. result = x < y
  147. } else {
  148. x, y := x.string(), y.string()
  149. result = x < y
  150. }
  151. if result {
  152. return lessThanTrue
  153. }
  154. return lessThanFalse
  155. }
  156. // FIXME Probably a map is not the most efficient way to do this
  157. var lessThanTable [4](map[_lessThanResult]bool) = [4](map[_lessThanResult]bool){
  158. // <
  159. map[_lessThanResult]bool{
  160. lessThanFalse: false,
  161. lessThanTrue: true,
  162. lessThanUndefined: false,
  163. },
  164. // >
  165. map[_lessThanResult]bool{
  166. lessThanFalse: false,
  167. lessThanTrue: true,
  168. lessThanUndefined: false,
  169. },
  170. // <=
  171. map[_lessThanResult]bool{
  172. lessThanFalse: true,
  173. lessThanTrue: false,
  174. lessThanUndefined: false,
  175. },
  176. // >=
  177. map[_lessThanResult]bool{
  178. lessThanFalse: true,
  179. lessThanTrue: false,
  180. lessThanUndefined: false,
  181. },
  182. }
  183. func (self *_runtime) calculateComparison(comparator token.Token, left Value, right Value) bool {
  184. // FIXME Use strictEqualityComparison?
  185. // TODO This might be redundant now (with regards to evaluateComparison)
  186. x := left.resolve()
  187. y := right.resolve()
  188. kindEqualKind := false
  189. result := true
  190. negate := false
  191. switch comparator {
  192. case token.LESS:
  193. result = lessThanTable[0][calculateLessThan(x, y, true)]
  194. case token.GREATER:
  195. result = lessThanTable[1][calculateLessThan(y, x, false)]
  196. case token.LESS_OR_EQUAL:
  197. result = lessThanTable[2][calculateLessThan(y, x, false)]
  198. case token.GREATER_OR_EQUAL:
  199. result = lessThanTable[3][calculateLessThan(x, y, true)]
  200. case token.STRICT_NOT_EQUAL:
  201. negate = true
  202. fallthrough
  203. case token.STRICT_EQUAL:
  204. if x.kind != y.kind {
  205. result = false
  206. } else {
  207. kindEqualKind = true
  208. }
  209. case token.NOT_EQUAL:
  210. negate = true
  211. fallthrough
  212. case token.EQUAL:
  213. if x.kind == y.kind {
  214. kindEqualKind = true
  215. } else if x.kind <= valueNull && y.kind <= valueNull {
  216. result = true
  217. } else if x.kind <= valueNull || y.kind <= valueNull {
  218. result = false
  219. } else if x.kind <= valueString && y.kind <= valueString {
  220. result = x.float64() == y.float64()
  221. } else if x.kind == valueBoolean {
  222. result = self.calculateComparison(token.EQUAL, toValue_float64(x.float64()), y)
  223. } else if y.kind == valueBoolean {
  224. result = self.calculateComparison(token.EQUAL, x, toValue_float64(y.float64()))
  225. } else if x.kind == valueObject {
  226. result = self.calculateComparison(token.EQUAL, toPrimitive(x), y)
  227. } else if y.kind == valueObject {
  228. result = self.calculateComparison(token.EQUAL, x, toPrimitive(y))
  229. } else {
  230. panic(hereBeDragons("Unable to test for equality: %v ==? %v", x, y))
  231. }
  232. default:
  233. panic(fmt.Errorf("Unknown comparator %s", comparator.String()))
  234. }
  235. if kindEqualKind {
  236. switch x.kind {
  237. case valueUndefined, valueNull:
  238. result = true
  239. case valueNumber:
  240. x := x.float64()
  241. y := y.float64()
  242. if math.IsNaN(x) || math.IsNaN(y) {
  243. result = false
  244. } else {
  245. result = x == y
  246. }
  247. case valueString:
  248. result = x.string() == y.string()
  249. case valueBoolean:
  250. result = x.bool() == y.bool()
  251. case valueObject:
  252. result = x._object() == y._object()
  253. default:
  254. goto ERROR
  255. }
  256. }
  257. if negate {
  258. result = !result
  259. }
  260. return result
  261. ERROR:
  262. panic(hereBeDragons("%v (%v) %s %v (%v)", x, x.kind, comparator, y, y.kind))
  263. }