cinap_lenrekadd hg and python4bb9e2215 years agoHistory
3279 lines · 93.5 KB · C
RawDownload
  /*  PyObject* parser_expr(PyObject* self, PyObject* args) *  PyObject* parser_suite(PyObject* self, PyObject* args) * *  External interfaces to the parser itself.  Which is called determines if *  the parser attempts to recognize an expression ('eval' form) or statement *  suite ('exec' form).  The real work is done by parser_do_parse() above. * */static PyObject*parser_expr(PyST_Object *self, PyObject *args, PyObject *kw){    NOTE(ARGUNUSED(self))    return (parser_do_parse(args, kw, "s:expr", PyST_EXPR));}  static PyObject*parser_suite(PyST_Object *self, PyObject *args, PyObject *kw){    NOTE(ARGUNUSED(self))    return (parser_do_parse(args, kw, "s:suite", PyST_SUITE));}   /*  This is the messy part of the code.  Conversion from a tuple to an ST *  object requires that the input tuple be valid without having to rely on *  catching an exception from the compiler.  This is done to allow the *  compiler itself to remain fast, since most of its input will come from *  the parser directly, and therefore be known to be syntactically correct. *  This validation is done to ensure that we don't core dump the compile *  phase, returning an exception instead. * *  Two aspects can be broken out in this code:  creating a node tree from *  the tuple passed in, and verifying that it is indeed valid.  It may be *  advantageous to expand the number of ST types to include funcdefs and *  lambdadefs to take advantage of the optimizer, recognizing those STs *  here.  They are not necessary, and not quite as useful in a raw form. *  For now, let's get expressions and suites working reliably. */  static node* build_node_tree(PyObject *tuple);static int   validate_expr_tree(node *tree);static int   validate_file_input(node *tree);static int   validate_encoding_decl(node *tree); /*  PyObject* parser_tuple2st(PyObject* self, PyObject* args) * *  This is the public function, called from the Python code.  It receives a *  single tuple object from the caller, and creates an ST object if the *  tuple can be validated.  It does this by checking the first code of the *  tuple, and, if acceptable, builds the internal representation.  If this *  step succeeds, the internal representation is validated as fully as *  possible with the various validate_*() routines defined below. * *  This function must be changed if support is to be added for PyST_FRAGMENT *  ST objects. * */static PyObject*parser_tuple2st(PyST_Object *self, PyObject *args, PyObject *kw){    NOTE(ARGUNUSED(self))    PyObject *st = 0;    PyObject *tuple;    node *tree;     static char *keywords[] = {"sequence", NULL};     if (!PyArg_ParseTupleAndKeywords(args, kw, "O:sequence2st", keywords,                                     &tuple))        return (0);    if (!PySequence_Check(tuple)) {        PyErr_SetString(PyExc_ValueError,                        "sequence2st() requires a single sequence argument");        return (0);    }    /*     *  Convert the tree to the internal form before checking it.     */    tree = build_node_tree(tuple);    if (tree != 0) {        int start_sym = TYPE(tree);        if (start_sym == eval_input) {            /*  Might be an eval form.  */            if (validate_expr_tree(tree))                st = parser_newstobject(tree, PyST_EXPR);            else                PyNode_Free(tree);        }        else if (start_sym == file_input) {            /*  This looks like an exec form so far.  */            if (validate_file_input(tree))                st = parser_newstobject(tree, PyST_SUITE);            else                PyNode_Free(tree);        }        else if (start_sym == encoding_decl) {            /* This looks like an encoding_decl so far. */            if (validate_encoding_decl(tree))                st = parser_newstobject(tree, PyST_SUITE);            else                PyNode_Free(tree);        }        else {            /*  This is a fragment, at best. */            PyNode_Free(tree);            err_string("parse tree does not use a valid start symbol");        }    }    /*  Make sure we throw an exception on all errors.  We should never     *  get this, but we'd do well to be sure something is done.     */    if (st == NULL && !PyErr_Occurred())        err_string("unspecified ST error occurred");     return st;}  /*  node* build_node_children() * *  Iterate across the children of the current non-terminal node and build *  their structures.  If successful, return the root of this portion of *  the tree, otherwise, 0.  Any required exception will be specified already, *  and no memory will have been deallocated. * */static node*build_node_children(PyObject *tuple, node *root, int *line_num){    Py_ssize_t len = PyObject_Size(tuple);    Py_ssize_t i;    int  err;     for (i = 1; i < len; ++i) {        /* elem must always be a sequence, however simple */        PyObject* elem = PySequence_GetItem(tuple, i);        int ok = elem != NULL;        long  type = 0;        char *strn = 0;         if (ok)            ok = PySequence_Check(elem);        if (ok) {            PyObject *temp = PySequence_GetItem(elem, 0);            if (temp == NULL)                ok = 0;            else {                ok = PyInt_Check(temp);                if (ok)                    type = PyInt_AS_LONG(temp);                Py_DECREF(temp);            }        }        if (!ok) {            PyObject *err = Py_BuildValue("os", elem,                                          "Illegal node construct.");            PyErr_SetObject(parser_error, err);            Py_XDECREF(err);            Py_XDECREF(elem);            return (0);        }        if (ISTERMINAL(type)) {            Py_ssize_t len = PyObject_Size(elem);            PyObject *temp;             if ((len != 2) && (len != 3)) {                err_string("terminal nodes must have 2 or 3 entries");                return 0;            }            temp = PySequence_GetItem(elem, 1);            if (temp == NULL)                return 0;            if (!PyString_Check(temp)) {                PyErr_Format(parser_error,                             "second item in terminal node must be a string,"                             " found %s",                             temp->ob_type->tp_name);                Py_DECREF(temp);                return 0;            }            if (len == 3) {                PyObject *o = PySequence_GetItem(elem, 2);                if (o != NULL) {                    if (PyInt_Check(o))                        *line_num = PyInt_AS_LONG(o);                    else {                        PyErr_Format(parser_error,                                     "third item in terminal node must be an"                                     " integer, found %s",				     temp->ob_type->tp_name);                        Py_DECREF(o);                        Py_DECREF(temp);                        return 0;                    }                    Py_DECREF(o);                }            }            len = PyString_GET_SIZE(temp) + 1;            strn = (char *)PyObject_MALLOC(len);            if (strn != NULL)                (void) memcpy(strn, PyString_AS_STRING(temp), len);            Py_DECREF(temp);        }        else if (!ISNONTERMINAL(type)) {            /*             *  It has to be one or the other; this is an error.             *  Throw an exception.             */            PyObject *err = Py_BuildValue("os", elem, "unknown node type.");            PyErr_SetObject(parser_error, err);            Py_XDECREF(err);            Py_XDECREF(elem);            return (0);        }        err = PyNode_AddChild(root, type, strn, *line_num, 0);        if (err == E_NOMEM) {            PyObject_FREE(strn);            return (node *) PyErr_NoMemory();        }        if (err == E_OVERFLOW) {            PyObject_FREE(strn);            PyErr_SetString(PyExc_ValueError,                            "unsupported number of child nodes");            return NULL;        }         if (ISNONTERMINAL(type)) {            node* new_child = CHILD(root, i - 1);             if (new_child != build_node_children(elem, new_child, line_num)) {                Py_XDECREF(elem);                return (0);            }        }        else if (type == NEWLINE) {     /* It's true:  we increment the     */            ++(*line_num);              /* line number *after* the newline! */        }        Py_XDECREF(elem);    }    return root;}  static node*build_node_tree(PyObject *tuple){    node* res = 0;    PyObject *temp = PySequence_GetItem(tuple, 0);    long num = -1;     if (temp != NULL)        num = PyInt_AsLong(temp);    Py_XDECREF(temp);    if (ISTERMINAL(num)) {        /*         *  The tuple is simple, but it doesn't start with a start symbol.         *  Throw an exception now and be done with it.         */        tuple = Py_BuildValue("os", tuple,                    "Illegal syntax-tree; cannot start with terminal symbol.");        PyErr_SetObject(parser_error, tuple);        Py_XDECREF(tuple);    }    else if (ISNONTERMINAL(num)) {        /*         *  Not efficient, but that can be handled later.         */        int line_num = 0;        PyObject *encoding = NULL;         if (num == encoding_decl) {            encoding = PySequence_GetItem(tuple, 2);            /* tuple isn't borrowed anymore here, need to DECREF */            tuple = PySequence_GetSlice(tuple, 0, 2);        }        res = PyNode_New(num);        if (res != NULL) {            if (res != build_node_children(tuple, res, &line_num)) {                PyNode_Free(res);                res = NULL;            }            if (res && encoding) {                Py_ssize_t len;                len = PyString_GET_SIZE(encoding) + 1;                res->n_str = (char *)PyObject_MALLOC(len);                if (res->n_str != NULL)                    (void) memcpy(res->n_str, PyString_AS_STRING(encoding), len);                Py_DECREF(encoding);                Py_DECREF(tuple);            }        }    }    else {        /*  The tuple is illegal -- if the number is neither TERMINAL nor         *  NONTERMINAL, we can't use it.  Not sure the implementation         *  allows this condition, but the API doesn't preclude it.         */        PyObject *err = Py_BuildValue("os", tuple,                                      "Illegal component tuple.");        PyErr_SetObject(parser_error, err);        Py_XDECREF(err);    }     return (res);}  /* *  Validation routines used within the validation section: */static int validate_terminal(node *terminal, int type, char *string); #define validate_ampersand(ch)  validate_terminal(ch,      AMPER, "&")#define validate_circumflex(ch) validate_terminal(ch, CIRCUMFLEX, "^")#define validate_colon(ch)      validate_terminal(ch,      COLON, ":")#define validate_comma(ch)      validate_terminal(ch,      COMMA, ",")#define validate_dedent(ch)     validate_terminal(ch,     DEDENT, "")#define validate_equal(ch)      validate_terminal(ch,      EQUAL, "=")#define validate_indent(ch)     validate_terminal(ch,     INDENT, (char*)NULL)#define validate_lparen(ch)     validate_terminal(ch,       LPAR, "(")#define validate_newline(ch)    validate_terminal(ch,    NEWLINE, (char*)NULL)#define validate_rparen(ch)     validate_terminal(ch,       RPAR, ")")#define validate_semi(ch)       validate_terminal(ch,       SEMI, ";")#define validate_star(ch)       validate_terminal(ch,       STAR, "*")#define validate_vbar(ch)       validate_terminal(ch,       VBAR, "|")#define validate_doublestar(ch) validate_terminal(ch, DOUBLESTAR, "**")#define validate_dot(ch)        validate_terminal(ch,        DOT, ".")#define validate_at(ch)         validate_terminal(ch,         AT, "@")#define validate_name(ch, str)  validate_terminal(ch,       NAME, str) #define VALIDATER(n)    static int validate_##n(node *tree) VALIDATER(node);                VALIDATER(small_stmt);VALIDATER(class);               VALIDATER(node);VALIDATER(parameters);          VALIDATER(suite);VALIDATER(testlist);            VALIDATER(varargslist);VALIDATER(fpdef);               VALIDATER(fplist);VALIDATER(stmt);                VALIDATER(simple_stmt);VALIDATER(expr_stmt);           VALIDATER(power);VALIDATER(print_stmt);          VALIDATER(del_stmt);VALIDATER(return_stmt);         VALIDATER(list_iter);VALIDATER(raise_stmt);          VALIDATER(import_stmt);VALIDATER(import_name);         VALIDATER(import_from);VALIDATER(global_stmt);         VALIDATER(list_if);VALIDATER(assert_stmt);         VALIDATER(list_for);VALIDATER(exec_stmt);           VALIDATER(compound_stmt);VALIDATER(while);               VALIDATER(for);VALIDATER(try);                 VALIDATER(except_clause);VALIDATER(test);                VALIDATER(and_test);VALIDATER(not_test);            VALIDATER(comparison);VALIDATER(comp_op);             VALIDATER(expr);VALIDATER(xor_expr);            VALIDATER(and_expr);VALIDATER(shift_expr);          VALIDATER(arith_expr);VALIDATER(term);                VALIDATER(factor);VALIDATER(atom);                VALIDATER(lambdef);VALIDATER(trailer);             VALIDATER(subscript);VALIDATER(subscriptlist);       VALIDATER(sliceop);VALIDATER(exprlist);            VALIDATER(dictmaker);VALIDATER(arglist);             VALIDATER(argument);VALIDATER(listmaker);           VALIDATER(yield_stmt);VALIDATER(testlist1);           VALIDATER(gen_for);VALIDATER(gen_iter);            VALIDATER(gen_if);VALIDATER(testlist_gexp);	VALIDATER(yield_expr);VALIDATER(yield_or_testlist);	VALIDATER(or_test);VALIDATER(old_test); 		VALIDATER(old_lambdef); #undef VALIDATER #define is_even(n)      (((n) & 1) == 0)#define is_odd(n)       (((n) & 1) == 1)  static intvalidate_ntype(node *n, int t){    if (TYPE(n) != t) {        PyErr_Format(parser_error, "Expected node type %d, got %d.",                     t, TYPE(n));        return 0;    }    return 1;}  /*  Verifies that the number of child nodes is exactly 'num', raising *  an exception if it isn't.  The exception message does not indicate *  the exact number of nodes, allowing this to be used to raise the *  "right" exception when the wrong number of nodes is present in a *  specific variant of a statement's syntax.  This is commonly used *  in that fashion. */static intvalidate_numnodes(node *n, int num, const char *const name){    if (NCH(n) != num) {        PyErr_Format(parser_error,                     "Illegal number of children for %s node.", name);        return 0;    }    return 1;}  static intvalidate_terminal(node *terminal, int type, char *string){    int res = (validate_ntype(terminal, type)               && ((string == 0) || (strcmp(string, STR(terminal)) == 0)));     if (!res && !PyErr_Occurred()) {        PyErr_Format(parser_error,                     "Illegal terminal: expected \"%s\"", string);    }    return (res);}  /*  X (',' X) [','] */static intvalidate_repeating_list(node *tree, int ntype, int (*vfunc)(node *),                        const char *const name){    int nch = NCH(tree);    int res = (nch && validate_ntype(tree, ntype)               && vfunc(CHILD(tree, 0)));     if (!res && !PyErr_Occurred())        (void) validate_numnodes(tree, 1, name);    else {        if (is_even(nch))            res = validate_comma(CHILD(tree, --nch));        if (res && nch > 1) {            int pos = 1;            for ( ; res && pos < nch; pos += 2)                res = (validate_comma(CHILD(tree, pos))                       && vfunc(CHILD(tree, pos + 1)));        }    }    return (res);}  /*  validate_class() * *  classdef: *      'class' NAME ['(' testlist ')'] ':' suite */static intvalidate_class(node *tree){    int nch = NCH(tree);    int res = (validate_ntype(tree, classdef) &&	       	((nch == 4) || (nch == 6) || (nch == 7)));     if (res) {        res = (validate_name(CHILD(tree, 0), "class")               && validate_ntype(CHILD(tree, 1), NAME)               && validate_colon(CHILD(tree, nch - 2))               && validate_suite(CHILD(tree, nch - 1)));    }    else {        (void) validate_numnodes(tree, 4, "class");    }	    if (res) {	if (nch == 7) {		res = ((validate_lparen(CHILD(tree, 2)) &&			validate_testlist(CHILD(tree, 3)) &&			validate_rparen(CHILD(tree, 4))));	}	else if (nch == 6) {		res = (validate_lparen(CHILD(tree,2)) &&			validate_rparen(CHILD(tree,3)));	}    }    return (res);}  /*  if_stmt: *      'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] */static intvalidate_if(node *tree){    int nch = NCH(tree);    int res = (validate_ntype(tree, if_stmt)               && (nch >= 4)               && validate_name(CHILD(tree, 0), "if")               && validate_test(CHILD(tree, 1))               && validate_colon(CHILD(tree, 2))               && validate_suite(CHILD(tree, 3)));     if (res && ((nch % 4) == 3)) {

Lines 501–1000 of 3279. Previous lines