Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
d48c21c1
Commit
d48c21c1
authored
Jun 02, 2016
by
Benjamin Peterson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
replace custom validation logic in the parse module with a simple DFA validator (closes #26526)
Patch from A. Skrobov.
parent
114baf5f
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
96 additions
and
2452 deletions
+96
-2452
Misc/NEWS
Misc/NEWS
+3
-0
Modules/parsermodule.c
Modules/parsermodule.c
+93
-2452
No files found.
Misc/NEWS
View file @
d48c21c1
...
...
@@ -22,6 +22,9 @@ Core and Builtins
Library
-------
- Issue #26526: Replace custom parse tree validation in the parser
module with a simple DFA validator.
- Issue #27114: Fix SSLContext._load_windows_store_certs fails with
PermissionError
...
...
Modules/parsermodule.c
View file @
d48c21c1
...
...
@@ -670,9 +670,75 @@ parser_suite(PyST_Object *self, PyObject *args, PyObject *kw)
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
);
static
int
validate_node
(
node
*
tree
)
{
int
type
=
TYPE
(
tree
);
int
nch
=
NCH
(
tree
);
dfa
*
nt_dfa
;
state
*
dfa_state
;
int
pos
,
arc
;
assert
(
ISNONTERMINAL
(
type
));
type
-=
NT_OFFSET
;
if
(
type
>=
_PyParser_Grammar
.
g_ndfas
)
{
PyErr_Format
(
parser_error
,
"Unrecognized node type %d."
,
TYPE
(
tree
));
return
0
;
}
nt_dfa
=
&
_PyParser_Grammar
.
g_dfa
[
type
];
REQ
(
tree
,
nt_dfa
->
d_type
);
/* Run the DFA for this nonterminal. */
dfa_state
=
&
nt_dfa
->
d_state
[
nt_dfa
->
d_initial
];
for
(
pos
=
0
;
pos
<
nch
;
++
pos
)
{
node
*
ch
=
CHILD
(
tree
,
pos
);
int
ch_type
=
TYPE
(
ch
);
for
(
arc
=
0
;
arc
<
dfa_state
->
s_narcs
;
++
arc
)
{
short
a_label
=
dfa_state
->
s_arc
[
arc
].
a_lbl
;
assert
(
a_label
<
_PyParser_Grammar
.
g_ll
.
ll_nlabels
);
if
(
_PyParser_Grammar
.
g_ll
.
ll_label
[
a_label
].
lb_type
==
ch_type
)
{
/* The child is acceptable; if non-terminal, validate it recursively. */
if
(
ISNONTERMINAL
(
ch_type
)
&&
!
validate_node
(
ch
))
return
0
;
/* Update the state, and move on to the next child. */
dfa_state
=
&
nt_dfa
->
d_state
[
dfa_state
->
s_arc
[
arc
].
a_arrow
];
goto
arc_found
;
}
}
/* What would this state have accepted? */
{
short
a_label
=
dfa_state
->
s_arc
->
a_lbl
;
int
next_type
;
if
(
!
a_label
)
/* Wouldn't accept any more children */
goto
illegal_num_children
;
next_type
=
_PyParser_Grammar
.
g_ll
.
ll_label
[
a_label
].
lb_type
;
if
(
ISNONTERMINAL
(
next_type
))
PyErr_Format
(
parser_error
,
"Expected node type %d, got %d."
,
next_type
,
ch_type
);
else
PyErr_Format
(
parser_error
,
"Illegal terminal: expected %s."
,
_PyParser_TokenNames
[
next_type
]);
return
0
;
}
arc_found:
continue
;
}
/* Are we in a final state? If so, return 1 for successful validation. */
for
(
arc
=
0
;
arc
<
dfa_state
->
s_narcs
;
++
arc
)
{
if
(
!
dfa_state
->
s_arc
[
arc
].
a_lbl
)
{
return
1
;
}
}
illegal_num_children:
PyErr_Format
(
parser_error
,
"Illegal number of children for %s node."
,
nt_dfa
->
d_name
);
return
0
;
}
/* PyObject* parser_tuple2st(PyObject* self, PyObject* args)
*
...
...
@@ -681,7 +747,7 @@ static int validate_encoding_decl(node *tree);
* 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
.
* possible with the
recursive validate_node() routine defined above
.
*
* This function must be changed if support is to be added for PyST_FRAGMENT
* ST objects.
...
...
@@ -710,33 +776,35 @@ parser_tuple2st(PyST_Object *self, PyObject *args, PyObject *kw)
*/
tree
=
build_node_tree
(
tuple
);
if
(
tree
!=
0
)
{
int
start_sym
=
TYPE
(
tree
);
if
(
start_sym
==
eval_input
)
{
node
*
validation_root
=
tree
;
int
tree_type
=
0
;
switch
(
TYPE
(
tree
))
{
case
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
)
{
tree_type
=
PyST_EXPR
;
break
;
case
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
{
if
(
NCH
(
tree
)
!=
1
)
err_string
(
"Error Parsing encoding_decl"
);
validation_root
=
CHILD
(
tree
,
0
);
/* Fall through */
case
file_input
:
/* This looks like an exec form so far. */
tree_type
=
PyST_SUITE
;
break
;
default:
/* This is a fragment, at best. */
PyNode_Free
(
tree
);
err_string
(
"parse tree does not use a valid start symbol"
);
return
(
0
);
}
if
(
validate_node
(
validation_root
))
st
=
parser_newstobject
(
tree
,
tree_type
);
else
PyNode_Free
(
tree
);
}
/* Make sure we raise an exception on all errors. We should never
* get this, but we'd do well to be sure something is done.
...
...
@@ -981,2433 +1049,6 @@ build_node_tree(PyObject *tuple)
}
/*
* Validation routines used within the validation section:
*/
static
int
validate_terminal
(
node
*
terminal
,
int
type
,
const
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_rarrow(ch) validate_terminal(ch, RARROW, "->")
#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
(
vfpdef
);
VALIDATER
(
stmt
);
VALIDATER
(
simple_stmt
);
VALIDATER
(
expr_stmt
);
VALIDATER
(
power
);
VALIDATER
(
del_stmt
);
VALIDATER
(
return_stmt
);
VALIDATER
(
raise_stmt
);
VALIDATER
(
import_stmt
);
VALIDATER
(
import_stmt
);
VALIDATER
(
import_name
);
VALIDATER
(
yield_stmt
);
VALIDATER
(
global_stmt
);
VALIDATER
(
nonlocal_stmt
);
VALIDATER
(
assert_stmt
);
VALIDATER
(
compound_stmt
);
VALIDATER
(
test_or_star_expr
);
VALIDATER
(
while
);
VALIDATER
(
for
);
VALIDATER
(
try
);
VALIDATER
(
except_clause
);
VALIDATER
(
test
);
VALIDATER
(
and_test
);
VALIDATER
(
not_test
);
VALIDATER
(
comparison
);
VALIDATER
(
comp_op
);
VALIDATER
(
star_expr
);
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
(
dictorsetmaker
);
VALIDATER
(
arglist
);
VALIDATER
(
argument
);
VALIDATER
(
comp_for
);
VALIDATER
(
comp_iter
);
VALIDATER
(
comp_if
);
VALIDATER
(
testlist_comp
);
VALIDATER
(
yield_expr
);
VALIDATER
(
or_test
);
VALIDATER
(
test_nocond
);
VALIDATER
(
lambdef_nocond
);
VALIDATER
(
yield_arg
);
VALIDATER
(
async_funcdef
);
VALIDATER
(
async_stmt
);
VALIDATER
(
atom_expr
);
#undef VALIDATER
#define is_even(n) (((n) & 1) == 0)
#define is_odd(n) (((n) & 1) == 1)
static
int
validate_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
int
validate_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
int
validate_terminal
(
node
*
terminal
,
int
type
,
const
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
int
validate_repeating_list_variable
(
node
*
tree
,
int
list_node_type
,
int
(
*
validate_child_func_inc
)(
node
*
,
int
*
),
int
*
pos
,
const
char
*
const
list_node_type_name
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
nch
&&
validate_ntype
(
tree
,
list_node_type
));
if
(
!
res
&&
!
PyErr_Occurred
())
{
/* Unconditionally raise. */
(
void
)
validate_numnodes
(
tree
,
1
,
list_node_type_name
);
}
else
{
for
(
;
res
&&
*
pos
<
nch
;
)
{
res
=
validate_child_func_inc
(
tree
,
pos
);
if
(
!
res
||
*
pos
>=
nch
)
break
;
res
=
validate_comma
(
CHILD
(
tree
,
(
*
pos
)
++
));
}
}
return
res
;
}
/* X (',' X) [','] */
static
int
validate_repeating_list
(
node
*
tree
,
int
list_node_type
,
int
(
*
validate_child_func
)(
node
*
),
const
char
*
const
list_node_type_name
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
nch
&&
validate_ntype
(
tree
,
list_node_type
));
int
pos
=
0
;
if
(
!
res
&&
!
PyErr_Occurred
())
{
/* Unconditionally raise. */
(
void
)
validate_numnodes
(
tree
,
1
,
list_node_type_name
);
}
else
{
for
(
;
res
&&
pos
<
nch
;
)
{
res
=
validate_child_func
(
CHILD
(
tree
,
pos
++
));
if
(
!
res
||
pos
>=
nch
)
break
;
res
=
validate_comma
(
CHILD
(
tree
,
pos
++
));
}
}
return
res
;
}
/* validate_class()
*
* classdef:
* 'class' NAME ['(' testlist ')'] ':' suite
*/
static
int
validate_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_arglist
(
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
int
validate_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
))
{
/* ... 'else' ':' suite */
res
=
(
validate_name
(
CHILD
(
tree
,
nch
-
3
),
"else"
)
&&
validate_colon
(
CHILD
(
tree
,
nch
-
2
))
&&
validate_suite
(
CHILD
(
tree
,
nch
-
1
)));
nch
-=
3
;
}
else
if
(
!
res
&&
!
PyErr_Occurred
())
(
void
)
validate_numnodes
(
tree
,
4
,
"if"
);
if
((
nch
%
4
)
!=
0
)
/* Will catch the case for nch < 4 */
res
=
validate_numnodes
(
tree
,
0
,
"if"
);
else
if
(
res
&&
(
nch
>
4
))
{
/* ... ('elif' test ':' suite)+ ... */
int
j
=
4
;
while
((
j
<
nch
)
&&
res
)
{
res
=
(
validate_name
(
CHILD
(
tree
,
j
),
"elif"
)
&&
validate_colon
(
CHILD
(
tree
,
j
+
2
))
&&
validate_test
(
CHILD
(
tree
,
j
+
1
))
&&
validate_suite
(
CHILD
(
tree
,
j
+
3
)));
j
+=
4
;
}
}
return
(
res
);
}
/* parameters:
* '(' [varargslist] ')'
*
*/
static
int
validate_parameters
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_ntype
(
tree
,
parameters
)
&&
((
nch
==
2
)
||
(
nch
==
3
));
if
(
res
)
{
res
=
(
validate_lparen
(
CHILD
(
tree
,
0
))
&&
validate_rparen
(
CHILD
(
tree
,
nch
-
1
)));
if
(
res
&&
(
nch
==
3
))
res
=
validate_varargslist
(
CHILD
(
tree
,
1
));
}
else
{
(
void
)
validate_numnodes
(
tree
,
2
,
"parameters"
);
}
return
(
res
);
}
/* validate_suite()
*
* suite:
* simple_stmt
* | NEWLINE INDENT stmt+ DEDENT
*/
static
int
validate_suite
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
suite
)
&&
((
nch
==
1
)
||
(
nch
>=
4
)));
if
(
res
&&
(
nch
==
1
))
res
=
validate_simple_stmt
(
CHILD
(
tree
,
0
));
else
if
(
res
)
{
/* NEWLINE INDENT stmt+ DEDENT */
res
=
(
validate_newline
(
CHILD
(
tree
,
0
))
&&
validate_indent
(
CHILD
(
tree
,
1
))
&&
validate_stmt
(
CHILD
(
tree
,
2
))
&&
validate_dedent
(
CHILD
(
tree
,
nch
-
1
)));
if
(
res
&&
(
nch
>
4
))
{
int
i
=
3
;
--
nch
;
/* forget the DEDENT */
for
(
;
res
&&
(
i
<
nch
);
++
i
)
res
=
validate_stmt
(
CHILD
(
tree
,
i
));
}
else
if
(
nch
<
4
)
res
=
validate_numnodes
(
tree
,
4
,
"suite"
);
}
return
(
res
);
}
static
int
validate_testlist
(
node
*
tree
)
{
return
(
validate_repeating_list
(
tree
,
testlist
,
validate_test
,
"testlist"
));
}
static
int
validate_testlist_star_expr
(
node
*
tl
)
{
return
(
validate_repeating_list
(
tl
,
testlist_star_expr
,
validate_test_or_star_expr
,
"testlist"
));
}
/* validate either vfpdef or tfpdef.
* vfpdef: NAME
* tfpdef: NAME [':' test]
*/
static
int
validate_vfpdef
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
if
(
TYPE
(
tree
)
==
vfpdef
)
{
return
nch
==
1
&&
validate_name
(
CHILD
(
tree
,
0
),
NULL
);
}
else
if
(
TYPE
(
tree
)
==
tfpdef
)
{
if
(
nch
==
1
)
{
return
validate_name
(
CHILD
(
tree
,
0
),
NULL
);
}
else
if
(
nch
==
3
)
{
return
validate_name
(
CHILD
(
tree
,
0
),
NULL
)
&&
validate_colon
(
CHILD
(
tree
,
1
))
&&
validate_test
(
CHILD
(
tree
,
2
));
}
}
return
0
;
}
/* '*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef
* ..or tfpdef in place of vfpdef. vfpdef: NAME; tfpdef: NAME [':' test]
*/
static
int
validate_varargslist_trailer
(
node
*
tree
,
int
start
)
{
int
nch
=
NCH
(
tree
);
int
res
=
0
;
if
(
nch
<=
start
)
{
err_string
(
"expected variable argument trailer for varargslist"
);
return
0
;
}
if
(
TYPE
(
CHILD
(
tree
,
start
))
==
STAR
)
{
/*
* '*' [vfpdef]
*/
res
=
validate_star
(
CHILD
(
tree
,
start
++
));
if
(
res
&&
start
<
nch
&&
(
TYPE
(
CHILD
(
tree
,
start
))
==
vfpdef
||
TYPE
(
CHILD
(
tree
,
start
))
==
tfpdef
))
res
=
validate_vfpdef
(
CHILD
(
tree
,
start
++
));
/*
* (',' vfpdef ['=' test])*
*/
while
(
res
&&
start
+
1
<
nch
&&
(
TYPE
(
CHILD
(
tree
,
start
+
1
))
==
vfpdef
||
TYPE
(
CHILD
(
tree
,
start
+
1
))
==
tfpdef
))
{
res
=
(
validate_comma
(
CHILD
(
tree
,
start
++
))
&&
validate_vfpdef
(
CHILD
(
tree
,
start
++
)));
if
(
res
&&
start
+
1
<
nch
&&
TYPE
(
CHILD
(
tree
,
start
))
==
EQUAL
)
res
=
(
validate_equal
(
CHILD
(
tree
,
start
++
))
&&
validate_test
(
CHILD
(
tree
,
start
++
)));
}
/*
* [',' '**' vfpdef]
*/
if
(
res
&&
start
+
2
<
nch
&&
TYPE
(
CHILD
(
tree
,
start
+
1
))
==
DOUBLESTAR
)
res
=
(
validate_comma
(
CHILD
(
tree
,
start
++
))
&&
validate_doublestar
(
CHILD
(
tree
,
start
++
))
&&
validate_vfpdef
(
CHILD
(
tree
,
start
++
)));
}
else
if
(
TYPE
(
CHILD
(
tree
,
start
))
==
DOUBLESTAR
)
{
/*
* '**' vfpdef
*/
if
(
start
+
1
<
nch
)
res
=
(
validate_doublestar
(
CHILD
(
tree
,
start
++
))
&&
validate_vfpdef
(
CHILD
(
tree
,
start
++
)));
else
{
res
=
0
;
err_string
(
"expected vfpdef after ** in varargslist trailer"
);
}
}
else
{
res
=
0
;
err_string
(
"expected * or ** in varargslist trailer"
);
}
if
(
res
&&
start
!=
nch
)
{
res
=
0
;
err_string
(
"unexpected extra children in varargslist trailer"
);
}
return
res
;
}
/* validate_varargslist()
*
* Validate typedargslist or varargslist.
*
* typedargslist: ((tfpdef ['=' test] ',')*
* ('*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] |
* '**' tfpdef)
* | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
* tfpdef: NAME [':' test]
* varargslist: ((vfpdef ['=' test] ',')*
* ('*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] |
* '**' vfpdef)
* | vfpdef ['=' test] (',' vfpdef ['=' test])* [','])
* vfpdef: NAME
*
*/
static
int
validate_varargslist
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
TYPE
(
tree
)
==
varargslist
||
TYPE
(
tree
)
==
typedargslist
)
&&
(
nch
!=
0
);
int
sym
;
node
*
ch
;
int
i
=
0
;
if
(
!
res
)
return
0
;
if
(
nch
<
1
)
{
err_string
(
"varargslist missing child nodes"
);
return
0
;
}
while
(
i
<
nch
)
{
ch
=
CHILD
(
tree
,
i
);
sym
=
TYPE
(
ch
);
if
(
sym
==
vfpdef
||
sym
==
tfpdef
)
{
/* validate (vfpdef ['=' test] ',')+ */
res
=
validate_vfpdef
(
ch
);
++
i
;
if
(
res
&&
(
i
+
2
<=
nch
)
&&
TYPE
(
CHILD
(
tree
,
i
))
==
EQUAL
)
{
res
=
(
validate_equal
(
CHILD
(
tree
,
i
))
&&
validate_test
(
CHILD
(
tree
,
i
+
1
)));
if
(
res
)
i
+=
2
;
}
if
(
res
&&
i
<
nch
)
{
res
=
validate_comma
(
CHILD
(
tree
,
i
));
++
i
;
}
}
else
if
(
sym
==
DOUBLESTAR
||
sym
==
STAR
)
{
res
=
validate_varargslist_trailer
(
tree
,
i
);
break
;
}
else
{
res
=
0
;
err_string
(
"illegal formation for varargslist"
);
}
}
return
res
;
}
/* comp_iter: comp_for | comp_if
*/
static
int
validate_comp_iter
(
node
*
tree
)
{
int
res
=
(
validate_ntype
(
tree
,
comp_iter
)
&&
validate_numnodes
(
tree
,
1
,
"comp_iter"
));
if
(
res
&&
TYPE
(
CHILD
(
tree
,
0
))
==
comp_for
)
res
=
validate_comp_for
(
CHILD
(
tree
,
0
));
else
res
=
validate_comp_if
(
CHILD
(
tree
,
0
));
return
res
;
}
/* comp_for: 'for' exprlist 'in' test [comp_iter]
*/
static
int
validate_comp_for
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
;
if
(
nch
==
5
)
res
=
validate_comp_iter
(
CHILD
(
tree
,
4
));
else
res
=
validate_numnodes
(
tree
,
4
,
"comp_for"
);
if
(
res
)
res
=
(
validate_name
(
CHILD
(
tree
,
0
),
"for"
)
&&
validate_exprlist
(
CHILD
(
tree
,
1
))
&&
validate_name
(
CHILD
(
tree
,
2
),
"in"
)
&&
validate_or_test
(
CHILD
(
tree
,
3
)));
return
res
;
}
/* comp_if: 'if' test_nocond [comp_iter]
*/
static
int
validate_comp_if
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
;
if
(
nch
==
3
)
res
=
validate_comp_iter
(
CHILD
(
tree
,
2
));
else
res
=
validate_numnodes
(
tree
,
2
,
"comp_if"
);
if
(
res
)
res
=
(
validate_name
(
CHILD
(
tree
,
0
),
"if"
)
&&
validate_test_nocond
(
CHILD
(
tree
,
1
)));
return
res
;
}
/* simple_stmt | compound_stmt
*
*/
static
int
validate_stmt
(
node
*
tree
)
{
int
res
=
(
validate_ntype
(
tree
,
stmt
)
&&
validate_numnodes
(
tree
,
1
,
"stmt"
));
if
(
res
)
{
tree
=
CHILD
(
tree
,
0
);
if
(
TYPE
(
tree
)
==
simple_stmt
)
res
=
validate_simple_stmt
(
tree
);
else
res
=
validate_compound_stmt
(
tree
);
}
return
(
res
);
}
/* small_stmt (';' small_stmt)* [';'] NEWLINE
*
*/
static
int
validate_simple_stmt
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
simple_stmt
)
&&
(
nch
>=
2
)
&&
validate_small_stmt
(
CHILD
(
tree
,
0
))
&&
validate_newline
(
CHILD
(
tree
,
nch
-
1
)));
if
(
nch
<
2
)
res
=
validate_numnodes
(
tree
,
2
,
"simple_stmt"
);
--
nch
;
/* forget the NEWLINE */
if
(
res
&&
is_even
(
nch
))
res
=
validate_semi
(
CHILD
(
tree
,
--
nch
));
if
(
res
&&
(
nch
>
2
))
{
int
i
;
for
(
i
=
1
;
res
&&
(
i
<
nch
);
i
+=
2
)
res
=
(
validate_semi
(
CHILD
(
tree
,
i
))
&&
validate_small_stmt
(
CHILD
(
tree
,
i
+
1
)));
}
return
(
res
);
}
static
int
validate_small_stmt
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_numnodes
(
tree
,
1
,
"small_stmt"
);
if
(
res
)
{
int
ntype
=
TYPE
(
CHILD
(
tree
,
0
));
if
(
(
ntype
==
expr_stmt
)
||
(
ntype
==
del_stmt
)
||
(
ntype
==
pass_stmt
)
||
(
ntype
==
flow_stmt
)
||
(
ntype
==
import_stmt
)
||
(
ntype
==
global_stmt
)
||
(
ntype
==
nonlocal_stmt
)
||
(
ntype
==
assert_stmt
))
res
=
validate_node
(
CHILD
(
tree
,
0
));
else
{
res
=
0
;
err_string
(
"illegal small_stmt child type"
);
}
}
else
if
(
nch
==
1
)
{
res
=
0
;
PyErr_Format
(
parser_error
,
"Unrecognized child node of small_stmt: %d."
,
TYPE
(
CHILD
(
tree
,
0
)));
}
return
(
res
);
}
/* compound_stmt:
* if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated
*/
static
int
validate_compound_stmt
(
node
*
tree
)
{
int
res
=
(
validate_ntype
(
tree
,
compound_stmt
)
&&
validate_numnodes
(
tree
,
1
,
"compound_stmt"
));
int
ntype
;
if
(
!
res
)
return
(
0
);
tree
=
CHILD
(
tree
,
0
);
ntype
=
TYPE
(
tree
);
if
(
(
ntype
==
if_stmt
)
||
(
ntype
==
while_stmt
)
||
(
ntype
==
for_stmt
)
||
(
ntype
==
try_stmt
)
||
(
ntype
==
with_stmt
)
||
(
ntype
==
funcdef
)
||
(
ntype
==
async_stmt
)
||
(
ntype
==
classdef
)
||
(
ntype
==
decorated
))
res
=
validate_node
(
tree
);
else
{
res
=
0
;
PyErr_Format
(
parser_error
,
"Illegal compound statement type: %d."
,
TYPE
(
tree
));
}
return
(
res
);
}
static
int
validate_yield_or_testlist
(
node
*
tree
,
int
tse
)
{
if
(
TYPE
(
tree
)
==
yield_expr
)
{
return
validate_yield_expr
(
tree
);
}
else
{
if
(
tse
)
return
validate_testlist_star_expr
(
tree
);
else
return
validate_testlist
(
tree
);
}
}
static
int
validate_expr_stmt
(
node
*
tree
)
{
int
j
;
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
expr_stmt
)
&&
is_odd
(
nch
)
&&
validate_testlist_star_expr
(
CHILD
(
tree
,
0
)));
if
(
res
&&
nch
==
3
&&
TYPE
(
CHILD
(
tree
,
1
))
==
augassign
)
{
res
=
validate_numnodes
(
CHILD
(
tree
,
1
),
1
,
"augassign"
)
&&
validate_yield_or_testlist
(
CHILD
(
tree
,
2
),
0
);
if
(
res
)
{
char
*
s
=
STR
(
CHILD
(
CHILD
(
tree
,
1
),
0
));
res
=
(
strcmp
(
s
,
"+="
)
==
0
||
strcmp
(
s
,
"-="
)
==
0
||
strcmp
(
s
,
"*="
)
==
0
||
strcmp
(
s
,
"/="
)
==
0
||
strcmp
(
s
,
"//="
)
==
0
||
strcmp
(
s
,
"%="
)
==
0
||
strcmp
(
s
,
"&="
)
==
0
||
strcmp
(
s
,
"|="
)
==
0
||
strcmp
(
s
,
"^="
)
==
0
||
strcmp
(
s
,
"<<="
)
==
0
||
strcmp
(
s
,
">>="
)
==
0
||
strcmp
(
s
,
"**="
)
==
0
);
if
(
!
res
)
err_string
(
"illegal augmented assignment operator"
);
}
}
else
{
for
(
j
=
1
;
res
&&
(
j
<
nch
);
j
+=
2
)
res
=
validate_equal
(
CHILD
(
tree
,
j
))
&&
validate_yield_or_testlist
(
CHILD
(
tree
,
j
+
1
),
1
);
}
return
(
res
);
}
static
int
validate_del_stmt
(
node
*
tree
)
{
return
(
validate_numnodes
(
tree
,
2
,
"del_stmt"
)
&&
validate_name
(
CHILD
(
tree
,
0
),
"del"
)
&&
validate_exprlist
(
CHILD
(
tree
,
1
)));
}
static
int
validate_return_stmt
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
return_stmt
)
&&
((
nch
==
1
)
||
(
nch
==
2
))
&&
validate_name
(
CHILD
(
tree
,
0
),
"return"
));
if
(
res
&&
(
nch
==
2
))
res
=
validate_testlist
(
CHILD
(
tree
,
1
));
return
(
res
);
}
/*
* raise_stmt:
*
* 'raise' [test ['from' test]]
*/
static
int
validate_raise_stmt
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
raise_stmt
)
&&
((
nch
==
1
)
||
(
nch
==
2
)
||
(
nch
==
4
)));
if
(
!
res
&&
!
PyErr_Occurred
())
(
void
)
validate_numnodes
(
tree
,
2
,
"raise"
);
if
(
res
)
{
res
=
validate_name
(
CHILD
(
tree
,
0
),
"raise"
);
if
(
res
&&
(
nch
>=
2
))
res
=
validate_test
(
CHILD
(
tree
,
1
));
if
(
res
&&
(
nch
==
4
))
{
res
=
(
validate_name
(
CHILD
(
tree
,
2
),
"from"
)
&&
validate_test
(
CHILD
(
tree
,
3
)));
}
}
return
(
res
);
}
/* yield_expr: 'yield' [yield_arg]
*/
static
int
validate_yield_expr
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
if
(
nch
<
1
||
nch
>
2
)
return
0
;
if
(
!
validate_ntype
(
tree
,
yield_expr
))
return
0
;
if
(
!
validate_name
(
CHILD
(
tree
,
0
),
"yield"
))
return
0
;
if
(
nch
==
2
)
{
if
(
!
validate_yield_arg
(
CHILD
(
tree
,
1
)))
return
0
;
}
return
1
;
}
/* yield_arg: 'from' test | testlist
*/
static
int
validate_yield_arg
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
if
(
!
validate_ntype
(
tree
,
yield_arg
))
return
0
;
switch
(
nch
)
{
case
1
:
if
(
!
validate_testlist
(
CHILD
(
tree
,
nch
-
1
)))
return
0
;
break
;
case
2
:
if
(
!
validate_name
(
CHILD
(
tree
,
0
),
"from"
))
return
0
;
if
(
!
validate_test
(
CHILD
(
tree
,
1
)))
return
0
;
break
;
default:
return
0
;
}
return
1
;
}
/* yield_stmt: yield_expr
*/
static
int
validate_yield_stmt
(
node
*
tree
)
{
return
(
validate_ntype
(
tree
,
yield_stmt
)
&&
validate_numnodes
(
tree
,
1
,
"yield_stmt"
)
&&
validate_yield_expr
(
CHILD
(
tree
,
0
)));
}
static
int
validate_import_as_name
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
ok
=
validate_ntype
(
tree
,
import_as_name
);
if
(
ok
)
{
if
(
nch
==
1
)
ok
=
validate_name
(
CHILD
(
tree
,
0
),
NULL
);
else
if
(
nch
==
3
)
ok
=
(
validate_name
(
CHILD
(
tree
,
0
),
NULL
)
&&
validate_name
(
CHILD
(
tree
,
1
),
"as"
)
&&
validate_name
(
CHILD
(
tree
,
2
),
NULL
));
else
ok
=
validate_numnodes
(
tree
,
3
,
"import_as_name"
);
}
return
ok
;
}
/* dotted_name: NAME ("." NAME)*
*/
static
int
validate_dotted_name
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
dotted_name
)
&&
is_odd
(
nch
)
&&
validate_name
(
CHILD
(
tree
,
0
),
NULL
));
int
i
;
for
(
i
=
1
;
res
&&
(
i
<
nch
);
i
+=
2
)
{
res
=
(
validate_dot
(
CHILD
(
tree
,
i
))
&&
validate_name
(
CHILD
(
tree
,
i
+
1
),
NULL
));
}
return
res
;
}
/* dotted_as_name: dotted_name [NAME NAME]
*/
static
int
validate_dotted_as_name
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_ntype
(
tree
,
dotted_as_name
);
if
(
res
)
{
if
(
nch
==
1
)
res
=
validate_dotted_name
(
CHILD
(
tree
,
0
));
else
if
(
nch
==
3
)
res
=
(
validate_dotted_name
(
CHILD
(
tree
,
0
))
&&
validate_name
(
CHILD
(
tree
,
1
),
"as"
)
&&
validate_name
(
CHILD
(
tree
,
2
),
NULL
));
else
{
res
=
0
;
err_string
(
"illegal number of children for dotted_as_name"
);
}
}
return
res
;
}
/* dotted_as_name (',' dotted_as_name)* */
static
int
validate_dotted_as_names
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
is_odd
(
nch
)
&&
validate_dotted_as_name
(
CHILD
(
tree
,
0
));
int
i
;
for
(
i
=
1
;
res
&&
(
i
<
nch
);
i
+=
2
)
res
=
(
validate_comma
(
CHILD
(
tree
,
i
))
&&
validate_dotted_as_name
(
CHILD
(
tree
,
i
+
1
)));
return
(
res
);
}
/* import_as_name (',' import_as_name)* [','] */
static
int
validate_import_as_names
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_import_as_name
(
CHILD
(
tree
,
0
));
int
i
;
for
(
i
=
1
;
res
&&
(
i
+
1
<
nch
);
i
+=
2
)
res
=
(
validate_comma
(
CHILD
(
tree
,
i
))
&&
validate_import_as_name
(
CHILD
(
tree
,
i
+
1
)));
return
(
res
);
}
/* 'import' dotted_as_names */
static
int
validate_import_name
(
node
*
tree
)
{
return
(
validate_ntype
(
tree
,
import_name
)
&&
validate_numnodes
(
tree
,
2
,
"import_name"
)
&&
validate_name
(
CHILD
(
tree
,
0
),
"import"
)
&&
validate_dotted_as_names
(
CHILD
(
tree
,
1
)));
}
/* Helper function to count the number of leading dots (or ellipsis tokens) in
* 'from ...module import name'
*/
static
int
count_from_dots
(
node
*
tree
)
{
int
i
;
for
(
i
=
1
;
i
<
NCH
(
tree
);
i
++
)
if
(
TYPE
(
CHILD
(
tree
,
i
))
!=
DOT
&&
TYPE
(
CHILD
(
tree
,
i
))
!=
ELLIPSIS
)
break
;
return
i
-
1
;
}
/* import_from: ('from' ('.'* dotted_name | '.'+)
* 'import' ('*' | '(' import_as_names ')' | import_as_names))
*/
static
int
validate_import_from
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
ndots
=
count_from_dots
(
tree
);
int
havename
=
(
TYPE
(
CHILD
(
tree
,
ndots
+
1
))
==
dotted_name
);
int
offset
=
ndots
+
havename
;
int
res
=
validate_ntype
(
tree
,
import_from
)
&&
(
offset
>=
1
)
&&
(
nch
>=
3
+
offset
)
&&
validate_name
(
CHILD
(
tree
,
0
),
"from"
)
&&
(
!
havename
||
validate_dotted_name
(
CHILD
(
tree
,
ndots
+
1
)))
&&
validate_name
(
CHILD
(
tree
,
offset
+
1
),
"import"
);
if
(
res
&&
TYPE
(
CHILD
(
tree
,
offset
+
2
))
==
LPAR
)
res
=
((
nch
==
offset
+
5
)
&&
validate_lparen
(
CHILD
(
tree
,
offset
+
2
))
&&
validate_import_as_names
(
CHILD
(
tree
,
offset
+
3
))
&&
validate_rparen
(
CHILD
(
tree
,
offset
+
4
)));
else
if
(
res
&&
TYPE
(
CHILD
(
tree
,
offset
+
2
))
!=
STAR
)
res
=
validate_import_as_names
(
CHILD
(
tree
,
offset
+
2
));
return
(
res
);
}
/* import_stmt: import_name | import_from */
static
int
validate_import_stmt
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_numnodes
(
tree
,
1
,
"import_stmt"
);
if
(
res
)
{
int
ntype
=
TYPE
(
CHILD
(
tree
,
0
));
if
(
ntype
==
import_name
||
ntype
==
import_from
)
res
=
validate_node
(
CHILD
(
tree
,
0
));
else
{
res
=
0
;
err_string
(
"illegal import_stmt child type"
);
}
}
else
if
(
nch
==
1
)
{
res
=
0
;
PyErr_Format
(
parser_error
,
"Unrecognized child node of import_stmt: %d."
,
TYPE
(
CHILD
(
tree
,
0
)));
}
return
(
res
);
}
/* global_stmt:
*
* 'global' NAME (',' NAME)*
*/
static
int
validate_global_stmt
(
node
*
tree
)
{
int
j
;
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
global_stmt
)
&&
is_even
(
nch
)
&&
(
nch
>=
2
));
if
(
!
res
&&
!
PyErr_Occurred
())
err_string
(
"illegal global statement"
);
if
(
res
)
res
=
(
validate_name
(
CHILD
(
tree
,
0
),
"global"
)
&&
validate_ntype
(
CHILD
(
tree
,
1
),
NAME
));
for
(
j
=
2
;
res
&&
(
j
<
nch
);
j
+=
2
)
res
=
(
validate_comma
(
CHILD
(
tree
,
j
))
&&
validate_ntype
(
CHILD
(
tree
,
j
+
1
),
NAME
));
return
(
res
);
}
/* nonlocal_stmt:
*
* 'nonlocal' NAME (',' NAME)*
*/
static
int
validate_nonlocal_stmt
(
node
*
tree
)
{
int
j
;
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
nonlocal_stmt
)
&&
is_even
(
nch
)
&&
(
nch
>=
2
));
if
(
!
res
&&
!
PyErr_Occurred
())
err_string
(
"illegal nonlocal statement"
);
if
(
res
)
res
=
(
validate_name
(
CHILD
(
tree
,
0
),
"nonlocal"
)
&&
validate_ntype
(
CHILD
(
tree
,
1
),
NAME
));
for
(
j
=
2
;
res
&&
(
j
<
nch
);
j
+=
2
)
res
=
(
validate_comma
(
CHILD
(
tree
,
j
))
&&
validate_ntype
(
CHILD
(
tree
,
j
+
1
),
NAME
));
return
res
;
}
/* assert_stmt:
*
* 'assert' test [',' test]
*/
static
int
validate_assert_stmt
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
assert_stmt
)
&&
((
nch
==
2
)
||
(
nch
==
4
))
&&
(
validate_name
(
CHILD
(
tree
,
0
),
"assert"
))
&&
validate_test
(
CHILD
(
tree
,
1
)));
if
(
!
res
&&
!
PyErr_Occurred
())
err_string
(
"illegal assert statement"
);
if
(
res
&&
(
nch
>
2
))
res
=
(
validate_comma
(
CHILD
(
tree
,
2
))
&&
validate_test
(
CHILD
(
tree
,
3
)));
return
(
res
);
}
static
int
validate_while
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
while_stmt
)
&&
((
nch
==
4
)
||
(
nch
==
7
))
&&
validate_name
(
CHILD
(
tree
,
0
),
"while"
)
&&
validate_test
(
CHILD
(
tree
,
1
))
&&
validate_colon
(
CHILD
(
tree
,
2
))
&&
validate_suite
(
CHILD
(
tree
,
3
)));
if
(
res
&&
(
nch
==
7
))
res
=
(
validate_name
(
CHILD
(
tree
,
4
),
"else"
)
&&
validate_colon
(
CHILD
(
tree
,
5
))
&&
validate_suite
(
CHILD
(
tree
,
6
)));
return
(
res
);
}
static
int
validate_for
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
for_stmt
)
&&
((
nch
==
6
)
||
(
nch
==
9
))
&&
validate_name
(
CHILD
(
tree
,
0
),
"for"
)
&&
validate_exprlist
(
CHILD
(
tree
,
1
))
&&
validate_name
(
CHILD
(
tree
,
2
),
"in"
)
&&
validate_testlist
(
CHILD
(
tree
,
3
))
&&
validate_colon
(
CHILD
(
tree
,
4
))
&&
validate_suite
(
CHILD
(
tree
,
5
)));
if
(
res
&&
(
nch
==
9
))
res
=
(
validate_name
(
CHILD
(
tree
,
6
),
"else"
)
&&
validate_colon
(
CHILD
(
tree
,
7
))
&&
validate_suite
(
CHILD
(
tree
,
8
)));
return
(
res
);
}
/* try_stmt:
* 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
['finally' ':' suite]
* | 'try' ':' suite 'finally' ':' suite
*
*/
static
int
validate_try
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
pos
=
3
;
int
res
=
(
validate_ntype
(
tree
,
try_stmt
)
&&
(
nch
>=
6
)
&&
((
nch
%
3
)
==
0
));
if
(
res
)
res
=
(
validate_name
(
CHILD
(
tree
,
0
),
"try"
)
&&
validate_colon
(
CHILD
(
tree
,
1
))
&&
validate_suite
(
CHILD
(
tree
,
2
))
&&
validate_colon
(
CHILD
(
tree
,
nch
-
2
))
&&
validate_suite
(
CHILD
(
tree
,
nch
-
1
)));
else
if
(
!
PyErr_Occurred
())
{
const
char
*
name
=
"except"
;
if
(
TYPE
(
CHILD
(
tree
,
nch
-
3
))
!=
except_clause
)
name
=
STR
(
CHILD
(
tree
,
nch
-
3
));
PyErr_Format
(
parser_error
,
"Illegal number of children for try/%s node."
,
name
);
}
/* Handle try/finally statement */
if
(
res
&&
(
TYPE
(
CHILD
(
tree
,
pos
))
==
NAME
)
&&
(
strcmp
(
STR
(
CHILD
(
tree
,
pos
)),
"finally"
)
==
0
))
{
res
=
(
validate_numnodes
(
tree
,
6
,
"try/finally"
)
&&
validate_colon
(
CHILD
(
tree
,
4
))
&&
validate_suite
(
CHILD
(
tree
,
5
)));
return
(
res
);
}
/* try/except statement: skip past except_clause sections */
while
(
res
&&
pos
<
nch
&&
(
TYPE
(
CHILD
(
tree
,
pos
))
==
except_clause
))
{
res
=
(
validate_except_clause
(
CHILD
(
tree
,
pos
))
&&
validate_colon
(
CHILD
(
tree
,
pos
+
1
))
&&
validate_suite
(
CHILD
(
tree
,
pos
+
2
)));
pos
+=
3
;
}
/* skip else clause */
if
(
res
&&
pos
<
nch
&&
(
TYPE
(
CHILD
(
tree
,
pos
))
==
NAME
)
&&
(
strcmp
(
STR
(
CHILD
(
tree
,
pos
)),
"else"
)
==
0
))
{
res
=
(
validate_colon
(
CHILD
(
tree
,
pos
+
1
))
&&
validate_suite
(
CHILD
(
tree
,
pos
+
2
)));
pos
+=
3
;
}
if
(
res
&&
pos
<
nch
)
{
/* last clause must be a finally */
res
=
(
validate_name
(
CHILD
(
tree
,
pos
),
"finally"
)
&&
validate_numnodes
(
tree
,
pos
+
3
,
"try/except/finally"
)
&&
validate_colon
(
CHILD
(
tree
,
pos
+
1
))
&&
validate_suite
(
CHILD
(
tree
,
pos
+
2
)));
}
return
(
res
);
}
static
int
validate_except_clause
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
except_clause
)
&&
((
nch
==
1
)
||
(
nch
==
2
)
||
(
nch
==
4
))
&&
validate_name
(
CHILD
(
tree
,
0
),
"except"
));
if
(
res
&&
(
nch
>
1
))
res
=
validate_test
(
CHILD
(
tree
,
1
));
if
(
res
&&
(
nch
==
4
))
res
=
(
validate_name
(
CHILD
(
tree
,
2
),
"as"
)
&&
validate_ntype
(
CHILD
(
tree
,
3
),
NAME
));
return
(
res
);
}
static
int
validate_test
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_ntype
(
tree
,
test
)
&&
is_odd
(
nch
);
if
(
res
&&
(
TYPE
(
CHILD
(
tree
,
0
))
==
lambdef
))
res
=
((
nch
==
1
)
&&
validate_lambdef
(
CHILD
(
tree
,
0
)));
else
if
(
res
)
{
res
=
validate_or_test
(
CHILD
(
tree
,
0
));
res
=
(
res
&&
(
nch
==
1
||
(
nch
==
5
&&
validate_name
(
CHILD
(
tree
,
1
),
"if"
)
&&
validate_or_test
(
CHILD
(
tree
,
2
))
&&
validate_name
(
CHILD
(
tree
,
3
),
"else"
)
&&
validate_test
(
CHILD
(
tree
,
4
)))));
}
return
(
res
);
}
static
int
validate_test_nocond
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_ntype
(
tree
,
test_nocond
)
&&
(
nch
==
1
);
if
(
res
&&
(
TYPE
(
CHILD
(
tree
,
0
))
==
lambdef_nocond
))
res
=
(
validate_lambdef_nocond
(
CHILD
(
tree
,
0
)));
else
if
(
res
)
{
res
=
(
validate_or_test
(
CHILD
(
tree
,
0
)));
}
return
(
res
);
}
static
int
validate_or_test
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_ntype
(
tree
,
or_test
)
&&
is_odd
(
nch
);
if
(
res
)
{
int
pos
;
res
=
validate_and_test
(
CHILD
(
tree
,
0
));
for
(
pos
=
1
;
res
&&
(
pos
<
nch
);
pos
+=
2
)
res
=
(
validate_name
(
CHILD
(
tree
,
pos
),
"or"
)
&&
validate_and_test
(
CHILD
(
tree
,
pos
+
1
)));
}
return
(
res
);
}
static
int
validate_and_test
(
node
*
tree
)
{
int
pos
;
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
and_test
)
&&
is_odd
(
nch
)
&&
validate_not_test
(
CHILD
(
tree
,
0
)));
for
(
pos
=
1
;
res
&&
(
pos
<
nch
);
pos
+=
2
)
res
=
(
validate_name
(
CHILD
(
tree
,
pos
),
"and"
)
&&
validate_not_test
(
CHILD
(
tree
,
0
)));
return
(
res
);
}
static
int
validate_not_test
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_ntype
(
tree
,
not_test
)
&&
((
nch
==
1
)
||
(
nch
==
2
));
if
(
res
)
{
if
(
nch
==
2
)
res
=
(
validate_name
(
CHILD
(
tree
,
0
),
"not"
)
&&
validate_not_test
(
CHILD
(
tree
,
1
)));
else
if
(
nch
==
1
)
res
=
validate_comparison
(
CHILD
(
tree
,
0
));
}
return
(
res
);
}
static
int
validate_comparison
(
node
*
tree
)
{
int
pos
;
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
comparison
)
&&
is_odd
(
nch
)
&&
validate_expr
(
CHILD
(
tree
,
0
)));
for
(
pos
=
1
;
res
&&
(
pos
<
nch
);
pos
+=
2
)
res
=
(
validate_comp_op
(
CHILD
(
tree
,
pos
))
&&
validate_expr
(
CHILD
(
tree
,
pos
+
1
)));
return
(
res
);
}
static
int
validate_comp_op
(
node
*
tree
)
{
int
res
=
0
;
int
nch
=
NCH
(
tree
);
if
(
!
validate_ntype
(
tree
,
comp_op
))
return
(
0
);
if
(
nch
==
1
)
{
/*
* Only child will be a terminal with a well-defined symbolic name
* or a NAME with a string of either 'is' or 'in'
*/
tree
=
CHILD
(
tree
,
0
);
switch
(
TYPE
(
tree
))
{
case
LESS
:
case
GREATER
:
case
EQEQUAL
:
case
EQUAL
:
case
LESSEQUAL
:
case
GREATEREQUAL
:
case
NOTEQUAL
:
res
=
1
;
break
;
case
NAME
:
res
=
((
strcmp
(
STR
(
tree
),
"in"
)
==
0
)
||
(
strcmp
(
STR
(
tree
),
"is"
)
==
0
));
if
(
!
res
)
{
PyErr_Format
(
parser_error
,
"illegal operator '%s'"
,
STR
(
tree
));
}
break
;
default:
err_string
(
"illegal comparison operator type"
);
break
;
}
}
else
if
((
res
=
validate_numnodes
(
tree
,
2
,
"comp_op"
))
!=
0
)
{
res
=
(
validate_ntype
(
CHILD
(
tree
,
0
),
NAME
)
&&
validate_ntype
(
CHILD
(
tree
,
1
),
NAME
)
&&
(((
strcmp
(
STR
(
CHILD
(
tree
,
0
)),
"is"
)
==
0
)
&&
(
strcmp
(
STR
(
CHILD
(
tree
,
1
)),
"not"
)
==
0
))
||
((
strcmp
(
STR
(
CHILD
(
tree
,
0
)),
"not"
)
==
0
)
&&
(
strcmp
(
STR
(
CHILD
(
tree
,
1
)),
"in"
)
==
0
))));
if
(
!
res
&&
!
PyErr_Occurred
())
err_string
(
"unknown comparison operator"
);
}
return
(
res
);
}
static
int
validate_star_expr
(
node
*
tree
)
{
int
res
=
validate_ntype
(
tree
,
star_expr
);
if
(
!
res
)
return
res
;
if
(
!
validate_numnodes
(
tree
,
2
,
"star_expr"
))
return
0
;
return
validate_ntype
(
CHILD
(
tree
,
0
),
STAR
)
&&
\
validate_expr
(
CHILD
(
tree
,
1
));
}
static
int
validate_expr
(
node
*
tree
)
{
int
j
;
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
expr
)
&&
is_odd
(
nch
)
&&
validate_xor_expr
(
CHILD
(
tree
,
0
)));
for
(
j
=
2
;
res
&&
(
j
<
nch
);
j
+=
2
)
res
=
(
validate_xor_expr
(
CHILD
(
tree
,
j
))
&&
validate_vbar
(
CHILD
(
tree
,
j
-
1
)));
return
(
res
);
}
static
int
validate_xor_expr
(
node
*
tree
)
{
int
j
;
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
xor_expr
)
&&
is_odd
(
nch
)
&&
validate_and_expr
(
CHILD
(
tree
,
0
)));
for
(
j
=
2
;
res
&&
(
j
<
nch
);
j
+=
2
)
res
=
(
validate_circumflex
(
CHILD
(
tree
,
j
-
1
))
&&
validate_and_expr
(
CHILD
(
tree
,
j
)));
return
(
res
);
}
static
int
validate_and_expr
(
node
*
tree
)
{
int
pos
;
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
and_expr
)
&&
is_odd
(
nch
)
&&
validate_shift_expr
(
CHILD
(
tree
,
0
)));
for
(
pos
=
1
;
res
&&
(
pos
<
nch
);
pos
+=
2
)
res
=
(
validate_ampersand
(
CHILD
(
tree
,
pos
))
&&
validate_shift_expr
(
CHILD
(
tree
,
pos
+
1
)));
return
(
res
);
}
static
int
validate_chain_two_ops
(
node
*
tree
,
int
(
*
termvalid
)(
node
*
),
int
op1
,
int
op2
)
{
int
pos
=
1
;
int
nch
=
NCH
(
tree
);
int
res
=
(
is_odd
(
nch
)
&&
(
*
termvalid
)(
CHILD
(
tree
,
0
)));
for
(
;
res
&&
(
pos
<
nch
);
pos
+=
2
)
{
if
(
TYPE
(
CHILD
(
tree
,
pos
))
!=
op1
)
res
=
validate_ntype
(
CHILD
(
tree
,
pos
),
op2
);
if
(
res
)
res
=
(
*
termvalid
)(
CHILD
(
tree
,
pos
+
1
));
}
return
(
res
);
}
static
int
validate_shift_expr
(
node
*
tree
)
{
return
(
validate_ntype
(
tree
,
shift_expr
)
&&
validate_chain_two_ops
(
tree
,
validate_arith_expr
,
LEFTSHIFT
,
RIGHTSHIFT
));
}
static
int
validate_arith_expr
(
node
*
tree
)
{
return
(
validate_ntype
(
tree
,
arith_expr
)
&&
validate_chain_two_ops
(
tree
,
validate_term
,
PLUS
,
MINUS
));
}
static
int
validate_term
(
node
*
tree
)
{
int
pos
=
1
;
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
term
)
&&
is_odd
(
nch
)
&&
validate_factor
(
CHILD
(
tree
,
0
)));
for
(
;
res
&&
(
pos
<
nch
);
pos
+=
2
)
res
=
(((
TYPE
(
CHILD
(
tree
,
pos
))
==
STAR
)
||
(
TYPE
(
CHILD
(
tree
,
pos
))
==
SLASH
)
||
(
TYPE
(
CHILD
(
tree
,
pos
))
==
DOUBLESLASH
)
||
(
TYPE
(
CHILD
(
tree
,
pos
))
==
PERCENT
))
&&
validate_factor
(
CHILD
(
tree
,
pos
+
1
)));
return
(
res
);
}
/* factor:
*
* factor: ('+'|'-'|'~') factor | power
*/
static
int
validate_factor
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
factor
)
&&
(((
nch
==
2
)
&&
((
TYPE
(
CHILD
(
tree
,
0
))
==
PLUS
)
||
(
TYPE
(
CHILD
(
tree
,
0
))
==
MINUS
)
||
(
TYPE
(
CHILD
(
tree
,
0
))
==
TILDE
))
&&
validate_factor
(
CHILD
(
tree
,
1
)))
||
((
nch
==
1
)
&&
validate_power
(
CHILD
(
tree
,
0
)))));
return
(
res
);
}
/* power:
*
* power: atom_expr trailer* ['**' factor]
*/
static
int
validate_power
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
power
)
&&
(
nch
>=
1
)
&&
validate_atom_expr
(
CHILD
(
tree
,
0
)));
if
(
nch
>
1
)
{
if
(
nch
!=
3
)
{
err_string
(
"illegal number of nodes for 'power'"
);
return
(
0
);
}
res
=
(
validate_doublestar
(
CHILD
(
tree
,
1
))
&&
validate_factor
(
CHILD
(
tree
,
2
)));
}
return
(
res
);
}
/* atom_expr:
*
* atom_expr: [AWAIT] atom trailer*
*/
static
int
validate_atom_expr
(
node
*
tree
)
{
int
start
=
0
;
int
nch
=
NCH
(
tree
);
int
res
;
int
pos
;
res
=
validate_ntype
(
tree
,
atom_expr
)
&&
(
nch
>=
1
);
if
(
!
res
)
{
return
(
res
);
}
if
(
TYPE
(
CHILD
(
tree
,
0
))
==
AWAIT
)
{
start
=
1
;
if
(
nch
<
2
)
{
err_string
(
"illegal number of nodes for 'atom_expr'"
);
return
(
0
);
}
}
res
=
validate_atom
(
CHILD
(
tree
,
start
));
if
(
res
)
{
pos
=
start
+
1
;
while
(
res
&&
(
pos
<
nch
)
&&
(
TYPE
(
CHILD
(
tree
,
pos
))
==
trailer
))
res
=
validate_trailer
(
CHILD
(
tree
,
pos
++
));
}
return
(
res
);
}
static
int
validate_atom
(
node
*
tree
)
{
int
pos
;
int
nch
=
NCH
(
tree
);
int
res
=
validate_ntype
(
tree
,
atom
);
if
(
res
&&
nch
<
1
)
res
=
validate_numnodes
(
tree
,
nch
+
1
,
"atom"
);
if
(
res
)
{
switch
(
TYPE
(
CHILD
(
tree
,
0
)))
{
case
LPAR
:
res
=
((
nch
<=
3
)
&&
(
validate_rparen
(
CHILD
(
tree
,
nch
-
1
))));
if
(
res
&&
(
nch
==
3
))
{
if
(
TYPE
(
CHILD
(
tree
,
1
))
==
yield_expr
)
res
=
validate_yield_expr
(
CHILD
(
tree
,
1
));
else
res
=
validate_testlist_comp
(
CHILD
(
tree
,
1
));
}
break
;
case
LSQB
:
if
(
nch
==
2
)
res
=
validate_ntype
(
CHILD
(
tree
,
1
),
RSQB
);
else
if
(
nch
==
3
)
res
=
(
validate_testlist_comp
(
CHILD
(
tree
,
1
))
&&
validate_ntype
(
CHILD
(
tree
,
2
),
RSQB
));
else
{
res
=
0
;
err_string
(
"illegal list display atom"
);
}
break
;
case
LBRACE
:
res
=
((
nch
<=
3
)
&&
validate_ntype
(
CHILD
(
tree
,
nch
-
1
),
RBRACE
));
if
(
res
&&
(
nch
==
3
))
res
=
validate_dictorsetmaker
(
CHILD
(
tree
,
1
));
break
;
case
NAME
:
case
NUMBER
:
case
ELLIPSIS
:
res
=
(
nch
==
1
);
break
;
case
STRING
:
for
(
pos
=
1
;
res
&&
(
pos
<
nch
);
++
pos
)
res
=
validate_ntype
(
CHILD
(
tree
,
pos
),
STRING
);
break
;
default:
res
=
0
;
break
;
}
}
return
(
res
);
}
/* testlist_comp:
* (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
*/
static
int
validate_testlist_comp
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
ok
;
if
(
nch
==
0
)
{
err_string
(
"missing child nodes of testlist_comp"
);
return
0
;
}
if
(
nch
==
2
&&
TYPE
(
CHILD
(
tree
,
1
))
==
comp_for
)
{
ok
=
(
validate_test
(
CHILD
(
tree
,
0
))
&&
validate_comp_for
(
CHILD
(
tree
,
1
)));
}
else
{
ok
=
validate_repeating_list
(
tree
,
testlist_comp
,
validate_test_or_star_expr
,
"testlist_comp"
);
}
return
ok
;
}
/* decorator:
* '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
*/
static
int
validate_decorator
(
node
*
tree
)
{
int
ok
;
int
nch
=
NCH
(
tree
);
ok
=
(
validate_ntype
(
tree
,
decorator
)
&&
(
nch
==
3
||
nch
==
5
||
nch
==
6
)
&&
validate_at
(
CHILD
(
tree
,
0
))
&&
validate_dotted_name
(
CHILD
(
tree
,
1
))
&&
validate_newline
(
RCHILD
(
tree
,
-
1
)));
if
(
ok
&&
nch
!=
3
)
{
ok
=
(
validate_lparen
(
CHILD
(
tree
,
2
))
&&
validate_rparen
(
RCHILD
(
tree
,
-
2
)));
if
(
ok
&&
nch
==
6
)
ok
=
validate_arglist
(
CHILD
(
tree
,
3
));
}
return
ok
;
}
/* decorators:
* decorator+
*/
static
int
validate_decorators
(
node
*
tree
)
{
int
i
,
nch
,
ok
;
nch
=
NCH
(
tree
);
ok
=
validate_ntype
(
tree
,
decorators
)
&&
nch
>=
1
;
for
(
i
=
0
;
ok
&&
i
<
nch
;
++
i
)
ok
=
validate_decorator
(
CHILD
(
tree
,
i
));
return
ok
;
}
/* with_item:
* test ['as' expr]
*/
static
int
validate_with_item
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
ok
=
(
validate_ntype
(
tree
,
with_item
)
&&
(
nch
==
1
||
nch
==
3
)
&&
validate_test
(
CHILD
(
tree
,
0
)));
if
(
ok
&&
nch
==
3
)
ok
=
(
validate_name
(
CHILD
(
tree
,
1
),
"as"
)
&&
validate_expr
(
CHILD
(
tree
,
2
)));
return
ok
;
}
/* with_stmt:
* 0 1 ... -2 -1
* 'with' with_item (',' with_item)* ':' suite
*/
static
int
validate_with_stmt
(
node
*
tree
)
{
int
i
;
int
nch
=
NCH
(
tree
);
int
ok
=
(
validate_ntype
(
tree
,
with_stmt
)
&&
(
nch
%
2
==
0
)
&&
validate_name
(
CHILD
(
tree
,
0
),
"with"
)
&&
validate_colon
(
RCHILD
(
tree
,
-
2
))
&&
validate_suite
(
RCHILD
(
tree
,
-
1
)));
for
(
i
=
1
;
ok
&&
i
<
nch
-
2
;
i
+=
2
)
ok
=
validate_with_item
(
CHILD
(
tree
,
i
));
return
ok
;
}
/* funcdef: 'def' NAME parameters ['->' test] ':' suite */
static
int
validate_funcdef
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_ntype
(
tree
,
funcdef
);
if
(
res
)
{
if
(
nch
==
5
)
{
res
=
(
validate_name
(
CHILD
(
tree
,
0
),
"def"
)
&&
validate_ntype
(
CHILD
(
tree
,
1
),
NAME
)
&&
validate_parameters
(
CHILD
(
tree
,
2
))
&&
validate_colon
(
CHILD
(
tree
,
3
))
&&
validate_suite
(
CHILD
(
tree
,
4
)));
}
else
if
(
nch
==
7
)
{
res
=
(
validate_name
(
CHILD
(
tree
,
0
),
"def"
)
&&
validate_ntype
(
CHILD
(
tree
,
1
),
NAME
)
&&
validate_parameters
(
CHILD
(
tree
,
2
))
&&
validate_rarrow
(
CHILD
(
tree
,
3
))
&&
validate_test
(
CHILD
(
tree
,
4
))
&&
validate_colon
(
CHILD
(
tree
,
5
))
&&
validate_suite
(
CHILD
(
tree
,
6
)));
}
else
{
res
=
0
;
err_string
(
"illegal number of children for funcdef"
);
}
}
return
res
;
}
/* async_funcdef: ASYNC funcdef */
static
int
validate_async_funcdef
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_ntype
(
tree
,
async_funcdef
);
if
(
res
)
{
if
(
nch
==
2
)
{
res
=
(
validate_ntype
(
CHILD
(
tree
,
0
),
ASYNC
)
&&
validate_funcdef
(
CHILD
(
tree
,
1
)));
}
else
{
res
=
0
;
err_string
(
"illegal number of children for async_funcdef"
);
}
}
return
res
;
}
/* async_stmt: ASYNC (funcdef | with_stmt | for_stmt) */
static
int
validate_async_stmt
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
async_stmt
)
&&
validate_ntype
(
CHILD
(
tree
,
0
),
ASYNC
));
if
(
nch
!=
2
)
{
res
=
0
;
err_string
(
"illegal number of children for async_stmt"
);
}
else
{
if
(
TYPE
(
CHILD
(
tree
,
1
))
==
funcdef
)
{
res
=
validate_funcdef
(
CHILD
(
tree
,
1
));
}
else
if
(
TYPE
(
CHILD
(
tree
,
1
))
==
with_stmt
)
{
res
=
validate_with_stmt
(
CHILD
(
tree
,
1
));
}
else
if
(
TYPE
(
CHILD
(
tree
,
1
))
==
for_stmt
)
{
res
=
validate_for
(
CHILD
(
tree
,
1
));
}
}
return
res
;
}
/* decorated
* decorators (classdef | funcdef)
*/
static
int
validate_decorated
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
ok
=
(
validate_ntype
(
tree
,
decorated
)
&&
(
nch
==
2
)
&&
validate_decorators
(
RCHILD
(
tree
,
-
2
)));
if
(
TYPE
(
RCHILD
(
tree
,
-
1
))
==
funcdef
)
ok
=
ok
&&
validate_funcdef
(
RCHILD
(
tree
,
-
1
));
else
ok
=
ok
&&
validate_class
(
RCHILD
(
tree
,
-
1
));
return
ok
;
}
static
int
validate_lambdef
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
lambdef
)
&&
((
nch
==
3
)
||
(
nch
==
4
))
&&
validate_name
(
CHILD
(
tree
,
0
),
"lambda"
)
&&
validate_colon
(
CHILD
(
tree
,
nch
-
2
))
&&
validate_test
(
CHILD
(
tree
,
nch
-
1
)));
if
(
res
&&
(
nch
==
4
))
res
=
validate_varargslist
(
CHILD
(
tree
,
1
));
else
if
(
!
res
&&
!
PyErr_Occurred
())
(
void
)
validate_numnodes
(
tree
,
3
,
"lambdef"
);
return
(
res
);
}
static
int
validate_lambdef_nocond
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
lambdef_nocond
)
&&
((
nch
==
3
)
||
(
nch
==
4
))
&&
validate_name
(
CHILD
(
tree
,
0
),
"lambda"
)
&&
validate_colon
(
CHILD
(
tree
,
nch
-
2
))
&&
validate_test
(
CHILD
(
tree
,
nch
-
1
)));
if
(
res
&&
(
nch
==
4
))
res
=
validate_varargslist
(
CHILD
(
tree
,
1
));
else
if
(
!
res
&&
!
PyErr_Occurred
())
(
void
)
validate_numnodes
(
tree
,
3
,
"lambdef_nocond"
);
return
(
res
);
}
/* arglist:
*
* (argument ',')* (argument [','] | '*' test [',' '**' test] | '**' test)
*/
static
int
validate_arglist
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
i
=
0
;
int
ok
=
1
;
if
(
nch
<=
0
)
/* raise the right error from having an invalid number of children */
return
validate_numnodes
(
tree
,
nch
+
1
,
"arglist"
);
if
(
nch
>
1
)
{
for
(
i
=
0
;
i
<
nch
;
i
++
)
{
if
(
TYPE
(
CHILD
(
tree
,
i
))
==
argument
)
{
node
*
ch
=
CHILD
(
tree
,
i
);
if
(
NCH
(
ch
)
==
2
&&
TYPE
(
CHILD
(
ch
,
1
))
==
comp_for
)
{
err_string
(
"need '(', ')' for generator expression"
);
return
0
;
}
}
}
}
while
(
ok
&&
nch
-
i
>=
2
)
{
/* skip leading (argument ',') */
ok
=
(
validate_argument
(
CHILD
(
tree
,
i
))
&&
validate_comma
(
CHILD
(
tree
,
i
+
1
)));
if
(
ok
)
i
+=
2
;
else
PyErr_Clear
();
}
ok
=
1
;
if
(
nch
-
i
>
0
)
{
int
sym
=
TYPE
(
CHILD
(
tree
,
i
));
if
(
sym
==
argument
)
{
ok
=
validate_argument
(
CHILD
(
tree
,
i
));
if
(
ok
&&
i
+
1
!=
nch
)
{
err_string
(
"illegal arglist specification"
" (extra stuff on end)"
);
ok
=
0
;
}
}
else
{
err_string
(
"illegal arglist specification"
);
ok
=
0
;
}
}
return
(
ok
);
}
/* argument: ( test [comp_for] |
* test '=' test |
* '**' test |
* '*' test )
*/
static
int
validate_argument
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
argument
)
&&
((
nch
==
1
)
||
(
nch
==
2
)
||
(
nch
==
3
)));
if
(
res
)
{
if
(
TYPE
(
CHILD
(
tree
,
0
))
==
DOUBLESTAR
)
{
res
=
validate_test
(
CHILD
(
tree
,
1
));
}
else
if
(
TYPE
(
CHILD
(
tree
,
0
))
==
STAR
)
{
res
=
validate_test
(
CHILD
(
tree
,
1
));
}
else
if
(
nch
==
1
)
{
res
=
validate_test
(
CHILD
(
tree
,
0
));
}
else
if
(
nch
==
2
)
{
res
=
(
validate_test
(
CHILD
(
tree
,
0
))
&&
validate_comp_for
(
CHILD
(
tree
,
1
)));
}
else
if
(
res
&&
(
nch
==
3
))
{
res
=
(
validate_test
(
CHILD
(
tree
,
0
))
&&
validate_equal
(
CHILD
(
tree
,
1
))
&&
validate_test
(
CHILD
(
tree
,
2
)));
}
}
return
(
res
);
}
/* trailer:
*
* '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
*/
static
int
validate_trailer
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
validate_ntype
(
tree
,
trailer
)
&&
((
nch
==
2
)
||
(
nch
==
3
));
if
(
res
)
{
switch
(
TYPE
(
CHILD
(
tree
,
0
)))
{
case
LPAR
:
res
=
validate_rparen
(
CHILD
(
tree
,
nch
-
1
));
if
(
res
&&
(
nch
==
3
))
res
=
validate_arglist
(
CHILD
(
tree
,
1
));
break
;
case
LSQB
:
res
=
(
validate_numnodes
(
tree
,
3
,
"trailer"
)
&&
validate_subscriptlist
(
CHILD
(
tree
,
1
))
&&
validate_ntype
(
CHILD
(
tree
,
2
),
RSQB
));
break
;
case
DOT
:
res
=
(
validate_numnodes
(
tree
,
2
,
"trailer"
)
&&
validate_ntype
(
CHILD
(
tree
,
1
),
NAME
));
break
;
default:
res
=
0
;
break
;
}
}
else
{
(
void
)
validate_numnodes
(
tree
,
2
,
"trailer"
);
}
return
(
res
);
}
/* subscriptlist:
*
* subscript (',' subscript)* [',']
*/
static
int
validate_subscriptlist
(
node
*
tree
)
{
return
(
validate_repeating_list
(
tree
,
subscriptlist
,
validate_subscript
,
"subscriptlist"
));
}
/* subscript:
*
* '.' '.' '.' | test | [test] ':' [test] [sliceop]
*/
static
int
validate_subscript
(
node
*
tree
)
{
int
offset
=
0
;
int
nch
=
NCH
(
tree
);
int
res
=
validate_ntype
(
tree
,
subscript
)
&&
(
nch
>=
1
)
&&
(
nch
<=
4
);
if
(
!
res
)
{
if
(
!
PyErr_Occurred
())
err_string
(
"invalid number of arguments for subscript node"
);
return
(
0
);
}
if
(
TYPE
(
CHILD
(
tree
,
0
))
==
DOT
)
/* take care of ('.' '.' '.') possibility */
return
(
validate_numnodes
(
tree
,
3
,
"subscript"
)
&&
validate_dot
(
CHILD
(
tree
,
0
))
&&
validate_dot
(
CHILD
(
tree
,
1
))
&&
validate_dot
(
CHILD
(
tree
,
2
)));
if
(
nch
==
1
)
{
if
(
TYPE
(
CHILD
(
tree
,
0
))
==
test
)
res
=
validate_test
(
CHILD
(
tree
,
0
));
else
res
=
validate_colon
(
CHILD
(
tree
,
0
));
return
(
res
);
}
/* Must be [test] ':' [test] [sliceop],
* but at least one of the optional components will
* be present, but we don't know which yet.
*/
if
((
TYPE
(
CHILD
(
tree
,
0
))
!=
COLON
)
||
(
nch
==
4
))
{
res
=
validate_test
(
CHILD
(
tree
,
0
));
offset
=
1
;
}
if
(
res
)
res
=
validate_colon
(
CHILD
(
tree
,
offset
));
if
(
res
)
{
int
rem
=
nch
-
++
offset
;
if
(
rem
)
{
if
(
TYPE
(
CHILD
(
tree
,
offset
))
==
test
)
{
res
=
validate_test
(
CHILD
(
tree
,
offset
));
++
offset
;
--
rem
;
}
if
(
res
&&
rem
)
res
=
validate_sliceop
(
CHILD
(
tree
,
offset
));
}
}
return
(
res
);
}
static
int
validate_sliceop
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
((
nch
==
1
)
||
validate_numnodes
(
tree
,
2
,
"sliceop"
))
&&
validate_ntype
(
tree
,
sliceop
);
if
(
!
res
&&
!
PyErr_Occurred
())
{
res
=
validate_numnodes
(
tree
,
1
,
"sliceop"
);
}
if
(
res
)
res
=
validate_colon
(
CHILD
(
tree
,
0
));
if
(
res
&&
(
nch
==
2
))
res
=
validate_test
(
CHILD
(
tree
,
1
));
return
(
res
);
}
static
int
validate_test_or_star_expr
(
node
*
n
)
{
if
(
TYPE
(
n
)
==
test
)
return
validate_test
(
n
);
return
validate_star_expr
(
n
);
}
static
int
validate_expr_or_star_expr
(
node
*
n
)
{
if
(
TYPE
(
n
)
==
expr
)
return
validate_expr
(
n
);
return
validate_star_expr
(
n
);
}
static
int
validate_exprlist
(
node
*
tree
)
{
return
(
validate_repeating_list
(
tree
,
exprlist
,
validate_expr_or_star_expr
,
"exprlist"
));
}
/* Incrementing validate functions returns nonzero iff success (like other
* validate functions, and advance *i by the length of the matched pattern. */
/* test ':' test */
static
int
validate_test_colon_test_inc
(
node
*
tree
,
int
*
i
)
{
return
(
validate_test
(
CHILD
(
tree
,
(
*
i
)
++
))
&&
validate_colon
(
CHILD
(
tree
,
(
*
i
)
++
))
&&
validate_test
(
CHILD
(
tree
,
(
*
i
)
++
)));
}
/* test ':' test | '**' expr */
static
int
validate_dict_element_inc
(
node
*
tree
,
int
*
i
)
{
int
nch
=
NCH
(
tree
);
int
res
=
0
;
if
(
nch
-
*
i
>=
2
)
{
if
(
TYPE
(
CHILD
(
tree
,
*
i
+
1
))
==
COLON
)
{
/* test ':' test */
res
=
validate_test_colon_test_inc
(
tree
,
i
);
}
else
{
/* '**' expr */
res
=
(
validate_doublestar
(
CHILD
(
tree
,
(
*
i
)
++
))
&&
validate_expr
(
CHILD
(
tree
,
(
*
i
)
++
)));
}
}
return
res
;
}
/*
* dictorsetmaker:
*
* ( ((test ':' test | '**' expr)
* (comp_for | (',' (test ':' test | '**' expr))* [','])) |
* ((test | '*' test)
* (comp_for | (',' (test | '*' test))* [','])) )
*/
static
int
validate_dictorsetmaker
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
;
int
i
=
0
;
res
=
validate_ntype
(
tree
,
dictorsetmaker
);
if
(
!
res
)
return
0
;
if
(
nch
-
i
<
1
)
{
/* Unconditionally raise. */
(
void
)
validate_numnodes
(
tree
,
1
,
"dictorsetmaker"
);
return
0
;
}
if
(
nch
-
i
>=
2
&&
((
TYPE
(
CHILD
(
tree
,
i
+
1
))
==
COLON
)
||
(
TYPE
(
CHILD
(
tree
,
i
))
==
DOUBLESTAR
)))
{
/* Dictionary display or dictionary comprehension. */
if
(
nch
-
i
>=
4
&&
TYPE
(
CHILD
(
tree
,
i
+
3
))
==
comp_for
)
{
/* Dictionary comprehension. */
res
=
(
validate_test_colon_test_inc
(
tree
,
&
i
)
&&
validate_comp_for
(
CHILD
(
tree
,
i
++
)));
if
(
!
res
)
return
0
;
}
else
{
/* Dictionary display. */
return
validate_repeating_list_variable
(
tree
,
dictorsetmaker
,
validate_dict_element_inc
,
&
i
,
"dictorsetmaker"
);
}
}
else
{
/* Set display or set comprehension. */
if
(
nch
-
i
>=
2
&&
TYPE
(
CHILD
(
tree
,
i
+
1
))
==
comp_for
)
{
/* Set comprehension. */
res
=
(
validate_test
(
CHILD
(
tree
,
i
++
))
&&
validate_comp_for
(
CHILD
(
tree
,
i
++
)));
if
(
!
res
)
return
0
;
}
else
{
/* Set display. */
return
validate_repeating_list
(
tree
,
dictorsetmaker
,
validate_test_or_star_expr
,
"dictorsetmaker"
);
}
}
if
(
nch
-
i
>
0
)
{
err_string
(
"Illegal trailing nodes for dictorsetmaker."
);
return
0
;
}
return
1
;
}
static
int
validate_eval_input
(
node
*
tree
)
{
int
pos
;
int
nch
=
NCH
(
tree
);
int
res
=
(
validate_ntype
(
tree
,
eval_input
)
&&
(
nch
>=
2
)
&&
validate_testlist
(
CHILD
(
tree
,
0
))
&&
validate_ntype
(
CHILD
(
tree
,
nch
-
1
),
ENDMARKER
));
for
(
pos
=
1
;
res
&&
(
pos
<
(
nch
-
1
));
++
pos
)
res
=
validate_ntype
(
CHILD
(
tree
,
pos
),
NEWLINE
);
return
(
res
);
}
static
int
validate_node
(
node
*
tree
)
{
int
nch
=
0
;
/* num. children on current node */
int
res
=
1
;
/* result value */
node
*
next
=
0
;
/* node to process after this one */
while
(
res
&&
(
tree
!=
0
))
{
nch
=
NCH
(
tree
);
next
=
0
;
switch
(
TYPE
(
tree
))
{
/*
* Definition nodes.
*/
case
async_funcdef
:
res
=
validate_async_funcdef
(
tree
);
break
;
case
async_stmt
:
res
=
validate_async_stmt
(
tree
);
break
;
case
funcdef
:
res
=
validate_funcdef
(
tree
);
break
;
case
with_stmt
:
res
=
validate_with_stmt
(
tree
);
break
;
case
classdef
:
res
=
validate_class
(
tree
);
break
;
case
decorated
:
res
=
validate_decorated
(
tree
);
break
;
/*
* "Trivial" parse tree nodes.
* (Why did I call these trivial?)
*/
case
stmt
:
res
=
validate_stmt
(
tree
);
break
;
case
small_stmt
:
/*
* expr_stmt | del_stmt | pass_stmt | flow_stmt |
* import_stmt | global_stmt | nonlocal_stmt | assert_stmt
*/
res
=
validate_small_stmt
(
tree
);
break
;
case
flow_stmt
:
res
=
(
validate_numnodes
(
tree
,
1
,
"flow_stmt"
)
&&
((
TYPE
(
CHILD
(
tree
,
0
))
==
break_stmt
)
||
(
TYPE
(
CHILD
(
tree
,
0
))
==
continue_stmt
)
||
(
TYPE
(
CHILD
(
tree
,
0
))
==
yield_stmt
)
||
(
TYPE
(
CHILD
(
tree
,
0
))
==
return_stmt
)
||
(
TYPE
(
CHILD
(
tree
,
0
))
==
raise_stmt
)));
if
(
res
)
next
=
CHILD
(
tree
,
0
);
else
if
(
nch
==
1
)
err_string
(
"illegal flow_stmt type"
);
break
;
case
yield_stmt
:
res
=
validate_yield_stmt
(
tree
);
break
;
/*
* Compound statements.
*/
case
simple_stmt
:
res
=
validate_simple_stmt
(
tree
);
break
;
case
compound_stmt
:
res
=
validate_compound_stmt
(
tree
);
break
;
/*
* Fundamental statements.
*/
case
expr_stmt
:
res
=
validate_expr_stmt
(
tree
);
break
;
case
del_stmt
:
res
=
validate_del_stmt
(
tree
);
break
;
case
pass_stmt
:
res
=
(
validate_numnodes
(
tree
,
1
,
"pass"
)
&&
validate_name
(
CHILD
(
tree
,
0
),
"pass"
));
break
;
case
break_stmt
:
res
=
(
validate_numnodes
(
tree
,
1
,
"break"
)
&&
validate_name
(
CHILD
(
tree
,
0
),
"break"
));
break
;
case
continue_stmt
:
res
=
(
validate_numnodes
(
tree
,
1
,
"continue"
)
&&
validate_name
(
CHILD
(
tree
,
0
),
"continue"
));
break
;
case
return_stmt
:
res
=
validate_return_stmt
(
tree
);
break
;
case
raise_stmt
:
res
=
validate_raise_stmt
(
tree
);
break
;
case
import_stmt
:
res
=
validate_import_stmt
(
tree
);
break
;
case
import_name
:
res
=
validate_import_name
(
tree
);
break
;
case
import_from
:
res
=
validate_import_from
(
tree
);
break
;
case
global_stmt
:
res
=
validate_global_stmt
(
tree
);
break
;
case
nonlocal_stmt
:
res
=
validate_nonlocal_stmt
(
tree
);
break
;
case
assert_stmt
:
res
=
validate_assert_stmt
(
tree
);
break
;
case
if_stmt
:
res
=
validate_if
(
tree
);
break
;
case
while_stmt
:
res
=
validate_while
(
tree
);
break
;
case
for_stmt
:
res
=
validate_for
(
tree
);
break
;
case
try_stmt
:
res
=
validate_try
(
tree
);
break
;
case
suite
:
res
=
validate_suite
(
tree
);
break
;
/*
* Expression nodes.
*/
case
testlist
:
res
=
validate_testlist
(
tree
);
break
;
case
yield_expr
:
res
=
validate_yield_expr
(
tree
);
break
;
case
test
:
res
=
validate_test
(
tree
);
break
;
case
and_test
:
res
=
validate_and_test
(
tree
);
break
;
case
not_test
:
res
=
validate_not_test
(
tree
);
break
;
case
comparison
:
res
=
validate_comparison
(
tree
);
break
;
case
exprlist
:
res
=
validate_exprlist
(
tree
);
break
;
case
comp_op
:
res
=
validate_comp_op
(
tree
);
break
;
case
expr
:
res
=
validate_expr
(
tree
);
break
;
case
xor_expr
:
res
=
validate_xor_expr
(
tree
);
break
;
case
and_expr
:
res
=
validate_and_expr
(
tree
);
break
;
case
shift_expr
:
res
=
validate_shift_expr
(
tree
);
break
;
case
arith_expr
:
res
=
validate_arith_expr
(
tree
);
break
;
case
term
:
res
=
validate_term
(
tree
);
break
;
case
factor
:
res
=
validate_factor
(
tree
);
break
;
case
power
:
res
=
validate_power
(
tree
);
break
;
case
atom
:
res
=
validate_atom
(
tree
);
break
;
default:
/* Hopefully never reached! */
err_string
(
"unrecognized node type"
);
res
=
0
;
break
;
}
tree
=
next
;
}
return
(
res
);
}
static
int
validate_expr_tree
(
node
*
tree
)
{
int
res
=
validate_eval_input
(
tree
);
if
(
!
res
&&
!
PyErr_Occurred
())
err_string
(
"could not validate expression tuple"
);
return
(
res
);
}
/* file_input:
* (NEWLINE | stmt)* ENDMARKER
*/
static
int
validate_file_input
(
node
*
tree
)
{
int
j
;
int
nch
=
NCH
(
tree
)
-
1
;
int
res
=
((
nch
>=
0
)
&&
validate_ntype
(
CHILD
(
tree
,
nch
),
ENDMARKER
));
for
(
j
=
0
;
res
&&
(
j
<
nch
);
++
j
)
{
if
(
TYPE
(
CHILD
(
tree
,
j
))
==
stmt
)
res
=
validate_stmt
(
CHILD
(
tree
,
j
));
else
res
=
validate_newline
(
CHILD
(
tree
,
j
));
}
/* This stays in to prevent any internal failures from getting to the
* user. Hopefully, this won't be needed. If a user reports getting
* this, we have some debugging to do.
*/
if
(
!
res
&&
!
PyErr_Occurred
())
err_string
(
"VALIDATION FAILURE: report this to the maintainer!"
);
return
(
res
);
}
static
int
validate_encoding_decl
(
node
*
tree
)
{
int
nch
=
NCH
(
tree
);
int
res
=
((
nch
==
1
)
&&
validate_file_input
(
CHILD
(
tree
,
0
)));
if
(
!
res
&&
!
PyErr_Occurred
())
err_string
(
"Error Parsing encoding_decl"
);
return
res
;
}
static
PyObject
*
pickle_constructor
=
NULL
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment