Kaydet (Commit) 0ac9b079 authored tarafından Fred Drake's avatar Fred Drake

Simplify some of the code. Use PyErr_Format() instead of sprintf(), etc.

Reduces lines of code and compiled object size.
üst e92cdba1
...@@ -579,83 +579,41 @@ parser_tuple2ast(PyAST_Object *self, PyObject *args, PyObject *kw) ...@@ -579,83 +579,41 @@ parser_tuple2ast(PyAST_Object *self, PyObject *args, PyObject *kw)
{ {
NOTE(ARGUNUSED(self)) NOTE(ARGUNUSED(self))
PyObject *ast = 0; PyObject *ast = 0;
PyObject *tuple = 0; PyObject *tuple;
PyObject *temp = 0; node *tree;
int ok;
int start_sym = 0;
static char *keywords[] = {"sequence", NULL}; static char *keywords[] = {"sequence", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kw, "O:tuple2ast", keywords, if (!PyArg_ParseTupleAndKeywords(args, kw, "O:sequence2ast", keywords,
&tuple)) &tuple))
return (0); return (0);
if (!PySequence_Check(tuple)) { if (!PySequence_Check(tuple)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"tuple2ast() requires a single sequence argument"); "sequence2ast() requires a single sequence argument");
return (0); return (0);
} }
/* /*
* This mess of tests is written this way so we can use the abstract * Convert the tree to the internal form before checking it.
* object interface (AOI). Unfortunately, the AOI increments reference
* counts, which requires that we store a pointer to retrieved object
* so we can DECREF it after the check. But we really should accept
* lists as well as tuples at the very least.
*/
ok = PyObject_Size(tuple) >= 2;
if (ok) {
temp = PySequence_GetItem(tuple, 0);
ok = (temp != NULL) && PyInt_Check(temp);
if (ok)
/* this is used after the initial checks: */
start_sym = PyInt_AS_LONG(temp);
Py_XDECREF(temp);
}
if (ok) {
temp = PySequence_GetItem(tuple, 1);
ok = (temp != NULL) && PySequence_Check(temp);
Py_XDECREF(temp);
}
if (ok) {
temp = PySequence_GetItem(tuple, 1);
ok = (temp != NULL) && PyObject_Size(temp) >= 2;
if (ok) {
PyObject *temp2 = PySequence_GetItem(temp, 0);
if (temp2 != NULL) {
ok = PyInt_Check(temp2);
Py_DECREF(temp2);
}
}
Py_XDECREF(temp);
}
/* If we've failed at some point, get out of here. */
if (!ok) {
err_string("malformed sequence for tuple2ast()");
return (0);
}
/*
* This might be a valid parse tree, but let's do a quick check
* before we jump the gun.
*/ */
tree = build_node_tree(tuple);
if (tree != 0) {
int start_sym = TYPE(tree);
if (start_sym == eval_input) { if (start_sym == eval_input) {
/* Might be an eval form. */ /* Might be an eval form. */
node* expression = build_node_tree(tuple); if (validate_expr_tree(tree))
ast = parser_newastobject(tree, PyAST_EXPR);
if ((expression != 0) && validate_expr_tree(expression))
ast = parser_newastobject(expression, PyAST_EXPR);
} }
else if (start_sym == file_input) { else if (start_sym == file_input) {
/* This looks like an exec form so far. */ /* This looks like an exec form so far. */
node* suite_tree = build_node_tree(tuple); if (validate_file_input(tree))
ast = parser_newastobject(tree, PyAST_SUITE);
if ((suite_tree != 0) && validate_file_input(suite_tree)) }
ast = parser_newastobject(suite_tree, PyAST_SUITE); else {
/* This is a fragment, at best. */
PyNode_Free(tree);
err_string("Parse tree does not use a valid start symbol.");
}
} }
else
/* This is a fragment, and is not yet supported. Maybe they
* will be if I find a use for them.
*/
err_string("Fragmentary parse trees not supported.");
/* Make sure we throw an exception on all errors. We should never /* 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. * get this, but we'd do well to be sure something is done.
*/ */
...@@ -666,51 +624,6 @@ parser_tuple2ast(PyAST_Object *self, PyObject *args, PyObject *kw) ...@@ -666,51 +624,6 @@ parser_tuple2ast(PyAST_Object *self, PyObject *args, PyObject *kw)
} }
/* int check_terminal_tuple()
*
* Check a tuple to determine that it is indeed a valid terminal
* node. The node is known to be required as a terminal, so we throw
* an exception if there is a failure.
*
* The format of an acceptable terminal tuple is "(is[i])": the fact
* that elem is a tuple and the integer is a valid terminal symbol
* has been established before this function is called. We must
* check the length of the tuple and the type of the second element
* and optional third element. We do *NOT* check the actual text of
* the string element, which we could do in many cases. This is done
* by the validate_*() functions which operate on the internal
* representation.
*/
static int
check_terminal_tuple(PyObject *elem)
{
int len = PyObject_Size(elem);
int res = 1;
char* str = "Illegal terminal symbol; bad node length.";
if ((len == 2) || (len == 3)) {
PyObject *temp = PySequence_GetItem(elem, 1);
res = PyString_Check(temp);
str = "Illegal terminal symbol; expected a string.";
if (res && (len == 3)) {
PyObject* third = PySequence_GetItem(elem, 2);
res = PyInt_Check(third);
str = "Invalid third element of terminal node.";
Py_XDECREF(third);
}
Py_XDECREF(temp);
}
else {
res = 0;
}
if (!res) {
elem = Py_BuildValue("(os)", elem, str);
PyErr_SetObject(parser_error, elem);
}
return (res);
}
/* node* build_node_children() /* node* build_node_children()
* *
* Iterate across the children of the current non-terminal node and build * Iterate across the children of the current non-terminal node and build
...@@ -726,7 +639,7 @@ build_node_children(PyObject *tuple, node *root, int *line_num) ...@@ -726,7 +639,7 @@ build_node_children(PyObject *tuple, node *root, int *line_num)
int i; int i;
for (i = 1; i < len; ++i) { for (i = 1; i < len; ++i) {
/* elem must always be a tuple, however simple */ /* elem must always be a sequence, however simple */
PyObject* elem = PySequence_GetItem(tuple, i); PyObject* elem = PySequence_GetItem(tuple, i);
int ok = elem != NULL; int ok = elem != NULL;
long type = 0; long type = 0;
...@@ -747,31 +660,52 @@ build_node_children(PyObject *tuple, node *root, int *line_num) ...@@ -747,31 +660,52 @@ build_node_children(PyObject *tuple, node *root, int *line_num)
} }
if (!ok) { if (!ok) {
PyErr_SetObject(parser_error, PyErr_SetObject(parser_error,
Py_BuildValue("(os)", elem, Py_BuildValue("os", elem,
"Illegal node construct.")); "Illegal node construct."));
Py_XDECREF(elem); Py_XDECREF(elem);
return (0); return (0);
} }
if (ISTERMINAL(type)) { if (ISTERMINAL(type)) {
if (check_terminal_tuple(elem)) { int len = PyObject_Size(elem);
PyObject *temp = PySequence_GetItem(elem, 1); PyObject *temp;
/* check_terminal_tuple() already verified it's a string */ if ((len != 2) && (len != 3)) {
strn = (char *)PyMem_MALLOC(PyString_GET_SIZE(temp) + 1); err_string("Terminal nodes must have 2 or 3 entries.");
if (strn != NULL) return 0;
(void) strcpy(strn, PyString_AS_STRING(temp)); }
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.",
((PyTypeObject*)PyObject_Type(temp))->tp_name);
Py_DECREF(temp); Py_DECREF(temp);
return 0;
if (PyObject_Size(elem) == 3) { }
PyObject* temp = PySequence_GetItem(elem, 2); if (len == 3) {
*line_num = PyInt_AsLong(temp); 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.",
((PyTypeObject*)PyObject_Type(temp))->tp_name);
Py_DECREF(o);
Py_DECREF(temp); Py_DECREF(temp);
return 0;
} }
Py_DECREF(o);
} }
else {
Py_XDECREF(elem);
return (0);
} }
len = PyString_GET_SIZE(temp) + 1;
strn = (char *)PyMem_MALLOC(len);
if (strn != NULL)
(void) memcpy(strn, PyString_AS_STRING(temp), len);
Py_DECREF(temp);
} }
else if (!ISNONTERMINAL(type)) { else if (!ISNONTERMINAL(type)) {
/* /*
...@@ -779,8 +713,7 @@ build_node_children(PyObject *tuple, node *root, int *line_num) ...@@ -779,8 +713,7 @@ build_node_children(PyObject *tuple, node *root, int *line_num)
* Throw an exception. * Throw an exception.
*/ */
PyErr_SetObject(parser_error, PyErr_SetObject(parser_error,
Py_BuildValue("(os)", elem, Py_BuildValue("os", elem, "Unknown node type."));
"Unknown node type."));
Py_XDECREF(elem); Py_XDECREF(elem);
return (0); return (0);
} }
...@@ -818,7 +751,7 @@ build_node_tree(PyObject *tuple) ...@@ -818,7 +751,7 @@ build_node_tree(PyObject *tuple)
* The tuple is simple, but it doesn't start with a start symbol. * The tuple is simple, but it doesn't start with a start symbol.
* Throw an exception now and be done with it. * Throw an exception now and be done with it.
*/ */
tuple = Py_BuildValue("(os)", tuple, tuple = Py_BuildValue("os", tuple,
"Illegal ast tuple; cannot start with terminal symbol."); "Illegal ast tuple; cannot start with terminal symbol.");
PyErr_SetObject(parser_error, tuple); PyErr_SetObject(parser_error, tuple);
} }
...@@ -836,19 +769,17 @@ build_node_tree(PyObject *tuple) ...@@ -836,19 +769,17 @@ build_node_tree(PyObject *tuple)
} }
else else
/* The tuple is illegal -- if the number is neither TERMINAL nor /* The tuple is illegal -- if the number is neither TERMINAL nor
* NONTERMINAL, we can't use it. * NONTERMINAL, we can't use it. Not sure the implementation
* allows this condition, but the API doesn't preclude it.
*/ */
PyErr_SetObject(parser_error, PyErr_SetObject(parser_error,
Py_BuildValue("(os)", tuple, Py_BuildValue("os", tuple,
"Illegal component tuple.")); "Illegal component tuple."));
return (res); return (res);
} }
#define VALIDATER(n) static int validate_##n(node *tree)
/* /*
* Validation routines used within the validation section: * Validation routines used within the validation section:
*/ */
...@@ -871,6 +802,8 @@ staticforward int validate_terminal(node *terminal, int type, char *string); ...@@ -871,6 +802,8 @@ staticforward int validate_terminal(node *terminal, int type, char *string);
#define validate_dot(ch) validate_terminal(ch, DOT, ".") #define validate_dot(ch) validate_terminal(ch, DOT, ".")
#define validate_name(ch, str) validate_terminal(ch, NAME, str) #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(node); VALIDATER(small_stmt);
VALIDATER(class); VALIDATER(node); VALIDATER(class); VALIDATER(node);
VALIDATER(parameters); VALIDATER(suite); VALIDATER(parameters); VALIDATER(suite);
...@@ -899,6 +832,7 @@ VALIDATER(exprlist); VALIDATER(dictmaker); ...@@ -899,6 +832,7 @@ VALIDATER(exprlist); VALIDATER(dictmaker);
VALIDATER(arglist); VALIDATER(argument); VALIDATER(arglist); VALIDATER(argument);
VALIDATER(listmaker); VALIDATER(listmaker);
#undef VALIDATER
#define is_even(n) (((n) & 1) == 0) #define is_even(n) (((n) & 1) == 0)
#define is_odd(n) (((n) & 1) == 1) #define is_odd(n) (((n) & 1) == 1)
...@@ -907,14 +841,12 @@ VALIDATER(listmaker); ...@@ -907,14 +841,12 @@ VALIDATER(listmaker);
static int static int
validate_ntype(node *n, int t) validate_ntype(node *n, int t)
{ {
int res = (TYPE(n) == t); if (TYPE(n) != t) {
PyErr_Format(parser_error, "Expected node type %d, got %d.",
if (!res) { t, TYPE(n));
char buffer[128]; return 0;
(void) sprintf(buffer, "Expected node type %d, got %d.", t, TYPE(n));
err_string(buffer);
} }
return (res); return 1;
} }
...@@ -929,11 +861,11 @@ static int ...@@ -929,11 +861,11 @@ static int
validate_numnodes(node *n, int num, const char *const name) validate_numnodes(node *n, int num, const char *const name)
{ {
if (NCH(n) != num) { if (NCH(n) != num) {
char buff[60]; PyErr_Format(parser_error,
(void) sprintf(buff, "Illegal number of children for %s node.", name); "Illegal number of children for %s node.", name);
err_string(buff); return 0;
} }
return (NCH(n) == num); return 1;
} }
...@@ -944,9 +876,8 @@ validate_terminal(node *terminal, int type, char *string) ...@@ -944,9 +876,8 @@ validate_terminal(node *terminal, int type, char *string)
&& ((string == 0) || (strcmp(string, STR(terminal)) == 0))); && ((string == 0) || (strcmp(string, STR(terminal)) == 0)));
if (!res && !PyErr_Occurred()) { if (!res && !PyErr_Occurred()) {
char buffer[60]; PyErr_Format(parser_error,
(void) sprintf(buffer, "Illegal terminal: expected \"%s\"", string); "Illegal terminal: expected \"%s\"", string);
err_string(buffer);
} }
return (res); return (res);
} }
...@@ -1395,24 +1326,31 @@ static int ...@@ -1395,24 +1326,31 @@ static int
validate_small_stmt(node *tree) validate_small_stmt(node *tree)
{ {
int nch = NCH(tree); int nch = NCH(tree);
int res = (validate_numnodes(tree, 1, "small_stmt") int res = validate_numnodes(tree, 1, "small_stmt");
&& ((TYPE(CHILD(tree, 0)) == expr_stmt)
|| (TYPE(CHILD(tree, 0)) == print_stmt)
|| (TYPE(CHILD(tree, 0)) == del_stmt)
|| (TYPE(CHILD(tree, 0)) == pass_stmt)
|| (TYPE(CHILD(tree, 0)) == flow_stmt)
|| (TYPE(CHILD(tree, 0)) == import_stmt)
|| (TYPE(CHILD(tree, 0)) == global_stmt)
|| (TYPE(CHILD(tree, 0)) == assert_stmt)
|| (TYPE(CHILD(tree, 0)) == exec_stmt)));
if (res) if (res) {
int ntype = TYPE(CHILD(tree, 0));
if ( (ntype == expr_stmt)
|| (ntype == print_stmt)
|| (ntype == del_stmt)
|| (ntype == pass_stmt)
|| (ntype == flow_stmt)
|| (ntype == import_stmt)
|| (ntype == global_stmt)
|| (ntype == assert_stmt)
|| (ntype == exec_stmt))
res = validate_node(CHILD(tree, 0)); res = validate_node(CHILD(tree, 0));
else {
res = 0;
err_string("illegal small_stmt child type");
}
}
else if (nch == 1) { else if (nch == 1) {
char buffer[60]; res = 0;
(void) sprintf(buffer, "Unrecognized child node of small_stmt: %d.", PyErr_Format(parser_error,
"Unrecognized child node of small_stmt: %d.",
TYPE(CHILD(tree, 0))); TYPE(CHILD(tree, 0)));
err_string(buffer);
} }
return (res); return (res);
} }
...@@ -1426,24 +1364,24 @@ validate_compound_stmt(node *tree) ...@@ -1426,24 +1364,24 @@ validate_compound_stmt(node *tree)
{ {
int res = (validate_ntype(tree, compound_stmt) int res = (validate_ntype(tree, compound_stmt)
&& validate_numnodes(tree, 1, "compound_stmt")); && validate_numnodes(tree, 1, "compound_stmt"));
int ntype;
if (!res) if (!res)
return (0); return (0);
tree = CHILD(tree, 0); tree = CHILD(tree, 0);
res = ((TYPE(tree) == if_stmt) ntype = TYPE(tree);
|| (TYPE(tree) == while_stmt) if ( (ntype == if_stmt)
|| (TYPE(tree) == for_stmt) || (ntype == while_stmt)
|| (TYPE(tree) == try_stmt) || (ntype == for_stmt)
|| (TYPE(tree) == funcdef) || (ntype == try_stmt)
|| (TYPE(tree) == classdef)); || (ntype == funcdef)
if (res) || (ntype == classdef))
res = validate_node(tree); res = validate_node(tree);
else { else {
char buffer[60]; res = 0;
(void) sprintf(buffer, "Illegal compound statement type: %d.", PyErr_Format(parser_error,
TYPE(tree)); "Illegal compound statement type: %d.", TYPE(tree));
err_string(buffer);
} }
return (res); return (res);
} }
...@@ -1814,14 +1752,13 @@ validate_try(node *tree) ...@@ -1814,14 +1752,13 @@ validate_try(node *tree)
&& validate_suite(CHILD(tree, 2)) && validate_suite(CHILD(tree, 2))
&& validate_colon(CHILD(tree, nch - 2)) && validate_colon(CHILD(tree, nch - 2))
&& validate_suite(CHILD(tree, nch - 1))); && validate_suite(CHILD(tree, nch - 1)));
else { else if (!PyErr_Occurred()) {
const char* name = "except"; const char* name = "except";
char buffer[60];
if (TYPE(CHILD(tree, nch - 3)) != except_clause) if (TYPE(CHILD(tree, nch - 3)) != except_clause)
name = STR(CHILD(tree, nch - 3)); name = STR(CHILD(tree, nch - 3));
(void) sprintf(buffer,
PyErr_Format(parser_error,
"Illegal number of children for try/%s node.", name); "Illegal number of children for try/%s node.", name);
err_string(buffer);
} }
/* Skip past except_clause sections: */ /* Skip past except_clause sections: */
while (res && (TYPE(CHILD(tree, pos)) == except_clause)) { while (res && (TYPE(CHILD(tree, pos)) == except_clause)) {
...@@ -1974,9 +1911,8 @@ validate_comp_op(node *tree) ...@@ -1974,9 +1911,8 @@ validate_comp_op(node *tree)
res = ((strcmp(STR(tree), "in") == 0) res = ((strcmp(STR(tree), "in") == 0)
|| (strcmp(STR(tree), "is") == 0)); || (strcmp(STR(tree), "is") == 0));
if (!res) { if (!res) {
char buff[128]; PyErr_Format(parser_error,
(void) sprintf(buff, "Illegal operator: '%s'.", STR(tree)); "Illegal operator: '%s'.", STR(tree));
err_string(buff);
} }
break; break;
default: default:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment