cmpl_evaluate_statement.go 10 KB

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