@@ -347,13 +347,6 @@ func (c *compiler) Jump(Op byte, Dest *Label) {
347347 }
348348}
349349
350- // Compile statements
351- func (c * compiler ) Stmts (stmts []ast.Stmt ) {
352- for _ , stmt := range stmts {
353- c .Stmt (stmt )
354- }
355- }
356-
357350/* The test for LOCAL must come before the test for FREE in order to
358351 handle classes where name is both local and free. The local var is
359352 a method and the free var is a free var referenced within a method.
@@ -494,9 +487,7 @@ func (c *compiler) compileFunc(compilerScope compilerScopeType, Ast ast.Ast, Arg
494487 code .Kwonlyargcount = int32 (len (Args .Kwonlyargs ))
495488
496489 // Defaults
497- for _ , expr := range Args .Defaults {
498- c .Expr (expr )
499- }
490+ c .Exprs (Args .Defaults )
500491
501492 // KwDefaults
502493 if len (Args .Kwonlyargs ) != len (Args .KwDefaults ) {
@@ -532,9 +523,7 @@ func (c *compiler) compileFunc(compilerScope compilerScopeType, Ast ast.Ast, Arg
532523 }
533524
534525 // Load decorators onto stack
535- for _ , expr := range DecoratorList {
536- c .Expr (expr )
537- }
526+ c .Exprs (DecoratorList )
538527
539528 // Make function or closure, leaving it on the stack
540529 posdefaults := uint32 (len (Args .Defaults ))
@@ -551,9 +540,7 @@ func (c *compiler) compileFunc(compilerScope compilerScopeType, Ast ast.Ast, Arg
551540// Compile class definition
552541func (c * compiler ) class (Ast ast.Ast , class * ast.ClassDef ) {
553542 // Load decorators onto stack
554- for _ , expr := range class .DecoratorList {
555- c .Expr (expr )
556- }
543+ c .Exprs (class .DecoratorList )
557544
558545 /* ultimately generate code for:
559546 <name> = __build_class__(<func>, <name>, *<bases>, **<keywords>)
@@ -643,9 +630,7 @@ func (c *compiler) with(node *ast.With, pos int) {
643630 pos ++
644631 if pos == len (node .Items ) {
645632 /* BLOCK code */
646- for _ , stmt := range node .Body {
647- c .Stmt (stmt )
648- }
633+ c .Stmts (node .Body )
649634 } else {
650635 c .with (node , pos )
651636 }
@@ -664,6 +649,176 @@ func (c *compiler) with(node *ast.With, pos int) {
664649 c .Op (vm .END_FINALLY )
665650}
666651
652+ /* Code generated for "try: <body> finally: <finalbody>" is as follows:
653+
654+ SETUP_FINALLY L
655+ <code for body>
656+ POP_BLOCK
657+ LOAD_CONST <None>
658+ L: <code for finalbody>
659+ END_FINALLY
660+
661+ The special instructions use the block stack. Each block
662+ stack entry contains the instruction that created it (here
663+ SETUP_FINALLY), the level of the value stack at the time the
664+ block stack entry was created, and a label (here L).
665+
666+ SETUP_FINALLY:
667+ Pushes the current value stack level and the label
668+ onto the block stack.
669+ POP_BLOCK:
670+ Pops en entry from the block stack, and pops the value
671+ stack until its level is the same as indicated on the
672+ block stack. (The label is ignored.)
673+ END_FINALLY:
674+ Pops a variable number of entries from the *value* stack
675+ and re-raises the exception they specify. The number of
676+ entries popped depends on the (pseudo) exception type.
677+
678+ The block stack is unwound when an exception is raised:
679+ when a SETUP_FINALLY entry is found, the exception is pushed
680+ onto the value stack (and the exception condition is cleared),
681+ and the interpreter jumps to the label gotten from the block
682+ stack.
683+ */
684+ func (c * compiler ) tryFinally (node * ast.Try ) {
685+ end := new (Label )
686+ c .Jump (vm .SETUP_FINALLY , end )
687+ if len (node .Handlers ) > 0 {
688+ c .tryExcept (node )
689+ } else {
690+ c .Stmts (node .Body )
691+ }
692+ c .Op (vm .POP_BLOCK )
693+ c .LoadConst (py .None )
694+ c .Label (end )
695+ c .Stmts (node .Finalbody )
696+ c .Op (vm .END_FINALLY )
697+ }
698+
699+ /*
700+ Code generated for "try: S except E1 as V1: S1 except E2 as V2: S2 ...":
701+ (The contents of the value stack is shown in [], with the top
702+ at the right; 'tb' is trace-back info, 'val' the exception's
703+ associated value, and 'exc' the exception.)
704+
705+ Value stack Label Instruction Argument
706+ [] SETUP_EXCEPT L1
707+ [] <code for S>
708+ [] POP_BLOCK
709+ [] JUMP_FORWARD L0
710+
711+ [tb, val, exc] L1: DUP )
712+ [tb, val, exc, exc] <evaluate E1> )
713+ [tb, val, exc, exc, E1] COMPARE_OP EXC_MATCH ) only if E1
714+ [tb, val, exc, 1-or-0] POP_JUMP_IF_FALSE L2 )
715+ [tb, val, exc] POP
716+ [tb, val] <assign to V1> (or POP if no V1)
717+ [tb] POP
718+ [] <code for S1>
719+ JUMP_FORWARD L0
720+
721+ [tb, val, exc] L2: DUP
722+ .............................etc.......................
723+
724+ [tb, val, exc] Ln+1: END_FINALLY # re-raise exception
725+
726+ [] L0: <next statement>
727+
728+ Of course, parts are not generated if Vi or Ei is not present.
729+ */
730+ func (c * compiler ) tryExcept (node * ast.Try ) {
731+ except := new (Label )
732+ orelse := new (Label )
733+ end := new (Label )
734+ c .Jump (vm .SETUP_EXCEPT , except )
735+ c .Stmts (node .Body )
736+ c .Op (vm .POP_BLOCK )
737+ c .Jump (vm .JUMP_FORWARD , orelse )
738+ n := len (node .Handlers )
739+ c .Label (except )
740+ for i , handler := range node .Handlers {
741+ if handler .ExprType == nil && i < n - 1 {
742+ panic (py .ExceptionNewf (py .SyntaxError , "default 'except:' must be last" ))
743+ }
744+ // FIXME c.u.u_lineno_set = 0
745+ // c.u.u_lineno = handler.lineno
746+ // c.u.u_col_offset = handler.col_offset
747+ except := new (Label )
748+ if handler .ExprType != nil {
749+ c .Op (vm .DUP_TOP )
750+ c .Expr (handler .ExprType )
751+ c .OpArg (vm .COMPARE_OP , vm .PyCmp_EXC_MATCH )
752+ c .Jump (vm .POP_JUMP_IF_FALSE , except )
753+ }
754+ c .Op (vm .POP_TOP )
755+ if handler .Name != "" {
756+ cleanup_end := new (Label )
757+ c .NameOp (string (handler .Name ), ast .Store )
758+ c .Op (vm .POP_TOP )
759+
760+ /*
761+ try:
762+ # body
763+ except type as name:
764+ try:
765+ # body
766+ finally:
767+ name = None
768+ del name
769+ */
770+
771+ /* second try: */
772+ c .Jump (vm .SETUP_FINALLY , cleanup_end )
773+
774+ /* second # body */
775+ c .Stmts (handler .Body )
776+ c .Op (vm .POP_BLOCK )
777+ c .Op (vm .POP_EXCEPT )
778+
779+ /* finally: */
780+ c .LoadConst (py .None )
781+ c .Label (cleanup_end )
782+
783+ /* name = None */
784+ c .LoadConst (py .None )
785+ c .NameOp (string (handler .Name ), ast .Store )
786+
787+ /* del name */
788+ c .NameOp (string (handler .Name ), ast .Del )
789+
790+ c .Op (vm .END_FINALLY )
791+ } else {
792+ c .Op (vm .POP_TOP )
793+ c .Op (vm .POP_TOP )
794+ c .Stmts (handler .Body )
795+ c .Op (vm .POP_EXCEPT )
796+ }
797+ c .Jump (vm .JUMP_FORWARD , end )
798+ c .Label (except )
799+ }
800+ c .Op (vm .END_FINALLY )
801+ c .Label (orelse )
802+ c .Stmts (node .Orelse )
803+ c .Label (end )
804+ }
805+
806+ // Compile a try statement
807+ func (c * compiler ) try (node * ast.Try ) {
808+ if len (node .Finalbody ) > 0 {
809+ c .tryFinally (node )
810+ } else {
811+ c .tryExcept (node )
812+ }
813+ }
814+
815+ // Compile statements
816+ func (c * compiler ) Stmts (stmts []ast.Stmt ) {
817+ for _ , stmt := range stmts {
818+ c .Stmt (stmt )
819+ }
820+ }
821+
667822// Compile statement
668823func (c * compiler ) Stmt (stmt ast.Stmt ) {
669824 switch node := stmt .(type ) {
@@ -766,16 +921,12 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
766921 c .loops .Push (loop {Start : forloop , End : endpopblock , IsForLoop : true })
767922 c .Jump (vm .FOR_ITER , endfor )
768923 c .Expr (node .Target )
769- for _ , stmt := range node .Body {
770- c .Stmt (stmt )
771- }
924+ c .Stmts (node .Body )
772925 c .Jump (vm .JUMP_ABSOLUTE , forloop )
773926 c .Label (endfor )
774927 c .Op (vm .POP_BLOCK )
775928 c .loops .Pop ()
776- for _ , stmt := range node .Orelse {
777- c .Stmt (stmt )
778- }
929+ c .Stmts (node .Orelse )
779930 c .Label (endpopblock )
780931 case * ast.While :
781932 // Test Expr
@@ -788,16 +939,12 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
788939 c .loops .Push (loop {Start : while , End : endpopblock })
789940 c .Expr (node .Test )
790941 c .Jump (vm .POP_JUMP_IF_FALSE , endwhile )
791- for _ , stmt := range node .Body {
792- c .Stmt (stmt )
793- }
942+ c .Stmts (node .Body )
794943 c .Jump (vm .JUMP_ABSOLUTE , while )
795944 c .Label (endwhile )
796945 c .Op (vm .POP_BLOCK )
797946 c .loops .Pop ()
798- for _ , stmt := range node .Orelse {
799- c .Stmt (stmt )
800- }
947+ c .Stmts (node .Orelse )
801948 c .Label (endpopblock )
802949 case * ast.If :
803950 // Test Expr
@@ -807,17 +954,13 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
807954 endif := new (Label )
808955 c .Expr (node .Test )
809956 c .Jump (vm .POP_JUMP_IF_FALSE , orelse )
810- for _ , stmt := range node .Body {
811- c .Stmt (stmt )
812- }
957+ c .Stmts (node .Body )
813958 // FIXME this puts a JUMP_FORWARD in when not
814959 // necessary (when no Orelse statements) but it
815960 // matches python3.4 (this is fixed in py3.5)
816961 c .Jump (vm .JUMP_FORWARD , endif )
817962 c .Label (orelse )
818- for _ , stmt := range node .Orelse {
819- c .Stmt (stmt )
820- }
963+ c .Stmts (node .Orelse )
821964 c .Label (endif )
822965 case * ast.With :
823966 // Items []*WithItem
@@ -841,7 +984,7 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
841984 // Handlers []*ExceptHandler
842985 // Orelse []Stmt
843986 // Finalbody []Stmt
844- panic ( "FIXME compile: Try not implemented" )
987+ c . try ( node )
845988 case * ast.Assert :
846989 // Test Expr
847990 // Msg Expr
@@ -913,7 +1056,7 @@ func (c *compiler) NameOp(name string, ctx ast.ExprContext) {
9131056 // PyObject *mangled;
9141057 /* XXX AugStore isn't used anywhere! */
9151058
916- // FIXME mangled = _Py_Mangle(c->u-> u_private, name);
1059+ // FIXME mangled = _Py_Mangle(c.u. u_private, name);
9171060 mangled := name
9181061
9191062 if name == "None" || name == "True" || name == "False" {
@@ -1143,6 +1286,13 @@ func (c *compiler) comprehension(expr ast.Expr, generators []ast.Comprehension)
11431286}
11441287
11451288// Compile expressions
1289+ func (c * compiler ) Exprs (exprs []ast.Expr ) {
1290+ for _ , expr := range exprs {
1291+ c .Expr (expr )
1292+ }
1293+ }
1294+
1295+ // Compile and expression
11461296func (c * compiler ) Expr (expr ast.Expr ) {
11471297 switch node := expr .(type ) {
11481298 case * ast.BoolOp :
0 commit comments