@@ -312,7 +312,7 @@ func do_MAP_ADD(vm *Vm, i int32) {
312
312
313
313
// Returns with TOS to the caller of the function.
314
314
func do_RETURN_VALUE (vm * Vm , arg int32 ) {
315
- vm .exit = true
315
+ vm .PopFrame ()
316
316
}
317
317
318
318
// Pops TOS and delegates to it as a subiterator from a generator.
@@ -400,7 +400,7 @@ func do_WITH_CLEANUP(vm *Vm, arg int32) {
400
400
// co_names of the code object. The compiler tries to use STORE_FAST
401
401
// or STORE_GLOBAL if possible.
402
402
func do_STORE_NAME (vm * Vm , namei int32 ) {
403
- vm .locals [vm .co .Names [namei ]] = vm .POP ()
403
+ vm .frame . Locals [vm .frame . Code .Names [namei ]] = vm .POP ()
404
404
}
405
405
406
406
// Implements del name, where namei is the index into co_names
@@ -438,13 +438,13 @@ func do_DELETE_GLOBAL(vm *Vm, namei int32) {
438
438
439
439
// Pushes co_consts[consti] onto the stack.
440
440
func do_LOAD_CONST (vm * Vm , consti int32 ) {
441
- vm .PUSH (vm .co .Consts [consti ])
441
+ vm .PUSH (vm .frame . Code .Consts [consti ])
442
442
// fmt.Printf("LOAD_CONST %v\n", vm.TOP())
443
443
}
444
444
445
445
// Pushes the value associated with co_names[namei] onto the stack.
446
446
func do_LOAD_NAME (vm * Vm , namei int32 ) {
447
- vm .PUSH (py .String (vm .co .Names [namei ]))
447
+ vm .PUSH (py .String (vm .frame . Code .Names [namei ]))
448
448
}
449
449
450
450
// Creates a tuple consuming count items from the stack, and pushes
@@ -539,7 +539,7 @@ func do_FOR_ITER(vm *Vm, delta int32) {
539
539
// Loads the global named co_names[namei] onto the stack.
540
540
func do_LOAD_GLOBAL (vm * Vm , namei int32 ) {
541
541
// FIXME this is looking in local scope too - is that correct?
542
- vm .PUSH (vm .lookup (vm .co .Names [namei ]))
542
+ vm .PUSH (vm .frame . Lookup (vm .frame . Code .Names [namei ]))
543
543
}
544
544
545
545
// Pushes a block for a loop onto the block stack. The block spans
@@ -568,12 +568,12 @@ func do_STORE_MAP(vm *Vm, arg int32) {
568
568
569
569
// Pushes a reference to the local co_varnames[var_num] onto the stack.
570
570
func do_LOAD_FAST (vm * Vm , var_num int32 ) {
571
- vm .PUSH (vm .locals [vm .co .Varnames [var_num ]])
571
+ vm .PUSH (vm .frame . Locals [vm .frame . Code .Varnames [var_num ]])
572
572
}
573
573
574
574
// Stores TOS into the local co_varnames[var_num].
575
575
func do_STORE_FAST (vm * Vm , var_num int32 ) {
576
- vm .locals [vm .co .Varnames [var_num ]] = vm .POP ()
576
+ vm .frame . Locals [vm .frame . Code .Varnames [var_num ]] = vm .POP ()
577
577
}
578
578
579
579
// Deletes local co_varnames[var_num].
@@ -633,8 +633,8 @@ func do_RAISE_VARARGS(vm *Vm, argc int32) {
633
633
// pushes the return value.
634
634
func do_CALL_FUNCTION (vm * Vm , argc int32 ) {
635
635
fmt .Printf ("Stack: %v\n " , vm .stack )
636
- fmt .Printf ("Locals: %v\n " , vm .locals )
637
- fmt .Printf ("Globals: %v\n " , vm .globals )
636
+ fmt .Printf ("Locals: %v\n " , vm .frame . Locals )
637
+ fmt .Printf ("Globals: %v\n " , vm .frame . Globals )
638
638
nargs := int (argc & 0xFF )
639
639
nkwargs := int ((argc >> 8 ) & 0xFF )
640
640
p , q := len (vm .stack )- 2 * nkwargs , len (vm .stack )
@@ -643,9 +643,9 @@ func do_CALL_FUNCTION(vm *Vm, argc int32) {
643
643
args := py .Tuple (vm .stack [p :q ])
644
644
p , q = p - 1 , p
645
645
fn := vm .stack [p ]
646
- vm .stack [p ] = vm .call (fn , args , kwargs )
647
- // Drop the args off the stack
646
+ // Drop everything off the stack
648
647
vm .stack = vm .stack [:q ]
648
+ vm .Call (fn , args , kwargs )
649
649
}
650
650
651
651
// Pushes a new function object on the stack. TOS is the code
@@ -659,7 +659,7 @@ func do_MAKE_FUNCTION(vm *Vm, argc int32) {
659
659
num_annotations := (argc >> 16 ) & 0x7fff
660
660
qualname := vm .POP ()
661
661
code := vm .POP ()
662
- function := py .NewFunction (code .(* py.Code ), vm .globals , string (qualname .(py.String )))
662
+ function := py .NewFunction (code .(* py.Code ), vm .frame . Globals , string (qualname .(py.String )))
663
663
664
664
// FIXME share code with MAKE_CLOSURE
665
665
// if opcode == MAKE_CLOSURE {
@@ -756,17 +756,80 @@ func (vm *Vm) NotImplemented(name string, arg int32) {
756
756
fmt .Printf ("%s %d NOT IMPLEMENTED\n " , name , arg )
757
757
}
758
758
759
- // Poke the vm.Run into py
760
- func init () {
761
- py .VmRun = Run
759
+ // Calls function fn with args and kwargs
760
+ //
761
+ // fn can be a string in which case it will be looked up or another callable type
762
+ //
763
+ // kwargs is a sequence of name, value pairs
764
+ //
765
+ // The result is put on the stack
766
+ func (vm * Vm ) Call (fnObj py.Object , args []py.Object , kwargs []py.Object ) {
767
+ fmt .Printf ("Call %T %v with args = %v, kwargs = %v\n " , fnObj , fnObj , args , kwargs )
768
+ var kwargsd py.StringDict
769
+ if len (kwargs ) > 0 {
770
+ // Convert kwargs into dictionary
771
+ if len (kwargs )% 2 != 0 {
772
+ panic ("Odd length kwargs" )
773
+ }
774
+ kwargsd = py .NewStringDict ()
775
+ for i := 0 ; i < len (kwargs ); i += 2 {
776
+ kwargsd [string (kwargs [i ].(py.String ))] = kwargs [i + 1 ]
777
+ }
778
+ }
779
+ try_again:
780
+ switch fn := fnObj .(type ) {
781
+ case py.String :
782
+ fnObj = vm .frame .Lookup (string (fn ))
783
+ goto try_again
784
+ case * py.Method :
785
+ self := py .None // FIXME should be the module
786
+ if kwargsd != nil {
787
+ vm .PUSH (fn .CallWithKeywords (self , args , kwargsd ))
788
+ } else {
789
+ vm .PUSH (fn .Call (self , args ))
790
+ }
791
+ case * py.Function :
792
+ var locals py.StringDict
793
+ if kwargsd != nil {
794
+ locals = fn .LocalsForCallWithKeywords (args , kwargsd )
795
+ } else {
796
+ locals = fn .LocalsForCall (args )
797
+ }
798
+ vm .PushFrame (vm .frame .Globals , locals , fn .Code )
799
+ default :
800
+ // FIXME should be TypeError
801
+ panic (fmt .Sprintf ("TypeError: '%s' object is not callable" , fnObj .Type ().Name ))
802
+ }
803
+ }
804
+
805
+ // Make a new Frame with globals, locals and Code on the frames stack
806
+ func (vm * Vm ) PushFrame (globals , locals py.StringDict , code * py.Code ) {
807
+ frame := py.Frame {
808
+ Globals : globals ,
809
+ Locals : locals ,
810
+ Code : code ,
811
+ Builtins : py .Builtins .Globals ,
812
+ }
813
+ vm .frames = append (vm .frames , frame )
814
+ vm .frame = & frame
815
+ }
816
+
817
+ // Drop the current frame
818
+ func (vm * Vm ) PopFrame () {
819
+ vm .frames = vm .frames [:len (vm .frames )- 1 ]
820
+ if len (vm .frames ) > 0 {
821
+ vm .frame = & vm .frames [len (vm .frames )- 1 ]
822
+ } else {
823
+ vm .frame = nil
824
+ }
762
825
}
763
826
764
827
// Run the virtual machine on the code object in the module
765
828
//
766
829
// FIXME figure out how we are going to signal exceptions!
767
830
//
768
831
// Any parameters are expected to have been decoded into locals
769
- func Run (globals , locals py.StringDict , co * py.Code ) (err error ) {
832
+ func Run (globals , locals py.StringDict , code * py.Code ) (err error ) {
770
833
defer func () {
771
834
if r := recover (); r != nil {
772
835
switch x := r .(type ) {
@@ -779,25 +842,21 @@ func Run(globals, locals py.StringDict, co *py.Code) (err error) {
779
842
}
780
843
}
781
844
}()
782
- _vm := Vm {
783
- stack : make ([]py.Object , 0 , 16 ),
784
- globals : globals ,
785
- locals : locals ,
786
- co : co ,
787
- }
788
- vm := & _vm
789
- ip := 0
845
+ vm := NewVm ()
846
+ vm .PushFrame (globals , locals , code )
847
+
790
848
var opcode byte
791
849
var arg int32
792
- code := co .Code
793
- for ! vm .exit {
794
- opcode = code [ip ]
795
- ip ++
850
+ for vm .frame != nil {
851
+ frame := vm .frame
852
+ opcodes := frame .Code .Code
853
+ opcode = opcodes [frame .Lasti ]
854
+ frame .Lasti ++
796
855
if HAS_ARG (opcode ) {
797
- arg = int32 (code [ ip ])
798
- ip ++
799
- arg += int32 (code [ ip ] << 8 )
800
- ip ++
856
+ arg = int32 (opcodes [ frame . Lasti ])
857
+ frame . Lasti ++
858
+ arg += int32 (opcodes [ frame . Lasti ] << 8 )
859
+ frame . Lasti ++
801
860
if vm .extended {
802
861
arg += vm .ext << 16
803
862
}
0 commit comments