summaryrefslogtreecommitdiffstats
path: root/Python/future.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/future.c')
-rw-r--r--Python/future.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/Python/future.c b/Python/future.c
new file mode 100644
index 0000000..f67abc9
--- /dev/null
+++ b/Python/future.c
@@ -0,0 +1,146 @@
+#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"
+
+static int
+future_check_features(PyFutureFeatures *ff, node *n)
+{
+ int i;
+ char *feature;
+
+ REQ(n, import_stmt); /* must by from __future__ import ... */
+
+ for (i = 3; i < NCH(n); ++i) {
+ feature = STR(CHILD(CHILD(n, i), 0));
+ if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
+ ff->ff_nested_scopes = 1;
+ } else {
+ PyErr_Format(PyExc_SyntaxError,
+ UNDEFINED_FUTURE_FEATURE, feature);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* 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() 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)
+{
+ int i, r, found;
+ loop:
+
+/* fprintf(stderr, "future_parse(%d, %d, %s)\n",
+ TYPE(n), NCH(n), (n == NULL) ? "NULL" : STR(n));
+*/
+ switch (TYPE(n)) {
+
+ case file_input:
+ for (i = 0; i < NCH(n); i++) {
+ node *ch = CHILD(n, i);
+ if (TYPE(ch) == stmt) {
+ n = ch;
+ goto loop;
+ }
+ }
+ return 0;
+
+ case simple_stmt:
+ if (NCH(n) == 1) {
+ REQ(CHILD(n, 0), small_stmt);
+ n = CHILD(n, 0);
+ goto loop;
+ }
+ found = 0;
+ for (i = 0; i < NCH(n); ++i)
+ if (TYPE(CHILD(n, i)) == small_stmt) {
+ r = future_parse(ff, CHILD(n, i));
+ if (r < 1) {
+ ff->ff_last_lineno = n->n_lineno;
+ ff->ff_n_simple_stmt = i;
+ return r;
+ } else
+ found++;
+ }
+ if (found)
+ return 1;
+ else
+ return 0;
+
+ case stmt:
+ if (TYPE(CHILD(n, 0)) == simple_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) < 0)
+ return -1;
+ return 1;
+ }
+
+ default:
+ ff->ff_last_lineno = n->n_lineno;
+ return 0;
+ }
+}
+
+PyFutureFeatures *
+PyNode_Future(node *n, char *filename)
+{
+ PyFutureFeatures *ff;
+
+ ff = (PyFutureFeatures *)PyMem_Malloc(sizeof(PyFutureFeatures));
+ if (ff == NULL)
+ return NULL;
+ ff->ff_last_lineno = 0;
+ ff->ff_n_simple_stmt = -1;
+ ff->ff_nested_scopes = 0;
+
+ if (future_parse(ff, n) < 0) {
+ PyMem_Free((void *)ff);
+ return NULL;
+ }
+ return ff;
+}
+