From a73a964e51247ed169d322c725a3a18859f109a3 Mon Sep 17 00:00:00 2001 From: Ori Bernstein Date: Mon, 14 Jun 2021 00:00:37 +0000 Subject: python, hg: tow outside the environment. they've served us well, and can ride off into the sunset. --- sys/src/cmd/python/Python/symtable.c | 1425 ---------------------------------- 1 file changed, 1425 deletions(-) delete mode 100644 sys/src/cmd/python/Python/symtable.c (limited to 'sys/src/cmd/python/Python/symtable.c') diff --git a/sys/src/cmd/python/Python/symtable.c b/sys/src/cmd/python/Python/symtable.c deleted file mode 100644 index 3e58b5034..000000000 --- a/sys/src/cmd/python/Python/symtable.c +++ /dev/null @@ -1,1425 +0,0 @@ -#include "Python.h" -#include "Python-ast.h" -#include "code.h" -#include "symtable.h" -#include "structmember.h" - -/* error strings used for warnings */ -#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 IMPORT_STAR_WARNING "import * only allowed at module level" - -#define RETURN_VAL_IN_GENERATOR \ - "'return' with argument inside generator" - -/* XXX(nnorwitz): change name since static? */ -static PySTEntryObject * -PySTEntry_New(struct symtable *st, identifier name, _Py_block_ty block, - void *key, int lineno) -{ - PySTEntryObject *ste = NULL; - PyObject *k; - - k = PyLong_FromVoidPtr(key); - if (k == NULL) - goto fail; - ste = (PySTEntryObject *)PyObject_New(PySTEntryObject, - &PySTEntry_Type); - ste->ste_table = st; - ste->ste_id = k; - ste->ste_tmpname = 0; - - ste->ste_name = name; - Py_INCREF(name); - - ste->ste_symbols = NULL; - ste->ste_varnames = NULL; - ste->ste_children = NULL; - - ste->ste_symbols = PyDict_New(); - if (ste->ste_symbols == NULL) - goto fail; - - ste->ste_varnames = PyList_New(0); - if (ste->ste_varnames == NULL) - goto fail; - - ste->ste_children = PyList_New(0); - if (ste->ste_children == NULL) - goto fail; - - ste->ste_type = block; - ste->ste_unoptimized = 0; - ste->ste_nested = 0; - ste->ste_free = 0; - ste->ste_varargs = 0; - ste->ste_varkeywords = 0; - ste->ste_opt_lineno = 0; - ste->ste_tmpname = 0; - ste->ste_lineno = lineno; - - if (st->st_cur != NULL && - (st->st_cur->ste_nested || - st->st_cur->ste_type == FunctionBlock)) - ste->ste_nested = 1; - ste->ste_child_free = 0; - ste->ste_generator = 0; - ste->ste_returns_value = 0; - - if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0) - goto fail; - - return ste; - fail: - Py_XDECREF(ste); - return NULL; -} - -static PyObject * -ste_repr(PySTEntryObject *ste) -{ - char buf[256]; - - PyOS_snprintf(buf, sizeof(buf), - "", - PyString_AS_STRING(ste->ste_name), - PyInt_AS_LONG(ste->ste_id), ste->ste_lineno); - return PyString_FromString(buf); -} - -static void -ste_dealloc(PySTEntryObject *ste) -{ - ste->ste_table = NULL; - Py_XDECREF(ste->ste_id); - Py_XDECREF(ste->ste_name); - Py_XDECREF(ste->ste_symbols); - Py_XDECREF(ste->ste_varnames); - Py_XDECREF(ste->ste_children); - PyObject_Del(ste); -} - -#define OFF(x) offsetof(PySTEntryObject, x) - -static PyMemberDef ste_memberlist[] = { - {"id", T_OBJECT, OFF(ste_id), READONLY}, - {"name", T_OBJECT, OFF(ste_name), READONLY}, - {"symbols", T_OBJECT, OFF(ste_symbols), READONLY}, - {"varnames", T_OBJECT, OFF(ste_varnames), READONLY}, - {"children", T_OBJECT, OFF(ste_children), READONLY}, - {"type", T_INT, OFF(ste_type), READONLY}, - {"lineno", T_INT, OFF(ste_lineno), READONLY}, - {NULL} -}; - -PyTypeObject PySTEntry_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "symtable entry", - sizeof(PySTEntryObject), - 0, - (destructor)ste_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)ste_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - ste_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 */ - 0, /* tp_new */ -}; - -static int symtable_analyze(struct symtable *st); -static int symtable_warn(struct symtable *st, char *msg, int lineno); -static int symtable_enter_block(struct symtable *st, identifier name, - _Py_block_ty block, void *ast, int lineno); -static int symtable_exit_block(struct symtable *st, void *ast); -static int symtable_visit_stmt(struct symtable *st, stmt_ty s); -static int symtable_visit_expr(struct symtable *st, expr_ty s); -static int symtable_visit_genexp(struct symtable *st, expr_ty s); -static int symtable_visit_arguments(struct symtable *st, arguments_ty); -static int symtable_visit_excepthandler(struct symtable *st, excepthandler_ty); -static int symtable_visit_alias(struct symtable *st, alias_ty); -static int symtable_visit_comprehension(struct symtable *st, comprehension_ty); -static int symtable_visit_keyword(struct symtable *st, keyword_ty); -static int symtable_visit_slice(struct symtable *st, slice_ty); -static int symtable_visit_params(struct symtable *st, asdl_seq *args, int top); -static int symtable_visit_params_nested(struct symtable *st, asdl_seq *args); -static int symtable_implicit_arg(struct symtable *st, int pos); - - -static identifier top = NULL, lambda = NULL, genexpr = NULL; - -#define GET_IDENTIFIER(VAR) \ - ((VAR) ? (VAR) : ((VAR) = PyString_InternFromString(# VAR))) - -#define DUPLICATE_ARGUMENT \ -"duplicate argument '%s' in function definition" - -static struct symtable * -symtable_new(void) -{ - struct symtable *st; - - st = (struct symtable *)PyMem_Malloc(sizeof(struct symtable)); - if (st == NULL) - return NULL; - - st->st_filename = NULL; - st->st_symbols = NULL; - - if ((st->st_stack = PyList_New(0)) == NULL) - goto fail; - if ((st->st_symbols = PyDict_New()) == NULL) - goto fail; - st->st_cur = NULL; - st->st_tmpname = 0; - st->st_private = NULL; - return st; - fail: - PySymtable_Free(st); - return NULL; -} - -struct symtable * -PySymtable_Build(mod_ty mod, const char *filename, PyFutureFeatures *future) -{ - struct symtable *st = symtable_new(); - asdl_seq *seq; - int i; - - if (st == NULL) - return st; - st->st_filename = filename; - st->st_future = future; - if (!symtable_enter_block(st, GET_IDENTIFIER(top), ModuleBlock, - (void *)mod, 0)) { - PySymtable_Free(st); - return NULL; - } - - st->st_top = st->st_cur; - st->st_cur->ste_unoptimized = OPT_TOPLEVEL; - /* Any other top-level initialization? */ - switch (mod->kind) { - case Module_kind: - seq = mod->v.Module.body; - for (i = 0; i < asdl_seq_LEN(seq); i++) - if (!symtable_visit_stmt(st, - (stmt_ty)asdl_seq_GET(seq, i))) - goto error; - break; - case Expression_kind: - if (!symtable_visit_expr(st, mod->v.Expression.body)) - goto error; - break; - case Interactive_kind: - seq = mod->v.Interactive.body; - for (i = 0; i < asdl_seq_LEN(seq); i++) - if (!symtable_visit_stmt(st, - (stmt_ty)asdl_seq_GET(seq, i))) - goto error; - break; - case Suite_kind: - PyErr_SetString(PyExc_RuntimeError, - "this compiler does not handle Suites"); - goto error; - } - if (!symtable_exit_block(st, (void *)mod)) { - PySymtable_Free(st); - return NULL; - } - if (symtable_analyze(st)) - return st; - PySymtable_Free(st); - return NULL; - error: - (void) symtable_exit_block(st, (void *)mod); - PySymtable_Free(st); - return NULL; -} - -void -PySymtable_Free(struct symtable *st) -{ - Py_XDECREF(st->st_symbols); - Py_XDECREF(st->st_stack); - PyMem_Free((void *)st); -} - -PySTEntryObject * -PySymtable_Lookup(struct symtable *st, void *key) -{ - PyObject *k, *v; - - k = PyLong_FromVoidPtr(key); - if (k == NULL) - return NULL; - v = PyDict_GetItem(st->st_symbols, k); - if (v) { - assert(PySTEntry_Check(v)); - Py_INCREF(v); - } - else { - PyErr_SetString(PyExc_KeyError, - "unknown symbol table entry"); - } - - Py_DECREF(k); - return (PySTEntryObject *)v; -} - -int -PyST_GetScope(PySTEntryObject *ste, PyObject *name) -{ - PyObject *v = PyDict_GetItem(ste->ste_symbols, name); - if (!v) - return 0; - assert(PyInt_Check(v)); - return (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK; -} - - -/* Analyze raw symbol information to determine scope of each name. - - The next several functions are helpers for PySymtable_Analyze(), - which determines whether a name is local, global, or free. In addition, - it determines which local variables are cell variables; they provide - bindings that are used for free variables in enclosed blocks. - - There are also two kinds of free variables, implicit and explicit. An - explicit global is declared with the global statement. An implicit - global is a free variable for which the compiler has found no binding - in an enclosing function scope. The implicit global is either a global - or a builtin. Python's module and class blocks use the xxx_NAME opcodes - to handle these names to implement slightly odd semantics. In such a - block, the name is treated as global until it is assigned to; then it - is treated as a local. - - The symbol table requires two passes to determine the scope of each name. - The first pass collects raw facts from the AST: the name is a parameter - here, the name is used by not defined here, etc. The second pass analyzes - these facts during a pass over the PySTEntryObjects created during pass 1. - - When a function is entered during the second pass, the parent passes - the set of all name bindings visible to its children. These bindings - are used to determine if the variable is free or an implicit global. - After doing the local analysis, it analyzes each of its child blocks - using an updated set of name bindings. - - The children update the free variable set. If a local variable is free - in a child, the variable is marked as a cell. The current function must - provide runtime storage for the variable that may outlive the function's - frame. Cell variables are removed from the free set before the analyze - function returns to its parent. - - The sets of bound and free variables are implemented as dictionaries - mapping strings to None. -*/ - -#define SET_SCOPE(DICT, NAME, I) { \ - PyObject *o = PyInt_FromLong(I); \ - if (!o) \ - return 0; \ - if (PyDict_SetItem((DICT), (NAME), o) < 0) { \ - Py_DECREF(o); \ - return 0; \ - } \ - Py_DECREF(o); \ -} - -/* Decide on scope of name, given flags. - - The dicts passed in as arguments are modified as necessary. - ste is passed so that flags can be updated. -*/ - -static int -analyze_name(PySTEntryObject *ste, PyObject *dict, PyObject *name, long flags, - PyObject *bound, PyObject *local, PyObject *free, - PyObject *global) -{ - if (flags & DEF_GLOBAL) { - if (flags & DEF_PARAM) { - PyErr_Format(PyExc_SyntaxError, - "name '%s' is local and global", - PyString_AS_STRING(name)); - return 0; - } - SET_SCOPE(dict, name, GLOBAL_EXPLICIT); - if (PyDict_SetItem(global, name, Py_None) < 0) - return 0; - if (bound && PyDict_GetItem(bound, name)) { - if (PyDict_DelItem(bound, name) < 0) - return 0; - } - return 1; - } - if (flags & DEF_BOUND) { - SET_SCOPE(dict, name, LOCAL); - if (PyDict_SetItem(local, name, Py_None) < 0) - return 0; - if (PyDict_GetItem(global, name)) { - if (PyDict_DelItem(global, name) < 0) - return 0; - } - return 1; - } - /* If an enclosing block has a binding for this name, it - is a free variable rather than a global variable. - Note that having a non-NULL bound implies that the block - is nested. - */ - if (bound && PyDict_GetItem(bound, name)) { - SET_SCOPE(dict, name, FREE); - ste->ste_free = 1; - if (PyDict_SetItem(free, name, Py_None) < 0) - return 0; - return 1; - } - /* If a parent has a global statement, then call it global - explicit? It could also be global implicit. - */ - else if (global && PyDict_GetItem(global, name)) { - SET_SCOPE(dict, name, GLOBAL_EXPLICIT); - return 1; - } - else { - if (ste->ste_nested) - ste->ste_free = 1; - SET_SCOPE(dict, name, GLOBAL_IMPLICIT); - return 1; - } - return 0; /* Can't get here */ -} - -#undef SET_SCOPE - -/* If a name is defined in free and also in locals, then this block - provides the binding for the free variable. The name should be - marked CELL in this block and removed from the free list. - - Note that the current block's free variables are included in free. - That's safe because no name can be free and local in the same scope. -*/ - -static int -analyze_cells(PyObject *scope, PyObject *free) -{ - PyObject *name, *v, *w; - int success = 0; - Py_ssize_t pos = 0; - - w = PyInt_FromLong(CELL); - if (!w) - return 0; - while (PyDict_Next(scope, &pos, &name, &v)) { - long flags; - assert(PyInt_Check(v)); - flags = PyInt_AS_LONG(v); - if (flags != LOCAL) - continue; - if (!PyDict_GetItem(free, name)) - continue; - /* Replace LOCAL with CELL for this name, and remove - from free. It is safe to replace the value of name - in the dict, because it will not cause a resize. - */ - if (PyDict_SetItem(scope, name, w) < 0) - goto error; - if (!PyDict_DelItem(free, name) < 0) - goto error; - } - success = 1; - error: - Py_DECREF(w); - return success; -} - -/* Check for illegal statements in unoptimized namespaces */ -static int -check_unoptimized(const PySTEntryObject* ste) { - char buf[300]; - const char* trailer; - - if (ste->ste_type != FunctionBlock || !ste->ste_unoptimized - || !(ste->ste_free || ste->ste_child_free)) - return 1; - - trailer = (ste->ste_child_free ? - "contains a nested function with free variables" : - "is a nested function"); - - switch (ste->ste_unoptimized) { - case OPT_TOPLEVEL: /* exec / import * at top-level is fine */ - case OPT_EXEC: /* qualified exec is fine */ - return 1; - case OPT_IMPORT_STAR: - PyOS_snprintf(buf, sizeof(buf), - "import * is not allowed in function '%.100s' " - "because it is %s", - PyString_AS_STRING(ste->ste_name), trailer); - break; - case OPT_BARE_EXEC: - PyOS_snprintf(buf, sizeof(buf), - "unqualified exec is not allowed in function " - "'%.100s' it %s", - PyString_AS_STRING(ste->ste_name), trailer); - break; - default: - PyOS_snprintf(buf, sizeof(buf), - "function '%.100s' uses import * and bare exec, " - "which are illegal because it %s", - PyString_AS_STRING(ste->ste_name), trailer); - break; - } - - PyErr_SetString(PyExc_SyntaxError, buf); - PyErr_SyntaxLocation(ste->ste_table->st_filename, - ste->ste_opt_lineno); - return 0; -} - -/* Enter the final scope information into the st_symbols dict. - * - * All arguments are dicts. Modifies symbols, others are read-only. -*/ -static int -update_symbols(PyObject *symbols, PyObject *scope, - PyObject *bound, PyObject *free, int classflag) -{ - PyObject *name, *v, *u, *w, *free_value = NULL; - Py_ssize_t pos = 0; - - while (PyDict_Next(symbols, &pos, &name, &v)) { - long i, flags; - assert(PyInt_Check(v)); - flags = PyInt_AS_LONG(v); - w = PyDict_GetItem(scope, name); - assert(w && PyInt_Check(w)); - i = PyInt_AS_LONG(w); - flags |= (i << SCOPE_OFF); - u = PyInt_FromLong(flags); - if (!u) - return 0; - if (PyDict_SetItem(symbols, name, u) < 0) { - Py_DECREF(u); - return 0; - } - Py_DECREF(u); - } - - free_value = PyInt_FromLong(FREE << SCOPE_OFF); - if (!free_value) - return 0; - - /* add a free variable when it's only use is for creating a closure */ - pos = 0; - while (PyDict_Next(free, &pos, &name, &v)) { - PyObject *o = PyDict_GetItem(symbols, name); - - if (o) { - /* It could be a free variable in a method of - the class that has the same name as a local - or global in the class scope. - */ - if (classflag && - PyInt_AS_LONG(o) & (DEF_BOUND | DEF_GLOBAL)) { - long i = PyInt_AS_LONG(o) | DEF_FREE_CLASS; - o = PyInt_FromLong(i); - if (!o) { - Py_DECREF(free_value); - return 0; - } - if (PyDict_SetItem(symbols, name, o) < 0) { - Py_DECREF(o); - Py_DECREF(free_value); - return 0; - } - Py_DECREF(o); - } - /* else it's not free, probably a cell */ - continue; - } - if (!PyDict_GetItem(bound, name)) - continue; /* it's a global */ - - if (PyDict_SetItem(symbols, name, free_value) < 0) { - Py_DECREF(free_value); - return 0; - } - } - Py_DECREF(free_value); - return 1; -} - -/* Make final symbol table decisions for block of ste. - Arguments: - ste -- current symtable entry (input/output) - bound -- set of variables bound in enclosing scopes (input) - free -- set of free variables in enclosed scopes (output) - globals -- set of declared global variables in enclosing scopes (input) -*/ - -static int -analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, - PyObject *global) -{ - PyObject *name, *v, *local = NULL, *scope = NULL, *newbound = NULL; - PyObject *newglobal = NULL, *newfree = NULL; - int i, success = 0; - Py_ssize_t pos = 0; - - local = PyDict_New(); - if (!local) - goto error; - scope = PyDict_New(); - if (!scope) - goto error; - newglobal = PyDict_New(); - if (!newglobal) - goto error; - newfree = PyDict_New(); - if (!newfree) - goto error; - newbound = PyDict_New(); - if (!newbound) - goto error; - - if (ste->ste_type == ClassBlock) { - /* make a copy of globals before calling analyze_name(), - because global statements in the class have no effect - on nested functions. - */ - if (PyDict_Update(newglobal, global) < 0) - goto error; - if (bound) - if (PyDict_Update(newbound, bound) < 0) - goto error; - } - - assert(PySTEntry_Check(ste)); - assert(PyDict_Check(ste->ste_symbols)); - while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) { - long flags = PyInt_AS_LONG(v); - if (!analyze_name(ste, scope, name, flags, bound, local, free, - global)) - goto error; - } - - if (ste->ste_type != ClassBlock) { - if (ste->ste_type == FunctionBlock) { - if (PyDict_Update(newbound, local) < 0) - goto error; - } - if (bound) { - if (PyDict_Update(newbound, bound) < 0) - goto error; - } - if (PyDict_Update(newglobal, global) < 0) - goto error; - } - - /* Recursively call analyze_block() on each child block */ - for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) { - PyObject *c = PyList_GET_ITEM(ste->ste_children, i); - PySTEntryObject* entry; - assert(c && PySTEntry_Check(c)); - entry = (PySTEntryObject*)c; - if (!analyze_block(entry, newbound, newfree, newglobal)) - goto error; - if (entry->ste_free || entry->ste_child_free) - ste->ste_child_free = 1; - } - - if (ste->ste_type == FunctionBlock && !analyze_cells(scope, newfree)) - goto error; - if (!update_symbols(ste->ste_symbols, scope, bound, newfree, - ste->ste_type == ClassBlock)) - goto error; - if (!check_unoptimized(ste)) - goto error; - - if (PyDict_Update(free, newfree) < 0) - goto error; - success = 1; - error: - Py_XDECREF(local); - Py_XDECREF(scope); - Py_XDECREF(newbound); - Py_XDECREF(newglobal); - Py_XDECREF(newfree); - if (!success) - assert(PyErr_Occurred()); - return success; -} - -static int -symtable_analyze(struct symtable *st) -{ - PyObject *free, *global; - int r; - - free = PyDict_New(); - if (!free) - return 0; - global = PyDict_New(); - if (!global) { - Py_DECREF(free); - return 0; - } - r = analyze_block(st->st_top, NULL, free, global); - Py_DECREF(free); - Py_DECREF(global); - return r; -} - - -static int -symtable_warn(struct symtable *st, char *msg, int lineno) -{ - if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, st->st_filename, - lineno, NULL, NULL) < 0) { - if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { - PyErr_SetString(PyExc_SyntaxError, msg); - PyErr_SyntaxLocation(st->st_filename, - st->st_cur->ste_lineno); - } - return 0; - } - return 1; -} - -/* symtable_enter_block() gets a reference via PySTEntry_New(). - This reference is released when the block is exited, via the DECREF - in symtable_exit_block(). -*/ - -static int -symtable_exit_block(struct symtable *st, void *ast) -{ - Py_ssize_t end; - - Py_CLEAR(st->st_cur); - end = PyList_GET_SIZE(st->st_stack) - 1; - if (end >= 0) { - st->st_cur = (PySTEntryObject *)PyList_GET_ITEM(st->st_stack, - end); - if (st->st_cur == NULL) - return 0; - Py_INCREF(st->st_cur); - if (PySequence_DelItem(st->st_stack, end) < 0) - return 0; - } - return 1; -} - -static int -symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block, - void *ast, int lineno) -{ - PySTEntryObject *prev = NULL; - - if (st->st_cur) { - prev = st->st_cur; - if (PyList_Append(st->st_stack, (PyObject *)st->st_cur) < 0) { - return 0; - } - Py_DECREF(st->st_cur); - } - st->st_cur = PySTEntry_New(st, name, block, ast, lineno); - if (st->st_cur == NULL) - return 0; - if (name == GET_IDENTIFIER(top)) - st->st_global = st->st_cur->ste_symbols; - if (prev) { - if (PyList_Append(prev->ste_children, - (PyObject *)st->st_cur) < 0) { - return 0; - } - } - return 1; -} - -static long -symtable_lookup(struct symtable *st, PyObject *name) -{ - PyObject *o; - PyObject *mangled = _Py_Mangle(st->st_private, name); - if (!mangled) - return 0; - o = PyDict_GetItem(st->st_cur->ste_symbols, mangled); - Py_DECREF(mangled); - if (!o) - return 0; - return PyInt_AsLong(o); -} - -static int -symtable_add_def(struct symtable *st, PyObject *name, int flag) -{ - PyObject *o; - PyObject *dict; - long val; - PyObject *mangled = _Py_Mangle(st->st_private, name); - - if (!mangled) - return 0; - dict = st->st_cur->ste_symbols; - if ((o = PyDict_GetItem(dict, mangled))) { - val = PyInt_AS_LONG(o); - if ((flag & DEF_PARAM) && (val & DEF_PARAM)) { - /* Is it better to use 'mangled' or 'name' here? */ - PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT, - PyString_AsString(name)); - PyErr_SyntaxLocation(st->st_filename, - st->st_cur->ste_lineno); - goto error; - } - val |= flag; - } else - val = flag; - o = PyInt_FromLong(val); - if (o == NULL) - goto error; - if (PyDict_SetItem(dict, mangled, o) < 0) { - Py_DECREF(o); - goto error; - } - Py_DECREF(o); - - if (flag & DEF_PARAM) { - if (PyList_Append(st->st_cur->ste_varnames, mangled) < 0) - goto error; - } else if (flag & DEF_GLOBAL) { - /* XXX need to update DEF_GLOBAL for other flags too; - perhaps only DEF_FREE_GLOBAL */ - val = flag; - if ((o = PyDict_GetItem(st->st_global, mangled))) { - val |= PyInt_AS_LONG(o); - } - o = PyInt_FromLong(val); - if (o == NULL) - goto error; - if (PyDict_SetItem(st->st_global, mangled, o) < 0) { - Py_DECREF(o); - goto error; - } - Py_DECREF(o); - } - Py_DECREF(mangled); - return 1; - -error: - Py_DECREF(mangled); - return 0; -} - -/* VISIT, VISIT_SEQ and VIST_SEQ_TAIL take an ASDL type as their second argument. - They use the ASDL name to synthesize the name of the C type and the visit - function. - - VISIT_SEQ_TAIL permits the start of an ASDL sequence to be skipped, which is - useful if the first node in the sequence requires special treatment. -*/ - -#define VISIT(ST, TYPE, V) \ - if (!symtable_visit_ ## TYPE((ST), (V))) \ - return 0; - -#define VISIT_IN_BLOCK(ST, TYPE, V, S) \ - if (!symtable_visit_ ## TYPE((ST), (V))) { \ - symtable_exit_block((ST), (S)); \ - return 0; \ - } - -#define VISIT_SEQ(ST, TYPE, SEQ) { \ - int i; \ - asdl_seq *seq = (SEQ); /* avoid variable capture */ \ - for (i = 0; i < asdl_seq_LEN(seq); i++) { \ - TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ - if (!symtable_visit_ ## TYPE((ST), elt)) \ - return 0; \ - } \ -} - -#define VISIT_SEQ_IN_BLOCK(ST, TYPE, SEQ, S) { \ - int i; \ - asdl_seq *seq = (SEQ); /* avoid variable capture */ \ - for (i = 0; i < asdl_seq_LEN(seq); i++) { \ - TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ - if (!symtable_visit_ ## TYPE((ST), elt)) { \ - symtable_exit_block((ST), (S)); \ - return 0; \ - } \ - } \ -} - -#define VISIT_SEQ_TAIL(ST, TYPE, SEQ, START) { \ - int i; \ - asdl_seq *seq = (SEQ); /* avoid variable capture */ \ - for (i = (START); i < asdl_seq_LEN(seq); i++) { \ - TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ - if (!symtable_visit_ ## TYPE((ST), elt)) \ - return 0; \ - } \ -} - -#define VISIT_SEQ_TAIL_IN_BLOCK(ST, TYPE, SEQ, START, S) { \ - int i; \ - asdl_seq *seq = (SEQ); /* avoid variable capture */ \ - for (i = (START); i < asdl_seq_LEN(seq); i++) { \ - TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ - if (!symtable_visit_ ## TYPE((ST), elt)) { \ - symtable_exit_block((ST), (S)); \ - return 0; \ - } \ - } \ -} - -static int -symtable_new_tmpname(struct symtable *st) -{ - char tmpname[256]; - identifier tmp; - - PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", - ++st->st_cur->ste_tmpname); - tmp = PyString_InternFromString(tmpname); - if (!tmp) - return 0; - if (!symtable_add_def(st, tmp, DEF_LOCAL)) - return 0; - Py_DECREF(tmp); - return 1; -} - -static int -symtable_visit_stmt(struct symtable *st, stmt_ty s) -{ - switch (s->kind) { - case FunctionDef_kind: - if (!symtable_add_def(st, s->v.FunctionDef.name, DEF_LOCAL)) - return 0; - if (s->v.FunctionDef.args->defaults) - VISIT_SEQ(st, expr, s->v.FunctionDef.args->defaults); - if (s->v.FunctionDef.decorators) - VISIT_SEQ(st, expr, s->v.FunctionDef.decorators); - if (!symtable_enter_block(st, s->v.FunctionDef.name, - FunctionBlock, (void *)s, s->lineno)) - return 0; - VISIT_IN_BLOCK(st, arguments, s->v.FunctionDef.args, s); - VISIT_SEQ_IN_BLOCK(st, stmt, s->v.FunctionDef.body, s); - if (!symtable_exit_block(st, s)) - return 0; - break; - case ClassDef_kind: { - PyObject *tmp; - if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL)) - return 0; - VISIT_SEQ(st, expr, s->v.ClassDef.bases); - if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, - (void *)s, s->lineno)) - return 0; - tmp = st->st_private; - st->st_private = s->v.ClassDef.name; - VISIT_SEQ_IN_BLOCK(st, stmt, s->v.ClassDef.body, s); - st->st_private = tmp; - if (!symtable_exit_block(st, s)) - return 0; - break; - } - case Return_kind: - if (s->v.Return.value) { - VISIT(st, expr, s->v.Return.value); - st->st_cur->ste_returns_value = 1; - if (st->st_cur->ste_generator) { - PyErr_SetString(PyExc_SyntaxError, - RETURN_VAL_IN_GENERATOR); - PyErr_SyntaxLocation(st->st_filename, - s->lineno); - return 0; - } - } - break; - case Delete_kind: - VISIT_SEQ(st, expr, s->v.Delete.targets); - break; - case Assign_kind: - VISIT_SEQ(st, expr, s->v.Assign.targets); - VISIT(st, expr, s->v.Assign.value); - break; - case AugAssign_kind: - VISIT(st, expr, s->v.AugAssign.target); - VISIT(st, expr, s->v.AugAssign.value); - break; - case Print_kind: - if (s->v.Print.dest) - VISIT(st, expr, s->v.Print.dest); - VISIT_SEQ(st, expr, s->v.Print.values); - break; - case For_kind: - VISIT(st, expr, s->v.For.target); - VISIT(st, expr, s->v.For.iter); - VISIT_SEQ(st, stmt, s->v.For.body); - if (s->v.For.orelse) - VISIT_SEQ(st, stmt, s->v.For.orelse); - break; - case While_kind: - VISIT(st, expr, s->v.While.test); - VISIT_SEQ(st, stmt, s->v.While.body); - if (s->v.While.orelse) - VISIT_SEQ(st, stmt, s->v.While.orelse); - break; - case If_kind: - /* XXX if 0: and lookup_yield() hacks */ - VISIT(st, expr, s->v.If.test); - VISIT_SEQ(st, stmt, s->v.If.body); - if (s->v.If.orelse) - VISIT_SEQ(st, stmt, s->v.If.orelse); - break; - case Raise_kind: - if (s->v.Raise.type) { - VISIT(st, expr, s->v.Raise.type); - if (s->v.Raise.inst) { - VISIT(st, expr, s->v.Raise.inst); - if (s->v.Raise.tback) - VISIT(st, expr, s->v.Raise.tback); - } - } - break; - case TryExcept_kind: - VISIT_SEQ(st, stmt, s->v.TryExcept.body); - VISIT_SEQ(st, stmt, s->v.TryExcept.orelse); - VISIT_SEQ(st, excepthandler, s->v.TryExcept.handlers); - break; - case TryFinally_kind: - VISIT_SEQ(st, stmt, s->v.TryFinally.body); - VISIT_SEQ(st, stmt, s->v.TryFinally.finalbody); - break; - case Assert_kind: - VISIT(st, expr, s->v.Assert.test); - if (s->v.Assert.msg) - VISIT(st, expr, s->v.Assert.msg); - break; - case Import_kind: - VISIT_SEQ(st, alias, s->v.Import.names); - /* XXX Don't have the lineno available inside - visit_alias */ - if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno) - st->st_cur->ste_opt_lineno = s->lineno; - break; - case ImportFrom_kind: - VISIT_SEQ(st, alias, s->v.ImportFrom.names); - /* XXX Don't have the lineno available inside - visit_alias */ - if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno) - st->st_cur->ste_opt_lineno = s->lineno; - break; - case Exec_kind: - VISIT(st, expr, s->v.Exec.body); - if (!st->st_cur->ste_opt_lineno) - st->st_cur->ste_opt_lineno = s->lineno; - if (s->v.Exec.globals) { - st->st_cur->ste_unoptimized |= OPT_EXEC; - VISIT(st, expr, s->v.Exec.globals); - if (s->v.Exec.locals) - VISIT(st, expr, s->v.Exec.locals); - } else { - st->st_cur->ste_unoptimized |= OPT_BARE_EXEC; - } - break; - case Global_kind: { - int i; - asdl_seq *seq = s->v.Global.names; - for (i = 0; i < asdl_seq_LEN(seq); i++) { - identifier name = (identifier)asdl_seq_GET(seq, i); - char *c_name = PyString_AS_STRING(name); - long cur = symtable_lookup(st, name); - if (cur < 0) - return 0; - if (cur & (DEF_LOCAL | USE)) { - char buf[256]; - if (cur & DEF_LOCAL) - PyOS_snprintf(buf, sizeof(buf), - GLOBAL_AFTER_ASSIGN, - c_name); - else - PyOS_snprintf(buf, sizeof(buf), - GLOBAL_AFTER_USE, - c_name); - if (!symtable_warn(st, buf, s->lineno)) - return 0; - } - if (!symtable_add_def(st, name, DEF_GLOBAL)) - return 0; - } - break; - } - case Expr_kind: - VISIT(st, expr, s->v.Expr.value); - break; - case Pass_kind: - case Break_kind: - case Continue_kind: - /* nothing to do here */ - break; - case With_kind: - if (!symtable_new_tmpname(st)) - return 0; - VISIT(st, expr, s->v.With.context_expr); - if (s->v.With.optional_vars) { - if (!symtable_new_tmpname(st)) - return 0; - VISIT(st, expr, s->v.With.optional_vars); - } - VISIT_SEQ(st, stmt, s->v.With.body); - break; - } - return 1; -} - -static int -symtable_visit_expr(struct symtable *st, expr_ty e) -{ - switch (e->kind) { - case BoolOp_kind: - VISIT_SEQ(st, expr, e->v.BoolOp.values); - break; - case BinOp_kind: - VISIT(st, expr, e->v.BinOp.left); - VISIT(st, expr, e->v.BinOp.right); - break; - case UnaryOp_kind: - VISIT(st, expr, e->v.UnaryOp.operand); - break; - case Lambda_kind: { - if (!symtable_add_def(st, GET_IDENTIFIER(lambda), DEF_LOCAL)) - return 0; - if (e->v.Lambda.args->defaults) - VISIT_SEQ(st, expr, e->v.Lambda.args->defaults); - /* XXX how to get line numbers for expressions */ - if (!symtable_enter_block(st, GET_IDENTIFIER(lambda), - FunctionBlock, (void *)e, 0)) - return 0; - VISIT_IN_BLOCK(st, arguments, e->v.Lambda.args, (void*)e); - VISIT_IN_BLOCK(st, expr, e->v.Lambda.body, (void*)e); - if (!symtable_exit_block(st, (void *)e)) - return 0; - break; - } - case IfExp_kind: - VISIT(st, expr, e->v.IfExp.test); - VISIT(st, expr, e->v.IfExp.body); - VISIT(st, expr, e->v.IfExp.orelse); - break; - case Dict_kind: - VISIT_SEQ(st, expr, e->v.Dict.keys); - VISIT_SEQ(st, expr, e->v.Dict.values); - break; - case ListComp_kind: - if (!symtable_new_tmpname(st)) - return 0; - VISIT(st, expr, e->v.ListComp.elt); - VISIT_SEQ(st, comprehension, e->v.ListComp.generators); - break; - case GeneratorExp_kind: - if (!symtable_visit_genexp(st, e)) - return 0; - break; - case Yield_kind: - if (e->v.Yield.value) - VISIT(st, expr, e->v.Yield.value); - st->st_cur->ste_generator = 1; - if (st->st_cur->ste_returns_value) { - PyErr_SetString(PyExc_SyntaxError, - RETURN_VAL_IN_GENERATOR); - PyErr_SyntaxLocation(st->st_filename, - e->lineno); - return 0; - } - break; - case Compare_kind: - VISIT(st, expr, e->v.Compare.left); - VISIT_SEQ(st, expr, e->v.Compare.comparators); - break; - case Call_kind: - VISIT(st, expr, e->v.Call.func); - VISIT_SEQ(st, expr, e->v.Call.args); - VISIT_SEQ(st, keyword, e->v.Call.keywords); - if (e->v.Call.starargs) - VISIT(st, expr, e->v.Call.starargs); - if (e->v.Call.kwargs) - VISIT(st, expr, e->v.Call.kwargs); - break; - case Repr_kind: - VISIT(st, expr, e->v.Repr.value); - break; - case Num_kind: - case Str_kind: - /* Nothing to do here. */ - break; - /* The following exprs can be assignment targets. */ - case Attribute_kind: - VISIT(st, expr, e->v.Attribute.value); - break; - case Subscript_kind: - VISIT(st, expr, e->v.Subscript.value); - VISIT(st, slice, e->v.Subscript.slice); - break; - case Name_kind: - if (!symtable_add_def(st, e->v.Name.id, - e->v.Name.ctx == Load ? USE : DEF_LOCAL)) - return 0; - break; - /* child nodes of List and Tuple will have expr_context set */ - case List_kind: - VISIT_SEQ(st, expr, e->v.List.elts); - break; - case Tuple_kind: - VISIT_SEQ(st, expr, e->v.Tuple.elts); - break; - } - return 1; -} - -static int -symtable_implicit_arg(struct symtable *st, int pos) -{ - PyObject *id = PyString_FromFormat(".%d", pos); - if (id == NULL) - return 0; - if (!symtable_add_def(st, id, DEF_PARAM)) { - Py_DECREF(id); - return 0; - } - Py_DECREF(id); - return 1; -} - -static int -symtable_visit_params(struct symtable *st, asdl_seq *args, int toplevel) -{ - int i; - - /* go through all the toplevel arguments first */ - for (i = 0; i < asdl_seq_LEN(args); i++) { - expr_ty arg = (expr_ty)asdl_seq_GET(args, i); - if (arg->kind == Name_kind) { - assert(arg->v.Name.ctx == Param || - (arg->v.Name.ctx == Store && !toplevel)); - if (!symtable_add_def(st, arg->v.Name.id, DEF_PARAM)) - return 0; - } - else if (arg->kind == Tuple_kind) { - assert(arg->v.Tuple.ctx == Store); - if (toplevel) { - if (!symtable_implicit_arg(st, i)) - return 0; - } - } - else { - PyErr_SetString(PyExc_SyntaxError, - "invalid expression in parameter list"); - PyErr_SyntaxLocation(st->st_filename, - st->st_cur->ste_lineno); - return 0; - } - } - - if (!toplevel) { - if (!symtable_visit_params_nested(st, args)) - return 0; - } - - return 1; -} - -static int -symtable_visit_params_nested(struct symtable *st, asdl_seq *args) -{ - int i; - for (i = 0; i < asdl_seq_LEN(args); i++) { - expr_ty arg = (expr_ty)asdl_seq_GET(args, i); - if (arg->kind == Tuple_kind && - !symtable_visit_params(st, arg->v.Tuple.elts, 0)) - return 0; - } - - return 1; -} - -static int -symtable_visit_arguments(struct symtable *st, arguments_ty a) -{ - /* skip default arguments inside function block - XXX should ast be different? - */ - if (a->args && !symtable_visit_params(st, a->args, 1)) - return 0; - if (a->vararg) { - if (!symtable_add_def(st, a->vararg, DEF_PARAM)) - return 0; - st->st_cur->ste_varargs = 1; - } - if (a->kwarg) { - if (!symtable_add_def(st, a->kwarg, DEF_PARAM)) - return 0; - st->st_cur->ste_varkeywords = 1; - } - if (a->args && !symtable_visit_params_nested(st, a->args)) - return 0; - return 1; -} - - -static int -symtable_visit_excepthandler(struct symtable *st, excepthandler_ty eh) -{ - if (eh->type) - VISIT(st, expr, eh->type); - if (eh->name) - VISIT(st, expr, eh->name); - VISIT_SEQ(st, stmt, eh->body); - return 1; -} - - -static int -symtable_visit_alias(struct symtable *st, alias_ty a) -{ - /* Compute store_name, the name actually bound by the import - operation. It is diferent than a->name when a->name is a - dotted package name (e.g. spam.eggs) - */ - PyObject *store_name; - PyObject *name = (a->asname == NULL) ? a->name : a->asname; - const char *base = PyString_AS_STRING(name); - char *dot = strchr(base, '.'); - if (dot) { - store_name = PyString_FromStringAndSize(base, dot - base); - if (!store_name) - return 0; - } - else { - store_name = name; - Py_INCREF(store_name); - } - if (strcmp(PyString_AS_STRING(name), "*")) { - int r = symtable_add_def(st, store_name, DEF_IMPORT); - Py_DECREF(store_name); - return r; - } - else { - if (st->st_cur->ste_type != ModuleBlock) { - int lineno = st->st_cur->ste_lineno; - if (!symtable_warn(st, IMPORT_STAR_WARNING, lineno)) { - Py_DECREF(store_name); - return 0; - } - } - st->st_cur->ste_unoptimized |= OPT_IMPORT_STAR; - Py_DECREF(store_name); - return 1; - } -} - - -static int -symtable_visit_comprehension(struct symtable *st, comprehension_ty lc) -{ - VISIT(st, expr, lc->target); - VISIT(st, expr, lc->iter); - VISIT_SEQ(st, expr, lc->ifs); - return 1; -} - - -static int -symtable_visit_keyword(struct symtable *st, keyword_ty k) -{ - VISIT(st, expr, k->value); - return 1; -} - - -static int -symtable_visit_slice(struct symtable *st, slice_ty s) -{ - switch (s->kind) { - case Slice_kind: - if (s->v.Slice.lower) - VISIT(st, expr, s->v.Slice.lower) - if (s->v.Slice.upper) - VISIT(st, expr, s->v.Slice.upper) - if (s->v.Slice.step) - VISIT(st, expr, s->v.Slice.step) - break; - case ExtSlice_kind: - VISIT_SEQ(st, slice, s->v.ExtSlice.dims) - break; - case Index_kind: - VISIT(st, expr, s->v.Index.value) - break; - case Ellipsis_kind: - break; - } - return 1; -} - -static int -symtable_visit_genexp(struct symtable *st, expr_ty e) -{ - comprehension_ty outermost = ((comprehension_ty) - (asdl_seq_GET(e->v.GeneratorExp.generators, 0))); - /* Outermost iterator is evaluated in current scope */ - VISIT(st, expr, outermost->iter); - /* Create generator scope for the rest */ - if (!symtable_enter_block(st, GET_IDENTIFIER(genexpr), - FunctionBlock, (void *)e, 0)) { - return 0; - } - st->st_cur->ste_generator = 1; - /* Outermost iter is received as an argument */ - if (!symtable_implicit_arg(st, 0)) { - symtable_exit_block(st, (void *)e); - return 0; - } - VISIT_IN_BLOCK(st, expr, outermost->target, (void*)e); - VISIT_SEQ_IN_BLOCK(st, expr, outermost->ifs, (void*)e); - VISIT_SEQ_TAIL_IN_BLOCK(st, comprehension, - e->v.GeneratorExp.generators, 1, (void*)e); - VISIT_IN_BLOCK(st, expr, e->v.GeneratorExp.elt, (void*)e); - if (!symtable_exit_block(st, (void *)e)) - return 0; - return 1; -} -- cgit v1.2.3