summaryrefslogtreecommitdiffstats
path: root/Python/compile.c
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2005-10-20 19:59:25 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2005-10-20 19:59:25 (GMT)
commit3e0055f8c65c407e74ce476b8e2b1fb889723514 (patch)
tree169cce8c87033e15364b57de947073e6e9c34d59 /Python/compile.c
parent2cb94aba122b86dcda87d437eb36a860d14393d5 (diff)
downloadcpython-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.c8493
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;
}