static int future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename) { int i, found_docstring = 0, done = 0, prev_line = 0; if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) return 1; /* A subsequent pass will detect future imports that don't appear at the beginning of the file. There's one case, however, that is easier to handle here: A series of imports joined by semi-colons, where the first import is a future statement but some subsequent import has the future form but is preceded by a regular import. */ for (i = 0; i < asdl_seq_LEN(mod->v.Module.body); i++) { stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i); if (done && s->lineno > prev_line) return 1; prev_line = s->lineno; /* The tests below will return from this function unless it is still possible to find a future statement. The only things that can precede a future statement are another future statement and a doc string. */ if (s->kind == ImportFrom_kind) { identifier modname = s->v.ImportFrom.module; if (modname && PyString_GET_SIZE(modname) == 10 && !strcmp(PyString_AS_STRING(modname), "__future__")) { if (done) { PyErr_SetString(PyExc_SyntaxError, ERR_LATE_FUTURE); PyErr_SyntaxLocation(filename, s->lineno); return 0; } if (!future_check_features(ff, s, filename)) return 0; ff->ff_lineno = s->lineno; } else done = 1; } else if (s->kind == Expr_kind && !found_docstring) { expr_ty e = s->v.Expr.value; if (e->kind != Str_kind) done = 1; else found_docstring = 1; } else done = 1; } return 1; }
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; }
static void future_error(node *n, const char *filename) { PyErr_SetString(PyExc_SyntaxError, "from __future__ imports must occur at the " "beginning of the file"); PyErr_SyntaxLocation(filename, n->n_lineno); }
static int future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename) { int i; asdl_seq *names; assert(s->kind == ImportFrom_kind); names = s->v.ImportFrom.names; for (i = 0; i < asdl_seq_LEN(names); i++) { alias_ty name = (alias_ty)asdl_seq_GET(names, i); const char *feature = PyString_AsString(name->name); if (!feature) return 0; if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { continue; } else if (strcmp(feature, FUTURE_GENERATORS) == 0) { continue; } else if (strcmp(feature, FUTURE_DIVISION) == 0) { ff->ff_features |= CO_FUTURE_DIVISION; } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) { ff->ff_features |= CO_FUTURE_ABSOLUTE_IMPORT; } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) { ff->ff_features |= CO_FUTURE_WITH_STATEMENT; } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) { ff->ff_features |= CO_FUTURE_PRINT_FUNCTION; } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) { ff->ff_features |= CO_FUTURE_UNICODE_LITERALS; } else if (strcmp(feature, "braces") == 0) { PyErr_SetString(PyExc_SyntaxError, "not a chance"); PyErr_SyntaxLocation(filename, s->lineno); return 0; } else { PyErr_Format(PyExc_SyntaxError, UNDEFINED_FUTURE_FEATURE, feature); PyErr_SyntaxLocation(filename, s->lineno); return 0; } } return 1; }
static int future_check_features(PyFutureFeatures *ff, node *n, const char *filename) { int i; char *feature; node *ch, *nn; REQ(n, import_from); nn = CHILD(n, 3 + (TYPE(CHILD(n, 3)) == LPAR)); if (TYPE(nn) == STAR) { PyErr_SetString(PyExc_SyntaxError, FUTURE_IMPORT_STAR); PyErr_SyntaxLocation(filename, nn->n_lineno); return -1; } REQ(nn, import_as_names); for (i = 0; i < NCH(nn); i += 2) { ch = CHILD(nn, i); REQ(ch, import_as_name); feature = STR(CHILD(ch, 0)); if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { continue; } else if (strcmp(feature, FUTURE_GENERATORS) == 0) { continue; } else if (strcmp(feature, FUTURE_DIVISION) == 0) { ff->ff_features |= CO_FUTURE_DIVISION; } else if (strcmp(feature, "braces") == 0) { PyErr_SetString(PyExc_SyntaxError, "not a chance"); PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno); return -1; } else { PyErr_Format(PyExc_SyntaxError, UNDEFINED_FUTURE_FEATURE, feature); PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno); return -1; } } return 0; }
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; }
/* 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 %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' because 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; }
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_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.decorator_list) VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list); 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 (s->v.ClassDef.decorator_list) VISIT_SEQ(st, expr, s->v.ClassDef.decorator_list); 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: VISIT(st, expr, s->v.With.context_expr); if (s->v.With.optional_vars) { VISIT(st, expr, s->v.With.optional_vars); } VISIT_SEQ(st, stmt, s->v.With.body); break; } return 1; }
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)); PyErr_SyntaxLocation(ste->ste_table->st_filename, ste->ste_lineno); 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_IMPLICIT); return 1; } else { if (ste->ste_nested) ste->ste_free = 1; SET_SCOPE(dict, name, GLOBAL_IMPLICIT); return 1; } /* Should never get here. */ PyErr_Format(PyExc_SystemError, "failed to set scope for %s", PyString_AS_STRING(name)); return 0; }
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 (!GET_IDENTIFIER(lambda)) return 0; if (e->v.Lambda.args->defaults) VISIT_SEQ(st, expr, e->v.Lambda.args->defaults); if (!symtable_enter_block(st, lambda, FunctionBlock, (void *)e, e->lineno)) 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 Set_kind: VISIT_SEQ(st, expr, e->v.Set.elts); break; case ListComp_kind: 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 SetComp_kind: if (!symtable_visit_setcomp(st, e)) return 0; break; case DictComp_kind: if (!symtable_visit_dictcomp(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; }