compiler_stmt.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. package goja
  2. import (
  3. "fmt"
  4. "github.com/dop251/goja/ast"
  5. "github.com/dop251/goja/file"
  6. "github.com/dop251/goja/token"
  7. "strconv"
  8. )
  9. func (c *compiler) compileStatement(v ast.Statement, needResult bool) {
  10. // log.Printf("compileStatement(): %T", v)
  11. switch v := v.(type) {
  12. case *ast.BlockStatement:
  13. c.compileBlockStatement(v, needResult)
  14. case *ast.ExpressionStatement:
  15. c.compileExpressionStatement(v, needResult)
  16. case *ast.VariableStatement:
  17. c.compileVariableStatement(v, needResult)
  18. case *ast.ReturnStatement:
  19. c.compileReturnStatement(v)
  20. case *ast.IfStatement:
  21. c.compileIfStatement(v, needResult)
  22. case *ast.DoWhileStatement:
  23. c.compileDoWhileStatement(v, needResult)
  24. case *ast.ForStatement:
  25. c.compileForStatement(v, needResult)
  26. case *ast.ForInStatement:
  27. c.compileForInStatement(v, needResult)
  28. case *ast.ForOfStatement:
  29. c.compileForOfStatement(v, needResult)
  30. case *ast.WhileStatement:
  31. c.compileWhileStatement(v, needResult)
  32. case *ast.BranchStatement:
  33. c.compileBranchStatement(v, needResult)
  34. case *ast.TryStatement:
  35. c.compileTryStatement(v)
  36. if needResult {
  37. c.emit(loadUndef)
  38. }
  39. case *ast.ThrowStatement:
  40. c.compileThrowStatement(v)
  41. case *ast.SwitchStatement:
  42. c.compileSwitchStatement(v, needResult)
  43. case *ast.LabelledStatement:
  44. c.compileLabeledStatement(v, needResult)
  45. case *ast.EmptyStatement:
  46. c.compileEmptyStatement(needResult)
  47. case *ast.WithStatement:
  48. c.compileWithStatement(v, needResult)
  49. case *ast.DebuggerStatement:
  50. default:
  51. panic(fmt.Errorf("Unknown statement type: %T", v))
  52. }
  53. }
  54. func (c *compiler) compileLabeledStatement(v *ast.LabelledStatement, needResult bool) {
  55. label := v.Label.Name
  56. for b := c.block; b != nil; b = b.outer {
  57. if b.label == label {
  58. c.throwSyntaxError(int(v.Label.Idx-1), "Label '%s' has already been declared", label)
  59. }
  60. }
  61. switch s := v.Statement.(type) {
  62. case *ast.ForInStatement:
  63. c.compileLabeledForInStatement(s, needResult, label)
  64. case *ast.ForOfStatement:
  65. c.compileLabeledForOfStatement(s, needResult, label)
  66. case *ast.ForStatement:
  67. c.compileLabeledForStatement(s, needResult, label)
  68. case *ast.WhileStatement:
  69. c.compileLabeledWhileStatement(s, needResult, label)
  70. case *ast.DoWhileStatement:
  71. c.compileLabeledDoWhileStatement(s, needResult, label)
  72. default:
  73. c.compileGenericLabeledStatement(v.Statement, needResult, label)
  74. }
  75. }
  76. func (c *compiler) compileTryStatement(v *ast.TryStatement) {
  77. if c.scope.strict && v.Catch != nil {
  78. switch v.Catch.Parameter.Name {
  79. case "arguments", "eval":
  80. c.throwSyntaxError(int(v.Catch.Parameter.Idx)-1, "Catch variable may not be eval or arguments in strict mode")
  81. }
  82. }
  83. c.block = &block{
  84. typ: blockTry,
  85. outer: c.block,
  86. }
  87. lbl := len(c.p.code)
  88. c.emit(nil)
  89. c.compileStatement(v.Body, false)
  90. c.emit(halt)
  91. lbl2 := len(c.p.code)
  92. c.emit(nil)
  93. var catchOffset int
  94. dynamicCatch := true
  95. if v.Catch != nil {
  96. dyn := nearestNonLexical(c.scope).dynamic
  97. accessed := c.scope.accessed
  98. c.newScope()
  99. c.scope.bindName(v.Catch.Parameter.Name)
  100. c.scope.lexical = true
  101. start := len(c.p.code)
  102. c.emit(nil)
  103. catchOffset = len(c.p.code) - lbl
  104. c.emit(enterCatch(v.Catch.Parameter.Name))
  105. c.compileStatement(v.Catch.Body, false)
  106. dyn1 := c.scope.dynamic
  107. accessed1 := c.scope.accessed
  108. c.popScope()
  109. if !dyn && !dyn1 && !accessed1 {
  110. c.scope.accessed = accessed
  111. dynamicCatch = false
  112. code := c.p.code[start+1:]
  113. m := make(map[uint32]uint32)
  114. remap := func(instr uint32) uint32 {
  115. level := instr >> 24
  116. idx := instr & 0x00FFFFFF
  117. if level > 0 {
  118. level--
  119. return (level << 24) | idx
  120. } else {
  121. // remap
  122. newIdx, exists := m[idx]
  123. if !exists {
  124. exname := " __tmp" + strconv.Itoa(c.scope.lastFreeTmp)
  125. c.scope.lastFreeTmp++
  126. newIdx, _ = c.scope.bindName(exname)
  127. m[idx] = newIdx
  128. }
  129. return newIdx
  130. }
  131. }
  132. for pc, instr := range code {
  133. switch instr := instr.(type) {
  134. case getLocal:
  135. code[pc] = getLocal(remap(uint32(instr)))
  136. case setLocal:
  137. code[pc] = setLocal(remap(uint32(instr)))
  138. case setLocalP:
  139. code[pc] = setLocalP(remap(uint32(instr)))
  140. }
  141. }
  142. if catchVarIdx, exists := m[0]; exists {
  143. c.p.code[start] = setLocal(catchVarIdx)
  144. c.p.code[start+1] = pop
  145. catchOffset--
  146. } else {
  147. c.p.code[start+1] = nil
  148. catchOffset++
  149. }
  150. } else {
  151. c.scope.accessed = true
  152. }
  153. /*
  154. if true/*sc.dynamic/ {
  155. dynamicCatch = true
  156. c.scope.accessed = true
  157. c.newScope()
  158. c.scope.bindName(v.Catch.Parameter.Name)
  159. c.scope.lexical = true
  160. c.emit(enterCatch(v.Catch.Parameter.Name))
  161. c.compileStatement(v.Catch.Body, false)
  162. c.popScope()
  163. } else {
  164. exname := " __tmp" + strconv.Itoa(c.scope.lastFreeTmp)
  165. c.scope.lastFreeTmp++
  166. catchVarIdx, _ := c.scope.bindName(exname)
  167. c.emit(setLocal(catchVarIdx), pop)
  168. saved, wasSaved := c.scope.namesMap[v.Catch.Parameter.Name]
  169. c.scope.namesMap[v.Catch.Parameter.Name] = exname
  170. c.compileStatement(v.Catch.Body, false)
  171. if wasSaved {
  172. c.scope.namesMap[v.Catch.Parameter.Name] = saved
  173. } else {
  174. delete(c.scope.namesMap, v.Catch.Parameter.Name)
  175. }
  176. c.scope.lastFreeTmp--
  177. }*/
  178. c.emit(halt)
  179. }
  180. var finallyOffset int
  181. if v.Finally != nil {
  182. lbl1 := len(c.p.code)
  183. c.emit(nil)
  184. finallyOffset = len(c.p.code) - lbl
  185. c.compileStatement(v.Finally, false)
  186. c.emit(halt, retFinally)
  187. c.p.code[lbl1] = jump(len(c.p.code) - lbl1)
  188. }
  189. c.p.code[lbl] = try{catchOffset: int32(catchOffset), finallyOffset: int32(finallyOffset), dynamic: dynamicCatch}
  190. c.p.code[lbl2] = jump(len(c.p.code) - lbl2)
  191. c.leaveBlock()
  192. }
  193. func (c *compiler) compileThrowStatement(v *ast.ThrowStatement) {
  194. //c.p.srcMap = append(c.p.srcMap, srcMapItem{pc: len(c.p.code), srcPos: int(v.Throw) - 1})
  195. c.compileExpression(v.Argument).emitGetter(true)
  196. c.emit(throw)
  197. }
  198. func (c *compiler) compileDoWhileStatement(v *ast.DoWhileStatement, needResult bool) {
  199. c.compileLabeledDoWhileStatement(v, needResult, "")
  200. }
  201. func (c *compiler) compileLabeledDoWhileStatement(v *ast.DoWhileStatement, needResult bool, label string) {
  202. c.block = &block{
  203. typ: blockLoop,
  204. outer: c.block,
  205. label: label,
  206. needResult: needResult,
  207. }
  208. if needResult {
  209. c.emit(jump(2))
  210. }
  211. start := len(c.p.code)
  212. if needResult {
  213. c.emit(pop)
  214. }
  215. c.markBlockStart()
  216. c.compileStatement(v.Body, needResult)
  217. c.block.cont = len(c.p.code)
  218. c.emitExpr(c.compileExpression(v.Test), true)
  219. c.emit(jeq(start - len(c.p.code)))
  220. c.leaveBlock()
  221. }
  222. func (c *compiler) compileForStatement(v *ast.ForStatement, needResult bool) {
  223. c.compileLabeledForStatement(v, needResult, "")
  224. }
  225. func (c *compiler) compileLabeledForStatement(v *ast.ForStatement, needResult bool, label string) {
  226. c.block = &block{
  227. typ: blockLoop,
  228. outer: c.block,
  229. label: label,
  230. needResult: needResult,
  231. }
  232. if v.Initializer != nil {
  233. c.compileExpression(v.Initializer).emitGetter(false)
  234. }
  235. if needResult {
  236. c.emit(loadUndef) // initial result
  237. }
  238. start := len(c.p.code)
  239. c.markBlockStart()
  240. var j int
  241. testConst := false
  242. if v.Test != nil {
  243. expr := c.compileExpression(v.Test)
  244. if expr.constant() {
  245. r, ex := c.evalConst(expr)
  246. if ex == nil {
  247. if r.ToBoolean() {
  248. testConst = true
  249. } else {
  250. // TODO: Properly implement dummy compilation (no garbage in block, scope, etc..)
  251. /*
  252. p := c.p
  253. c.p = &program{}
  254. c.compileStatement(v.Body, false)
  255. if v.Update != nil {
  256. c.compileExpression(v.Update).emitGetter(false)
  257. }
  258. c.p = p*/
  259. goto end
  260. }
  261. } else {
  262. expr.addSrcMap()
  263. c.emitThrow(ex.val)
  264. goto end
  265. }
  266. } else {
  267. expr.emitGetter(true)
  268. j = len(c.p.code)
  269. c.emit(nil)
  270. }
  271. }
  272. if needResult {
  273. c.emit(pop) // remove last result
  274. }
  275. c.markBlockStart()
  276. c.compileStatement(v.Body, needResult)
  277. c.block.cont = len(c.p.code)
  278. if v.Update != nil {
  279. c.compileExpression(v.Update).emitGetter(false)
  280. }
  281. c.emit(jump(start - len(c.p.code)))
  282. if v.Test != nil {
  283. if !testConst {
  284. c.p.code[j] = jne(len(c.p.code) - j)
  285. }
  286. }
  287. end:
  288. c.leaveBlock()
  289. c.markBlockStart()
  290. }
  291. func (c *compiler) compileForInStatement(v *ast.ForInStatement, needResult bool) {
  292. c.compileLabeledForInStatement(v, needResult, "")
  293. }
  294. func (c *compiler) compileLabeledForInStatement(v *ast.ForInStatement, needResult bool, label string) {
  295. c.block = &block{
  296. typ: blockLoop,
  297. outer: c.block,
  298. label: label,
  299. needResult: needResult,
  300. }
  301. c.compileExpression(v.Source).emitGetter(true)
  302. c.emit(enumerate)
  303. if needResult {
  304. c.emit(loadUndef)
  305. }
  306. start := len(c.p.code)
  307. c.markBlockStart()
  308. c.block.cont = start
  309. c.emit(nil)
  310. c.compileExpression(v.Into).emitSetter(&c.enumGetExpr)
  311. c.emit(pop)
  312. if needResult {
  313. c.emit(pop) // remove last result
  314. }
  315. c.markBlockStart()
  316. c.compileStatement(v.Body, needResult)
  317. c.emit(jump(start - len(c.p.code)))
  318. c.p.code[start] = enumNext(len(c.p.code) - start)
  319. c.leaveBlock()
  320. c.markBlockStart()
  321. c.emit(enumPop)
  322. }
  323. func (c *compiler) compileForOfStatement(v *ast.ForOfStatement, needResult bool) {
  324. c.compileLabeledForOfStatement(v, needResult, "")
  325. }
  326. func (c *compiler) compileLabeledForOfStatement(v *ast.ForOfStatement, needResult bool, label string) {
  327. c.block = &block{
  328. typ: blockLoop,
  329. outer: c.block,
  330. label: label,
  331. needResult: needResult,
  332. }
  333. c.compileExpression(v.Source).emitGetter(true)
  334. c.emit(iterate)
  335. if needResult {
  336. c.emit(loadUndef)
  337. }
  338. start := len(c.p.code)
  339. c.markBlockStart()
  340. c.block.cont = start
  341. c.emit(nil)
  342. c.compileExpression(v.Into).emitSetter(&c.enumGetExpr)
  343. c.emit(pop)
  344. if needResult {
  345. c.emit(pop) // remove last result
  346. }
  347. c.markBlockStart()
  348. c.compileStatement(v.Body, needResult)
  349. c.emit(jump(start - len(c.p.code)))
  350. c.p.code[start] = iterNext(len(c.p.code) - start)
  351. c.leaveBlock()
  352. c.markBlockStart()
  353. c.emit(enumPop)
  354. }
  355. func (c *compiler) compileWhileStatement(v *ast.WhileStatement, needResult bool) {
  356. c.compileLabeledWhileStatement(v, needResult, "")
  357. }
  358. func (c *compiler) compileLabeledWhileStatement(v *ast.WhileStatement, needResult bool, label string) {
  359. c.block = &block{
  360. typ: blockLoop,
  361. outer: c.block,
  362. label: label,
  363. needResult: needResult,
  364. }
  365. if needResult {
  366. c.emit(loadUndef)
  367. }
  368. start := len(c.p.code)
  369. c.markBlockStart()
  370. c.block.cont = start
  371. expr := c.compileExpression(v.Test)
  372. testTrue := false
  373. var j int
  374. if expr.constant() {
  375. if t, ex := c.evalConst(expr); ex == nil {
  376. if t.ToBoolean() {
  377. testTrue = true
  378. } else {
  379. p := c.p
  380. c.p = &Program{}
  381. c.compileStatement(v.Body, false)
  382. c.p = p
  383. goto end
  384. }
  385. } else {
  386. c.emitThrow(ex.val)
  387. goto end
  388. }
  389. } else {
  390. expr.emitGetter(true)
  391. j = len(c.p.code)
  392. c.emit(nil)
  393. }
  394. if needResult {
  395. c.emit(pop)
  396. }
  397. c.markBlockStart()
  398. c.compileStatement(v.Body, needResult)
  399. c.emit(jump(start - len(c.p.code)))
  400. if !testTrue {
  401. c.p.code[j] = jne(len(c.p.code) - j)
  402. }
  403. end:
  404. c.leaveBlock()
  405. c.markBlockStart()
  406. }
  407. func (c *compiler) compileEmptyStatement(needResult bool) {
  408. if needResult {
  409. if len(c.p.code) == c.blockStart {
  410. // first statement in block, use undefined as result
  411. c.emit(loadUndef)
  412. }
  413. }
  414. }
  415. func (c *compiler) compileBranchStatement(v *ast.BranchStatement, needResult bool) {
  416. switch v.Token {
  417. case token.BREAK:
  418. c.compileBreak(v.Label, v.Idx)
  419. case token.CONTINUE:
  420. c.compileContinue(v.Label, v.Idx)
  421. default:
  422. panic(fmt.Errorf("Unknown branch statement token: %s", v.Token.String()))
  423. }
  424. }
  425. func (c *compiler) findBranchBlock(st *ast.BranchStatement) *block {
  426. switch st.Token {
  427. case token.BREAK:
  428. return c.findBreakBlock(st.Label)
  429. case token.CONTINUE:
  430. return c.findContinueBlock(st.Label)
  431. }
  432. return nil
  433. }
  434. func (c *compiler) findContinueBlock(label *ast.Identifier) (block *block) {
  435. if label != nil {
  436. for b := c.block; b != nil; b = b.outer {
  437. if b.typ == blockLoop && b.label == label.Name {
  438. block = b
  439. break
  440. }
  441. }
  442. } else {
  443. // find the nearest loop
  444. for b := c.block; b != nil; b = b.outer {
  445. if b.typ == blockLoop {
  446. block = b
  447. break
  448. }
  449. }
  450. }
  451. return
  452. }
  453. func (c *compiler) findBreakBlock(label *ast.Identifier) (block *block) {
  454. if label != nil {
  455. for b := c.block; b != nil; b = b.outer {
  456. if b.label == label.Name {
  457. block = b
  458. break
  459. }
  460. }
  461. } else {
  462. // find the nearest loop or switch
  463. L:
  464. for b := c.block; b != nil; b = b.outer {
  465. switch b.typ {
  466. case blockLoop, blockSwitch:
  467. block = b
  468. break L
  469. }
  470. }
  471. }
  472. return
  473. }
  474. func (c *compiler) compileBreak(label *ast.Identifier, idx file.Idx) {
  475. var block *block
  476. if label != nil {
  477. for b := c.block; b != nil; b = b.outer {
  478. switch b.typ {
  479. case blockTry:
  480. c.emit(halt)
  481. case blockWith:
  482. c.emit(leaveWith)
  483. }
  484. if b.label == label.Name {
  485. block = b
  486. break
  487. }
  488. }
  489. } else {
  490. // find the nearest loop or switch
  491. L:
  492. for b := c.block; b != nil; b = b.outer {
  493. switch b.typ {
  494. case blockTry:
  495. c.emit(halt)
  496. case blockWith:
  497. c.emit(leaveWith)
  498. case blockLoop, blockSwitch:
  499. block = b
  500. break L
  501. }
  502. }
  503. }
  504. if block != nil {
  505. if len(c.p.code) == c.blockStart && block.needResult {
  506. c.emit(loadUndef)
  507. }
  508. block.breaks = append(block.breaks, len(c.p.code))
  509. c.emit(nil)
  510. } else {
  511. c.throwSyntaxError(int(idx)-1, "Undefined label '%s'", label.Name)
  512. }
  513. }
  514. func (c *compiler) compileContinue(label *ast.Identifier, idx file.Idx) {
  515. var block *block
  516. if label != nil {
  517. for b := c.block; b != nil; b = b.outer {
  518. if b.typ == blockTry {
  519. c.emit(halt)
  520. } else if b.typ == blockLoop && b.label == label.Name {
  521. block = b
  522. break
  523. }
  524. }
  525. } else {
  526. // find the nearest loop
  527. for b := c.block; b != nil; b = b.outer {
  528. if b.typ == blockTry {
  529. c.emit(halt)
  530. } else if b.typ == blockLoop {
  531. block = b
  532. break
  533. }
  534. }
  535. }
  536. if block != nil {
  537. if len(c.p.code) == c.blockStart && block.needResult {
  538. c.emit(loadUndef)
  539. }
  540. block.conts = append(block.conts, len(c.p.code))
  541. c.emit(nil)
  542. } else {
  543. c.throwSyntaxError(int(idx)-1, "Undefined label '%s'", label.Name)
  544. }
  545. }
  546. func (c *compiler) compileIfStatement(v *ast.IfStatement, needResult bool) {
  547. test := c.compileExpression(v.Test)
  548. if test.constant() {
  549. r, ex := c.evalConst(test)
  550. if ex != nil {
  551. test.addSrcMap()
  552. c.emitThrow(ex.val)
  553. return
  554. }
  555. if r.ToBoolean() {
  556. c.markBlockStart()
  557. c.compileStatement(v.Consequent, needResult)
  558. if v.Alternate != nil {
  559. p := c.p
  560. c.p = &Program{}
  561. c.markBlockStart()
  562. c.compileStatement(v.Alternate, false)
  563. c.p = p
  564. }
  565. } else {
  566. // TODO: Properly implement dummy compilation (no garbage in block, scope, etc..)
  567. p := c.p
  568. c.p = &Program{}
  569. c.compileStatement(v.Consequent, false)
  570. c.p = p
  571. if v.Alternate != nil {
  572. c.compileStatement(v.Alternate, needResult)
  573. } else {
  574. if needResult {
  575. c.emit(loadUndef)
  576. }
  577. }
  578. }
  579. return
  580. }
  581. test.emitGetter(true)
  582. jmp := len(c.p.code)
  583. c.emit(nil)
  584. c.markBlockStart()
  585. c.compileStatement(v.Consequent, needResult)
  586. if v.Alternate != nil {
  587. jmp1 := len(c.p.code)
  588. c.emit(nil)
  589. c.p.code[jmp] = jne(len(c.p.code) - jmp)
  590. c.markBlockStart()
  591. c.compileStatement(v.Alternate, needResult)
  592. c.p.code[jmp1] = jump(len(c.p.code) - jmp1)
  593. c.markBlockStart()
  594. } else {
  595. c.p.code[jmp] = jne(len(c.p.code) - jmp)
  596. c.markBlockStart()
  597. if needResult {
  598. c.emit(loadUndef)
  599. }
  600. }
  601. }
  602. func (c *compiler) compileReturnStatement(v *ast.ReturnStatement) {
  603. if v.Argument != nil {
  604. c.compileExpression(v.Argument).emitGetter(true)
  605. //c.emit(checkResolve)
  606. } else {
  607. c.emit(loadUndef)
  608. }
  609. for b := c.block; b != nil; b = b.outer {
  610. if b.typ == blockTry {
  611. c.emit(halt)
  612. }
  613. }
  614. c.emit(ret)
  615. }
  616. func (c *compiler) compileVariableStatement(v *ast.VariableStatement, needResult bool) {
  617. for _, expr := range v.List {
  618. c.compileExpression(expr).emitGetter(false)
  619. }
  620. if needResult {
  621. c.emit(loadUndef)
  622. }
  623. }
  624. func (c *compiler) getFirstNonEmptyStatement(st ast.Statement) ast.Statement {
  625. switch st := st.(type) {
  626. case *ast.BlockStatement:
  627. return c.getFirstNonEmptyStatementList(st.List)
  628. case *ast.LabelledStatement:
  629. return c.getFirstNonEmptyStatement(st.Statement)
  630. }
  631. return st
  632. }
  633. func (c *compiler) getFirstNonEmptyStatementList(list []ast.Statement) ast.Statement {
  634. for _, st := range list {
  635. switch st := st.(type) {
  636. case *ast.EmptyStatement:
  637. continue
  638. case *ast.BlockStatement:
  639. return c.getFirstNonEmptyStatementList(st.List)
  640. case *ast.LabelledStatement:
  641. return c.getFirstNonEmptyStatement(st.Statement)
  642. }
  643. return st
  644. }
  645. return nil
  646. }
  647. func (c *compiler) compileStatements(list []ast.Statement, needResult bool) {
  648. if len(list) > 0 {
  649. cur := list[0]
  650. for idx := 0; idx < len(list); {
  651. var next ast.Statement
  652. // find next non-empty statement
  653. for idx++; idx < len(list); idx++ {
  654. if _, empty := list[idx].(*ast.EmptyStatement); !empty {
  655. next = list[idx]
  656. break
  657. }
  658. }
  659. if next != nil {
  660. bs := c.getFirstNonEmptyStatement(next)
  661. if bs, ok := bs.(*ast.BranchStatement); ok {
  662. block := c.findBranchBlock(bs)
  663. if block != nil {
  664. c.compileStatement(cur, block.needResult)
  665. cur = next
  666. continue
  667. }
  668. }
  669. c.compileStatement(cur, false)
  670. cur = next
  671. } else {
  672. c.compileStatement(cur, needResult)
  673. }
  674. }
  675. } else {
  676. if needResult {
  677. c.emit(loadUndef)
  678. }
  679. }
  680. }
  681. func (c *compiler) compileGenericLabeledStatement(v ast.Statement, needResult bool, label string) {
  682. c.block = &block{
  683. typ: blockBranch,
  684. outer: c.block,
  685. label: label,
  686. needResult: needResult,
  687. }
  688. c.compileStatement(v, needResult)
  689. c.leaveBlock()
  690. }
  691. func (c *compiler) compileBlockStatement(v *ast.BlockStatement, needResult bool) {
  692. c.compileStatements(v.List, needResult)
  693. }
  694. func (c *compiler) compileExpressionStatement(v *ast.ExpressionStatement, needResult bool) {
  695. expr := c.compileExpression(v.Expression)
  696. if expr.constant() {
  697. c.emitConst(expr, needResult)
  698. } else {
  699. expr.emitGetter(needResult)
  700. }
  701. }
  702. func (c *compiler) compileWithStatement(v *ast.WithStatement, needResult bool) {
  703. if c.scope.strict {
  704. c.throwSyntaxError(int(v.With)-1, "Strict mode code may not include a with statement")
  705. return
  706. }
  707. c.compileExpression(v.Object).emitGetter(true)
  708. c.emit(enterWith)
  709. c.block = &block{
  710. outer: c.block,
  711. typ: blockWith,
  712. needResult: needResult,
  713. }
  714. c.newScope()
  715. c.scope.dynamic = true
  716. c.scope.lexical = true
  717. c.compileStatement(v.Body, needResult)
  718. c.emit(leaveWith)
  719. c.leaveBlock()
  720. c.popScope()
  721. }
  722. func (c *compiler) compileSwitchStatement(v *ast.SwitchStatement, needResult bool) {
  723. c.block = &block{
  724. typ: blockSwitch,
  725. outer: c.block,
  726. needResult: needResult,
  727. }
  728. c.compileExpression(v.Discriminant).emitGetter(true)
  729. jumps := make([]int, len(v.Body))
  730. for i, s := range v.Body {
  731. if s.Test != nil {
  732. c.emit(dup)
  733. c.compileExpression(s.Test).emitGetter(true)
  734. c.emit(op_strict_eq)
  735. c.emit(jne(3), pop)
  736. jumps[i] = len(c.p.code)
  737. c.emit(nil)
  738. }
  739. }
  740. c.emit(pop)
  741. jumpNoMatch := -1
  742. if v.Default != -1 {
  743. if v.Default != 0 {
  744. jumps[v.Default] = len(c.p.code)
  745. c.emit(nil)
  746. }
  747. } else {
  748. jumpNoMatch = len(c.p.code)
  749. c.emit(nil)
  750. }
  751. for i, s := range v.Body {
  752. if s.Test != nil || i != 0 {
  753. c.p.code[jumps[i]] = jump(len(c.p.code) - jumps[i])
  754. c.markBlockStart()
  755. }
  756. nr := false
  757. c.markBlockStart()
  758. if needResult {
  759. if i < len(v.Body)-1 {
  760. st := c.getFirstNonEmptyStatementList(v.Body[i+1].Consequent)
  761. if st, ok := st.(*ast.BranchStatement); ok && st.Token == token.BREAK {
  762. if c.findBreakBlock(st.Label) != nil {
  763. stmts := append(s.Consequent, st)
  764. c.compileStatements(stmts, false)
  765. continue
  766. }
  767. }
  768. } else {
  769. nr = true
  770. }
  771. }
  772. c.compileStatements(s.Consequent, nr)
  773. }
  774. if jumpNoMatch != -1 {
  775. if needResult {
  776. c.emit(jump(2))
  777. }
  778. c.p.code[jumpNoMatch] = jump(len(c.p.code) - jumpNoMatch)
  779. if needResult {
  780. c.emit(loadUndef)
  781. }
  782. }
  783. c.leaveBlock()
  784. c.markBlockStart()
  785. }