]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Compile class definitions.
authorGuido van Rossum <guido@python.org>
Sun, 18 Nov 1990 17:35:03 +0000 (17:35 +0000)
committerGuido van Rossum <guido@python.org>
Sun, 18 Nov 1990 17:35:03 +0000 (17:35 +0000)
Document and fix code generation for try statements.
Use two bytes for all arguments.
Avoid duplicate entries in lists of constants and names.

Python/compile.c

index 03a1e32b7da6e1f829308b3d1d396814c87b4f47..2f5fd69a6c8cd4a6f7bb3e1969498c21d2498f93 100644 (file)
@@ -1,4 +1,3 @@
-#define DEBUG
 /* Compile an expression node to intermediate code */
 
 #include <stdio.h>
@@ -174,7 +173,8 @@ com_addint(c, x)
        struct compiling *c;
        int x;
 {
-       com_addbyte(c, x);
+       com_addbyte(c, x & 0xff);
+       com_addbyte(c, x >> 8); /* XXX x should be positive */
 }
 
 static void
@@ -215,22 +215,10 @@ com_backpatch(c, anchor)
        int prev;
        for (;;) {
                /* Make the JUMP instruction at anchor point to target */
-               prev = code[anchor];
-               dist = target - (anchor+1);
-               if (dist > 255 && lastanchor &&
-                               code[lastanchor-1] == code[anchor-1]) {
-                       /* Attempt to jump to a similar jump closer by */
-/* XXX Show that it works */
-fprintf(stderr, "com_backpatch: huge jump rescued (?)\n");
-                       target = lastanchor-1;
-                       dist = target - (anchor+1);
-                       lastanchor = 0;
-               }
-               if (dist > 255) {
-                       err_setstr(SystemError, "relative jump > 255 bytes");
-                       c->c_errors++;
-               }
-               code[anchor] = dist;
+               prev = code[anchor] + (code[anchor+1] << 8);
+               dist = target - (anchor+2);
+               code[anchor] = dist & 0xff;
+               code[anchor+1] = dist >> 8;
                if (!prev)
                        break;
                lastanchor = anchor;
@@ -246,11 +234,16 @@ com_add(c, list, v)
        object *list;
        object *v;
 {
-       /* XXX Should look through list for object with same value */
-       int i = getlistsize(list);
+       int n = getlistsize(list);
+       int i;
+       for (i = n; --i >= 0; ) {
+               object *w = getlistitem(list, i);
+               if (cmpobject(v, w) == 0)
+                       return i;
+       }
        if (addlistitem(list, v) != 0)
                c->c_errors++;
-       return i;
+       return n;
 }
 
 static int
@@ -926,6 +919,7 @@ com_assign(c, n, assigning)
        /* Loop to avoid trivial recursion */
        for (;;) {
                switch (TYPE(n)) {
+               
                case exprlist:
                case testlist:
                        if (NCH(n) > 1) {
@@ -934,6 +928,7 @@ com_assign(c, n, assigning)
                        }
                        n = CHILD(n, 0);
                        break;
+               
                case test:
                case and_test:
                case not_test:
@@ -945,6 +940,7 @@ com_assign(c, n, assigning)
                        }
                        n = CHILD(n, 0);
                        break;
+               
                case comparison:
                        if (NCH(n) > 1) {
                                err_setstr(TypeError,
@@ -954,6 +950,7 @@ com_assign(c, n, assigning)
                        }
                        n = CHILD(n, 0);
                        break;
+               
                case expr:
                        if (NCH(n) > 1) {
                                err_setstr(TypeError,
@@ -963,6 +960,7 @@ com_assign(c, n, assigning)
                        }
                        n = CHILD(n, 0);
                        break;
+               
                case term:
                        if (NCH(n) > 1) {
                                err_setstr(TypeError,
@@ -972,6 +970,7 @@ com_assign(c, n, assigning)
                        }
                        n = CHILD(n, 0);
                        break;
+               
                case factor: /* ('+'|'-') factor | atom trailer* */
                        if (TYPE(CHILD(n, 0)) != atom) { /* '+' | '-' */
                                err_setstr(TypeError,
@@ -991,6 +990,7 @@ com_assign(c, n, assigning)
                        }
                        n = CHILD(n, 0);
                        break;
+               
                case atom:
                        switch (TYPE(CHILD(n, 0))) {
                        case LPAR:
@@ -1023,11 +1023,13 @@ com_assign(c, n, assigning)
                                return;
                        }
                        break;
+               
                default:
                        fprintf(stderr, "node type %d\n", TYPE(n));
                        err_setstr(SystemError, "com_assign: bad node");
                        c->c_errors++;
                        return;
+               
                }
        }
 }
@@ -1065,6 +1067,7 @@ com_print_stmt(c, n)
        }
        if (TYPE(CHILD(n, NCH(n)-2)) != COMMA)
                com_addbyte(c, PRINT_NEWLINE);
+               /* XXX Alternatively, LOAD_CONST '\n' and then PRINT_ITEM */
 }
 
 static void
@@ -1112,6 +1115,7 @@ com_import_stmt(c, n)
                com_addbyte(c, POP_TOP);
        }
        else {
+               /* 'import' ... */
                for (i = 1; i < NCH(n); i += 2) {
                        com_addopname(c, IMPORT_NAME, CHILD(n, i));
                        com_addopname(c, STORE_NAME, CHILD(n, i));
@@ -1197,6 +1201,91 @@ com_for_stmt(c, n)
        com_backpatch(c, break_anchor);
 }
 
+/* Although 'execpt' and 'finally' clauses can be combined
+   syntactically, they are compiled separately.  In fact,
+       try: S
+       except E1: S1
+       except E2: S2
+       ...
+       finally: Sf
+   is equivalent to
+       try:
+           try: S
+           except E1: S1
+           except E2: S2
+           ...
+       finally: Sf
+   meaning that the 'finally' clause is entered even if things
+   go wrong again in an exception handler.  Note that this is
+   not the case for exception handlers: at most one is entered.
+   
+   Code generated for "try: S finally: Sf" is as follows:
+   
+               SETUP_FINALLY   L
+               <code for S>
+               POP_BLOCK
+               LOAD_CONST      <nil>
+               LOAD_CONST      <nil>
+       L:      <code for Sf>
+               END_FINALLY
+   
+   The special instructions use the block stack.  Each block
+   stack entry contains the instruction that created it (here
+   SETUP_FINALLY), the level of the value stack at the time the
+   block stack entry was created, and a label (here L).
+   
+   SETUP_FINALLY:
+       Pushes the current value stack level and the label
+       onto the block stack.
+   POP_BLOCK:
+       Pops en entry from the block stack, and pops the value
+       stack until its level is the same as indicated on the
+       block stack.  (The label is ignored.)
+   END_FINALLY:
+       Pops two entries from the *value* stack and re-raises
+       the exception they specify.  If the top entry is nil,
+       no exception is raised.  If it is a number, a pseudo
+       exception is raised ('return' or 'break').  Otherwise,
+       a real exception (specified by a string) is raised.
+       The second entry popped from the is the value that goes
+       with the exception (or the return value).
+   
+   The block stack is unwound when an exception is raised:
+   when a SETUP_FINALLY entry is found, the exception is pushed
+   onto the value stack (and the exception condition is cleared),
+   and the interpreter jumps to the label gotten from the block
+   stack.
+   
+   Code generated for "try: S except E1, V1: S1 except E2, V2: S2 ...":
+   
+   Value stack         Label   Instruction     Argument
+   []                          SETUP_EXCEPT    L1
+   []                          <code for S>
+   []                          POP_BLOCK
+   []                          JUMP_FORWARD    L0
+   
+   [val, exc]          L1:     DUP
+   [val, exc, exc]             <evaluate E1>
+   [val, exc, exc, E1]         COMPARE_OP      EXC_MATCH
+   [val, exc, 1-or-0]          JUMP_IF_FALSE   L2
+   [val, exc, 1]               POP
+   [val, exc]                  POP
+   [val]                       <assign to V1>
+   []                          <code for S1>
+                               JUMP_FORWARD    L0
+   
+   [val, exc, 0]       L2:     POP
+   [val, exc]                  DUP
+   .............................etc.......................
+
+   [val, exc, 0]       Ln+1:   POP
+   [val, exc]                  END_FINALLY     # re-raise exception
+   
+   []                  L0:     <next statement>
+   
+   Of course, parts are not generated if Vi or Ei is not present.
+*/
+
 static void
 com_try_stmt(c, n)
        struct compiling *c;
@@ -1206,6 +1295,7 @@ com_try_stmt(c, n)
        int except_anchor = 0;
        REQ(n, try_stmt);
        /* 'try' ':' suite (except_clause ':' suite)* ['finally' ':' suite] */
+       
        if (NCH(n) > 3 && TYPE(CHILD(n, NCH(n)-3)) != except_clause) {
                /* Have a 'finally' clause */
                com_addfwref(c, SETUP_FINALLY, &finally_anchor);
@@ -1226,12 +1316,18 @@ com_try_stmt(c, n)
                        i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause;
                                                                i += 3) {
                        /* except_clause: 'except' [expr [',' expr]] */
-                       int next_anchor = 0;
+                       if (except_anchor == 0) {
+                               err_setstr(TypeError,
+                                       "default 'except:' must be last");
+                               c->c_errors++;
+                               break;
+                       }
+                       except_anchor = 0;
                        if (NCH(ch) > 1) {
                                com_addbyte(c, DUP_TOP);
                                com_node(c, CHILD(ch, 1));
                                com_addoparg(c, COMPARE_OP, EXC_MATCH);
-                               com_addfwref(c, JUMP_IF_FALSE, &next_anchor);
+                               com_addfwref(c, JUMP_IF_FALSE, &except_anchor);
                                com_addbyte(c, POP_TOP);
                        }
                        com_addbyte(c, POP_TOP);
@@ -1241,8 +1337,10 @@ com_try_stmt(c, n)
                                com_addbyte(c, POP_TOP);
                        com_node(c, CHILD(n, i+2));
                        com_addfwref(c, JUMP_FORWARD, &end_anchor);
-                       if (next_anchor)
-                               com_backpatch(c, next_anchor);
+                       if (except_anchor) {
+                               com_backpatch(c, except_anchor);
+                               com_addbyte(c, POP_TOP);
+                       }
                }
                com_addbyte(c, END_FINALLY);
                com_backpatch(c, end_anchor);
@@ -1296,19 +1394,50 @@ com_funcdef(c, n)
        }
 }
 
+static void
+com_bases(c, n)
+       struct compiling *c;
+       node *n;
+{
+       int i, nbases;
+       REQ(n, baselist);
+       /*
+       baselist: atom arguments (',' atom arguments)*
+       arguments: '(' [testlist] ')'
+       */
+       for (i = 0; i < NCH(n); i += 3)
+               com_node(c, CHILD(n, i));
+       com_addoparg(c, BUILD_TUPLE, (NCH(n)+1) / 3);
+}
+
 static void
 com_classdef(c, n)
        struct compiling *c;
        node *n;
 {
+       object *v;
        REQ(n, classdef);
        /*
        classdef: 'class' NAME parameters ['=' baselist] ':' suite
        baselist: atom arguments (',' atom arguments)*
        arguments: '(' [testlist] ')'
        */
-       err_setstr(SystemError, "can't compile 'class' yet");
-       c->c_errors++;
+       if (NCH(n) == 7)
+               com_bases(c, CHILD(n, 4));
+       else
+               com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+       v = (object *)compile(n);
+       if (v == NULL)
+               c->c_errors++;
+       else {
+               int i = com_addconst(c, v);
+               com_addoparg(c, LOAD_CONST, i);
+               com_addbyte(c, BUILD_FUNCTION);
+               com_addbyte(c, UNARY_CALL);
+               com_addbyte(c, BUILD_CLASS);
+               com_addopname(c, STORE_NAME, CHILD(n, 1));
+               DECREF(v);
+       }
 }
 
 static void
@@ -1484,6 +1613,22 @@ compile_funcdef(c, n)
        com_addbyte(c, RETURN_VALUE);
 }
 
+static void
+compile_classdef(c, n)
+       struct compiling *c;
+       node *n;
+{
+       node *ch;
+       REQ(n, classdef);
+       /*
+       classdef: 'class' NAME parameters ['=' baselist] ':' suite
+       */
+       com_addbyte(c, REFUSE_ARGS);
+       com_node(c, CHILD(n, NCH(n)-1));
+       com_addbyte(c, LOAD_LOCALS);
+       com_addbyte(c, RETURN_VALUE);
+}
+
 static void
 compile_node(c, n)
        struct compiling *c;
@@ -1511,6 +1656,10 @@ compile_node(c, n)
                compile_funcdef(c, n);
                break;
        
+       case classdef:
+               compile_classdef(c, n);
+               break;
+       
        default:
                fprintf(stderr, "node type %d\n", TYPE(n));
                err_setstr(SystemError, "compile_node: unexpected node type");