Mercurial > cpython-lru_cache-weakref
view Python/future.c @ 24155:9456a2ccda61 legacy-trunk
The Py_REF_DEBUG/COUNT_ALLOCS/Py_TRACE_REFS macro minefield: added
more trivial lexical helper macros so that uses of these guys expand
to nothing at all when they're not enabled. This should help sub-
standard compilers that can't do a good job of optimizing away the
previous "(void)0" expressions.
Py_DECREF: There's only one definition of this now. Yay! That
was that last one in the family defined multiple times in an #ifdef
maze.
Py_FatalError(): Changed the char* signature to const char*.
_Py_NegativeRefcount(): New helper function for the Py_REF_DEBUG
expansion of Py_DECREF. Calling an external function cuts down on
the volume of generated code. The previous inline expansion of abort()
didn't work as intended on Windows (the program often kept going, and
the error msg scrolled off the screen unseen). _Py_NegativeRefcount
calls Py_FatalError instead, which captures our best knowledge of
how to abort effectively across platforms.
| author | Tim Peters <tim.peters@gmail.com> |
|---|---|
| date | Tue, 09 Jul 2002 02:57:01 +0000 |
| parents | ba0236f84318 |
| children | cc05c2c8660e |
line wrap: on
line source
#include "Python.h" #include "node.h" #include "token.h" #include "graminit.h" #include "compile.h" #include "symtable.h" #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined" #define FUTURE_IMPORT_STAR "future statement does not support import *" /* FUTURE_POSSIBLE() is provided to accomodate doc strings, which is the only statement that can occur before a future statement. */ #define FUTURE_POSSIBLE(FF) ((FF)->ff_last_lineno == -1) static int future_check_features(PyFutureFeatures *ff, node *n, char *filename) { int i; char *feature; node *ch; REQ(n, import_stmt); /* must by from __future__ import ... */ for (i = 3; i < NCH(n); i += 2) { ch = CHILD(n, i); if (TYPE(ch) == STAR) { PyErr_SetString(PyExc_SyntaxError, FUTURE_IMPORT_STAR); PyErr_SyntaxLocation(filename, ch->n_lineno); return -1; } 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 void future_error(node *n, char *filename) { PyErr_SetString(PyExc_SyntaxError, "from __future__ imports must occur at the " "beginning of the file"); PyErr_SyntaxLocation(filename, n->n_lineno); } /* Relevant portions of the grammar: single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE file_input: (NEWLINE | stmt)* ENDMARKER stmt: simple_stmt | compound_stmt simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt 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] dotted_as_name: dotted_name [NAME NAME] dotted_name: NAME ('.' NAME)* */ /* future_parse() finds future statements at the beginnning of a module. The function calls itself recursively, rather than factoring out logic for different kinds of statements into different routines. Return values: -1 indicates an error occurred, e.g. unknown feature name 0 indicates no feature was found 1 indicates a feature was found */ static int future_parse(PyFutureFeatures *ff, node *n, char *filename) { int i, r; loop: switch (TYPE(n)) { case single_input: if (TYPE(CHILD(n, 0)) == simple_stmt) { n = CHILD(n, 0); goto loop; } return 0; case file_input: /* Check each statement in the file, starting with the first, and continuing until the first statement that isn't a future statement. */ for (i = 0; i < NCH(n); i++) { node *ch = CHILD(n, i); if (TYPE(ch) == stmt) { r = future_parse(ff, ch, filename); /* Need to check both conditions below to accomodate doc strings, which causes r < 0. */ if (r < 1 && !FUTURE_POSSIBLE(ff)) return r; } } return 0; case simple_stmt: if (NCH(n) == 2) { REQ(CHILD(n, 0), small_stmt); n = CHILD(n, 0); goto loop; } else { /* Deal with the special case of a series of small statements on a single line. If a future statement follows some other statement, the SyntaxError is raised here. In all other cases, the symtable pass raises the exception. */ int found = 0, end_of_future = 0; for (i = 0; i < NCH(n); i += 2) { if (TYPE(CHILD(n, i)) == small_stmt) { r = future_parse(ff, CHILD(n, i), filename); if (r < 1) end_of_future = 1; else { found = 1; if (end_of_future) { future_error(n, filename); return -1; } } } } /* If we found one and only one, then the current lineno is legal. */ if (found) ff->ff_last_lineno = n->n_lineno + 1; else ff->ff_last_lineno = n->n_lineno; if (end_of_future && found) return 1; else return 0; } case stmt: if (TYPE(CHILD(n, 0)) == simple_stmt) { n = CHILD(n, 0); goto loop; } else if (TYPE(CHILD(n, 0)) == expr_stmt) { n = CHILD(n, 0); goto loop; } else { REQ(CHILD(n, 0), compound_stmt); ff->ff_last_lineno = n->n_lineno; return 0; } case small_stmt: n = CHILD(n, 0); goto loop; case import_stmt: { node *name; if (STR(CHILD(n, 0))[0] != 'f') { /* from */ ff->ff_last_lineno = n->n_lineno; return 0; } name = CHILD(n, 1); if (strcmp(STR(CHILD(name, 0)), "__future__") != 0) return 0; if (future_check_features(ff, n, filename) < 0) return -1; ff->ff_last_lineno = n->n_lineno + 1; return 1; } /* The cases below -- all of them! -- are necessary to find and skip doc strings. */ case expr_stmt: case testlist: 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 loop; } break; case atom: if (TYPE(CHILD(n, 0)) == STRING && ff->ff_found_docstring == 0) { ff->ff_found_docstring = 1; return 0; } ff->ff_last_lineno = n->n_lineno; return 0; default: ff->ff_last_lineno = n->n_lineno; return 0; } return 0; } PyFutureFeatures * PyNode_Future(node *n, char *filename) { PyFutureFeatures *ff; ff = (PyFutureFeatures *)PyMem_Malloc(sizeof(PyFutureFeatures)); if (ff == NULL) return NULL; ff->ff_found_docstring = 0; ff->ff_last_lineno = -1; ff->ff_features = 0; if (future_parse(ff, n, filename) < 0) { PyMem_Free((void *)ff); return NULL; } return ff; }
