mirror of
https://github.com/python/cpython.git
synced 2024-12-02 14:24:12 +08:00
985eba53f5
-DCALL_PROFILE: Count the number of function calls executed. When this symbol is defined, the ceval mainloop and helper functions count the number of function calls made. It keeps detailed statistics about what kind of object was called and whether the call hit any of the special fast paths in the code. Optimization: When we take the fast_function() path, which seems to be taken for most function calls, and there is minimal frame setup to do, avoid call PyEval_EvalCodeEx(). The eval code ex function does a lot of work to handle keywords args and star args, free variables, generators, etc. The inlined version simply allocates the frame and copies the arguments values into the frame. The optimization gets a little help from compile.c which adds a CO_NOFREE flag to code objects that don't have free variables or cell variables. This change allows fast_function() to get into the fast path with fewer tests. I measure a couple of percent speedup in pystone with this change, but there's surely more that can be done.
5650 lines
130 KiB
C
5650 lines
130 KiB
C
/* 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?
|
|
*/
|
|
|
|
#include "Python.h"
|
|
|
|
#include "node.h"
|
|
#include "token.h"
|
|
#include "graminit.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
|
|
|
|
#define VAR_LOAD 0
|
|
#define VAR_STORE 1
|
|
#define VAR_DELETE 2
|
|
|
|
#define DEL_CLOSURE_ERROR \
|
|
"can not delete variable '%.400s' referenced in nested scope"
|
|
|
|
#define DUPLICATE_ARGUMENT \
|
|
"duplicate argument '%s' in function definition"
|
|
|
|
#define ILLEGAL_DYNAMIC_SCOPE \
|
|
"%.100s: exec or 'import *' makes names ambiguous in nested scope"
|
|
|
|
#define GLOBAL_AFTER_ASSIGN \
|
|
"name '%.400s' is assigned to before global declaration"
|
|
|
|
#define GLOBAL_AFTER_USE \
|
|
"name '%.400s' is used prior to global declaration"
|
|
|
|
#define LOCAL_GLOBAL \
|
|
"name '%.400s' is a function parameter and declared global"
|
|
|
|
#define LATE_FUTURE \
|
|
"from __future__ imports must occur at the beginning of the file"
|
|
|
|
#define ASSIGN_DEBUG \
|
|
"can not assign to __debug__"
|
|
|
|
#define MANGLE_LEN 256
|
|
|
|
#define OFF(x) offsetof(PyCodeObject, x)
|
|
|
|
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 */
|
|
};
|
|
|
|
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.");
|
|
|
|
static PyObject *
|
|
code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
|
{
|
|
int argcount;
|
|
int nlocals;
|
|
int stacksize;
|
|
int flags;
|
|
PyObject *code;
|
|
PyObject *consts;
|
|
PyObject *names;
|
|
PyObject *varnames;
|
|
PyObject *freevars = NULL;
|
|
PyObject *cellvars = 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;
|
|
|
|
if (freevars == NULL || cellvars == NULL) {
|
|
PyObject *empty = PyTuple_New(0);
|
|
if (empty == NULL)
|
|
return NULL;
|
|
if (freevars == NULL) {
|
|
freevars = empty;
|
|
Py_INCREF(freevars);
|
|
}
|
|
if (cellvars == NULL) {
|
|
cellvars = empty;
|
|
Py_INCREF(cellvars);
|
|
}
|
|
Py_DECREF(empty);
|
|
}
|
|
|
|
if (!PyObject_CheckReadBuffer(code)) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"bytecode object must be a single-segment read-only buffer");
|
|
return NULL;
|
|
}
|
|
|
|
return (PyObject *)PyCode_New(argcount, nlocals, stacksize, flags,
|
|
code, consts, names, varnames,
|
|
freevars, cellvars, filename, name,
|
|
firstlineno, lnotab);
|
|
}
|
|
|
|
static void
|
|
code_dealloc(PyCodeObject *co)
|
|
{
|
|
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);
|
|
}
|
|
|
|
static PyObject *
|
|
code_repr(PyCodeObject *co)
|
|
{
|
|
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);
|
|
}
|
|
|
|
static int
|
|
code_compare(PyCodeObject *co, PyCodeObject *cp)
|
|
{
|
|
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 = 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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 */
|
|
};
|
|
|
|
#define NAME_CHARS \
|
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
|
|
|
|
/* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */
|
|
|
|
static int
|
|
all_name_chars(unsigned char *s)
|
|
{
|
|
static char ok_name_char[256];
|
|
static unsigned char *name_chars = (unsigned char *)NAME_CHARS;
|
|
|
|
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;
|
|
}
|
|
|
|
static int
|
|
intern_strings(PyObject *tuple)
|
|
{
|
|
int i;
|
|
|
|
for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
|
|
PyObject *v = PyTuple_GET_ITEM(tuple, i);
|
|
if (v == NULL || !PyString_Check(v)) {
|
|
Py_FatalError("non-string found in code slot");
|
|
PyErr_BadInternalCall();
|
|
return -1;
|
|
}
|
|
PyString_InternInPlace(&PyTuple_GET_ITEM(tuple, i));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
return co;
|
|
}
|
|
|
|
|
|
/* 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; /* list */
|
|
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, c_last_line, c_lnotab_next;
|
|
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 = Py_BuildValue("(OO)", 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)
|
|
{
|
|
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");
|
|
}
|
|
}
|
|
|
|
/* 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_list(struct compiling *, node *, int);
|
|
static void com_list_iter(struct compiling *, node *, node *, char *);
|
|
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 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_build(struct compiling *, node *);
|
|
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 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);
|
|
}
|
|
|
|
#define DUMP(N) dump(N, 0, -1)
|
|
|
|
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_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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
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);
|
|
*/
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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)
|
|
{
|
|
com_addbyte(c, x & 0xff);
|
|
com_addbyte(c, x >> 8); /* XXX x should be positive */
|
|
}
|
|
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
else {
|
|
int incr_addr = c->c_nexti - c->c_last_addr;
|
|
int incr_line = lineno - c->c_last_line;
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
com_addbyte(c, op);
|
|
com_addint(c, arg);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* 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 = Py_BuildValue("(OO)", 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);
|
|
}
|
|
Py_DECREF(t);
|
|
return n;
|
|
fail:
|
|
Py_XDECREF(np);
|
|
Py_XDECREF(t);
|
|
c->c_errors++;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
com_addconst(struct compiling *c, PyObject *v)
|
|
{
|
|
return com_add(c, c->c_consts, c->c_const_dict, v);
|
|
}
|
|
|
|
static int
|
|
com_addname(struct compiling *c, PyObject *v)
|
|
{
|
|
return com_add(c, c->c_names, c->c_name_dict, v);
|
|
}
|
|
|
|
int
|
|
_Py_Mangle(char *p, char *name, char *buffer, size_t maxlen)
|
|
{
|
|
/* 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;
|
|
}
|
|
|
|
static void
|
|
com_addop_name(struct compiling *c, int op, char *name)
|
|
{
|
|
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);
|
|
}
|
|
|
|
#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)
|
|
{
|
|
PyObject *v = PyDict_GetItem(dict, name);
|
|
if (v == NULL)
|
|
return -1;
|
|
else
|
|
return PyInt_AS_LONG(v);
|
|
}
|
|
|
|
static int
|
|
none_assignment_check(struct compiling *c, char *name, int assigning)
|
|
{
|
|
if (name[0] == 'N' && strcmp(name, "None") == 0) {
|
|
char *msg;
|
|
if (assigning)
|
|
msg = "assignment to None";
|
|
else
|
|
msg = "deleting None";
|
|
if (issue_warning(msg, c->c_filename, c->c_lineno) < 0) {
|
|
c->c_errors++;
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
com_addop_varname(struct compiling *c, int kind, char *name)
|
|
{
|
|
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))
|
|
{
|
|
c->c_errors++;
|
|
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;
|
|
}
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
done:
|
|
com_addoparg(c, op, i);
|
|
}
|
|
|
|
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)
|
|
{
|
|
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) {
|
|
if (PyErr_WarnExplicit(
|
|
PyExc_FutureWarning,
|
|
"hex/oct constants > sys.maxint "
|
|
"will return positive values "
|
|
"in Python 2.4 and up",
|
|
/* XXX: Give WarnExplicit
|
|
a const char* argument. */
|
|
(char*)c->c_filename,
|
|
c->c_lineno,
|
|
NULL,
|
|
NULL) < 0)
|
|
return NULL;
|
|
errno = 0; /* Might be changed by PyErr_Warn() */
|
|
}
|
|
}
|
|
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 = atof(s);
|
|
PyFPE_END_PROTECT(z)
|
|
return PyComplex_FromCComplex(z);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
PyFPE_START_PROTECT("atof", return 0)
|
|
dx = 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
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
v = PyString_DecodeEscape(s, len, NULL, unicode,
|
|
need_encoding ? encoding : NULL);
|
|
if (v == NULL)
|
|
PyErr_SyntaxLocation(c->c_filename, c->c_lineno);
|
|
return v;
|
|
}
|
|
|
|
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;
|
|
|
|
onError:
|
|
Py_XDECREF(v);
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
com_list_for(struct compiling *c, node *n, node *e, char *t)
|
|
{
|
|
int anchor = 0;
|
|
int save_begin = c->c_begin;
|
|
|
|
/* list_iter: 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 */
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
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_addoparg(c, CALL_FUNCTION, 1);
|
|
com_addbyte(c, POP_TOP);
|
|
com_pop(c, 2);
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_list_comprehension(struct compiling *c, node *n)
|
|
{
|
|
/* listmaker: test list_for */
|
|
char tmpname[30];
|
|
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_name(c, LOAD_ATTR, "append");
|
|
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;
|
|
}
|
|
|
|
static void
|
|
com_listmaker(struct compiling *c, node *n)
|
|
{
|
|
/* 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);
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_dictmaker(struct compiling *c, node *n)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_atom(struct compiling *c, node *n)
|
|
{
|
|
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
|
|
com_node(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");
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_argument(struct compiling *c, node *n, PyObject **pkeywords)
|
|
{
|
|
node *m;
|
|
REQ(n, argument); /* [test '='] test; 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;
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_select_member(struct compiling *c, node *n)
|
|
{
|
|
com_addopname(c, LOAD_ATTR, n);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
return found_radix_point;
|
|
}
|
|
|
|
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 && 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));
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_shift_expr(struct compiling *c, node *n)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_xor_expr(struct compiling *c, node *n)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
static enum cmp_op
|
|
cmp_type(node *n)
|
|
{
|
|
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: /* == */
|
|
case EQUAL: 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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
return PyCmp_BAD;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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 void
|
|
com_and_test(struct compiling *c, node *n)
|
|
{
|
|
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);
|
|
}
|
|
|
|
static int
|
|
com_make_closure(struct compiling *c, PyCodeObject *co)
|
|
{
|
|
int i, free = PyCode_GetNumFree(co);
|
|
if (free == 0)
|
|
return 0;
|
|
for (i = 0; i < free; ++i) {
|
|
/* Bypass com_addop_varname because it will generate
|
|
LOAD_DEREF but LOAD_CLOSURE is needed.
|
|
*/
|
|
PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
|
|
int arg, reftype;
|
|
|
|
/* Special case: If a class contains a method with a
|
|
free variable that has the same name as a method,
|
|
the name will be considered free *and* local in the
|
|
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));
|
|
if (reftype == CELL)
|
|
arg = com_lookup_arg(c->c_cellvars, name);
|
|
else /* (reftype == FREE) */
|
|
arg = com_lookup_arg(c->c_freevars, name);
|
|
if (arg == -1) {
|
|
fprintf(stderr, "lookup %s in %s %d %d\n"
|
|
"freevars of %s: %s\n",
|
|
PyObject_REPR(name),
|
|
c->c_name,
|
|
reftype, arg,
|
|
PyString_AS_STRING(co->co_name),
|
|
PyObject_REPR(co->co_freevars));
|
|
Py_FatalError("com_make_closure()");
|
|
}
|
|
com_addoparg(c, LOAD_CLOSURE, arg);
|
|
|
|
}
|
|
com_push(c, free);
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
com_test(struct compiling *c, node *n)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_list(struct compiling *c, node *n, int toplevel)
|
|
{
|
|
/* 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);
|
|
}
|
|
}
|
|
|
|
|
|
/* Begin of assignment compilation */
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_assign_sequence(struct compiling *c, node *n, int assigning)
|
|
{
|
|
int i;
|
|
if (TYPE(n) != testlist && 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);
|
|
}
|
|
|
|
static void
|
|
com_augassign_name(struct compiling *c, node *n, int opcode, node *augn)
|
|
{
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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:
|
|
if (NCH(n) > 1) {
|
|
if (assigning > OP_APPLY) {
|
|
com_error(c, PyExc_SyntaxError,
|
|
"augmented assign to tuple not possible");
|
|
return;
|
|
}
|
|
com_assign_sequence(c, n, assigning);
|
|
return;
|
|
}
|
|
n = CHILD(n, 0);
|
|
break;
|
|
|
|
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 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 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;
|
|
|
|
case lambdef:
|
|
com_error(c, PyExc_SyntaxError,
|
|
"can't assign to lambda");
|
|
return;
|
|
|
|
default:
|
|
com_error(c, PyExc_SystemError,
|
|
"com_assign: bad node");
|
|
return;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_augassign(struct compiling *c, node *n)
|
|
{
|
|
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));
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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>]
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
else {
|
|
com_node(c, CHILD(n, i));
|
|
/* stack: [...] => [... obj] */
|
|
com_addbyte(c, PRINT_ITEM);
|
|
com_pop(c, 1);
|
|
}
|
|
}
|
|
/* 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);
|
|
}
|
|
else
|
|
com_addbyte(c, PRINT_NEWLINE);
|
|
}
|
|
}
|
|
|
|
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_stmt(struct compiling *c, node *n)
|
|
{
|
|
int i;
|
|
REQ(n, yield_stmt); /* '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;
|
|
}
|
|
}
|
|
com_node(c, CHILD(n, 1));
|
|
com_addbyte(c, YIELD_VALUE);
|
|
com_pop(c, 1);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
static void
|
|
com_from_import(struct compiling *c, node *n)
|
|
{
|
|
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);
|
|
}
|
|
|
|
static void
|
|
com_import_stmt(struct compiling *c, node *n)
|
|
{
|
|
int i;
|
|
REQ(n, import_stmt);
|
|
/* 'import' dotted_name (',' dotted_name)* |
|
|
'from' dotted_name 'import' ('*' | NAME (',' NAME)*) */
|
|
if (STR(CHILD(n, 0))[0] == 'f') {
|
|
PyObject *tup;
|
|
/* 'from' dotted_name 'import' ... */
|
|
REQ(CHILD(n, 1), dotted_name);
|
|
|
|
if (TYPE(CHILD(n, 3)) == STAR) {
|
|
tup = Py_BuildValue("(s)", "*");
|
|
} else {
|
|
tup = PyTuple_New((NCH(n) - 2)/2);
|
|
for (i = 3; i < NCH(n); i += 2) {
|
|
PyTuple_SET_ITEM(tup, (i-3)/2,
|
|
PyString_FromString(STR(
|
|
CHILD(CHILD(n, i), 0))));
|
|
}
|
|
}
|
|
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(CHILD(n, 3)) == STAR)
|
|
com_addbyte(c, IMPORT_STAR);
|
|
else {
|
|
for (i = 3; i < NCH(n); i += 2)
|
|
com_from_import(c, CHILD(n, i));
|
|
com_addbyte(c, POP_TOP);
|
|
}
|
|
com_pop(c, 1);
|
|
}
|
|
else {
|
|
/* 'import' ... */
|
|
for (i = 1; i < NCH(n); i += 2) {
|
|
node *subn = CHILD(n, 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
if (NCH(n) >= 6)
|
|
com_node(c, CHILD(n, 5));
|
|
else {
|
|
com_addbyte(c, DUP_TOP);
|
|
com_push(c, 1);
|
|
}
|
|
com_addbyte(c, EXEC_STMT);
|
|
com_pop(c, 3);
|
|
}
|
|
|
|
static int
|
|
is_constant_false(struct compiling *c, node *n)
|
|
{
|
|
PyObject *v;
|
|
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;
|
|
}
|
|
}
|
|
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;
|
|
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);
|
|
}
|
|
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, n->n_lineno);
|
|
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);
|
|
}
|
|
|
|
/* Code generated for "try: S finally: Sf" is as follows:
|
|
|
|
SETUP_FINALLY L
|
|
<code for S>
|
|
POP_BLOCK
|
|
LOAD_CONST <nil>
|
|
L: <code for Sf>
|
|
END_FINALLY
|
|
|
|
The special instructions use the block stack. Each block
|
|
stack entry contains the instruction that created it (here
|
|
SETUP_FINALLY), the level of the value stack at the time the
|
|
block stack entry was created, and a label (here L).
|
|
|
|
SETUP_FINALLY:
|
|
Pushes the current value stack level and the label
|
|
onto the block stack.
|
|
POP_BLOCK:
|
|
Pops en entry from the block stack, and pops the value
|
|
stack until its level is the same as indicated on the
|
|
block stack. (The label is ignored.)
|
|
END_FINALLY:
|
|
Pops a variable number of entries from the *value* stack
|
|
and re-raises the exception they specify. The number of
|
|
entries popped depends on the (pseudo) exception type.
|
|
|
|
The block stack is unwound when an exception is raised:
|
|
when a SETUP_FINALLY entry is found, the exception is pushed
|
|
onto the value stack (and the exception condition is cleared),
|
|
and the interpreter jumps to the label gotten from the block
|
|
stack.
|
|
|
|
Code generated for "try: S except E1, V1: S1 except E2, V2: S2 ...":
|
|
(The contents of the value stack is shown in [], with the top
|
|
at the right; 'tb' is trace-back info, 'val' the exception's
|
|
associated value, and 'exc' the exception.)
|
|
|
|
Value stack Label Instruction Argument
|
|
[] SETUP_EXCEPT L1
|
|
[] <code for S>
|
|
[] POP_BLOCK
|
|
[] JUMP_FORWARD L0
|
|
|
|
[tb, val, exc] L1: DUP )
|
|
[tb, val, exc, exc] <evaluate E1> )
|
|
[tb, val, exc, exc, E1] COMPARE_OP EXC_MATCH ) only if E1
|
|
[tb, val, exc, 1-or-0] JUMP_IF_FALSE L2 )
|
|
[tb, val, exc, 1] POP )
|
|
[tb, val, exc] POP
|
|
[tb, val] <assign to V1> (or POP if no V1)
|
|
[tb] POP
|
|
[] <code for S1>
|
|
JUMP_FORWARD L0
|
|
|
|
[tb, val, exc, 0] L2: POP
|
|
[tb, val, exc] DUP
|
|
.............................etc.......................
|
|
|
|
[tb, val, exc, 0] Ln+1: POP
|
|
[tb, val, exc] END_FINALLY # re-raise exception
|
|
|
|
[] L0: <next statement>
|
|
|
|
Of course, parts are not generated if Vi or Ei is not present.
|
|
*/
|
|
|
|
static void
|
|
com_try_except(struct compiling *c, node *n)
|
|
{
|
|
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;
|
|
}
|
|
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);
|
|
}
|
|
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);
|
|
}
|
|
|
|
static void
|
|
com_try_finally(struct compiling *c, node *n)
|
|
{
|
|
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 */
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
static PyObject *
|
|
get_docstring(struct compiling *c, node *n)
|
|
{
|
|
/* 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);
|
|
}
|
|
|
|
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));
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
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 */
|
|
}
|
|
|
|
static int
|
|
com_argdefs(struct compiling *c, node *n)
|
|
{
|
|
int i, nch, nargs, ndefs;
|
|
if (TYPE(n) == lambdef) {
|
|
/* lambdef: 'lambda' [varargslist] ':' test */
|
|
n = CHILD(n, 1);
|
|
}
|
|
else {
|
|
REQ(n, funcdef); /* funcdef: 'def' NAME parameters ... */
|
|
n = CHILD(n, 2);
|
|
REQ(n, parameters); /* parameters: '(' [varargslist] ')' */
|
|
n = CHILD(n, 1);
|
|
}
|
|
if (TYPE(n) != varargslist)
|
|
return 0;
|
|
/* varargslist:
|
|
(fpdef ['=' test] ',')* '*' ....... |
|
|
fpdef ['=' test] (',' fpdef ['=' test])* [','] */
|
|
nch = NCH(n);
|
|
nargs = 0;
|
|
ndefs = 0;
|
|
for (i = 0; i < nch; i++) {
|
|
int t;
|
|
if (TYPE(CHILD(n, i)) == STAR ||
|
|
TYPE(CHILD(n, i)) == DOUBLESTAR)
|
|
break;
|
|
nargs++;
|
|
i++;
|
|
if (i >= nch)
|
|
t = RPAR; /* Anything except EQUAL or COMMA */
|
|
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));
|
|
}
|
|
else {
|
|
/* Treat "(a=1, b)" as an error */
|
|
if (ndefs)
|
|
com_error(c, PyExc_SyntaxError,
|
|
"non-default argument follows default argument");
|
|
}
|
|
if (t != COMMA)
|
|
break;
|
|
}
|
|
return ndefs;
|
|
}
|
|
|
|
static void
|
|
com_funcdef(struct compiling *c, node *n)
|
|
{
|
|
PyObject *co;
|
|
int ndefs;
|
|
REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
|
|
ndefs = com_argdefs(c, n);
|
|
symtable_enter_scope(c->c_symtable, STR(CHILD(n, 1)), 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);
|
|
else
|
|
com_addoparg(c, MAKE_FUNCTION, ndefs);
|
|
com_pop(c, ndefs);
|
|
com_addop_varname(c, VAR_STORE, STR(CHILD(n, 1)));
|
|
com_pop(c, 1);
|
|
Py_DECREF(co);
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_bases(struct compiling *c, node *n)
|
|
{
|
|
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);
|
|
}
|
|
|
|
static void
|
|
com_classdef(struct compiling *c, node *n)
|
|
{
|
|
int i;
|
|
PyObject *v;
|
|
PyCodeObject *co;
|
|
char *name;
|
|
|
|
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) {
|
|
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);
|
|
}
|
|
}
|
|
|
|
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);
|
|
break;
|
|
case for_stmt:
|
|
com_for_stmt(c, n);
|
|
break;
|
|
case try_stmt:
|
|
com_try_stmt(c, n);
|
|
break;
|
|
case suite:
|
|
com_suite(c, n);
|
|
break;
|
|
|
|
/* Expression nodes */
|
|
|
|
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);
|
|
break;
|
|
case power:
|
|
com_power(c, n);
|
|
break;
|
|
case atom:
|
|
com_atom(c, n);
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_fplist(struct compiling *c, node *n)
|
|
{
|
|
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));
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
com_file_input(struct compiling *c, node *n)
|
|
{
|
|
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);
|
|
}
|
|
for (i = 0; i < NCH(n); i++) {
|
|
node *ch = CHILD(n, i);
|
|
if (TYPE(ch) != ENDMARKER && TYPE(ch) != NEWLINE)
|
|
com_node(c, ch);
|
|
}
|
|
}
|
|
|
|
/* Top-level compile-node interface */
|
|
|
|
static void
|
|
compile_funcdef(struct compiling *c, node *n)
|
|
{
|
|
PyObject *doc;
|
|
node *ch;
|
|
REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
|
|
c->c_name = STR(CHILD(n, 1));
|
|
doc = get_docstring(c, CHILD(n, 4));
|
|
if (doc != NULL) {
|
|
(void) com_addconst(c, doc);
|
|
Py_DECREF(doc);
|
|
}
|
|
else
|
|
(void) com_addconst(c, Py_None); /* No docstring */
|
|
ch = CHILD(n, 2); /* parameters: '(' [varargslist] ')' */
|
|
ch = CHILD(ch, 1); /* ')' | varargslist */
|
|
if (TYPE(ch) == varargslist)
|
|
com_arglist(c, ch);
|
|
c->c_infunction = 1;
|
|
com_node(c, CHILD(n, 4));
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
else
|
|
ch = CHILD(n, 2);
|
|
com_node(c, ch);
|
|
com_addbyte(c, RETURN_VALUE);
|
|
com_pop(c, 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);
|
|
}
|
|
else
|
|
(void) com_addconst(c, Py_None);
|
|
com_node(c, ch);
|
|
com_addbyte(c, LOAD_LOCALS);
|
|
com_push(c, 1);
|
|
com_addbyte(c, RETURN_VALUE);
|
|
com_pop(c, 1);
|
|
}
|
|
|
|
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_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--;
|
|
break;
|
|
|
|
case file_input: /* A whole file, or built-in function exec() */
|
|
com_file_input(c, n);
|
|
com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
|
|
com_push(c, 1);
|
|
com_addbyte(c, RETURN_VALUE);
|
|
com_pop(c, 1);
|
|
break;
|
|
|
|
case eval_input: /* Built-in function input() */
|
|
com_node(c, CHILD(n, 0));
|
|
com_addbyte(c, RETURN_VALUE);
|
|
com_pop(c, 1);
|
|
break;
|
|
|
|
case lambdef: /* anonymous function definition */
|
|
compile_lambdef(c, n);
|
|
break;
|
|
|
|
case funcdef: /* A function definition */
|
|
compile_funcdef(c, n);
|
|
break;
|
|
|
|
case classdef: /* A class definition */
|
|
compile_classdef(c, n);
|
|
break;
|
|
|
|
default:
|
|
com_error(c, PyExc_SystemError,
|
|
"compile_node: unexpected node type");
|
|
}
|
|
}
|
|
|
|
static PyObject *
|
|
dict_keys_inorder(PyObject *dict, int offset)
|
|
{
|
|
PyObject *tuple, *k, *v;
|
|
int i, pos = 0, size = PyDict_Size(dict);
|
|
|
|
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;
|
|
}
|
|
|
|
PyCodeObject *
|
|
PyNode_Compile(node *n, const char *filename)
|
|
{
|
|
return PyNode_CompileFlags(n, filename, NULL);
|
|
}
|
|
|
|
PyCodeObject *
|
|
PyNode_CompileFlags(node *n, const char *filename, PyCompilerFlags *flags)
|
|
{
|
|
return jcompile(n, filename, NULL, flags);
|
|
}
|
|
|
|
struct symtable *
|
|
PyNode_CompileSymtable(node *n, const char *filename)
|
|
{
|
|
struct symtable *st;
|
|
PyFutureFeatures *ff;
|
|
|
|
ff = PyNode_Future(n, filename);
|
|
if (ff == NULL)
|
|
return NULL;
|
|
|
|
st = symtable_init();
|
|
if (st == NULL) {
|
|
PyObject_FREE((void *)ff);
|
|
return NULL;
|
|
}
|
|
st->st_future = ff;
|
|
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:
|
|
PyObject_FREE((void *)ff);
|
|
st->st_future = NULL;
|
|
PySymtable_Free(st);
|
|
return NULL;
|
|
}
|
|
|
|
static PyCodeObject *
|
|
icompile(node *n, struct compiling *base)
|
|
{
|
|
return jcompile(n, base->c_filename, base, NULL);
|
|
}
|
|
|
|
static PyCodeObject *
|
|
jcompile(node *n, const char *filename, struct compiling *base,
|
|
PyCompilerFlags *flags)
|
|
{
|
|
struct compiling sc;
|
|
PyCodeObject *co;
|
|
if (!com_init(&sc, filename))
|
|
return NULL;
|
|
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;
|
|
}
|
|
if (symtable_build(&sc, n) < 0) {
|
|
com_free(&sc);
|
|
return NULL;
|
|
}
|
|
}
|
|
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;
|
|
consts = PyList_AsTuple(sc.c_consts);
|
|
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);
|
|
if (!PyErr_Occurred())
|
|
co = PyCode_New(sc.c_argcount,
|
|
sc.c_nlocals,
|
|
sc.c_maxstacklevel,
|
|
sc.c_flags,
|
|
sc.c_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);
|
|
}
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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 int
|
|
get_ref_type(struct compiling *c, char *name)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/* Helper functions to issue warnings */
|
|
|
|
static int
|
|
issue_warning(const char *msg, const char *filename, int lineno)
|
|
{
|
|
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);
|
|
}
|
|
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;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Helper function for setting lineno and filename */
|
|
|
|
static int
|
|
symtable_build(struct compiling *c, node *n)
|
|
{
|
|
if ((c->c_symtable = symtable_init()) == NULL)
|
|
return -1;
|
|
c->c_symtable->st_future = c->c_future;
|
|
c->c_symtable->st_filename = c->c_filename;
|
|
symtable_enter_scope(c->c_symtable, TOP, TYPE(n), n->n_lineno);
|
|
if (c->c_symtable->st_errors > 0)
|
|
return -1;
|
|
symtable_node(c->c_symtable, n);
|
|
if (c->c_symtable->st_errors > 0)
|
|
return -1;
|
|
/* reset for second pass */
|
|
c->c_symtable->st_nscopes = 1;
|
|
c->c_symtable->st_pass = 2;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
symtable_init_compiling_symbols(struct compiling *c)
|
|
{
|
|
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 symbol_info {
|
|
int si_nlocals;
|
|
int si_ncells;
|
|
int si_nfrees;
|
|
int si_nimplicit;
|
|
};
|
|
|
|
static void
|
|
symtable_init_info(struct symbol_info *si)
|
|
{
|
|
si->si_nlocals = 0;
|
|
si->si_ncells = 0;
|
|
si->si_nfrees = 0;
|
|
si->si_nimplicit = 0;
|
|
}
|
|
|
|
static int
|
|
symtable_resolve_free(struct compiling *c, PyObject *name, int flags,
|
|
struct symbol_info *si)
|
|
{
|
|
PyObject *dict, *v;
|
|
|
|
/* 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;
|
|
}
|
|
Py_DECREF(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
|
|
symtable_cellvar_offsets(PyObject **cellvars, int argcount,
|
|
PyObject *varnames, int flags)
|
|
{
|
|
PyObject *v, *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
|
|
PyList_Insert(list, 0, v);
|
|
}
|
|
}
|
|
if (list == NULL || PyList_GET_SIZE(list) == 0)
|
|
return 0;
|
|
/* There are cellvars that are also arguments. Create a dict
|
|
to replace cellvars and put the args at the front.
|
|
*/
|
|
d = PyDict_New();
|
|
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;
|
|
}
|
|
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 (PyDict_SetItem(d, v, w) < 0) {
|
|
Py_DECREF(w);
|
|
goto fail;
|
|
}
|
|
Py_DECREF(w);
|
|
}
|
|
Py_DECREF(*cellvars);
|
|
*cellvars = d;
|
|
return 1;
|
|
fail:
|
|
Py_DECREF(d);
|
|
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);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
PyErr_SetString(PyExc_SyntaxError, buf);
|
|
PyErr_SyntaxLocation(c->c_symtable->st_filename,
|
|
ste->ste_opt_lineno);
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste,
|
|
struct symbol_info *si)
|
|
{
|
|
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);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
symtable_load_symbols(struct compiling *c)
|
|
{
|
|
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 (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, LOCAL_GLOBAL,
|
|
PyString_AS_STRING(name));
|
|
PyErr_SyntaxLocation(st->st_filename,
|
|
ste->ste_lineno);
|
|
st->st_errors++;
|
|
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 (PyDict_SetItem(st->st_global,
|
|
name, v))
|
|
goto fail;
|
|
Py_DECREF(v);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
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;
|
|
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_tmpname = 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);
|
|
}
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
static int
|
|
symtable_update_free_vars(struct symtable *st)
|
|
{
|
|
int i, j, def;
|
|
PyObject *o, *name, *list = NULL;
|
|
PySymtableEntryObject *child, *ste = st->st_cur;
|
|
|
|
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 (list)
|
|
PyList_SetSlice(list, 0,
|
|
((PyVarObject*)list)->ob_size, 0);
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Py_XDECREF(list);
|
|
return 0;
|
|
}
|
|
|
|
/* 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.
|
|
*/
|
|
|
|
static int
|
|
symtable_check_global(struct symtable *st, PyObject *child, PyObject *name)
|
|
{
|
|
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);
|
|
}
|
|
|
|
static int
|
|
symtable_undo_free(struct symtable *st, PyObject *id,
|
|
PyObject *name)
|
|
{
|
|
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)
|
|
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. */
|
|
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;
|
|
}
|
|
|
|
static void
|
|
symtable_enter_scope(struct symtable *st, char *name, int type,
|
|
int lineno)
|
|
{
|
|
PySymtableEntryObject *prev = NULL;
|
|
|
|
if (st->st_cur) {
|
|
prev = st->st_cur;
|
|
if (PyList_Append(st->st_stack, (PyObject *)st->st_cur) < 0) {
|
|
Py_DECREF(st->st_cur);
|
|
st->st_errors++;
|
|
return;
|
|
}
|
|
}
|
|
st->st_cur = (PySymtableEntryObject *)
|
|
PySymtableEntry_New(st, name, type, lineno);
|
|
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++;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static int
|
|
symtable_add_def(struct symtable *st, char *name, int flag)
|
|
{
|
|
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)
|
|
{
|
|
if (symtable_warn(st, "argument named None"))
|
|
return -1;
|
|
}
|
|
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;
|
|
}
|
|
|
|
/* Must only be called with mangled names */
|
|
|
|
static int
|
|
symtable_add_def_o(struct symtable *st, PyObject *dict,
|
|
PyObject *name, int flag)
|
|
{
|
|
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));
|
|
PyErr_SyntaxLocation(st->st_filename,
|
|
st->st_cur->ste_lineno);
|
|
return -1;
|
|
}
|
|
val |= flag;
|
|
} else
|
|
val = flag;
|
|
o = PyInt_FromLong(val);
|
|
if (PyDict_SetItem(dict, name, o) < 0) {
|
|
Py_DECREF(o);
|
|
return -1;
|
|
}
|
|
Py_DECREF(o);
|
|
|
|
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 (PyDict_SetItem(st->st_global, name, o) < 0) {
|
|
Py_DECREF(o);
|
|
return -1;
|
|
}
|
|
Py_DECREF(o);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define symtable_add_use(ST, NAME) symtable_add_def((ST), (NAME), USE)
|
|
|
|
/* Look for a yield stmt 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);
|
|
|
|
switch (TYPE(kid)) {
|
|
|
|
case classdef:
|
|
case funcdef:
|
|
case lambdef:
|
|
/* Stuff in nested functions and classes can't make
|
|
the parent a generator. */
|
|
return 0;
|
|
|
|
case yield_stmt:
|
|
return 1;
|
|
|
|
default:
|
|
if (look_for_yield(kid))
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
symtable_node(struct symtable *st, node *n)
|
|
{
|
|
int i;
|
|
|
|
loop:
|
|
switch (TYPE(n)) {
|
|
case funcdef: {
|
|
char *func_name = STR(CHILD(n, 1));
|
|
symtable_add_def(st, func_name, DEF_LOCAL);
|
|
symtable_default_args(st, CHILD(n, 2));
|
|
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;
|
|
|
|
}
|
|
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_stmt:
|
|
st->st_cur->ste_generator = 1;
|
|
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:
|
|
n = CHILD(n, 0);
|
|
if (TYPE(n) == list_for) {
|
|
st->st_tmpname++;
|
|
symtable_list_comprehension(st, n);
|
|
st->st_tmpname--;
|
|
} 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;
|
|
/* 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 argument:
|
|
if (TYPE(n) == argument && NCH(n) == 3) {
|
|
n = CHILD(n, 2);
|
|
goto loop;
|
|
}
|
|
/* fall through */
|
|
case listmaker:
|
|
if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for) {
|
|
st->st_tmpname++;
|
|
symtable_list_comprehension(st, CHILD(n, 1));
|
|
symtable_node(st, CHILD(n, 0));
|
|
st->st_tmpname--;
|
|
break;
|
|
}
|
|
/* fall through */
|
|
case atom:
|
|
if (TYPE(n) == atom && TYPE(CHILD(n, 0)) == NAME) {
|
|
symtable_add_use(st, STR(CHILD(n, 0)));
|
|
break;
|
|
}
|
|
/* 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));
|
|
}
|
|
}
|
|
|
|
static void
|
|
symtable_funcdef(struct symtable *st, node *n)
|
|
{
|
|
node *body;
|
|
|
|
if (TYPE(n) == lambdef) {
|
|
if (NCH(n) == 4)
|
|
symtable_params(st, CHILD(n, 1));
|
|
} else
|
|
symtable_params(st, CHILD(n, 2));
|
|
body = CHILD(n, NCH(n) - 1);
|
|
symtable_node(st, body);
|
|
}
|
|
|
|
/* 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.
|
|
|
|
varargslist:
|
|
(fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME)
|
|
| fpdef ['=' test] (',' fpdef ['=' test])* [',']
|
|
*/
|
|
|
|
static void
|
|
symtable_default_args(struct symtable *st, node *n)
|
|
{
|
|
node *c;
|
|
int i;
|
|
|
|
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 (i > 0 && (TYPE(CHILD(n, i - 1)) == EQUAL))
|
|
symtable_node(st, CHILD(n, i));
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
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));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
symtable_params_fplist(struct symtable *st, node *n)
|
|
{
|
|
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);
|
|
else
|
|
symtable_params_fplist(st, CHILD(c, 1));
|
|
}
|
|
|
|
}
|
|
|
|
static void
|
|
symtable_global(struct symtable *st, node *n)
|
|
{
|
|
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,
|
|
"name '%.400s' is local and global",
|
|
name);
|
|
PyErr_SyntaxLocation(st->st_filename,
|
|
st->st_cur->ste_lineno);
|
|
st->st_errors++;
|
|
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);
|
|
}
|
|
}
|
|
symtable_add_def(st, name, DEF_GLOBAL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
symtable_list_comprehension(struct symtable *st, node *n)
|
|
{
|
|
char tmpname[30];
|
|
|
|
PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", st->st_tmpname);
|
|
symtable_add_def(st, tmpname, DEF_LOCAL);
|
|
symtable_assign(st, CHILD(n, 1), 0);
|
|
symtable_node(st, CHILD(n, 3));
|
|
if (NCH(n) == 5)
|
|
symtable_node(st, CHILD(n, 4));
|
|
}
|
|
|
|
static void
|
|
symtable_import(struct symtable *st, node *n)
|
|
{
|
|
int i;
|
|
/* import_stmt: 'import' dotted_as_name (',' dotted_as_name)*
|
|
| 'from' dotted_name 'import'
|
|
('*' | import_as_name (',' import_as_name)*)
|
|
import_as_name: NAME [NAME NAME]
|
|
*/
|
|
if (STR(CHILD(n, 0))[0] == 'f') { /* from */
|
|
node *dotname = CHILD(n, 1);
|
|
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);
|
|
PyErr_SyntaxLocation(st->st_filename,
|
|
n->n_lineno);
|
|
st->st_errors++;
|
|
return;
|
|
}
|
|
}
|
|
if (TYPE(CHILD(n, 3)) == 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 {
|
|
for (i = 3; i < NCH(n); i += 2) {
|
|
node *c = CHILD(n, 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 {
|
|
for (i = 1; i < NCH(n); i += 2) {
|
|
symtable_assign(st, CHILD(n, i), DEF_IMPORT);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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;
|
|
|
|
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 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);
|
|
PyErr_SyntaxLocation(st->st_filename,
|
|
n->n_lineno);
|
|
st->st_errors++;
|
|
}
|
|
symtable_add_def(st, STR(tmp), DEF_LOCAL | def_flag);
|
|
}
|
|
return;
|
|
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);
|
|
}
|
|
}
|