cmpl_evaluate_statement.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. package otto
  2. import (
  3. "fmt"
  4. goruntime "runtime"
  5. "github.com/robertkrimen/otto/token"
  6. )
  7. func (rt *runtime) cmplEvaluateNodeStatement(node nodeStatement) Value {
  8. // Allow interpreter interruption
  9. // If the Interrupt channel is nil, then
  10. // we avoid runtime.Gosched() overhead (if any)
  11. // FIXME: Test this
  12. if rt.otto.Interrupt != nil {
  13. goruntime.Gosched()
  14. select {
  15. case value := <-rt.otto.Interrupt:
  16. value()
  17. default:
  18. }
  19. }
  20. switch node := node.(type) {
  21. case *nodeBlockStatement:
  22. labels := rt.labels
  23. rt.labels = nil
  24. value := rt.cmplEvaluateNodeStatementList(node.list)
  25. if value.kind == valueResult {
  26. if value.evaluateBreak(labels) == resultBreak {
  27. return emptyValue
  28. }
  29. }
  30. return value
  31. case *nodeBranchStatement:
  32. target := node.label
  33. switch node.branch { // FIXME Maybe node.kind? node.operator?
  34. case token.BREAK:
  35. return toValue(newBreakResult(target))
  36. case token.CONTINUE:
  37. return toValue(newContinueResult(target))
  38. default:
  39. panic(fmt.Errorf("unknown node branch token %T", node))
  40. }
  41. case *nodeDebuggerStatement:
  42. if rt.debugger != nil {
  43. rt.debugger(rt.otto)
  44. }
  45. return emptyValue // Nothing happens.
  46. case *nodeDoWhileStatement:
  47. return rt.cmplEvaluateNodeDoWhileStatement(node)
  48. case *nodeEmptyStatement:
  49. return emptyValue
  50. case *nodeExpressionStatement:
  51. return rt.cmplEvaluateNodeExpression(node.expression)
  52. case *nodeForInStatement:
  53. return rt.cmplEvaluateNodeForInStatement(node)
  54. case *nodeForStatement:
  55. return rt.cmplEvaluateNodeForStatement(node)
  56. case *nodeIfStatement:
  57. return rt.cmplEvaluateNodeIfStatement(node)
  58. case *nodeLabelledStatement:
  59. rt.labels = append(rt.labels, node.label)
  60. defer func() {
  61. if len(rt.labels) > 0 {
  62. rt.labels = rt.labels[:len(rt.labels)-1] // Pop the label
  63. } else {
  64. rt.labels = nil
  65. }
  66. }()
  67. return rt.cmplEvaluateNodeStatement(node.statement)
  68. case *nodeReturnStatement:
  69. if node.argument != nil {
  70. return toValue(newReturnResult(rt.cmplEvaluateNodeExpression(node.argument).resolve()))
  71. }
  72. return toValue(newReturnResult(Value{}))
  73. case *nodeSwitchStatement:
  74. return rt.cmplEvaluateNodeSwitchStatement(node)
  75. case *nodeThrowStatement:
  76. value := rt.cmplEvaluateNodeExpression(node.argument).resolve()
  77. panic(newException(value))
  78. case *nodeTryStatement:
  79. return rt.cmplEvaluateNodeTryStatement(node)
  80. case *nodeVariableStatement:
  81. // Variables are already defined, this is initialization only
  82. for _, variable := range node.list {
  83. rt.cmplEvaluateNodeVariableExpression(variable.(*nodeVariableExpression))
  84. }
  85. return emptyValue
  86. case *nodeWhileStatement:
  87. return rt.cmplEvaluateModeWhileStatement(node)
  88. case *nodeWithStatement:
  89. return rt.cmplEvaluateNodeWithStatement(node)
  90. default:
  91. panic(fmt.Errorf("unknown node statement type %T", node))
  92. }
  93. }
  94. func (rt *runtime) cmplEvaluateNodeStatementList(list []nodeStatement) Value {
  95. var result Value
  96. for _, node := range list {
  97. value := rt.cmplEvaluateNodeStatement(node)
  98. switch value.kind {
  99. case valueResult:
  100. return value
  101. case valueEmpty:
  102. default:
  103. // We have getValue here to (for example) trigger a
  104. // ReferenceError (of the not defined variety)
  105. // Not sure if this is the best way to error out early
  106. // for such errors or if there is a better way
  107. // TODO Do we still need this?
  108. result = value.resolve()
  109. }
  110. }
  111. return result
  112. }
  113. func (rt *runtime) cmplEvaluateNodeDoWhileStatement(node *nodeDoWhileStatement) Value {
  114. labels := append(rt.labels, "") //nolint:gocritic
  115. rt.labels = nil
  116. test := node.test
  117. result := emptyValue
  118. resultBreak:
  119. for {
  120. for _, node := range node.body {
  121. value := rt.cmplEvaluateNodeStatement(node)
  122. switch value.kind {
  123. case valueResult:
  124. switch value.evaluateBreakContinue(labels) {
  125. case resultReturn:
  126. return value
  127. case resultBreak:
  128. break resultBreak
  129. case resultContinue:
  130. goto resultContinue
  131. }
  132. case valueEmpty:
  133. default:
  134. result = value
  135. }
  136. }
  137. resultContinue:
  138. if !rt.cmplEvaluateNodeExpression(test).resolve().bool() {
  139. // Stahp: do ... while (false)
  140. break
  141. }
  142. }
  143. return result
  144. }
  145. func (rt *runtime) cmplEvaluateNodeForInStatement(node *nodeForInStatement) Value {
  146. labels := append(rt.labels, "") //nolint:gocritic
  147. rt.labels = nil
  148. source := rt.cmplEvaluateNodeExpression(node.source)
  149. sourceValue := source.resolve()
  150. switch sourceValue.kind {
  151. case valueUndefined, valueNull:
  152. return emptyValue
  153. }
  154. sourceObject := rt.toObject(sourceValue)
  155. into := node.into
  156. body := node.body
  157. result := emptyValue
  158. obj := sourceObject
  159. for obj != nil {
  160. enumerateValue := emptyValue
  161. obj.enumerate(false, func(name string) bool {
  162. into := rt.cmplEvaluateNodeExpression(into)
  163. // In the case of: for (var abc in def) ...
  164. if into.reference() == nil {
  165. identifier := into.string()
  166. // TODO Should be true or false (strictness) depending on context
  167. into = toValue(getIdentifierReference(rt, rt.scope.lexical, identifier, false, -1))
  168. }
  169. rt.putValue(into.reference(), stringValue(name))
  170. for _, node := range body {
  171. value := rt.cmplEvaluateNodeStatement(node)
  172. switch value.kind {
  173. case valueResult:
  174. switch value.evaluateBreakContinue(labels) {
  175. case resultReturn:
  176. enumerateValue = value
  177. return false
  178. case resultBreak:
  179. obj = nil
  180. return false
  181. case resultContinue:
  182. return true
  183. }
  184. case valueEmpty:
  185. default:
  186. enumerateValue = value
  187. }
  188. }
  189. return true
  190. })
  191. if obj == nil {
  192. break
  193. }
  194. obj = obj.prototype
  195. if !enumerateValue.isEmpty() {
  196. result = enumerateValue
  197. }
  198. }
  199. return result
  200. }
  201. func (rt *runtime) cmplEvaluateNodeForStatement(node *nodeForStatement) Value {
  202. labels := append(rt.labels, "") //nolint:gocritic
  203. rt.labels = nil
  204. initializer := node.initializer
  205. test := node.test
  206. update := node.update
  207. body := node.body
  208. if initializer != nil {
  209. initialResult := rt.cmplEvaluateNodeExpression(initializer)
  210. initialResult.resolve() // Side-effect trigger
  211. }
  212. result := emptyValue
  213. resultBreak:
  214. for {
  215. if test != nil {
  216. testResult := rt.cmplEvaluateNodeExpression(test)
  217. testResultValue := testResult.resolve()
  218. if !testResultValue.bool() {
  219. break
  220. }
  221. }
  222. // this is to prevent for cycles with no body from running forever
  223. if len(body) == 0 && rt.otto.Interrupt != nil {
  224. goruntime.Gosched()
  225. select {
  226. case value := <-rt.otto.Interrupt:
  227. value()
  228. default:
  229. }
  230. }
  231. for _, node := range body {
  232. value := rt.cmplEvaluateNodeStatement(node)
  233. switch value.kind {
  234. case valueResult:
  235. switch value.evaluateBreakContinue(labels) {
  236. case resultReturn:
  237. return value
  238. case resultBreak:
  239. break resultBreak
  240. case resultContinue:
  241. goto resultContinue
  242. }
  243. case valueEmpty:
  244. default:
  245. result = value
  246. }
  247. }
  248. resultContinue:
  249. if update != nil {
  250. updateResult := rt.cmplEvaluateNodeExpression(update)
  251. updateResult.resolve() // Side-effect trigger
  252. }
  253. }
  254. return result
  255. }
  256. func (rt *runtime) cmplEvaluateNodeIfStatement(node *nodeIfStatement) Value {
  257. test := rt.cmplEvaluateNodeExpression(node.test)
  258. testValue := test.resolve()
  259. if testValue.bool() {
  260. return rt.cmplEvaluateNodeStatement(node.consequent)
  261. } else if node.alternate != nil {
  262. return rt.cmplEvaluateNodeStatement(node.alternate)
  263. }
  264. return emptyValue
  265. }
  266. func (rt *runtime) cmplEvaluateNodeSwitchStatement(node *nodeSwitchStatement) Value {
  267. labels := append(rt.labels, "") //nolint:gocritic
  268. rt.labels = nil
  269. discriminantResult := rt.cmplEvaluateNodeExpression(node.discriminant)
  270. target := node.defaultIdx
  271. for index, clause := range node.body {
  272. test := clause.test
  273. if test != nil {
  274. if rt.calculateComparison(token.STRICT_EQUAL, discriminantResult, rt.cmplEvaluateNodeExpression(test)) {
  275. target = index
  276. break
  277. }
  278. }
  279. }
  280. result := emptyValue
  281. if target != -1 {
  282. for _, clause := range node.body[target:] {
  283. for _, statement := range clause.consequent {
  284. value := rt.cmplEvaluateNodeStatement(statement)
  285. switch value.kind {
  286. case valueResult:
  287. switch value.evaluateBreak(labels) {
  288. case resultReturn:
  289. return value
  290. case resultBreak:
  291. return emptyValue
  292. }
  293. case valueEmpty:
  294. default:
  295. result = value
  296. }
  297. }
  298. }
  299. }
  300. return result
  301. }
  302. func (rt *runtime) cmplEvaluateNodeTryStatement(node *nodeTryStatement) Value {
  303. tryCatchValue, exep := rt.tryCatchEvaluate(func() Value {
  304. return rt.cmplEvaluateNodeStatement(node.body)
  305. })
  306. if exep && node.catch != nil {
  307. outer := rt.scope.lexical
  308. rt.scope.lexical = rt.newDeclarationStash(outer)
  309. defer func() {
  310. rt.scope.lexical = outer
  311. }()
  312. // TODO If necessary, convert TypeError<runtime> => TypeError
  313. // That, is, such errors can be thrown despite not being JavaScript "native"
  314. // strict = false
  315. rt.scope.lexical.setValue(node.catch.parameter, tryCatchValue, false)
  316. // FIXME node.CatchParameter
  317. // FIXME node.Catch
  318. tryCatchValue, exep = rt.tryCatchEvaluate(func() Value {
  319. return rt.cmplEvaluateNodeStatement(node.catch.body)
  320. })
  321. }
  322. if node.finally != nil {
  323. finallyValue := rt.cmplEvaluateNodeStatement(node.finally)
  324. if finallyValue.kind == valueResult {
  325. return finallyValue
  326. }
  327. }
  328. if exep {
  329. panic(newException(tryCatchValue))
  330. }
  331. return tryCatchValue
  332. }
  333. func (rt *runtime) cmplEvaluateModeWhileStatement(node *nodeWhileStatement) Value {
  334. test := node.test
  335. body := node.body
  336. labels := append(rt.labels, "") //nolint:gocritic
  337. rt.labels = nil
  338. result := emptyValue
  339. resultBreakContinue:
  340. for {
  341. if !rt.cmplEvaluateNodeExpression(test).resolve().bool() {
  342. // Stahp: while (false) ...
  343. break
  344. }
  345. for _, node := range body {
  346. value := rt.cmplEvaluateNodeStatement(node)
  347. switch value.kind {
  348. case valueResult:
  349. switch value.evaluateBreakContinue(labels) {
  350. case resultReturn:
  351. return value
  352. case resultBreak:
  353. break resultBreakContinue
  354. case resultContinue:
  355. continue resultBreakContinue
  356. }
  357. case valueEmpty:
  358. default:
  359. result = value
  360. }
  361. }
  362. }
  363. return result
  364. }
  365. func (rt *runtime) cmplEvaluateNodeWithStatement(node *nodeWithStatement) Value {
  366. obj := rt.cmplEvaluateNodeExpression(node.object)
  367. outer := rt.scope.lexical
  368. lexical := rt.newObjectStash(rt.toObject(obj.resolve()), outer)
  369. rt.scope.lexical = lexical
  370. defer func() {
  371. rt.scope.lexical = outer
  372. }()
  373. return rt.cmplEvaluateNodeStatement(node.body)
  374. }