compiler_stmt.go 20 KB

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