1 package goja
2
3 import (
4 "github.com/dop251/goja/ast"
5 "github.com/dop251/goja/file"
6 "github.com/dop251/goja/token"
7 "github.com/dop251/goja/unistring"
8 )
9
10 func (c *compiler) compileStatement(v ast.Statement, needResult bool) {
11
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)
19 case *ast.LexicalDeclaration:
20 c.compileLexicalDeclaration(v)
21 case *ast.ReturnStatement:
22 c.compileReturnStatement(v)
23 case *ast.IfStatement:
24 c.compileIfStatement(v, needResult)
25 case *ast.DoWhileStatement:
26 c.compileDoWhileStatement(v, needResult)
27 case *ast.ForStatement:
28 c.compileForStatement(v, needResult)
29 case *ast.ForInStatement:
30 c.compileForInStatement(v, needResult)
31 case *ast.ForOfStatement:
32 c.compileForOfStatement(v, needResult)
33 case *ast.WhileStatement:
34 c.compileWhileStatement(v, needResult)
35 case *ast.BranchStatement:
36 c.compileBranchStatement(v)
37 case *ast.TryStatement:
38 c.compileTryStatement(v, needResult)
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.FunctionDeclaration:
48 c.compileStandaloneFunctionDecl(v)
49
50 case *ast.ClassDeclaration:
51 c.compileClassDeclaration(v)
52 case *ast.WithStatement:
53 c.compileWithStatement(v, needResult)
54 case *ast.DebuggerStatement:
55 default:
56 c.assert(false, int(v.Idx0())-1, "Unknown statement type: %T", v)
57 panic("unreachable")
58 }
59 }
60
61 func (c *compiler) compileLabeledStatement(v *ast.LabelledStatement, needResult bool) {
62 label := v.Label.Name
63 if c.scope.strict {
64 c.checkIdentifierName(label, int(v.Label.Idx)-1)
65 }
66 for b := c.block; b != nil; b = b.outer {
67 if b.label == label {
68 c.throwSyntaxError(int(v.Label.Idx-1), "Label '%s' has already been declared", label)
69 }
70 }
71 switch s := v.Statement.(type) {
72 case *ast.ForInStatement:
73 c.compileLabeledForInStatement(s, needResult, label)
74 case *ast.ForOfStatement:
75 c.compileLabeledForOfStatement(s, needResult, label)
76 case *ast.ForStatement:
77 c.compileLabeledForStatement(s, needResult, label)
78 case *ast.WhileStatement:
79 c.compileLabeledWhileStatement(s, needResult, label)
80 case *ast.DoWhileStatement:
81 c.compileLabeledDoWhileStatement(s, needResult, label)
82 default:
83 c.compileGenericLabeledStatement(s, needResult, label)
84 }
85 }
86
87 func (c *compiler) updateEnterBlock(enter *enterBlock) {
88 scope := c.scope
89 stashSize, stackSize := 0, 0
90 if scope.dynLookup {
91 stashSize = len(scope.bindings)
92 enter.names = scope.makeNamesMap()
93 } else {
94 for _, b := range scope.bindings {
95 if b.inStash {
96 stashSize++
97 } else {
98 stackSize++
99 }
100 }
101 }
102 enter.stashSize, enter.stackSize = uint32(stashSize), uint32(stackSize)
103 }
104
105 func (c *compiler) compileTryStatement(v *ast.TryStatement, needResult bool) {
106 c.block = &block{
107 typ: blockTry,
108 outer: c.block,
109 }
110 var lp int
111 var bodyNeedResult bool
112 var finallyBreaking *block
113 if v.Finally != nil {
114 lp, finallyBreaking = c.scanStatements(v.Finally.List)
115 }
116 if finallyBreaking != nil {
117 c.block.breaking = finallyBreaking
118 if lp == -1 {
119 bodyNeedResult = finallyBreaking.needResult
120 }
121 } else {
122 bodyNeedResult = needResult
123 }
124 lbl := len(c.p.code)
125 c.emit(nil)
126 if needResult {
127 c.emit(clearResult)
128 }
129 c.compileBlockStatement(v.Body, bodyNeedResult)
130 var catchOffset int
131 if v.Catch != nil {
132 lbl2 := len(c.p.code)
133 c.emit(nil)
134 catchOffset = len(c.p.code) - lbl
135 if v.Catch.Parameter != nil {
136 c.block = &block{
137 typ: blockScope,
138 outer: c.block,
139 }
140 c.newBlockScope()
141 list := v.Catch.Body.List
142 funcs := c.extractFunctions(list)
143 if _, ok := v.Catch.Parameter.(ast.Pattern); ok {
144
145 c.scope.addBinding(int(v.Catch.Idx0()) - 1)
146 }
147 c.createBindings(v.Catch.Parameter, func(name unistring.String, offset int) {
148 if c.scope.strict {
149 switch name {
150 case "arguments", "eval":
151 c.throwSyntaxError(offset, "Catch variable may not be eval or arguments in strict mode")
152 }
153 }
154 c.scope.bindNameLexical(name, true, offset)
155 })
156 enter := &enterBlock{}
157 c.emit(enter)
158 if pattern, ok := v.Catch.Parameter.(ast.Pattern); ok {
159 c.scope.bindings[0].emitGet()
160 c.emitPattern(pattern, func(target, init compiledExpr) {
161 c.emitPatternLexicalAssign(target, init)
162 }, false)
163 }
164 for _, decl := range funcs {
165 c.scope.bindNameLexical(decl.Function.Name.Name, true, int(decl.Function.Name.Idx1())-1)
166 }
167 c.compileLexicalDeclarations(list, true)
168 c.compileFunctions(funcs)
169 c.compileStatements(list, bodyNeedResult)
170 c.leaveScopeBlock(enter)
171 if c.scope.dynLookup || c.scope.bindings[0].inStash {
172 c.p.code[lbl+catchOffset] = &enterCatchBlock{
173 names: enter.names,
174 stashSize: enter.stashSize,
175 stackSize: enter.stackSize,
176 }
177 } else {
178 enter.stackSize--
179 }
180 c.popScope()
181 } else {
182 c.emit(pop)
183 c.compileBlockStatement(v.Catch.Body, bodyNeedResult)
184 }
185 c.p.code[lbl2] = jump(len(c.p.code) - lbl2)
186 }
187 var finallyOffset int
188 if v.Finally != nil {
189 c.emit(enterFinally{})
190 finallyOffset = len(c.p.code) - lbl
191 if bodyNeedResult && finallyBreaking != nil && lp == -1 {
192 c.emit(clearResult)
193 }
194 c.compileBlockStatement(v.Finally, false)
195 c.emit(leaveFinally{})
196 } else {
197 c.emit(leaveTry{})
198 }
199 c.p.code[lbl] = try{catchOffset: int32(catchOffset), finallyOffset: int32(finallyOffset)}
200 c.leaveBlock()
201 }
202
203 func (c *compiler) addSrcMap(node ast.Node) {
204 c.p.addSrcMap(int(node.Idx0()) - 1)
205 }
206
207 func (c *compiler) compileThrowStatement(v *ast.ThrowStatement) {
208 c.compileExpression(v.Argument).emitGetter(true)
209 c.addSrcMap(v)
210 c.emit(throw)
211 }
212
213 func (c *compiler) compileDoWhileStatement(v *ast.DoWhileStatement, needResult bool) {
214 c.compileLabeledDoWhileStatement(v, needResult, "")
215 }
216
217 func (c *compiler) compileLabeledDoWhileStatement(v *ast.DoWhileStatement, needResult bool, label unistring.String) {
218 c.block = &block{
219 typ: blockLoop,
220 outer: c.block,
221 label: label,
222 needResult: needResult,
223 }
224
225 start := len(c.p.code)
226 c.compileStatement(v.Body, needResult)
227 c.block.cont = len(c.p.code)
228 c.emitExpr(c.compileExpression(v.Test), true)
229 c.emit(jeq(start - len(c.p.code)))
230 c.leaveBlock()
231 }
232
233 func (c *compiler) compileForStatement(v *ast.ForStatement, needResult bool) {
234 c.compileLabeledForStatement(v, needResult, "")
235 }
236
237 func (c *compiler) compileForHeadLexDecl(decl *ast.LexicalDeclaration, needResult bool) *enterBlock {
238 c.block = &block{
239 typ: blockIterScope,
240 outer: c.block,
241 needResult: needResult,
242 }
243
244 c.newBlockScope()
245 enterIterBlock := &enterBlock{}
246 c.emit(enterIterBlock)
247 c.createLexicalBindings(decl)
248 c.compileLexicalDeclaration(decl)
249 return enterIterBlock
250 }
251
252 func (c *compiler) compileLabeledForStatement(v *ast.ForStatement, needResult bool, label unistring.String) {
253 loopBlock := &block{
254 typ: blockLoop,
255 outer: c.block,
256 label: label,
257 needResult: needResult,
258 }
259 c.block = loopBlock
260
261 var enterIterBlock *enterBlock
262 switch init := v.Initializer.(type) {
263 case nil:
264
265 case *ast.ForLoopInitializerLexicalDecl:
266 enterIterBlock = c.compileForHeadLexDecl(&init.LexicalDeclaration, needResult)
267 case *ast.ForLoopInitializerVarDeclList:
268 for _, expr := range init.List {
269 c.compileVarBinding(expr)
270 }
271 case *ast.ForLoopInitializerExpression:
272 c.compileExpression(init.Expression).emitGetter(false)
273 default:
274 c.assert(false, int(v.For)-1, "Unsupported for loop initializer: %T", init)
275 panic("unreachable")
276 }
277
278 if needResult {
279 c.emit(clearResult)
280 }
281
282 if enterIterBlock != nil {
283 c.emit(jump(1))
284 }
285
286 start := len(c.p.code)
287 var j int
288 testConst := false
289 if v.Test != nil {
290 expr := c.compileExpression(v.Test)
291 if expr.constant() {
292 r, ex := c.evalConst(expr)
293 if ex == nil {
294 if r.ToBoolean() {
295 testConst = true
296 } else {
297 leave := c.enterDummyMode()
298 c.compileStatement(v.Body, false)
299 if v.Update != nil {
300 c.compileExpression(v.Update).emitGetter(false)
301 }
302 leave()
303 goto end
304 }
305 } else {
306 expr.addSrcMap()
307 c.emitThrow(ex.val)
308 goto end
309 }
310 } else {
311 expr.emitGetter(true)
312 j = len(c.p.code)
313 c.emit(nil)
314 }
315 }
316 if needResult {
317 c.emit(clearResult)
318 }
319 c.compileStatement(v.Body, needResult)
320 loopBlock.cont = len(c.p.code)
321 if enterIterBlock != nil {
322 c.emit(jump(1))
323 }
324 if v.Update != nil {
325 c.compileExpression(v.Update).emitGetter(false)
326 }
327 if enterIterBlock != nil {
328 if c.scope.needStash || c.scope.isDynamic() {
329 c.p.code[start-1] = copyStash{}
330 c.p.code[loopBlock.cont] = copyStash{}
331 } else {
332 if l := len(c.p.code); l > loopBlock.cont {
333 loopBlock.cont++
334 } else {
335 c.p.code = c.p.code[:l-1]
336 }
337 }
338 }
339 c.emit(jump(start - len(c.p.code)))
340 if v.Test != nil {
341 if !testConst {
342 c.p.code[j] = jne(len(c.p.code) - j)
343 }
344 }
345 end:
346 if enterIterBlock != nil {
347 c.leaveScopeBlock(enterIterBlock)
348 c.popScope()
349 }
350 c.leaveBlock()
351 }
352
353 func (c *compiler) compileForInStatement(v *ast.ForInStatement, needResult bool) {
354 c.compileLabeledForInStatement(v, needResult, "")
355 }
356
357 func (c *compiler) compileForInto(into ast.ForInto, needResult bool) (enter *enterBlock) {
358 switch into := into.(type) {
359 case *ast.ForIntoExpression:
360 c.compileExpression(into.Expression).emitSetter(&c.enumGetExpr, false)
361 case *ast.ForIntoVar:
362 if c.scope.strict && into.Binding.Initializer != nil {
363 c.throwSyntaxError(int(into.Binding.Initializer.Idx0())-1, "for-in loop variable declaration may not have an initializer.")
364 }
365 switch target := into.Binding.Target.(type) {
366 case *ast.Identifier:
367 c.compileIdentifierExpression(target).emitSetter(&c.enumGetExpr, false)
368 case ast.Pattern:
369 c.emit(enumGet)
370 c.emitPattern(target, c.emitPatternVarAssign, false)
371 default:
372 c.throwSyntaxError(int(target.Idx0()-1), "unsupported for-in var target: %T", target)
373 }
374 case *ast.ForDeclaration:
375
376 c.block = &block{
377 typ: blockIterScope,
378 outer: c.block,
379 needResult: needResult,
380 }
381
382 c.newBlockScope()
383 enter = &enterBlock{}
384 c.emit(enter)
385 switch target := into.Target.(type) {
386 case *ast.Identifier:
387 b := c.createLexicalIdBinding(target.Name, into.IsConst, int(into.Idx)-1)
388 c.emit(enumGet)
389 b.emitInitP()
390 case ast.Pattern:
391 c.createLexicalBinding(target, into.IsConst)
392 c.emit(enumGet)
393 c.emitPattern(target, func(target, init compiledExpr) {
394 c.emitPatternLexicalAssign(target, init)
395 }, false)
396 default:
397 c.assert(false, int(into.Idx)-1, "Unsupported ForBinding: %T", into.Target)
398 }
399 default:
400 c.assert(false, int(into.Idx0())-1, "Unsupported for-into: %T", into)
401 panic("unreachable")
402 }
403
404 return
405 }
406
407 func (c *compiler) compileLabeledForInOfStatement(into ast.ForInto, source ast.Expression, body ast.Statement, iter, needResult bool, label unistring.String) {
408 c.block = &block{
409 typ: blockLoopEnum,
410 outer: c.block,
411 label: label,
412 needResult: needResult,
413 }
414 enterPos := -1
415 if forDecl, ok := into.(*ast.ForDeclaration); ok {
416 c.block = &block{
417 typ: blockScope,
418 outer: c.block,
419 needResult: false,
420 }
421 c.newBlockScope()
422 enterPos = len(c.p.code)
423 c.emit(jump(1))
424 c.createLexicalBinding(forDecl.Target, forDecl.IsConst)
425 }
426 c.compileExpression(source).emitGetter(true)
427 if enterPos != -1 {
428 s := c.scope
429 used := len(c.block.breaks) > 0 || s.isDynamic()
430 if !used {
431 for _, b := range s.bindings {
432 if b.useCount() > 0 {
433 used = true
434 break
435 }
436 }
437 }
438 if used {
439
440
441 for _, b := range s.bindings {
442 b.moveToStash()
443 }
444 enter := &enterBlock{}
445 c.p.code[enterPos] = enter
446 c.leaveScopeBlock(enter)
447 } else {
448 c.block = c.block.outer
449 }
450 c.popScope()
451 }
452 if iter {
453 c.emit(iterateP)
454 } else {
455 c.emit(enumerate)
456 }
457 if needResult {
458 c.emit(clearResult)
459 }
460 start := len(c.p.code)
461 c.block.cont = start
462 c.emit(nil)
463 enterIterBlock := c.compileForInto(into, needResult)
464 if needResult {
465 c.emit(clearResult)
466 }
467 c.compileStatement(body, needResult)
468 if enterIterBlock != nil {
469 c.leaveScopeBlock(enterIterBlock)
470 c.popScope()
471 }
472 c.emit(jump(start - len(c.p.code)))
473 if iter {
474 c.p.code[start] = iterNext(len(c.p.code) - start)
475 } else {
476 c.p.code[start] = enumNext(len(c.p.code) - start)
477 }
478 c.emit(enumPop, jump(2))
479 c.leaveBlock()
480 c.emit(enumPopClose)
481 }
482
483 func (c *compiler) compileLabeledForInStatement(v *ast.ForInStatement, needResult bool, label unistring.String) {
484 c.compileLabeledForInOfStatement(v.Into, v.Source, v.Body, false, needResult, label)
485 }
486
487 func (c *compiler) compileForOfStatement(v *ast.ForOfStatement, needResult bool) {
488 c.compileLabeledForOfStatement(v, needResult, "")
489 }
490
491 func (c *compiler) compileLabeledForOfStatement(v *ast.ForOfStatement, needResult bool, label unistring.String) {
492 c.compileLabeledForInOfStatement(v.Into, v.Source, v.Body, true, needResult, label)
493 }
494
495 func (c *compiler) compileWhileStatement(v *ast.WhileStatement, needResult bool) {
496 c.compileLabeledWhileStatement(v, needResult, "")
497 }
498
499 func (c *compiler) compileLabeledWhileStatement(v *ast.WhileStatement, needResult bool, label unistring.String) {
500 c.block = &block{
501 typ: blockLoop,
502 outer: c.block,
503 label: label,
504 needResult: needResult,
505 }
506
507 if needResult {
508 c.emit(clearResult)
509 }
510 start := len(c.p.code)
511 c.block.cont = start
512 expr := c.compileExpression(v.Test)
513 testTrue := false
514 var j int
515 if expr.constant() {
516 if t, ex := c.evalConst(expr); ex == nil {
517 if t.ToBoolean() {
518 testTrue = true
519 } else {
520 c.compileStatementDummy(v.Body)
521 goto end
522 }
523 } else {
524 c.emitThrow(ex.val)
525 goto end
526 }
527 } else {
528 expr.emitGetter(true)
529 j = len(c.p.code)
530 c.emit(nil)
531 }
532 if needResult {
533 c.emit(clearResult)
534 }
535 c.compileStatement(v.Body, needResult)
536 c.emit(jump(start - len(c.p.code)))
537 if !testTrue {
538 c.p.code[j] = jne(len(c.p.code) - j)
539 }
540 end:
541 c.leaveBlock()
542 }
543
544 func (c *compiler) compileEmptyStatement(needResult bool) {
545 if needResult {
546 c.emit(clearResult)
547 }
548 }
549
550 func (c *compiler) compileBranchStatement(v *ast.BranchStatement) {
551 switch v.Token {
552 case token.BREAK:
553 c.compileBreak(v.Label, v.Idx)
554 case token.CONTINUE:
555 c.compileContinue(v.Label, v.Idx)
556 default:
557 c.assert(false, int(v.Idx0())-1, "Unknown branch statement token: %s", v.Token.String())
558 panic("unreachable")
559 }
560 }
561
562 func (c *compiler) findBranchBlock(st *ast.BranchStatement) *block {
563 switch st.Token {
564 case token.BREAK:
565 return c.findBreakBlock(st.Label, true)
566 case token.CONTINUE:
567 return c.findBreakBlock(st.Label, false)
568 }
569 return nil
570 }
571
572 func (c *compiler) findBreakBlock(label *ast.Identifier, isBreak bool) (res *block) {
573 if label != nil {
574 var found *block
575 for b := c.block; b != nil; b = b.outer {
576 if res == nil {
577 if bb := b.breaking; bb != nil {
578 res = bb
579 if isBreak {
580 return
581 }
582 }
583 }
584 if b.label == label.Name {
585 found = b
586 break
587 }
588 }
589 if !isBreak && found != nil && found.typ != blockLoop && found.typ != blockLoopEnum {
590 c.throwSyntaxError(int(label.Idx)-1, "Illegal continue statement: '%s' does not denote an iteration statement", label.Name)
591 }
592 if res == nil {
593 res = found
594 }
595 } else {
596
597 L:
598 for b := c.block; b != nil; b = b.outer {
599 if bb := b.breaking; bb != nil {
600 return bb
601 }
602 switch b.typ {
603 case blockLoop, blockLoopEnum:
604 res = b
605 break L
606 case blockSwitch:
607 if isBreak {
608 res = b
609 break L
610 }
611 }
612 }
613 }
614
615 return
616 }
617
618 func (c *compiler) emitBlockExitCode(label *ast.Identifier, idx file.Idx, isBreak bool) *block {
619 block := c.findBreakBlock(label, isBreak)
620 if block == nil {
621 c.throwSyntaxError(int(idx)-1, "Could not find block")
622 panic("unreachable")
623 }
624 contForLoop := !isBreak && block.typ == blockLoop
625 L:
626 for b := c.block; b != block; b = b.outer {
627 switch b.typ {
628 case blockIterScope:
629
630
631 if contForLoop && b.outer == block {
632 break L
633 }
634 fallthrough
635 case blockScope:
636 b.breaks = append(b.breaks, len(c.p.code))
637 c.emit(nil)
638 case blockTry:
639 c.emit(leaveTry{})
640 case blockWith:
641 c.emit(leaveWith)
642 case blockLoopEnum:
643 c.emit(enumPopClose)
644 }
645 }
646 return block
647 }
648
649 func (c *compiler) compileBreak(label *ast.Identifier, idx file.Idx) {
650 block := c.emitBlockExitCode(label, idx, true)
651 block.breaks = append(block.breaks, len(c.p.code))
652 c.emit(nil)
653 }
654
655 func (c *compiler) compileContinue(label *ast.Identifier, idx file.Idx) {
656 block := c.emitBlockExitCode(label, idx, false)
657 block.conts = append(block.conts, len(c.p.code))
658 c.emit(nil)
659 }
660
661 func (c *compiler) compileIfBody(s ast.Statement, needResult bool) {
662 if !c.scope.strict {
663 if s, ok := s.(*ast.FunctionDeclaration); ok && !s.Function.Async && !s.Function.Generator {
664 c.compileFunction(s)
665 if needResult {
666 c.emit(clearResult)
667 }
668 return
669 }
670 }
671 c.compileStatement(s, needResult)
672 }
673
674 func (c *compiler) compileIfBodyDummy(s ast.Statement) {
675 leave := c.enterDummyMode()
676 defer leave()
677 c.compileIfBody(s, false)
678 }
679
680 func (c *compiler) compileIfStatement(v *ast.IfStatement, needResult bool) {
681 test := c.compileExpression(v.Test)
682 if needResult {
683 c.emit(clearResult)
684 }
685 if test.constant() {
686 r, ex := c.evalConst(test)
687 if ex != nil {
688 test.addSrcMap()
689 c.emitThrow(ex.val)
690 return
691 }
692 if r.ToBoolean() {
693 c.compileIfBody(v.Consequent, needResult)
694 if v.Alternate != nil {
695 c.compileIfBodyDummy(v.Alternate)
696 }
697 } else {
698 c.compileIfBodyDummy(v.Consequent)
699 if v.Alternate != nil {
700 c.compileIfBody(v.Alternate, needResult)
701 } else {
702 if needResult {
703 c.emit(clearResult)
704 }
705 }
706 }
707 return
708 }
709 test.emitGetter(true)
710 jmp := len(c.p.code)
711 c.emit(nil)
712 c.compileIfBody(v.Consequent, needResult)
713 if v.Alternate != nil {
714 jmp1 := len(c.p.code)
715 c.emit(nil)
716 c.p.code[jmp] = jne(len(c.p.code) - jmp)
717 c.compileIfBody(v.Alternate, needResult)
718 c.p.code[jmp1] = jump(len(c.p.code) - jmp1)
719 } else {
720 if needResult {
721 c.emit(jump(2))
722 c.p.code[jmp] = jne(len(c.p.code) - jmp)
723 c.emit(clearResult)
724 } else {
725 c.p.code[jmp] = jne(len(c.p.code) - jmp)
726 }
727 }
728 }
729
730 func (c *compiler) compileReturnStatement(v *ast.ReturnStatement) {
731 if s := c.scope.nearestFunction(); s != nil && s.funcType == funcClsInit {
732 c.throwSyntaxError(int(v.Return)-1, "Illegal return statement")
733 }
734 if v.Argument != nil {
735 c.emitExpr(c.compileExpression(v.Argument), true)
736 } else {
737 c.emit(loadUndef)
738 }
739 for b := c.block; b != nil; b = b.outer {
740 switch b.typ {
741 case blockTry:
742 c.emit(leaveTry{})
743 case blockLoopEnum:
744 c.emit(enumPopClose)
745 }
746 }
747 if s := c.scope.nearestFunction(); s != nil && s.funcType == funcDerivedCtor {
748 b := s.boundNames[thisBindingName]
749 c.assert(b != nil, int(v.Return)-1, "Derived constructor, but no 'this' binding")
750 b.markAccessPoint()
751 }
752 c.emit(ret)
753 }
754
755 func (c *compiler) checkVarConflict(name unistring.String, offset int) {
756 for sc := c.scope; sc != nil; sc = sc.outer {
757 if b, exists := sc.boundNames[name]; exists && !b.isVar && !(b.isArg && sc != c.scope) {
758 c.throwSyntaxError(offset, "Identifier '%s' has already been declared", name)
759 }
760 if sc.isFunction() {
761 break
762 }
763 }
764 }
765
766 func (c *compiler) emitVarAssign(name unistring.String, offset int, init compiledExpr) {
767 c.checkVarConflict(name, offset)
768 if init != nil {
769 b, noDyn := c.scope.lookupName(name)
770 if noDyn {
771 c.emitNamedOrConst(init, name)
772 c.p.addSrcMap(offset)
773 b.emitInitP()
774 } else {
775 c.emitVarRef(name, offset, b)
776 c.emitNamedOrConst(init, name)
777 c.p.addSrcMap(offset)
778 c.emit(initValueP)
779 }
780 }
781 }
782
783 func (c *compiler) compileVarBinding(expr *ast.Binding) {
784 switch target := expr.Target.(type) {
785 case *ast.Identifier:
786 c.emitVarAssign(target.Name, int(target.Idx)-1, c.compileExpression(expr.Initializer))
787 case ast.Pattern:
788 c.compileExpression(expr.Initializer).emitGetter(true)
789 c.emitPattern(target, c.emitPatternVarAssign, false)
790 default:
791 c.throwSyntaxError(int(target.Idx0()-1), "unsupported variable binding target: %T", target)
792 }
793 }
794
795 func (c *compiler) emitLexicalAssign(name unistring.String, offset int, init compiledExpr) {
796 b := c.scope.boundNames[name]
797 c.assert(b != nil, offset, "Lexical declaration for an unbound name")
798 if init != nil {
799 c.emitNamedOrConst(init, name)
800 c.p.addSrcMap(offset)
801 } else {
802 if b.isConst {
803 c.throwSyntaxError(offset, "Missing initializer in const declaration")
804 }
805 c.emit(loadUndef)
806 }
807 b.emitInitP()
808 }
809
810 func (c *compiler) emitPatternVarAssign(target, init compiledExpr) {
811 id := target.(*compiledIdentifierExpr)
812 c.emitVarAssign(id.name, id.offset, init)
813 }
814
815 func (c *compiler) emitPatternLexicalAssign(target, init compiledExpr) {
816 id := target.(*compiledIdentifierExpr)
817 c.emitLexicalAssign(id.name, id.offset, init)
818 }
819
820 func (c *compiler) emitPatternAssign(target, init compiledExpr) {
821 if id, ok := target.(*compiledIdentifierExpr); ok {
822 b, noDyn := c.scope.lookupName(id.name)
823 if noDyn {
824 c.emitNamedOrConst(init, id.name)
825 b.emitSetP()
826 } else {
827 c.emitVarRef(id.name, id.offset, b)
828 c.emitNamedOrConst(init, id.name)
829 c.emit(putValueP)
830 }
831 } else {
832 target.emitRef()
833 c.emitExpr(init, true)
834 c.emit(putValueP)
835 }
836 }
837
838 func (c *compiler) compileLexicalBinding(expr *ast.Binding) {
839 switch target := expr.Target.(type) {
840 case *ast.Identifier:
841 c.emitLexicalAssign(target.Name, int(target.Idx)-1, c.compileExpression(expr.Initializer))
842 case ast.Pattern:
843 c.compileExpression(expr.Initializer).emitGetter(true)
844 c.emitPattern(target, func(target, init compiledExpr) {
845 c.emitPatternLexicalAssign(target, init)
846 }, false)
847 default:
848 c.throwSyntaxError(int(target.Idx0()-1), "unsupported lexical binding target: %T", target)
849 }
850 }
851
852 func (c *compiler) compileVariableStatement(v *ast.VariableStatement) {
853 for _, expr := range v.List {
854 c.compileVarBinding(expr)
855 }
856 }
857
858 func (c *compiler) compileLexicalDeclaration(v *ast.LexicalDeclaration) {
859 for _, e := range v.List {
860 c.compileLexicalBinding(e)
861 }
862 }
863
864 func (c *compiler) isEmptyResult(st ast.Statement) bool {
865 switch st := st.(type) {
866 case *ast.EmptyStatement, *ast.VariableStatement, *ast.LexicalDeclaration, *ast.FunctionDeclaration,
867 *ast.ClassDeclaration, *ast.BranchStatement, *ast.DebuggerStatement:
868 return true
869 case *ast.LabelledStatement:
870 return c.isEmptyResult(st.Statement)
871 case *ast.BlockStatement:
872 for _, s := range st.List {
873 if _, ok := s.(*ast.BranchStatement); ok {
874 return true
875 }
876 if !c.isEmptyResult(s) {
877 return false
878 }
879 }
880 return true
881 }
882 return false
883 }
884
885 func (c *compiler) scanStatements(list []ast.Statement) (lastProducingIdx int, breakingBlock *block) {
886 lastProducingIdx = -1
887 for i, st := range list {
888 if bs, ok := st.(*ast.BranchStatement); ok {
889 if blk := c.findBranchBlock(bs); blk != nil {
890 breakingBlock = blk
891 }
892 break
893 }
894 if !c.isEmptyResult(st) {
895 lastProducingIdx = i
896 }
897 }
898 return
899 }
900
901 func (c *compiler) compileStatementsNeedResult(list []ast.Statement, lastProducingIdx int) {
902 if lastProducingIdx >= 0 {
903 for _, st := range list[:lastProducingIdx] {
904 if _, ok := st.(*ast.FunctionDeclaration); ok {
905 continue
906 }
907 c.compileStatement(st, false)
908 }
909 c.compileStatement(list[lastProducingIdx], true)
910 }
911 var leave func()
912 defer func() {
913 if leave != nil {
914 leave()
915 }
916 }()
917 for _, st := range list[lastProducingIdx+1:] {
918 if _, ok := st.(*ast.FunctionDeclaration); ok {
919 continue
920 }
921 c.compileStatement(st, false)
922 if leave == nil {
923 if _, ok := st.(*ast.BranchStatement); ok {
924 leave = c.enterDummyMode()
925 }
926 }
927 }
928 }
929
930 func (c *compiler) compileStatements(list []ast.Statement, needResult bool) {
931 lastProducingIdx, blk := c.scanStatements(list)
932 if blk != nil {
933 needResult = blk.needResult
934 }
935 if needResult {
936 c.compileStatementsNeedResult(list, lastProducingIdx)
937 return
938 }
939 for _, st := range list {
940 if _, ok := st.(*ast.FunctionDeclaration); ok {
941 continue
942 }
943 c.compileStatement(st, false)
944 }
945 }
946
947 func (c *compiler) compileGenericLabeledStatement(v ast.Statement, needResult bool, label unistring.String) {
948 c.block = &block{
949 typ: blockLabel,
950 outer: c.block,
951 label: label,
952 needResult: needResult,
953 }
954 c.compileStatement(v, needResult)
955 c.leaveBlock()
956 }
957
958 func (c *compiler) compileBlockStatement(v *ast.BlockStatement, needResult bool) {
959 var scopeDeclared bool
960 funcs := c.extractFunctions(v.List)
961 if len(funcs) > 0 {
962 c.newBlockScope()
963 scopeDeclared = true
964 }
965 c.createFunctionBindings(funcs)
966 scopeDeclared = c.compileLexicalDeclarations(v.List, scopeDeclared)
967
968 var enter *enterBlock
969 if scopeDeclared {
970 c.block = &block{
971 outer: c.block,
972 typ: blockScope,
973 needResult: needResult,
974 }
975 enter = &enterBlock{}
976 c.emit(enter)
977 }
978 c.compileFunctions(funcs)
979 c.compileStatements(v.List, needResult)
980 if scopeDeclared {
981 c.leaveScopeBlock(enter)
982 c.popScope()
983 }
984 }
985
986 func (c *compiler) compileExpressionStatement(v *ast.ExpressionStatement, needResult bool) {
987 c.emitExpr(c.compileExpression(v.Expression), needResult)
988 if needResult {
989 c.emit(saveResult)
990 }
991 }
992
993 func (c *compiler) compileWithStatement(v *ast.WithStatement, needResult bool) {
994 if c.scope.strict {
995 c.throwSyntaxError(int(v.With)-1, "Strict mode code may not include a with statement")
996 return
997 }
998 c.compileExpression(v.Object).emitGetter(true)
999 c.emit(enterWith)
1000 c.block = &block{
1001 outer: c.block,
1002 typ: blockWith,
1003 needResult: needResult,
1004 }
1005 c.newBlockScope()
1006 c.scope.dynamic = true
1007 c.compileStatement(v.Body, needResult)
1008 c.emit(leaveWith)
1009 c.leaveBlock()
1010 c.popScope()
1011 }
1012
1013 func (c *compiler) compileSwitchStatement(v *ast.SwitchStatement, needResult bool) {
1014 c.block = &block{
1015 typ: blockSwitch,
1016 outer: c.block,
1017 needResult: needResult,
1018 }
1019
1020 c.compileExpression(v.Discriminant).emitGetter(true)
1021
1022 var funcs []*ast.FunctionDeclaration
1023 for _, s := range v.Body {
1024 f := c.extractFunctions(s.Consequent)
1025 funcs = append(funcs, f...)
1026 }
1027 var scopeDeclared bool
1028 if len(funcs) > 0 {
1029 c.newBlockScope()
1030 scopeDeclared = true
1031 c.createFunctionBindings(funcs)
1032 }
1033
1034 for _, s := range v.Body {
1035 scopeDeclared = c.compileLexicalDeclarations(s.Consequent, scopeDeclared)
1036 }
1037
1038 var enter *enterBlock
1039 var db *binding
1040 if scopeDeclared {
1041 c.block = &block{
1042 typ: blockScope,
1043 outer: c.block,
1044 needResult: needResult,
1045 }
1046 enter = &enterBlock{}
1047 c.emit(enter)
1048
1049 bindings := c.scope.bindings
1050 var bb []*binding
1051 if cap(bindings) == len(bindings) {
1052 bb = make([]*binding, len(bindings)+1)
1053 } else {
1054 bb = bindings[:len(bindings)+1]
1055 }
1056 copy(bb[1:], bindings)
1057 db = &binding{
1058 scope: c.scope,
1059 isConst: true,
1060 isStrict: true,
1061 }
1062 bb[0] = db
1063 c.scope.bindings = bb
1064 }
1065
1066 c.compileFunctions(funcs)
1067
1068 if needResult {
1069 c.emit(clearResult)
1070 }
1071
1072 jumps := make([]int, len(v.Body))
1073
1074 for i, s := range v.Body {
1075 if s.Test != nil {
1076 if db != nil {
1077 db.emitGet()
1078 } else {
1079 c.emit(dup)
1080 }
1081 c.compileExpression(s.Test).emitGetter(true)
1082 c.emit(op_strict_eq)
1083 if db != nil {
1084 c.emit(jne(2))
1085 } else {
1086 c.emit(jne(3), pop)
1087 }
1088 jumps[i] = len(c.p.code)
1089 c.emit(nil)
1090 }
1091 }
1092
1093 if db == nil {
1094 c.emit(pop)
1095 }
1096 jumpNoMatch := -1
1097 if v.Default != -1 {
1098 if v.Default != 0 {
1099 jumps[v.Default] = len(c.p.code)
1100 c.emit(nil)
1101 }
1102 } else {
1103 jumpNoMatch = len(c.p.code)
1104 c.emit(nil)
1105 }
1106
1107 for i, s := range v.Body {
1108 if s.Test != nil || i != 0 {
1109 c.p.code[jumps[i]] = jump(len(c.p.code) - jumps[i])
1110 }
1111 c.compileStatements(s.Consequent, needResult)
1112 }
1113
1114 if jumpNoMatch != -1 {
1115 c.p.code[jumpNoMatch] = jump(len(c.p.code) - jumpNoMatch)
1116 }
1117 if enter != nil {
1118 c.leaveScopeBlock(enter)
1119 enter.stackSize--
1120 c.popScope()
1121 }
1122 c.leaveBlock()
1123 }
1124
1125 func (c *compiler) compileClassDeclaration(v *ast.ClassDeclaration) {
1126 c.emitLexicalAssign(v.Class.Name.Name, int(v.Class.Class)-1, c.compileClassLiteral(v.Class, false))
1127 }
1128
View as plain text