diff options
author | Jeremy Hylton <jeremy@alum.mit.edu> | 2005-10-20 19:59:25 (GMT) |
---|---|---|
committer | Jeremy Hylton <jeremy@alum.mit.edu> | 2005-10-20 19:59:25 (GMT) |
commit | 3e0055f8c65c407e74ce476b8e2b1fb889723514 (patch) | |
tree | 169cce8c87033e15364b57de947073e6e9c34d59 /Python/compile.c | |
parent | 2cb94aba122b86dcda87d437eb36a860d14393d5 (diff) | |
download | cpython-3e0055f8c65c407e74ce476b8e2b1fb889723514.zip cpython-3e0055f8c65c407e74ce476b8e2b1fb889723514.tar.gz cpython-3e0055f8c65c407e74ce476b8e2b1fb889723514.tar.bz2 |
Merge ast-branch to head
This change implements a new bytecode compiler, based on a
transformation of the parse tree to an abstract syntax defined in
Parser/Python.asdl.
The compiler implementation is not complete, but it is in stable
enough shape to run the entire test suite excepting two disabled
tests.
Diffstat (limited to 'Python/compile.c')
-rw-r--r-- | Python/compile.c | 8493 |
1 files changed, 2880 insertions, 5613 deletions
diff --git a/Python/compile.c b/Python/compile.c index 99ccf29..10c94e7 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1,385 +1,379 @@ -/* Compile an expression node to intermediate code */ - -/* XXX TO DO: - XXX add __doc__ attribute == co_doc to code object attributes? - XXX (it's currently the first item of the co_const tuple) - XXX Generate simple jump for break/return outside 'try...finally' - XXX Allow 'continue' inside finally clause of try-finally - XXX New opcode for loading the initial index for a for loop - XXX other JAR tricks? -*/ +/* + * This file compiles an abstract syntax tree (AST) into Python bytecode. + * + * The primary entry point is PyAST_Compile(), which returns a + * PyCodeObject. The compiler makes several passes to build the code + * object: + * 1. Checks for future statements. See future.c + * 2. Builds a symbol table. See symtable.c. + * 3. Generate code for basic blocks. See compiler_mod() in this file. + * 4. Assemble the basic blocks into final code. See assemble() in + * this file. + * + * Note that compiler_mod() suggests module, but the module ast type + * (mod_ty) has cases for expressions and interactive statements. + */ #include "Python.h" +#include "Python-ast.h" #include "node.h" -#include "token.h" -#include "graminit.h" +#include "ast.h" +#include "code.h" #include "compile.h" #include "symtable.h" #include "opcode.h" -#include "structmember.h" - -#include <ctype.h> - -/* Three symbols from graminit.h are also defined in Python.h, with - Py_ prefixes to their names. Python.h can't include graminit.h - (which defines too many confusing symbols), but we can check here - that they haven't changed (which is very unlikely, but possible). */ -#if Py_single_input != single_input - #error "single_input has changed -- update Py_single_input in Python.h" -#endif -#if Py_file_input != file_input - #error "file_input has changed -- update Py_file_input in Python.h" -#endif -#if Py_eval_input != eval_input - #error "eval_input has changed -- update Py_eval_input in Python.h" -#endif int Py_OptimizeFlag = 0; -#define OP_DELETE 0 -#define OP_ASSIGN 1 -#define OP_APPLY 2 +/* + ISSUES: -#define VAR_LOAD 0 -#define VAR_STORE 1 -#define VAR_DELETE 2 + character encodings aren't handled -#define DEL_CLOSURE_ERROR \ -"can not delete variable '%.400s' referenced in nested scope" + ref leaks in interpreter when press return on empty line -#define DUPLICATE_ARGUMENT \ -"duplicate argument '%s' in function definition" + opcode_stack_effect() function should be reviewed since stack depth bugs + could be really hard to find later. -#define GLOBAL_AFTER_ASSIGN \ -"name '%.400s' is assigned to before global declaration" - -#define GLOBAL_AFTER_USE \ -"name '%.400s' is used prior to global declaration" + Dead code is being generated (i.e. after unconditional jumps). +*/ -#define PARAM_GLOBAL \ -"name '%.400s' is a function parameter and declared global" +#define DEFAULT_BLOCK_SIZE 16 +#define DEFAULT_BLOCKS 8 +#define DEFAULT_CODE_SIZE 128 +#define DEFAULT_LNOTAB_SIZE 16 + +struct instr { + int i_jabs : 1; + int i_jrel : 1; + int i_hasarg : 1; + unsigned char i_opcode; + int i_oparg; + struct basicblock_ *i_target; /* target block (if jump instruction) */ + int i_lineno; +}; -#define LATE_FUTURE \ -"from __future__ imports must occur at the beginning of the file" +typedef struct basicblock_ { + /* next block in the list of blocks for a unit (don't confuse with + * b_next) */ + struct basicblock_ *b_list; + /* number of instructions used */ + int b_iused; + /* length of instruction array (b_instr) */ + int b_ialloc; + /* pointer to an array of instructions, initially NULL */ + struct instr *b_instr; + /* If b_next is non-NULL, it is a pointer to the next + block reached by normal control flow. */ + struct basicblock_ *b_next; + /* b_seen is used to perform a DFS of basicblocks. */ + int b_seen : 1; + /* b_return is true if a RETURN_VALUE opcode is inserted. */ + int b_return : 1; + /* depth of stack upon entry of block, computed by stackdepth() */ + int b_startdepth; + /* instruction offset for block, computed by assemble_jump_offsets() */ + int b_offset; +} basicblock; + +/* fblockinfo tracks the current frame block. + + A frame block is used to handle loops, try/except, and try/finally. + It's called a frame block to distinguish it from a basic block in the + compiler IR. +*/ -#define ASSIGN_DEBUG \ -"can not assign to __debug__" +enum fblocktype { LOOP, EXCEPT, FINALLY_TRY, FINALLY_END }; -#define MANGLE_LEN 256 +struct fblockinfo { + enum fblocktype fb_type; + basicblock *fb_block; +}; -#define OFF(x) offsetof(PyCodeObject, x) +/* The following items change on entry and exit of code blocks. + They must be saved and restored when returning to a block. +*/ +struct compiler_unit { + PySTEntryObject *u_ste; -static PyMemberDef code_memberlist[] = { - {"co_argcount", T_INT, OFF(co_argcount), READONLY}, - {"co_nlocals", T_INT, OFF(co_nlocals), READONLY}, - {"co_stacksize",T_INT, OFF(co_stacksize), READONLY}, - {"co_flags", T_INT, OFF(co_flags), READONLY}, - {"co_code", T_OBJECT, OFF(co_code), READONLY}, - {"co_consts", T_OBJECT, OFF(co_consts), READONLY}, - {"co_names", T_OBJECT, OFF(co_names), READONLY}, - {"co_varnames", T_OBJECT, OFF(co_varnames), READONLY}, - {"co_freevars", T_OBJECT, OFF(co_freevars), READONLY}, - {"co_cellvars", T_OBJECT, OFF(co_cellvars), READONLY}, - {"co_filename", T_OBJECT, OFF(co_filename), READONLY}, - {"co_name", T_OBJECT, OFF(co_name), READONLY}, - {"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY}, - {"co_lnotab", T_OBJECT, OFF(co_lnotab), READONLY}, - {NULL} /* Sentinel */ + PyObject *u_name; + /* The following fields are dicts that map objects to + the index of them in co_XXX. The index is used as + the argument for opcodes that refer to those collections. + */ + PyObject *u_consts; /* all constants */ + PyObject *u_names; /* all names */ + PyObject *u_varnames; /* local variables */ + PyObject *u_cellvars; /* cell variables */ + PyObject *u_freevars; /* free variables */ + + PyObject *u_private; /* for private name mangling */ + + int u_argcount; /* number of arguments for block */ + basicblock *u_blocks; /* pointer to list of blocks */ + basicblock *u_curblock; /* pointer to current block */ + int u_tmpname; /* temporary variables for list comps */ + + int u_nfblocks; + struct fblockinfo u_fblock[CO_MAXBLOCKS]; + + int u_firstlineno; /* the first lineno of the block */ + int u_lineno; /* the lineno for the current stmt */ + bool u_lineno_set; /* boolean to indicate whether instr + has been generated with current lineno */ }; -/* Helper for code_new: return a shallow copy of a tuple that is - guaranteed to contain exact strings, by converting string subclasses - to exact strings and complaining if a non-string is found. */ -static PyObject* -validate_and_copy_tuple(PyObject *tup) -{ - PyObject *newtuple; - PyObject *item; - int i, len; +/* This struct captures the global state of a compilation. - len = PyTuple_GET_SIZE(tup); - newtuple = PyTuple_New(len); - if (newtuple == NULL) - return NULL; + The u pointer points to the current compilation unit, while units + for enclosing blocks are stored in c_stack. The u and c_stack are + managed by compiler_enter_scope() and compiler_exit_scope(). +*/ - for (i = 0; i < len; i++) { - item = PyTuple_GET_ITEM(tup, i); - if (PyString_CheckExact(item)) { - Py_INCREF(item); - } - else if (!PyString_Check(item)) { - PyErr_Format( - PyExc_TypeError, - "name tuples must contain only " - "strings, not '%.500s'", - item->ob_type->tp_name); - Py_DECREF(newtuple); - return NULL; - } - else { - item = PyString_FromStringAndSize( - PyString_AS_STRING(item), - PyString_GET_SIZE(item)); - if (item == NULL) { - Py_DECREF(newtuple); - return NULL; - } - } - PyTuple_SET_ITEM(newtuple, i, item); - } +struct compiler { + const char *c_filename; + struct symtable *c_st; + PyFutureFeatures *c_future; /* pointer to module's __future__ */ + PyCompilerFlags *c_flags; - return newtuple; -} + int c_interactive; + int c_nestlevel; -PyDoc_STRVAR(code_doc, -"code(argcount, nlocals, stacksize, flags, codestring, constants, names,\n\ - varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])\n\ -\n\ -Create a code object. Not for the faint of heart."); + struct compiler_unit *u; /* compiler state for current block */ + PyObject *c_stack; /* Python list holding compiler_unit ptrs */ + char *c_encoding; /* source encoding (a borrowed reference) */ +}; -static PyObject * -code_new(PyTypeObject *type, PyObject *args, PyObject *kw) +struct assembler { + PyObject *a_bytecode; /* string containing bytecode */ + int a_offset; /* offset into bytecode */ + int a_nblocks; /* number of reachable blocks */ + basicblock **a_postorder; /* list of blocks in dfs postorder */ + PyObject *a_lnotab; /* string containing lnotab */ + int a_lnotab_off; /* offset into lnotab */ + int a_lineno; /* last lineno of emitted instruction */ + int a_lineno_off; /* bytecode offset of last lineno */ +}; + +static int compiler_enter_scope(struct compiler *, identifier, void *, int); +static void compiler_free(struct compiler *); +static basicblock *compiler_new_block(struct compiler *); +static int compiler_next_instr(struct compiler *, basicblock *); +static int compiler_addop(struct compiler *, int); +static int compiler_addop_o(struct compiler *, int, PyObject *, PyObject *); +static int compiler_addop_i(struct compiler *, int, int); +static int compiler_addop_j(struct compiler *, int, basicblock *, int); +static void compiler_use_block(struct compiler *, basicblock *); +static basicblock *compiler_use_new_block(struct compiler *); +static int compiler_error(struct compiler *, const char *); +static int compiler_nameop(struct compiler *, identifier, expr_context_ty); + +static PyCodeObject *compiler_mod(struct compiler *, mod_ty); +static int compiler_visit_stmt(struct compiler *, stmt_ty); +static int compiler_visit_keyword(struct compiler *, keyword_ty); +static int compiler_visit_expr(struct compiler *, expr_ty); +static int compiler_augassign(struct compiler *, stmt_ty); +static int compiler_visit_slice(struct compiler *, slice_ty, + expr_context_ty); + +static int compiler_push_fblock(struct compiler *, enum fblocktype, + basicblock *); +static void compiler_pop_fblock(struct compiler *, enum fblocktype, + basicblock *); + +static int inplace_binop(struct compiler *, operator_ty); +static int expr_constant(expr_ty e); + +static PyCodeObject *assemble(struct compiler *, int addNone); +static PyObject *__doc__; + +PyObject * +_Py_Mangle(PyObject *private, PyObject *ident) { - int argcount; - int nlocals; - int stacksize; - int flags; - PyObject *co = NULL; - PyObject *code; - PyObject *consts; - PyObject *names, *ournames = NULL; - PyObject *varnames, *ourvarnames = NULL; - PyObject *freevars = NULL, *ourfreevars = NULL; - PyObject *cellvars = NULL, *ourcellvars = NULL; - PyObject *filename; - PyObject *name; - int firstlineno; - PyObject *lnotab; - - if (!PyArg_ParseTuple(args, "iiiiSO!O!O!SSiS|O!O!:code", - &argcount, &nlocals, &stacksize, &flags, - &code, - &PyTuple_Type, &consts, - &PyTuple_Type, &names, - &PyTuple_Type, &varnames, - &filename, &name, - &firstlineno, &lnotab, - &PyTuple_Type, &freevars, - &PyTuple_Type, &cellvars)) - return NULL; + /* Name mangling: __private becomes _classname__private. + This is independent from how the name is used. */ + const char *p, *name = PyString_AsString(ident); + char *buffer; + size_t nlen, plen; + if (private == NULL || name == NULL || name[0] != '_' || name[1] != '_') { + Py_INCREF(ident); + return ident; + } + p = PyString_AsString(private); + nlen = strlen(name); + if (name[nlen-1] == '_' && name[nlen-2] == '_') { + Py_INCREF(ident); + return ident; /* Don't mangle __whatever__ */ + } + /* Strip leading underscores from class name */ + while (*p == '_') + p++; + if (*p == '\0') { + Py_INCREF(ident); + return ident; /* Don't mangle if class is just underscores */ + } + plen = strlen(p); + ident = PyString_FromStringAndSize(NULL, 1 + nlen + plen); + if (!ident) + return 0; + /* ident = "_" + p[:plen] + name # i.e. 1+plen+nlen bytes */ + buffer = PyString_AS_STRING(ident); + buffer[0] = '_'; + strncpy(buffer+1, p, plen); + strcpy(buffer+1+plen, name); + return ident; +} - if (argcount < 0) { - PyErr_SetString( - PyExc_ValueError, - "code: argcount must not be negative"); - goto cleanup; - } +static int +compiler_init(struct compiler *c) +{ + memset(c, 0, sizeof(struct compiler)); + + c->c_stack = PyList_New(0); + if (!c->c_stack) + return 0; + + return 1; +} - if (nlocals < 0) { - PyErr_SetString( - PyExc_ValueError, - "code: nlocals must not be negative"); - goto cleanup; +PyCodeObject * +PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags) +{ + struct compiler c; + PyCodeObject *co = NULL; + PyCompilerFlags local_flags; + int merged; + + if (!__doc__) { + __doc__ = PyString_InternFromString("__doc__"); + if (!__doc__) + goto error; + } + + if (!compiler_init(&c)) + goto error; + c.c_filename = filename; + c.c_future = PyFuture_FromAST(mod, filename); + if (c.c_future == NULL) + goto error; + if (!flags) { + local_flags.cf_flags = 0; + flags = &local_flags; + } + merged = c.c_future->ff_features | flags->cf_flags; + c.c_future->ff_features = merged; + flags->cf_flags = merged; + c.c_flags = flags; + c.c_nestlevel = 0; + + c.c_st = PySymtable_Build(mod, filename, c.c_future); + if (c.c_st == NULL) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_SystemError, "no symtable"); + goto error; } - ournames = validate_and_copy_tuple(names); - if (ournames == NULL) - goto cleanup; - ourvarnames = validate_and_copy_tuple(varnames); - if (ourvarnames == NULL) - goto cleanup; - if (freevars) - ourfreevars = validate_and_copy_tuple(freevars); - else - ourfreevars = PyTuple_New(0); - if (ourfreevars == NULL) - goto cleanup; - if (cellvars) - ourcellvars = validate_and_copy_tuple(cellvars); - else - ourcellvars = PyTuple_New(0); - if (ourcellvars == NULL) - goto cleanup; - - co = (PyObject *) PyCode_New(argcount, nlocals, stacksize, flags, - code, consts, ournames, ourvarnames, - ourfreevars, ourcellvars, filename, - name, firstlineno, lnotab); - cleanup: - Py_XDECREF(ournames); - Py_XDECREF(ourvarnames); - Py_XDECREF(ourfreevars); - Py_XDECREF(ourcellvars); + /* XXX initialize to NULL for now, need to handle */ + c.c_encoding = NULL; + + co = compiler_mod(&c, mod); + + error: + compiler_free(&c); return co; } -static void -code_dealloc(PyCodeObject *co) +PyCodeObject * +PyNode_Compile(struct _node *n, const char *filename) { - Py_XDECREF(co->co_code); - Py_XDECREF(co->co_consts); - Py_XDECREF(co->co_names); - Py_XDECREF(co->co_varnames); - Py_XDECREF(co->co_freevars); - Py_XDECREF(co->co_cellvars); - Py_XDECREF(co->co_filename); - Py_XDECREF(co->co_name); - Py_XDECREF(co->co_lnotab); - PyObject_DEL(co); + PyCodeObject *co; + mod_ty mod = PyAST_FromNode(n, NULL, filename); + if (!mod) + return NULL; + co = PyAST_Compile(mod, filename, NULL); + free_mod(mod); + return co; } -static PyObject * -code_repr(PyCodeObject *co) +static void +compiler_free(struct compiler *c) { - char buf[500]; - int lineno = -1; - char *filename = "???"; - char *name = "???"; - - if (co->co_firstlineno != 0) - lineno = co->co_firstlineno; - if (co->co_filename && PyString_Check(co->co_filename)) - filename = PyString_AS_STRING(co->co_filename); - if (co->co_name && PyString_Check(co->co_name)) - name = PyString_AS_STRING(co->co_name); - PyOS_snprintf(buf, sizeof(buf), - "<code object %.100s at %p, file \"%.300s\", line %d>", - name, co, filename, lineno); - return PyString_FromString(buf); + if (c->c_st) + PySymtable_Free(c->c_st); + if (c->c_future) + PyObject_Free((void *)c->c_future); + Py_DECREF(c->c_stack); } -static int -code_compare(PyCodeObject *co, PyCodeObject *cp) +static PyObject * +list2dict(PyObject *list) { - int cmp; - cmp = PyObject_Compare(co->co_name, cp->co_name); - if (cmp) return cmp; - cmp = co->co_argcount - cp->co_argcount; - if (cmp) return (cmp<0)?-1:1; - cmp = co->co_nlocals - cp->co_nlocals; - if (cmp) return (cmp<0)?-1:1; - cmp = co->co_flags - cp->co_flags; - if (cmp) return (cmp<0)?-1:1; - cmp = co->co_firstlineno - cp->co_firstlineno; - if (cmp) return (cmp<0)?-1:1; - cmp = PyObject_Compare(co->co_code, cp->co_code); - if (cmp) return cmp; - cmp = PyObject_Compare(co->co_consts, cp->co_consts); - if (cmp) return cmp; - cmp = PyObject_Compare(co->co_names, cp->co_names); - if (cmp) return cmp; - cmp = PyObject_Compare(co->co_varnames, cp->co_varnames); - if (cmp) return cmp; - cmp = PyObject_Compare(co->co_freevars, cp->co_freevars); - if (cmp) return cmp; - cmp = PyObject_Compare(co->co_cellvars, cp->co_cellvars); - return cmp; -} + int i, n; + PyObject *v, *k, *dict = PyDict_New(); -static long -code_hash(PyCodeObject *co) -{ - long h, h0, h1, h2, h3, h4, h5, h6; - h0 = PyObject_Hash(co->co_name); - if (h0 == -1) return -1; - h1 = PyObject_Hash(co->co_code); - if (h1 == -1) return -1; - h2 = PyObject_Hash(co->co_consts); - if (h2 == -1) return -1; - h3 = PyObject_Hash(co->co_names); - if (h3 == -1) return -1; - h4 = PyObject_Hash(co->co_varnames); - if (h4 == -1) return -1; - h5 = PyObject_Hash(co->co_freevars); - if (h5 == -1) return -1; - h6 = PyObject_Hash(co->co_cellvars); - if (h6 == -1) return -1; - h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^ - co->co_argcount ^ co->co_nlocals ^ co->co_flags; - if (h == -1) h = -2; - return h; + n = PyList_Size(list); + for (i = 0; i < n; i++) { + v = PyInt_FromLong(i); + if (!v) { + Py_DECREF(dict); + return NULL; + } + k = PyList_GET_ITEM(list, i); + k = Py_BuildValue("(OO)", k, k->ob_type); + if (k == NULL || PyDict_SetItem(dict, k, v) < 0) { + Py_XDECREF(k); + Py_DECREF(v); + Py_DECREF(dict); + return NULL; + } + Py_DECREF(v); + } + return dict; } -/* XXX code objects need to participate in GC? */ - -PyTypeObject PyCode_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "code", - sizeof(PyCodeObject), - 0, - (destructor)code_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)code_compare, /* tp_compare */ - (reprfunc)code_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)code_hash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - code_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - code_memberlist, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - code_new, /* tp_new */ -}; +/* Return new dict containing names from src that match scope(s). -#define NAME_CHARS \ - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" - -/* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */ + src is a symbol table dictionary. If the scope of a name matches + either scope_type or flag is set, insert it into the new dict. The + values are integers, starting at offset and increasing by one for + each key. +*/ -static int -all_name_chars(unsigned char *s) +static PyObject * +dictbytype(PyObject *src, int scope_type, int flag, int offset) { - static char ok_name_char[256]; - static unsigned char *name_chars = (unsigned char *)NAME_CHARS; + int pos = 0, i = offset, scope; + PyObject *k, *v, *dest = PyDict_New(); - if (ok_name_char[*name_chars] == 0) { - unsigned char *p; - for (p = name_chars; *p; p++) - ok_name_char[*p] = 1; - } - while (*s) { - if (ok_name_char[*s++] == 0) - return 0; - } - return 1; -} + assert(offset >= 0); + if (dest == NULL) + return NULL; -static void -intern_strings(PyObject *tuple) -{ - int i; + while (PyDict_Next(src, &pos, &k, &v)) { + /* XXX this should probably be a macro in symtable.h */ + assert(PyInt_Check(v)); + scope = (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK; - for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) { - PyObject *v = PyTuple_GET_ITEM(tuple, i); - if (v == NULL || !PyString_CheckExact(v)) { - Py_FatalError("non-string found in code slot"); + if (scope == scope_type || PyInt_AS_LONG(v) & flag) { + PyObject *tuple, *item = PyInt_FromLong(i); + if (item == NULL) { + Py_DECREF(dest); + return NULL; + } + i++; + tuple = Py_BuildValue("(OO)", k, k->ob_type); + if (!tuple || PyDict_SetItem(dest, tuple, item) < 0) { + Py_DECREF(item); + Py_DECREF(dest); + Py_XDECREF(tuple); + return NULL; } - PyString_InternInPlace(&PyTuple_GET_ITEM(tuple, i)); + Py_DECREF(item); + Py_DECREF(tuple); + } } + return dest; } /* Begin: Peephole optimizations ----------------------------------------- */ @@ -974,2262 +968,813 @@ exitUnchanged: /* End: Peephole optimizations ----------------------------------------- */ -PyCodeObject * -PyCode_New(int argcount, int nlocals, int stacksize, int flags, - PyObject *code, PyObject *consts, PyObject *names, - PyObject *varnames, PyObject *freevars, PyObject *cellvars, - PyObject *filename, PyObject *name, int firstlineno, - PyObject *lnotab) -{ - PyCodeObject *co; - int i; - /* Check argument types */ - if (argcount < 0 || nlocals < 0 || - code == NULL || - consts == NULL || !PyTuple_Check(consts) || - names == NULL || !PyTuple_Check(names) || - varnames == NULL || !PyTuple_Check(varnames) || - freevars == NULL || !PyTuple_Check(freevars) || - cellvars == NULL || !PyTuple_Check(cellvars) || - name == NULL || !PyString_Check(name) || - filename == NULL || !PyString_Check(filename) || - lnotab == NULL || !PyString_Check(lnotab) || - !PyObject_CheckReadBuffer(code)) { - PyErr_BadInternalCall(); - return NULL; - } - intern_strings(names); - intern_strings(varnames); - intern_strings(freevars); - intern_strings(cellvars); - /* Intern selected string constants */ - for (i = PyTuple_Size(consts); --i >= 0; ) { - PyObject *v = PyTuple_GetItem(consts, i); - if (!PyString_Check(v)) - continue; - if (!all_name_chars((unsigned char *)PyString_AS_STRING(v))) - continue; - PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i)); - } - co = PyObject_NEW(PyCodeObject, &PyCode_Type); - if (co != NULL) { - co->co_argcount = argcount; - co->co_nlocals = nlocals; - co->co_stacksize = stacksize; - co->co_flags = flags; - Py_INCREF(code); - co->co_code = code; - Py_INCREF(consts); - co->co_consts = consts; - Py_INCREF(names); - co->co_names = names; - Py_INCREF(varnames); - co->co_varnames = varnames; - Py_INCREF(freevars); - co->co_freevars = freevars; - Py_INCREF(cellvars); - co->co_cellvars = cellvars; - Py_INCREF(filename); - co->co_filename = filename; - Py_INCREF(name); - co->co_name = name; - co->co_firstlineno = firstlineno; - Py_INCREF(lnotab); - co->co_lnotab = lnotab; - if (PyTuple_GET_SIZE(freevars) == 0 && - PyTuple_GET_SIZE(cellvars) == 0) - co->co_flags |= CO_NOFREE; +/* + +Leave this debugging code for just a little longer. + +static void +compiler_display_symbols(PyObject *name, PyObject *symbols) +{ + PyObject *key, *value; + int flags, pos = 0; + + fprintf(stderr, "block %s\n", PyString_AS_STRING(name)); + while (PyDict_Next(symbols, &pos, &key, &value)) { + flags = PyInt_AsLong(value); + fprintf(stderr, "var %s:", PyString_AS_STRING(key)); + if (flags & DEF_GLOBAL) + fprintf(stderr, " declared_global"); + if (flags & DEF_LOCAL) + fprintf(stderr, " local"); + if (flags & DEF_PARAM) + fprintf(stderr, " param"); + if (flags & DEF_STAR) + fprintf(stderr, " stararg"); + if (flags & DEF_DOUBLESTAR) + fprintf(stderr, " starstar"); + if (flags & DEF_INTUPLE) + fprintf(stderr, " tuple"); + if (flags & DEF_FREE) + fprintf(stderr, " free"); + if (flags & DEF_FREE_GLOBAL) + fprintf(stderr, " global"); + if (flags & DEF_FREE_CLASS) + fprintf(stderr, " free/class"); + if (flags & DEF_IMPORT) + fprintf(stderr, " import"); + fprintf(stderr, "\n"); } - return co; + fprintf(stderr, "\n"); } - - -/* Data structure used internally */ - -/* The compiler uses two passes to generate bytecodes. The first pass - builds the symbol table. The second pass generates the bytecode. - - The first pass uses a single symtable struct. The second pass uses - a compiling struct for each code block. The compiling structs - share a reference to the symtable. - - The two passes communicate via symtable_load_symbols() and via - is_local() and is_global(). The former initializes several slots - in the compiling struct: c_varnames, c_locals, c_nlocals, - c_argcount, c_globals, and c_flags. */ -/* All about c_lnotab. - -c_lnotab is an array of unsigned bytes disguised as a Python string. Since -version 2.3, SET_LINENO opcodes are never generated and bytecode offsets are -mapped to source code line #s via c_lnotab instead. - -The array is conceptually a list of - (bytecode offset increment, line number increment) -pairs. The details are important and delicate, best illustrated by example: - - byte code offset source code line number - 0 1 - 6 2 - 50 7 - 350 307 - 361 308 - -The first trick is that these numbers aren't stored, only the increments -from one row to the next (this doesn't really work, but it's a start): - - 0, 1, 6, 1, 44, 5, 300, 300, 11, 1 - -The second trick is that an unsigned byte can't hold negative values, or -values larger than 255, so (a) there's a deep assumption that byte code -offsets and their corresponding line #s both increase monotonically, and (b) -if at least one column jumps by more than 255 from one row to the next, more -than one pair is written to the table. In case #b, there's no way to know -from looking at the table later how many were written. That's the delicate -part. A user of c_lnotab desiring to find the source line number -corresponding to a bytecode address A should do something like this - - lineno = addr = 0 - for addr_incr, line_incr in c_lnotab: - addr += addr_incr - if addr > A: - return lineno - lineno += line_incr - -In order for this to work, when the addr field increments by more than 255, -the line # increment in each pair generated must be 0 until the remaining addr -increment is < 256. So, in the example above, com_set_lineno should not (as -was actually done until 2.2) expand 300, 300 to 255, 255, 45, 45, but to -255, 0, 45, 255, 0, 45. -*/ - -struct compiling { - PyObject *c_code; /* string */ - PyObject *c_consts; /* list of objects */ - PyObject *c_const_dict; /* inverse of c_consts */ - PyObject *c_names; /* list of strings (names) */ - PyObject *c_name_dict; /* inverse of c_names */ - PyObject *c_globals; /* dictionary (value=None or True) */ - PyObject *c_locals; /* dictionary (value=localID) */ - PyObject *c_varnames; /* list (inverse of c_locals) */ - PyObject *c_freevars; /* dictionary (value=None) */ - PyObject *c_cellvars; /* dictionary */ - int c_nlocals; /* index of next local */ - int c_argcount; /* number of top-level arguments */ - int c_flags; /* same as co_flags */ - int c_nexti; /* index into c_code */ - int c_errors; /* counts errors occurred */ - int c_infunction; /* set when compiling a function */ - int c_interactive; /* generating code for interactive command */ - int c_loops; /* counts nested loops */ - int c_begin; /* begin of current loop, for 'continue' */ - int c_block[CO_MAXBLOCKS]; /* stack of block types */ - int c_nblocks; /* current block stack level */ - const char *c_filename; /* filename of current node */ - char *c_name; /* name of object (e.g. function) */ - int c_lineno; /* Current line number */ - int c_stacklevel; /* Current stack level */ - int c_maxstacklevel; /* Maximum stack level */ - int c_firstlineno; - PyObject *c_lnotab; /* Table mapping address to line number */ - int c_last_addr; /* last op addr seen and recorded in lnotab */ - int c_last_line; /* last line seen and recorded in lnotab */ - int c_lnotab_next; /* current length of lnotab */ - int c_lnotab_last; /* start of last lnotab record added */ - char *c_private; /* for private name mangling */ - int c_tmpname; /* temporary local name counter */ - int c_nested; /* Is block nested funcdef or lamdef? */ - int c_closure; /* Is nested w/freevars? */ - struct symtable *c_symtable; /* pointer to module symbol table */ - PyFutureFeatures *c_future; /* pointer to module's __future__ */ - char *c_encoding; /* source encoding (a borrowed reference) */ -}; - -static int -is_free(int v) -{ - if ((v & (USE | DEF_FREE)) - && !(v & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL))) - return 1; - if (v & DEF_FREE_CLASS) - return 1; - return 0; -} - -static void -com_error(struct compiling *c, PyObject *exc, char *msg) -{ - PyObject *t = NULL, *v = NULL, *w = NULL, *line = NULL; - - if (c == NULL) { - /* Error occurred via symtable call to - is_constant_false */ - PyErr_SetString(exc, msg); - return; - } - c->c_errors++; - if (c->c_lineno < 1 || c->c_interactive) { - /* Unknown line number or interactive input */ - PyErr_SetString(exc, msg); - return; - } - v = PyString_FromString(msg); - if (v == NULL) - return; /* MemoryError, too bad */ - - line = PyErr_ProgramText(c->c_filename, c->c_lineno); - if (line == NULL) { - Py_INCREF(Py_None); - line = Py_None; - } - if (exc == PyExc_SyntaxError) { - t = Py_BuildValue("(ziOO)", c->c_filename, c->c_lineno, - Py_None, line); - if (t == NULL) - goto exit; - w = PyTuple_Pack(2, v, t); - if (w == NULL) - goto exit; - PyErr_SetObject(exc, w); - } else { - /* Make sure additional exceptions are printed with - file and line, also. */ - PyErr_SetObject(exc, v); - PyErr_SyntaxLocation(c->c_filename, c->c_lineno); - } - exit: - Py_XDECREF(t); - Py_XDECREF(v); - Py_XDECREF(w); - Py_XDECREF(line); -} - -/* Interface to the block stack */ - static void -block_push(struct compiling *c, int type) +compiler_unit_check(struct compiler_unit *u) { - if (c->c_nblocks >= CO_MAXBLOCKS) { - com_error(c, PyExc_SystemError, - "too many statically nested blocks"); - } - else { - c->c_block[c->c_nblocks++] = type; - } -} - -static void -block_pop(struct compiling *c, int type) -{ - if (c->c_nblocks > 0) - c->c_nblocks--; - if (c->c_block[c->c_nblocks] != type && c->c_errors == 0) { - com_error(c, PyExc_SystemError, "bad block pop"); + basicblock *block; + for (block = u->u_blocks; block != NULL; block = block->b_list) { + assert(block != (void *)0xcbcbcbcb); + assert(block != (void *)0xfbfbfbfb); + assert(block != (void *)0xdbdbdbdb); + if (block->b_instr != NULL) { + assert(block->b_ialloc > 0); + assert(block->b_iused > 0); + assert(block->b_ialloc >= block->b_iused); + } + else { + assert (block->b_iused == 0); + assert (block->b_ialloc == 0); + } } } -/* Prototype forward declarations */ - -static int issue_warning(const char *, const char *, int); -static int com_init(struct compiling *, const char *); -static void com_free(struct compiling *); -static void com_push(struct compiling *, int); -static void com_pop(struct compiling *, int); -static void com_done(struct compiling *); -static void com_node(struct compiling *, node *); -static void com_factor(struct compiling *, node *); -static void com_addbyte(struct compiling *, int); -static void com_addint(struct compiling *, int); -static void com_addoparg(struct compiling *, int, int); -static void com_addfwref(struct compiling *, int, int *); -static void com_backpatch(struct compiling *, int); -static int com_add(struct compiling *, PyObject *, PyObject *, PyObject *); -static int com_addconst(struct compiling *, PyObject *); -static int com_addname(struct compiling *, PyObject *); -static void com_addopname(struct compiling *, int, node *); -static void com_test(struct compiling *c, node *n); -static void com_list(struct compiling *, node *, int); -static void com_list_iter(struct compiling *, node *, node *, char *); -static void com_gen_iter(struct compiling *, node *, node *); -static int com_argdefs(struct compiling *, node *); -static void com_assign(struct compiling *, node *, int, node *); -static void com_assign_name(struct compiling *, node *, int); -static int com_make_closure(struct compiling *c, PyCodeObject *co); - -static PyCodeObject *icompile(node *, struct compiling *); -static PyCodeObject *jcompile(node *, const char *, struct compiling *, - PyCompilerFlags *); -static PyObject *parsestrplus(struct compiling*, node *); -static PyObject *parsestr(struct compiling *, char *); -static node *get_rawdocstring(node *); - -static int get_ref_type(struct compiling *, char *); - -/* symtable operations */ -static int symtable_lookup(struct symtable *st, char *name); -static struct symtable *symtable_build(node *, PyFutureFeatures *, - const char *filename); -static int symtable_load_symbols(struct compiling *); -static struct symtable *symtable_init(void); -static void symtable_enter_scope(struct symtable *, char *, int, int); -static int symtable_exit_scope(struct symtable *); -static int symtable_add_def(struct symtable *, char *, int); -static int symtable_add_def_o(struct symtable *, PyObject *, PyObject *, int); - -static void symtable_node(struct symtable *, node *); -static void symtable_funcdef(struct symtable *, node *); -static void symtable_default_args(struct symtable *, node *); -static void symtable_params(struct symtable *, node *); -static void symtable_params_fplist(struct symtable *, node *n); -static void symtable_global(struct symtable *, node *); -static void symtable_import(struct symtable *, node *); -static void symtable_assign(struct symtable *, node *, int); -static void symtable_list_comprehension(struct symtable *, node *); -static void symtable_generator_expression(struct symtable *, node *); -static void symtable_list_for(struct symtable *, node *); -static void symtable_gen_for(struct symtable *, node *, int); -static void symtable_gen_iter(struct symtable *, node *); - -static int symtable_update_free_vars(struct symtable *); -static int symtable_undo_free(struct symtable *, PyObject *, PyObject *); -static int symtable_check_global(struct symtable *, PyObject *, PyObject *); - -/* helper */ -static void -do_pad(int pad) -{ - int i; - for (i = 0; i < pad; ++i) - fprintf(stderr, " "); -} - -static void -dump(node *n, int pad, int depth) -{ - int i; - if (depth == 0) - return; - do_pad(pad); - fprintf(stderr, "%d: %s\n", TYPE(n), STR(n)); - if (depth > 0) - depth--; - for (i = 0; i < NCH(n); ++i) - dump(CHILD(n, i), pad + 1, depth); -} - -static int -com_init(struct compiling *c, const char *filename) -{ - memset((void *)c, '\0', sizeof(struct compiling)); - if ((c->c_code = PyString_FromStringAndSize((char *)NULL, - 1000)) == NULL) - goto fail; - if ((c->c_consts = PyList_New(0)) == NULL) - goto fail; - if ((c->c_const_dict = PyDict_New()) == NULL) - goto fail; - if ((c->c_names = PyList_New(0)) == NULL) - goto fail; - if ((c->c_name_dict = PyDict_New()) == NULL) - goto fail; - if ((c->c_locals = PyDict_New()) == NULL) - goto fail; - if ((c->c_lnotab = PyString_FromStringAndSize((char *)NULL, - 1000)) == NULL) - goto fail; - c->c_globals = NULL; - c->c_varnames = NULL; - c->c_freevars = NULL; - c->c_cellvars = NULL; - c->c_nlocals = 0; - c->c_argcount = 0; - c->c_flags = 0; - c->c_nexti = 0; - c->c_errors = 0; - c->c_infunction = 0; - c->c_interactive = 0; - c->c_loops = 0; - c->c_begin = 0; - c->c_nblocks = 0; - c->c_filename = filename; - c->c_name = "?"; - c->c_lineno = 0; - c->c_stacklevel = 0; - c->c_maxstacklevel = 0; - c->c_firstlineno = 0; - c->c_last_addr = 0; - c->c_last_line = 0; - c->c_lnotab_next = 0; - c->c_lnotab_last = 0; - c->c_tmpname = 0; - c->c_nested = 0; - c->c_closure = 0; - c->c_symtable = NULL; - return 1; - - fail: - com_free(c); - return 0; -} - static void -com_free(struct compiling *c) +compiler_unit_free(struct compiler_unit *u) { - Py_XDECREF(c->c_code); - Py_XDECREF(c->c_consts); - Py_XDECREF(c->c_const_dict); - Py_XDECREF(c->c_names); - Py_XDECREF(c->c_name_dict); - Py_XDECREF(c->c_globals); - Py_XDECREF(c->c_locals); - Py_XDECREF(c->c_varnames); - Py_XDECREF(c->c_freevars); - Py_XDECREF(c->c_cellvars); - Py_XDECREF(c->c_lnotab); - if (c->c_future) - PyObject_FREE((void *)c->c_future); -} + basicblock *b, *next; -static void -com_push(struct compiling *c, int n) -{ - c->c_stacklevel += n; - if (c->c_stacklevel > c->c_maxstacklevel) { - c->c_maxstacklevel = c->c_stacklevel; - /* - fprintf(stderr, "%s:%s:%d max stack nexti=%d level=%d n=%d\n", - c->c_filename, c->c_name, c->c_lineno, - c->c_nexti, c->c_stacklevel, n); - */ + compiler_unit_check(u); + b = u->u_blocks; + while (b != NULL) { + if (b->b_instr) + PyObject_Free((void *)b->b_instr); + next = b->b_list; + PyObject_Free((void *)b); + b = next; } -} - -static void -com_pop(struct compiling *c, int n) -{ - if (c->c_stacklevel < n) - c->c_stacklevel = 0; - else - c->c_stacklevel -= n; -} - -static void -com_done(struct compiling *c) -{ - if (c->c_code != NULL) - _PyString_Resize(&c->c_code, c->c_nexti); - if (c->c_lnotab != NULL) - _PyString_Resize(&c->c_lnotab, c->c_lnotab_next); + Py_XDECREF(u->u_ste); + Py_XDECREF(u->u_name); + Py_XDECREF(u->u_consts); + Py_XDECREF(u->u_names); + Py_XDECREF(u->u_varnames); + Py_XDECREF(u->u_freevars); + Py_XDECREF(u->u_cellvars); + Py_XDECREF(u->u_private); + PyObject_Free(u); } static int -com_check_size(PyObject **s, int offset) -{ - int len = PyString_GET_SIZE(*s); - if (offset >= len) - return _PyString_Resize(s, len * 2); - return 0; -} - -static void -com_addbyte(struct compiling *c, int byte) -{ - /*fprintf(stderr, "%3d: %3d\n", c->c_nexti, byte);*/ - assert(byte >= 0 && byte <= 255); - assert(c->c_code != 0); - if (com_check_size(&c->c_code, c->c_nexti)) { - c->c_errors++; - return; - } - PyString_AS_STRING(c->c_code)[c->c_nexti++] = byte; -} - -static void -com_addint(struct compiling *c, int x) +compiler_enter_scope(struct compiler *c, identifier name, void *key, + int lineno) { - com_addbyte(c, x & 0xff); - com_addbyte(c, x >> 8); /* XXX x should be positive */ -} + struct compiler_unit *u; -static void -com_add_lnotab(struct compiling *c, int addr, int line) -{ - char *p; - if (c->c_lnotab == NULL) - return; - if (com_check_size(&c->c_lnotab, c->c_lnotab_next + 2)) { - c->c_errors++; - return; + u = PyObject_Malloc(sizeof(struct compiler_unit)); + memset(u, 0, sizeof(struct compiler_unit)); + u->u_argcount = 0; + u->u_ste = PySymtable_Lookup(c->c_st, key); + if (!u->u_ste) { + compiler_unit_free(u); + return 0; } - p = PyString_AS_STRING(c->c_lnotab) + c->c_lnotab_next; - *p++ = addr; - *p++ = line; - c->c_lnotab_next += 2; -} - -static void -com_set_lineno(struct compiling *c, int lineno) -{ - c->c_lineno = lineno; - if (c->c_firstlineno == 0) { - c->c_firstlineno = c->c_last_line = lineno; + Py_INCREF(name); + u->u_name = name; + u->u_varnames = list2dict(u->u_ste->ste_varnames); + u->u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL, 0, 0); + u->u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS, + PyDict_Size(u->u_cellvars)); + + u->u_blocks = NULL; + u->u_tmpname = 0; + u->u_nfblocks = 0; + u->u_firstlineno = lineno; + u->u_lineno = 0; + u->u_lineno_set = false; + u->u_consts = PyDict_New(); + if (!u->u_consts) { + compiler_unit_free(u); + return 0; } - else { - int incr_addr = c->c_nexti - c->c_last_addr; - int incr_line = lineno - c->c_last_line; - c->c_lnotab_last = c->c_lnotab_next; - while (incr_addr > 255) { - com_add_lnotab(c, 255, 0); - incr_addr -= 255; - } - while (incr_line > 255) { - com_add_lnotab(c, incr_addr, 255); - incr_line -=255; - incr_addr = 0; - } - if (incr_addr > 0 || incr_line > 0) - com_add_lnotab(c, incr_addr, incr_line); - c->c_last_addr = c->c_nexti; - c->c_last_line = lineno; + u->u_names = PyDict_New(); + if (!u->u_names) { + compiler_unit_free(u); + return 0; } -} -static void -com_strip_lnotab(struct compiling *c) -{ - /* strip the last lnotab entry if no opcode were emitted. - * This prevents a line number to be generated on a final - * pass, like in the following example: - * - * if a: - * print 5 - * else: - * pass - * - * Without the fix, a line trace event would be generated - * on the pass even if a is true (because of the implicit - * return). - */ - if (c->c_nexti == c->c_last_addr && c->c_lnotab_last > 0) { - c->c_lnotab_next = c->c_lnotab_last; - } -} + u->u_private = NULL; -static void -com_addoparg(struct compiling *c, int op, int arg) -{ - int extended_arg = arg >> 16; - if (extended_arg){ - com_addbyte(c, EXTENDED_ARG); - com_addint(c, extended_arg); - arg &= 0xffff; + /* Push the old compiler_unit on the stack. */ + if (c->u) { + PyObject *wrapper = PyCObject_FromVoidPtr(c->u, NULL); + if (PyList_Append(c->c_stack, wrapper) < 0) { + compiler_unit_free(u); + return 0; + } + Py_DECREF(wrapper); + u->u_private = c->u->u_private; + Py_XINCREF(u->u_private); } - com_addbyte(c, op); - com_addint(c, arg); -} + c->u = u; -static void -com_addfwref(struct compiling *c, int op, int *p_anchor) -{ - /* Compile a forward reference for backpatching */ - int here; - int anchor; - com_addbyte(c, op); - here = c->c_nexti; - anchor = *p_anchor; - *p_anchor = here; - com_addint(c, anchor == 0 ? 0 : here - anchor); -} + c->c_nestlevel++; + if (compiler_use_new_block(c) < 0) + return 0; -static void -com_backpatch(struct compiling *c, int anchor) -{ - unsigned char *code = (unsigned char *) PyString_AS_STRING(c->c_code); - int target = c->c_nexti; - int dist; - int prev; - for (;;) { - /* Make the JUMP instruction at anchor point to target */ - prev = code[anchor] + (code[anchor+1] << 8); - dist = target - (anchor+2); - code[anchor] = dist & 0xff; - dist >>= 8; - code[anchor+1] = dist; - dist >>= 8; - if (dist) { - com_error(c, PyExc_SystemError, - "com_backpatch: offset too large"); - break; - } - if (!prev) - break; - anchor -= prev; - } + return 1; } -/* Handle literals and names uniformly */ - static int -com_add(struct compiling *c, PyObject *list, PyObject *dict, PyObject *v) -{ - PyObject *w, *t, *np=NULL; - long n; - - t = PyTuple_Pack(2, v, v->ob_type); - if (t == NULL) - goto fail; - w = PyDict_GetItem(dict, t); - if (w != NULL) { - n = PyInt_AsLong(w); - } else { - n = PyList_Size(list); - np = PyInt_FromLong(n); - if (np == NULL) - goto fail; - if (PyList_Append(list, v) != 0) - goto fail; - if (PyDict_SetItem(dict, t, np) != 0) - goto fail; - Py_DECREF(np); +compiler_exit_scope(struct compiler *c) +{ + int n; + PyObject *wrapper; + + c->c_nestlevel--; + compiler_unit_free(c->u); + /* Restore c->u to the parent unit. */ + n = PyList_GET_SIZE(c->c_stack) - 1; + if (n >= 0) { + wrapper = PyList_GET_ITEM(c->c_stack, n); + c->u = (struct compiler_unit *)PyCObject_AsVoidPtr(wrapper); + if (PySequence_DelItem(c->c_stack, n) < 0) + return 0; + compiler_unit_check(c->u); } - Py_DECREF(t); - return n; - fail: - Py_XDECREF(np); - Py_XDECREF(t); - c->c_errors++; - return 0; -} + else + c->u = NULL; -static int -com_addconst(struct compiling *c, PyObject *v) -{ - return com_add(c, c->c_consts, c->c_const_dict, v); + return 1; /* XXX void? */ } -static int -com_addname(struct compiling *c, PyObject *v) -{ - return com_add(c, c->c_names, c->c_name_dict, v); -} +/* Allocate a new block and return a pointer to it. + Returns NULL on error. +*/ -int -_Py_Mangle(char *p, char *name, char *buffer, size_t maxlen) +static basicblock * +compiler_new_block(struct compiler *c) { - /* Name mangling: __private becomes _classname__private. - This is independent from how the name is used. */ - size_t nlen, plen; - if (p == NULL || name == NULL || name[0] != '_' || name[1] != '_') - return 0; - nlen = strlen(name); - if (nlen+2 >= maxlen) - return 0; /* Don't mangle __extremely_long_names */ - if (name[nlen-1] == '_' && name[nlen-2] == '_') - return 0; /* Don't mangle __whatever__ */ - /* Strip leading underscores from class name */ - while (*p == '_') - p++; - if (*p == '\0') - return 0; /* Don't mangle if class is just underscores */ - plen = strlen(p); - if (plen + nlen >= maxlen) - plen = maxlen-nlen-2; /* Truncate class name if too long */ - /* buffer = "_" + p[:plen] + name # i.e. 1+plen+nlen bytes */ - buffer[0] = '_'; - strncpy(buffer+1, p, plen); - strcpy(buffer+1+plen, name); - return 1; + basicblock *b; + struct compiler_unit *u; + + u = c->u; + b = (basicblock *)PyObject_Malloc(sizeof(basicblock)); + if (b == NULL) + return NULL; + memset((void *)b, 0, sizeof(basicblock)); + assert (b->b_next == NULL); + b->b_list = u->u_blocks; + u->u_blocks = b; + return b; } static void -com_addop_name(struct compiling *c, int op, char *name) +compiler_use_block(struct compiler *c, basicblock *block) { - PyObject *v; - int i; - char buffer[MANGLE_LEN]; - - if (_Py_Mangle(c->c_private, name, buffer, sizeof(buffer))) - name = buffer; - if (name == NULL || (v = PyString_InternFromString(name)) == NULL) { - c->c_errors++; - i = 255; - } - else { - i = com_addname(c, v); - Py_DECREF(v); - } - com_addoparg(c, op, i); + assert (block != NULL); + c->u->u_curblock = block; } -#define NAME_LOCAL 0 -#define NAME_GLOBAL 1 -#define NAME_DEFAULT 2 -#define NAME_CLOSURE 3 - -static int -com_lookup_arg(PyObject *dict, PyObject *name) +static basicblock * +compiler_use_new_block(struct compiler *c) { - PyObject *v = PyDict_GetItem(dict, name); - if (v == NULL) - return -1; - else - return PyInt_AS_LONG(v); + basicblock *block = compiler_new_block(c); + if (block == NULL) + return NULL; + c->u->u_curblock = block; + return block; } -static int -none_assignment_check(struct compiling *c, char *name, int assigning) +static basicblock * +compiler_next_block(struct compiler *c) { - if (name[0] == 'N' && strcmp(name, "None") == 0) { - char *msg; - if (assigning) - msg = "assignment to None"; - else - msg = "deleting None"; - com_error(c, PyExc_SyntaxError, msg); - return -1; - } - return 0; + basicblock *block = compiler_new_block(c); + if (block == NULL) + return NULL; + c->u->u_curblock->b_next = block; + c->u->u_curblock = block; + return block; } -static void -com_addop_varname(struct compiling *c, int kind, char *name) +static basicblock * +compiler_use_next_block(struct compiler *c, basicblock *block) { - PyObject *v; - int i, reftype; - int scope = NAME_DEFAULT; - int op = STOP_CODE; - char buffer[MANGLE_LEN]; - - if (kind != VAR_LOAD && - none_assignment_check(c, name, kind == VAR_STORE)) - { - i = 255; - goto done; - } - if (_Py_Mangle(c->c_private, name, buffer, sizeof(buffer))) - name = buffer; - if (name == NULL || (v = PyString_InternFromString(name)) == NULL) { - c->c_errors++; - i = 255; - goto done; - } - - reftype = get_ref_type(c, name); - switch (reftype) { - case LOCAL: - if (c->c_symtable->st_cur->ste_type == TYPE_FUNCTION) - scope = NAME_LOCAL; - break; - case GLOBAL_EXPLICIT: - scope = NAME_GLOBAL; - break; - case GLOBAL_IMPLICIT: - if (c->c_flags & CO_OPTIMIZED) - scope = NAME_GLOBAL; - break; - case FREE: - case CELL: - scope = NAME_CLOSURE; - break; - } + assert(block != NULL); + c->u->u_curblock->b_next = block; + c->u->u_curblock = block; + return block; +} - i = com_addname(c, v); - if (scope == NAME_LOCAL) - i = com_lookup_arg(c->c_locals, v); - else if (reftype == FREE) - i = com_lookup_arg(c->c_freevars, v); - else if (reftype == CELL) - i = com_lookup_arg(c->c_cellvars, v); - if (i == -1) { - c->c_errors++; /* XXX no exception set */ - i = 255; - goto done; - } - Py_DECREF(v); +/* Returns the offset of the next instruction in the current block's + b_instr array. Resizes the b_instr as necessary. + Returns -1 on failure. + */ - switch (kind) { - case VAR_LOAD: - switch (scope) { - case NAME_LOCAL: - op = LOAD_FAST; - break; - case NAME_GLOBAL: - op = LOAD_GLOBAL; - break; - case NAME_DEFAULT: - op = LOAD_NAME; - break; - case NAME_CLOSURE: - op = LOAD_DEREF; - break; - } - break; - case VAR_STORE: - switch (scope) { - case NAME_LOCAL: - op = STORE_FAST; - break; - case NAME_GLOBAL: - op = STORE_GLOBAL; - break; - case NAME_DEFAULT: - op = STORE_NAME; - break; - case NAME_CLOSURE: - op = STORE_DEREF; - break; - } - break; - case VAR_DELETE: - switch (scope) { - case NAME_LOCAL: - op = DELETE_FAST; - break; - case NAME_GLOBAL: - op = DELETE_GLOBAL; - break; - case NAME_DEFAULT: - op = DELETE_NAME; - break; - case NAME_CLOSURE: { - char buf[500]; - PyOS_snprintf(buf, sizeof(buf), - DEL_CLOSURE_ERROR, name); - com_error(c, PyExc_SyntaxError, buf); - i = 255; - break; +static int +compiler_next_instr(struct compiler *c, basicblock *b) +{ + assert(b != NULL); + if (b->b_instr == NULL) { + b->b_instr = PyObject_Malloc(sizeof(struct instr) * + DEFAULT_BLOCK_SIZE); + if (b->b_instr == NULL) { + PyErr_NoMemory(); + return -1; } + b->b_ialloc = DEFAULT_BLOCK_SIZE; + memset((char *)b->b_instr, 0, + sizeof(struct instr) * DEFAULT_BLOCK_SIZE); + } + else if (b->b_iused == b->b_ialloc) { + size_t oldsize, newsize; + oldsize = b->b_ialloc * sizeof(struct instr); + newsize = oldsize << 1; + if (newsize == 0) { + PyErr_NoMemory(); + return -1; } - break; + b->b_ialloc <<= 1; + b->b_instr = PyObject_Realloc((void *)b->b_instr, newsize); + if (b->b_instr == NULL) + return -1; + memset((char *)b->b_instr + oldsize, 0, newsize - oldsize); } -done: - com_addoparg(c, op, i); + return b->b_iused++; } static void -com_addopname(struct compiling *c, int op, node *n) -{ - char *name; - char buffer[1000]; - /* XXX it is possible to write this code without the 1000 - chars on the total length of dotted names, I just can't be - bothered right now */ - if (TYPE(n) == STAR) - name = "*"; - else if (TYPE(n) == dotted_name) { - char *p = buffer; - int i; - name = buffer; - for (i = 0; i < NCH(n); i += 2) { - char *s = STR(CHILD(n, i)); - if (p + strlen(s) > buffer + (sizeof buffer) - 2) { - com_error(c, PyExc_MemoryError, - "dotted_name too long"); - name = NULL; - break; - } - if (p != buffer) - *p++ = '.'; - strcpy(p, s); - p = strchr(p, '\0'); - } - } - else { - REQ(n, NAME); - name = STR(n); - } - com_addop_name(c, op, name); -} - -static PyObject * -parsenumber(struct compiling *c, char *s) +compiler_set_lineno(struct compiler *c, int off) { - char *end; - long x; - double dx; -#ifndef WITHOUT_COMPLEX - int imflag; -#endif - - errno = 0; - end = s + strlen(s) - 1; -#ifndef WITHOUT_COMPLEX - imflag = *end == 'j' || *end == 'J'; -#endif - if (*end == 'l' || *end == 'L') - return PyLong_FromString(s, (char **)0, 0); - if (s[0] == '0') { - x = (long) PyOS_strtoul(s, &end, 0); - if (x < 0 && errno == 0) { - return PyLong_FromString(s, (char **)0, 0); - } - } - else - x = PyOS_strtol(s, &end, 0); - if (*end == '\0') { - if (errno != 0) - return PyLong_FromString(s, (char **)0, 0); - return PyInt_FromLong(x); - } - /* XXX Huge floats may silently fail */ -#ifndef WITHOUT_COMPLEX - if (imflag) { - Py_complex z; - z.real = 0.; - PyFPE_START_PROTECT("atof", return 0) - z.imag = PyOS_ascii_atof(s); - PyFPE_END_PROTECT(z) - return PyComplex_FromCComplex(z); - } - else -#endif - { - PyFPE_START_PROTECT("atof", return 0) - dx = PyOS_ascii_atof(s); - PyFPE_END_PROTECT(dx) - return PyFloat_FromDouble(dx); - } -} - -static PyObject * -decode_utf8(char **sPtr, char *end, char* encoding) -{ -#ifndef Py_USING_UNICODE - Py_FatalError("decode_utf8 should not be called in this build."); - return NULL; -#else - PyObject *u, *v; - char *s, *t; - t = s = *sPtr; - /* while (s < end && *s != '\\') s++; */ /* inefficient for u".." */ - while (s < end && (*s & 0x80)) s++; - *sPtr = s; - u = PyUnicode_DecodeUTF8(t, s - t, NULL); - if (u == NULL) - return NULL; - v = PyUnicode_AsEncodedString(u, encoding, NULL); - Py_DECREF(u); - return v; -#endif + basicblock *b; + if (c->u->u_lineno_set) + return; + c->u->u_lineno_set = true; + b = c->u->u_curblock; + b->b_instr[off].i_lineno = c->u->u_lineno; } -/* compiler.transformer.Transformer.decode_literal depends on what - might seem like minor details of this function -- changes here - must be reflected there. */ -static PyObject * -parsestr(struct compiling *c, char *s) +static int +opcode_stack_effect(int opcode, int oparg) { - PyObject *v; - size_t len; - int quote = *s; - int rawmode = 0; - char* encoding = ((c == NULL) ? NULL : c->c_encoding); - int need_encoding; - int unicode = 0; - - if (isalpha(quote) || quote == '_') { - if (quote == 'u' || quote == 'U') { - quote = *++s; - unicode = 1; - } - if (quote == 'r' || quote == 'R') { - quote = *++s; - rawmode = 1; - } - } - if (quote != '\'' && quote != '\"') { - PyErr_BadInternalCall(); - return NULL; - } - s++; - len = strlen(s); - if (len > INT_MAX) { - com_error(c, PyExc_OverflowError, - "string to parse is too long"); - return NULL; - } - if (s[--len] != quote) { - PyErr_BadInternalCall(); - return NULL; - } - if (len >= 4 && s[0] == quote && s[1] == quote) { - s += 2; - len -= 2; - if (s[--len] != quote || s[--len] != quote) { - PyErr_BadInternalCall(); - return NULL; - } - } -#ifdef Py_USING_UNICODE - if (unicode || Py_UnicodeFlag) { - PyObject *u, *w; - char *buf; - char *p; - char *end; - if (encoding == NULL) { - buf = s; - u = NULL; - } else if (strcmp(encoding, "iso-8859-1") == 0) { - buf = s; - u = NULL; - } else { - /* "\XX" may become "\u005c\uHHLL" (12 bytes) */ - u = PyString_FromStringAndSize((char *)NULL, len * 4); - if (u == NULL) - return NULL; - p = buf = PyString_AsString(u); - end = s + len; - while (s < end) { - if (*s == '\\') { - *p++ = *s++; - if (*s & 0x80) { - strcpy(p, "u005c"); - p += 5; - } - } - if (*s & 0x80) { /* XXX inefficient */ - char *r; - int rn, i; - w = decode_utf8(&s, end, "utf-16-be"); - if (w == NULL) { - Py_DECREF(u); - return NULL; - } - r = PyString_AsString(w); - rn = PyString_Size(w); - assert(rn % 2 == 0); - for (i = 0; i < rn; i += 2) { - sprintf(p, "\\u%02x%02x", - r[i + 0] & 0xFF, - r[i + 1] & 0xFF); - p += 6; - } - Py_DECREF(w); - } else { - *p++ = *s++; - } - } - len = p - buf; - } - if (rawmode) - v = PyUnicode_DecodeRawUnicodeEscape(buf, len, NULL); - else - v = PyUnicode_DecodeUnicodeEscape(buf, len, NULL); - Py_XDECREF(u); - if (v == NULL) - PyErr_SyntaxLocation(c->c_filename, c->c_lineno); - return v; - - } -#endif - need_encoding = (encoding != NULL && - strcmp(encoding, "utf-8") != 0 && - strcmp(encoding, "iso-8859-1") != 0); - if (rawmode || strchr(s, '\\') == NULL) { - if (need_encoding) { -#ifndef Py_USING_UNICODE - /* This should not happen - we never see any other - encoding. */ - Py_FatalError("cannot deal with encodings in this build."); -#else - PyObject* u = PyUnicode_DecodeUTF8(s, len, NULL); - if (u == NULL) - return NULL; - v = PyUnicode_AsEncodedString(u, encoding, NULL); - Py_DECREF(u); - return v; -#endif - } else { - return PyString_FromStringAndSize(s, len); - } - } + switch (opcode) { + case POP_TOP: + return -1; + case ROT_TWO: + case ROT_THREE: + return 0; + case DUP_TOP: + return 1; + case ROT_FOUR: + return 0; - v = PyString_DecodeEscape(s, len, NULL, unicode, - need_encoding ? encoding : NULL); - if (v == NULL) - PyErr_SyntaxLocation(c->c_filename, c->c_lineno); - return v; -} + case UNARY_POSITIVE: + case UNARY_NEGATIVE: + case UNARY_NOT: + case UNARY_CONVERT: + case UNARY_INVERT: + return 0; -static PyObject * -parsestrplus(struct compiling* c, node *n) -{ - PyObject *v; - int i; - REQ(CHILD(n, 0), STRING); - if ((v = parsestr(c, STR(CHILD(n, 0)))) != NULL) { - /* String literal concatenation */ - for (i = 1; i < NCH(n); i++) { - PyObject *s; - s = parsestr(c, STR(CHILD(n, i))); - if (s == NULL) - goto onError; - if (PyString_Check(v) && PyString_Check(s)) { - PyString_ConcatAndDel(&v, s); - if (v == NULL) - goto onError; - } -#ifdef Py_USING_UNICODE - else { - PyObject *temp; - temp = PyUnicode_Concat(v, s); - Py_DECREF(s); - if (temp == NULL) - goto onError; - Py_DECREF(v); - v = temp; - } -#endif - } - } - return v; + case BINARY_POWER: + case BINARY_MULTIPLY: + case BINARY_DIVIDE: + case BINARY_MODULO: + case BINARY_ADD: + case BINARY_SUBTRACT: + case BINARY_SUBSCR: + case BINARY_FLOOR_DIVIDE: + case BINARY_TRUE_DIVIDE: + return -1; + case INPLACE_FLOOR_DIVIDE: + case INPLACE_TRUE_DIVIDE: + return -1; - onError: - Py_XDECREF(v); - return NULL; -} + case SLICE+0: + return 1; + case SLICE+1: + return 0; + case SLICE+2: + return 0; + case SLICE+3: + return -1; -static void -com_list_for(struct compiling *c, node *n, node *e, char *t) -{ - int anchor = 0; - int save_begin = c->c_begin; - - /* list_for: for v in expr [list_iter] */ - com_node(c, CHILD(n, 3)); /* expr */ - com_addbyte(c, GET_ITER); - c->c_begin = c->c_nexti; - com_addfwref(c, FOR_ITER, &anchor); - com_push(c, 1); - com_assign(c, CHILD(n, 1), OP_ASSIGN, NULL); - c->c_loops++; - com_list_iter(c, n, e, t); - c->c_loops--; - com_addoparg(c, JUMP_ABSOLUTE, c->c_begin); - c->c_begin = save_begin; - com_backpatch(c, anchor); - com_pop(c, 1); /* FOR_ITER has popped this */ -} + case STORE_SLICE+0: + return -2; + case STORE_SLICE+1: + return -3; + case STORE_SLICE+2: + return -3; + case STORE_SLICE+3: + return -4; -static void -com_gen_for(struct compiling *c, node *n, node *t, int is_outmost) -{ - int break_anchor = 0; - int anchor = 0; - int save_begin = c->c_begin; + case DELETE_SLICE+0: + return -1; + case DELETE_SLICE+1: + return -2; + case DELETE_SLICE+2: + return -2; + case DELETE_SLICE+3: + return -3; + + case INPLACE_ADD: + case INPLACE_SUBTRACT: + case INPLACE_MULTIPLY: + case INPLACE_DIVIDE: + case INPLACE_MODULO: + return -1; + case STORE_SUBSCR: + return -3; + case DELETE_SUBSCR: + return -2; - REQ(n, gen_for); - /* gen_for: for v in test [gen_iter] */ + case BINARY_LSHIFT: + case BINARY_RSHIFT: + case BINARY_AND: + case BINARY_XOR: + case BINARY_OR: + return -1; + case INPLACE_POWER: + return -1; + case GET_ITER: + return 0; - com_addfwref(c, SETUP_LOOP, &break_anchor); - block_push(c, SETUP_LOOP); + case PRINT_EXPR: + return -1; + case PRINT_ITEM: + return -1; + case PRINT_NEWLINE: + return 0; + case PRINT_ITEM_TO: + return -2; + case PRINT_NEWLINE_TO: + return -1; + case INPLACE_LSHIFT: + case INPLACE_RSHIFT: + case INPLACE_AND: + case INPLACE_XOR: + case INPLACE_OR: + return -1; + case BREAK_LOOP: + return 0; - if (is_outmost) { - com_addop_varname(c, VAR_LOAD, "[outmost-iterable]"); - com_push(c, 1); - } - else { - com_node(c, CHILD(n, 3)); - com_addbyte(c, GET_ITER); - } + case LOAD_LOCALS: + return 1; + case RETURN_VALUE: + return -1; + case IMPORT_STAR: + return -1; + case EXEC_STMT: + return -3; + case YIELD_VALUE: + return 0; - c->c_begin = c->c_nexti; - com_set_lineno(c, c->c_last_line); - com_addfwref(c, FOR_ITER, &anchor); - com_push(c, 1); - com_assign(c, CHILD(n, 1), OP_ASSIGN, NULL); + case POP_BLOCK: + return 0; + case END_FINALLY: + return -1; /* or -2 or -3 if exception occurred */ + case BUILD_CLASS: + return -2; - if (NCH(n) == 5) - com_gen_iter(c, CHILD(n, 4), t); - else { - com_test(c, t); - com_addbyte(c, YIELD_VALUE); - com_addbyte(c, POP_TOP); - com_pop(c, 1); - } + case STORE_NAME: + return -1; + case DELETE_NAME: + return 0; + case UNPACK_SEQUENCE: + return oparg-1; + case FOR_ITER: + return 1; - com_addoparg(c, JUMP_ABSOLUTE, c->c_begin); - c->c_begin = save_begin; + case STORE_ATTR: + return -2; + case DELETE_ATTR: + return -1; + case STORE_GLOBAL: + return -1; + case DELETE_GLOBAL: + return 0; + case DUP_TOPX: + return oparg; + case LOAD_CONST: + return 1; + case LOAD_NAME: + return 1; + case BUILD_TUPLE: + case BUILD_LIST: + return 1-oparg; + case BUILD_MAP: + return 1; + case LOAD_ATTR: + return 0; + case COMPARE_OP: + return -1; + case IMPORT_NAME: + return 0; + case IMPORT_FROM: + return 1; - com_backpatch(c, anchor); - com_pop(c, 1); /* FOR_ITER has popped this */ - com_addbyte(c, POP_BLOCK); - block_pop(c, SETUP_LOOP); - com_backpatch(c, break_anchor); -} + case JUMP_FORWARD: + case JUMP_IF_FALSE: + case JUMP_IF_TRUE: + case JUMP_ABSOLUTE: + return 0; -static void -com_list_if(struct compiling *c, node *n, node *e, char *t) -{ - int anchor = 0; - int a = 0; - /* list_iter: 'if' test [list_iter] */ - com_node(c, CHILD(n, 1)); - com_addfwref(c, JUMP_IF_FALSE, &a); - com_addbyte(c, POP_TOP); - com_pop(c, 1); - com_list_iter(c, n, e, t); - com_addfwref(c, JUMP_FORWARD, &anchor); - com_backpatch(c, a); - /* We jump here with an extra entry which we now pop */ - com_addbyte(c, POP_TOP); - com_backpatch(c, anchor); -} + case LOAD_GLOBAL: + return 1; -static void -com_gen_if(struct compiling *c, node *n, node *t) -{ - /* gen_if: 'if' test [gen_iter] */ - int anchor = 0; - int a=0; + case CONTINUE_LOOP: + return 0; + case SETUP_LOOP: + return 0; + case SETUP_EXCEPT: + case SETUP_FINALLY: + return 3; /* actually pushed by an exception */ - com_node(c, CHILD(n, 1)); - com_addfwref(c, JUMP_IF_FALSE, &a); - com_addbyte(c, POP_TOP); - com_pop(c, 1); + case LOAD_FAST: + return 1; + case STORE_FAST: + return -1; + case DELETE_FAST: + return 0; - if (NCH(n) == 3) - com_gen_iter(c, CHILD(n, 2), t); - else { - com_test(c, t); - com_addbyte(c, YIELD_VALUE); - com_addbyte(c, POP_TOP); - com_pop(c, 1); - } - com_addfwref(c, JUMP_FORWARD, &anchor); - com_backpatch(c, a); - /* We jump here with an extra entry which we now pop */ - com_addbyte(c, POP_TOP); - com_backpatch(c, anchor); -} + case RAISE_VARARGS: + return -oparg; +#define NARGS(o) (((o) % 256) + 2*((o) / 256)) + case CALL_FUNCTION: + return -NARGS(oparg); + case CALL_FUNCTION_VAR: + case CALL_FUNCTION_KW: + return -NARGS(oparg)-1; + case CALL_FUNCTION_VAR_KW: + return -NARGS(oparg)-2; +#undef NARGS + case MAKE_FUNCTION: + return -oparg; + case BUILD_SLICE: + if (oparg == 3) + return -2; + else + return -1; -static void -com_list_iter(struct compiling *c, - node *p, /* parent of list_iter node */ - node *e, /* element expression node */ - char *t /* name of result list temp local */) -{ - /* list_iter is the last child in a listmaker, list_for, or list_if */ - node *n = CHILD(p, NCH(p)-1); - if (TYPE(n) == list_iter) { - n = CHILD(n, 0); - switch (TYPE(n)) { - case list_for: - com_list_for(c, n, e, t); - break; - case list_if: - com_list_if(c, n, e, t); - break; + case MAKE_CLOSURE: + return -oparg; + case LOAD_CLOSURE: + return 1; + case LOAD_DEREF: + return 1; + case STORE_DEREF: + return -1; default: - com_error(c, PyExc_SystemError, - "invalid list_iter node type"); - } - } - else { - com_addop_varname(c, VAR_LOAD, t); - com_push(c, 1); - com_node(c, e); - com_addbyte(c, LIST_APPEND); - com_pop(c, 2); - } -} - -static void -com_gen_iter(struct compiling *c, node *n, node *t) -{ - /* gen_iter: gen_for | gen_if */ - node *ch; - REQ(n, gen_iter); - - ch = CHILD(n, 0); + fprintf(stderr, "opcode = %d\n", opcode); + Py_FatalError("opcode_stack_effect()"); - switch (TYPE(ch)) { - case gen_for: - com_gen_for(c, ch, t, 0); - break; - case gen_if: - com_gen_if(c, ch, t); - break; - default: - com_error(c, PyExc_SystemError, - "invalid gen_iter node type"); } + return 0; /* not reachable */ } -static void -com_list_comprehension(struct compiling *c, node *n) -{ - /* listmaker: test list_for */ - char tmpname[30]; - - REQ(n, listmaker); - PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", ++c->c_tmpname); - com_addoparg(c, BUILD_LIST, 0); - com_addbyte(c, DUP_TOP); /* leave the result on the stack */ - com_push(c, 2); - com_addop_varname(c, VAR_STORE, tmpname); - com_pop(c, 1); - com_list_for(c, CHILD(n, 1), CHILD(n, 0), tmpname); - com_addop_varname(c, VAR_DELETE, tmpname); - --c->c_tmpname; -} +/* Add an opcode with no argument. + Returns 0 on failure, 1 on success. +*/ -static void -com_listmaker(struct compiling *c, node *n) +static int +compiler_addop(struct compiler *c, int opcode) { - /* listmaker: test ( list_for | (',' test)* [','] ) */ - if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for) - com_list_comprehension(c, n); - else { - int len = 0; - int i; - for (i = 0; i < NCH(n); i += 2, len++) - com_node(c, CHILD(n, i)); - com_addoparg(c, BUILD_LIST, len); - com_pop(c, len-1); - } + basicblock *b; + struct instr *i; + int off; + off = compiler_next_instr(c, c->u->u_curblock); + if (off < 0) + return 0; + b = c->u->u_curblock; + i = &b->b_instr[off]; + i->i_opcode = opcode; + i->i_hasarg = 0; + if (opcode == RETURN_VALUE) + b->b_return = 1; + compiler_set_lineno(c, off); + return 1; } -static void -com_generator_expression(struct compiling *c, node *n) -{ - /* testlist_gexp: test gen_for */ - /* argument: test gen_for */ - PyCodeObject *co; - - REQ(CHILD(n, 0), test); - REQ(CHILD(n, 1), gen_for); - - symtable_enter_scope(c->c_symtable, "<genexpr>", TYPE(n), - n->n_lineno); - co = icompile(n, c); - symtable_exit_scope(c->c_symtable); - - if (co == NULL) - c->c_errors++; - else { - int closure = com_make_closure(c, co); - int i = com_addconst(c, (PyObject *)co); - - com_addoparg(c, LOAD_CONST, i); - com_push(c, 1); - if (closure) - com_addoparg(c, MAKE_CLOSURE, 0); - else - com_addoparg(c, MAKE_FUNCTION, 0); - - com_test(c, CHILD(CHILD(n, 1), 3)); - com_addbyte(c, GET_ITER); - com_addoparg(c, CALL_FUNCTION, 1); - com_pop(c, 1); - - Py_DECREF(co); +static int +compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o) +{ + PyObject *t, *v; + int arg; + + /* necessary to make sure types aren't coerced (e.g., int and long) */ + /* XXX should use: t = PyTuple_Pack(2, o, o->ob_type); */ + t = Py_BuildValue("(OO)", o, o->ob_type); + if (t == NULL) + return -1; + + v = PyDict_GetItem(dict, t); + if (!v) { + arg = PyDict_Size(dict); + v = PyInt_FromLong(arg); + if (!v) { + Py_DECREF(t); + return -1; + } + if (PyDict_SetItem(dict, t, v) < 0) { + Py_DECREF(t); + Py_DECREF(v); + return -1; + } + Py_DECREF(v); } + else + arg = PyInt_AsLong(v); + Py_DECREF(t); + return arg; } -static void -com_testlist_gexp(struct compiling *c, node *n) +static int +compiler_addop_o(struct compiler *c, int opcode, PyObject *dict, + PyObject *o) { - /* testlist_gexp: test ( gen_for | (',' test)* [','] ) */ - if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) - com_generator_expression(c, n); - else com_list(c, n, 0); + int arg = compiler_add_o(c, dict, o); + if (arg < 0) + return 0; + return compiler_addop_i(c, opcode, arg); } +static int +compiler_addop_name(struct compiler *c, int opcode, PyObject *dict, + PyObject *o) +{ + int arg; + PyObject *mangled = _Py_Mangle(c->u->u_private, o); + if (!mangled) + return 0; + arg = compiler_add_o(c, dict, mangled); + Py_DECREF(mangled); + if (arg < 0) + return 0; + return compiler_addop_i(c, opcode, arg); +} + +/* Add an opcode with an integer argument. + Returns 0 on failure, 1 on success. +*/ -static void -com_dictmaker(struct compiling *c, node *n) +static int +compiler_addop_i(struct compiler *c, int opcode, int oparg) { - int i; - /* dictmaker: test ':' test (',' test ':' value)* [','] */ - for (i = 0; i+2 < NCH(n); i += 4) { - /* We must arrange things just right for STORE_SUBSCR. - It wants the stack to look like (value) (dict) (key) */ - com_addbyte(c, DUP_TOP); - com_push(c, 1); - com_node(c, CHILD(n, i)); /* key */ - com_node(c, CHILD(n, i+2)); /* value */ - com_addbyte(c, ROT_THREE); - com_addbyte(c, STORE_SUBSCR); - com_pop(c, 3); - } + struct instr *i; + int off; + off = compiler_next_instr(c, c->u->u_curblock); + if (off < 0) + return 0; + i = &c->u->u_curblock->b_instr[off]; + i->i_opcode = opcode; + i->i_oparg = oparg; + i->i_hasarg = 1; + compiler_set_lineno(c, off); + return 1; } - -/* forward reference */ -static void com_yield_expr(struct compiling *c, node *n); - -static void -com_atom(struct compiling *c, node *n) +static int +compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute) { - node *ch; - PyObject *v; - int i; - REQ(n, atom); - ch = CHILD(n, 0); - switch (TYPE(ch)) { - case LPAR: - if (TYPE(CHILD(n, 1)) == RPAR) { - com_addoparg(c, BUILD_TUPLE, 0); - com_push(c, 1); - } - else - if (TYPE(CHILD(n, 1)) == yield_expr) - com_yield_expr(c, CHILD(n, 1)); - else - com_testlist_gexp(c, CHILD(n, 1)); - break; - case LSQB: /* '[' [listmaker] ']' */ - if (TYPE(CHILD(n, 1)) == RSQB) { - com_addoparg(c, BUILD_LIST, 0); - com_push(c, 1); - } - else - com_listmaker(c, CHILD(n, 1)); - break; - case LBRACE: /* '{' [dictmaker] '}' */ - com_addoparg(c, BUILD_MAP, 0); - com_push(c, 1); - if (TYPE(CHILD(n, 1)) == dictmaker) - com_dictmaker(c, CHILD(n, 1)); - break; - case BACKQUOTE: - com_node(c, CHILD(n, 1)); - com_addbyte(c, UNARY_CONVERT); - break; - case NUMBER: - if ((v = parsenumber(c, STR(ch))) == NULL) { - i = 255; - } - else { - i = com_addconst(c, v); - Py_DECREF(v); - } - com_addoparg(c, LOAD_CONST, i); - com_push(c, 1); - break; - case STRING: - v = parsestrplus(c, n); - if (v == NULL) { - c->c_errors++; - i = 255; - } - else { - i = com_addconst(c, v); - Py_DECREF(v); - } - com_addoparg(c, LOAD_CONST, i); - com_push(c, 1); - break; - case NAME: - com_addop_varname(c, VAR_LOAD, STR(ch)); - com_push(c, 1); - break; - default: - com_error(c, PyExc_SystemError, - "com_atom: unexpected node type"); - } -} + struct instr *i; + int off; -static void -com_slice(struct compiling *c, node *n, int op) -{ - if (NCH(n) == 1) { - com_addbyte(c, op); - } - else if (NCH(n) == 2) { - if (TYPE(CHILD(n, 0)) != COLON) { - com_node(c, CHILD(n, 0)); - com_addbyte(c, op+1); - } - else { - com_node(c, CHILD(n, 1)); - com_addbyte(c, op+2); - } - com_pop(c, 1); - } - else { - com_node(c, CHILD(n, 0)); - com_node(c, CHILD(n, 2)); - com_addbyte(c, op+3); - com_pop(c, 2); - } + assert(b != NULL); + off = compiler_next_instr(c, c->u->u_curblock); + if (off < 0) + return 0; + compiler_set_lineno(c, off); + i = &c->u->u_curblock->b_instr[off]; + i->i_opcode = opcode; + i->i_target = b; + i->i_hasarg = 1; + if (absolute) + i->i_jabs = 1; + else + i->i_jrel = 1; + return 1; } -static void -com_augassign_slice(struct compiling *c, node *n, int opcode, node *augn) -{ - if (NCH(n) == 1) { - com_addbyte(c, DUP_TOP); - com_push(c, 1); - com_addbyte(c, SLICE); - com_node(c, augn); - com_addbyte(c, opcode); - com_pop(c, 1); - com_addbyte(c, ROT_TWO); - com_addbyte(c, STORE_SLICE); - com_pop(c, 2); - } else if (NCH(n) == 2 && TYPE(CHILD(n, 0)) != COLON) { - com_node(c, CHILD(n, 0)); - com_addoparg(c, DUP_TOPX, 2); - com_push(c, 2); - com_addbyte(c, SLICE+1); - com_pop(c, 1); - com_node(c, augn); - com_addbyte(c, opcode); - com_pop(c, 1); - com_addbyte(c, ROT_THREE); - com_addbyte(c, STORE_SLICE+1); - com_pop(c, 3); - } else if (NCH(n) == 2) { - com_node(c, CHILD(n, 1)); - com_addoparg(c, DUP_TOPX, 2); - com_push(c, 2); - com_addbyte(c, SLICE+2); - com_pop(c, 1); - com_node(c, augn); - com_addbyte(c, opcode); - com_pop(c, 1); - com_addbyte(c, ROT_THREE); - com_addbyte(c, STORE_SLICE+2); - com_pop(c, 3); - } else { - com_node(c, CHILD(n, 0)); - com_node(c, CHILD(n, 2)); - com_addoparg(c, DUP_TOPX, 3); - com_push(c, 3); - com_addbyte(c, SLICE+3); - com_pop(c, 2); - com_node(c, augn); - com_addbyte(c, opcode); - com_pop(c, 1); - com_addbyte(c, ROT_FOUR); - com_addbyte(c, STORE_SLICE+3); - com_pop(c, 4); - } -} +/* The distinction between NEW_BLOCK and NEXT_BLOCK is subtle. (I'd + like to find better names.) NEW_BLOCK() creates a new block and sets + it as the current block. NEXT_BLOCK() also creates an implicit jump + from the current block to the new block. +*/ -static void -com_argument(struct compiling *c, node *n, PyObject **pkeywords) -{ - node *m; - REQ(n, argument); /* [test '='] test [gen_for]; really [keyword '='] test */ - if (NCH(n) == 1) { - if (*pkeywords != NULL) { - com_error(c, PyExc_SyntaxError, - "non-keyword arg after keyword arg"); - } - else { - com_node(c, CHILD(n, 0)); - } - return; - } - if (NCH(n) == 2) { - com_generator_expression(c, n); - return; - } +/* XXX The returns inside these macros make it impossible to decref + objects created in the local function. +*/ - m = n; - do { - m = CHILD(m, 0); - } while (NCH(m) == 1); - if (TYPE(m) != NAME) { - /* f(lambda x: x[0] = 3) ends up getting parsed with - * LHS test = lambda x: x[0], and RHS test = 3. - * SF bug 132313 points out that complaining about a keyword - * then is very confusing. - */ - com_error(c, PyExc_SyntaxError, - TYPE(m) == lambdef ? - "lambda cannot contain assignment" : - "keyword can't be an expression"); - } - else { - PyObject *v = PyString_InternFromString(STR(m)); - (void) none_assignment_check(c, STR(m), 1); - if (v != NULL && *pkeywords == NULL) - *pkeywords = PyDict_New(); - if (v == NULL) - c->c_errors++; - else if (*pkeywords == NULL) { - c->c_errors++; - Py_DECREF(v); - } else { - if (PyDict_GetItem(*pkeywords, v) != NULL) - com_error(c, PyExc_SyntaxError, - "duplicate keyword argument"); - else - if (PyDict_SetItem(*pkeywords, v, v) != 0) - c->c_errors++; - com_addoparg(c, LOAD_CONST, com_addconst(c, v)); - com_push(c, 1); - Py_DECREF(v); - } - } - com_node(c, CHILD(n, 2)); -} -static void -com_call_function(struct compiling *c, node *n) -{ - if (TYPE(n) == RPAR) { - com_addoparg(c, CALL_FUNCTION, 0); - } - else { - PyObject *keywords = NULL; - int i, na, nk; - int lineno = n->n_lineno; - int star_flag = 0; - int starstar_flag = 0; - int opcode; - REQ(n, arglist); - na = 0; - nk = 0; - for (i = 0; i < NCH(n); i += 2) { - node *ch = CHILD(n, i); - if (TYPE(ch) == STAR || - TYPE(ch) == DOUBLESTAR) - break; - if (ch->n_lineno != lineno) { - lineno = ch->n_lineno; - com_set_lineno(c, lineno); - } - com_argument(c, ch, &keywords); - if (keywords == NULL) - na++; - else - nk++; - } - Py_XDECREF(keywords); - while (i < NCH(n)) { - node *tok = CHILD(n, i); - node *ch = CHILD(n, i+1); - i += 3; - switch (TYPE(tok)) { - case STAR: star_flag = 1; break; - case DOUBLESTAR: starstar_flag = 1; break; - } - com_node(c, ch); - } - if (na > 255 || nk > 255) { - com_error(c, PyExc_SyntaxError, - "more than 255 arguments"); - } - if (star_flag || starstar_flag) - opcode = CALL_FUNCTION_VAR - 1 + - star_flag + (starstar_flag << 1); - else - opcode = CALL_FUNCTION; - com_addoparg(c, opcode, na | (nk << 8)); - com_pop(c, na + 2*nk + star_flag + starstar_flag); - } +#define NEW_BLOCK(C) { \ + if (compiler_use_new_block((C)) == NULL) \ + return 0; \ } -static void -com_select_member(struct compiling *c, node *n) -{ - com_addopname(c, LOAD_ATTR, n); +#define NEXT_BLOCK(C) { \ + if (compiler_next_block((C)) == NULL) \ + return 0; \ } -static void -com_sliceobj(struct compiling *c, node *n) -{ - int i=0; - int ns=2; /* number of slice arguments */ - node *ch; - - /* first argument */ - if (TYPE(CHILD(n,i)) == COLON) { - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - com_push(c, 1); - i++; - } - else { - com_node(c, CHILD(n,i)); - i++; - REQ(CHILD(n,i),COLON); - i++; - } - /* second argument */ - if (i < NCH(n) && TYPE(CHILD(n,i)) == test) { - com_node(c, CHILD(n,i)); - i++; - } - else { - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - com_push(c, 1); - } - /* remaining arguments */ - for (; i < NCH(n); i++) { - ns++; - ch=CHILD(n,i); - REQ(ch, sliceop); - if (NCH(ch) == 1) { - /* right argument of ':' missing */ - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - com_push(c, 1); - } - else - com_node(c, CHILD(ch,1)); - } - com_addoparg(c, BUILD_SLICE, ns); - com_pop(c, 1 + (ns == 3)); +#define ADDOP(C, OP) { \ + if (!compiler_addop((C), (OP))) \ + return 0; \ } -static void -com_subscript(struct compiling *c, node *n) -{ - node *ch; - REQ(n, subscript); - ch = CHILD(n,0); - /* check for rubber index */ - if (TYPE(ch) == DOT && TYPE(CHILD(n,1)) == DOT) { - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_Ellipsis)); - com_push(c, 1); - } - else { - /* check for slice */ - if ((TYPE(ch) == COLON || NCH(n) > 1)) - com_sliceobj(c, n); - else { - REQ(ch, test); - com_node(c, ch); - } - } +#define ADDOP_O(C, OP, O, TYPE) { \ + if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) \ + return 0; \ } -static void -com_subscriptlist(struct compiling *c, node *n, int assigning, node *augn) -{ - int i, op; - REQ(n, subscriptlist); - /* Check to make backward compatible slice behavior for '[i:j]' */ - if (NCH(n) == 1) { - node *sub = CHILD(n, 0); /* subscript */ - /* 'Basic' slice, should have exactly one colon. */ - if ((TYPE(CHILD(sub, 0)) == COLON - || (NCH(sub) > 1 && TYPE(CHILD(sub, 1)) == COLON)) - && (TYPE(CHILD(sub,NCH(sub)-1)) != sliceop)) - { - switch (assigning) { - case OP_DELETE: - op = DELETE_SLICE; - break; - case OP_ASSIGN: - op = STORE_SLICE; - break; - case OP_APPLY: - op = SLICE; - break; - default: - com_augassign_slice(c, sub, assigning, augn); - return; - } - com_slice(c, sub, op); - if (op == STORE_SLICE) - com_pop(c, 2); - else if (op == DELETE_SLICE) - com_pop(c, 1); - return; - } - } - /* Else normal subscriptlist. Compile each subscript. */ - for (i = 0; i < NCH(n); i += 2) - com_subscript(c, CHILD(n, i)); - /* Put multiple subscripts into a tuple */ - if (NCH(n) > 1) { - i = (NCH(n)+1) / 2; - com_addoparg(c, BUILD_TUPLE, i); - com_pop(c, i-1); - } - switch (assigning) { - case OP_DELETE: - op = DELETE_SUBSCR; - i = 2; - break; - default: - case OP_ASSIGN: - op = STORE_SUBSCR; - i = 3; - break; - case OP_APPLY: - op = BINARY_SUBSCR; - i = 1; - break; - } - if (assigning > OP_APPLY) { - com_addoparg(c, DUP_TOPX, 2); - com_push(c, 2); - com_addbyte(c, BINARY_SUBSCR); - com_pop(c, 1); - com_node(c, augn); - com_addbyte(c, assigning); - com_pop(c, 1); - com_addbyte(c, ROT_THREE); - } - com_addbyte(c, op); - com_pop(c, i); +#define ADDOP_NAME(C, OP, O, TYPE) { \ + if (!compiler_addop_name((C), (OP), (C)->u->u_ ## TYPE, (O))) \ + return 0; \ } -static void -com_apply_trailer(struct compiling *c, node *n) -{ - REQ(n, trailer); - switch (TYPE(CHILD(n, 0))) { - case LPAR: - com_call_function(c, CHILD(n, 1)); - break; - case DOT: - com_select_member(c, CHILD(n, 1)); - break; - case LSQB: - com_subscriptlist(c, CHILD(n, 1), OP_APPLY, NULL); - break; - default: - com_error(c, PyExc_SystemError, - "com_apply_trailer: unknown trailer type"); - } +#define ADDOP_I(C, OP, O) { \ + if (!compiler_addop_i((C), (OP), (O))) \ + return 0; \ } -static void -com_power(struct compiling *c, node *n) -{ - int i; - REQ(n, power); - com_atom(c, CHILD(n, 0)); - for (i = 1; i < NCH(n); i++) { - if (TYPE(CHILD(n, i)) == DOUBLESTAR) { - com_factor(c, CHILD(n, i+1)); - com_addbyte(c, BINARY_POWER); - com_pop(c, 1); - break; - } - else - com_apply_trailer(c, CHILD(n, i)); - } +#define ADDOP_JABS(C, OP, O) { \ + if (!compiler_addop_j((C), (OP), (O), 1)) \ + return 0; \ } -static void -com_invert_constant(struct compiling *c, node *n) -{ - /* Compute the inverse of int and longs and use them directly, - but be prepared to generate code for all other - possibilities (invalid numbers, floats, complex). - */ - PyObject *num, *inv = NULL; - int i; - - REQ(n, NUMBER); - num = parsenumber(c, STR(n)); - if (num == NULL) - i = 255; - else { - inv = PyNumber_Invert(num); - if (inv == NULL) { - PyErr_Clear(); - i = com_addconst(c, num); - } else { - i = com_addconst(c, inv); - Py_DECREF(inv); - } - Py_DECREF(num); - } - com_addoparg(c, LOAD_CONST, i); - com_push(c, 1); - if (num != NULL && inv == NULL) - com_addbyte(c, UNARY_INVERT); +#define ADDOP_JREL(C, OP, O) { \ + if (!compiler_addop_j((C), (OP), (O), 0)) \ + return 0; \ } -static int -is_float_zero(const char *p) -{ - int found_radix_point = 0; - int ch; - while ((ch = Py_CHARMASK(*p++)) != '\0') { - switch (ch) { - case '0': - /* no reason to believe it's not 0 -- continue */ - break; - - case 'e': case 'E': case 'j': case 'J': - /* If this was a hex constant, we already would have - returned 0 due to the 'x' or 'X', so 'e' or 'E' - must be an exponent marker, and we haven't yet - seen a non-zero digit, and it doesn't matter what - the exponent is then. For 'j' or 'J' similarly, - except that this is an imaginary 0 then. */ - return 1; - - case '.': - found_radix_point = 1; - break; +/* VISIT and VISIT_SEQ takes an ASDL type as their second argument. They use + the ASDL name to synthesize the name of the C type and the visit function. +*/ - default: - return 0; - } - } - return found_radix_point; +#define VISIT(C, TYPE, V) {\ + if (!compiler_visit_ ## TYPE((C), (V))) \ + return 0; \ } -static void -com_factor(struct compiling *c, node *n) -{ - int childtype = TYPE(CHILD(n, 0)); - node *pfactor, *ppower, *patom, *pnum; - REQ(n, factor); - /* If the unary +, -, or ~ operator is applied to a constant, - don't generate a UNARY_xxx opcode. Just store the - approriate value as a constant. If the value is negative, - extend the string containing the constant and insert a - negative in the 0th position -- unless we're doing unary minus - of a floating zero! In that case the sign is significant, but - the const dict can't distinguish +0.0 from -0.0. - */ - if ((childtype == PLUS || childtype == MINUS || childtype == TILDE) - && NCH(n) == 2 - && TYPE((pfactor = CHILD(n, 1))) == factor - && NCH(pfactor) == 1 - && TYPE((ppower = CHILD(pfactor, 0))) == power - && NCH(ppower) == 1 - && TYPE((patom = CHILD(ppower, 0))) == atom - && TYPE((pnum = CHILD(patom, 0))) == NUMBER - && !(childtype == MINUS && - (STR(pnum)[0] == '0' || is_float_zero(STR(pnum))))) { - if (childtype == TILDE) { - com_invert_constant(c, pnum); - return; - } - if (childtype == MINUS) { - char *s = PyObject_MALLOC(strlen(STR(pnum)) + 2); - if (s == NULL) { - com_error(c, PyExc_MemoryError, ""); - com_addbyte(c, 255); - return; - } - s[0] = '-'; - strcpy(s + 1, STR(pnum)); - PyObject_FREE(STR(pnum)); - STR(pnum) = s; - } - com_atom(c, patom); - } - else if (childtype == PLUS) { - com_factor(c, CHILD(n, 1)); - com_addbyte(c, UNARY_POSITIVE); - } - else if (childtype == MINUS) { - com_factor(c, CHILD(n, 1)); - com_addbyte(c, UNARY_NEGATIVE); - } - else if (childtype == TILDE) { - com_factor(c, CHILD(n, 1)); - com_addbyte(c, UNARY_INVERT); - } - else { - com_power(c, CHILD(n, 0)); - } +#define VISIT_SLICE(C, V, CTX) {\ + if (!compiler_visit_slice((C), (V), (CTX))) \ + return 0; \ } -static void -com_term(struct compiling *c, node *n) -{ - int i; - int op; - REQ(n, term); - com_factor(c, CHILD(n, 0)); - for (i = 2; i < NCH(n); i += 2) { - com_factor(c, CHILD(n, i)); - switch (TYPE(CHILD(n, i-1))) { - case STAR: - op = BINARY_MULTIPLY; - break; - case SLASH: - if (c->c_flags & CO_FUTURE_DIVISION) - op = BINARY_TRUE_DIVIDE; - else - op = BINARY_DIVIDE; - break; - case PERCENT: - op = BINARY_MODULO; - break; - case DOUBLESLASH: - op = BINARY_FLOOR_DIVIDE; - break; - default: - com_error(c, PyExc_SystemError, - "com_term: operator not *, /, // or %"); - op = 255; - } - com_addbyte(c, op); - com_pop(c, 1); - } -} - -static void -com_arith_expr(struct compiling *c, node *n) -{ - int i; - int op; - REQ(n, arith_expr); - com_term(c, CHILD(n, 0)); - for (i = 2; i < NCH(n); i += 2) { - com_term(c, CHILD(n, i)); - switch (TYPE(CHILD(n, i-1))) { - case PLUS: - op = BINARY_ADD; - break; - case MINUS: - op = BINARY_SUBTRACT; - break; - default: - com_error(c, PyExc_SystemError, - "com_arith_expr: operator not + or -"); - op = 255; - } - com_addbyte(c, op); - com_pop(c, 1); - } +#define VISIT_SEQ(C, TYPE, SEQ) { \ + int i; \ + asdl_seq *seq = (SEQ); /* avoid variable capture */ \ + for (i = 0; i < asdl_seq_LEN(seq); i++) { \ + TYPE ## _ty elt = asdl_seq_GET(seq, i); \ + if (!compiler_visit_ ## TYPE((C), elt)) \ + return 0; \ + } \ } -static void -com_shift_expr(struct compiling *c, node *n) +static int +compiler_isdocstring(stmt_ty s) { - int i; - int op; - REQ(n, shift_expr); - com_arith_expr(c, CHILD(n, 0)); - for (i = 2; i < NCH(n); i += 2) { - com_arith_expr(c, CHILD(n, i)); - switch (TYPE(CHILD(n, i-1))) { - case LEFTSHIFT: - op = BINARY_LSHIFT; - break; - case RIGHTSHIFT: - op = BINARY_RSHIFT; - break; - default: - com_error(c, PyExc_SystemError, - "com_shift_expr: operator not << or >>"); - op = 255; - } - com_addbyte(c, op); - com_pop(c, 1); - } + if (s->kind != Expr_kind) + return 0; + return s->v.Expr.value->kind == Str_kind; } -static void -com_and_expr(struct compiling *c, node *n) -{ - int i; - int op; - REQ(n, and_expr); - com_shift_expr(c, CHILD(n, 0)); - for (i = 2; i < NCH(n); i += 2) { - com_shift_expr(c, CHILD(n, i)); - if (TYPE(CHILD(n, i-1)) == AMPER) { - op = BINARY_AND; - } - else { - com_error(c, PyExc_SystemError, - "com_and_expr: operator not &"); - op = 255; - } - com_addbyte(c, op); - com_pop(c, 1); - } -} +/* Compile a sequence of statements, checking for a docstring. */ -static void -com_xor_expr(struct compiling *c, node *n) +static int +compiler_body(struct compiler *c, asdl_seq *stmts) { - int i; - int op; - REQ(n, xor_expr); - com_and_expr(c, CHILD(n, 0)); - for (i = 2; i < NCH(n); i += 2) { - com_and_expr(c, CHILD(n, i)); - if (TYPE(CHILD(n, i-1)) == CIRCUMFLEX) { - op = BINARY_XOR; - } - else { - com_error(c, PyExc_SystemError, - "com_xor_expr: operator not ^"); - op = 255; - } - com_addbyte(c, op); - com_pop(c, 1); - } -} + int i = 0; + stmt_ty st; -static void -com_expr(struct compiling *c, node *n) -{ - int i; - int op; - REQ(n, expr); - com_xor_expr(c, CHILD(n, 0)); - for (i = 2; i < NCH(n); i += 2) { - com_xor_expr(c, CHILD(n, i)); - if (TYPE(CHILD(n, i-1)) == VBAR) { - op = BINARY_OR; - } - else { - com_error(c, PyExc_SystemError, - "com_expr: expr operator not |"); - op = 255; - } - com_addbyte(c, op); - com_pop(c, 1); + if (!asdl_seq_LEN(stmts)) + return 1; + st = asdl_seq_GET(stmts, 0); + if (compiler_isdocstring(st)) { + i = 1; + VISIT(c, expr, st->v.Expr.value); + if (!compiler_nameop(c, __doc__, Store)) + return 0; } + for (; i < asdl_seq_LEN(stmts); i++) + VISIT(c, stmt, asdl_seq_GET(stmts, i)); + return 1; } -static enum cmp_op -cmp_type(node *n) +static PyCodeObject * +compiler_mod(struct compiler *c, mod_ty mod) { - REQ(n, comp_op); - /* comp_op: '<' | '>' | '>=' | '<=' | '<>' | '!=' | '==' - | 'in' | 'not' 'in' | 'is' | 'is' not' */ - if (NCH(n) == 1) { - n = CHILD(n, 0); - switch (TYPE(n)) { - case LESS: return PyCmp_LT; - case GREATER: return PyCmp_GT; - case EQEQUAL: return PyCmp_EQ; - case LESSEQUAL: return PyCmp_LE; - case GREATEREQUAL: return PyCmp_GE; - case NOTEQUAL: return PyCmp_NE; /* <> or != */ - case NAME: if (strcmp(STR(n), "in") == 0) return PyCmp_IN; - if (strcmp(STR(n), "is") == 0) return PyCmp_IS; - } + PyCodeObject *co; + int addNone = 1; + static PyObject *module; + if (!module) { + module = PyString_FromString("<module>"); + if (!module) + return NULL; } - else if (NCH(n) == 2) { - switch (TYPE(CHILD(n, 0))) { - case NAME: if (strcmp(STR(CHILD(n, 1)), "in") == 0) - return PyCmp_NOT_IN; - if (strcmp(STR(CHILD(n, 0)), "is") == 0) - return PyCmp_IS_NOT; - } + if (!compiler_enter_scope(c, module, mod, 1)) + return NULL; + switch (mod->kind) { + case Module_kind: + if (!compiler_body(c, mod->v.Module.body)) + return 0; + break; + case Interactive_kind: + c->c_interactive = 1; + VISIT_SEQ(c, stmt, mod->v.Interactive.body); + break; + case Expression_kind: + VISIT(c, expr, mod->v.Expression.body); + addNone = 0; + break; + case Suite_kind: + assert(0); /* XXX: what should we do here? */ + VISIT_SEQ(c, stmt, mod->v.Suite.body); + break; + default: + assert(0); } - return PyCmp_BAD; + co = assemble(c, addNone); + compiler_exit_scope(c); + return co; } -static void -com_comparison(struct compiling *c, node *n) -{ - int i; - enum cmp_op op; - int anchor; - REQ(n, comparison); /* comparison: expr (comp_op expr)* */ - com_expr(c, CHILD(n, 0)); - if (NCH(n) == 1) - return; - - /**************************************************************** - The following code is generated for all but the last - comparison in a chain: - - label: on stack: opcode: jump to: - - a <code to load b> - a, b DUP_TOP - a, b, b ROT_THREE - b, a, b COMPARE_OP - b, 0-or-1 JUMP_IF_FALSE L1 - b, 1 POP_TOP - b - - We are now ready to repeat this sequence for the next - comparison in the chain. - - For the last we generate: - - b <code to load c> - b, c COMPARE_OP - 0-or-1 - - If there were any jumps to L1 (i.e., there was more than one - comparison), we generate: - - 0-or-1 JUMP_FORWARD L2 - L1: b, 0 ROT_TWO - 0, b POP_TOP - 0 - L2: 0-or-1 - ****************************************************************/ - - anchor = 0; - - for (i = 2; i < NCH(n); i += 2) { - com_expr(c, CHILD(n, i)); - if (i+2 < NCH(n)) { - com_addbyte(c, DUP_TOP); - com_push(c, 1); - com_addbyte(c, ROT_THREE); - } - op = cmp_type(CHILD(n, i-1)); - if (op == PyCmp_BAD) { - com_error(c, PyExc_SystemError, - "com_comparison: unknown comparison op"); - } - com_addoparg(c, COMPARE_OP, op); - com_pop(c, 1); - if (i+2 < NCH(n)) { - com_addfwref(c, JUMP_IF_FALSE, &anchor); - com_addbyte(c, POP_TOP); - com_pop(c, 1); - } - } - - if (anchor) { - int anchor2 = 0; - com_addfwref(c, JUMP_FORWARD, &anchor2); - com_backpatch(c, anchor); - com_addbyte(c, ROT_TWO); - com_addbyte(c, POP_TOP); - com_backpatch(c, anchor2); - } -} +/* The test for LOCAL must come before the test for FREE in order to + handle classes where name is both local and free. The local var is + a method and the free var is a free var referenced within a method. +*/ -static void -com_not_test(struct compiling *c, node *n) -{ - REQ(n, not_test); /* 'not' not_test | comparison */ - if (NCH(n) == 1) { - com_comparison(c, CHILD(n, 0)); - } - else { - com_not_test(c, CHILD(n, 1)); - com_addbyte(c, UNARY_NOT); - } +static int +get_ref_type(struct compiler *c, PyObject *name) +{ + int scope = PyST_GetScope(c->u->u_ste, name); + if (scope == 0) { + char buf[350]; + PyOS_snprintf(buf, sizeof(buf), + "unknown scope for %.100s in %.100s(%s) in %s\n" + "symbols: %s\nlocals: %s\nglobals: %s\n", + PyString_AS_STRING(name), + PyString_AS_STRING(c->u->u_name), + PyObject_REPR(c->u->u_ste->ste_id), + c->c_filename, + PyObject_REPR(c->u->u_ste->ste_symbols), + PyObject_REPR(c->u->u_varnames), + PyObject_REPR(c->u->u_names) + ); + Py_FatalError(buf); + } + + return scope; } -static void -com_and_test(struct compiling *c, node *n) +static int +compiler_lookup_arg(PyObject *dict, PyObject *name) { - int i; - int anchor; - REQ(n, and_test); /* not_test ('and' not_test)* */ - anchor = 0; - i = 0; - for (;;) { - com_not_test(c, CHILD(n, i)); - if ((i += 2) >= NCH(n)) - break; - com_addfwref(c, JUMP_IF_FALSE, &anchor); - com_addbyte(c, POP_TOP); - com_pop(c, 1); - } - if (anchor) - com_backpatch(c, anchor); + PyObject *k, *v; + k = Py_BuildValue("(OO)", name, name->ob_type); + if (k == NULL) + return -1; + v = PyDict_GetItem(dict, k); + if (v == NULL) + return -1; + return PyInt_AS_LONG(v); } static int -com_make_closure(struct compiling *c, PyCodeObject *co) +compiler_make_closure(struct compiler *c, PyCodeObject *co, int args) { int i, free = PyCode_GetNumFree(co); - if (free == 0) - return 0; + if (free == 0) { + ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts); + ADDOP_I(c, MAKE_FUNCTION, args); + return 1; + } for (i = 0; i < free; ++i) { /* Bypass com_addop_varname because it will generate LOAD_DEREF but LOAD_CLOSURE is needed. @@ -3243,919 +1788,385 @@ com_make_closure(struct compiling *c, PyCodeObject *co) class. It should be handled by the closure, as well as by the normal name loookup logic. */ - reftype = get_ref_type(c, PyString_AS_STRING(name)); + reftype = get_ref_type(c, name); if (reftype == CELL) - arg = com_lookup_arg(c->c_cellvars, name); + arg = compiler_lookup_arg(c->u->u_cellvars, name); else /* (reftype == FREE) */ - arg = com_lookup_arg(c->c_freevars, name); + arg = compiler_lookup_arg(c->u->u_freevars, name); if (arg == -1) { - fprintf(stderr, "lookup %s in %s %d %d\n" + printf("lookup %s in %s %d %d\n" "freevars of %s: %s\n", PyObject_REPR(name), - c->c_name, + PyString_AS_STRING(c->u->u_name), reftype, arg, PyString_AS_STRING(co->co_name), PyObject_REPR(co->co_freevars)); - Py_FatalError("com_make_closure()"); + Py_FatalError("compiler_make_closure()"); } - com_addoparg(c, LOAD_CLOSURE, arg); - + ADDOP_I(c, LOAD_CLOSURE, arg); } - com_push(c, free); - return 1; + ADDOP_I(c, BUILD_TUPLE, free); + ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts); + ADDOP_I(c, MAKE_CLOSURE, args); + return 1; } -static void -com_test(struct compiling *c, node *n) +static int +compiler_decorators(struct compiler *c, asdl_seq* decos) { - REQ(n, test); /* and_test ('or' and_test)* | lambdef */ - if (NCH(n) == 1 && TYPE(CHILD(n, 0)) == lambdef) { - PyCodeObject *co; - int i, closure; - int ndefs = com_argdefs(c, CHILD(n, 0)); - symtable_enter_scope(c->c_symtable, "lambda", lambdef, - n->n_lineno); - co = icompile(CHILD(n, 0), c); - if (co == NULL) { - c->c_errors++; - return; - } - symtable_exit_scope(c->c_symtable); - i = com_addconst(c, (PyObject *)co); - closure = com_make_closure(c, co); - com_addoparg(c, LOAD_CONST, i); - com_push(c, 1); - if (closure) { - com_addoparg(c, MAKE_CLOSURE, ndefs); - com_pop(c, PyCode_GetNumFree(co)); - } else - com_addoparg(c, MAKE_FUNCTION, ndefs); - Py_DECREF(co); - com_pop(c, ndefs); - } - else { - int anchor = 0; - int i = 0; - for (;;) { - com_and_test(c, CHILD(n, i)); - if ((i += 2) >= NCH(n)) - break; - com_addfwref(c, JUMP_IF_TRUE, &anchor); - com_addbyte(c, POP_TOP); - com_pop(c, 1); - } - if (anchor) - com_backpatch(c, anchor); + int i; + + if (!decos) + return 1; + + for (i = 0; i < asdl_seq_LEN(decos); i++) { + VISIT(c, expr, asdl_seq_GET(decos, i)); } + return 1; } -static void -com_list(struct compiling *c, node *n, int toplevel) +static int +compiler_arguments(struct compiler *c, arguments_ty args) { - /* exprlist: expr (',' expr)* [',']; likewise for testlist */ - if (NCH(n) == 1 && !toplevel) { - com_node(c, CHILD(n, 0)); - } - else { - int i; - int len; - len = (NCH(n) + 1) / 2; - for (i = 0; i < NCH(n); i += 2) - com_node(c, CHILD(n, i)); - com_addoparg(c, BUILD_TUPLE, len); - com_pop(c, len-1); + int i; + int n = asdl_seq_LEN(args->args); + /* Correctly handle nested argument lists */ + for (i = 0; i < n; i++) { + expr_ty arg = asdl_seq_GET(args->args, i); + if (arg->kind == Tuple_kind) { + PyObject *id = PyString_FromFormat(".%d", i); + if (id == NULL) { + return 0; + } + if (!compiler_nameop(c, id, Load)) { + Py_DECREF(id); + return 0; + } + Py_DECREF(id); + VISIT(c, expr, arg); + } } + return 1; } +static int +compiler_function(struct compiler *c, stmt_ty s) +{ + PyCodeObject *co; + PyObject *first_const = Py_None; + arguments_ty args = s->v.FunctionDef.args; + asdl_seq* decos = s->v.FunctionDef.decorators; + stmt_ty st; + int i, n, docstring; -/* Begin of assignment compilation */ + assert(s->kind == FunctionDef_kind); + if (!compiler_decorators(c, decos)) + return 0; + if (args->defaults) + VISIT_SEQ(c, expr, args->defaults); + if (!compiler_enter_scope(c, s->v.FunctionDef.name, (void *)s, + s->lineno)) + return 0; -static void -com_augassign_attr(struct compiling *c, node *n, int opcode, node *augn) -{ - com_addbyte(c, DUP_TOP); - com_push(c, 1); - com_addopname(c, LOAD_ATTR, n); - com_node(c, augn); - com_addbyte(c, opcode); - com_pop(c, 1); - com_addbyte(c, ROT_TWO); - com_addopname(c, STORE_ATTR, n); - com_pop(c, 2); -} + st = asdl_seq_GET(s->v.FunctionDef.body, 0); + docstring = compiler_isdocstring(st); + if (docstring) + first_const = st->v.Expr.value->v.Str.s; + if (compiler_add_o(c, c->u->u_consts, first_const) < 0) + return 0; + + /* unpack nested arguments */ + compiler_arguments(c, args); + + c->u->u_argcount = asdl_seq_LEN(args->args); + n = asdl_seq_LEN(s->v.FunctionDef.body); + /* if there was a docstring, we need to skip the first statement */ + for (i = docstring; i < n; i++) { + stmt_ty s2 = asdl_seq_GET(s->v.FunctionDef.body, i); + if (i == 0 && s2->kind == Expr_kind && + s2->v.Expr.value->kind == Str_kind) + continue; + VISIT(c, stmt, s2); + } + co = assemble(c, 1); + if (co == NULL) + return 0; + compiler_exit_scope(c); -static void -com_assign_attr(struct compiling *c, node *n, int assigning) -{ - if (none_assignment_check(c, STR(n), assigning)) - return; - com_addopname(c, assigning ? STORE_ATTR : DELETE_ATTR, n); - com_pop(c, assigning ? 2 : 1); -} + compiler_make_closure(c, co, asdl_seq_LEN(args->defaults)); -static void -com_assign_trailer(struct compiling *c, node *n, int assigning, node *augn) -{ - REQ(n, trailer); - switch (TYPE(CHILD(n, 0))) { - case LPAR: /* '(' [exprlist] ')' */ - if (assigning == OP_DELETE) - com_error(c, PyExc_SyntaxError, - "can't delete function call"); - else - com_error(c, PyExc_SyntaxError, - "can't assign to function call"); - break; - case DOT: /* '.' NAME */ - if (assigning > OP_APPLY) - com_augassign_attr(c, CHILD(n, 1), assigning, augn); - else - com_assign_attr(c, CHILD(n, 1), assigning); - break; - case LSQB: /* '[' subscriptlist ']' */ - com_subscriptlist(c, CHILD(n, 1), assigning, augn); - break; - default: - com_error(c, PyExc_SystemError, "unknown trailer type"); + for (i = 0; i < asdl_seq_LEN(decos); i++) { + ADDOP_I(c, CALL_FUNCTION, 1); } -} -static void -com_assign_sequence(struct compiling *c, node *n, int assigning) -{ - int i; - if (TYPE(n) != testlist && TYPE(n) != testlist_gexp && - TYPE(n) != listmaker) - REQ(n, exprlist); - if (assigning) { - i = (NCH(n)+1)/2; - com_addoparg(c, UNPACK_SEQUENCE, i); - com_push(c, i-1); - } - for (i = 0; i < NCH(n); i += 2) - com_assign(c, CHILD(n, i), assigning, NULL); + return compiler_nameop(c, s->v.FunctionDef.name, Store); } -static void -com_augassign_name(struct compiling *c, node *n, int opcode, node *augn) +static int +compiler_class(struct compiler *c, stmt_ty s) { - REQ(n, NAME); - com_addop_varname(c, VAR_LOAD, STR(n)); - com_push(c, 1); - com_node(c, augn); - com_addbyte(c, opcode); - com_pop(c, 1); - com_assign_name(c, n, OP_ASSIGN); -} + int n; + PyCodeObject *co; + PyObject *str; + /* push class name on stack, needed by BUILD_CLASS */ + ADDOP_O(c, LOAD_CONST, s->v.ClassDef.name, consts); + /* push the tuple of base classes on the stack */ + n = asdl_seq_LEN(s->v.ClassDef.bases); + if (n > 0) + VISIT_SEQ(c, expr, s->v.ClassDef.bases); + ADDOP_I(c, BUILD_TUPLE, n); + if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s, + s->lineno)) + return 0; + c->u->u_private = s->v.ClassDef.name; + Py_INCREF(c->u->u_private); + str = PyString_InternFromString("__name__"); + if (!str || !compiler_nameop(c, str, Load)) { + Py_XDECREF(str); + return 0; + } + + Py_DECREF(str); + str = PyString_InternFromString("__module__"); + if (!str || !compiler_nameop(c, str, Store)) { + Py_XDECREF(str); + return 0; + } + Py_DECREF(str); -static void -com_assign_name(struct compiling *c, node *n, int assigning) -{ - REQ(n, NAME); - com_addop_varname(c, assigning ? VAR_STORE : VAR_DELETE, STR(n)); - if (assigning) - com_pop(c, 1); -} + if (!compiler_body(c, s->v.ClassDef.body)) + return 0; -static void -com_assign(struct compiling *c, node *n, int assigning, node *augn) -{ - /* Loop to avoid trivial recursion */ - for (;;) { - switch (TYPE(n)) { - - case exprlist: - case testlist: - case testlist1: - case testlist_gexp: - if (NCH(n) > 1) { - if (TYPE(CHILD(n, 1)) == gen_for) { - com_error(c, PyExc_SyntaxError, - "assign to generator expression not possible"); - return; - } - if (assigning > OP_APPLY) { - com_error(c, PyExc_SyntaxError, - "augmented assign to generator expression not possible"); - return; - } - com_assign_sequence(c, n, assigning); - return; - } - n = CHILD(n, 0); - break; - case yield_expr: - com_error(c, PyExc_SyntaxError, - "assignment to yield expression not possible"); - return; - - case test: - case and_test: - case not_test: - case comparison: - case expr: - case xor_expr: - case and_expr: - case shift_expr: - case arith_expr: - case term: - case factor: - if (NCH(n) > 1) { - com_error(c, PyExc_SyntaxError, - "can't assign to operator"); - return; - } - n = CHILD(n, 0); - break; - - case power: /* atom trailer* ('**' power)* - ('+'|'-'|'~') factor | atom trailer* */ - if (TYPE(CHILD(n, 0)) != atom) { - com_error(c, PyExc_SyntaxError, - "can't assign to operator"); - return; - } - if (NCH(n) > 1) { /* trailer or exponent present */ - int i; - com_node(c, CHILD(n, 0)); - for (i = 1; i+1 < NCH(n); i++) { - if (TYPE(CHILD(n, i)) == DOUBLESTAR) { - com_error(c, PyExc_SyntaxError, - "can't assign to operator"); - return; - } - com_apply_trailer(c, CHILD(n, i)); - } /* NB i is still alive */ - com_assign_trailer(c, - CHILD(n, i), assigning, augn); - return; - } - n = CHILD(n, 0); - break; - - case atom: - switch (TYPE(CHILD(n, 0))) { - case LPAR: - n = CHILD(n, 1); - if (TYPE(n) == RPAR) { - /* XXX Should allow () = () ??? */ - com_error(c, PyExc_SyntaxError, - "can't assign to ()"); - return; - } - if (assigning > OP_APPLY) { - com_error(c, PyExc_SyntaxError, - "augmented assign to tuple literal, yield, or generator expression not possible"); - return; - } - break; - case LSQB: - n = CHILD(n, 1); - if (TYPE(n) == RSQB) { - com_error(c, PyExc_SyntaxError, - "can't assign to []"); - return; - } - if (assigning > OP_APPLY) { - com_error(c, PyExc_SyntaxError, - "augmented assign to list literal or comprehension not possible"); - return; - } - if (NCH(n) > 1 - && TYPE(CHILD(n, 1)) == list_for) { - com_error(c, PyExc_SyntaxError, - "can't assign to list comprehension"); - return; - } - com_assign_sequence(c, n, assigning); - return; - case NAME: - if (assigning > OP_APPLY) - com_augassign_name(c, CHILD(n, 0), - assigning, augn); - else - com_assign_name(c, CHILD(n, 0), - assigning); - return; - default: - com_error(c, PyExc_SyntaxError, - "can't assign to literal"); - return; - } - break; + ADDOP(c, LOAD_LOCALS); + ADDOP(c, RETURN_VALUE); + co = assemble(c, 1); + if (co == NULL) + return 0; + compiler_exit_scope(c); - case lambdef: - com_error(c, PyExc_SyntaxError, - "can't assign to lambda"); - return; - - default: - com_error(c, PyExc_SystemError, - "com_assign: bad node"); - return; - - } - } + compiler_make_closure(c, co, 0); + ADDOP_I(c, CALL_FUNCTION, 0); + ADDOP(c, BUILD_CLASS); + if (!compiler_nameop(c, s->v.ClassDef.name, Store)) + return 0; + return 1; } -static void -com_augassign(struct compiling *c, node *n) +static int +compiler_lambda(struct compiler *c, expr_ty e) { - int opcode; - - switch (STR(CHILD(CHILD(n, 1), 0))[0]) { - case '+': opcode = INPLACE_ADD; break; - case '-': opcode = INPLACE_SUBTRACT; break; - case '/': - if (STR(CHILD(CHILD(n, 1), 0))[1] == '/') - opcode = INPLACE_FLOOR_DIVIDE; - else if (c->c_flags & CO_FUTURE_DIVISION) - opcode = INPLACE_TRUE_DIVIDE; - else - opcode = INPLACE_DIVIDE; - break; - case '%': opcode = INPLACE_MODULO; break; - case '<': opcode = INPLACE_LSHIFT; break; - case '>': opcode = INPLACE_RSHIFT; break; - case '&': opcode = INPLACE_AND; break; - case '^': opcode = INPLACE_XOR; break; - case '|': opcode = INPLACE_OR; break; - case '*': - if (STR(CHILD(CHILD(n, 1), 0))[1] == '*') - opcode = INPLACE_POWER; - else - opcode = INPLACE_MULTIPLY; - break; - default: - com_error(c, PyExc_SystemError, "com_augassign: bad operator"); - return; - } - com_assign(c, CHILD(n, 0), opcode, CHILD(n, 2)); -} + PyCodeObject *co; + identifier name; + arguments_ty args = e->v.Lambda.args; + assert(e->kind == Lambda_kind); -static void -com_expr_stmt(struct compiling *c, node *n) -{ - REQ(n, expr_stmt); - /* testlist (('=' testlist)* | augassign testlist) */ - /* Forget it if we have just a doc string here */ - if (!c->c_interactive && NCH(n) == 1 && get_rawdocstring(n) != NULL) - return; - if (NCH(n) == 1) { - com_node(c, CHILD(n, NCH(n)-1)); - if (c->c_interactive) - com_addbyte(c, PRINT_EXPR); - else - com_addbyte(c, POP_TOP); - com_pop(c, 1); - } - else if (TYPE(CHILD(n,1)) == augassign) - com_augassign(c, n); - else { - int i; - com_node(c, CHILD(n, NCH(n)-1)); - for (i = 0; i < NCH(n)-2; i+=2) { - if (i+2 < NCH(n)-2) { - com_addbyte(c, DUP_TOP); - com_push(c, 1); - } - com_assign(c, CHILD(n, i), OP_ASSIGN, NULL); - } - } -} + name = PyString_InternFromString("lambda"); + if (!name) + return 0; -static void -com_assert_stmt(struct compiling *c, node *n) -{ - int a = 0; - int i; - REQ(n, assert_stmt); /* 'assert' test [',' test] */ - if (Py_OptimizeFlag) - return; - /* Generate code like - - if not <test>: - raise AssertionError [, <message>] + if (args->defaults) + VISIT_SEQ(c, expr, args->defaults); + if (!compiler_enter_scope(c, name, (void *)e, e->lineno)) + return 0; + + /* unpack nested arguments */ + compiler_arguments(c, args); + + c->u->u_argcount = asdl_seq_LEN(args->args); + VISIT(c, expr, e->v.Lambda.body); + ADDOP(c, RETURN_VALUE); + co = assemble(c, 1); + if (co == NULL) + return 0; + compiler_exit_scope(c); - where <message> is the second test, if present. - */ - com_node(c, CHILD(n, 1)); - com_addfwref(c, JUMP_IF_TRUE, &a); - com_addbyte(c, POP_TOP); - com_pop(c, 1); - /* Raise that exception! */ - com_addop_name(c, LOAD_GLOBAL, "AssertionError"); - com_push(c, 1); - i = NCH(n)/2; /* Either 2 or 4 */ - if (i > 1) - com_node(c, CHILD(n, 3)); - com_addoparg(c, RAISE_VARARGS, i); - com_pop(c, i); - /* The interpreter does not fall through */ - /* Jump ends up here */ - com_backpatch(c, a); - com_addbyte(c, POP_TOP); + compiler_make_closure(c, co, asdl_seq_LEN(args->defaults)); + Py_DECREF(name); + + return 1; } -static void -com_print_stmt(struct compiling *c, node *n) -{ - int i = 1; - node* stream = NULL; - - REQ(n, print_stmt); /* 'print' (test ',')* [test] */ - - /* are we using the extended print form? */ - if (NCH(n) >= 2 && TYPE(CHILD(n, 1)) == RIGHTSHIFT) { - stream = CHILD(n, 2); - com_node(c, stream); - /* stack: [...] => [... stream] */ - com_push(c, 1); - if (NCH(n) > 3 && TYPE(CHILD(n, 3)) == COMMA) - i = 4; - else - i = 3; - } - for (; i < NCH(n); i += 2) { - if (stream != NULL) { - com_addbyte(c, DUP_TOP); - /* stack: [stream] => [stream stream] */ - com_push(c, 1); - com_node(c, CHILD(n, i)); - /* stack: [stream stream] => [stream stream obj] */ - com_addbyte(c, ROT_TWO); - /* stack: [stream stream obj] => [stream obj stream] */ - com_addbyte(c, PRINT_ITEM_TO); - /* stack: [stream obj stream] => [stream] */ - com_pop(c, 2); +static int +compiler_print(struct compiler *c, stmt_ty s) +{ + int i, n; + bool dest; + + assert(s->kind == Print_kind); + n = asdl_seq_LEN(s->v.Print.values); + dest = false; + if (s->v.Print.dest) { + VISIT(c, expr, s->v.Print.dest); + dest = true; + } + for (i = 0; i < n; i++) { + expr_ty e = (expr_ty)asdl_seq_GET(s->v.Print.values, i); + if (dest) { + ADDOP(c, DUP_TOP); + VISIT(c, expr, e); + ADDOP(c, ROT_TWO); + ADDOP(c, PRINT_ITEM_TO); } else { - com_node(c, CHILD(n, i)); - /* stack: [...] => [... obj] */ - com_addbyte(c, PRINT_ITEM); - com_pop(c, 1); + VISIT(c, expr, e); + ADDOP(c, PRINT_ITEM); } } - /* XXX Alternatively, LOAD_CONST '\n' and then PRINT_ITEM */ - if (TYPE(CHILD(n, NCH(n)-1)) == COMMA) { - if (stream != NULL) { - /* must pop the extra stream object off the stack */ - com_addbyte(c, POP_TOP); - /* stack: [... stream] => [...] */ - com_pop(c, 1); - } - } - else { - if (stream != NULL) { - /* this consumes the last stream object on stack */ - com_addbyte(c, PRINT_NEWLINE_TO); - /* stack: [... stream] => [...] */ - com_pop(c, 1); - } + if (s->v.Print.nl) { + if (dest) + ADDOP(c, PRINT_NEWLINE_TO) else - com_addbyte(c, PRINT_NEWLINE); + ADDOP(c, PRINT_NEWLINE) } + else if (dest) + ADDOP(c, POP_TOP); + return 1; } -static void -com_return_stmt(struct compiling *c, node *n) -{ - REQ(n, return_stmt); /* 'return' [testlist] */ - if (!c->c_infunction) { - com_error(c, PyExc_SyntaxError, "'return' outside function"); - } - if (c->c_flags & CO_GENERATOR) { - if (NCH(n) > 1) { - com_error(c, PyExc_SyntaxError, - "'return' with argument inside generator"); - } - } - if (NCH(n) < 2) { - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - com_push(c, 1); - } - else - com_node(c, CHILD(n, 1)); - com_addbyte(c, RETURN_VALUE); - com_pop(c, 1); -} - -static void -com_yield_expr(struct compiling *c, node *n) +static int +compiler_if(struct compiler *c, stmt_ty s) { - REQ(n, yield_expr); /* 'yield' testlist */ - if (!c->c_infunction) { - com_error(c, PyExc_SyntaxError, "'yield' outside function"); - } - - /* for (i = 0; i < c->c_nblocks; ++i) { - if (c->c_block[i] == SETUP_FINALLY) { - com_error(c, PyExc_SyntaxError, - "'yield' not allowed in a 'try' block " - "with a 'finally' clause"); - return; - } - } */ + basicblock *end, *next; - if (NCH(n) < 2) { - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - com_push(c, 1); - } - else - com_node(c, CHILD(n, 1)); - com_addbyte(c, YIELD_VALUE); + assert(s->kind == If_kind); + end = compiler_new_block(c); + if (end == NULL) + return 0; + next = compiler_new_block(c); + if (next == NULL) + return 0; + VISIT(c, expr, s->v.If.test); + ADDOP_JREL(c, JUMP_IF_FALSE, next); + ADDOP(c, POP_TOP); + VISIT_SEQ(c, stmt, s->v.If.body); + ADDOP_JREL(c, JUMP_FORWARD, end); + compiler_use_next_block(c, next); + ADDOP(c, POP_TOP); + if (s->v.If.orelse) + VISIT_SEQ(c, stmt, s->v.If.orelse); + compiler_use_next_block(c, end); + return 1; } -static void -com_yield_stmt(struct compiling *c, node *n) +static int +compiler_for(struct compiler *c, stmt_ty s) { - REQ(n, yield_stmt); /* yield_expr */ - com_node(c, CHILD(n, 0)); - com_addbyte(c, POP_TOP); - com_pop(c, 1); -} + basicblock *start, *cleanup, *end; - -static void -com_raise_stmt(struct compiling *c, node *n) -{ - int i; - REQ(n, raise_stmt); /* 'raise' [test [',' test [',' test]]] */ - if (NCH(n) > 1) { - com_node(c, CHILD(n, 1)); - if (NCH(n) > 3) { - com_node(c, CHILD(n, 3)); - if (NCH(n) > 5) - com_node(c, CHILD(n, 5)); - } - } - i = NCH(n)/2; - com_addoparg(c, RAISE_VARARGS, i); - com_pop(c, i); + start = compiler_new_block(c); + cleanup = compiler_new_block(c); + end = compiler_new_block(c); + if (start == NULL || end == NULL || cleanup == NULL) + return 0; + ADDOP_JREL(c, SETUP_LOOP, end); + if (!compiler_push_fblock(c, LOOP, start)) + return 0; + VISIT(c, expr, s->v.For.iter); + ADDOP(c, GET_ITER); + compiler_use_next_block(c, start); + ADDOP_JREL(c, FOR_ITER, cleanup); + VISIT(c, expr, s->v.For.target); + VISIT_SEQ(c, stmt, s->v.For.body); + ADDOP_JABS(c, JUMP_ABSOLUTE, start); + compiler_use_next_block(c, cleanup); + ADDOP(c, POP_BLOCK); + compiler_pop_fblock(c, LOOP, start); + VISIT_SEQ(c, stmt, s->v.For.orelse); + compiler_use_next_block(c, end); + return 1; } -static void -com_from_import(struct compiling *c, node *n) +static int +compiler_while(struct compiler *c, stmt_ty s) { - com_addopname(c, IMPORT_FROM, CHILD(n, 0)); - com_push(c, 1); - if (NCH(n) > 1) { - if (strcmp(STR(CHILD(n, 1)), "as") != 0) { - com_error(c, PyExc_SyntaxError, "invalid syntax"); - return; - } - com_addop_varname(c, VAR_STORE, STR(CHILD(n, 2))); - } else - com_addop_varname(c, VAR_STORE, STR(CHILD(n, 0))); - com_pop(c, 1); -} + basicblock *loop, *orelse, *end, *anchor = NULL; + int constant = expr_constant(s->v.While.test); -static void -com_import_stmt(struct compiling *c, node *n) -{ - node *nn; - int i; - REQ(n, import_stmt); - n = CHILD(n, 0); - /* import_stmt: import_name | import_from */ - if (TYPE(n) == import_from) { - /* 'from' dotted_name 'import' ('*' | - '(' import_as_names ')' | import_as_names) */ - PyObject *tup; - REQ(CHILD(n, 1), dotted_name); - nn = CHILD(n, 3 + (TYPE(CHILD(n, 3)) == LPAR)); - if (TYPE(nn) == STAR) - tup = Py_BuildValue("(s)", "*"); - else { - if (TYPE(CHILD(nn, NCH(nn) - 1)) == COMMA && - TYPE(CHILD(n, 3)) != LPAR) { - com_error(c, PyExc_SyntaxError, - "trailing comma not allowed " - "without surrounding parentheses"); - return; - } - REQ(nn, import_as_names); - tup = PyTuple_New((NCH(nn) + 1) / 2); - for (i = 0; i < NCH(nn); i += 2) { - PyObject *s = PyString_FromString( - STR(CHILD(CHILD(nn, i), 0))); - if (s == NULL) { - Py_CLEAR(tup); - break; - } else - PyTuple_SET_ITEM(tup, i / 2, s); - } - if (tup == NULL) { - /* Assume that failue above was MemoryError */ - com_error(c, PyExc_MemoryError, ""); - return; - } - } - com_addoparg(c, LOAD_CONST, com_addconst(c, tup)); - Py_DECREF(tup); - com_push(c, 1); - com_addopname(c, IMPORT_NAME, CHILD(n, 1)); - if (TYPE(nn) == STAR) - com_addbyte(c, IMPORT_STAR); - else { - for (i = 0; i < NCH(nn); i += 2) - com_from_import(c, CHILD(nn, i)); - com_addbyte(c, POP_TOP); - } - com_pop(c, 1); + if (constant == 0) + return 1; + loop = compiler_new_block(c); + end = compiler_new_block(c); + if (constant == -1) { + anchor = compiler_new_block(c); + if (anchor == NULL) + return 0; } - else { - /* 'import' dotted_as_names */ - nn = CHILD(n, 1); - REQ(nn, dotted_as_names); - for (i = 0; i < NCH(nn); i += 2) { - node *subn = CHILD(nn, i); - REQ(subn, dotted_as_name); - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - com_push(c, 1); - com_addopname(c, IMPORT_NAME, CHILD(subn, 0)); - if (NCH(subn) > 1) { - int j; - if (strcmp(STR(CHILD(subn, 1)), "as") != 0) { - com_error(c, PyExc_SyntaxError, - "invalid syntax"); - return; - } - for (j=2 ; j < NCH(CHILD(subn, 0)); j += 2) - com_addopname(c, LOAD_ATTR, - CHILD(CHILD(subn, 0), - j)); - com_addop_varname(c, VAR_STORE, - STR(CHILD(subn, 2))); - } else - com_addop_varname(c, VAR_STORE, - STR(CHILD(CHILD(subn, 0), - 0))); - com_pop(c, 1); - } + if (loop == NULL || end == NULL) + return 0; + if (s->v.While.orelse) { + orelse = compiler_new_block(c); + if (orelse == NULL) + return 0; } -} + else + orelse = NULL; -static void -com_exec_stmt(struct compiling *c, node *n) -{ - REQ(n, exec_stmt); - /* exec_stmt: 'exec' expr ['in' expr [',' expr]] */ - com_node(c, CHILD(n, 1)); - if (NCH(n) >= 4) - com_node(c, CHILD(n, 3)); - else { - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - com_push(c, 1); + ADDOP_JREL(c, SETUP_LOOP, end); + compiler_use_next_block(c, loop); + if (!compiler_push_fblock(c, LOOP, loop)) + return 0; + if (constant == -1) { + VISIT(c, expr, s->v.While.test); + ADDOP_JREL(c, JUMP_IF_FALSE, anchor); + ADDOP(c, POP_TOP); } - if (NCH(n) >= 6) - com_node(c, CHILD(n, 5)); - else { - com_addbyte(c, DUP_TOP); - com_push(c, 1); + VISIT_SEQ(c, stmt, s->v.While.body); + ADDOP_JABS(c, JUMP_ABSOLUTE, loop); + + /* XXX should the two POP instructions be in a separate block + if there is no else clause ? + */ + + if (constant == -1) { + compiler_use_next_block(c, anchor); + ADDOP(c, POP_TOP); + ADDOP(c, POP_BLOCK); } - com_addbyte(c, EXEC_STMT); - com_pop(c, 3); + compiler_pop_fblock(c, LOOP, loop); + if (orelse != NULL) + VISIT_SEQ(c, stmt, s->v.While.orelse); + compiler_use_next_block(c, end); + + return 1; } static int -is_constant_false(struct compiling *c, node *n) +compiler_continue(struct compiler *c) { - PyObject *v; + static const char LOOP_ERROR_MSG[] = "'continue' not properly in loop"; int i; - /* argument c will be NULL when called from symtable_node() */ - - /* Label to avoid tail recursion */ - next: - switch (TYPE(n)) { - case suite: - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto next; - } - /* Fall through */ - case file_input: - for (i = 0; i < NCH(n); i++) { - node *ch = CHILD(n, i); - if (TYPE(ch) == stmt) { - n = ch; - goto next; - } - } + if (!c->u->u_nfblocks) + return compiler_error(c, LOOP_ERROR_MSG); + i = c->u->u_nfblocks - 1; + switch (c->u->u_fblock[i].fb_type) { + case LOOP: + ADDOP_JABS(c, JUMP_ABSOLUTE, c->u->u_fblock[i].fb_block); break; - - case stmt: - case simple_stmt: - case small_stmt: - n = CHILD(n, 0); - goto next; - - case expr_stmt: - case testlist: - case testlist1: - case test: - case and_test: - case not_test: - case comparison: - case expr: - case xor_expr: - case and_expr: - case shift_expr: - case arith_expr: - case term: - case factor: - case power: - case atom: - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto next; - } - break; - - case NAME: - if (Py_OptimizeFlag && strcmp(STR(n), "__debug__") == 0) - return 1; + case EXCEPT: + case FINALLY_TRY: + while (--i >= 0 && c->u->u_fblock[i].fb_type != LOOP) + ; + if (i == -1) + return compiler_error(c, LOOP_ERROR_MSG); + ADDOP_JABS(c, CONTINUE_LOOP, c->u->u_fblock[i].fb_block); break; - - case NUMBER: - v = parsenumber(c, STR(n)); - if (v == NULL) { - PyErr_Clear(); - break; - } - i = PyObject_IsTrue(v); - Py_DECREF(v); - return i == 0; - - case STRING: - v = parsestr(c, STR(n)); - if (v == NULL) { - PyErr_Clear(); - break; - } - i = PyObject_IsTrue(v); - Py_DECREF(v); - return i == 0; - - } - return 0; -} - - -/* Look under n for a return stmt with an expression. - * This hack is used to find illegal returns under "if 0:" blocks in - * functions already known to be generators (as determined by the symtable - * pass). - * Return the offending return node if found, else NULL. - */ -static node * -look_for_offending_return(node *n) -{ - int i; - - for (i = 0; i < NCH(n); ++i) { - node *kid = CHILD(n, i); - - switch (TYPE(kid)) { - case classdef: - case funcdef: - case lambdef: - /* Stuff in nested functions & classes doesn't - affect the code block we started in. */ - return NULL; - - case return_stmt: - if (NCH(kid) > 1) - return kid; - break; - - default: { - node *bad = look_for_offending_return(kid); - if (bad != NULL) - return bad; - } - } - } - - return NULL; -} - -static void -com_if_stmt(struct compiling *c, node *n) -{ - int i; - int anchor = 0; - REQ(n, if_stmt); - /*'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] */ - for (i = 0; i+3 < NCH(n); i+=4) { - int a = 0; - node *ch = CHILD(n, i+1); - if (is_constant_false(c, ch)) { - /* We're going to skip this block. However, if this - is a generator, we have to check the dead code - anyway to make sure there aren't any return stmts - with expressions, in the same scope. */ - if (c->c_flags & CO_GENERATOR) { - node *p = look_for_offending_return(n); - if (p != NULL) { - int savelineno = c->c_lineno; - c->c_lineno = p->n_lineno; - com_error(c, PyExc_SyntaxError, - "'return' with argument " - "inside generator"); - c->c_lineno = savelineno; - } - } - continue; - } - if (i > 0) - com_set_lineno(c, ch->n_lineno); - com_node(c, ch); - com_addfwref(c, JUMP_IF_FALSE, &a); - com_addbyte(c, POP_TOP); - com_pop(c, 1); - com_node(c, CHILD(n, i+3)); - com_addfwref(c, JUMP_FORWARD, &anchor); - com_backpatch(c, a); - /* We jump here with an extra entry which we now pop */ - com_addbyte(c, POP_TOP); + case FINALLY_END: + return compiler_error(c, + "'continue' not supported inside 'finally' clause"); } - if (i+2 < NCH(n)) - com_node(c, CHILD(n, i+2)); - if (anchor) - com_backpatch(c, anchor); -} - -static void -com_while_stmt(struct compiling *c, node *n) -{ - int break_anchor = 0; - int anchor = 0; - int save_begin = c->c_begin; - REQ(n, while_stmt); /* 'while' test ':' suite ['else' ':' suite] */ - com_addfwref(c, SETUP_LOOP, &break_anchor); - block_push(c, SETUP_LOOP); - c->c_begin = c->c_nexti; - com_set_lineno(c, n->n_lineno); - com_node(c, CHILD(n, 1)); - com_addfwref(c, JUMP_IF_FALSE, &anchor); - com_addbyte(c, POP_TOP); - com_pop(c, 1); - c->c_loops++; - com_node(c, CHILD(n, 3)); - c->c_loops--; - com_addoparg(c, JUMP_ABSOLUTE, c->c_begin); - c->c_begin = save_begin; - com_backpatch(c, anchor); - /* We jump here with one entry more on the stack */ - com_addbyte(c, POP_TOP); - com_addbyte(c, POP_BLOCK); - block_pop(c, SETUP_LOOP); - if (NCH(n) > 4) - com_node(c, CHILD(n, 6)); - com_backpatch(c, break_anchor); -} -static void -com_for_stmt(struct compiling *c, node *n) -{ - int break_anchor = 0; - int anchor = 0; - int save_begin = c->c_begin; - REQ(n, for_stmt); - /* 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] */ - com_addfwref(c, SETUP_LOOP, &break_anchor); - block_push(c, SETUP_LOOP); - com_node(c, CHILD(n, 3)); - com_addbyte(c, GET_ITER); - c->c_begin = c->c_nexti; - com_set_lineno(c, c->c_last_line); - com_addfwref(c, FOR_ITER, &anchor); - com_push(c, 1); - com_assign(c, CHILD(n, 1), OP_ASSIGN, NULL); - c->c_loops++; - com_node(c, CHILD(n, 5)); - c->c_loops--; - com_addoparg(c, JUMP_ABSOLUTE, c->c_begin); - c->c_begin = save_begin; - com_backpatch(c, anchor); - com_pop(c, 1); /* FOR_ITER has popped this */ - com_addbyte(c, POP_BLOCK); - block_pop(c, SETUP_LOOP); - if (NCH(n) > 8) - com_node(c, CHILD(n, 8)); - com_backpatch(c, break_anchor); + return 1; } -/* Code generated for "try: S finally: Sf" is as follows: +/* Code generated for "try: <body> finally: <finalbody>" is as follows: SETUP_FINALLY L - <code for S> + <code for body> POP_BLOCK - LOAD_CONST <nil> - L: <code for Sf> + LOAD_CONST <None> + L: <code for finalbody> END_FINALLY The special instructions use the block stack. Each block @@ -4180,7 +2191,37 @@ com_for_stmt(struct compiling *c, node *n) onto the value stack (and the exception condition is cleared), and the interpreter jumps to the label gotten from the block stack. - +*/ + +static int +compiler_try_finally(struct compiler *c, stmt_ty s) +{ + basicblock *body, *end; + body = compiler_new_block(c); + end = compiler_new_block(c); + if (body == NULL || end == NULL) + return 0; + + ADDOP_JREL(c, SETUP_FINALLY, end); + compiler_use_next_block(c, body); + if (!compiler_push_fblock(c, FINALLY_TRY, body)) + return 0; + VISIT_SEQ(c, stmt, s->v.TryFinally.body); + ADDOP(c, POP_BLOCK); + compiler_pop_fblock(c, FINALLY_TRY, body); + + ADDOP_O(c, LOAD_CONST, Py_None, consts); + compiler_use_next_block(c, end); + if (!compiler_push_fblock(c, FINALLY_END, end)) + return 0; + VISIT_SEQ(c, stmt, s->v.TryFinally.finalbody); + ADDOP(c, END_FINALLY); + compiler_pop_fblock(c, FINALLY_END, end); + + return 1; +} + +/* Code generated for "try: S except E1, V1: S1 except E2, V2: S2 ...": (The contents of the value stack is shown in [], with the top at the right; 'tb' is trace-back info, 'val' the exception's @@ -4214,2609 +2255,1835 @@ com_for_stmt(struct compiling *c, node *n) Of course, parts are not generated if Vi or Ei is not present. */ - -static void -com_try_except(struct compiling *c, node *n) +static int +compiler_try_except(struct compiler *c, stmt_ty s) { - int except_anchor = 0; - int end_anchor = 0; - int else_anchor = 0; - int i; - node *ch; - - com_addfwref(c, SETUP_EXCEPT, &except_anchor); - block_push(c, SETUP_EXCEPT); - com_node(c, CHILD(n, 2)); - com_addbyte(c, POP_BLOCK); - block_pop(c, SETUP_EXCEPT); - com_addfwref(c, JUMP_FORWARD, &else_anchor); - com_backpatch(c, except_anchor); - for (i = 3; - i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause; - i += 3) { - /* except_clause: 'except' [expr [',' var]] */ - if (except_anchor == 0) { - com_error(c, PyExc_SyntaxError, - "default 'except:' must be last"); - break; + basicblock *body, *orelse, *except, *end; + int i, n; + + body = compiler_new_block(c); + except = compiler_new_block(c); + orelse = compiler_new_block(c); + end = compiler_new_block(c); + if (body == NULL || except == NULL || orelse == NULL || end == NULL) + return 0; + ADDOP_JREL(c, SETUP_EXCEPT, except); + compiler_use_next_block(c, body); + if (!compiler_push_fblock(c, EXCEPT, body)) + return 0; + VISIT_SEQ(c, stmt, s->v.TryExcept.body); + ADDOP(c, POP_BLOCK); + compiler_pop_fblock(c, EXCEPT, body); + ADDOP_JREL(c, JUMP_FORWARD, orelse); + n = asdl_seq_LEN(s->v.TryExcept.handlers); + compiler_use_next_block(c, except); + for (i = 0; i < n; i++) { + excepthandler_ty handler = asdl_seq_GET( + s->v.TryExcept.handlers, i); + if (!handler->type && i < n-1) + return compiler_error(c, "default 'except:' must be last"); + except = compiler_new_block(c); + if (except == NULL) + return 0; + if (handler->type) { + ADDOP(c, DUP_TOP); + VISIT(c, expr, handler->type); + ADDOP_I(c, COMPARE_OP, PyCmp_EXC_MATCH); + ADDOP_JREL(c, JUMP_IF_FALSE, except); + ADDOP(c, POP_TOP); } - except_anchor = 0; - com_push(c, 3); /* tb, val, exc pushed by exception */ - com_set_lineno(c, ch->n_lineno); - if (NCH(ch) > 1) { - com_addbyte(c, DUP_TOP); - com_push(c, 1); - com_node(c, CHILD(ch, 1)); - com_addoparg(c, COMPARE_OP, PyCmp_EXC_MATCH); - com_pop(c, 1); - com_addfwref(c, JUMP_IF_FALSE, &except_anchor); - com_addbyte(c, POP_TOP); - com_pop(c, 1); + ADDOP(c, POP_TOP); + if (handler->name) { + VISIT(c, expr, handler->name); } - com_addbyte(c, POP_TOP); - com_pop(c, 1); - if (NCH(ch) > 3) - com_assign(c, CHILD(ch, 3), OP_ASSIGN, NULL); else { - com_addbyte(c, POP_TOP); - com_pop(c, 1); - } - com_addbyte(c, POP_TOP); - com_pop(c, 1); - com_node(c, CHILD(n, i+2)); - com_addfwref(c, JUMP_FORWARD, &end_anchor); - if (except_anchor) { - com_backpatch(c, except_anchor); - /* We come in with [tb, val, exc, 0] on the - stack; one pop and it's the same as - expected at the start of the loop */ - com_addbyte(c, POP_TOP); - } - } - /* We actually come in here with [tb, val, exc] but the - END_FINALLY will zap those and jump around. - The c_stacklevel does not reflect them so we need not pop - anything. */ - com_addbyte(c, END_FINALLY); - com_backpatch(c, else_anchor); - if (i < NCH(n)) - com_node(c, CHILD(n, i+2)); - com_backpatch(c, end_anchor); + ADDOP(c, POP_TOP); + } + ADDOP(c, POP_TOP); + VISIT_SEQ(c, stmt, handler->body); + ADDOP_JREL(c, JUMP_FORWARD, end); + compiler_use_next_block(c, except); + if (handler->type) + ADDOP(c, POP_TOP); + } + ADDOP(c, END_FINALLY); + compiler_use_next_block(c, orelse); + VISIT_SEQ(c, stmt, s->v.TryExcept.orelse); + compiler_use_next_block(c, end); + return 1; } -static void -com_try_finally(struct compiling *c, node *n) +static int +compiler_import_as(struct compiler *c, identifier name, identifier asname) { - int finally_anchor = 0; - node *ch; - - com_addfwref(c, SETUP_FINALLY, &finally_anchor); - block_push(c, SETUP_FINALLY); - com_node(c, CHILD(n, 2)); - com_addbyte(c, POP_BLOCK); - block_pop(c, SETUP_FINALLY); - block_push(c, END_FINALLY); - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - /* While the generated code pushes only one item, - the try-finally handling can enter here with - up to three items. OK, here are the details: - 3 for an exception, 2 for RETURN, 1 for BREAK. */ - com_push(c, 3); - com_backpatch(c, finally_anchor); - ch = CHILD(n, NCH(n)-1); - com_set_lineno(c, ch->n_lineno); - com_node(c, ch); - com_addbyte(c, END_FINALLY); - block_pop(c, END_FINALLY); - com_pop(c, 3); /* Matches the com_push above */ -} + /* The IMPORT_NAME opcode was already generated. This function + merely needs to bind the result to a name. -static void -com_try_stmt(struct compiling *c, node *n) -{ - REQ(n, try_stmt); - /* 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] - | 'try' ':' suite 'finally' ':' suite */ - if (TYPE(CHILD(n, 3)) != except_clause) - com_try_finally(c, n); - else - com_try_except(c, n); + If there is a dot in name, we need to split it and emit a + LOAD_ATTR for each name. + */ + const char *src = PyString_AS_STRING(name); + const char *dot = strchr(src, '.'); + if (dot) { + /* Consume the base module name to get the first attribute */ + src = dot + 1; + while (dot) { + /* NB src is only defined when dot != NULL */ + dot = strchr(src, '.'); + PyObject *attr = PyString_FromStringAndSize(src, + dot ? dot - src : strlen(src)); + ADDOP_O(c, LOAD_ATTR, attr, names); + src = dot + 1; + } + } + return compiler_nameop(c, asname, Store); } -static node * -get_rawdocstring(node *n) -{ - int i; - - /* Label to avoid tail recursion */ - next: - switch (TYPE(n)) { - - case suite: - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto next; - } - /* Fall through */ - case file_input: - for (i = 0; i < NCH(n); i++) { - node *ch = CHILD(n, i); - if (TYPE(ch) == stmt) { - n = ch; - goto next; +static int +compiler_import(struct compiler *c, stmt_ty s) +{ + /* The Import node stores a module name like a.b.c as a single + string. This is convenient for all cases except + import a.b.c as d + where we need to parse that string to extract the individual + module names. + XXX Perhaps change the representation to make this case simpler? + */ + int i, n = asdl_seq_LEN(s->v.Import.names); + for (i = 0; i < n; i++) { + alias_ty alias = asdl_seq_GET(s->v.Import.names, i); + int r; + + ADDOP_O(c, LOAD_CONST, Py_None, consts); + ADDOP_NAME(c, IMPORT_NAME, alias->name, names); + + if (alias->asname) { + return compiler_import_as(c, + alias->name, alias->asname); + } + else { + identifier tmp = alias->name; + const char *base = PyString_AS_STRING(alias->name); + char *dot = strchr(base, '.'); + if (dot) + tmp = PyString_FromStringAndSize(base, + dot - base); + r = compiler_nameop(c, tmp, Store); + if (dot) { + Py_DECREF(tmp); } + if (!r) + return r; } - break; - - case stmt: - case simple_stmt: - case small_stmt: - n = CHILD(n, 0); - goto next; - - case expr_stmt: - case testlist: - case testlist1: - case test: - case and_test: - case not_test: - case comparison: - case expr: - case xor_expr: - case and_expr: - case shift_expr: - case arith_expr: - case term: - case factor: - case power: - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto next; - } - break; - - case atom: - if (TYPE(CHILD(n, 0)) == STRING) - return n; - break; - } - return NULL; + return 1; } -static PyObject * -get_docstring(struct compiling *c, node *n) +static int +compiler_from_import(struct compiler *c, stmt_ty s) { - /* Don't generate doc-strings if run with -OO */ - if (Py_OptimizeFlag > 1) - return NULL; - n = get_rawdocstring(n); - if (n == NULL) - return NULL; - return parsestrplus(c, n); -} + int i, n = asdl_seq_LEN(s->v.ImportFrom.names); + int star = 0; -static void -com_suite(struct compiling *c, node *n) -{ - REQ(n, suite); - /* simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT */ - if (NCH(n) == 1) { - com_node(c, CHILD(n, 0)); + PyObject *names = PyTuple_New(n); + if (!names) + return 0; + + /* build up the names */ + for (i = 0; i < n; i++) { + alias_ty alias = asdl_seq_GET(s->v.ImportFrom.names, i); + Py_INCREF(alias->name); + PyTuple_SET_ITEM(names, i, alias->name); } - else { - int i; - for (i = 0; i < NCH(n) && c->c_errors == 0; i++) { - node *ch = CHILD(n, i); - if (TYPE(ch) == stmt) - com_node(c, ch); + + if (s->lineno > c->c_future->ff_lineno) { + if (!strcmp(PyString_AS_STRING(s->v.ImportFrom.module), + "__future__")) { + Py_DECREF(names); + return compiler_error(c, + "from __future__ imports must occur " + "at the beginning of the file"); + } } -} -/* ARGSUSED */ -static void -com_continue_stmt(struct compiling *c, node *n) -{ - int i = c->c_nblocks; - if (i-- > 0 && c->c_block[i] == SETUP_LOOP) { - com_addoparg(c, JUMP_ABSOLUTE, c->c_begin); - } - else if (i <= 0) { - /* at the outer level */ - com_error(c, PyExc_SyntaxError, - "'continue' not properly in loop"); - } - else { - int j; - for (j = i-1; j >= 0; --j) { - if (c->c_block[j] == SETUP_LOOP) - break; + ADDOP_O(c, LOAD_CONST, names, consts); + ADDOP_NAME(c, IMPORT_NAME, s->v.ImportFrom.module, names); + for (i = 0; i < n; i++) { + alias_ty alias = asdl_seq_GET(s->v.ImportFrom.names, i); + identifier store_name; + + if (i == 0 && *PyString_AS_STRING(alias->name) == '*') { + assert(n == 1); + ADDOP(c, IMPORT_STAR); + star = 1; + break; } - if (j >= 0) { - /* there is a loop, but something interferes */ - for (; i > j; --i) { - if (c->c_block[i] == SETUP_EXCEPT || - c->c_block[i] == SETUP_FINALLY) { - com_addoparg(c, CONTINUE_LOOP, - c->c_begin); - return; - } - if (c->c_block[i] == END_FINALLY) { - com_error(c, PyExc_SyntaxError, - "'continue' not supported inside 'finally' clause"); - return; - } - } + + ADDOP_NAME(c, IMPORT_FROM, alias->name, names); + store_name = alias->name; + if (alias->asname) + store_name = alias->asname; + + if (!compiler_nameop(c, store_name, Store)) { + Py_DECREF(names); + return 0; } - com_error(c, PyExc_SyntaxError, - "'continue' not properly in loop"); } - /* XXX Could allow it inside a 'finally' clause - XXX if we could pop the exception still on the stack */ + if (!star) + /* remove imported module */ + ADDOP(c, POP_TOP); + return 1; } -/* Return the number of default values in the argument list. - - If a non-default argument follows a default argument, set an - exception and return -1. -*/ - static int -com_argdefs(struct compiling *c, node *n) +compiler_assert(struct compiler *c, stmt_ty s) { - int i, nch, ndefs; - if (TYPE(n) == lambdef) { - /* lambdef: 'lambda' [varargslist] ':' test */ - n = CHILD(n, 1); + static PyObject *assertion_error = NULL; + basicblock *end; + + if (Py_OptimizeFlag) + return 1; + if (assertion_error == NULL) { + assertion_error = PyString_FromString("AssertionError"); + if (assertion_error == NULL) + return 0; + } + VISIT(c, expr, s->v.Assert.test); + end = compiler_new_block(c); + if (end == NULL) + return 0; + ADDOP_JREL(c, JUMP_IF_TRUE, end); + ADDOP(c, POP_TOP); + ADDOP_O(c, LOAD_GLOBAL, assertion_error, names); + if (s->v.Assert.msg) { + VISIT(c, expr, s->v.Assert.msg); + ADDOP_I(c, RAISE_VARARGS, 2); } else { - REQ(n, funcdef); - /* funcdef: [decorators] 'def' NAME parameters ':' suite */ - n = RCHILD(n, -3); - REQ(n, parameters); /* parameters: '(' [varargslist] ')' */ - n = CHILD(n, 1); + ADDOP_I(c, RAISE_VARARGS, 1); } - if (TYPE(n) != varargslist) - return 0; - /* varargslist: - (fpdef ['=' test] ',')* '*' ....... | - fpdef ['=' test] (',' fpdef ['=' test])* [','] */ - nch = NCH(n); - ndefs = 0; - for (i = 0; i < nch; i++) { - int t; - if (TYPE(CHILD(n, i)) == STAR || - TYPE(CHILD(n, i)) == DOUBLESTAR) - break; - i++; - if (i >= nch) - t = RPAR; /* Anything except EQUAL or COMMA */ + compiler_use_block(c, end); + ADDOP(c, POP_TOP); + return 1; +} + +static int +compiler_visit_stmt(struct compiler *c, stmt_ty s) +{ + int i, n; + + c->u->u_lineno = s->lineno; + c->u->u_lineno_set = false; + switch (s->kind) { + case FunctionDef_kind: + return compiler_function(c, s); + case ClassDef_kind: + return compiler_class(c, s); + case Return_kind: + if (c->u->u_ste->ste_type != FunctionBlock) + return compiler_error(c, "'return' outside function"); + if (s->v.Return.value) { + if (c->u->u_ste->ste_generator) { + return compiler_error(c, + "'return' with argument inside generator"); + } + VISIT(c, expr, s->v.Return.value); + } else - t = TYPE(CHILD(n, i)); - if (t == EQUAL) { - i++; - ndefs++; - com_node(c, CHILD(n, i)); - i++; - if (i >= nch) - break; - t = TYPE(CHILD(n, i)); + ADDOP_O(c, LOAD_CONST, Py_None, consts); + ADDOP(c, RETURN_VALUE); + break; + case Delete_kind: + VISIT_SEQ(c, expr, s->v.Delete.targets) + break; + case Assign_kind: + n = asdl_seq_LEN(s->v.Assign.targets); + VISIT(c, expr, s->v.Assign.value); + for (i = 0; i < n; i++) { + if (i < n - 1) + ADDOP(c, DUP_TOP); + VISIT(c, expr, + (expr_ty)asdl_seq_GET(s->v.Assign.targets, i)); + } + break; + case AugAssign_kind: + return compiler_augassign(c, s); + case Print_kind: + return compiler_print(c, s); + case For_kind: + return compiler_for(c, s); + case While_kind: + return compiler_while(c, s); + case If_kind: + return compiler_if(c, s); + case Raise_kind: + n = 0; + if (s->v.Raise.type) { + VISIT(c, expr, s->v.Raise.type); + n++; + if (s->v.Raise.inst) { + VISIT(c, expr, s->v.Raise.inst); + n++; + if (s->v.Raise.tback) { + VISIT(c, expr, s->v.Raise.tback); + n++; + } + } } - else { - /* Treat "(a=1, b)" as an error */ - if (ndefs) { - com_error(c, PyExc_SyntaxError, - "non-default argument follows default argument"); - return -1; + ADDOP_I(c, RAISE_VARARGS, n); + break; + case TryExcept_kind: + return compiler_try_except(c, s); + case TryFinally_kind: + return compiler_try_finally(c, s); + case Assert_kind: + return compiler_assert(c, s); + case Import_kind: + return compiler_import(c, s); + case ImportFrom_kind: + return compiler_from_import(c, s); + case Exec_kind: + VISIT(c, expr, s->v.Exec.body); + if (s->v.Exec.globals) { + VISIT(c, expr, s->v.Exec.globals); + if (s->v.Exec.locals) { + VISIT(c, expr, s->v.Exec.locals); + } else { + ADDOP(c, DUP_TOP); } + } else { + ADDOP_O(c, LOAD_CONST, Py_None, consts); + ADDOP(c, DUP_TOP); } - if (t != COMMA) - break; + ADDOP(c, EXEC_STMT); + break; + case Global_kind: + break; + case Expr_kind: + VISIT(c, expr, s->v.Expr.value); + if (c->c_interactive && c->c_nestlevel <= 1) { + ADDOP(c, PRINT_EXPR); + } + else { + ADDOP(c, POP_TOP); + } + break; + case Pass_kind: + break; + case Break_kind: + if (!c->u->u_nfblocks) + return compiler_error(c, "'break' outside loop"); + ADDOP(c, BREAK_LOOP); + break; + case Continue_kind: + return compiler_continue(c); } - return ndefs; + return 1; } -static void -com_decorator_name(struct compiling *c, node *n) -{ - /* dotted_name: NAME ('.' NAME)* */ - - int i, nch; - node *varname; - - REQ(n, dotted_name); - nch = NCH(n); - assert(nch >= 1 && nch % 2 == 1); - - varname = CHILD(n, 0); - REQ(varname, NAME); - com_addop_varname(c, VAR_LOAD, STR(varname)); - com_push(c, 1); - - for (i = 1; i < nch; i += 2) { - node *attrname; - - REQ(CHILD(n, i), DOT); - - attrname = CHILD(n, i + 1); - REQ(attrname, NAME); - com_addop_name(c, LOAD_ATTR, STR(attrname)); +static int +unaryop(unaryop_ty op) +{ + switch (op) { + case Invert: + return UNARY_INVERT; + case Not: + return UNARY_NOT; + case UAdd: + return UNARY_POSITIVE; + case USub: + return UNARY_NEGATIVE; } + return 0; } -static void -com_decorator(struct compiling *c, node *n) -{ - /* decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE */ - int nch = NCH(n); - assert(nch >= 3); - REQ(CHILD(n, 0), AT); - REQ(RCHILD(n, -1), NEWLINE); - com_decorator_name(c, CHILD(n, 1)); - - if (nch > 3) { - assert(nch == 5 || nch == 6); - REQ(CHILD(n, 2), LPAR); - REQ(RCHILD(n, -2), RPAR); - com_call_function(c, CHILD(n, 3)); +static int +binop(struct compiler *c, operator_ty op) +{ + switch (op) { + case Add: + return BINARY_ADD; + case Sub: + return BINARY_SUBTRACT; + case Mult: + return BINARY_MULTIPLY; + case Div: + if (c->c_flags && c->c_flags->cf_flags & CO_FUTURE_DIVISION) + return BINARY_TRUE_DIVIDE; + else + return BINARY_DIVIDE; + case Mod: + return BINARY_MODULO; + case Pow: + return BINARY_POWER; + case LShift: + return BINARY_LSHIFT; + case RShift: + return BINARY_RSHIFT; + case BitOr: + return BINARY_OR; + case BitXor: + return BINARY_XOR; + case BitAnd: + return BINARY_AND; + case FloorDiv: + return BINARY_FLOOR_DIVIDE; } + return 0; } static int -com_decorators(struct compiling *c, node *n) -{ - int i, nch; - - /* decorator+ */ - nch = NCH(n); - assert(nch >= 1); - - for (i = 0; i < nch; ++i) { - node *ch = CHILD(n, i); - REQ(ch, decorator); - - com_decorator(c, ch); +cmpop(cmpop_ty op) +{ + switch (op) { + case Eq: + return PyCmp_EQ; + case NotEq: + return PyCmp_NE; + case Lt: + return PyCmp_LT; + case LtE: + return PyCmp_LE; + case Gt: + return PyCmp_GT; + case GtE: + return PyCmp_GE; + case Is: + return PyCmp_IS; + case IsNot: + return PyCmp_IS_NOT; + case In: + return PyCmp_IN; + case NotIn: + return PyCmp_NOT_IN; } - - return nch; + return PyCmp_BAD; } -static void -com_funcdef(struct compiling *c, node *n) -{ - PyObject *co; - int ndefs, ndecorators; - - REQ(n, funcdef); - /* -6 -5 -4 -3 -2 -1 - funcdef: [decorators] 'def' NAME parameters ':' suite */ - - if (NCH(n) == 6) - ndecorators = com_decorators(c, CHILD(n, 0)); - else - ndecorators = 0; - - ndefs = com_argdefs(c, n); - if (ndefs < 0) - return; - symtable_enter_scope(c->c_symtable, STR(RCHILD(n, -4)), TYPE(n), - n->n_lineno); - co = (PyObject *)icompile(n, c); - symtable_exit_scope(c->c_symtable); - if (co == NULL) - c->c_errors++; - else { - int closure = com_make_closure(c, (PyCodeObject *)co); - int i = com_addconst(c, co); - com_addoparg(c, LOAD_CONST, i); - com_push(c, 1); - if (closure) - com_addoparg(c, MAKE_CLOSURE, ndefs); +static int +inplace_binop(struct compiler *c, operator_ty op) +{ + switch (op) { + case Add: + return INPLACE_ADD; + case Sub: + return INPLACE_SUBTRACT; + case Mult: + return INPLACE_MULTIPLY; + case Div: + if (c->c_flags && c->c_flags->cf_flags & CO_FUTURE_DIVISION) + return INPLACE_TRUE_DIVIDE; else - com_addoparg(c, MAKE_FUNCTION, ndefs); - com_pop(c, ndefs); - - while (ndecorators > 0) { - com_addoparg(c, CALL_FUNCTION, 1); - com_pop(c, 1); - --ndecorators; - } - - com_addop_varname(c, VAR_STORE, STR(RCHILD(n, -4))); - com_pop(c, 1); - Py_DECREF(co); - } + return INPLACE_DIVIDE; + case Mod: + return INPLACE_MODULO; + case Pow: + return INPLACE_POWER; + case LShift: + return INPLACE_LSHIFT; + case RShift: + return INPLACE_RSHIFT; + case BitOr: + return INPLACE_OR; + case BitXor: + return INPLACE_XOR; + case BitAnd: + return INPLACE_AND; + case FloorDiv: + return INPLACE_FLOOR_DIVIDE; + } + assert(0); + return 0; } -static void -com_bases(struct compiling *c, node *n) +static int +compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx) { - int i; - REQ(n, testlist); - /* testlist: test (',' test)* [','] */ - for (i = 0; i < NCH(n); i += 2) - com_node(c, CHILD(n, i)); - i = (NCH(n)+1) / 2; - com_addoparg(c, BUILD_TUPLE, i); - com_pop(c, i-1); -} + int op, scope; + enum { OP_FAST, OP_GLOBAL, OP_DEREF, OP_NAME } optype; -static void -com_classdef(struct compiling *c, node *n) -{ - int i; - PyObject *v; - PyCodeObject *co; - char *name; + PyObject *dict = c->u->u_names; + /* XXX AugStore isn't used anywhere! */ - REQ(n, classdef); - /* classdef: class NAME ['(' [testlist] ')'] ':' suite */ - if ((v = PyString_InternFromString(STR(CHILD(n, 1)))) == NULL) { - c->c_errors++; - return; - } - /* Push the class name on the stack */ - i = com_addconst(c, v); - com_addoparg(c, LOAD_CONST, i); - com_push(c, 1); - Py_DECREF(v); - /* Push the tuple of base classes on the stack */ - if (TYPE(CHILD(n, 2)) != LPAR || - TYPE(CHILD(n, 3)) == RPAR) { - com_addoparg(c, BUILD_TUPLE, 0); - com_push(c, 1); - } - else - com_bases(c, CHILD(n, 3)); - name = STR(CHILD(n, 1)); - symtable_enter_scope(c->c_symtable, name, TYPE(n), n->n_lineno); - co = icompile(n, c); - symtable_exit_scope(c->c_symtable); - if (co == NULL) - c->c_errors++; - else { - int closure = com_make_closure(c, co); - i = com_addconst(c, (PyObject *)co); - com_addoparg(c, LOAD_CONST, i); - com_push(c, 1); - if (closure) { - com_addoparg(c, MAKE_CLOSURE, 0); - com_pop(c, PyCode_GetNumFree(co)); - } else - com_addoparg(c, MAKE_FUNCTION, 0); - com_addoparg(c, CALL_FUNCTION, 0); - com_addbyte(c, BUILD_CLASS); - com_pop(c, 2); - com_addop_varname(c, VAR_STORE, STR(CHILD(n, 1))); - com_pop(c, 1); - Py_DECREF(co); + /* First check for assignment to __debug__. Param? */ + if ((ctx == Store || ctx == AugStore || ctx == Del) + && !strcmp(PyString_AS_STRING(name), "__debug__")) { + return compiler_error(c, "can not assign to __debug__"); } -} - -static void -com_node(struct compiling *c, node *n) -{ - loop: - if (c->c_errors) - return; - switch (TYPE(n)) { - - /* Definition nodes */ - - case funcdef: - com_funcdef(c, n); - break; - case classdef: - com_classdef(c, n); - break; - - /* Trivial parse tree nodes */ - - case stmt: - case small_stmt: - case flow_stmt: - n = CHILD(n, 0); - goto loop; - - case simple_stmt: - /* small_stmt (';' small_stmt)* [';'] NEWLINE */ - com_set_lineno(c, n->n_lineno); - { - int i; - for (i = 0; i < NCH(n)-1; i += 2) - com_node(c, CHILD(n, i)); - } - break; - - case compound_stmt: - com_set_lineno(c, n->n_lineno); - n = CHILD(n, 0); - goto loop; - /* Statement nodes */ - - case expr_stmt: - com_expr_stmt(c, n); - break; - case print_stmt: - com_print_stmt(c, n); - break; - case del_stmt: /* 'del' exprlist */ - com_assign(c, CHILD(n, 1), OP_DELETE, NULL); - break; - case pass_stmt: - break; - case break_stmt: - if (c->c_loops == 0) { - com_error(c, PyExc_SyntaxError, - "'break' outside loop"); - } - com_addbyte(c, BREAK_LOOP); - break; - case continue_stmt: - com_continue_stmt(c, n); - break; - case return_stmt: - com_return_stmt(c, n); - break; - case yield_stmt: - com_yield_stmt(c, n); - break; - case raise_stmt: - com_raise_stmt(c, n); - break; - case import_stmt: - com_import_stmt(c, n); - break; - case global_stmt: - break; - case exec_stmt: - com_exec_stmt(c, n); - break; - case assert_stmt: - com_assert_stmt(c, n); - break; - case if_stmt: - com_if_stmt(c, n); - break; - case while_stmt: - com_while_stmt(c, n); + op = 0; + optype = OP_NAME; + scope = PyST_GetScope(c->u->u_ste, name); + switch (scope) { + case FREE: + dict = c->u->u_freevars; + optype = OP_DEREF; break; - case for_stmt: - com_for_stmt(c, n); + case CELL: + dict = c->u->u_cellvars; + optype = OP_DEREF; break; - case try_stmt: - com_try_stmt(c, n); + case LOCAL: + if (c->u->u_ste->ste_type == FunctionBlock) + optype = OP_FAST; break; - case suite: - com_suite(c, n); + case GLOBAL_IMPLICIT: + if (!c->u->u_ste->ste_unoptimized) + optype = OP_GLOBAL; break; - - /* Expression nodes */ - - case yield_expr: - com_yield_expr(c, n); + case GLOBAL_EXPLICIT: + optype = OP_GLOBAL; break; + } - case testlist: - case testlist1: - case testlist_safe: - com_list(c, n, 0); - break; - case test: - com_test(c, n); - break; - case and_test: - com_and_test(c, n); - break; - case not_test: - com_not_test(c, n); - break; - case comparison: - com_comparison(c, n); - break; - case exprlist: - com_list(c, n, 0); - break; - case expr: - com_expr(c, n); - break; - case xor_expr: - com_xor_expr(c, n); - break; - case and_expr: - com_and_expr(c, n); - break; - case shift_expr: - com_shift_expr(c, n); - break; - case arith_expr: - com_arith_expr(c, n); - break; - case term: - com_term(c, n); - break; - case factor: - com_factor(c, n); + /* XXX Leave assert here, but handle __doc__ and the like better */ + assert(scope || PyString_AS_STRING(name)[0] == '_'); + + switch (optype) { + case OP_DEREF: + switch (ctx) { + case Load: op = LOAD_DEREF; break; + case Store: op = STORE_DEREF; break; + case AugLoad: + case AugStore: + break; + case Del: + PyErr_Format(PyExc_SyntaxError, + "can not delete variable '%s' referenced " + "in nested scope", + PyString_AS_STRING(name)); + return 0; + break; + case Param: + assert(0); /* impossible */ + } break; - case power: - com_power(c, n); + case OP_FAST: + switch (ctx) { + case Load: op = LOAD_FAST; break; + case Store: op = STORE_FAST; break; + case Del: op = DELETE_FAST; break; + case AugLoad: + case AugStore: + break; + case Param: + assert(0); /* impossible */ + } + ADDOP_O(c, op, name, varnames); + return 1; + case OP_GLOBAL: + switch (ctx) { + case Load: op = LOAD_GLOBAL; break; + case Store: op = STORE_GLOBAL; break; + case Del: op = DELETE_GLOBAL; break; + case AugLoad: + case AugStore: + break; + case Param: + assert(0); /* impossible */ + } break; - case atom: - com_atom(c, n); + case OP_NAME: + switch (ctx) { + case Load: op = LOAD_NAME; break; + case Store: op = STORE_NAME; break; + case Del: op = DELETE_NAME; break; + case AugLoad: + case AugStore: + break; + case Param: + assert(0); /* impossible */ + } break; - - default: - com_error(c, PyExc_SystemError, - "com_node: unexpected node type"); } -} - -static void com_fplist(struct compiling *, node *); -static void -com_fpdef(struct compiling *c, node *n) -{ - REQ(n, fpdef); /* fpdef: NAME | '(' fplist ')' */ - if (TYPE(CHILD(n, 0)) == LPAR) - com_fplist(c, CHILD(n, 1)); - else { - com_addop_varname(c, VAR_STORE, STR(CHILD(n, 0))); - com_pop(c, 1); - } + assert(op); + return compiler_addop_name(c, op, dict, name); } -static void -com_fplist(struct compiling *c, node *n) +static int +compiler_boolop(struct compiler *c, expr_ty e) { - REQ(n, fplist); /* fplist: fpdef (',' fpdef)* [','] */ - if (NCH(n) == 1) { - com_fpdef(c, CHILD(n, 0)); - } - else { - int i = (NCH(n)+1)/2; - com_addoparg(c, UNPACK_SEQUENCE, i); - com_push(c, i-1); - for (i = 0; i < NCH(n); i += 2) - com_fpdef(c, CHILD(n, i)); - } -} + basicblock *end; + int jumpi, i, n; + asdl_seq *s; -static void -com_arglist(struct compiling *c, node *n) -{ - int nch, i, narg; - int complex = 0; - char nbuf[30]; - REQ(n, varargslist); - /* varargslist: - (fpdef ['=' test] ',')* (fpdef ['=' test] | '*' .....) */ - nch = NCH(n); - /* Enter all arguments in table of locals */ - for (i = 0, narg = 0; i < nch; i++) { - node *ch = CHILD(n, i); - node *fp; - if (TYPE(ch) == STAR || TYPE(ch) == DOUBLESTAR) - break; - REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */ - fp = CHILD(ch, 0); - if (TYPE(fp) != NAME) { - PyOS_snprintf(nbuf, sizeof(nbuf), ".%d", i); - complex = 1; - } - narg++; - /* all name updates handled by symtable */ - if (++i >= nch) - break; - ch = CHILD(n, i); - if (TYPE(ch) == EQUAL) - i += 2; - else - REQ(ch, COMMA); - } - if (complex) { - /* Generate code for complex arguments only after - having counted the simple arguments */ - int ilocal = 0; - for (i = 0; i < nch; i++) { - node *ch = CHILD(n, i); - node *fp; - if (TYPE(ch) == STAR || TYPE(ch) == DOUBLESTAR) - break; - REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */ - fp = CHILD(ch, 0); - if (TYPE(fp) != NAME) { - com_addoparg(c, LOAD_FAST, ilocal); - com_push(c, 1); - com_fpdef(c, ch); - } - ilocal++; - if (++i >= nch) - break; - ch = CHILD(n, i); - if (TYPE(ch) == EQUAL) - i += 2; - else - REQ(ch, COMMA); - } - } + assert(e->kind == BoolOp_kind); + if (e->v.BoolOp.op == And) + jumpi = JUMP_IF_FALSE; + else + jumpi = JUMP_IF_TRUE; + end = compiler_new_block(c); + if (end < 0) + return 0; + s = e->v.BoolOp.values; + n = asdl_seq_LEN(s) - 1; + for (i = 0; i < n; ++i) { + VISIT(c, expr, asdl_seq_GET(s, i)); + ADDOP_JREL(c, jumpi, end); + ADDOP(c, POP_TOP) + } + VISIT(c, expr, asdl_seq_GET(s, n)); + compiler_use_next_block(c, end); + return 1; } -static void -com_file_input(struct compiling *c, node *n) +static int +compiler_list(struct compiler *c, expr_ty e) { - int i; - PyObject *doc; - REQ(n, file_input); /* (NEWLINE | stmt)* ENDMARKER */ - doc = get_docstring(c, n); - if (doc != NULL) { - int i = com_addconst(c, doc); - Py_DECREF(doc); - com_addoparg(c, LOAD_CONST, i); - com_push(c, 1); - com_addop_name(c, STORE_NAME, "__doc__"); - com_pop(c, 1); + int n = asdl_seq_LEN(e->v.List.elts); + if (e->v.List.ctx == Store) { + ADDOP_I(c, UNPACK_SEQUENCE, n); } - for (i = 0; i < NCH(n); i++) { - node *ch = CHILD(n, i); - if (TYPE(ch) != ENDMARKER && TYPE(ch) != NEWLINE) - com_node(c, ch); + VISIT_SEQ(c, expr, e->v.List.elts); + if (e->v.List.ctx == Load) { + ADDOP_I(c, BUILD_LIST, n); } + return 1; } -/* Top-level compile-node interface */ - -static void -compile_funcdef(struct compiling *c, node *n) +static int +compiler_tuple(struct compiler *c, expr_ty e) { - PyObject *doc; - node *ch; - REQ(n, funcdef); - /* -6 -5 -4 -3 -2 -1 - funcdef: [decorators] 'def' NAME parameters ':' suite */ - c->c_name = STR(RCHILD(n, -4)); - doc = get_docstring(c, RCHILD(n, -1)); - if (doc != NULL) { - (void) com_addconst(c, doc); - Py_DECREF(doc); + int n = asdl_seq_LEN(e->v.Tuple.elts); + if (e->v.Tuple.ctx == Store) { + ADDOP_I(c, UNPACK_SEQUENCE, n); } - else - (void) com_addconst(c, Py_None); /* No docstring */ - ch = RCHILD(n, -3); /* parameters: '(' [varargslist] ')' */ - ch = CHILD(ch, 1); /* ')' | varargslist */ - if (TYPE(ch) == varargslist) - com_arglist(c, ch); - c->c_infunction = 1; - com_node(c, RCHILD(n, -1)); - c->c_infunction = 0; - com_strip_lnotab(c); - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - com_push(c, 1); - com_addbyte(c, RETURN_VALUE); - com_pop(c, 1); -} - -static void -compile_lambdef(struct compiling *c, node *n) -{ - node *ch; - REQ(n, lambdef); /* lambdef: 'lambda' [varargslist] ':' test */ - c->c_name = "<lambda>"; - - ch = CHILD(n, 1); - (void) com_addconst(c, Py_None); /* No docstring */ - if (TYPE(ch) == varargslist) { - com_arglist(c, ch); - ch = CHILD(n, 3); + VISIT_SEQ(c, expr, e->v.Tuple.elts); + if (e->v.Tuple.ctx == Load) { + ADDOP_I(c, BUILD_TUPLE, n); } - else - ch = CHILD(n, 2); - com_node(c, ch); - com_addbyte(c, RETURN_VALUE); - com_pop(c, 1); + return 1; } -static void -compile_classdef(struct compiling *c, node *n) -{ - node *ch; - PyObject *doc; - REQ(n, classdef); - /* classdef: 'class' NAME ['(' testlist ')'] ':' suite */ - c->c_name = STR(CHILD(n, 1)); - c->c_private = c->c_name; - /* Initialize local __module__ from global __name__ */ - com_addop_name(c, LOAD_GLOBAL, "__name__"); - com_addop_name(c, STORE_NAME, "__module__"); - ch = CHILD(n, NCH(n)-1); /* The suite */ - doc = get_docstring(c, ch); - if (doc != NULL) { - int i = com_addconst(c, doc); - Py_DECREF(doc); - com_addoparg(c, LOAD_CONST, i); - com_push(c, 1); - com_addop_name(c, STORE_NAME, "__doc__"); - com_pop(c, 1); +static int +compiler_compare(struct compiler *c, expr_ty e) +{ + int i, n; + basicblock *cleanup = NULL; + + /* XXX the logic can be cleaned up for 1 or multiple comparisons */ + VISIT(c, expr, e->v.Compare.left); + n = asdl_seq_LEN(e->v.Compare.ops); + assert(n > 0); + if (n > 1) { + cleanup = compiler_new_block(c); + if (cleanup == NULL) + return 0; + VISIT(c, expr, asdl_seq_GET(e->v.Compare.comparators, 0)); + } + for (i = 1; i < n; i++) { + ADDOP(c, DUP_TOP); + ADDOP(c, ROT_THREE); + /* XXX We're casting a void* to cmpop_ty in the next stmt. */ + ADDOP_I(c, COMPARE_OP, + cmpop((cmpop_ty)asdl_seq_GET(e->v.Compare.ops, i - 1))); + ADDOP_JREL(c, JUMP_IF_FALSE, cleanup); + NEXT_BLOCK(c); + ADDOP(c, POP_TOP); + if (i < (n - 1)) + VISIT(c, expr, asdl_seq_GET(e->v.Compare.comparators, i)); + } + VISIT(c, expr, asdl_seq_GET(e->v.Compare.comparators, n - 1)); + ADDOP_I(c, COMPARE_OP, + /* XXX We're casting a void* to cmpop_ty in the next stmt. */ + cmpop((cmpop_ty)asdl_seq_GET(e->v.Compare.ops, n - 1))); + if (n > 1) { + basicblock *end = compiler_new_block(c); + if (end == NULL) + return 0; + ADDOP_JREL(c, JUMP_FORWARD, end); + compiler_use_next_block(c, cleanup); + ADDOP(c, ROT_TWO); + ADDOP(c, POP_TOP); + compiler_use_next_block(c, end); } - else - (void) com_addconst(c, Py_None); - com_node(c, ch); - com_strip_lnotab(c); - com_addbyte(c, LOAD_LOCALS); - com_push(c, 1); - com_addbyte(c, RETURN_VALUE); - com_pop(c, 1); + return 1; } -static void -compile_generator_expression(struct compiling *c, node *n) +static int +compiler_call(struct compiler *c, expr_ty e) { - /* testlist_gexp: test gen_for */ - /* argument: test gen_for */ - REQ(CHILD(n, 0), test); - REQ(CHILD(n, 1), gen_for); - - c->c_name = "<generator expression>"; - c->c_infunction = 1; - com_gen_for(c, CHILD(n, 1), CHILD(n, 0), 1); - c->c_infunction = 0; - - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - com_push(c, 1); - com_addbyte(c, RETURN_VALUE); - com_pop(c, 1); -} + int n, code = 0; -static void -compile_node(struct compiling *c, node *n) -{ - com_set_lineno(c, n->n_lineno); - - switch (TYPE(n)) { - - case single_input: /* One interactive command */ - /* NEWLINE | simple_stmt | compound_stmt NEWLINE */ - c->c_interactive++; - n = CHILD(n, 0); - if (TYPE(n) != NEWLINE) - com_node(c, n); - com_strip_lnotab(c); - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - com_push(c, 1); - com_addbyte(c, RETURN_VALUE); - com_pop(c, 1); - c->c_interactive--; + VISIT(c, expr, e->v.Call.func); + n = asdl_seq_LEN(e->v.Call.args); + VISIT_SEQ(c, expr, e->v.Call.args); + if (e->v.Call.keywords) { + VISIT_SEQ(c, keyword, e->v.Call.keywords); + n |= asdl_seq_LEN(e->v.Call.keywords) << 8; + } + if (e->v.Call.starargs) { + VISIT(c, expr, e->v.Call.starargs); + code |= 1; + } + if (e->v.Call.kwargs) { + VISIT(c, expr, e->v.Call.kwargs); + code |= 2; + } + switch (code) { + case 0: + ADDOP_I(c, CALL_FUNCTION, n); break; - - case file_input: /* A whole file, or built-in function exec() */ - com_file_input(c, n); - com_strip_lnotab(c); - com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); - com_push(c, 1); - com_addbyte(c, RETURN_VALUE); - com_pop(c, 1); + case 1: + ADDOP_I(c, CALL_FUNCTION_VAR, n); break; - - case eval_input: /* Built-in function input() */ - com_node(c, CHILD(n, 0)); - com_addbyte(c, RETURN_VALUE); - com_pop(c, 1); + case 2: + ADDOP_I(c, CALL_FUNCTION_KW, n); break; - - case lambdef: /* anonymous function definition */ - compile_lambdef(c, n); + case 3: + ADDOP_I(c, CALL_FUNCTION_VAR_KW, n); break; + } + return 1; +} - case funcdef: /* A function definition */ - compile_funcdef(c, n); - break; - - case classdef: /* A class definition */ - compile_classdef(c, n); - break; +static int +compiler_listcomp_generator(struct compiler *c, PyObject *tmpname, + asdl_seq *generators, int gen_index, + expr_ty elt) +{ + /* generate code for the iterator, then each of the ifs, + and then write to the element */ + + comprehension_ty l; + basicblock *start, *anchor, *skip, *if_cleanup; + int i, n; + + start = compiler_new_block(c); + skip = compiler_new_block(c); + if_cleanup = compiler_new_block(c); + anchor = compiler_new_block(c); + + if (start == NULL || skip == NULL || if_cleanup == NULL || + anchor == NULL) + return 0; + + l = asdl_seq_GET(generators, gen_index); + VISIT(c, expr, l->iter); + ADDOP(c, GET_ITER); + compiler_use_next_block(c, start); + ADDOP_JREL(c, FOR_ITER, anchor); + NEXT_BLOCK(c); + VISIT(c, expr, l->target); + + /* XXX this needs to be cleaned up...a lot! */ + n = asdl_seq_LEN(l->ifs); + for (i = 0; i < n; i++) { + expr_ty e = asdl_seq_GET(l->ifs, i); + VISIT(c, expr, e); + ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup); + NEXT_BLOCK(c); + ADDOP(c, POP_TOP); + } + + if (++gen_index < asdl_seq_LEN(generators)) + if (!compiler_listcomp_generator(c, tmpname, + generators, gen_index, elt)) + return 0; + + /* only append after the last for generator */ + if (gen_index >= asdl_seq_LEN(generators)) { + if (!compiler_nameop(c, tmpname, Load)) + return 0; + VISIT(c, expr, elt); + ADDOP_I(c, CALL_FUNCTION, 1); + ADDOP(c, POP_TOP); + + compiler_use_next_block(c, skip); + } + for (i = 0; i < n; i++) { + ADDOP_I(c, JUMP_FORWARD, 1); + if (i == 0) + compiler_use_next_block(c, if_cleanup); + ADDOP(c, POP_TOP); + } + ADDOP_JABS(c, JUMP_ABSOLUTE, start); + compiler_use_next_block(c, anchor); + /* delete the append method added to locals */ + if (gen_index == 1) + if (!compiler_nameop(c, tmpname, Del)) + return 0; - case testlist_gexp: /* A generator expression */ - case argument: /* A generator expression */ - compile_generator_expression(c, n); - break; + return 1; +} - default: - com_error(c, PyExc_SystemError, - "compile_node: unexpected node type"); +static int +compiler_listcomp(struct compiler *c, expr_ty e) +{ + char tmpname[256]; + identifier tmp; + int rc = 0; + static identifier append; + asdl_seq *generators = e->v.ListComp.generators; + + assert(e->kind == ListComp_kind); + if (!append) { + append = PyString_InternFromString("append"); + if (!append) + return 0; } + PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", ++c->u->u_tmpname); + tmp = PyString_FromString(tmpname); + if (!tmp) + return 0; + ADDOP_I(c, BUILD_LIST, 0); + ADDOP(c, DUP_TOP); + ADDOP_O(c, LOAD_ATTR, append, names); + if (compiler_nameop(c, tmp, Store)) + rc = compiler_listcomp_generator(c, tmp, generators, 0, + e->v.ListComp.elt); + Py_DECREF(tmp); + return rc; } -static PyObject * -dict_keys_inorder(PyObject *dict, int offset) +static int +compiler_genexp_generator(struct compiler *c, + asdl_seq *generators, int gen_index, + expr_ty elt) { - PyObject *tuple, *k, *v; - int i, pos = 0, size = PyDict_Size(dict); + /* generate code for the iterator, then each of the ifs, + and then write to the element */ - tuple = PyTuple_New(size); - if (tuple == NULL) - return NULL; - while (PyDict_Next(dict, &pos, &k, &v)) { - i = PyInt_AS_LONG(v); - Py_INCREF(k); - assert((i - offset) < size); - PyTuple_SET_ITEM(tuple, i - offset, k); - } - return tuple; -} + comprehension_ty ge; + basicblock *start, *anchor, *skip, *if_cleanup, *end; + int i, n; -PyCodeObject * -PyNode_Compile(node *n, const char *filename) -{ - return PyNode_CompileFlags(n, filename, NULL); -} + start = compiler_new_block(c); + skip = compiler_new_block(c); + if_cleanup = compiler_new_block(c); + anchor = compiler_new_block(c); + end = compiler_new_block(c); -PyCodeObject * -PyNode_CompileFlags(node *n, const char *filename, PyCompilerFlags *flags) -{ - return jcompile(n, filename, NULL, flags); -} + if (start == NULL || skip == NULL || if_cleanup == NULL || + anchor == NULL || end == NULL) + return 0; -struct symtable * -PyNode_CompileSymtable(node *n, const char *filename) -{ - struct symtable *st; - PyFutureFeatures *ff; + ge = asdl_seq_GET(generators, gen_index); + ADDOP_JREL(c, SETUP_LOOP, end); + if (!compiler_push_fblock(c, LOOP, start)) + return 0; - ff = PyNode_Future(n, filename); - if (ff == NULL) - return NULL; - st = symtable_build(n, ff, filename); - if (st == NULL) { - PyObject_FREE((void *)ff); - return NULL; + if (gen_index == 0) { + /* Receive outermost iter as an implicit argument */ + c->u->u_argcount = 1; + ADDOP_I(c, LOAD_FAST, 0); } - return st; -} + else { + /* Sub-iter - calculate on the fly */ + VISIT(c, expr, ge->iter); + ADDOP(c, GET_ITER); + } + compiler_use_next_block(c, start); + ADDOP_JREL(c, FOR_ITER, anchor); + NEXT_BLOCK(c); + VISIT(c, expr, ge->target); + + /* XXX this needs to be cleaned up...a lot! */ + n = asdl_seq_LEN(ge->ifs); + for (i = 0; i < n; i++) { + expr_ty e = asdl_seq_GET(ge->ifs, i); + VISIT(c, expr, e); + ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup); + NEXT_BLOCK(c); + ADDOP(c, POP_TOP); + } + + if (++gen_index < asdl_seq_LEN(generators)) + if (!compiler_genexp_generator(c, generators, gen_index, elt)) + return 0; -static PyCodeObject * -icompile(node *n, struct compiling *base) -{ - return jcompile(n, base->c_filename, base, NULL); + /* only append after the last 'for' generator */ + if (gen_index >= asdl_seq_LEN(generators)) { + VISIT(c, expr, elt); + ADDOP(c, YIELD_VALUE); + ADDOP(c, POP_TOP); + + compiler_use_next_block(c, skip); + } + for (i = 0; i < n; i++) { + ADDOP_I(c, JUMP_FORWARD, 1); + if (i == 0) + compiler_use_next_block(c, if_cleanup); + + ADDOP(c, POP_TOP); + } + ADDOP_JABS(c, JUMP_ABSOLUTE, start); + compiler_use_next_block(c, anchor); + ADDOP(c, POP_BLOCK); + compiler_pop_fblock(c, LOOP, start); + compiler_use_next_block(c, end); + + return 1; } -static PyCodeObject * -jcompile(node *n, const char *filename, struct compiling *base, - PyCompilerFlags *flags) +static int +compiler_genexp(struct compiler *c, expr_ty e) { - struct compiling sc; + PyObject *name; PyCodeObject *co; - if (!com_init(&sc, filename)) - return NULL; - if (flags && flags->cf_flags & PyCF_SOURCE_IS_UTF8) { - sc.c_encoding = "utf-8"; - } else if (TYPE(n) == encoding_decl) { - sc.c_encoding = STR(n); - n = CHILD(n, 0); - } else { - sc.c_encoding = NULL; - } - if (base) { - sc.c_private = base->c_private; - sc.c_symtable = base->c_symtable; - /* c_symtable still points to parent's symbols */ - if (base->c_nested - || (sc.c_symtable->st_cur->ste_type == TYPE_FUNCTION)) - sc.c_nested = 1; - sc.c_flags |= base->c_flags & PyCF_MASK; - if (base->c_encoding != NULL) { - assert(sc.c_encoding == NULL); - sc.c_encoding = base->c_encoding; - } - } else { - sc.c_private = NULL; - sc.c_future = PyNode_Future(n, filename); - if (sc.c_future == NULL) { - com_free(&sc); - return NULL; - } - if (flags) { - int merged = sc.c_future->ff_features | - flags->cf_flags; - sc.c_future->ff_features = merged; - flags->cf_flags = merged; - } - sc.c_symtable = symtable_build(n, sc.c_future, sc.c_filename); - if (sc.c_symtable == NULL) { - com_free(&sc); - return NULL; - } - /* reset symbol table for second pass */ - sc.c_symtable->st_nscopes = 1; - sc.c_symtable->st_pass = 2; - } - co = NULL; - if (symtable_load_symbols(&sc) < 0) { - sc.c_errors++; - goto exit; - } - compile_node(&sc, n); - com_done(&sc); - if (sc.c_errors == 0) { - PyObject *consts, *names, *varnames, *filename, *name, - *freevars, *cellvars, *code; - names = PyList_AsTuple(sc.c_names); - varnames = PyList_AsTuple(sc.c_varnames); - cellvars = dict_keys_inorder(sc.c_cellvars, 0); - freevars = dict_keys_inorder(sc.c_freevars, - PyTuple_GET_SIZE(cellvars)); - filename = PyString_InternFromString(sc.c_filename); - name = PyString_InternFromString(sc.c_name); - code = optimize_code(sc.c_code, sc.c_consts, names, sc.c_lnotab); - consts = PyList_AsTuple(sc.c_consts); - if (!PyErr_Occurred()) - co = PyCode_New(sc.c_argcount, - sc.c_nlocals, - sc.c_maxstacklevel, - sc.c_flags, - code, - consts, - names, - varnames, - freevars, - cellvars, - filename, - name, - sc.c_firstlineno, - sc.c_lnotab); - Py_XDECREF(consts); - Py_XDECREF(names); - Py_XDECREF(varnames); - Py_XDECREF(freevars); - Py_XDECREF(cellvars); - Py_XDECREF(filename); - Py_XDECREF(name); - Py_XDECREF(code); - } - else if (!PyErr_Occurred()) { - /* This could happen if someone called PyErr_Clear() after an - error was reported above. That's not supposed to happen, - but I just plugged one case and I'm not sure there can't be - others. In that case, raise SystemError so that at least - it gets reported instead dumping core. */ - PyErr_SetString(PyExc_SystemError, "lost syntax error"); - } - exit: - if (base == NULL) { - PySymtable_Free(sc.c_symtable); - sc.c_symtable = NULL; - } - com_free(&sc); - return co; -} + expr_ty outermost_iter = ((comprehension_ty) + (asdl_seq_GET(e->v.GeneratorExp.generators, + 0)))->iter; -int -PyCode_Addr2Line(PyCodeObject *co, int addrq) -{ - int size = PyString_Size(co->co_lnotab) / 2; - unsigned char *p = (unsigned char*)PyString_AsString(co->co_lnotab); - int line = co->co_firstlineno; - int addr = 0; - while (--size >= 0) { - addr += *p++; - if (addr > addrq) - break; - line += *p++; - } - return line; -} + name = PyString_FromString("<generator expression>"); + if (!name) + return 0; -/* The test for LOCAL must come before the test for FREE in order to - handle classes where name is both local and free. The local var is - a method and the free var is a free var referenced within a method. -*/ + if (!compiler_enter_scope(c, name, (void *)e, e->lineno)) + return 0; + compiler_genexp_generator(c, e->v.GeneratorExp.generators, 0, + e->v.GeneratorExp.elt); + co = assemble(c, 1); + if (co == NULL) + return 0; + compiler_exit_scope(c); + + compiler_make_closure(c, co, 0); + VISIT(c, expr, outermost_iter); + ADDOP(c, GET_ITER); + ADDOP_I(c, CALL_FUNCTION, 1); + Py_DECREF(name); + Py_DECREF(co); + + return 1; +} static int -get_ref_type(struct compiling *c, char *name) +compiler_visit_keyword(struct compiler *c, keyword_ty k) { - char buf[350]; - PyObject *v; - - if (PyDict_GetItemString(c->c_cellvars, name) != NULL) - return CELL; - if (PyDict_GetItemString(c->c_locals, name) != NULL) - return LOCAL; - if (PyDict_GetItemString(c->c_freevars, name) != NULL) - return FREE; - v = PyDict_GetItemString(c->c_globals, name); - if (v) { - if (v == Py_None) - return GLOBAL_EXPLICIT; - else { - return GLOBAL_IMPLICIT; - } - } - PyOS_snprintf(buf, sizeof(buf), - "unknown scope for %.100s in %.100s(%s) " - "in %s\nsymbols: %s\nlocals: %s\nglobals: %s\n", - name, c->c_name, - PyObject_REPR(c->c_symtable->st_cur->ste_id), - c->c_filename, - PyObject_REPR(c->c_symtable->st_cur->ste_symbols), - PyObject_REPR(c->c_locals), - PyObject_REPR(c->c_globals) - ); - - Py_FatalError(buf); - return -1; + ADDOP_O(c, LOAD_CONST, k->arg, consts); + VISIT(c, expr, k->value); + return 1; } -/* Helper functions to issue warnings */ +/* Test whether expression is constant. For constants, report + whether they are true or false. + + Return values: 1 for true, 0 for false, -1 for non-constant. + */ static int -issue_warning(const char *msg, const char *filename, int lineno) +expr_constant(expr_ty e) { - if (PyErr_Occurred()) { - /* This can happen because symtable_node continues - processing even after raising a SyntaxError. - Calling PyErr_WarnExplicit now would clobber the - pending exception; instead we fail and let that - exception propagate. - */ - return -1; - } - if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, filename, - lineno, NULL, NULL) < 0) { - if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { - PyErr_SetString(PyExc_SyntaxError, msg); - PyErr_SyntaxLocation(filename, lineno); - } + switch (e->kind) { + case Num_kind: + return PyObject_IsTrue(e->v.Num.n); + case Str_kind: + return PyObject_IsTrue(e->v.Str.s); + default: return -1; } - return 0; } static int -symtable_warn(struct symtable *st, char *msg) -{ - if (issue_warning(msg, st->st_filename, st->st_cur->ste_lineno) < 0) { - st->st_errors++; - return -1; +compiler_visit_expr(struct compiler *c, expr_ty e) +{ + int i, n; + + if (e->lineno > c->u->u_lineno) { + c->u->u_lineno = e->lineno; + c->u->u_lineno_set = false; + } + switch (e->kind) { + case BoolOp_kind: + return compiler_boolop(c, e); + case BinOp_kind: + VISIT(c, expr, e->v.BinOp.left); + VISIT(c, expr, e->v.BinOp.right); + ADDOP(c, binop(c, e->v.BinOp.op)); + break; + case UnaryOp_kind: + VISIT(c, expr, e->v.UnaryOp.operand); + ADDOP(c, unaryop(e->v.UnaryOp.op)); + break; + case Lambda_kind: + return compiler_lambda(c, e); + case Dict_kind: + /* XXX get rid of arg? */ + ADDOP_I(c, BUILD_MAP, 0); + n = asdl_seq_LEN(e->v.Dict.values); + /* We must arrange things just right for STORE_SUBSCR. + It wants the stack to look like (value) (dict) (key) */ + for (i = 0; i < n; i++) { + ADDOP(c, DUP_TOP); + VISIT(c, expr, asdl_seq_GET(e->v.Dict.values, i)); + ADDOP(c, ROT_TWO); + VISIT(c, expr, asdl_seq_GET(e->v.Dict.keys, i)); + ADDOP(c, STORE_SUBSCR); + } + break; + case ListComp_kind: + return compiler_listcomp(c, e); + case GeneratorExp_kind: + return compiler_genexp(c, e); + case Yield_kind: + if (c->u->u_ste->ste_type != FunctionBlock) + return compiler_error(c, "'yield' outside function"); + /* + for (i = 0; i < c->u->u_nfblocks; i++) { + if (c->u->u_fblock[i].fb_type == FINALLY_TRY) + return compiler_error( + c, "'yield' not allowed in a 'try' " + "block with a 'finally' clause"); + } + */ + if (e->v.Yield.value) { + VISIT(c, expr, e->v.Yield.value); + } + else { + ADDOP_O(c, LOAD_CONST, Py_None, consts); + } + ADDOP(c, YIELD_VALUE); + break; + case Compare_kind: + return compiler_compare(c, e); + case Call_kind: + return compiler_call(c, e); + case Repr_kind: + VISIT(c, expr, e->v.Repr.value); + ADDOP(c, UNARY_CONVERT); + break; + case Num_kind: + ADDOP_O(c, LOAD_CONST, e->v.Num.n, consts); + break; + case Str_kind: + ADDOP_O(c, LOAD_CONST, e->v.Str.s, consts); + break; + /* The following exprs can be assignment targets. */ + case Attribute_kind: + if (e->v.Attribute.ctx != AugStore) + VISIT(c, expr, e->v.Attribute.value); + switch (e->v.Attribute.ctx) { + case AugLoad: + ADDOP(c, DUP_TOP); + /* Fall through to load */ + case Load: + ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names); + break; + case AugStore: + ADDOP(c, ROT_TWO); + /* Fall through to save */ + case Store: + ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names); + break; + case Del: + ADDOP_NAME(c, DELETE_ATTR, e->v.Attribute.attr, names); + break; + case Param: + assert(0); + break; + } + break; + case Subscript_kind: + switch (e->v.Subscript.ctx) { + case AugLoad: + VISIT(c, expr, e->v.Subscript.value); + VISIT_SLICE(c, e->v.Subscript.slice, AugLoad); + break; + case Load: + VISIT(c, expr, e->v.Subscript.value); + VISIT_SLICE(c, e->v.Subscript.slice, Load); + break; + case AugStore: + VISIT_SLICE(c, e->v.Subscript.slice, AugStore); + break; + case Store: + VISIT(c, expr, e->v.Subscript.value); + VISIT_SLICE(c, e->v.Subscript.slice, Store); + break; + case Del: + VISIT(c, expr, e->v.Subscript.value); + VISIT_SLICE(c, e->v.Subscript.slice, Del); + break; + case Param: + assert(0); + break; + } + break; + case Name_kind: + return compiler_nameop(c, e->v.Name.id, e->v.Name.ctx); + /* child nodes of List and Tuple will have expr_context set */ + case List_kind: + return compiler_list(c, e); + case Tuple_kind: + return compiler_tuple(c, e); } - return 0; + return 1; } -/* Helper function for setting lineno and filename */ - -static struct symtable * -symtable_build(node *n, PyFutureFeatures *ff, const char *filename) -{ - struct symtable *st; - - st = symtable_init(); - if (st == NULL) - return NULL; - st->st_future = ff; - st->st_filename = filename; - symtable_enter_scope(st, TOP, TYPE(n), n->n_lineno); - if (st->st_errors > 0) - goto fail; - symtable_node(st, n); - if (st->st_errors > 0) - goto fail; - return st; - fail: - if (!PyErr_Occurred()) { - /* This could happen because after a syntax error is - detected, the symbol-table-building continues for - a while, and PyErr_Clear() might erroneously be - called during that process. One such case has been - fixed, but there might be more (now or later). - */ - PyErr_SetString(PyExc_SystemError, "lost exception"); +static int +compiler_augassign(struct compiler *c, stmt_ty s) +{ + expr_ty e = s->v.AugAssign.target; + expr_ty auge; + + assert(s->kind == AugAssign_kind); + + switch (e->kind) { + case Attribute_kind: + auge = Attribute(e->v.Attribute.value, e->v.Attribute.attr, + AugLoad, e->lineno); + if (auge == NULL) + return 0; + VISIT(c, expr, auge); + VISIT(c, expr, s->v.AugAssign.value); + ADDOP(c, inplace_binop(c, s->v.AugAssign.op)); + auge->v.Attribute.ctx = AugStore; + VISIT(c, expr, auge); + free(auge); + break; + case Subscript_kind: + auge = Subscript(e->v.Subscript.value, e->v.Subscript.slice, + AugLoad, e->lineno); + if (auge == NULL) + return 0; + VISIT(c, expr, auge); + VISIT(c, expr, s->v.AugAssign.value); + ADDOP(c, inplace_binop(c, s->v.AugAssign.op)); + auge->v.Subscript.ctx = AugStore; + VISIT(c, expr, auge); + free(auge); + break; + case Name_kind: + VISIT(c, expr, s->v.AugAssign.target); + VISIT(c, expr, s->v.AugAssign.value); + ADDOP(c, inplace_binop(c, s->v.AugAssign.op)); + return compiler_nameop(c, e->v.Name.id, Store); + default: + fprintf(stderr, + "invalid node type for augmented assignment\n"); + return 0; } - st->st_future = NULL; - st->st_filename = NULL; - PySymtable_Free(st); - return NULL; + return 1; } static int -symtable_init_compiling_symbols(struct compiling *c) +compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b) { - PyObject *varnames; - - varnames = c->c_symtable->st_cur->ste_varnames; - if (varnames == NULL) { - varnames = PyList_New(0); - if (varnames == NULL) - return -1; - c->c_symtable->st_cur->ste_varnames = varnames; - Py_INCREF(varnames); - } else - Py_INCREF(varnames); - c->c_varnames = varnames; - - c->c_globals = PyDict_New(); - if (c->c_globals == NULL) - return -1; - c->c_freevars = PyDict_New(); - if (c->c_freevars == NULL) - return -1; - c->c_cellvars = PyDict_New(); - if (c->c_cellvars == NULL) - return -1; - return 0; + struct fblockinfo *f; + if (c->u->u_nfblocks >= CO_MAXBLOCKS) + return 0; + f = &c->u->u_fblock[c->u->u_nfblocks++]; + f->fb_type = t; + f->fb_block = b; + return 1; } -struct symbol_info { - int si_nlocals; - int si_ncells; - int si_nfrees; - int si_nimplicit; -}; - static void -symtable_init_info(struct symbol_info *si) +compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b) { - si->si_nlocals = 0; - si->si_ncells = 0; - si->si_nfrees = 0; - si->si_nimplicit = 0; + struct compiler_unit *u = c->u; + assert(u->u_nfblocks > 0); + u->u_nfblocks--; + assert(u->u_fblock[u->u_nfblocks].fb_type == t); + assert(u->u_fblock[u->u_nfblocks].fb_block == b); } +/* Raises a SyntaxError and returns 0. + If something goes wrong, a different exception may be raised. +*/ + static int -symtable_resolve_free(struct compiling *c, PyObject *name, int flags, - struct symbol_info *si) +compiler_error(struct compiler *c, const char *errstr) { - PyObject *dict, *v; + PyObject *loc; + PyObject *u = NULL, *v = NULL; - /* Seperate logic for DEF_FREE. If it occurs in a function, - it indicates a local that we must allocate storage for (a - cell var). If it occurs in a class, then the class has a - method and a free variable with the same name. - */ - if (c->c_symtable->st_cur->ste_type == TYPE_FUNCTION) { - /* If it isn't declared locally, it can't be a cell. */ - if (!(flags & (DEF_LOCAL | DEF_PARAM))) - return 0; - v = PyInt_FromLong(si->si_ncells++); - dict = c->c_cellvars; - } else { - /* If it is free anyway, then there is no need to do - anything here. - */ - if (is_free(flags ^ DEF_FREE_CLASS) - || (flags == DEF_FREE_CLASS)) - return 0; - v = PyInt_FromLong(si->si_nfrees++); - dict = c->c_freevars; - } - if (v == NULL) - return -1; - if (PyDict_SetItem(dict, name, v) < 0) { - Py_DECREF(v); - return -1; + loc = PyErr_ProgramText(c->c_filename, c->u->u_lineno); + if (!loc) { + Py_INCREF(Py_None); + loc = Py_None; } - Py_DECREF(v); + u = Py_BuildValue("(ziOO)", c->c_filename, c->u->u_lineno, + Py_None, loc); + if (!u) + goto exit; + v = Py_BuildValue("(zO)", errstr, u); + if (!v) + goto exit; + PyErr_SetObject(PyExc_SyntaxError, v); + exit: + Py_DECREF(loc); + Py_XDECREF(u); + Py_XDECREF(v); return 0; } -/* If a variable is a cell and an argument, make sure that appears in - co_cellvars before any variable to its right in varnames. -*/ - +static int +compiler_handle_subscr(struct compiler *c, const char *kind, + expr_context_ty ctx) +{ + int op = 0; + + /* XXX this code is duplicated */ + switch (ctx) { + case AugLoad: /* fall through to Load */ + case Load: op = BINARY_SUBSCR; break; + case AugStore:/* fall through to Store */ + case Store: op = STORE_SUBSCR; break; + case Del: op = DELETE_SUBSCR; break; + case Param: + fprintf(stderr, + "invalid %s kind %d in subscript\n", + kind, ctx); + return 0; + } + if (ctx == AugLoad) { + ADDOP_I(c, DUP_TOPX, 2); + } + else if (ctx == AugStore) { + ADDOP(c, ROT_THREE); + } + ADDOP(c, op); + return 1; +} static int -symtable_cellvar_offsets(PyObject **cellvars, int argcount, - PyObject *varnames, int flags) +compiler_slice(struct compiler *c, slice_ty s, expr_context_ty ctx) { - PyObject *v = NULL; - PyObject *w, *d, *list = NULL; - int i, pos; - - if (flags & CO_VARARGS) - argcount++; - if (flags & CO_VARKEYWORDS) - argcount++; - for (i = argcount; --i >= 0; ) { - v = PyList_GET_ITEM(varnames, i); - if (PyDict_GetItem(*cellvars, v)) { - if (list == NULL) { - list = PyList_New(1); - if (list == NULL) - return -1; - PyList_SET_ITEM(list, 0, v); - Py_INCREF(v); - } else { - if (PyList_Insert(list, 0, v) < 0) { - Py_DECREF(list); - return -1; - } - } - } - } - if (list == NULL) - return 0; + int n = 2; + assert(s->kind == Slice_kind); - /* There are cellvars that are also arguments. Create a dict - to replace cellvars and put the args at the front. - */ - d = PyDict_New(); - if (d == NULL) - return -1; - for (i = PyList_GET_SIZE(list); --i >= 0; ) { - v = PyInt_FromLong(i); - if (v == NULL) - goto fail; - if (PyDict_SetItem(d, PyList_GET_ITEM(list, i), v) < 0) - goto fail; - if (PyDict_DelItem(*cellvars, PyList_GET_ITEM(list, i)) < 0) - goto fail; - Py_DECREF(v); + /* only handles the cases where BUILD_SLICE is emitted */ + if (s->v.Slice.lower) { + VISIT(c, expr, s->v.Slice.lower); } - pos = 0; - i = PyList_GET_SIZE(list); - Py_DECREF(list); - while (PyDict_Next(*cellvars, &pos, &v, &w)) { - w = PyInt_FromLong(i++); /* don't care about the old key */ - if (w == NULL) - goto fail; - if (PyDict_SetItem(d, v, w) < 0) { - Py_DECREF(w); - v = NULL; - goto fail; - } - Py_DECREF(w); + else { + ADDOP_O(c, LOAD_CONST, Py_None, consts); + } + + if (s->v.Slice.upper) { + VISIT(c, expr, s->v.Slice.upper); + } + else { + ADDOP_O(c, LOAD_CONST, Py_None, consts); } - Py_DECREF(*cellvars); - *cellvars = d; - return 1; - fail: - Py_DECREF(d); - Py_XDECREF(v); - return -1; -} -static int -symtable_freevar_offsets(PyObject *freevars, int offset) -{ - PyObject *name, *v; - int pos; - - /* The cell vars are the first elements of the closure, - followed by the free vars. Update the offsets in - c_freevars to account for number of cellvars. */ - pos = 0; - while (PyDict_Next(freevars, &pos, &name, &v)) { - int i = PyInt_AS_LONG(v) + offset; - PyObject *o = PyInt_FromLong(i); - if (o == NULL) - return -1; - if (PyDict_SetItem(freevars, name, o) < 0) { - Py_DECREF(o); - return -1; - } - Py_DECREF(o); + if (s->v.Slice.step) { + n++; + VISIT(c, expr, s->v.Slice.step); } - return 0; + ADDOP_I(c, BUILD_SLICE, n); + return 1; } static int -symtable_check_unoptimized(struct compiling *c, - PySymtableEntryObject *ste, - struct symbol_info *si) -{ - char buf[300]; - - if (!(si->si_ncells || si->si_nfrees || ste->ste_child_free - || (ste->ste_nested && si->si_nimplicit))) - return 0; - -#define ILLEGAL_CONTAINS "contains a nested function with free variables" - -#define ILLEGAL_IS "is a nested function" - -#define ILLEGAL_IMPORT_STAR \ -"import * is not allowed in function '%.100s' because it %s" - -#define ILLEGAL_BARE_EXEC \ -"unqualified exec is not allowed in function '%.100s' it %s" - -#define ILLEGAL_EXEC_AND_IMPORT_STAR \ -"function '%.100s' uses import * and bare exec, which are illegal " \ -"because it %s" - - /* XXX perhaps the linenos for these opt-breaking statements - should be stored so the exception can point to them. */ - - if (ste->ste_child_free) { - if (ste->ste_optimized == OPT_IMPORT_STAR) - PyOS_snprintf(buf, sizeof(buf), - ILLEGAL_IMPORT_STAR, - PyString_AS_STRING(ste->ste_name), - ILLEGAL_CONTAINS); - else if (ste->ste_optimized == (OPT_BARE_EXEC | OPT_EXEC)) - PyOS_snprintf(buf, sizeof(buf), - ILLEGAL_BARE_EXEC, - PyString_AS_STRING(ste->ste_name), - ILLEGAL_CONTAINS); - else { - PyOS_snprintf(buf, sizeof(buf), - ILLEGAL_EXEC_AND_IMPORT_STAR, - PyString_AS_STRING(ste->ste_name), - ILLEGAL_CONTAINS); - } - } else { - if (ste->ste_optimized == OPT_IMPORT_STAR) - PyOS_snprintf(buf, sizeof(buf), - ILLEGAL_IMPORT_STAR, - PyString_AS_STRING(ste->ste_name), - ILLEGAL_IS); - else if (ste->ste_optimized == (OPT_BARE_EXEC | OPT_EXEC)) - PyOS_snprintf(buf, sizeof(buf), - ILLEGAL_BARE_EXEC, - PyString_AS_STRING(ste->ste_name), - ILLEGAL_IS); - else { - PyOS_snprintf(buf, sizeof(buf), - ILLEGAL_EXEC_AND_IMPORT_STAR, - PyString_AS_STRING(ste->ste_name), - ILLEGAL_IS); - } +compiler_simple_slice(struct compiler *c, slice_ty s, expr_context_ty ctx) +{ + int op = 0, slice_offset = 0, stack_count = 0; + + assert(s->v.Slice.step == NULL); + if (s->v.Slice.lower) { + slice_offset++; + stack_count++; + if (ctx != AugStore) + VISIT(c, expr, s->v.Slice.lower); + } + if (s->v.Slice.upper) { + slice_offset += 2; + stack_count++; + if (ctx != AugStore) + VISIT(c, expr, s->v.Slice.upper); + } + + if (ctx == AugLoad) { + switch (stack_count) { + case 0: ADDOP(c, DUP_TOP); break; + case 1: ADDOP_I(c, DUP_TOPX, 2); break; + case 2: ADDOP_I(c, DUP_TOPX, 3); break; + } + } + else if (ctx == AugStore) { + switch (stack_count) { + case 0: ADDOP(c, ROT_TWO); break; + case 1: ADDOP(c, ROT_THREE); break; + case 2: ADDOP(c, ROT_FOUR); break; + } + } + + switch (ctx) { + case AugLoad: /* fall through to Load */ + case Load: op = SLICE; break; + case AugStore:/* fall through to Store */ + case Store: op = STORE_SLICE; break; + case Del: op = DELETE_SLICE; break; + case Param: /* XXX impossible? */ + fprintf(stderr, "param invalid\n"); + assert(0); } - PyErr_SetString(PyExc_SyntaxError, buf); - PyErr_SyntaxLocation(c->c_symtable->st_filename, - ste->ste_opt_lineno); - return -1; + ADDOP(c, op + slice_offset); + return 1; } static int -symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste, - struct symbol_info *si) +compiler_visit_nested_slice(struct compiler *c, slice_ty s, + expr_context_ty ctx) { - if (c->c_future) - c->c_flags |= c->c_future->ff_features; - if (ste->ste_generator) - c->c_flags |= CO_GENERATOR; - if (ste->ste_type != TYPE_MODULE) - c->c_flags |= CO_NEWLOCALS; - if (ste->ste_type == TYPE_FUNCTION) { - c->c_nlocals = si->si_nlocals; - if (ste->ste_optimized == 0) - c->c_flags |= CO_OPTIMIZED; - else if (ste->ste_optimized != OPT_EXEC) - return symtable_check_unoptimized(c, ste, si); + switch (s->kind) { + case Ellipsis_kind: + ADDOP_O(c, LOAD_CONST, Py_Ellipsis, consts); + break; + case Slice_kind: + return compiler_slice(c, s, ctx); + break; + case Index_kind: + VISIT(c, expr, s->v.Index.value); + break; + case ExtSlice_kind: + assert(0); + break; } - return 0; + return 1; } -static int -symtable_error(struct symtable *st, int lineno) -{ - if (lineno == 0) - lineno = st->st_cur->ste_lineno; - PyErr_SyntaxLocation(st->st_filename, lineno); - st->st_errors++; - return -1; -} static int -symtable_load_symbols(struct compiling *c) +compiler_visit_slice(struct compiler *c, slice_ty s, expr_context_ty ctx) { - struct symtable *st = c->c_symtable; - PySymtableEntryObject *ste = st->st_cur; - PyObject *name, *varnames, *v; - int i, flags, pos; - struct symbol_info si; - - v = NULL; - - if (symtable_init_compiling_symbols(c) < 0) - goto fail; - symtable_init_info(&si); - varnames = st->st_cur->ste_varnames; - si.si_nlocals = PyList_GET_SIZE(varnames); - c->c_argcount = si.si_nlocals; - - for (i = 0; i < si.si_nlocals; ++i) { - v = PyInt_FromLong(i); - if (v == NULL) - goto fail; - if (PyDict_SetItem(c->c_locals, - PyList_GET_ITEM(varnames, i), v) < 0) - goto fail; - Py_DECREF(v); - } - - /* XXX The cases below define the rules for whether a name is - local or global. The logic could probably be clearer. */ - pos = 0; - while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) { - flags = PyInt_AS_LONG(v); - - if (flags & DEF_FREE_GLOBAL) - /* undo the original DEF_FREE */ - flags &= ~(DEF_FREE | DEF_FREE_CLASS); - - /* Deal with names that need two actions: - 1. Cell variables that are also locals. - 2. Free variables in methods that are also class - variables or declared global. - */ - if (flags & (DEF_FREE | DEF_FREE_CLASS)) - symtable_resolve_free(c, name, flags, &si); - - if (flags & DEF_STAR) { - c->c_argcount--; - c->c_flags |= CO_VARARGS; - } else if (flags & DEF_DOUBLESTAR) { - c->c_argcount--; - c->c_flags |= CO_VARKEYWORDS; - } else if (flags & DEF_INTUPLE) - c->c_argcount--; - else if (flags & DEF_GLOBAL) { - if (flags & DEF_PARAM) { - PyErr_Format(PyExc_SyntaxError, PARAM_GLOBAL, - PyString_AS_STRING(name)); - symtable_error(st, 0); - goto fail; - } - if (PyDict_SetItem(c->c_globals, name, Py_None) < 0) - goto fail; - } else if (flags & DEF_FREE_GLOBAL) { - si.si_nimplicit++; - if (PyDict_SetItem(c->c_globals, name, Py_True) < 0) - goto fail; - } else if ((flags & DEF_LOCAL) && !(flags & DEF_PARAM)) { - v = PyInt_FromLong(si.si_nlocals++); - if (v == NULL) - goto fail; - if (PyDict_SetItem(c->c_locals, name, v) < 0) - goto fail; - Py_DECREF(v); - if (ste->ste_type != TYPE_CLASS) - if (PyList_Append(c->c_varnames, name) < 0) - goto fail; - } else if (is_free(flags)) { - if (ste->ste_nested) { - v = PyInt_FromLong(si.si_nfrees++); - if (v == NULL) - goto fail; - if (PyDict_SetItem(c->c_freevars, name, v) < 0) - goto fail; - Py_DECREF(v); - } else { - si.si_nimplicit++; - if (PyDict_SetItem(c->c_globals, name, - Py_True) < 0) - goto fail; - if (st->st_nscopes != 1) { - v = PyInt_FromLong(flags); - if (v == NULL) - goto fail; - if (PyDict_SetItem(st->st_global, - name, v)) - goto fail; - Py_DECREF(v); - } - } + switch (s->kind) { + case Ellipsis_kind: + ADDOP_O(c, LOAD_CONST, Py_Ellipsis, consts); + break; + case Slice_kind: + if (!s->v.Slice.step) + return compiler_simple_slice(c, s, ctx); + if (!compiler_slice(c, s, ctx)) + return 0; + if (ctx == AugLoad) { + ADDOP_I(c, DUP_TOPX, 2); } + else if (ctx == AugStore) { + ADDOP(c, ROT_THREE); + } + return compiler_handle_subscr(c, "slice", ctx); + break; + case ExtSlice_kind: { + int i, n = asdl_seq_LEN(s->v.ExtSlice.dims); + for (i = 0; i < n; i++) { + slice_ty sub = asdl_seq_GET(s->v.ExtSlice.dims, i); + if (!compiler_visit_nested_slice(c, sub, ctx)) + return 0; + } + ADDOP_I(c, BUILD_TUPLE, n); + return compiler_handle_subscr(c, "extended slice", ctx); + break; } - assert(PyDict_Size(c->c_freevars) == si.si_nfrees); - - if (si.si_ncells > 1) { /* one cell is always in order */ - if (symtable_cellvar_offsets(&c->c_cellvars, c->c_argcount, - c->c_varnames, c->c_flags) < 0) - return -1; + case Index_kind: + if (ctx != AugStore) + VISIT(c, expr, s->v.Index.value); + return compiler_handle_subscr(c, "index", ctx); } - if (symtable_freevar_offsets(c->c_freevars, si.si_ncells) < 0) - return -1; - return symtable_update_flags(c, ste, &si); - fail: - /* is this always the right thing to do? */ - Py_XDECREF(v); - return -1; -} - -static struct symtable * -symtable_init() -{ - struct symtable *st; - - st = (struct symtable *)PyObject_MALLOC(sizeof(struct symtable)); - if (st == NULL) - return NULL; - st->st_pass = 1; - - st->st_filename = NULL; - st->st_symbols = NULL; - if ((st->st_stack = PyList_New(0)) == NULL) - goto fail; - if ((st->st_symbols = PyDict_New()) == NULL) - goto fail; - st->st_cur = NULL; - st->st_nscopes = 0; - st->st_errors = 0; - st->st_private = NULL; - return st; - fail: - PySymtable_Free(st); - return NULL; -} - -void -PySymtable_Free(struct symtable *st) -{ - Py_XDECREF(st->st_symbols); - Py_XDECREF(st->st_stack); - Py_XDECREF(st->st_cur); - PyObject_FREE((void *)st); + return 1; } -/* When the compiler exits a scope, it must should update the scope's - free variable information with the list of free variables in its - children. - - Variables that are free in children and defined in the current - scope are cellvars. - - If the scope being exited is defined at the top-level (ste_nested is - false), free variables in children that are not defined here are - implicit globals. +/* do depth-first search of basic block graph, starting with block. + post records the block indices in post-order. + XXX must handle implicit jumps from one block to next */ -static int -symtable_update_free_vars(struct symtable *st) +static void +dfs(struct compiler *c, basicblock *b, struct assembler *a) { - int i, j, def; - PyObject *o, *name, *list = NULL; - PySymtableEntryObject *child, *ste = st->st_cur; + int i; + struct instr *instr = NULL; - if (ste->ste_type == TYPE_CLASS) - def = DEF_FREE_CLASS; - else - def = DEF_FREE; - for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) { - int pos = 0; + if (b->b_seen) + return; + b->b_seen = 1; + if (b->b_next != NULL) + dfs(c, b->b_next, a); + for (i = 0; i < b->b_iused; i++) { + instr = &b->b_instr[i]; + if (instr->i_jrel || instr->i_jabs) + dfs(c, instr->i_target, a); + } + a->a_postorder[a->a_nblocks++] = b; +} - if (list && PyList_SetSlice(list, 0, - PyList_GET_SIZE(list), 0) < 0) - return -1; - child = (PySymtableEntryObject *) - PyList_GET_ITEM(ste->ste_children, i); - while (PyDict_Next(child->ste_symbols, &pos, &name, &o)) { - int flags = PyInt_AS_LONG(o); - if (!(is_free(flags))) - continue; /* avoids indentation */ - if (list == NULL) { - list = PyList_New(0); - if (list == NULL) - return -1; - } - ste->ste_child_free = 1; - if (PyList_Append(list, name) < 0) { - Py_DECREF(list); - return -1; - } - } - for (j = 0; list && j < PyList_GET_SIZE(list); j++) { - PyObject *v; - name = PyList_GET_ITEM(list, j); - v = PyDict_GetItem(ste->ste_symbols, name); - /* If a name N is declared global in scope A and - referenced in scope B contained (perhaps - indirectly) in A and there are no scopes - with bindings for N between B and A, then N - is global in B. Unless A is a class scope, - because class scopes are not considered for - nested scopes. - */ - if (v && (ste->ste_type != TYPE_CLASS)) { - int flags = PyInt_AS_LONG(v); - if (flags & DEF_GLOBAL) { - symtable_undo_free(st, child->ste_id, - name); - continue; - } - } - if (ste->ste_nested) { - if (symtable_add_def_o(st, ste->ste_symbols, - name, def) < 0) { - Py_DECREF(list); - return -1; - } - } else { - if (symtable_check_global(st, child->ste_id, - name) < 0) { - Py_DECREF(list); - return -1; - } +int +stackdepth_walk(struct compiler *c, basicblock *b, int depth, int maxdepth) +{ + int i; + struct instr *instr; + if (b->b_seen || b->b_startdepth >= depth) + return maxdepth; + b->b_seen = 1; + b->b_startdepth = depth; + for (i = 0; i < b->b_iused; i++) { + instr = &b->b_instr[i]; + depth += opcode_stack_effect(instr->i_opcode, instr->i_oparg); + if (depth > maxdepth) + maxdepth = depth; + assert(depth >= 0); /* invalid code or bug in stackdepth() */ + if (instr->i_jrel || instr->i_jabs) { + maxdepth = stackdepth_walk(c, instr->i_target, + depth, maxdepth); + if (instr->i_opcode == JUMP_ABSOLUTE || + instr->i_opcode == JUMP_FORWARD) { + goto out; /* remaining code is dead */ } } } - - Py_XDECREF(list); - return 0; + if (b->b_next) + maxdepth = stackdepth_walk(c, b->b_next, depth, maxdepth); +out: + b->b_seen = 0; + return maxdepth; } -/* If the current scope is a non-nested class or if name is not - defined in the current, non-nested scope, then it is an implicit - global in all nested scopes. -*/ - +/* Find the flow path that needs the largest stack. We assume that + * cycles in the flow graph have no net effect on the stack depth. + */ static int -symtable_check_global(struct symtable *st, PyObject *child, PyObject *name) +stackdepth(struct compiler *c) { - PyObject *o; - int v; - PySymtableEntryObject *ste = st->st_cur; - - if (ste->ste_type == TYPE_CLASS) - return symtable_undo_free(st, child, name); - o = PyDict_GetItem(ste->ste_symbols, name); - if (o == NULL) - return symtable_undo_free(st, child, name); - v = PyInt_AS_LONG(o); - - if (is_free(v) || (v & DEF_GLOBAL)) - return symtable_undo_free(st, child, name); - else - return symtable_add_def_o(st, ste->ste_symbols, - name, DEF_FREE); + basicblock *b, *entryblock; + entryblock = NULL; + for (b = c->u->u_blocks; b != NULL; b = b->b_list) { + b->b_seen = 0; + b->b_startdepth = INT_MIN; + entryblock = b; + } + return stackdepth_walk(c, entryblock, 0, 0); } static int -symtable_undo_free(struct symtable *st, PyObject *id, - PyObject *name) +assemble_init(struct assembler *a, int nblocks, int firstlineno) { - int i, v, x; - PyObject *info; - PySymtableEntryObject *ste; - - ste = (PySymtableEntryObject *)PyDict_GetItem(st->st_symbols, id); - if (ste == NULL) - return -1; - - info = PyDict_GetItem(ste->ste_symbols, name); - if (info == NULL) + memset(a, 0, sizeof(struct assembler)); + a->a_lineno = firstlineno; + a->a_bytecode = PyString_FromStringAndSize(NULL, DEFAULT_CODE_SIZE); + if (!a->a_bytecode) return 0; - v = PyInt_AS_LONG(info); - if (is_free(v)) { - if (symtable_add_def_o(st, ste->ste_symbols, name, - DEF_FREE_GLOBAL) < 0) - return -1; - } else - /* If the name is defined here or declared global, - then the recursion stops. */ + a->a_lnotab = PyString_FromStringAndSize(NULL, DEFAULT_LNOTAB_SIZE); + if (!a->a_lnotab) return 0; - - for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) { - PySymtableEntryObject *child; - child = (PySymtableEntryObject *) - PyList_GET_ITEM(ste->ste_children, i); - x = symtable_undo_free(st, child->ste_id, name); - if (x < 0) - return x; - } - return 0; -} - -/* symtable_enter_scope() gets a reference via PySymtableEntry_New(). - This reference is released when the scope is exited, via the DECREF - in symtable_exit_scope(). -*/ - -static int -symtable_exit_scope(struct symtable *st) -{ - int end; - - if (st->st_pass == 1) - symtable_update_free_vars(st); - Py_DECREF(st->st_cur); - end = PyList_GET_SIZE(st->st_stack) - 1; - st->st_cur = (PySymtableEntryObject *)PyList_GET_ITEM(st->st_stack, - end); - if (PySequence_DelItem(st->st_stack, end) < 0) - return -1; - return 0; + a->a_postorder = (basicblock **)PyObject_Malloc( + sizeof(basicblock *) * nblocks); + if (!a->a_postorder) + return 0; + return 1; } static void -symtable_enter_scope(struct symtable *st, char *name, int type, - int lineno) +assemble_free(struct assembler *a) { - PySymtableEntryObject *prev = NULL; - - if (st->st_cur) { - prev = st->st_cur; - if (PyList_Append(st->st_stack, (PyObject *)st->st_cur) < 0) { - st->st_errors++; - return; - } - } - st->st_cur = (PySymtableEntryObject *) - PySymtableEntry_New(st, name, type, lineno); - if (st->st_cur == NULL) { - st->st_errors++; - return; - } - if (strcmp(name, TOP) == 0) - st->st_global = st->st_cur->ste_symbols; - if (prev && st->st_pass == 1) { - if (PyList_Append(prev->ste_children, - (PyObject *)st->st_cur) < 0) - st->st_errors++; - } + Py_XDECREF(a->a_bytecode); + Py_XDECREF(a->a_lnotab); + if (a->a_postorder) + PyObject_Free(a->a_postorder); } -static int -symtable_lookup(struct symtable *st, char *name) -{ - char buffer[MANGLE_LEN]; - PyObject *v; - int flags; - - if (_Py_Mangle(st->st_private, name, buffer, sizeof(buffer))) - name = buffer; - v = PyDict_GetItemString(st->st_cur->ste_symbols, name); - if (v == NULL) { - if (PyErr_Occurred()) - return -1; - else - return 0; - } - - flags = PyInt_AS_LONG(v); - return flags; -} +/* Return the size of a basic block in bytes. */ static int -symtable_add_def(struct symtable *st, char *name, int flag) +instrsize(struct instr *instr) { - PyObject *s; - char buffer[MANGLE_LEN]; - int ret; - - /* Warn about None, except inside a tuple (where the assignment - code already issues a warning). */ - if ((flag & DEF_PARAM) && !(flag & DEF_INTUPLE) && - *name == 'N' && strcmp(name, "None") == 0) - { - PyErr_SetString(PyExc_SyntaxError, - "Invalid syntax. Assignment to None."); - symtable_error(st, 0); - return -1; + int size = 1; + if (instr->i_hasarg) { + size += 2; + if (instr->i_oparg >> 16) + size += 2; } - if (_Py_Mangle(st->st_private, name, buffer, sizeof(buffer))) - name = buffer; - if ((s = PyString_InternFromString(name)) == NULL) - return -1; - ret = symtable_add_def_o(st, st->st_cur->ste_symbols, s, flag); - Py_DECREF(s); - return ret; + return size; } -/* Must only be called with mangled names */ - static int -symtable_add_def_o(struct symtable *st, PyObject *dict, - PyObject *name, int flag) +blocksize(basicblock *b) { - PyObject *o; - int val; - - if ((o = PyDict_GetItem(dict, name))) { - val = PyInt_AS_LONG(o); - if ((flag & DEF_PARAM) && (val & DEF_PARAM)) { - PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT, - PyString_AsString(name)); - return symtable_error(st, 0); - } - val |= flag; - } else - val = flag; - o = PyInt_FromLong(val); - if (o == NULL) - return -1; - if (PyDict_SetItem(dict, name, o) < 0) { - Py_DECREF(o); - return -1; - } - Py_DECREF(o); + int i; + int size = 0; - if (flag & DEF_PARAM) { - if (PyList_Append(st->st_cur->ste_varnames, name) < 0) - return -1; - } else if (flag & DEF_GLOBAL) { - /* XXX need to update DEF_GLOBAL for other flags too; - perhaps only DEF_FREE_GLOBAL */ - if ((o = PyDict_GetItem(st->st_global, name))) { - val = PyInt_AS_LONG(o); - val |= flag; - } else - val = flag; - o = PyInt_FromLong(val); - if (o == NULL) - return -1; - if (PyDict_SetItem(st->st_global, name, o) < 0) { - Py_DECREF(o); - return -1; - } - Py_DECREF(o); - } - return 0; + for (i = 0; i < b->b_iused; i++) + size += instrsize(&b->b_instr[i]); + return size; } -#define symtable_add_use(ST, NAME) symtable_add_def((ST), (NAME), USE) - -/* Look for a yield stmt or expr under n. Return 1 if found, else 0. - This hack is used to look inside "if 0:" blocks (which are normally - ignored) in case those are the only places a yield occurs (so that this - function is a generator). */ -static int -look_for_yield(node *n) -{ - int i; - - for (i = 0; i < NCH(n); ++i) { - node *kid = CHILD(n, i); +/* All about a_lnotab. - switch (TYPE(kid)) { +c_lnotab is an array of unsigned bytes disguised as a Python string. +It is used to map bytecode offsets to source code line #s (when needed +for tracebacks). - case classdef: - case funcdef: - case lambdef: - /* Stuff in nested functions and classes can't make - the parent a generator. */ - return 0; +The array is conceptually a list of + (bytecode offset increment, line number increment) +pairs. The details are important and delicate, best illustrated by example: - case yield_stmt: - case yield_expr: - return GENERATOR; + byte code offset source code line number + 0 1 + 6 2 + 50 7 + 350 307 + 361 308 - default: - if (look_for_yield(kid)) - return GENERATOR; - } - } - return 0; -} +The first trick is that these numbers aren't stored, only the increments +from one row to the next (this doesn't really work, but it's a start): -static void -symtable_node(struct symtable *st, node *n) -{ - int i; + 0, 1, 6, 1, 44, 5, 300, 300, 11, 1 - loop: - switch (TYPE(n)) { - case funcdef: { - char *func_name; - if (NCH(n) == 6) - symtable_node(st, CHILD(n, 0)); - func_name = STR(RCHILD(n, -4)); - symtable_add_def(st, func_name, DEF_LOCAL); - symtable_default_args(st, RCHILD(n, -3)); - symtable_enter_scope(st, func_name, TYPE(n), n->n_lineno); - symtable_funcdef(st, n); - symtable_exit_scope(st); - break; - } - case lambdef: - if (NCH(n) == 4) - symtable_default_args(st, CHILD(n, 1)); - symtable_enter_scope(st, "lambda", TYPE(n), n->n_lineno); - symtable_funcdef(st, n); - symtable_exit_scope(st); - break; - case classdef: { - char *tmp, *class_name = STR(CHILD(n, 1)); - symtable_add_def(st, class_name, DEF_LOCAL); - if (TYPE(CHILD(n, 2)) == LPAR) { - node *bases = CHILD(n, 3); - int i; - for (i = 0; i < NCH(bases); i += 2) { - symtable_node(st, CHILD(bases, i)); - } - } - symtable_enter_scope(st, class_name, TYPE(n), n->n_lineno); - tmp = st->st_private; - st->st_private = class_name; - symtable_node(st, CHILD(n, NCH(n) - 1)); - st->st_private = tmp; - symtable_exit_scope(st); - break; - } - case if_stmt: - for (i = 0; i + 3 < NCH(n); i += 4) { - if (is_constant_false(NULL, (CHILD(n, i + 1)))) { - if (st->st_cur->ste_generator == 0) - st->st_cur->ste_generator = - look_for_yield(CHILD(n, i+3)); - continue; - } - symtable_node(st, CHILD(n, i + 1)); - symtable_node(st, CHILD(n, i + 3)); - } - if (i + 2 < NCH(n)) - symtable_node(st, CHILD(n, i + 2)); - break; - case global_stmt: - symtable_global(st, n); - break; - case import_stmt: - symtable_import(st, n); - break; - case exec_stmt: { - st->st_cur->ste_optimized |= OPT_EXEC; - symtable_node(st, CHILD(n, 1)); - if (NCH(n) > 2) - symtable_node(st, CHILD(n, 3)); - else { - st->st_cur->ste_optimized |= OPT_BARE_EXEC; - st->st_cur->ste_opt_lineno = n->n_lineno; - } - if (NCH(n) > 4) - symtable_node(st, CHILD(n, 5)); - break; +The second trick is that an unsigned byte can't hold negative values, or +values larger than 255, so (a) there's a deep assumption that byte code +offsets and their corresponding line #s both increase monotonically, and (b) +if at least one column jumps by more than 255 from one row to the next, more +than one pair is written to the table. In case #b, there's no way to know +from looking at the table later how many were written. That's the delicate +part. A user of c_lnotab desiring to find the source line number +corresponding to a bytecode address A should do something like this - } - case assert_stmt: - if (Py_OptimizeFlag) - return; - if (NCH(n) == 2) { - n = CHILD(n, 1); - goto loop; - } else { - symtable_node(st, CHILD(n, 1)); - n = CHILD(n, 3); - goto loop; - } - case except_clause: - if (NCH(n) == 4) - symtable_assign(st, CHILD(n, 3), 0); - if (NCH(n) > 1) { - n = CHILD(n, 1); - goto loop; - } - break; - case del_stmt: - symtable_assign(st, CHILD(n, 1), 0); - break; - case yield_expr: - st->st_cur->ste_generator = 1; - if (NCH(n)==1) - break; - n = CHILD(n, 1); - goto loop; - case expr_stmt: - if (NCH(n) == 1) - n = CHILD(n, 0); - else { - if (TYPE(CHILD(n, 1)) == augassign) { - symtable_assign(st, CHILD(n, 0), 0); - symtable_node(st, CHILD(n, 2)); - break; - } else { - int i; - for (i = 0; i < NCH(n) - 2; i += 2) - symtable_assign(st, CHILD(n, i), 0); - n = CHILD(n, NCH(n) - 1); - } - } - goto loop; - case list_iter: - /* only occurs when there are multiple for loops - in a list comprehension */ - n = CHILD(n, 0); - if (TYPE(n) == list_for) - symtable_list_for(st, n); - else { - REQ(n, list_if); - symtable_node(st, CHILD(n, 1)); - if (NCH(n) == 3) { - n = CHILD(n, 2); - goto loop; - } - } - break; - case for_stmt: - symtable_assign(st, CHILD(n, 1), 0); - for (i = 3; i < NCH(n); ++i) - if (TYPE(CHILD(n, i)) >= single_input) - symtable_node(st, CHILD(n, i)); - break; - case arglist: - if (NCH(n) > 1) - for (i = 0; i < NCH(n); ++i) { - node *ch = CHILD(n, i); - if (TYPE(ch) == argument && NCH(ch) == 2 && - TYPE(CHILD(ch, 1)) == gen_for) { - PyErr_SetString(PyExc_SyntaxError, - "invalid syntax"); - symtable_error(st, n->n_lineno); - return; - } - } - /* The remaining cases fall through to default except in - special circumstances. This requires the individual cases - to be coded with great care, even though they look like - rather innocuous. Each case must double-check TYPE(n). - */ - case decorator: - if (TYPE(n) == decorator) { - /* decorator: '@' dotted_name [ '(' [arglist] ')' ] */ - node *name, *varname; - name = CHILD(n, 1); - REQ(name, dotted_name); - varname = CHILD(name, 0); - REQ(varname, NAME); - symtable_add_use(st, STR(varname)); - } - /* fall through */ - case argument: - if (TYPE(n) == argument && NCH(n) == 3) { - n = CHILD(n, 2); - goto loop; - } - else if (TYPE(n) == argument && NCH(n) == 2 && - TYPE(CHILD(n, 1)) == gen_for) { - symtable_generator_expression(st, n); - break; - } - /* fall through */ - case listmaker: - if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for) { - symtable_list_comprehension(st, n); - break; - } - /* fall through */ - case testlist_gexp: - if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) { - symtable_generator_expression(st, n); - break; - } - /* fall through */ + lineno = addr = 0 + for addr_incr, line_incr in c_lnotab: + addr += addr_incr + if addr > A: + return lineno + lineno += line_incr - case atom: - if (TYPE(n) == atom) { - if (TYPE(CHILD(n, 0)) == NAME) { - symtable_add_use(st, STR(CHILD(n, 0))); - break; - } - else if (TYPE(CHILD(n,0)) == LPAR) { - n = CHILD(n,1); - goto loop; - } - } - /* fall through */ - default: - /* Walk over every non-token child with a special case - for one child. - */ - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto loop; - } - for (i = 0; i < NCH(n); ++i) - if (TYPE(CHILD(n, i)) >= single_input) - symtable_node(st, CHILD(n, i)); - } -} +In order for this to work, when the addr field increments by more than 255, +the line # increment in each pair generated must be 0 until the remaining addr +increment is < 256. So, in the example above, com_set_lineno should not (as +was actually done until 2.2) expand 300, 300 to 255, 255, 45, 45, but to +255, 0, 45, 255, 0, 45. +*/ -static void -symtable_funcdef(struct symtable *st, node *n) +static int +assemble_lnotab(struct assembler *a, struct instr *i) { - node *body; - - if (TYPE(n) == lambdef) { - if (NCH(n) == 4) - symtable_params(st, CHILD(n, 1)); - } else - symtable_params(st, RCHILD(n, -3)); - body = CHILD(n, NCH(n) - 1); - symtable_node(st, body); -} + int d_bytecode, d_lineno; + int len; + char *lnotab; -/* The next two functions parse the argument tuple. - symtable_default_args() checks for names in the default arguments, - which are references in the defining scope. symtable_params() - parses the parameter names, which are defined in the function's - body. + d_bytecode = a->a_offset - a->a_lineno_off; + d_lineno = i->i_lineno - a->a_lineno; - varargslist: - (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) - | fpdef ['=' test] (',' fpdef ['=' test])* [','] -*/ + assert(d_bytecode >= 0); + assert(d_lineno >= 0); -static void -symtable_default_args(struct symtable *st, node *n) -{ - node *c; - int i; + if (d_lineno == 0) + return 1; - if (TYPE(n) == parameters) { - n = CHILD(n, 1); - if (TYPE(n) == RPAR) - return; - } - REQ(n, varargslist); - for (i = 0; i < NCH(n); i += 2) { - c = CHILD(n, i); - if (TYPE(c) == STAR || TYPE(c) == DOUBLESTAR) { - break; + if (d_bytecode > 255) { + int i, nbytes, ncodes = d_bytecode / 255; + nbytes = a->a_lnotab_off + 2 * ncodes; + len = PyString_GET_SIZE(a->a_lnotab); + if (nbytes >= len) { + if (len * 2 < nbytes) + len = nbytes; + else + len *= 2; + if (_PyString_Resize(&a->a_lnotab, len) < 0) + return 0; + } + lnotab = PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off; + for (i = 0; i < ncodes; i++) { + *lnotab++ = 255; + *lnotab++ = 0; + } + d_bytecode -= ncodes * 255; + a->a_lnotab_off += ncodes * 2; + } + assert(d_bytecode <= 255); + if (d_lineno > 255) { + int i, nbytes, ncodes = d_lineno / 255; + nbytes = a->a_lnotab_off + 2 * ncodes; + len = PyString_GET_SIZE(a->a_lnotab); + if (nbytes >= len) { + if (len * 2 < nbytes) + len = nbytes; + else + len *= 2; + if (_PyString_Resize(&a->a_lnotab, len) < 0) + return 0; } - if (i > 0 && (TYPE(CHILD(n, i - 1)) == EQUAL)) - symtable_node(st, CHILD(n, i)); + lnotab = PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off; + *lnotab++ = 255; + *lnotab++ = d_bytecode; + d_bytecode = 0; + for (i = 1; i < ncodes; i++) { + *lnotab++ = 255; + *lnotab++ = 0; + } + d_lineno -= ncodes * 255; + a->a_lnotab_off += ncodes * 2; } -} -static void -symtable_params(struct symtable *st, node *n) -{ - int i, complex = -1, ext = 0; - node *c = NULL; - - if (TYPE(n) == parameters) { - n = CHILD(n, 1); - if (TYPE(n) == RPAR) - return; - } - REQ(n, varargslist); - for (i = 0; i < NCH(n); i += 2) { - c = CHILD(n, i); - if (TYPE(c) == STAR || TYPE(c) == DOUBLESTAR) { - ext = 1; - break; - } - if (TYPE(c) == test) { - continue; - } - if (TYPE(CHILD(c, 0)) == NAME) - symtable_add_def(st, STR(CHILD(c, 0)), DEF_PARAM); - else { - char nbuf[30]; - PyOS_snprintf(nbuf, sizeof(nbuf), ".%d", i); - symtable_add_def(st, nbuf, DEF_PARAM); - complex = i; - } + len = PyString_GET_SIZE(a->a_lnotab); + if (a->a_lnotab_off + 2 >= len) { + if (_PyString_Resize(&a->a_lnotab, len * 2) < 0) + return 0; } - if (ext) { - c = CHILD(n, i); - if (TYPE(c) == STAR) { - i++; - symtable_add_def(st, STR(CHILD(n, i)), - DEF_PARAM | DEF_STAR); - i += 2; - if (i >= NCH(n)) - c = NULL; - else - c = CHILD(n, i); - } - if (c && TYPE(c) == DOUBLESTAR) { - i++; - symtable_add_def(st, STR(CHILD(n, i)), - DEF_PARAM | DEF_DOUBLESTAR); - } + lnotab = PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off; + + a->a_lnotab_off += 2; + if (d_bytecode) { + *lnotab++ = d_bytecode; + *lnotab++ = d_lineno; } - if (complex >= 0) { - int j; - for (j = 0; j <= complex; j++) { - c = CHILD(n, j); - if (TYPE(c) == COMMA) - c = CHILD(n, ++j); - else if (TYPE(c) == EQUAL) - c = CHILD(n, j += 3); - if (TYPE(CHILD(c, 0)) == LPAR) - symtable_params_fplist(st, CHILD(c, 1)); - } + else { /* First line of a block; def stmt, etc. */ + *lnotab++ = 0; + *lnotab++ = d_lineno; } + a->a_lineno = i->i_lineno; + a->a_lineno_off = a->a_offset; + return 1; } -static void -symtable_params_fplist(struct symtable *st, node *n) +/* assemble_emit() + Extend the bytecode with a new instruction. + Update lnotab if necessary. +*/ + +static int +assemble_emit(struct assembler *a, struct instr *i) { - int i; - node *c; - - REQ(n, fplist); - for (i = 0; i < NCH(n); i += 2) { - c = CHILD(n, i); - REQ(c, fpdef); - if (NCH(c) == 1) - symtable_add_def(st, STR(CHILD(c, 0)), - DEF_PARAM | DEF_INTUPLE); + int arg = 0, size = 0, ext = i->i_oparg >> 16; + int len = PyString_GET_SIZE(a->a_bytecode); + char *code; + + if (!i->i_hasarg) + size = 1; + else { + if (ext) + size = 6; else - symtable_params_fplist(st, CHILD(c, 1)); + size = 3; + arg = i->i_oparg; } - + if (i->i_lineno && !assemble_lnotab(a, i)) + return 0; + if (a->a_offset + size >= len) { + if (_PyString_Resize(&a->a_bytecode, len * 2) < 0) + return 0; + } + code = PyString_AS_STRING(a->a_bytecode) + a->a_offset; + a->a_offset += size; + if (ext > 0) { + *code++ = (char)EXTENDED_ARG; + *code++ = ext & 0xff; + *code++ = ext >> 8; + arg &= 0xffff; + } + *code++ = i->i_opcode; + if (size == 1) + return 1; + *code++ = arg & 0xff; + *code++ = arg >> 8; + return 1; } -static void -symtable_global(struct symtable *st, node *n) +static int +assemble_jump_offsets(struct assembler *a, struct compiler *c) { + basicblock *b; + int bsize, totsize = 0; int i; - /* XXX It might be helpful to warn about module-level global - statements, but it's hard to tell the difference between - module-level and a string passed to exec. - */ - - for (i = 1; i < NCH(n); i += 2) { - char *name = STR(CHILD(n, i)); - int flags; - - flags = symtable_lookup(st, name); - if (flags < 0) - continue; - if (flags && flags != DEF_GLOBAL) { - char buf[500]; - if (flags & DEF_PARAM) { - PyErr_Format(PyExc_SyntaxError, PARAM_GLOBAL, - name); - symtable_error(st, 0); - return; - } - else { - if (flags & DEF_LOCAL) - PyOS_snprintf(buf, sizeof(buf), - GLOBAL_AFTER_ASSIGN, - name); - else - PyOS_snprintf(buf, sizeof(buf), - GLOBAL_AFTER_USE, name); - symtable_warn(st, buf); + /* Compute the size of each block and fixup jump args. + Replace block pointer with position in bytecode. */ + for (i = a->a_nblocks - 1; i >= 0; i--) { + basicblock *b = a->a_postorder[i]; + bsize = blocksize(b); + b->b_offset = totsize; + totsize += bsize; + } + for (b = c->u->u_blocks; b != NULL; b = b->b_list) { + bsize = b->b_offset; + for (i = 0; i < b->b_iused; i++) { + struct instr *instr = &b->b_instr[i]; + /* Relative jumps are computed relative to + the instruction pointer after fetching + the jump instruction. + */ + bsize += instrsize(instr); + if (instr->i_jabs) + instr->i_oparg = instr->i_target->b_offset; + else if (instr->i_jrel) { + int delta = instr->i_target->b_offset - bsize; + instr->i_oparg = delta; } } - symtable_add_def(st, name, DEF_GLOBAL); } + return 1; } -static void -symtable_list_comprehension(struct symtable *st, node *n) -{ - /* listmaker: test list_for */ - char tmpname[30]; - - REQ(n, listmaker); - PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", - ++st->st_cur->ste_tmpname); - symtable_add_def(st, tmpname, DEF_LOCAL); - symtable_list_for(st, CHILD(n, 1)); - symtable_node(st, CHILD(n, 0)); - --st->st_cur->ste_tmpname; -} - -static void -symtable_generator_expression(struct symtable *st, node *n) +static PyObject * +dict_keys_inorder(PyObject *dict, int offset) { - /* testlist_gexp: test gen_for */ - REQ(CHILD(n, 0), test); - REQ(CHILD(n, 1), gen_for); - - symtable_enter_scope(st, "<genexpr>", TYPE(n), n->n_lineno); - st->st_cur->ste_generator = GENERATOR_EXPRESSION; - - symtable_add_def(st, "[outmost-iterable]", DEF_PARAM); - - symtable_gen_for(st, CHILD(n, 1), 1); - symtable_node(st, CHILD(n, 0)); - symtable_exit_scope(st); - - /* for outmost iterable precomputation */ - symtable_node(st, CHILD(CHILD(n, 1), 3)); -} + PyObject *tuple, *k, *v; + int i, pos = 0, size = PyDict_Size(dict); -static void -symtable_list_for(struct symtable *st, node *n) -{ - REQ(n, list_for); - /* list_for: for v in expr [list_iter] */ - symtable_assign(st, CHILD(n, 1), 0); - symtable_node(st, CHILD(n, 3)); - if (NCH(n) == 5) - symtable_node(st, CHILD(n, 4)); + tuple = PyTuple_New(size); + if (tuple == NULL) + return NULL; + while (PyDict_Next(dict, &pos, &k, &v)) { + i = PyInt_AS_LONG(v); + k = PyTuple_GET_ITEM(k, 0); + Py_INCREF(k); + assert((i - offset) < size); + assert((i - offset) >= 0); + PyTuple_SET_ITEM(tuple, i - offset, k); + } + return tuple; } -static void -symtable_gen_for(struct symtable *st, node *n, int is_outmost) -{ - REQ(n, gen_for); +static int +compute_code_flags(struct compiler *c) +{ + PySTEntryObject *ste = c->u->u_ste; + int flags = 0, n; + if (ste->ste_type != ModuleBlock) + flags |= CO_NEWLOCALS; + if (ste->ste_type == FunctionBlock) { + if (!ste->ste_unoptimized) + flags |= CO_OPTIMIZED; + if (ste->ste_nested) + flags |= CO_NESTED; + if (ste->ste_generator) + flags |= CO_GENERATOR; + } + if (ste->ste_varargs) + flags |= CO_VARARGS; + if (ste->ste_varkeywords) + flags |= CO_VARKEYWORDS; + if (ste->ste_generator) + flags |= CO_GENERATOR; + if (c->c_flags->cf_flags & CO_FUTURE_DIVISION) + flags |= CO_FUTURE_DIVISION; + n = PyDict_Size(c->u->u_freevars); + if (n < 0) + return -1; + if (n == 0) { + n = PyDict_Size(c->u->u_cellvars); + if (n < 0) + return -1; + if (n == 0) { + flags |= CO_NOFREE; + } + } - /* gen_for: for v in test [gen_iter] */ - symtable_assign(st, CHILD(n, 1), 0); - if (is_outmost) - symtable_add_use(st, "[outmost-iterable]"); - else - symtable_node(st, CHILD(n, 3)); + return flags; +} - if (NCH(n) == 5) - symtable_gen_iter(st, CHILD(n, 4)); +static PyCodeObject * +makecode(struct compiler *c, struct assembler *a) +{ + PyObject *tmp; + PyCodeObject *co = NULL; + PyObject *consts = NULL; + PyObject *names = NULL; + PyObject *varnames = NULL; + PyObject *filename = NULL; + PyObject *name = NULL; + PyObject *freevars = NULL; + PyObject *cellvars = NULL; + PyObject *bytecode = NULL; + int nlocals, flags; + + tmp = dict_keys_inorder(c->u->u_consts, 0); + if (!tmp) + goto error; + consts = PySequence_List(tmp); /* optimize_code requires a list */ + Py_DECREF(tmp); + + names = dict_keys_inorder(c->u->u_names, 0); + varnames = dict_keys_inorder(c->u->u_varnames, 0); + if (!consts || !names || !varnames) + goto error; + + cellvars = dict_keys_inorder(c->u->u_cellvars, 0); + if (!cellvars) + goto error; + freevars = dict_keys_inorder(c->u->u_freevars, PyTuple_Size(cellvars)); + if (!freevars) + goto error; + filename = PyString_FromString(c->c_filename); + if (!filename) + goto error; + + nlocals = PyDict_Size(c->u->u_varnames); + flags = compute_code_flags(c); + if (flags < 0) + goto error; + + bytecode = optimize_code(a->a_bytecode, consts, names, a->a_lnotab); + if (!bytecode) + goto error; + + tmp = PyList_AsTuple(consts); /* PyCode_New requires a tuple */ + if (!tmp) + goto error; + Py_DECREF(consts); + consts = tmp; + + co = PyCode_New(c->u->u_argcount, nlocals, stackdepth(c), flags, + bytecode, consts, names, varnames, + freevars, cellvars, + filename, c->u->u_name, + c->u->u_firstlineno, + a->a_lnotab); + error: + Py_XDECREF(consts); + Py_XDECREF(names); + Py_XDECREF(varnames); + Py_XDECREF(filename); + Py_XDECREF(name); + Py_XDECREF(freevars); + Py_XDECREF(cellvars); + Py_XDECREF(bytecode); + return co; } -static void -symtable_gen_iter(struct symtable *st, node *n) +static PyCodeObject * +assemble(struct compiler *c, int addNone) { - REQ(n, gen_iter); - - n = CHILD(n, 0); - if (TYPE(n) == gen_for) - symtable_gen_for(st, n, 0); - else { - REQ(n, gen_if); - symtable_node(st, CHILD(n, 1)); + basicblock *b, *entryblock; + struct assembler a; + int i, j, nblocks; + PyCodeObject *co = NULL; - if (NCH(n) == 3) - symtable_gen_iter(st, CHILD(n, 2)); + /* Make sure every block that falls off the end returns None. + XXX NEXT_BLOCK() isn't quite right, because if the last + block ends with a jump or return b_next shouldn't set. + */ + if (!c->u->u_curblock->b_return) { + NEXT_BLOCK(c); + if (addNone) + ADDOP_O(c, LOAD_CONST, Py_None, consts); + ADDOP(c, RETURN_VALUE); } -} -static void -symtable_import(struct symtable *st, node *n) -{ - node *nn; - int i; - /* import_stmt: import_name | import_from */ - n = CHILD(n, 0); - if (TYPE(n) == import_from) { - /* import_from: 'from' dotted_name 'import' ('*' | - | '(' import_as_names ')' | import_as_names) */ - node *dotname = CHILD(n, 1); - REQ(dotname, dotted_name); - if (strcmp(STR(CHILD(dotname, 0)), "__future__") == 0) { - /* check for bogus imports */ - if (n->n_lineno >= st->st_future->ff_last_lineno) { - PyErr_SetString(PyExc_SyntaxError, - LATE_FUTURE); - symtable_error(st, n->n_lineno); - return; - } - } - nn = CHILD(n, 3 + (TYPE(CHILD(n, 3)) == LPAR)); - if (TYPE(nn) == STAR) { - if (st->st_cur->ste_type != TYPE_MODULE) { - if (symtable_warn(st, - "import * only allowed at module level") < 0) - return; - } - st->st_cur->ste_optimized |= OPT_IMPORT_STAR; - st->st_cur->ste_opt_lineno = n->n_lineno; - } else { - REQ(nn, import_as_names); - for (i = 0; i < NCH(nn); i += 2) { - node *c = CHILD(nn, i); - if (NCH(c) > 1) /* import as */ - symtable_assign(st, CHILD(c, 2), - DEF_IMPORT); - else - symtable_assign(st, CHILD(c, 0), - DEF_IMPORT); - } - } - } else { - /* 'import' dotted_as_names */ - nn = CHILD(n, 1); - REQ(nn, dotted_as_names); - for (i = 0; i < NCH(nn); i += 2) - symtable_assign(st, CHILD(nn, i), DEF_IMPORT); + nblocks = 0; + entryblock = NULL; + for (b = c->u->u_blocks; b != NULL; b = b->b_list) { + nblocks++; + entryblock = b; } -} - -/* The third argument to symatble_assign() is a flag to be passed to - symtable_add_def() if it is eventually called. The flag is useful - to specify the particular type of assignment that should be - recorded, e.g. an assignment caused by import. - */ -static void -symtable_assign(struct symtable *st, node *n, int def_flag) -{ - node *tmp; - int i; + if (!assemble_init(&a, nblocks, c->u->u_firstlineno)) + goto error; + dfs(c, entryblock, &a); - loop: - switch (TYPE(n)) { - case lambdef: - /* invalid assignment, e.g. lambda x:x=2. The next - pass will catch this error. */ - return; - case power: - if (NCH(n) > 2) { - for (i = 2; i < NCH(n); ++i) - if (TYPE(CHILD(n, i)) != DOUBLESTAR) - symtable_node(st, CHILD(n, i)); - } - if (NCH(n) > 1) { - symtable_node(st, CHILD(n, 0)); - symtable_node(st, CHILD(n, 1)); - } else { - n = CHILD(n, 0); - goto loop; - } - return; - case listmaker: - if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for) { - /* XXX This is an error, but the next pass - will catch it. */ - return; - } else { - for (i = 0; i < NCH(n); i += 2) - symtable_assign(st, CHILD(n, i), def_flag); - } - return; - case testlist_gexp: - if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) { - /* XXX This is an error, but the next pass - will catch it. */ - return; - } else { - for (i = 0; i < NCH(n); i += 2) - symtable_assign(st, CHILD(n, i), def_flag); - } - return; + /* Can't modify the bytecode after computing jump offsets. */ + if (!assemble_jump_offsets(&a, c)) + goto error; - case exprlist: - case testlist: - case testlist1: - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto loop; - } - else { - int i; - for (i = 0; i < NCH(n); i += 2) - symtable_assign(st, CHILD(n, i), def_flag); - return; - } - case atom: - tmp = CHILD(n, 0); - if (TYPE(tmp) == LPAR || TYPE(tmp) == LSQB) { - n = CHILD(n, 1); - goto loop; - } else if (TYPE(tmp) == NAME) { - if (strcmp(STR(tmp), "__debug__") == 0) { - PyErr_SetString(PyExc_SyntaxError, - ASSIGN_DEBUG); - symtable_error(st, n->n_lineno); - return; - } - symtable_add_def(st, STR(tmp), DEF_LOCAL | def_flag); - } - return; + /* Emit code in reverse postorder from dfs. */ + for (i = a.a_nblocks - 1; i >= 0; i--) { + basicblock *b = a.a_postorder[i]; + for (j = 0; j < b->b_iused; j++) + if (!assemble_emit(&a, &b->b_instr[j])) + goto error; + } - case yield_expr: - st->st_cur->ste_generator = 1; - if (NCH(n)==2) { - n = CHILD(n, 1); - goto loop; - } - return; + if (_PyString_Resize(&a.a_lnotab, a.a_lnotab_off) < 0) + goto error; + if (_PyString_Resize(&a.a_bytecode, a.a_offset) < 0) + goto error; - case dotted_as_name: - if (NCH(n) == 3) - symtable_add_def(st, STR(CHILD(n, 2)), - DEF_LOCAL | def_flag); - else - symtable_add_def(st, - STR(CHILD(CHILD(n, - 0), 0)), - DEF_LOCAL | def_flag); - return; - case dotted_name: - symtable_add_def(st, STR(CHILD(n, 0)), DEF_LOCAL | def_flag); - return; - case NAME: - symtable_add_def(st, STR(n), DEF_LOCAL | def_flag); - return; - default: - if (NCH(n) == 0) - return; - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto loop; - } - /* Should only occur for errors like x + 1 = 1, - which will be caught in the next pass. */ - for (i = 0; i < NCH(n); ++i) - if (TYPE(CHILD(n, i)) >= single_input) - symtable_assign(st, CHILD(n, i), def_flag); - } + co = makecode(c, &a); + error: + assemble_free(&a); + return co; } |