@@ -19,6 +19,7 @@ import (
19
19
"github.com/ncw/gpython/marshal"
20
20
"github.com/ncw/gpython/parser"
21
21
"github.com/ncw/gpython/py"
22
+ "github.com/ncw/gpython/symtable"
22
23
"github.com/ncw/gpython/vm"
23
24
)
24
25
@@ -91,25 +92,37 @@ sys.stdout.close()`,
91
92
// the effects of any future statements in effect in the code calling
92
93
// compile; if absent or zero these statements do influence the compilation,
93
94
// in addition to any features explicitly specified.
94
- func Compile (str , filename , mode string , flags int , dont_inherit bool ) py.Object {
95
+ func Compile (str , filename , mode string , flags int , dont_inherit bool ) (py.Object , error ) {
96
+ // Parse Ast
95
97
Ast , err := parser .ParseString (str , mode )
96
98
if err != nil {
97
- panic ( err ) // FIXME error handling!
99
+ return nil , err
98
100
}
99
- return CompileAst (Ast , filename , flags , dont_inherit )
101
+ // Make symbol table
102
+ SymTable , err := symtable .NewSymTable (Ast )
103
+ if err != nil {
104
+ return nil , err
105
+ }
106
+ return CompileAst (Ast , filename , flags , dont_inherit , SymTable )
100
107
}
101
108
102
109
// As Compile but takes an Ast
103
- func CompileAst (Ast ast.Ast , filename string , flags int , dont_inherit bool ) * py.Code {
110
+ func CompileAst (Ast ast.Ast , filename string , flags int , dont_inherit bool , SymTable * symtable.SymTable ) (code * py.Code , err error ) {
111
+ defer func () {
112
+ if r := recover (); r != nil {
113
+ err = py .MakeException (r )
114
+ }
115
+ }()
104
116
//fmt.Println(ast.Dump(Ast))
105
- code : = & py.Code {
117
+ code = & py.Code {
106
118
Filename : filename ,
107
119
Firstlineno : 1 , // FIXME
108
120
Name : "<module>" , // FIXME
109
121
Flags : int32 (flags | py .CO_NOFREE ), // FIXME
110
122
}
111
123
c := & compiler {
112
- Code : code ,
124
+ Code : code ,
125
+ SymTable : SymTable ,
113
126
}
114
127
valueOnStack := false
115
128
switch node := Ast .(type ) {
@@ -143,7 +156,7 @@ func CompileAst(Ast ast.Ast, filename string, flags int, dont_inherit bool) *py.
143
156
}
144
157
code .Code = c .OpCodes .Assemble ()
145
158
code .Stacksize = int32 (c .OpCodes .StackDepth ())
146
- return code
159
+ return code , nil
147
160
}
148
161
149
162
// Loop
@@ -176,15 +189,17 @@ func (ls loopstack) Top() *loop {
176
189
177
190
// State for the compiler
178
191
type compiler struct {
179
- Code * py.Code // code being built up
180
- OpCodes Instructions
181
- loops loopstack
192
+ Code * py.Code // code being built up
193
+ OpCodes Instructions
194
+ loops loopstack
195
+ SymTable * symtable.SymTable
182
196
}
183
197
184
198
// Compiles a python constant
185
199
//
186
200
// Returns the index into the Consts tuple
187
201
func (c * compiler ) Const (obj py.Object ) uint32 {
202
+ // FIXME back this with a dict to stop O(N**2) behaviour on lots of consts
188
203
for i , c := range c .Code .Consts {
189
204
if obj .Type () == c .Type () && py .Eq (obj , c ) == py .True {
190
205
return uint32 (i )
@@ -199,19 +214,25 @@ func (c *compiler) LoadConst(obj py.Object) {
199
214
c .OpArg (vm .LOAD_CONST , c .Const (obj ))
200
215
}
201
216
202
- // Compiles a python name
203
- //
204
- // Returns the index into the Name tuple
205
- func (c * compiler ) Name (Id ast.Identifier ) uint32 {
206
- for i , s := range c .Code .Names {
207
- if string (Id ) == s {
217
+ // Returns the index into the slice provided, updating the slice if necessary
218
+ func (c * compiler ) Index (Id string , Names * []string ) uint32 {
219
+ // FIXME back this with a dict to stop O(N**2) behaviour on lots of vars
220
+ for i , s := range * Names {
221
+ if Id == s {
208
222
return uint32 (i )
209
223
}
210
224
}
211
- c . Code . Names = append (c . Code . Names , string ( Id ) )
225
+ * Names = append (* Names , Id )
212
226
return uint32 (len (c .Code .Names ) - 1 )
213
227
}
214
228
229
+ // Compiles a python name
230
+ //
231
+ // Returns the index into the Name tuple
232
+ func (c * compiler ) Name (Id ast.Identifier ) uint32 {
233
+ return c .Index (string (Id ), & c .Code .Names )
234
+ }
235
+
215
236
// Compiles an instruction with an argument
216
237
func (c * compiler ) OpArg (Op byte , Arg uint32 ) {
217
238
if ! vm .HAS_ARG (Op ) {
@@ -268,7 +289,14 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
268
289
// Body []Stmt
269
290
// DecoratorList []Expr
270
291
// Returns Expr
271
- code := CompileAst (node , c .Code .Filename , int (c .Code .Flags )| py .CO_OPTIMIZED | py .CO_NEWLOCALS , false ) // FIXME pass on compile args
292
+ newSymTable := c .SymTable .FindChild (stmt )
293
+ if newSymTable == nil {
294
+ panic ("No symtable found for function" )
295
+ }
296
+ code , err := CompileAst (node , c .Code .Filename , int (c .Code .Flags )| py .CO_OPTIMIZED | py .CO_NEWLOCALS , false , newSymTable ) // FIXME pass on compile args
297
+ if err != nil {
298
+ panic (err )
299
+ }
272
300
code .Argcount = int32 (len (node .Args .Args ))
273
301
code .Name = string (node .Name )
274
302
code .Kwonlyargcount = int32 (len (node .Args .Kwonlyargs ))
@@ -555,6 +583,129 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
555
583
}
556
584
}
557
585
586
+ // Compile a NameOp
587
+ func (c * compiler ) NameOp (name string , ctx ast.ExprContext ) {
588
+ // int op, scope;
589
+ // Py_ssize_t arg;
590
+ const (
591
+ OP_FAST = iota
592
+ OP_GLOBAL
593
+ OP_DEREF
594
+ OP_NAME
595
+ )
596
+
597
+ dict := & c .Code .Names
598
+ // PyObject *mangled;
599
+ /* XXX AugStore isn't used anywhere! */
600
+
601
+ // FIXME mangled = _Py_Mangle(c->u->u_private, name);
602
+ mangled := name
603
+
604
+ if name == "None" || name == "True" || name == "False" {
605
+ panic ("NameOp: Can't compile None, True or False" )
606
+ }
607
+
608
+ op := byte (0 )
609
+ optype := OP_NAME
610
+ scope := c .SymTable .GetScope (mangled )
611
+ switch scope {
612
+ case symtable .ScopeFree :
613
+ dict = & c .Code .Freevars
614
+ optype = OP_DEREF
615
+ case symtable .ScopeCell :
616
+ dict = & c .Code .Cellvars
617
+ optype = OP_DEREF
618
+ case symtable .ScopeLocal :
619
+ if c .SymTable .Type == symtable .FunctionBlock {
620
+ optype = OP_FAST
621
+ }
622
+ case symtable .ScopeGlobalImplicit :
623
+ if c .SymTable .Type == symtable .FunctionBlock && c .SymTable .Unoptimized == 0 {
624
+ optype = OP_GLOBAL
625
+ }
626
+ case symtable .ScopeGlobalExplicit :
627
+ optype = OP_GLOBAL
628
+ default :
629
+ panic (fmt .Sprintf ("NameOp: Invalid scope %v for %q" , scope , mangled ))
630
+ }
631
+
632
+ /* XXX Leave assert here, but handle __doc__ and the like better */
633
+ // FIXME assert(scope || PyUnicode_READ_CHAR(name, 0) == '_')
634
+
635
+ switch optype {
636
+ case OP_DEREF :
637
+ switch ctx {
638
+ case ast .Load :
639
+ if c .SymTable .Type == symtable .ClassBlock {
640
+ op = vm .LOAD_CLASSDEREF
641
+ } else {
642
+ op = vm .LOAD_DEREF
643
+ }
644
+ case ast .Store :
645
+ op = vm .STORE_DEREF
646
+ case ast .AugLoad :
647
+ case ast .AugStore :
648
+ case ast .Del :
649
+ op = vm .DELETE_DEREF
650
+ case ast .Param :
651
+ panic ("NameOp: param invalid for deref variable" )
652
+ default :
653
+ panic ("NameOp: ctx invalid for deref variable" )
654
+ }
655
+ case OP_FAST :
656
+ switch ctx {
657
+ case ast .Load :
658
+ op = vm .LOAD_FAST
659
+ case ast .Store :
660
+ op = vm .STORE_FAST
661
+ case ast .Del :
662
+ op = vm .DELETE_FAST
663
+ case ast .AugLoad :
664
+ case ast .AugStore :
665
+ case ast .Param :
666
+ panic ("NameOp: param invalid for local variable" )
667
+ default :
668
+ panic ("NameOp: ctx invalid for local variable" )
669
+ }
670
+ dict = & c .Code .Varnames
671
+ case OP_GLOBAL :
672
+ switch ctx {
673
+ case ast .Load :
674
+ op = vm .LOAD_GLOBAL
675
+ case ast .Store :
676
+ op = vm .STORE_GLOBAL
677
+ case ast .Del :
678
+ op = vm .DELETE_GLOBAL
679
+ case ast .AugLoad :
680
+ case ast .AugStore :
681
+ case ast .Param :
682
+ panic ("NameOp: param invalid for global variable" )
683
+ default :
684
+ panic ("NameOp: ctx invalid for global variable" )
685
+ }
686
+ case OP_NAME :
687
+ switch ctx {
688
+ case ast .Load :
689
+ op = vm .LOAD_NAME
690
+ case ast .Store :
691
+ op = vm .STORE_NAME
692
+ case ast .Del :
693
+ op = vm .DELETE_NAME
694
+ case ast .AugLoad :
695
+ case ast .AugStore :
696
+ case ast .Param :
697
+ panic ("NameOp: param invalid for name variable" )
698
+ default :
699
+ panic ("NameOp: ctx invalid for name variable" )
700
+ }
701
+ break
702
+ }
703
+ if op == 0 {
704
+ panic ("NameOp: Op not set" )
705
+ }
706
+ c .OpArg (op , c .Index (mangled , dict ))
707
+ }
708
+
558
709
// Compile expressions
559
710
func (c * compiler ) Expr (expr ast.Expr ) {
560
711
switch node := expr .(type ) {
@@ -636,7 +787,15 @@ func (c *compiler) Expr(expr ast.Expr) {
636
787
// Args *Arguments
637
788
// Body Expr
638
789
// newC := Compiler
639
- code := CompileAst (node .Body , c .Code .Filename , int (c .Code .Flags )| py .CO_OPTIMIZED | py .CO_NEWLOCALS , false ) // FIXME pass on compile args
790
+ newSymTable := c .SymTable .FindChild (expr )
791
+ if newSymTable == nil {
792
+ panic ("No symtable found for lambda" )
793
+ }
794
+ code , err := CompileAst (node .Body , c .Code .Filename , int (c .Code .Flags )| py .CO_OPTIMIZED | py .CO_NEWLOCALS , false , newSymTable ) // FIXME pass on compile args
795
+ if err != nil {
796
+ panic (err )
797
+ }
798
+
640
799
code .Argcount = int32 (len (node .Args .Args ))
641
800
c .LoadConst (code )
642
801
c .LoadConst (py .String ("<lambda>" ))
@@ -819,19 +978,7 @@ func (c *compiler) Expr(expr ast.Expr) {
819
978
case * ast.Name :
820
979
// Id Identifier
821
980
// Ctx ExprContext
822
- switch node .Ctx {
823
- case ast .Load :
824
- c .OpArg (vm .LOAD_NAME , c .Name (node .Id ))
825
- case ast .Store :
826
- c .OpArg (vm .STORE_NAME , c .Name (node .Id ))
827
- case ast .Del :
828
- c .OpArg (vm .DELETE_NAME , c .Name (node .Id ))
829
- // case ast.AugLoad:
830
- // case ast.AugStore:
831
- // case ast.Param:
832
- default :
833
- panic (fmt .Sprintf ("FIXME ast.Name Ctx=%v not implemented" , node .Ctx ))
834
- }
981
+ c .NameOp (string (node .Id ), node .Ctx )
835
982
case * ast.List :
836
983
// Elts []Expr
837
984
// Ctx ExprContext
0 commit comments