1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package compile
28
29 import (
30 "bytes"
31 "fmt"
32 "log"
33 "os"
34 "path/filepath"
35 "strconv"
36 "strings"
37 "sync"
38
39 "go.starlark.net/resolve"
40 "go.starlark.net/syntax"
41 )
42
43
44
45 var Disassemble = false
46
47 const debug = false
48
49
50 const Version = 13
51
52 type Opcode uint8
53
54
55
56
57
58
59 const (
60 NOP Opcode = iota
61
62
63 DUP
64 DUP2
65 POP
66 EXCH
67
68
69
70 LT
71 GT
72 GE
73 LE
74 EQL
75 NEQ
76
77
78
79 PLUS
80 MINUS
81 STAR
82 SLASH
83 SLASHSLASH
84 PERCENT
85 AMP
86 PIPE
87 CIRCUMFLEX
88 LTLT
89 GTGT
90
91 IN
92
93
94 UPLUS
95 UMINUS
96 TILDE
97
98 NONE
99 TRUE
100 FALSE
101 MANDATORY
102
103 ITERPUSH
104 ITERPOP
105 NOT
106 RETURN
107 SETINDEX
108 INDEX
109 SETDICT
110 SETDICTUNIQ
111 APPEND
112 SLICE
113 INPLACE_ADD
114 INPLACE_PIPE
115 MAKEDICT
116
117
118
119
120 JMP
121 CJMP
122 ITERJMP
123
124
125 CONSTANT
126 MAKETUPLE
127 MAKELIST
128 MAKEFUNC
129 LOAD
130 SETLOCAL
131 SETGLOBAL
132 LOCAL
133 FREE
134 FREECELL
135 LOCALCELL
136 SETLOCALCELL
137 GLOBAL
138 PREDECLARED
139 UNIVERSAL
140 ATTR
141 SETFIELD
142 UNPACK
143
144
145 CALL
146 CALL_VAR
147 CALL_KW
148 CALL_VAR_KW
149
150 OpcodeArgMin = JMP
151 OpcodeMax = CALL_VAR_KW
152 )
153
154
155
156 var opcodeNames = [...]string{
157 AMP: "amp",
158 APPEND: "append",
159 ATTR: "attr",
160 CALL: "call",
161 CALL_KW: "call_kw ",
162 CALL_VAR: "call_var",
163 CALL_VAR_KW: "call_var_kw",
164 CIRCUMFLEX: "circumflex",
165 CJMP: "cjmp",
166 CONSTANT: "constant",
167 DUP2: "dup2",
168 DUP: "dup",
169 EQL: "eql",
170 EXCH: "exch",
171 FALSE: "false",
172 FREE: "free",
173 FREECELL: "freecell",
174 GE: "ge",
175 GLOBAL: "global",
176 GT: "gt",
177 GTGT: "gtgt",
178 IN: "in",
179 INDEX: "index",
180 INPLACE_ADD: "inplace_add",
181 INPLACE_PIPE: "inplace_pipe",
182 ITERJMP: "iterjmp",
183 ITERPOP: "iterpop",
184 ITERPUSH: "iterpush",
185 JMP: "jmp",
186 LE: "le",
187 LOAD: "load",
188 LOCAL: "local",
189 LOCALCELL: "localcell",
190 LT: "lt",
191 LTLT: "ltlt",
192 MAKEDICT: "makedict",
193 MAKEFUNC: "makefunc",
194 MAKELIST: "makelist",
195 MAKETUPLE: "maketuple",
196 MANDATORY: "mandatory",
197 MINUS: "minus",
198 NEQ: "neq",
199 NONE: "none",
200 NOP: "nop",
201 NOT: "not",
202 PERCENT: "percent",
203 PIPE: "pipe",
204 PLUS: "plus",
205 POP: "pop",
206 PREDECLARED: "predeclared",
207 RETURN: "return",
208 SETDICT: "setdict",
209 SETDICTUNIQ: "setdictuniq",
210 SETFIELD: "setfield",
211 SETGLOBAL: "setglobal",
212 SETINDEX: "setindex",
213 SETLOCAL: "setlocal",
214 SETLOCALCELL: "setlocalcell",
215 SLASH: "slash",
216 SLASHSLASH: "slashslash",
217 SLICE: "slice",
218 STAR: "star",
219 TILDE: "tilde",
220 TRUE: "true",
221 UMINUS: "uminus",
222 UNIVERSAL: "universal",
223 UNPACK: "unpack",
224 UPLUS: "uplus",
225 }
226
227 const variableStackEffect = 0x7f
228
229
230
231 var stackEffect = [...]int8{
232 AMP: -1,
233 APPEND: -2,
234 ATTR: 0,
235 CALL: variableStackEffect,
236 CALL_KW: variableStackEffect,
237 CALL_VAR: variableStackEffect,
238 CALL_VAR_KW: variableStackEffect,
239 CIRCUMFLEX: -1,
240 CJMP: -1,
241 CONSTANT: +1,
242 DUP2: +2,
243 DUP: +1,
244 EQL: -1,
245 FALSE: +1,
246 FREE: +1,
247 FREECELL: +1,
248 GE: -1,
249 GLOBAL: +1,
250 GT: -1,
251 GTGT: -1,
252 IN: -1,
253 INDEX: -1,
254 INPLACE_ADD: -1,
255 INPLACE_PIPE: -1,
256 ITERJMP: variableStackEffect,
257 ITERPOP: 0,
258 ITERPUSH: -1,
259 JMP: 0,
260 LE: -1,
261 LOAD: -1,
262 LOCAL: +1,
263 LOCALCELL: +1,
264 LT: -1,
265 LTLT: -1,
266 MAKEDICT: +1,
267 MAKEFUNC: 0,
268 MAKELIST: variableStackEffect,
269 MAKETUPLE: variableStackEffect,
270 MANDATORY: +1,
271 MINUS: -1,
272 NEQ: -1,
273 NONE: +1,
274 NOP: 0,
275 NOT: 0,
276 PERCENT: -1,
277 PIPE: -1,
278 PLUS: -1,
279 POP: -1,
280 PREDECLARED: +1,
281 RETURN: -1,
282 SETLOCALCELL: -1,
283 SETDICT: -3,
284 SETDICTUNIQ: -3,
285 SETFIELD: -2,
286 SETGLOBAL: -1,
287 SETINDEX: -3,
288 SETLOCAL: -1,
289 SLASH: -1,
290 SLASHSLASH: -1,
291 SLICE: -3,
292 STAR: -1,
293 TRUE: +1,
294 UMINUS: 0,
295 UNIVERSAL: +1,
296 UNPACK: variableStackEffect,
297 UPLUS: 0,
298 }
299
300 func (op Opcode) String() string {
301 if op < OpcodeMax {
302 if name := opcodeNames[op]; name != "" {
303 return name
304 }
305 }
306 return fmt.Sprintf("illegal op (%d)", op)
307 }
308
309
310
311
312
313 type Program struct {
314 Loads []Binding
315 Names []string
316 Constants []interface{}
317 Functions []*Funcode
318 Globals []Binding
319 Toplevel *Funcode
320 }
321
322
323 type Bytes string
324
325
326
327
328
329 type Funcode struct {
330 Prog *Program
331 Pos syntax.Position
332 Name string
333 Doc string
334 Code []byte
335 pclinetab []uint16
336 Locals []Binding
337 Cells []int
338 Freevars []Binding
339 MaxStack int
340 NumParams int
341 NumKwonlyParams int
342 HasVarargs, HasKwargs bool
343
344
345
346 lntOnce sync.Once
347 lnt []pclinecol
348 }
349
350 type pclinecol struct {
351 pc uint32
352 line, col int32
353 }
354
355
356 type Binding struct {
357 Name string
358 Pos syntax.Position
359 }
360
361
362 type pcomp struct {
363 prog *Program
364
365 names map[string]uint32
366 constants map[interface{}]uint32
367 functions map[*Funcode]uint32
368 }
369
370
371 type fcomp struct {
372 fn *Funcode
373
374 pcomp *pcomp
375 pos syntax.Position
376 loops []loop
377 block *block
378 }
379
380 type loop struct {
381 break_, continue_ *block
382 }
383
384 type block struct {
385 insns []insn
386
387
388
389
390
391 jmp, cjmp *block
392
393 initialstack int
394
395
396 index int
397 addr uint32
398 }
399
400 type insn struct {
401 op Opcode
402 arg uint32
403 line, col int32
404 }
405
406
407 func (fn *Funcode) Position(pc uint32) syntax.Position {
408 fn.lntOnce.Do(fn.decodeLNT)
409
410
411
412
413
414 n := len(fn.lnt)
415 i, j := 0, n
416 for i < j {
417 h := int(uint(i+j) >> 1)
418 if !(h >= n-1 || fn.lnt[h+1].pc > pc) {
419 i = h + 1
420 } else {
421 j = h
422 }
423 }
424
425 var line, col int32
426 if i < n {
427 line = fn.lnt[i].line
428 col = fn.lnt[i].col
429 }
430
431 pos := fn.Pos
432 pos.Col = col
433 pos.Line = line
434 return pos
435 }
436
437
438
439 func (fn *Funcode) decodeLNT() {
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462 fn.lnt = make([]pclinecol, 0, len(fn.pclinetab))
463 entry := pclinecol{
464 pc: 0,
465 line: fn.Pos.Line,
466 col: fn.Pos.Col,
467 }
468 for _, x := range fn.pclinetab {
469 entry.pc += uint32(x) >> 12
470 entry.line += int32((int16(x) << 4) >> (16 - 5))
471 entry.col += int32((int16(x) << 9) >> (16 - 6))
472 if (x & 1) == 0 {
473 fn.lnt = append(fn.lnt, entry)
474 }
475 }
476 }
477
478
479 func bindings(bindings []*resolve.Binding) []Binding {
480 res := make([]Binding, len(bindings))
481 for i, bind := range bindings {
482 res[i].Name = bind.First.Name
483 res[i].Pos = bind.First.NamePos
484 }
485 return res
486 }
487
488
489 func Expr(expr syntax.Expr, name string, locals []*resolve.Binding) *Program {
490 pos := syntax.Start(expr)
491 stmts := []syntax.Stmt{&syntax.ReturnStmt{Result: expr}}
492 return File(stmts, pos, name, locals, nil)
493 }
494
495
496 func File(stmts []syntax.Stmt, pos syntax.Position, name string, locals, globals []*resolve.Binding) *Program {
497 pcomp := &pcomp{
498 prog: &Program{
499 Globals: bindings(globals),
500 },
501 names: make(map[string]uint32),
502 constants: make(map[interface{}]uint32),
503 functions: make(map[*Funcode]uint32),
504 }
505 pcomp.prog.Toplevel = pcomp.function(name, pos, stmts, locals, nil)
506
507 return pcomp.prog
508 }
509
510 func (pcomp *pcomp) function(name string, pos syntax.Position, stmts []syntax.Stmt, locals, freevars []*resolve.Binding) *Funcode {
511 fcomp := &fcomp{
512 pcomp: pcomp,
513 pos: pos,
514 fn: &Funcode{
515 Prog: pcomp.prog,
516 Pos: pos,
517 Name: name,
518 Doc: docStringFromBody(stmts),
519 Locals: bindings(locals),
520 Freevars: bindings(freevars),
521 },
522 }
523
524
525 for i, local := range locals {
526 if local.Scope == resolve.Cell {
527 fcomp.fn.Cells = append(fcomp.fn.Cells, i)
528 }
529 }
530
531 if debug {
532 fmt.Fprintf(os.Stderr, "start function(%s @ %s)\n", name, pos)
533 }
534
535
536 entry := fcomp.newBlock()
537 fcomp.block = entry
538 fcomp.stmts(stmts)
539 if fcomp.block != nil {
540 fcomp.emit(NONE)
541 fcomp.emit(RETURN)
542 }
543
544 var oops bool
545
546 setinitialstack := func(b *block, depth int) {
547 if b.initialstack == -1 {
548 b.initialstack = depth
549 } else if b.initialstack != depth {
550 fmt.Fprintf(os.Stderr, "%d: setinitialstack: depth mismatch: %d vs %d\n",
551 b.index, b.initialstack, depth)
552 oops = true
553 }
554 }
555
556
557
558
559 var pc uint32
560 var blocks []*block
561 var maxstack int
562 var visit func(b *block)
563 visit = func(b *block) {
564 if b.index >= 0 {
565 return
566 }
567 b.index = len(blocks)
568 b.addr = pc
569 blocks = append(blocks, b)
570
571 stack := b.initialstack
572 if debug {
573 fmt.Fprintf(os.Stderr, "%s block %d: (stack = %d)\n", name, b.index, stack)
574 }
575 var cjmpAddr *uint32
576 var isiterjmp int
577 for i, insn := range b.insns {
578 pc++
579
580
581 if insn.op >= OpcodeArgMin {
582 switch insn.op {
583 case ITERJMP:
584 isiterjmp = 1
585 fallthrough
586 case CJMP:
587 cjmpAddr = &b.insns[i].arg
588 pc += 4
589 default:
590 pc += uint32(argLen(insn.arg))
591 }
592 }
593
594
595 se := insn.stackeffect()
596 if debug {
597 fmt.Fprintln(os.Stderr, "\t", insn.op, stack, stack+se)
598 }
599 stack += se
600 if stack < 0 {
601 fmt.Fprintf(os.Stderr, "After pc=%d: stack underflow\n", pc)
602 oops = true
603 }
604 if stack+isiterjmp > maxstack {
605 maxstack = stack + isiterjmp
606 }
607 }
608
609 if debug {
610 fmt.Fprintf(os.Stderr, "successors of block %d (start=%d):\n",
611 b.addr, b.index)
612 if b.jmp != nil {
613 fmt.Fprintf(os.Stderr, "jmp to %d\n", b.jmp.index)
614 }
615 if b.cjmp != nil {
616 fmt.Fprintf(os.Stderr, "cjmp to %d\n", b.cjmp.index)
617 }
618 }
619
620
621 if b.jmp != nil {
622
623 for b.jmp.insns == nil {
624 b.jmp = b.jmp.jmp
625 }
626
627 setinitialstack(b.jmp, stack+isiterjmp)
628 if b.jmp.index < 0 {
629
630
631 visit(b.jmp)
632 } else {
633
634
635 pc += 5
636 }
637 }
638
639
640 if b.cjmp != nil {
641
642 for b.cjmp.insns == nil {
643 b.cjmp = b.cjmp.jmp
644 }
645
646 setinitialstack(b.cjmp, stack)
647 visit(b.cjmp)
648
649
650 if cjmpAddr != nil {
651 *cjmpAddr = b.cjmp.addr
652 }
653 }
654 }
655 setinitialstack(entry, 0)
656 visit(entry)
657
658 fn := fcomp.fn
659 fn.MaxStack = maxstack
660
661
662 if Disassemble {
663 fmt.Fprintf(os.Stderr, "Function %s: (%d blocks, %d bytes)\n", name, len(blocks), pc)
664 }
665 fcomp.generate(blocks, pc)
666
667 if debug {
668 fmt.Fprintf(os.Stderr, "code=%d maxstack=%d\n", fn.Code, fn.MaxStack)
669 }
670
671
672 if oops {
673 panic("internal error")
674 }
675
676 if debug {
677 fmt.Fprintf(os.Stderr, "end function(%s @ %s)\n", name, pos)
678 }
679
680 return fn
681 }
682
683 func docStringFromBody(body []syntax.Stmt) string {
684 if len(body) == 0 {
685 return ""
686 }
687 expr, ok := body[0].(*syntax.ExprStmt)
688 if !ok {
689 return ""
690 }
691 lit, ok := expr.X.(*syntax.Literal)
692 if !ok {
693 return ""
694 }
695 if lit.Token != syntax.STRING {
696 return ""
697 }
698 return lit.Value.(string)
699 }
700
701 func (insn *insn) stackeffect() int {
702 se := int(stackEffect[insn.op])
703 if se == variableStackEffect {
704 arg := int(insn.arg)
705 switch insn.op {
706 case CALL, CALL_KW, CALL_VAR, CALL_VAR_KW:
707 se = -int(2*(insn.arg&0xff) + insn.arg>>8)
708 if insn.op != CALL {
709 se--
710 }
711 if insn.op == CALL_VAR_KW {
712 se--
713 }
714 case ITERJMP:
715
716
717
718
719 se = 0
720 case MAKELIST, MAKETUPLE:
721 se = 1 - arg
722 case UNPACK:
723 se = arg - 1
724 default:
725 panic(insn.op)
726 }
727 }
728 return se
729 }
730
731
732
733 func (fcomp *fcomp) generate(blocks []*block, codelen uint32) {
734 code := make([]byte, 0, codelen)
735 var pclinetab []uint16
736 prev := pclinecol{
737 pc: 0,
738 line: fcomp.fn.Pos.Line,
739 col: fcomp.fn.Pos.Col,
740 }
741
742 for _, b := range blocks {
743 if Disassemble {
744 fmt.Fprintf(os.Stderr, "%d:\n", b.index)
745 }
746 pc := b.addr
747 for _, insn := range b.insns {
748 if insn.line != 0 {
749
750
751 for {
752 var incomplete uint16
753
754
755 deltapc := pc - prev.pc
756 if deltapc > 0x0f {
757 deltapc = 0x0f
758 incomplete = 1
759 }
760 prev.pc += deltapc
761
762
763 deltaline, ok := clip(insn.line-prev.line, -0x10, 0x0f)
764 if !ok {
765 incomplete = 1
766 }
767 prev.line += deltaline
768
769
770 deltacol, ok := clip(insn.col-prev.col, -0x20, 0x1f)
771 if !ok {
772 incomplete = 1
773 }
774 prev.col += deltacol
775
776 entry := uint16(deltapc<<12) | uint16(deltaline&0x1f)<<7 | uint16(deltacol&0x3f)<<1 | incomplete
777 pclinetab = append(pclinetab, entry)
778 if incomplete == 0 {
779 break
780 }
781 }
782
783 if Disassemble {
784 fmt.Fprintf(os.Stderr, "\t\t\t\t\t; %s:%d:%d\n",
785 filepath.Base(fcomp.fn.Pos.Filename()), insn.line, insn.col)
786 }
787 }
788 if Disassemble {
789 PrintOp(fcomp.fn, pc, insn.op, insn.arg)
790 }
791 code = append(code, byte(insn.op))
792 pc++
793 if insn.op >= OpcodeArgMin {
794 if insn.op == CJMP || insn.op == ITERJMP {
795 code = addUint32(code, insn.arg, 4)
796 } else {
797 code = addUint32(code, insn.arg, 0)
798 }
799 pc = uint32(len(code))
800 }
801 }
802
803 if b.jmp != nil && b.jmp.index != b.index+1 {
804 addr := b.jmp.addr
805 if Disassemble {
806 fmt.Fprintf(os.Stderr, "\t%d\tjmp\t\t%d\t; block %d\n",
807 pc, addr, b.jmp.index)
808 }
809 code = append(code, byte(JMP))
810 code = addUint32(code, addr, 4)
811 }
812 }
813 if len(code) != int(codelen) {
814 panic("internal error: wrong code length")
815 }
816
817 fcomp.fn.pclinetab = pclinetab
818 fcomp.fn.Code = code
819 }
820
821
822
823 func clip(x, min, max int32) (int32, bool) {
824 if x > max {
825 return max, false
826 } else if x < min {
827 return min, false
828 } else {
829 return x, true
830 }
831 }
832
833
834
835
836 func addUint32(code []byte, x uint32, min int) []byte {
837 end := len(code) + min
838 for x >= 0x80 {
839 code = append(code, byte(x)|0x80)
840 x >>= 7
841 }
842 code = append(code, byte(x))
843
844 for len(code) < end {
845 code = append(code, byte(NOP))
846 }
847 return code
848 }
849
850 func argLen(x uint32) int {
851 n := 0
852 for x >= 0x80 {
853 n++
854 x >>= 7
855 }
856 return n + 1
857 }
858
859
860
861 func PrintOp(fn *Funcode, pc uint32, op Opcode, arg uint32) {
862 if op < OpcodeArgMin {
863 fmt.Fprintf(os.Stderr, "\t%d\t%s\n", pc, op)
864 return
865 }
866
867 var comment string
868 switch op {
869 case CONSTANT:
870 switch x := fn.Prog.Constants[arg].(type) {
871 case string:
872 comment = strconv.Quote(x)
873 case Bytes:
874 comment = "b" + strconv.Quote(string(x))
875 default:
876 comment = fmt.Sprint(x)
877 }
878 case MAKEFUNC:
879 comment = fn.Prog.Functions[arg].Name
880 case SETLOCAL, LOCAL:
881 comment = fn.Locals[arg].Name
882 case SETGLOBAL, GLOBAL:
883 comment = fn.Prog.Globals[arg].Name
884 case ATTR, SETFIELD, PREDECLARED, UNIVERSAL:
885 comment = fn.Prog.Names[arg]
886 case FREE:
887 comment = fn.Freevars[arg].Name
888 case CALL, CALL_VAR, CALL_KW, CALL_VAR_KW:
889 comment = fmt.Sprintf("%d pos, %d named", arg>>8, arg&0xff)
890 default:
891
892
893 }
894 var buf bytes.Buffer
895 fmt.Fprintf(&buf, "\t%d\t%-10s\t%d", pc, op, arg)
896 if comment != "" {
897 fmt.Fprint(&buf, "\t; ", comment)
898 }
899 fmt.Fprintln(&buf)
900 os.Stderr.Write(buf.Bytes())
901 }
902
903
904 func (fcomp) newBlock() *block {
905 return &block{index: -1, initialstack: -1}
906 }
907
908
909 func (fcomp *fcomp) emit(op Opcode) {
910 if op >= OpcodeArgMin {
911 panic("missing arg: " + op.String())
912 }
913 insn := insn{op: op, line: fcomp.pos.Line, col: fcomp.pos.Col}
914 fcomp.block.insns = append(fcomp.block.insns, insn)
915 fcomp.pos.Line = 0
916 fcomp.pos.Col = 0
917 }
918
919
920 func (fcomp *fcomp) emit1(op Opcode, arg uint32) {
921 if op < OpcodeArgMin {
922 panic("unwanted arg: " + op.String())
923 }
924 insn := insn{op: op, arg: arg, line: fcomp.pos.Line, col: fcomp.pos.Col}
925 fcomp.block.insns = append(fcomp.block.insns, insn)
926 fcomp.pos.Line = 0
927 fcomp.pos.Col = 0
928 }
929
930
931
932 func (fcomp *fcomp) jump(b *block) {
933 if b == fcomp.block {
934 panic("self-jump")
935 }
936 fcomp.block.jmp = b
937 fcomp.block = nil
938 }
939
940
941
942
943
944 func (fcomp *fcomp) condjump(op Opcode, t, f *block) {
945 if !(op == CJMP || op == ITERJMP) {
946 panic("not a conditional jump: " + op.String())
947 }
948 fcomp.emit1(op, 0)
949 fcomp.block.cjmp = t
950 fcomp.jump(f)
951 }
952
953
954
955 func (pcomp *pcomp) nameIndex(name string) uint32 {
956 index, ok := pcomp.names[name]
957 if !ok {
958 index = uint32(len(pcomp.prog.Names))
959 pcomp.names[name] = index
960 pcomp.prog.Names = append(pcomp.prog.Names, name)
961 }
962 return index
963 }
964
965
966
967 func (pcomp *pcomp) constantIndex(v interface{}) uint32 {
968 index, ok := pcomp.constants[v]
969 if !ok {
970 index = uint32(len(pcomp.prog.Constants))
971 pcomp.constants[v] = index
972 pcomp.prog.Constants = append(pcomp.prog.Constants, v)
973 }
974 return index
975 }
976
977
978
979 func (pcomp *pcomp) functionIndex(fn *Funcode) uint32 {
980 index, ok := pcomp.functions[fn]
981 if !ok {
982 index = uint32(len(pcomp.prog.Functions))
983 pcomp.functions[fn] = index
984 pcomp.prog.Functions = append(pcomp.prog.Functions, fn)
985 }
986 return index
987 }
988
989
990 func (fcomp *fcomp) string(s string) {
991 fcomp.emit1(CONSTANT, fcomp.pcomp.constantIndex(s))
992 }
993
994
995
996
997 func (fcomp *fcomp) setPos(pos syntax.Position) {
998 fcomp.pos = pos
999 }
1000
1001
1002
1003 func (fcomp *fcomp) set(id *syntax.Ident) {
1004 bind := id.Binding.(*resolve.Binding)
1005 switch bind.Scope {
1006 case resolve.Local:
1007 fcomp.emit1(SETLOCAL, uint32(bind.Index))
1008 case resolve.Cell:
1009 fcomp.emit1(SETLOCALCELL, uint32(bind.Index))
1010 case resolve.Global:
1011 fcomp.emit1(SETGLOBAL, uint32(bind.Index))
1012 default:
1013 log.Panicf("%s: set(%s): not global/local/cell (%d)", id.NamePos, id.Name, bind.Scope)
1014 }
1015 }
1016
1017
1018 func (fcomp *fcomp) lookup(id *syntax.Ident) {
1019 bind := id.Binding.(*resolve.Binding)
1020 if bind.Scope != resolve.Universal {
1021 fcomp.setPos(id.NamePos)
1022 }
1023 switch bind.Scope {
1024 case resolve.Local:
1025 fcomp.emit1(LOCAL, uint32(bind.Index))
1026 case resolve.Free:
1027 fcomp.emit1(FREECELL, uint32(bind.Index))
1028 case resolve.Cell:
1029 fcomp.emit1(LOCALCELL, uint32(bind.Index))
1030 case resolve.Global:
1031 fcomp.emit1(GLOBAL, uint32(bind.Index))
1032 case resolve.Predeclared:
1033 fcomp.emit1(PREDECLARED, fcomp.pcomp.nameIndex(id.Name))
1034 case resolve.Universal:
1035 fcomp.emit1(UNIVERSAL, fcomp.pcomp.nameIndex(id.Name))
1036 default:
1037 log.Panicf("%s: compiler.lookup(%s): scope = %d", id.NamePos, id.Name, bind.Scope)
1038 }
1039 }
1040
1041 func (fcomp *fcomp) stmts(stmts []syntax.Stmt) {
1042 for _, stmt := range stmts {
1043 fcomp.stmt(stmt)
1044 }
1045 }
1046
1047 func (fcomp *fcomp) stmt(stmt syntax.Stmt) {
1048 switch stmt := stmt.(type) {
1049 case *syntax.ExprStmt:
1050 if _, ok := stmt.X.(*syntax.Literal); ok {
1051
1052 return
1053 }
1054 fcomp.expr(stmt.X)
1055 fcomp.emit(POP)
1056
1057 case *syntax.BranchStmt:
1058
1059 switch stmt.Token {
1060 case syntax.PASS:
1061
1062 case syntax.BREAK:
1063 b := fcomp.loops[len(fcomp.loops)-1].break_
1064 fcomp.jump(b)
1065 fcomp.block = fcomp.newBlock()
1066 case syntax.CONTINUE:
1067 b := fcomp.loops[len(fcomp.loops)-1].continue_
1068 fcomp.jump(b)
1069 fcomp.block = fcomp.newBlock()
1070 }
1071
1072 case *syntax.IfStmt:
1073
1074 t := fcomp.newBlock()
1075 f := fcomp.newBlock()
1076 done := fcomp.newBlock()
1077
1078 fcomp.ifelse(stmt.Cond, t, f)
1079
1080 fcomp.block = t
1081 fcomp.stmts(stmt.True)
1082 fcomp.jump(done)
1083
1084 fcomp.block = f
1085 fcomp.stmts(stmt.False)
1086 fcomp.jump(done)
1087
1088 fcomp.block = done
1089
1090 case *syntax.AssignStmt:
1091 switch stmt.Op {
1092 case syntax.EQ:
1093
1094 fcomp.expr(stmt.RHS)
1095 fcomp.assign(stmt.OpPos, stmt.LHS)
1096
1097 case syntax.PLUS_EQ,
1098 syntax.MINUS_EQ,
1099 syntax.STAR_EQ,
1100 syntax.SLASH_EQ,
1101 syntax.SLASHSLASH_EQ,
1102 syntax.PERCENT_EQ,
1103 syntax.AMP_EQ,
1104 syntax.PIPE_EQ,
1105 syntax.CIRCUMFLEX_EQ,
1106 syntax.LTLT_EQ,
1107 syntax.GTGT_EQ:
1108
1109
1110 var set func()
1111
1112
1113 switch lhs := unparen(stmt.LHS).(type) {
1114 case *syntax.Ident:
1115
1116 fcomp.lookup(lhs)
1117 set = func() {
1118 fcomp.set(lhs)
1119 }
1120
1121 case *syntax.IndexExpr:
1122
1123 fcomp.expr(lhs.X)
1124 fcomp.expr(lhs.Y)
1125 fcomp.emit(DUP2)
1126 fcomp.setPos(lhs.Lbrack)
1127 fcomp.emit(INDEX)
1128 set = func() {
1129 fcomp.setPos(lhs.Lbrack)
1130 fcomp.emit(SETINDEX)
1131 }
1132
1133 case *syntax.DotExpr:
1134
1135 fcomp.expr(lhs.X)
1136 fcomp.emit(DUP)
1137 name := fcomp.pcomp.nameIndex(lhs.Name.Name)
1138 fcomp.setPos(lhs.Dot)
1139 fcomp.emit1(ATTR, name)
1140 set = func() {
1141 fcomp.setPos(lhs.Dot)
1142 fcomp.emit1(SETFIELD, name)
1143 }
1144
1145 default:
1146 panic(lhs)
1147 }
1148
1149 fcomp.expr(stmt.RHS)
1150
1151
1152
1153 switch stmt.Op {
1154 case syntax.PLUS_EQ:
1155 fcomp.setPos(stmt.OpPos)
1156 fcomp.emit(INPLACE_ADD)
1157 case syntax.PIPE_EQ:
1158 fcomp.setPos(stmt.OpPos)
1159 fcomp.emit(INPLACE_PIPE)
1160 default:
1161 fcomp.binop(stmt.OpPos, stmt.Op-syntax.PLUS_EQ+syntax.PLUS)
1162 }
1163 set()
1164 }
1165
1166 case *syntax.DefStmt:
1167 fcomp.function(stmt.Function.(*resolve.Function))
1168 fcomp.set(stmt.Name)
1169
1170 case *syntax.ForStmt:
1171
1172 head := fcomp.newBlock()
1173 body := fcomp.newBlock()
1174 tail := fcomp.newBlock()
1175
1176 fcomp.expr(stmt.X)
1177 fcomp.setPos(stmt.For)
1178 fcomp.emit(ITERPUSH)
1179 fcomp.jump(head)
1180
1181 fcomp.block = head
1182 fcomp.condjump(ITERJMP, tail, body)
1183
1184 fcomp.block = body
1185 fcomp.assign(stmt.For, stmt.Vars)
1186 fcomp.loops = append(fcomp.loops, loop{break_: tail, continue_: head})
1187 fcomp.stmts(stmt.Body)
1188 fcomp.loops = fcomp.loops[:len(fcomp.loops)-1]
1189 fcomp.jump(head)
1190
1191 fcomp.block = tail
1192 fcomp.emit(ITERPOP)
1193
1194 case *syntax.WhileStmt:
1195 head := fcomp.newBlock()
1196 body := fcomp.newBlock()
1197 done := fcomp.newBlock()
1198
1199 fcomp.jump(head)
1200 fcomp.block = head
1201 fcomp.ifelse(stmt.Cond, body, done)
1202
1203 fcomp.block = body
1204 fcomp.loops = append(fcomp.loops, loop{break_: done, continue_: head})
1205 fcomp.stmts(stmt.Body)
1206 fcomp.loops = fcomp.loops[:len(fcomp.loops)-1]
1207 fcomp.jump(head)
1208
1209 fcomp.block = done
1210
1211 case *syntax.ReturnStmt:
1212 if stmt.Result != nil {
1213 fcomp.expr(stmt.Result)
1214 } else {
1215 fcomp.emit(NONE)
1216 }
1217 fcomp.emit(RETURN)
1218 fcomp.block = fcomp.newBlock()
1219
1220 case *syntax.LoadStmt:
1221 for i := range stmt.From {
1222 fcomp.string(stmt.From[i].Name)
1223 }
1224 module := stmt.Module.Value.(string)
1225 fcomp.pcomp.prog.Loads = append(fcomp.pcomp.prog.Loads, Binding{
1226 Name: module,
1227 Pos: stmt.Module.TokenPos,
1228 })
1229 fcomp.string(module)
1230 fcomp.setPos(stmt.Load)
1231 fcomp.emit1(LOAD, uint32(len(stmt.From)))
1232 for i := range stmt.To {
1233 fcomp.set(stmt.To[len(stmt.To)-1-i])
1234 }
1235
1236 default:
1237 start, _ := stmt.Span()
1238 log.Panicf("%s: exec: unexpected statement %T", start, stmt)
1239 }
1240 }
1241
1242
1243
1244 func (fcomp *fcomp) assign(pos syntax.Position, lhs syntax.Expr) {
1245 switch lhs := lhs.(type) {
1246 case *syntax.ParenExpr:
1247
1248 fcomp.assign(pos, lhs.X)
1249
1250 case *syntax.Ident:
1251
1252 fcomp.set(lhs)
1253
1254 case *syntax.TupleExpr:
1255
1256 fcomp.assignSequence(pos, lhs.List)
1257
1258 case *syntax.ListExpr:
1259
1260 fcomp.assignSequence(pos, lhs.List)
1261
1262 case *syntax.IndexExpr:
1263
1264 fcomp.expr(lhs.X)
1265 fcomp.emit(EXCH)
1266 fcomp.expr(lhs.Y)
1267 fcomp.emit(EXCH)
1268 fcomp.setPos(lhs.Lbrack)
1269 fcomp.emit(SETINDEX)
1270
1271 case *syntax.DotExpr:
1272
1273 fcomp.expr(lhs.X)
1274 fcomp.emit(EXCH)
1275 fcomp.setPos(lhs.Dot)
1276 fcomp.emit1(SETFIELD, fcomp.pcomp.nameIndex(lhs.Name.Name))
1277
1278 default:
1279 panic(lhs)
1280 }
1281 }
1282
1283 func (fcomp *fcomp) assignSequence(pos syntax.Position, lhs []syntax.Expr) {
1284 fcomp.setPos(pos)
1285 fcomp.emit1(UNPACK, uint32(len(lhs)))
1286 for i := range lhs {
1287 fcomp.assign(pos, lhs[i])
1288 }
1289 }
1290
1291 func (fcomp *fcomp) expr(e syntax.Expr) {
1292 switch e := e.(type) {
1293 case *syntax.ParenExpr:
1294 fcomp.expr(e.X)
1295
1296 case *syntax.Ident:
1297 fcomp.lookup(e)
1298
1299 case *syntax.Literal:
1300
1301 v := e.Value
1302 if e.Token == syntax.BYTES {
1303 v = Bytes(v.(string))
1304 }
1305 fcomp.emit1(CONSTANT, fcomp.pcomp.constantIndex(v))
1306
1307 case *syntax.ListExpr:
1308 for _, x := range e.List {
1309 fcomp.expr(x)
1310 }
1311 fcomp.emit1(MAKELIST, uint32(len(e.List)))
1312
1313 case *syntax.CondExpr:
1314
1315 t := fcomp.newBlock()
1316 f := fcomp.newBlock()
1317 done := fcomp.newBlock()
1318
1319 fcomp.ifelse(e.Cond, t, f)
1320
1321 fcomp.block = t
1322 fcomp.expr(e.True)
1323 fcomp.jump(done)
1324
1325 fcomp.block = f
1326 fcomp.expr(e.False)
1327 fcomp.jump(done)
1328
1329 fcomp.block = done
1330
1331 case *syntax.IndexExpr:
1332 fcomp.expr(e.X)
1333 fcomp.expr(e.Y)
1334 fcomp.setPos(e.Lbrack)
1335 fcomp.emit(INDEX)
1336
1337 case *syntax.SliceExpr:
1338 fcomp.setPos(e.Lbrack)
1339 fcomp.expr(e.X)
1340 if e.Lo != nil {
1341 fcomp.expr(e.Lo)
1342 } else {
1343 fcomp.emit(NONE)
1344 }
1345 if e.Hi != nil {
1346 fcomp.expr(e.Hi)
1347 } else {
1348 fcomp.emit(NONE)
1349 }
1350 if e.Step != nil {
1351 fcomp.expr(e.Step)
1352 } else {
1353 fcomp.emit(NONE)
1354 }
1355 fcomp.emit(SLICE)
1356
1357 case *syntax.Comprehension:
1358 if e.Curly {
1359 fcomp.emit(MAKEDICT)
1360 } else {
1361 fcomp.emit1(MAKELIST, 0)
1362 }
1363 fcomp.comprehension(e, 0)
1364
1365 case *syntax.TupleExpr:
1366 fcomp.tuple(e.List)
1367
1368 case *syntax.DictExpr:
1369 fcomp.emit(MAKEDICT)
1370 for _, entry := range e.List {
1371 entry := entry.(*syntax.DictEntry)
1372 fcomp.emit(DUP)
1373 fcomp.expr(entry.Key)
1374 fcomp.expr(entry.Value)
1375 fcomp.setPos(entry.Colon)
1376 fcomp.emit(SETDICTUNIQ)
1377 }
1378
1379 case *syntax.UnaryExpr:
1380 fcomp.expr(e.X)
1381 fcomp.setPos(e.OpPos)
1382 switch e.Op {
1383 case syntax.MINUS:
1384 fcomp.emit(UMINUS)
1385 case syntax.PLUS:
1386 fcomp.emit(UPLUS)
1387 case syntax.NOT:
1388 fcomp.emit(NOT)
1389 case syntax.TILDE:
1390 fcomp.emit(TILDE)
1391 default:
1392 log.Panicf("%s: unexpected unary op: %s", e.OpPos, e.Op)
1393 }
1394
1395 case *syntax.BinaryExpr:
1396 switch e.Op {
1397
1398
1399 case syntax.OR:
1400
1401 done := fcomp.newBlock()
1402 y := fcomp.newBlock()
1403
1404 fcomp.expr(e.X)
1405 fcomp.emit(DUP)
1406 fcomp.condjump(CJMP, done, y)
1407
1408 fcomp.block = y
1409 fcomp.emit(POP)
1410 fcomp.expr(e.Y)
1411 fcomp.jump(done)
1412
1413 fcomp.block = done
1414
1415 case syntax.AND:
1416
1417 done := fcomp.newBlock()
1418 y := fcomp.newBlock()
1419
1420 fcomp.expr(e.X)
1421 fcomp.emit(DUP)
1422 fcomp.condjump(CJMP, y, done)
1423
1424 fcomp.block = y
1425 fcomp.emit(POP)
1426 fcomp.expr(e.Y)
1427 fcomp.jump(done)
1428
1429 fcomp.block = done
1430
1431 case syntax.PLUS:
1432 fcomp.plus(e)
1433
1434 default:
1435
1436 fcomp.expr(e.X)
1437 fcomp.expr(e.Y)
1438 fcomp.binop(e.OpPos, e.Op)
1439 }
1440
1441 case *syntax.DotExpr:
1442 fcomp.expr(e.X)
1443 fcomp.setPos(e.Dot)
1444 fcomp.emit1(ATTR, fcomp.pcomp.nameIndex(e.Name.Name))
1445
1446 case *syntax.CallExpr:
1447 fcomp.call(e)
1448
1449 case *syntax.LambdaExpr:
1450 fcomp.function(e.Function.(*resolve.Function))
1451
1452 default:
1453 start, _ := e.Span()
1454 log.Panicf("%s: unexpected expr %T", start, e)
1455 }
1456 }
1457
1458 type summand struct {
1459 x syntax.Expr
1460 plusPos syntax.Position
1461 }
1462
1463
1464
1465
1466 func (fcomp *fcomp) plus(e *syntax.BinaryExpr) {
1467
1468
1469 args := make([]summand, 0, 2)
1470 for plus := e; ; {
1471 args = append(args, summand{unparen(plus.Y), plus.OpPos})
1472 left := unparen(plus.X)
1473 x, ok := left.(*syntax.BinaryExpr)
1474 if !ok || x.Op != syntax.PLUS {
1475 args = append(args, summand{x: left})
1476 break
1477 }
1478 plus = x
1479 }
1480
1481 for i, n := 0, len(args)/2; i < n; i++ {
1482 j := len(args) - 1 - i
1483 args[i], args[j] = args[j], args[i]
1484 }
1485
1486
1487 out := args[:0]
1488 for i := 0; i < len(args); {
1489 j := i + 1
1490 if code := addable(args[i].x); code != 0 {
1491 for j < len(args) && addable(args[j].x) == code {
1492 j++
1493 }
1494 if j > i+1 {
1495 args[i].x = add(code, args[i:j])
1496 }
1497 }
1498 out = append(out, args[i])
1499 i = j
1500 }
1501 args = out
1502
1503
1504 fcomp.expr(args[0].x)
1505 for _, summand := range args[1:] {
1506 fcomp.expr(summand.x)
1507 fcomp.setPos(summand.plusPos)
1508 fcomp.emit(PLUS)
1509 }
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540 }
1541
1542
1543
1544 func addable(e syntax.Expr) rune {
1545 switch e := e.(type) {
1546 case *syntax.Literal:
1547
1548 switch e.Token {
1549 case syntax.STRING:
1550 return 's'
1551 case syntax.BYTES:
1552 return 'b'
1553 }
1554 case *syntax.ListExpr:
1555 return 'l'
1556 case *syntax.TupleExpr:
1557 return 't'
1558 }
1559 return 0
1560 }
1561
1562
1563
1564
1565 func add(code rune, args []summand) syntax.Expr {
1566 switch code {
1567 case 's', 'b':
1568 var buf strings.Builder
1569 for _, arg := range args {
1570 buf.WriteString(arg.x.(*syntax.Literal).Value.(string))
1571 }
1572 tok := syntax.STRING
1573 if code == 'b' {
1574 tok = syntax.BYTES
1575 }
1576 return &syntax.Literal{Token: tok, Value: buf.String()}
1577 case 'l':
1578 var elems []syntax.Expr
1579 for _, arg := range args {
1580 elems = append(elems, arg.x.(*syntax.ListExpr).List...)
1581 }
1582 return &syntax.ListExpr{List: elems}
1583 case 't':
1584 var elems []syntax.Expr
1585 for _, arg := range args {
1586 elems = append(elems, arg.x.(*syntax.TupleExpr).List...)
1587 }
1588 return &syntax.TupleExpr{List: elems}
1589 }
1590 panic(code)
1591 }
1592
1593 func unparen(e syntax.Expr) syntax.Expr {
1594 if p, ok := e.(*syntax.ParenExpr); ok {
1595 return unparen(p.X)
1596 }
1597 return e
1598 }
1599
1600 func (fcomp *fcomp) binop(pos syntax.Position, op syntax.Token) {
1601
1602 fcomp.setPos(pos)
1603 switch op {
1604
1605 case syntax.PLUS:
1606 fcomp.emit(PLUS)
1607 case syntax.MINUS:
1608 fcomp.emit(MINUS)
1609 case syntax.STAR:
1610 fcomp.emit(STAR)
1611 case syntax.SLASH:
1612 fcomp.emit(SLASH)
1613 case syntax.SLASHSLASH:
1614 fcomp.emit(SLASHSLASH)
1615 case syntax.PERCENT:
1616 fcomp.emit(PERCENT)
1617 case syntax.AMP:
1618 fcomp.emit(AMP)
1619 case syntax.PIPE:
1620 fcomp.emit(PIPE)
1621 case syntax.CIRCUMFLEX:
1622 fcomp.emit(CIRCUMFLEX)
1623 case syntax.LTLT:
1624 fcomp.emit(LTLT)
1625 case syntax.GTGT:
1626 fcomp.emit(GTGT)
1627 case syntax.IN:
1628 fcomp.emit(IN)
1629 case syntax.NOT_IN:
1630 fcomp.emit(IN)
1631 fcomp.emit(NOT)
1632
1633
1634 case syntax.EQL,
1635 syntax.NEQ,
1636 syntax.GT,
1637 syntax.LT,
1638 syntax.LE,
1639 syntax.GE:
1640 fcomp.emit(Opcode(op-syntax.EQL) + EQL)
1641
1642 default:
1643 log.Panicf("%s: unexpected binary op: %s", pos, op)
1644 }
1645 }
1646
1647 func (fcomp *fcomp) call(call *syntax.CallExpr) {
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658 fcomp.expr(call.Fn)
1659 op, arg := fcomp.args(call)
1660 fcomp.setPos(call.Lparen)
1661 fcomp.emit1(op, arg)
1662 }
1663
1664
1665
1666
1667 func (fcomp *fcomp) args(call *syntax.CallExpr) (op Opcode, arg uint32) {
1668 var callmode int
1669
1670 var p, n int
1671 var varargs, kwargs syntax.Expr
1672 for _, arg := range call.Args {
1673 if binary, ok := arg.(*syntax.BinaryExpr); ok && binary.Op == syntax.EQ {
1674
1675
1676 fcomp.string(binary.X.(*syntax.Ident).Name)
1677 fcomp.expr(binary.Y)
1678 n++
1679 continue
1680 }
1681 if unary, ok := arg.(*syntax.UnaryExpr); ok {
1682 if unary.Op == syntax.STAR {
1683 callmode |= 1
1684 varargs = unary.X
1685 continue
1686 } else if unary.Op == syntax.STARSTAR {
1687 callmode |= 2
1688 kwargs = unary.X
1689 continue
1690 }
1691 }
1692
1693
1694 fcomp.expr(arg)
1695 p++
1696 }
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717 if varargs != nil {
1718 fcomp.expr(varargs)
1719 }
1720
1721
1722 if kwargs != nil {
1723 fcomp.expr(kwargs)
1724 }
1725
1726
1727 if p >= 256 || n >= 256 {
1728
1729 panic("too many arguments in call")
1730 }
1731
1732 return CALL + Opcode(callmode), uint32(p<<8 | n)
1733 }
1734
1735 func (fcomp *fcomp) tuple(elems []syntax.Expr) {
1736 for _, elem := range elems {
1737 fcomp.expr(elem)
1738 }
1739 fcomp.emit1(MAKETUPLE, uint32(len(elems)))
1740 }
1741
1742 func (fcomp *fcomp) comprehension(comp *syntax.Comprehension, clauseIndex int) {
1743 if clauseIndex == len(comp.Clauses) {
1744 fcomp.emit(DUP)
1745 if comp.Curly {
1746
1747
1748
1749
1750 entry := comp.Body.(*syntax.DictEntry)
1751 fcomp.expr(entry.Key)
1752 fcomp.expr(entry.Value)
1753 fcomp.setPos(entry.Colon)
1754 fcomp.emit(SETDICT)
1755 } else {
1756
1757 fcomp.expr(comp.Body)
1758 fcomp.emit(APPEND)
1759 }
1760 return
1761 }
1762
1763 clause := comp.Clauses[clauseIndex]
1764 switch clause := clause.(type) {
1765 case *syntax.IfClause:
1766 t := fcomp.newBlock()
1767 done := fcomp.newBlock()
1768 fcomp.ifelse(clause.Cond, t, done)
1769
1770 fcomp.block = t
1771 fcomp.comprehension(comp, clauseIndex+1)
1772 fcomp.jump(done)
1773
1774 fcomp.block = done
1775 return
1776
1777 case *syntax.ForClause:
1778
1779 head := fcomp.newBlock()
1780 body := fcomp.newBlock()
1781 tail := fcomp.newBlock()
1782
1783 fcomp.expr(clause.X)
1784 fcomp.setPos(clause.For)
1785 fcomp.emit(ITERPUSH)
1786 fcomp.jump(head)
1787
1788 fcomp.block = head
1789 fcomp.condjump(ITERJMP, tail, body)
1790
1791 fcomp.block = body
1792 fcomp.assign(clause.For, clause.Vars)
1793 fcomp.comprehension(comp, clauseIndex+1)
1794 fcomp.jump(head)
1795
1796 fcomp.block = tail
1797 fcomp.emit(ITERPOP)
1798 return
1799 }
1800
1801 start, _ := clause.Span()
1802 log.Panicf("%s: unexpected comprehension clause %T", start, clause)
1803 }
1804
1805 func (fcomp *fcomp) function(f *resolve.Function) {
1806
1807 fcomp.setPos(f.Pos)
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817 ndefaults := 0
1818 seenStar := false
1819 for _, param := range f.Params {
1820 switch param := param.(type) {
1821 case *syntax.BinaryExpr:
1822 fcomp.expr(param.Y)
1823 ndefaults++
1824 case *syntax.UnaryExpr:
1825 seenStar = true
1826 case *syntax.Ident:
1827 if seenStar {
1828 fcomp.emit(MANDATORY)
1829 ndefaults++
1830 }
1831 }
1832 }
1833
1834
1835
1836 for _, freevar := range f.FreeVars {
1837
1838
1839 switch freevar.Scope {
1840 case resolve.Free:
1841 fcomp.emit1(FREE, uint32(freevar.Index))
1842 case resolve.Cell:
1843 fcomp.emit1(LOCAL, uint32(freevar.Index))
1844 }
1845 }
1846
1847 fcomp.emit1(MAKETUPLE, uint32(ndefaults+len(f.FreeVars)))
1848
1849 funcode := fcomp.pcomp.function(f.Name, f.Pos, f.Body, f.Locals, f.FreeVars)
1850
1851 if debug {
1852
1853
1854
1855 fmt.Fprintf(os.Stderr, "resuming %s @ %s\n", fcomp.fn.Name, fcomp.pos)
1856 }
1857
1858
1859 numParams := len(f.Params)
1860 if f.NumKwonlyParams > 0 && !f.HasVarargs {
1861 numParams--
1862 }
1863
1864 funcode.NumParams = numParams
1865 funcode.NumKwonlyParams = f.NumKwonlyParams
1866 funcode.HasVarargs = f.HasVarargs
1867 funcode.HasKwargs = f.HasKwargs
1868 fcomp.emit1(MAKEFUNC, fcomp.pcomp.functionIndex(funcode))
1869 }
1870
1871
1872
1873 func (fcomp *fcomp) ifelse(cond syntax.Expr, t, f *block) {
1874 switch cond := cond.(type) {
1875 case *syntax.UnaryExpr:
1876 if cond.Op == syntax.NOT {
1877
1878
1879
1880 fcomp.ifelse(cond.X, f, t)
1881 return
1882 }
1883
1884 case *syntax.BinaryExpr:
1885 switch cond.Op {
1886 case syntax.AND:
1887
1888
1889
1890 fcomp.expr(cond.X)
1891 y := fcomp.newBlock()
1892 fcomp.condjump(CJMP, y, f)
1893
1894 fcomp.block = y
1895 fcomp.ifelse(cond.Y, t, f)
1896 return
1897
1898 case syntax.OR:
1899
1900
1901
1902 fcomp.expr(cond.X)
1903 y := fcomp.newBlock()
1904 fcomp.condjump(CJMP, t, y)
1905
1906 fcomp.block = y
1907 fcomp.ifelse(cond.Y, t, f)
1908 return
1909 case syntax.NOT_IN:
1910
1911
1912
1913 copy := *cond
1914 copy.Op = syntax.IN
1915 fcomp.expr(©)
1916 fcomp.condjump(CJMP, f, t)
1917 return
1918 }
1919 }
1920
1921
1922 fcomp.expr(cond)
1923 fcomp.condjump(CJMP, t, f)
1924 }
1925
View as plain text