@@ -19,6 +19,7 @@ import (
1919 "github.com/ncw/gpython/marshal"
2020 "github.com/ncw/gpython/parser"
2121 "github.com/ncw/gpython/py"
22+ "github.com/ncw/gpython/symtable"
2223 "github.com/ncw/gpython/vm"
2324)
2425
@@ -91,25 +92,37 @@ sys.stdout.close()`,
9192// the effects of any future statements in effect in the code calling
9293// compile; if absent or zero these statements do influence the compilation,
9394// 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
9597 Ast , err := parser .ParseString (str , mode )
9698 if err != nil {
97- panic ( err ) // FIXME error handling!
99+ return nil , err
98100 }
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 )
100107}
101108
102109// 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+ }()
104116 //fmt.Println(ast.Dump(Ast))
105- code : = & py.Code {
117+ code = & py.Code {
106118 Filename : filename ,
107119 Firstlineno : 1 , // FIXME
108120 Name : "<module>" , // FIXME
109121 Flags : int32 (flags | py .CO_NOFREE ), // FIXME
110122 }
111123 c := & compiler {
112- Code : code ,
124+ Code : code ,
125+ SymTable : SymTable ,
113126 }
114127 valueOnStack := false
115128 switch node := Ast .(type ) {
@@ -143,7 +156,7 @@ func CompileAst(Ast ast.Ast, filename string, flags int, dont_inherit bool) *py.
143156 }
144157 code .Code = c .OpCodes .Assemble ()
145158 code .Stacksize = int32 (c .OpCodes .StackDepth ())
146- return code
159+ return code , nil
147160}
148161
149162// Loop
@@ -176,15 +189,17 @@ func (ls loopstack) Top() *loop {
176189
177190// State for the compiler
178191type 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
182196}
183197
184198// Compiles a python constant
185199//
186200// Returns the index into the Consts tuple
187201func (c * compiler ) Const (obj py.Object ) uint32 {
202+ // FIXME back this with a dict to stop O(N**2) behaviour on lots of consts
188203 for i , c := range c .Code .Consts {
189204 if obj .Type () == c .Type () && py .Eq (obj , c ) == py .True {
190205 return uint32 (i )
@@ -199,19 +214,25 @@ func (c *compiler) LoadConst(obj py.Object) {
199214 c .OpArg (vm .LOAD_CONST , c .Const (obj ))
200215}
201216
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 {
208222 return uint32 (i )
209223 }
210224 }
211- c . Code . Names = append (c . Code . Names , string ( Id ) )
225+ * Names = append (* Names , Id )
212226 return uint32 (len (c .Code .Names ) - 1 )
213227}
214228
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+
215236// Compiles an instruction with an argument
216237func (c * compiler ) OpArg (Op byte , Arg uint32 ) {
217238 if ! vm .HAS_ARG (Op ) {
@@ -268,7 +289,14 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
268289 // Body []Stmt
269290 // DecoratorList []Expr
270291 // 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+ }
272300 code .Argcount = int32 (len (node .Args .Args ))
273301 code .Name = string (node .Name )
274302 code .Kwonlyargcount = int32 (len (node .Args .Kwonlyargs ))
@@ -555,6 +583,129 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
555583 }
556584}
557585
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+
558709// Compile expressions
559710func (c * compiler ) Expr (expr ast.Expr ) {
560711 switch node := expr .(type ) {
@@ -636,7 +787,15 @@ func (c *compiler) Expr(expr ast.Expr) {
636787 // Args *Arguments
637788 // Body Expr
638789 // 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+
640799 code .Argcount = int32 (len (node .Args .Args ))
641800 c .LoadConst (code )
642801 c .LoadConst (py .String ("<lambda>" ))
@@ -819,19 +978,7 @@ func (c *compiler) Expr(expr ast.Expr) {
819978 case * ast.Name :
820979 // Id Identifier
821980 // 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 )
835982 case * ast.List :
836983 // Elts []Expr
837984 // Ctx ExprContext
0 commit comments