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
572bdce4
Commit
572bdce4
authored
Sep 20, 2000
by
Jeremy Hylton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
change 2-space indent to 4-space indent
parent
9c36a416
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
2158 additions
and
2162 deletions
+2158
-2162
Lib/compiler/transformer.py
Lib/compiler/transformer.py
+1079
-1081
Tools/compiler/compiler/transformer.py
Tools/compiler/compiler/transformer.py
+1079
-1081
No files found.
Lib/compiler/transformer.py
View file @
572bdce4
...
...
@@ -118,1135 +118,1133 @@ def parse(buf):
return
Transformer
().
parsesuite
(
buf
)
def
asList
(
nodes
):
l
=
[]
for
item
in
nodes
:
if
hasattr
(
item
,
"asList"
):
l
.
append
(
item
.
asList
())
else
:
if
type
(
item
)
is
type
(
(
None
,
None
)
):
l
.
append
(
tuple
(
asList
(
item
)))
elif
type
(
item
)
is
type
(
[]
):
l
.
append
(
asList
(
item
))
else
:
l
.
append
(
item
)
return
l
l
=
[]
for
item
in
nodes
:
if
hasattr
(
item
,
"asList"
):
l
.
append
(
item
.
asList
())
else
:
if
type
(
item
)
is
type
(
(
None
,
None
)
):
l
.
append
(
tuple
(
asList
(
item
)))
elif
type
(
item
)
is
type
(
[]
):
l
.
append
(
asList
(
item
))
else
:
l
.
append
(
item
)
return
l
def
Node
(
*
args
):
kind
=
args
[
0
]
if
ast
.
nodes
.
has_key
(
kind
):
try
:
return
apply
(
ast
.
nodes
[
kind
],
args
[
1
:])
except
TypeError
:
print
ast
.
nodes
[
kind
],
len
(
args
),
args
raise
else
:
raise
error
,
"Can't find appropriate Node type."
#return apply(ast.Node, args)
kind
=
args
[
0
]
if
ast
.
nodes
.
has_key
(
kind
):
try
:
return
apply
(
ast
.
nodes
[
kind
],
args
[
1
:])
except
TypeError
:
print
ast
.
nodes
[
kind
],
len
(
args
),
args
raise
else
:
raise
error
,
"Can't find appropriate Node type."
#return apply(ast.Node, args)
class
Transformer
:
"""Utility object for transforming Python parse trees.
Exposes the following methods:
tree = transform(ast_tree)
tree = parsesuite(text)
tree = parseexpr(text)
tree = parsefile(fileob | filename)
"""
def
__init__
(
self
):
self
.
_dispatch
=
{
}
for
value
,
name
in
symbol
.
sym_name
.
items
():
if
hasattr
(
self
,
name
):
self
.
_dispatch
[
value
]
=
getattr
(
self
,
name
)
def
transform
(
self
,
tree
):
"""Transform an AST into a modified parse tree."""
if
type
(
tree
)
!=
type
(())
and
type
(
tree
)
!=
type
([]):
tree
=
parser
.
ast2tuple
(
tree
,
1
)
return
self
.
compile_node
(
tree
)
def
parsesuite
(
self
,
text
):
"""Return a modified parse tree for the given suite text."""
# Hack for handling non-native line endings on non-DOS like OSs.
text
=
string
.
replace
(
text
,
'
\
x0d
'
,
''
)
return
self
.
transform
(
parser
.
suite
(
text
))
def
parseexpr
(
self
,
text
):
"""Return a modified parse tree for the given expression text."""
return
self
.
transform
(
parser
.
expr
(
text
))
def
parsefile
(
self
,
file
):
"""Return a modified parse tree for the contents of the given file."""
if
type
(
file
)
==
type
(
''
):
file
=
open
(
file
)
return
self
.
parsesuite
(
file
.
read
())
# --------------------------------------------------------------
#
# PRIVATE METHODS
#
def
compile_node
(
self
,
node
):
### emit a line-number node?
n
=
node
[
0
]
if
n
==
symbol
.
single_input
:
return
self
.
single_input
(
node
[
1
:])
if
n
==
symbol
.
file_input
:
return
self
.
file_input
(
node
[
1
:])
if
n
==
symbol
.
eval_input
:
return
self
.
eval_input
(
node
[
1
:])
if
n
==
symbol
.
lambdef
:
return
self
.
lambdef
(
node
[
1
:])
if
n
==
symbol
.
funcdef
:
return
self
.
funcdef
(
node
[
1
:])
if
n
==
symbol
.
classdef
:
return
self
.
classdef
(
node
[
1
:])
raise
error
,
(
'unexpected node type'
,
n
)
def
single_input
(
self
,
node
):
### do we want to do anything about being "interactive" ?
# NEWLINE | simple_stmt | compound_stmt NEWLINE
n
=
node
[
0
][
0
]
if
n
!=
token
.
NEWLINE
:
return
self
.
com_stmt
(
node
[
0
])
return
Node
(
'pass'
)
def
file_input
(
self
,
nodelist
):
doc
=
self
.
get_docstring
(
nodelist
,
symbol
.
file_input
)
stmts
=
[
]
for
node
in
nodelist
:
if
node
[
0
]
!=
token
.
ENDMARKER
and
node
[
0
]
!=
token
.
NEWLINE
:
self
.
com_append_stmt
(
stmts
,
node
)
return
Node
(
'module'
,
doc
,
Node
(
'stmt'
,
stmts
))
def
eval_input
(
self
,
nodelist
):
# from the built-in function input()
### is this sufficient?
return
self
.
com_node
(
nodelist
[
0
])
def
funcdef
(
self
,
nodelist
):
# funcdef: 'def' NAME parameters ':' suite
# parameters: '(' [varargslist] ')'
lineno
=
nodelist
[
1
][
2
]
name
=
nodelist
[
1
][
1
]
args
=
nodelist
[
2
][
2
]
if
args
[
0
]
==
symbol
.
varargslist
:
names
,
defaults
,
flags
=
self
.
com_arglist
(
args
[
1
:])
else
:
names
=
defaults
=
()
flags
=
0
doc
=
self
.
get_docstring
(
nodelist
[
4
])
"""Utility object for transforming Python parse trees.
Exposes the following methods:
tree = transform(ast_tree)
tree = parsesuite(text)
tree = parseexpr(text)
tree = parsefile(fileob | filename)
"""
def
__init__
(
self
):
self
.
_dispatch
=
{
}
for
value
,
name
in
symbol
.
sym_name
.
items
():
if
hasattr
(
self
,
name
):
self
.
_dispatch
[
value
]
=
getattr
(
self
,
name
)
def
transform
(
self
,
tree
):
"""Transform an AST into a modified parse tree."""
if
type
(
tree
)
!=
type
(())
and
type
(
tree
)
!=
type
([]):
tree
=
parser
.
ast2tuple
(
tree
,
1
)
return
self
.
compile_node
(
tree
)
def
parsesuite
(
self
,
text
):
"""Return a modified parse tree for the given suite text."""
# Hack for handling non-native line endings on non-DOS like OSs.
text
=
string
.
replace
(
text
,
'
\
x0d
'
,
''
)
return
self
.
transform
(
parser
.
suite
(
text
))
def
parseexpr
(
self
,
text
):
"""Return a modified parse tree for the given expression text."""
return
self
.
transform
(
parser
.
expr
(
text
))
def
parsefile
(
self
,
file
):
"""Return a modified parse tree for the contents of the given file."""
if
type
(
file
)
==
type
(
''
):
file
=
open
(
file
)
return
self
.
parsesuite
(
file
.
read
())
# --------------------------------------------------------------
#
# PRIVATE METHODS
#
# code for function
code
=
self
.
com_node
(
nodelist
[
4
])
def
compile_node
(
self
,
node
):
### emit a line-number node?
n
=
node
[
0
]
if
n
==
symbol
.
single_input
:
return
self
.
single_input
(
node
[
1
:])
if
n
==
symbol
.
file_input
:
return
self
.
file_input
(
node
[
1
:])
if
n
==
symbol
.
eval_input
:
return
self
.
eval_input
(
node
[
1
:])
if
n
==
symbol
.
lambdef
:
return
self
.
lambdef
(
node
[
1
:])
if
n
==
symbol
.
funcdef
:
return
self
.
funcdef
(
node
[
1
:])
if
n
==
symbol
.
classdef
:
return
self
.
classdef
(
node
[
1
:])
raise
error
,
(
'unexpected node type'
,
n
)
def
single_input
(
self
,
node
):
### do we want to do anything about being "interactive" ?
# NEWLINE | simple_stmt | compound_stmt NEWLINE
n
=
node
[
0
][
0
]
if
n
!=
token
.
NEWLINE
:
return
self
.
com_stmt
(
node
[
0
])
return
Node
(
'pass'
)
def
file_input
(
self
,
nodelist
):
doc
=
self
.
get_docstring
(
nodelist
,
symbol
.
file_input
)
stmts
=
[
]
for
node
in
nodelist
:
if
node
[
0
]
!=
token
.
ENDMARKER
and
node
[
0
]
!=
token
.
NEWLINE
:
self
.
com_append_stmt
(
stmts
,
node
)
return
Node
(
'module'
,
doc
,
Node
(
'stmt'
,
stmts
))
def
eval_input
(
self
,
nodelist
):
# from the built-in function input()
### is this sufficient?
return
self
.
com_node
(
nodelist
[
0
])
def
funcdef
(
self
,
nodelist
):
# funcdef: 'def' NAME parameters ':' suite
# parameters: '(' [varargslist] ')'
lineno
=
nodelist
[
1
][
2
]
name
=
nodelist
[
1
][
1
]
args
=
nodelist
[
2
][
2
]
if
args
[
0
]
==
symbol
.
varargslist
:
names
,
defaults
,
flags
=
self
.
com_arglist
(
args
[
1
:])
else
:
names
=
defaults
=
()
flags
=
0
doc
=
self
.
get_docstring
(
nodelist
[
4
])
n
=
Node
(
'function'
,
name
,
names
,
defaults
,
flags
,
doc
,
code
)
n
.
lineno
=
lineno
return
n
# code for function
code
=
self
.
com_node
(
nodelist
[
4
])
def
lambdef
(
self
,
nodelist
):
# lambdef: 'lambda' [varargslist] ':' test
if
nodelist
[
2
][
0
]
==
symbol
.
varargslist
:
names
,
defaults
,
flags
=
self
.
com_arglist
(
nodelist
[
2
][
1
:])
else
:
names
=
defaults
=
()
flags
=
0
n
=
Node
(
'function'
,
name
,
names
,
defaults
,
flags
,
doc
,
code
)
n
.
lineno
=
lineno
return
n
# code for lambda
code
=
self
.
com_node
(
nodelist
[
-
1
])
def
lambdef
(
self
,
nodelist
):
# lambdef: 'lambda' [varargslist] ':' test
if
nodelist
[
2
][
0
]
==
symbol
.
varargslist
:
names
,
defaults
,
flags
=
self
.
com_arglist
(
nodelist
[
2
][
1
:])
else
:
names
=
defaults
=
()
flags
=
0
n
=
Node
(
'lambda'
,
names
,
defaults
,
flags
,
code
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
# code for lambda
code
=
self
.
com_node
(
nodelist
[
-
1
])
def
classdef
(
self
,
nodelist
):
# classdef: 'class' NAME ['(' testlist ')'] ':' suite
n
=
Node
(
'lambda'
,
names
,
defaults
,
flags
,
code
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
name
=
nodelist
[
1
][
1
]
doc
=
self
.
get_docstring
(
nodelist
[
-
1
])
if
nodelist
[
2
][
0
]
==
token
.
COLON
:
bases
=
[]
else
:
bases
=
self
.
com_bases
(
nodelist
[
3
])
# code for class
code
=
self
.
com_node
(
nodelist
[
-
1
])
n
=
Node
(
'class'
,
name
,
bases
,
doc
,
code
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
def
stmt
(
self
,
nodelist
):
return
self
.
com_stmt
(
nodelist
[
0
])
small_stmt
=
stmt
flow_stmt
=
stmt
compound_stmt
=
stmt
def
simple_stmt
(
self
,
nodelist
):
# small_stmt (';' small_stmt)* [';'] NEWLINE
stmts
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
),
2
):
self
.
com_append_stmt
(
stmts
,
nodelist
[
i
])
return
Node
(
'stmt'
,
stmts
)
def
parameters
(
self
,
nodelist
):
raise
error
def
varargslist
(
self
,
nodelist
):
raise
error
def
fpdef
(
self
,
nodelist
):
raise
error
def
fplist
(
self
,
nodelist
):
raise
error
def
dotted_name
(
self
,
nodelist
):
raise
error
def
comp_op
(
self
,
nodelist
):
raise
error
def
trailer
(
self
,
nodelist
):
raise
error
def
sliceop
(
self
,
nodelist
):
raise
error
def
argument
(
self
,
nodelist
):
raise
error
# --------------------------------------------------------------
#
# STATEMENT NODES (invoked by com_node())
#
def
expr_stmt
(
self
,
nodelist
):
# testlist ('=' testlist)*
exprNode
=
self
.
com_node
(
nodelist
[
-
1
])
if
len
(
nodelist
)
==
1
:
return
Node
(
'discard'
,
exprNode
)
nodes
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
)
-
2
,
2
):
nodes
.
append
(
self
.
com_assign
(
nodelist
[
i
],
OP_ASSIGN
))
n
=
Node
(
'assign'
,
nodes
,
exprNode
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
def
print_stmt
(
self
,
nodelist
):
# print: (test ',')* [test]
items
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
items
.
append
(
self
.
com_node
(
nodelist
[
i
]))
if
nodelist
[
-
1
][
0
]
==
token
.
COMMA
:
n
=
Node
(
'print'
,
items
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
n
=
Node
(
'printnl'
,
items
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
del_stmt
(
self
,
nodelist
):
return
self
.
com_assign
(
nodelist
[
1
],
OP_DELETE
)
def
pass_stmt
(
self
,
nodelist
):
# pass:
n
=
Node
(
'pass'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
break_stmt
(
self
,
nodelist
):
# break:
n
=
Node
(
'break'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
continue_stmt
(
self
,
nodelist
):
# continue
n
=
Node
(
'continue'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
return_stmt
(
self
,
nodelist
):
# return: [testlist]
if
len
(
nodelist
)
<
2
:
n
=
Node
(
'return'
,
Node
(
'const'
,
None
))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
n
=
Node
(
'return'
,
self
.
com_node
(
nodelist
[
1
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
raise_stmt
(
self
,
nodelist
):
# raise: [test [',' test [',' test]]]
if
len
(
nodelist
)
>
5
:
expr3
=
self
.
com_node
(
nodelist
[
5
])
else
:
expr3
=
None
if
len
(
nodelist
)
>
3
:
expr2
=
self
.
com_node
(
nodelist
[
3
])
else
:
expr2
=
None
if
len
(
nodelist
)
>
1
:
expr1
=
self
.
com_node
(
nodelist
[
1
])
else
:
expr1
=
None
n
=
Node
(
'raise'
,
expr1
,
expr2
,
expr3
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
import_stmt
(
self
,
nodelist
):
# import_stmt: 'import' dotted_as_name (',' dotted_as_name)* |
# from: 'from' dotted_name 'import'
# ('*' | import_as_name (',' import_as_name)*)
names
=
[]
is_as
=
0
if
nodelist
[
0
][
1
]
==
'from'
:
for
i
in
range
(
3
,
len
(
nodelist
),
2
):
names
.
append
(
self
.
com_import_as_name
(
nodelist
[
i
][
1
]))
n
=
Node
(
'from'
,
self
.
com_dotted_name
(
nodelist
[
1
]),
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
names
.
append
(
self
.
com_dotted_as_name
(
nodelist
[
i
]))
n
=
Node
(
'import'
,
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
global_stmt
(
self
,
nodelist
):
# global: NAME (',' NAME)*
names
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
names
.
append
(
nodelist
[
i
][
1
])
n
=
Node
(
'global'
,
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
exec_stmt
(
self
,
nodelist
):
# exec_stmt: 'exec' expr ['in' expr [',' expr]]
expr1
=
self
.
com_node
(
nodelist
[
1
])
if
len
(
nodelist
)
>=
4
:
expr2
=
self
.
com_node
(
nodelist
[
3
])
if
len
(
nodelist
)
>=
6
:
expr3
=
self
.
com_node
(
nodelist
[
5
])
else
:
expr3
=
None
else
:
expr2
=
expr3
=
None
def
classdef
(
self
,
nodelist
):
# classdef: 'class' NAME ['(' testlist ')'] ':' suite
n
=
Node
(
'exec'
,
expr1
,
expr2
,
expr3
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
name
=
nodelist
[
1
][
1
]
doc
=
self
.
get_docstring
(
nodelist
[
-
1
])
if
nodelist
[
2
][
0
]
==
token
.
COLON
:
bases
=
[]
else
:
bases
=
self
.
com_bases
(
nodelist
[
3
])
def
assert_stmt
(
self
,
nodelist
):
# 'assert': test, [',' test]
expr1
=
self
.
com_node
(
nodelist
[
1
])
if
(
len
(
nodelist
)
==
4
):
expr2
=
self
.
com_node
(
nodelist
[
3
])
else
:
expr2
=
Node
(
'name'
,
'None'
)
n
=
Node
(
'assert'
,
expr1
,
expr2
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
if_stmt
(
self
,
nodelist
):
# if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
tests
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
)
-
3
,
4
):
testNode
=
self
.
com_node
(
nodelist
[
i
+
1
])
suiteNode
=
self
.
com_node
(
nodelist
[
i
+
3
])
tests
.
append
((
testNode
,
suiteNode
))
if
len
(
nodelist
)
%
4
==
3
:
elseNode
=
self
.
com_node
(
nodelist
[
-
1
])
## elseNode.lineno = nodelist[-1][1][2]
else
:
elseNode
=
None
n
=
Node
(
'if'
,
tests
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
# code for class
code
=
self
.
com_node
(
nodelist
[
-
1
])
def
while_stmt
(
self
,
nodelist
):
# 'while' test ':' suite ['else' ':' suite]
n
=
Node
(
'class'
,
name
,
bases
,
doc
,
code
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
testNode
=
self
.
com_node
(
nodelist
[
1
])
bodyNode
=
self
.
com_node
(
nodelist
[
3
])
def
stmt
(
self
,
nodelist
):
return
self
.
com_stmt
(
nodelist
[
0
])
if
len
(
nodelist
)
>
4
:
elseNode
=
self
.
com_node
(
nodelist
[
6
])
else
:
elseNode
=
None
small_stmt
=
stmt
flow_stmt
=
stmt
compound_stmt
=
stmt
n
=
Node
(
'while'
,
testNode
,
bodyNode
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
simple_stmt
(
self
,
nodelist
):
# small_stmt (';' small_stmt)* [';'] NEWLINE
stmts
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
),
2
):
self
.
com_append_stmt
(
stmts
,
nodelist
[
i
])
return
Node
(
'stmt'
,
stmts
)
def
for_stmt
(
self
,
nodelist
):
# 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
def
parameters
(
self
,
nodelist
):
raise
error
assignNode
=
self
.
com_assign
(
nodelist
[
1
],
OP_ASSIGN
)
listNode
=
self
.
com_node
(
nodelist
[
3
])
bodyNode
=
self
.
com_node
(
nodelist
[
5
])
def
varargslist
(
self
,
nodelist
):
raise
error
if
len
(
nodelist
)
>
8
:
elseNode
=
self
.
com_node
(
nodelist
[
8
])
else
:
elseNode
=
None
n
=
Node
(
'for'
,
assignNode
,
listNode
,
bodyNode
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
try_stmt
(
self
,
nodelist
):
# 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
# | 'try' ':' suite 'finally' ':' suite
if
nodelist
[
3
][
0
]
!=
symbol
.
except_clause
:
return
self
.
com_try_finally
(
nodelist
)
return
self
.
com_try_except
(
nodelist
)
def
suite
(
self
,
nodelist
):
# simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
if
len
(
nodelist
)
==
1
:
return
self
.
com_stmt
(
nodelist
[
0
])
stmts
=
[
]
for
node
in
nodelist
:
if
node
[
0
]
==
symbol
.
stmt
:
self
.
com_append_stmt
(
stmts
,
node
)
return
Node
(
'stmt'
,
stmts
)
# --------------------------------------------------------------
#
# EXPRESSION NODES (invoked by com_node())
#
def
testlist
(
self
,
nodelist
):
# testlist: expr (',' expr)* [',']
# exprlist: expr (',' expr)* [',']
return
self
.
com_binary
(
'tuple'
,
nodelist
)
exprlist
=
testlist
def
test
(
self
,
nodelist
):
# and_test ('or' and_test)* | lambdef
if
len
(
nodelist
)
==
1
and
nodelist
[
0
][
0
]
==
symbol
.
lambdef
:
return
self
.
lambdef
(
nodelist
[
0
])
return
self
.
com_binary
(
'or'
,
nodelist
)
def
and_test
(
self
,
nodelist
):
# not_test ('and' not_test)*
return
self
.
com_binary
(
'and'
,
nodelist
)
def
not_test
(
self
,
nodelist
):
# 'not' not_test | comparison
result
=
self
.
com_node
(
nodelist
[
-
1
])
if
len
(
nodelist
)
==
2
:
n
=
Node
(
'not'
,
result
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
result
def
comparison
(
self
,
nodelist
):
# comparison: expr (comp_op expr)*
node
=
self
.
com_node
(
nodelist
[
0
])
if
len
(
nodelist
)
==
1
:
return
node
results
=
[
]
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
nl
=
nodelist
[
i
-
1
]
# comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
# | 'in' | 'not' 'in' | 'is' | 'is' 'not'
n
=
nl
[
1
]
if
n
[
0
]
==
token
.
NAME
:
type
=
n
[
1
]
if
len
(
nl
)
==
3
:
if
type
==
'not'
:
type
=
'not in'
else
:
type
=
'is not'
else
:
type
=
_cmp_types
[
n
[
0
]]
lineno
=
nl
[
1
][
2
]
results
.
append
((
type
,
self
.
com_node
(
nodelist
[
i
])))
# we need a special "compare" node so that we can distinguish
# 3 < x < 5 from (3 < x) < 5
# the two have very different semantics and results (note that the
# latter form is always true)
n
=
Node
(
'compare'
,
node
,
results
)
n
.
lineno
=
lineno
return
n
def
expr
(
self
,
nodelist
):
# xor_expr ('|' xor_expr)*
return
self
.
com_binary
(
'bitor'
,
nodelist
)
def
xor_expr
(
self
,
nodelist
):
# xor_expr ('^' xor_expr)*
return
self
.
com_binary
(
'bitxor'
,
nodelist
)
def
and_expr
(
self
,
nodelist
):
# xor_expr ('&' xor_expr)*
return
self
.
com_binary
(
'bitand'
,
nodelist
)
def
shift_expr
(
self
,
nodelist
):
# shift_expr ('<<'|'>>' shift_expr)*
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
LEFTSHIFT
:
node
=
Node
(
'<<'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'>>'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
arith_expr
(
self
,
nodelist
):
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
PLUS
:
node
=
Node
(
'+'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'-'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
term
(
self
,
nodelist
):
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
STAR
:
node
=
Node
(
'*'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
elif
nodelist
[
i
-
1
][
0
]
==
token
.
SLASH
:
node
=
Node
(
'/'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'%'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
factor
(
self
,
nodelist
):
t
=
nodelist
[
0
][
0
]
node
=
self
.
com_node
(
nodelist
[
-
1
])
if
t
==
token
.
PLUS
:
node
=
Node
(
'unary+'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
elif
t
==
token
.
MINUS
:
node
=
Node
(
'unary-'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
elif
t
==
token
.
TILDE
:
node
=
Node
(
'invert'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
return
node
def
power
(
self
,
nodelist
):
# power: atom trailer* ('**' factor)*
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
1
,
len
(
nodelist
)):
if
nodelist
[
i
][
0
]
==
token
.
DOUBLESTAR
:
n
=
Node
(
'power'
,
[
node
,
self
.
com_node
(
nodelist
[
i
+
1
])])
n
.
lineno
=
nodelist
[
i
][
2
]
def
fpdef
(
self
,
nodelist
):
raise
error
def
fplist
(
self
,
nodelist
):
raise
error
def
dotted_name
(
self
,
nodelist
):
raise
error
def
comp_op
(
self
,
nodelist
):
raise
error
def
trailer
(
self
,
nodelist
):
raise
error
def
sliceop
(
self
,
nodelist
):
raise
error
def
argument
(
self
,
nodelist
):
raise
error
# --------------------------------------------------------------
#
# STATEMENT NODES (invoked by com_node())
#
def
expr_stmt
(
self
,
nodelist
):
# testlist ('=' testlist)*
exprNode
=
self
.
com_node
(
nodelist
[
-
1
])
if
len
(
nodelist
)
==
1
:
return
Node
(
'discard'
,
exprNode
)
nodes
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
)
-
2
,
2
):
nodes
.
append
(
self
.
com_assign
(
nodelist
[
i
],
OP_ASSIGN
))
n
=
Node
(
'assign'
,
nodes
,
exprNode
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
node
=
self
.
com_apply_trailer
(
node
,
nodelist
[
i
])
def
print_stmt
(
self
,
nodelist
):
# print: (test ',')* [test]
items
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
items
.
append
(
self
.
com_node
(
nodelist
[
i
]))
if
nodelist
[
-
1
][
0
]
==
token
.
COMMA
:
n
=
Node
(
'print'
,
items
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
n
=
Node
(
'printnl'
,
items
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
node
def
del_stmt
(
self
,
nodelist
):
return
self
.
com_assign
(
nodelist
[
1
],
OP_DELETE
)
def
atom
(
self
,
nodelist
):
t
=
nodelist
[
0
][
0
]
if
t
==
token
.
LPAR
:
if
nodelist
[
1
][
0
]
==
token
.
RPAR
:
n
=
Node
(
'tuple'
,
())
def
pass_stmt
(
self
,
nodelist
):
# pass:
n
=
Node
(
'pass'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
self
.
com_node
(
nodelist
[
1
])
if
t
==
token
.
LSQB
:
if
nodelist
[
1
][
0
]
==
token
.
RSQB
:
n
=
Node
(
'
list'
,
()
)
def
break_stmt
(
self
,
nodelist
)
:
# break
:
n
=
Node
(
'
break'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
self
.
com_list_constructor
(
nodelist
[
1
])
if
t
==
token
.
LBRACE
:
if
nodelist
[
1
][
0
]
==
token
.
RBRACE
:
return
Node
(
'dict'
,
())
return
self
.
com_dictmaker
(
nodelist
[
1
])
if
t
==
token
.
BACKQUOTE
:
n
=
Node
(
'backquote'
,
self
.
com_node
(
nodelist
[
1
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
NUMBER
:
### need to verify this matches compile.c
k
=
eval
(
nodelist
[
0
][
1
])
n
=
Node
(
'const'
,
k
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
STRING
:
### need to verify this matches compile.c
k
=
''
for
node
in
nodelist
:
k
=
k
+
eval
(
node
[
1
])
n
=
Node
(
'const'
,
k
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
NAME
:
### any processing to do?
n
=
Node
(
'name'
,
nodelist
[
0
][
1
])
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
raise
error
,
"unknown node type"
# --------------------------------------------------------------
#
# INTERNAL PARSING UTILITIES
#
def
com_node
(
self
,
node
):
# Note: compile.c has handling in com_node for del_stmt, pass_stmt,
# break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
# and compound_stmt.
# We'll just dispatch them.
#
# A ';' at the end of a line can make a NEWLINE token appear here,
# Render it harmless. (genc discards ('discard', ('const', xxxx)) Nodes)
#
if
node
[
0
]
==
token
.
NEWLINE
:
return
Node
(
'discard'
,
Node
(
'const'
,
None
))
def
continue_stmt
(
self
,
nodelist
):
# continue
n
=
Node
(
'continue'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
node
[
0
]
not
in
_legal_node_types
:
raise
error
,
'illegal node passed to com_node: %s'
%
node
[
0
]
def
return_stmt
(
self
,
nodelist
):
# return: [testlist]
if
len
(
nodelist
)
<
2
:
n
=
Node
(
'return'
,
Node
(
'const'
,
None
))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
n
=
Node
(
'return'
,
self
.
com_node
(
nodelist
[
1
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
# print "dispatch", self._dispatch[node[0]].__name__, node
return
self
.
_dispatch
[
node
[
0
]](
node
[
1
:])
def
com_arglist
(
self
,
nodelist
):
# varargslist:
# (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME]
# | fpdef ['=' test] (',' fpdef ['=' test])* [',']
# | ('**'|'*' '*') NAME)
# fpdef: NAME | '(' fplist ')'
# fplist: fpdef (',' fpdef)* [',']
names
=
[
]
defaults
=
[
]
flags
=
0
i
=
0
while
i
<
len
(
nodelist
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
token
.
STAR
or
node
[
0
]
==
token
.
DOUBLESTAR
:
if
node
[
0
]
==
token
.
STAR
:
node
=
nodelist
[
i
+
1
]
if
node
[
0
]
==
token
.
NAME
:
names
.
append
(
node
[
1
])
flags
=
flags
|
CO_VARARGS
i
=
i
+
3
if
i
<
len
(
nodelist
):
# should be DOUBLESTAR or STAR STAR
if
nodelist
[
i
][
0
]
==
token
.
DOUBLESTAR
:
node
=
nodelist
[
i
+
1
]
else
:
node
=
nodelist
[
i
+
2
]
names
.
append
(
node
[
1
])
flags
=
flags
|
CO_VARKEYWORDS
break
# fpdef: NAME | '(' fplist ')'
names
.
append
(
self
.
com_fpdef
(
node
))
i
=
i
+
1
if
i
>=
len
(
nodelist
):
break
if
nodelist
[
i
][
0
]
==
token
.
EQUAL
:
defaults
.
append
(
self
.
com_node
(
nodelist
[
i
+
1
]))
i
=
i
+
2
elif
len
(
defaults
):
# Treat "(a=1, b)" as "(a=1, b=None)"
defaults
.
append
(
Node
(
'const'
,
None
))
i
=
i
+
1
return
names
,
defaults
,
flags
def
com_fpdef
(
self
,
node
):
# fpdef: NAME | '(' fplist ')'
if
node
[
1
][
0
]
==
token
.
LPAR
:
return
self
.
com_fplist
(
node
[
2
])
return
node
[
1
][
1
]
def
com_fplist
(
self
,
node
):
# fplist: fpdef (',' fpdef)* [',']
if
len
(
node
)
==
2
:
return
self
.
com_fpdef
(
node
[
1
])
list
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
list
.
append
(
self
.
com_fpdef
(
node
[
i
]))
return
tuple
(
list
)
def
com_dotted_name
(
self
,
node
):
# String together the dotted names and return the string
name
=
""
for
n
in
node
:
if
type
(
n
)
==
type
(())
and
n
[
0
]
==
1
:
name
=
name
+
n
[
1
]
+
'.'
return
name
[:
-
1
]
def
com_dotted_as_name
(
self
,
node
):
dot
=
self
.
com_dotted_name
(
node
[
1
])
if
len
(
node
)
==
2
:
return
dot
,
None
assert
node
[
2
][
1
]
==
'as'
assert
node
[
3
][
0
]
==
token
.
NAME
return
dot
,
node
[
3
][
1
]
def
com_import_as_name
(
self
,
node
):
if
node
[
0
]
==
token
.
NAME
:
return
node
[
1
],
None
assert
len
(
node
)
==
4
assert
node
[
2
][
1
]
==
'as'
assert
node
[
3
][
0
]
==
token
.
NAME
return
node
[
1
][
1
],
node
[
3
][
1
]
def
com_bases
(
self
,
node
):
bases
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
bases
.
append
(
self
.
com_node
(
node
[
i
]))
return
bases
def
com_try_finally
(
self
,
nodelist
):
# try_fin_stmt: "try" ":" suite "finally" ":" suite
n
=
Node
(
'tryfinally'
,
self
.
com_node
(
nodelist
[
2
]),
self
.
com_node
(
nodelist
[
5
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
com_try_except
(
self
,
nodelist
):
# try_except: 'try' ':' suite (except_clause ':' suite)* ['else' suite]
#tryexcept: [TryNode, [except_clauses], elseNode)]
stmt
=
self
.
com_node
(
nodelist
[
2
])
clauses
=
[]
elseNode
=
None
for
i
in
range
(
3
,
len
(
nodelist
),
3
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
symbol
.
except_clause
:
# except_clause: 'except' [expr [',' expr]] */
if
len
(
node
)
>
2
:
expr1
=
self
.
com_node
(
node
[
2
])
if
len
(
node
)
>
4
:
expr2
=
self
.
com_assign
(
node
[
4
],
OP_ASSIGN
)
else
:
def
raise_stmt
(
self
,
nodelist
):
# raise: [test [',' test [',' test]]]
if
len
(
nodelist
)
>
5
:
expr3
=
self
.
com_node
(
nodelist
[
5
])
else
:
expr3
=
None
if
len
(
nodelist
)
>
3
:
expr2
=
self
.
com_node
(
nodelist
[
3
])
else
:
expr2
=
None
if
len
(
nodelist
)
>
1
:
expr1
=
self
.
com_node
(
nodelist
[
1
])
else
:
expr1
=
expr2
=
None
clauses
.
append
((
expr1
,
expr2
,
self
.
com_node
(
nodelist
[
i
+
2
])))
if
node
[
0
]
==
token
.
NAME
:
elseNode
=
self
.
com_node
(
nodelist
[
i
+
2
])
n
=
Node
(
'tryexcept'
,
self
.
com_node
(
nodelist
[
2
]),
clauses
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
com_assign
(
self
,
node
,
assigning
):
# return a node suitable for use as an "lvalue"
# loop to avoid trivial recursion
while
1
:
t
=
node
[
0
]
if
t
==
symbol
.
exprlist
or
t
==
symbol
.
testlist
:
if
len
(
node
)
>
2
:
return
self
.
com_assign_tuple
(
node
,
assigning
)
node
=
node
[
1
]
elif
t
in
_assign_types
:
if
len
(
node
)
>
2
:
raise
SyntaxError
,
"can't assign to operator"
node
=
node
[
1
]
elif
t
==
symbol
.
power
:
if
node
[
1
][
0
]
!=
symbol
.
atom
:
raise
SyntaxError
,
"can't assign to operator"
if
len
(
node
)
>
2
:
primary
=
self
.
com_node
(
node
[
1
])
for
i
in
range
(
2
,
len
(
node
)
-
1
):
ch
=
node
[
i
]
if
ch
[
0
]
==
token
.
DOUBLESTAR
:
raise
SyntaxError
,
"can't assign to operator"
primary
=
self
.
com_apply_trailer
(
primary
,
ch
)
return
self
.
com_assign_trailer
(
primary
,
node
[
-
1
],
assigning
)
node
=
node
[
1
]
elif
t
==
symbol
.
atom
:
t
=
node
[
1
][
0
]
if
t
==
token
.
LPAR
:
node
=
node
[
2
]
if
node
[
0
]
==
token
.
RPAR
:
raise
SyntaxError
,
"can't assign to ()"
elif
t
==
token
.
LSQB
:
node
=
node
[
2
]
if
node
[
0
]
==
token
.
RSQB
:
raise
SyntaxError
,
"can't assign to []"
return
self
.
com_assign_list
(
node
,
assigning
)
elif
t
==
token
.
NAME
:
return
self
.
com_assign_name
(
node
[
1
],
assigning
)
expr1
=
None
n
=
Node
(
'raise'
,
expr1
,
expr2
,
expr3
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
import_stmt
(
self
,
nodelist
):
# import_stmt: 'import' dotted_as_name (',' dotted_as_name)* |
# from: 'from' dotted_name 'import'
# ('*' | import_as_name (',' import_as_name)*)
names
=
[]
is_as
=
0
if
nodelist
[
0
][
1
]
==
'from'
:
for
i
in
range
(
3
,
len
(
nodelist
),
2
):
names
.
append
(
self
.
com_import_as_name
(
nodelist
[
i
][
1
]))
n
=
Node
(
'from'
,
self
.
com_dotted_name
(
nodelist
[
1
]),
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
names
.
append
(
self
.
com_dotted_as_name
(
nodelist
[
i
]))
n
=
Node
(
'import'
,
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
global_stmt
(
self
,
nodelist
):
# global: NAME (',' NAME)*
names
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
names
.
append
(
nodelist
[
i
][
1
])
n
=
Node
(
'global'
,
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
exec_stmt
(
self
,
nodelist
):
# exec_stmt: 'exec' expr ['in' expr [',' expr]]
expr1
=
self
.
com_node
(
nodelist
[
1
])
if
len
(
nodelist
)
>=
4
:
expr2
=
self
.
com_node
(
nodelist
[
3
])
if
len
(
nodelist
)
>=
6
:
expr3
=
self
.
com_node
(
nodelist
[
5
])
else
:
expr3
=
None
else
:
raise
SyntaxError
,
"can't assign to literal"
else
:
raise
SyntaxError
,
"bad assignment"
def
com_assign_tuple
(
self
,
node
,
assigning
):
assigns
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
assigns
.
append
(
self
.
com_assign
(
node
[
i
],
assigning
))
return
Node
(
'ass_tuple'
,
assigns
)
def
com_assign_list
(
self
,
node
,
assigning
):
assigns
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
assigns
.
append
(
self
.
com_assign
(
node
[
i
],
assigning
))
return
Node
(
'ass_list'
,
assigns
)
def
com_assign_name
(
self
,
node
,
assigning
):
n
=
Node
(
'ass_name'
,
node
[
1
],
assigning
)
n
.
lineno
=
node
[
2
]
return
n
def
com_assign_trailer
(
self
,
primary
,
node
,
assigning
):
t
=
node
[
1
][
0
]
if
t
==
token
.
LPAR
:
raise
SyntaxError
,
"can't assign to function call"
if
t
==
token
.
DOT
:
return
self
.
com_assign_attr
(
primary
,
node
[
2
],
assigning
)
if
t
==
token
.
LSQB
:
return
self
.
com_subscriptlist
(
primary
,
node
[
2
],
assigning
)
raise
SyntaxError
,
"unknown trailer type: %s"
%
t
def
com_assign_attr
(
self
,
primary
,
node
,
assigning
):
return
Node
(
'ass_attr'
,
primary
,
node
[
1
],
assigning
)
def
com_binary
(
self
,
type
,
nodelist
):
"Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
if
len
(
nodelist
)
==
1
:
return
self
.
com_node
(
nodelist
[
0
])
items
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
),
2
):
items
.
append
(
self
.
com_node
(
nodelist
[
i
]))
return
Node
(
type
,
items
)
def
com_stmt
(
self
,
node
):
#pprint.pprint(node)
result
=
self
.
com_node
(
node
)
try
:
result
[
0
]
except
:
print
node
[
0
]
if
result
[
0
]
==
'stmt'
:
return
result
return
Node
(
'stmt'
,
[
result
])
def
com_append_stmt
(
self
,
stmts
,
node
):
result
=
self
.
com_node
(
node
)
try
:
result
[
0
]
except
:
print
node
if
result
[
0
]
==
'stmt'
:
stmts
[
len
(
stmts
):]
=
result
[
1
]
else
:
stmts
.
append
(
result
)
def
com_list_constructor
(
self
,
nodelist
):
values
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
values
.
append
(
self
.
com_node
(
nodelist
[
i
]))
return
Node
(
'list'
,
values
)
def
com_dictmaker
(
self
,
nodelist
):
# dictmaker: test ':' test (',' test ':' value)* [',']
items
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
4
):
items
.
append
((
self
.
com_node
(
nodelist
[
i
]),
self
.
com_node
(
nodelist
[
i
+
2
])))
return
Node
(
'dict'
,
items
)
def
com_apply_trailer
(
self
,
primaryNode
,
nodelist
):
t
=
nodelist
[
1
][
0
]
if
t
==
token
.
LPAR
:
return
self
.
com_call_function
(
primaryNode
,
nodelist
[
2
])
if
t
==
token
.
DOT
:
return
self
.
com_select_member
(
primaryNode
,
nodelist
[
2
])
if
t
==
token
.
LSQB
:
return
self
.
com_subscriptlist
(
primaryNode
,
nodelist
[
2
],
OP_APPLY
)
raise
SyntaxError
,
'unknown node type: %s'
%
t
def
com_select_member
(
self
,
primaryNode
,
nodelist
):
if
nodelist
[
0
]
!=
token
.
NAME
:
raise
SyntaxError
,
"member must be a name"
n
=
Node
(
'getattr'
,
primaryNode
,
nodelist
[
1
])
n
.
lineno
=
nodelist
[
2
]
return
n
def
com_call_function
(
self
,
primaryNode
,
nodelist
):
if
nodelist
[
0
]
==
token
.
RPAR
:
return
Node
(
'call_func'
,
primaryNode
,
[
])
args
=
[
]
kw
=
0
len_nodelist
=
len
(
nodelist
)
for
i
in
range
(
1
,
len_nodelist
,
2
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
token
.
STAR
or
node
[
0
]
==
token
.
DOUBLESTAR
:
break
kw
,
result
=
self
.
com_argument
(
node
,
kw
)
args
.
append
(
result
)
else
:
i
=
i
+
1
# No broken by star arg, so skip the last one we processed.
if
i
<
len_nodelist
and
nodelist
[
i
][
0
]
==
token
.
COMMA
:
# need to accept an application that looks like "f(a, b,)"
i
=
i
+
1
star_node
=
dstar_node
=
None
while
i
<
len_nodelist
:
tok
=
nodelist
[
i
]
ch
=
nodelist
[
i
+
1
]
i
=
i
+
3
if
tok
[
0
]
==
token
.
STAR
:
if
star_node
is
not
None
:
raise
SyntaxError
,
'already have the varargs indentifier'
star_node
=
self
.
com_node
(
ch
)
elif
tok
[
0
]
==
token
.
DOUBLESTAR
:
if
dstar_node
is
not
None
:
raise
SyntaxError
,
'already have the kwargs indentifier'
dstar_node
=
self
.
com_node
(
ch
)
expr2
=
expr3
=
None
n
=
Node
(
'exec'
,
expr1
,
expr2
,
expr3
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
assert_stmt
(
self
,
nodelist
):
# 'assert': test, [',' test]
expr1
=
self
.
com_node
(
nodelist
[
1
])
if
(
len
(
nodelist
)
==
4
):
expr2
=
self
.
com_node
(
nodelist
[
3
])
else
:
expr2
=
Node
(
'name'
,
'None'
)
n
=
Node
(
'assert'
,
expr1
,
expr2
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
if_stmt
(
self
,
nodelist
):
# if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
tests
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
)
-
3
,
4
):
testNode
=
self
.
com_node
(
nodelist
[
i
+
1
])
suiteNode
=
self
.
com_node
(
nodelist
[
i
+
3
])
tests
.
append
((
testNode
,
suiteNode
))
if
len
(
nodelist
)
%
4
==
3
:
elseNode
=
self
.
com_node
(
nodelist
[
-
1
])
## elseNode.lineno = nodelist[-1][1][2]
else
:
elseNode
=
None
n
=
Node
(
'if'
,
tests
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
while_stmt
(
self
,
nodelist
):
# 'while' test ':' suite ['else' ':' suite]
testNode
=
self
.
com_node
(
nodelist
[
1
])
bodyNode
=
self
.
com_node
(
nodelist
[
3
])
if
len
(
nodelist
)
>
4
:
elseNode
=
self
.
com_node
(
nodelist
[
6
])
else
:
elseNode
=
None
n
=
Node
(
'while'
,
testNode
,
bodyNode
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
for_stmt
(
self
,
nodelist
):
# 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
assignNode
=
self
.
com_assign
(
nodelist
[
1
],
OP_ASSIGN
)
listNode
=
self
.
com_node
(
nodelist
[
3
])
bodyNode
=
self
.
com_node
(
nodelist
[
5
])
if
len
(
nodelist
)
>
8
:
elseNode
=
self
.
com_node
(
nodelist
[
8
])
else
:
raise
SyntaxError
,
'unknown node type: %s'
%
tok
return
Node
(
'call_func'
,
primaryNode
,
args
,
star_node
,
dstar_node
)
def
com_argument
(
self
,
nodelist
,
kw
):
if
len
(
nodelist
)
==
2
:
if
kw
:
raise
SyntaxError
,
"non-keyword arg after keyword arg"
return
0
,
self
.
com_node
(
nodelist
[
1
])
result
=
self
.
com_node
(
nodelist
[
3
])
n
=
nodelist
[
1
]
while
len
(
n
)
==
2
and
n
[
0
]
!=
token
.
NAME
:
n
=
n
[
1
]
if
n
[
0
]
!=
token
.
NAME
:
raise
SyntaxError
,
"keyword can't be an expression (%s)"
%
n
[
0
]
node
=
Node
(
'keyword'
,
n
[
1
],
result
)
node
.
lineno
=
n
[
2
]
return
1
,
node
def
com_subscriptlist
(
self
,
primary
,
nodelist
,
assigning
):
# slicing: simple_slicing | extended_slicing
# simple_slicing: primary "[" short_slice "]"
# extended_slicing: primary "[" slice_list "]"
# slice_list: slice_item ("," slice_item)* [","]
# backwards compat slice for '[i:j]'
if
len
(
nodelist
)
==
2
:
sub
=
nodelist
[
1
]
if
(
sub
[
1
][
0
]
==
token
.
COLON
or
\
(
len
(
sub
)
>
2
and
sub
[
2
][
0
]
==
token
.
COLON
))
and
\
sub
[
-
1
][
0
]
!=
symbol
.
sliceop
:
return
self
.
com_slice
(
primary
,
sub
,
assigning
)
subscripts
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
subscripts
.
append
(
self
.
com_subscript
(
nodelist
[
i
]))
return
Node
(
'subscript'
,
primary
,
assigning
,
subscripts
)
def
com_subscript
(
self
,
node
):
# slice_item: expression | proper_slice | ellipsis
ch
=
node
[
1
]
if
ch
[
0
]
==
token
.
DOT
and
node
[
2
][
0
]
==
token
.
DOT
:
return
Node
(
'ellipsis'
)
if
ch
[
0
]
==
token
.
COLON
or
len
(
node
)
>
2
:
return
self
.
com_sliceobj
(
node
)
return
self
.
com_node
(
ch
)
def
com_sliceobj
(
self
,
node
):
# proper_slice: short_slice | long_slice
# short_slice: [lower_bound] ":" [upper_bound]
# long_slice: short_slice ":" [stride]
# lower_bound: expression
# upper_bound: expression
# stride: expression
elseNode
=
None
n
=
Node
(
'for'
,
assignNode
,
listNode
,
bodyNode
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
try_stmt
(
self
,
nodelist
):
# 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
# | 'try' ':' suite 'finally' ':' suite
if
nodelist
[
3
][
0
]
!=
symbol
.
except_clause
:
return
self
.
com_try_finally
(
nodelist
)
return
self
.
com_try_except
(
nodelist
)
def
suite
(
self
,
nodelist
):
# simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
if
len
(
nodelist
)
==
1
:
return
self
.
com_stmt
(
nodelist
[
0
])
stmts
=
[
]
for
node
in
nodelist
:
if
node
[
0
]
==
symbol
.
stmt
:
self
.
com_append_stmt
(
stmts
,
node
)
return
Node
(
'stmt'
,
stmts
)
# --------------------------------------------------------------
#
# EXPRESSION NODES (invoked by com_node())
#
# Note: a stride may be further slicing...
items
=
[
]
def
testlist
(
self
,
nodelist
):
# testlist: expr (',' expr)* [',']
# exprlist: expr (',' expr)* [',']
return
self
.
com_binary
(
'tuple'
,
nodelist
)
exprlist
=
testlist
def
test
(
self
,
nodelist
):
# and_test ('or' and_test)* | lambdef
if
len
(
nodelist
)
==
1
and
nodelist
[
0
][
0
]
==
symbol
.
lambdef
:
return
self
.
lambdef
(
nodelist
[
0
])
return
self
.
com_binary
(
'or'
,
nodelist
)
def
and_test
(
self
,
nodelist
):
# not_test ('and' not_test)*
return
self
.
com_binary
(
'and'
,
nodelist
)
def
not_test
(
self
,
nodelist
):
# 'not' not_test | comparison
result
=
self
.
com_node
(
nodelist
[
-
1
])
if
len
(
nodelist
)
==
2
:
n
=
Node
(
'not'
,
result
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
result
def
comparison
(
self
,
nodelist
):
# comparison: expr (comp_op expr)*
node
=
self
.
com_node
(
nodelist
[
0
])
if
len
(
nodelist
)
==
1
:
return
node
results
=
[
]
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
nl
=
nodelist
[
i
-
1
]
# comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
# | 'in' | 'not' 'in' | 'is' | 'is' 'not'
n
=
nl
[
1
]
if
n
[
0
]
==
token
.
NAME
:
type
=
n
[
1
]
if
len
(
nl
)
==
3
:
if
type
==
'not'
:
type
=
'not in'
else
:
type
=
'is not'
else
:
type
=
_cmp_types
[
n
[
0
]]
lineno
=
nl
[
1
][
2
]
results
.
append
((
type
,
self
.
com_node
(
nodelist
[
i
])))
# we need a special "compare" node so that we can distinguish
# 3 < x < 5 from (3 < x) < 5
# the two have very different semantics and results (note that the
# latter form is always true)
n
=
Node
(
'compare'
,
node
,
results
)
n
.
lineno
=
lineno
return
n
if
node
[
1
][
0
]
==
token
.
COLON
:
items
.
append
(
Node
(
'const'
,
None
))
i
=
2
else
:
items
.
append
(
self
.
com_node
(
node
[
1
]))
# i == 2 is a COLON
i
=
3
def
expr
(
self
,
nodelist
):
# xor_expr ('|' xor_expr)*
return
self
.
com_binary
(
'bitor'
,
nodelist
)
def
xor_expr
(
self
,
nodelist
):
# xor_expr ('^' xor_expr)*
return
self
.
com_binary
(
'bitxor'
,
nodelist
)
def
and_expr
(
self
,
nodelist
):
# xor_expr ('&' xor_expr)*
return
self
.
com_binary
(
'bitand'
,
nodelist
)
def
shift_expr
(
self
,
nodelist
):
# shift_expr ('<<'|'>>' shift_expr)*
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
LEFTSHIFT
:
node
=
Node
(
'<<'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'>>'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
arith_expr
(
self
,
nodelist
):
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
PLUS
:
node
=
Node
(
'+'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'-'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
term
(
self
,
nodelist
):
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
STAR
:
node
=
Node
(
'*'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
elif
nodelist
[
i
-
1
][
0
]
==
token
.
SLASH
:
node
=
Node
(
'/'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'%'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
factor
(
self
,
nodelist
):
t
=
nodelist
[
0
][
0
]
node
=
self
.
com_node
(
nodelist
[
-
1
])
if
t
==
token
.
PLUS
:
node
=
Node
(
'unary+'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
elif
t
==
token
.
MINUS
:
node
=
Node
(
'unary-'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
elif
t
==
token
.
TILDE
:
node
=
Node
(
'invert'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
return
node
def
power
(
self
,
nodelist
):
# power: atom trailer* ('**' factor)*
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
1
,
len
(
nodelist
)):
if
nodelist
[
i
][
0
]
==
token
.
DOUBLESTAR
:
n
=
Node
(
'power'
,
[
node
,
self
.
com_node
(
nodelist
[
i
+
1
])])
n
.
lineno
=
nodelist
[
i
][
2
]
return
n
node
=
self
.
com_apply_trailer
(
node
,
nodelist
[
i
])
return
node
def
atom
(
self
,
nodelist
):
t
=
nodelist
[
0
][
0
]
if
t
==
token
.
LPAR
:
if
nodelist
[
1
][
0
]
==
token
.
RPAR
:
n
=
Node
(
'tuple'
,
())
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
self
.
com_node
(
nodelist
[
1
])
if
t
==
token
.
LSQB
:
if
nodelist
[
1
][
0
]
==
token
.
RSQB
:
n
=
Node
(
'list'
,
())
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
self
.
com_list_constructor
(
nodelist
[
1
])
if
t
==
token
.
LBRACE
:
if
nodelist
[
1
][
0
]
==
token
.
RBRACE
:
return
Node
(
'dict'
,
())
return
self
.
com_dictmaker
(
nodelist
[
1
])
if
t
==
token
.
BACKQUOTE
:
n
=
Node
(
'backquote'
,
self
.
com_node
(
nodelist
[
1
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
NUMBER
:
### need to verify this matches compile.c
k
=
eval
(
nodelist
[
0
][
1
])
n
=
Node
(
'const'
,
k
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
STRING
:
### need to verify this matches compile.c
k
=
''
for
node
in
nodelist
:
k
=
k
+
eval
(
node
[
1
])
n
=
Node
(
'const'
,
k
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
NAME
:
### any processing to do?
n
=
Node
(
'name'
,
nodelist
[
0
][
1
])
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
raise
error
,
"unknown node type"
# --------------------------------------------------------------
#
# INTERNAL PARSING UTILITIES
#
if
i
<
len
(
node
)
and
node
[
i
][
0
]
==
symbol
.
test
:
items
.
append
(
self
.
com_node
(
node
[
i
]))
i
=
i
+
1
else
:
items
.
append
(
Node
(
'const'
,
None
))
# a short_slice has been built. look for long_slice now by looking
# for strides...
for
j
in
range
(
i
,
len
(
node
)):
ch
=
node
[
j
]
if
len
(
ch
)
==
2
:
items
.
append
(
Node
(
'const'
,
None
))
else
:
items
.
append
(
self
.
com_node
(
ch
[
2
]))
return
Node
(
'sliceobj'
,
items
)
def
com_slice
(
self
,
primary
,
node
,
assigning
):
# short_slice: [lower_bound] ":" [upper_bound]
lower
=
upper
=
None
if
len
(
node
)
==
3
:
if
node
[
1
][
0
]
==
token
.
COLON
:
upper
=
self
.
com_node
(
node
[
2
])
else
:
lower
=
self
.
com_node
(
node
[
1
])
elif
len
(
node
)
==
4
:
lower
=
self
.
com_node
(
node
[
1
])
upper
=
self
.
com_node
(
node
[
3
])
return
Node
(
'slice'
,
primary
,
assigning
,
lower
,
upper
)
def
get_docstring
(
self
,
node
,
n
=
None
):
if
n
is
None
:
n
=
node
[
0
]
node
=
node
[
1
:]
if
n
==
symbol
.
suite
:
if
len
(
node
)
==
1
:
return
self
.
get_docstring
(
node
[
0
])
for
sub
in
node
:
if
sub
[
0
]
==
symbol
.
stmt
:
return
self
.
get_docstring
(
sub
)
return
None
if
n
==
symbol
.
file_input
:
for
sub
in
node
:
if
sub
[
0
]
==
symbol
.
stmt
:
return
self
.
get_docstring
(
sub
)
return
None
if
n
==
symbol
.
atom
:
if
node
[
0
][
0
]
==
token
.
STRING
:
s
=
''
for
t
in
node
:
s
=
s
+
eval
(
t
[
1
])
return
s
return
None
if
n
==
symbol
.
stmt
or
n
==
symbol
.
simple_stmt
or
n
==
symbol
.
small_stmt
:
return
self
.
get_docstring
(
node
[
0
])
if
n
in
_doc_nodes
and
len
(
node
)
==
1
:
return
self
.
get_docstring
(
node
[
0
])
return
None
def
com_node
(
self
,
node
):
# Note: compile.c has handling in com_node for del_stmt, pass_stmt,
# break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
# and compound_stmt.
# We'll just dispatch them.
#
# A ';' at the end of a line can make a NEWLINE token appear here,
# Render it harmless. (genc discards ('discard', ('const', xxxx)) Nodes)
#
if
node
[
0
]
==
token
.
NEWLINE
:
return
Node
(
'discard'
,
Node
(
'const'
,
None
))
if
node
[
0
]
not
in
_legal_node_types
:
raise
error
,
'illegal node passed to com_node: %s'
%
node
[
0
]
# print "dispatch", self._dispatch[node[0]].__name__, node
return
self
.
_dispatch
[
node
[
0
]](
node
[
1
:])
def
com_arglist
(
self
,
nodelist
):
# varargslist:
# (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME]
# | fpdef ['=' test] (',' fpdef ['=' test])* [',']
# | ('**'|'*' '*') NAME)
# fpdef: NAME | '(' fplist ')'
# fplist: fpdef (',' fpdef)* [',']
names
=
[
]
defaults
=
[
]
flags
=
0
i
=
0
while
i
<
len
(
nodelist
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
token
.
STAR
or
node
[
0
]
==
token
.
DOUBLESTAR
:
if
node
[
0
]
==
token
.
STAR
:
node
=
nodelist
[
i
+
1
]
if
node
[
0
]
==
token
.
NAME
:
names
.
append
(
node
[
1
])
flags
=
flags
|
CO_VARARGS
i
=
i
+
3
if
i
<
len
(
nodelist
):
# should be DOUBLESTAR or STAR STAR
if
nodelist
[
i
][
0
]
==
token
.
DOUBLESTAR
:
node
=
nodelist
[
i
+
1
]
else
:
node
=
nodelist
[
i
+
2
]
names
.
append
(
node
[
1
])
flags
=
flags
|
CO_VARKEYWORDS
break
# fpdef: NAME | '(' fplist ')'
names
.
append
(
self
.
com_fpdef
(
node
))
i
=
i
+
1
if
i
>=
len
(
nodelist
):
break
if
nodelist
[
i
][
0
]
==
token
.
EQUAL
:
defaults
.
append
(
self
.
com_node
(
nodelist
[
i
+
1
]))
i
=
i
+
2
elif
len
(
defaults
):
# Treat "(a=1, b)" as "(a=1, b=None)"
defaults
.
append
(
Node
(
'const'
,
None
))
i
=
i
+
1
return
names
,
defaults
,
flags
def
com_fpdef
(
self
,
node
):
# fpdef: NAME | '(' fplist ')'
if
node
[
1
][
0
]
==
token
.
LPAR
:
return
self
.
com_fplist
(
node
[
2
])
return
node
[
1
][
1
]
def
com_fplist
(
self
,
node
):
# fplist: fpdef (',' fpdef)* [',']
if
len
(
node
)
==
2
:
return
self
.
com_fpdef
(
node
[
1
])
list
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
list
.
append
(
self
.
com_fpdef
(
node
[
i
]))
return
tuple
(
list
)
def
com_dotted_name
(
self
,
node
):
# String together the dotted names and return the string
name
=
""
for
n
in
node
:
if
type
(
n
)
==
type
(())
and
n
[
0
]
==
1
:
name
=
name
+
n
[
1
]
+
'.'
return
name
[:
-
1
]
def
com_dotted_as_name
(
self
,
node
):
dot
=
self
.
com_dotted_name
(
node
[
1
])
if
len
(
node
)
==
2
:
return
dot
,
None
assert
node
[
2
][
1
]
==
'as'
assert
node
[
3
][
0
]
==
token
.
NAME
return
dot
,
node
[
3
][
1
]
def
com_import_as_name
(
self
,
node
):
if
node
[
0
]
==
token
.
NAME
:
return
node
[
1
],
None
assert
len
(
node
)
==
4
assert
node
[
2
][
1
]
==
'as'
assert
node
[
3
][
0
]
==
token
.
NAME
return
node
[
1
][
1
],
node
[
3
][
1
]
def
com_bases
(
self
,
node
):
bases
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
bases
.
append
(
self
.
com_node
(
node
[
i
]))
return
bases
def
com_try_finally
(
self
,
nodelist
):
# try_fin_stmt: "try" ":" suite "finally" ":" suite
n
=
Node
(
'tryfinally'
,
self
.
com_node
(
nodelist
[
2
]),
self
.
com_node
(
nodelist
[
5
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
com_try_except
(
self
,
nodelist
):
# try_except: 'try' ':' suite (except_clause ':' suite)* ['else' suite]
#tryexcept: [TryNode, [except_clauses], elseNode)]
stmt
=
self
.
com_node
(
nodelist
[
2
])
clauses
=
[]
elseNode
=
None
for
i
in
range
(
3
,
len
(
nodelist
),
3
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
symbol
.
except_clause
:
# except_clause: 'except' [expr [',' expr]] */
if
len
(
node
)
>
2
:
expr1
=
self
.
com_node
(
node
[
2
])
if
len
(
node
)
>
4
:
expr2
=
self
.
com_assign
(
node
[
4
],
OP_ASSIGN
)
else
:
expr2
=
None
else
:
expr1
=
expr2
=
None
clauses
.
append
((
expr1
,
expr2
,
self
.
com_node
(
nodelist
[
i
+
2
])))
if
node
[
0
]
==
token
.
NAME
:
elseNode
=
self
.
com_node
(
nodelist
[
i
+
2
])
n
=
Node
(
'tryexcept'
,
self
.
com_node
(
nodelist
[
2
]),
clauses
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
com_assign
(
self
,
node
,
assigning
):
# return a node suitable for use as an "lvalue"
# loop to avoid trivial recursion
while
1
:
t
=
node
[
0
]
if
t
==
symbol
.
exprlist
or
t
==
symbol
.
testlist
:
if
len
(
node
)
>
2
:
return
self
.
com_assign_tuple
(
node
,
assigning
)
node
=
node
[
1
]
elif
t
in
_assign_types
:
if
len
(
node
)
>
2
:
raise
SyntaxError
,
"can't assign to operator"
node
=
node
[
1
]
elif
t
==
symbol
.
power
:
if
node
[
1
][
0
]
!=
symbol
.
atom
:
raise
SyntaxError
,
"can't assign to operator"
if
len
(
node
)
>
2
:
primary
=
self
.
com_node
(
node
[
1
])
for
i
in
range
(
2
,
len
(
node
)
-
1
):
ch
=
node
[
i
]
if
ch
[
0
]
==
token
.
DOUBLESTAR
:
raise
SyntaxError
,
"can't assign to operator"
primary
=
self
.
com_apply_trailer
(
primary
,
ch
)
return
self
.
com_assign_trailer
(
primary
,
node
[
-
1
],
assigning
)
node
=
node
[
1
]
elif
t
==
symbol
.
atom
:
t
=
node
[
1
][
0
]
if
t
==
token
.
LPAR
:
node
=
node
[
2
]
if
node
[
0
]
==
token
.
RPAR
:
raise
SyntaxError
,
"can't assign to ()"
elif
t
==
token
.
LSQB
:
node
=
node
[
2
]
if
node
[
0
]
==
token
.
RSQB
:
raise
SyntaxError
,
"can't assign to []"
return
self
.
com_assign_list
(
node
,
assigning
)
elif
t
==
token
.
NAME
:
return
self
.
com_assign_name
(
node
[
1
],
assigning
)
else
:
raise
SyntaxError
,
"can't assign to literal"
else
:
raise
SyntaxError
,
"bad assignment"
def
com_assign_tuple
(
self
,
node
,
assigning
):
assigns
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
assigns
.
append
(
self
.
com_assign
(
node
[
i
],
assigning
))
return
Node
(
'ass_tuple'
,
assigns
)
def
com_assign_list
(
self
,
node
,
assigning
):
assigns
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
assigns
.
append
(
self
.
com_assign
(
node
[
i
],
assigning
))
return
Node
(
'ass_list'
,
assigns
)
def
com_assign_name
(
self
,
node
,
assigning
):
n
=
Node
(
'ass_name'
,
node
[
1
],
assigning
)
n
.
lineno
=
node
[
2
]
return
n
def
com_assign_trailer
(
self
,
primary
,
node
,
assigning
):
t
=
node
[
1
][
0
]
if
t
==
token
.
LPAR
:
raise
SyntaxError
,
"can't assign to function call"
if
t
==
token
.
DOT
:
return
self
.
com_assign_attr
(
primary
,
node
[
2
],
assigning
)
if
t
==
token
.
LSQB
:
return
self
.
com_subscriptlist
(
primary
,
node
[
2
],
assigning
)
raise
SyntaxError
,
"unknown trailer type: %s"
%
t
def
com_assign_attr
(
self
,
primary
,
node
,
assigning
):
return
Node
(
'ass_attr'
,
primary
,
node
[
1
],
assigning
)
def
com_binary
(
self
,
type
,
nodelist
):
"Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
if
len
(
nodelist
)
==
1
:
return
self
.
com_node
(
nodelist
[
0
])
items
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
),
2
):
items
.
append
(
self
.
com_node
(
nodelist
[
i
]))
return
Node
(
type
,
items
)
def
com_stmt
(
self
,
node
):
#pprint.pprint(node)
result
=
self
.
com_node
(
node
)
try
:
result
[
0
]
except
:
print
node
[
0
]
if
result
[
0
]
==
'stmt'
:
return
result
return
Node
(
'stmt'
,
[
result
])
def
com_append_stmt
(
self
,
stmts
,
node
):
result
=
self
.
com_node
(
node
)
try
:
result
[
0
]
except
:
print
node
if
result
[
0
]
==
'stmt'
:
stmts
[
len
(
stmts
):]
=
result
[
1
]
else
:
stmts
.
append
(
result
)
def
com_list_constructor
(
self
,
nodelist
):
values
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
values
.
append
(
self
.
com_node
(
nodelist
[
i
]))
return
Node
(
'list'
,
values
)
def
com_dictmaker
(
self
,
nodelist
):
# dictmaker: test ':' test (',' test ':' value)* [',']
items
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
4
):
items
.
append
((
self
.
com_node
(
nodelist
[
i
]),
self
.
com_node
(
nodelist
[
i
+
2
])))
return
Node
(
'dict'
,
items
)
def
com_apply_trailer
(
self
,
primaryNode
,
nodelist
):
t
=
nodelist
[
1
][
0
]
if
t
==
token
.
LPAR
:
return
self
.
com_call_function
(
primaryNode
,
nodelist
[
2
])
if
t
==
token
.
DOT
:
return
self
.
com_select_member
(
primaryNode
,
nodelist
[
2
])
if
t
==
token
.
LSQB
:
return
self
.
com_subscriptlist
(
primaryNode
,
nodelist
[
2
],
OP_APPLY
)
raise
SyntaxError
,
'unknown node type: %s'
%
t
def
com_select_member
(
self
,
primaryNode
,
nodelist
):
if
nodelist
[
0
]
!=
token
.
NAME
:
raise
SyntaxError
,
"member must be a name"
n
=
Node
(
'getattr'
,
primaryNode
,
nodelist
[
1
])
n
.
lineno
=
nodelist
[
2
]
return
n
def
com_call_function
(
self
,
primaryNode
,
nodelist
):
if
nodelist
[
0
]
==
token
.
RPAR
:
return
Node
(
'call_func'
,
primaryNode
,
[
])
args
=
[
]
kw
=
0
len_nodelist
=
len
(
nodelist
)
for
i
in
range
(
1
,
len_nodelist
,
2
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
token
.
STAR
or
node
[
0
]
==
token
.
DOUBLESTAR
:
break
kw
,
result
=
self
.
com_argument
(
node
,
kw
)
args
.
append
(
result
)
else
:
i
=
i
+
1
# No broken by star arg, so skip the last one we processed.
if
i
<
len_nodelist
and
nodelist
[
i
][
0
]
==
token
.
COMMA
:
# need to accept an application that looks like "f(a, b,)"
i
=
i
+
1
star_node
=
dstar_node
=
None
while
i
<
len_nodelist
:
tok
=
nodelist
[
i
]
ch
=
nodelist
[
i
+
1
]
i
=
i
+
3
if
tok
[
0
]
==
token
.
STAR
:
if
star_node
is
not
None
:
raise
SyntaxError
,
'already have the varargs indentifier'
star_node
=
self
.
com_node
(
ch
)
elif
tok
[
0
]
==
token
.
DOUBLESTAR
:
if
dstar_node
is
not
None
:
raise
SyntaxError
,
'already have the kwargs indentifier'
dstar_node
=
self
.
com_node
(
ch
)
else
:
raise
SyntaxError
,
'unknown node type: %s'
%
tok
return
Node
(
'call_func'
,
primaryNode
,
args
,
star_node
,
dstar_node
)
def
com_argument
(
self
,
nodelist
,
kw
):
if
len
(
nodelist
)
==
2
:
if
kw
:
raise
SyntaxError
,
"non-keyword arg after keyword arg"
return
0
,
self
.
com_node
(
nodelist
[
1
])
result
=
self
.
com_node
(
nodelist
[
3
])
n
=
nodelist
[
1
]
while
len
(
n
)
==
2
and
n
[
0
]
!=
token
.
NAME
:
n
=
n
[
1
]
if
n
[
0
]
!=
token
.
NAME
:
raise
SyntaxError
,
"keyword can't be an expression (%s)"
%
n
[
0
]
node
=
Node
(
'keyword'
,
n
[
1
],
result
)
node
.
lineno
=
n
[
2
]
return
1
,
node
def
com_subscriptlist
(
self
,
primary
,
nodelist
,
assigning
):
# slicing: simple_slicing | extended_slicing
# simple_slicing: primary "[" short_slice "]"
# extended_slicing: primary "[" slice_list "]"
# slice_list: slice_item ("," slice_item)* [","]
# backwards compat slice for '[i:j]'
if
len
(
nodelist
)
==
2
:
sub
=
nodelist
[
1
]
if
(
sub
[
1
][
0
]
==
token
.
COLON
or
\
(
len
(
sub
)
>
2
and
sub
[
2
][
0
]
==
token
.
COLON
))
and
\
sub
[
-
1
][
0
]
!=
symbol
.
sliceop
:
return
self
.
com_slice
(
primary
,
sub
,
assigning
)
subscripts
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
subscripts
.
append
(
self
.
com_subscript
(
nodelist
[
i
]))
return
Node
(
'subscript'
,
primary
,
assigning
,
subscripts
)
def
com_subscript
(
self
,
node
):
# slice_item: expression | proper_slice | ellipsis
ch
=
node
[
1
]
if
ch
[
0
]
==
token
.
DOT
and
node
[
2
][
0
]
==
token
.
DOT
:
return
Node
(
'ellipsis'
)
if
ch
[
0
]
==
token
.
COLON
or
len
(
node
)
>
2
:
return
self
.
com_sliceobj
(
node
)
return
self
.
com_node
(
ch
)
def
com_sliceobj
(
self
,
node
):
# proper_slice: short_slice | long_slice
# short_slice: [lower_bound] ":" [upper_bound]
# long_slice: short_slice ":" [stride]
# lower_bound: expression
# upper_bound: expression
# stride: expression
#
# Note: a stride may be further slicing...
items
=
[
]
if
node
[
1
][
0
]
==
token
.
COLON
:
items
.
append
(
Node
(
'const'
,
None
))
i
=
2
else
:
items
.
append
(
self
.
com_node
(
node
[
1
]))
# i == 2 is a COLON
i
=
3
if
i
<
len
(
node
)
and
node
[
i
][
0
]
==
symbol
.
test
:
items
.
append
(
self
.
com_node
(
node
[
i
]))
i
=
i
+
1
else
:
items
.
append
(
Node
(
'const'
,
None
))
# a short_slice has been built. look for long_slice now by looking
# for strides...
for
j
in
range
(
i
,
len
(
node
)):
ch
=
node
[
j
]
if
len
(
ch
)
==
2
:
items
.
append
(
Node
(
'const'
,
None
))
else
:
items
.
append
(
self
.
com_node
(
ch
[
2
]))
return
Node
(
'sliceobj'
,
items
)
def
com_slice
(
self
,
primary
,
node
,
assigning
):
# short_slice: [lower_bound] ":" [upper_bound]
lower
=
upper
=
None
if
len
(
node
)
==
3
:
if
node
[
1
][
0
]
==
token
.
COLON
:
upper
=
self
.
com_node
(
node
[
2
])
else
:
lower
=
self
.
com_node
(
node
[
1
])
elif
len
(
node
)
==
4
:
lower
=
self
.
com_node
(
node
[
1
])
upper
=
self
.
com_node
(
node
[
3
])
return
Node
(
'slice'
,
primary
,
assigning
,
lower
,
upper
)
def
get_docstring
(
self
,
node
,
n
=
None
):
if
n
is
None
:
n
=
node
[
0
]
node
=
node
[
1
:]
if
n
==
symbol
.
suite
:
if
len
(
node
)
==
1
:
return
self
.
get_docstring
(
node
[
0
])
for
sub
in
node
:
if
sub
[
0
]
==
symbol
.
stmt
:
return
self
.
get_docstring
(
sub
)
return
None
if
n
==
symbol
.
file_input
:
for
sub
in
node
:
if
sub
[
0
]
==
symbol
.
stmt
:
return
self
.
get_docstring
(
sub
)
return
None
if
n
==
symbol
.
atom
:
if
node
[
0
][
0
]
==
token
.
STRING
:
s
=
''
for
t
in
node
:
s
=
s
+
eval
(
t
[
1
])
return
s
return
None
if
n
==
symbol
.
stmt
or
n
==
symbol
.
simple_stmt
or
n
==
symbol
.
small_stmt
:
return
self
.
get_docstring
(
node
[
0
])
if
n
in
_doc_nodes
and
len
(
node
)
==
1
:
return
self
.
get_docstring
(
node
[
0
])
return
None
_doc_nodes
=
[
symbol
.
expr_stmt
,
symbol
.
testlist
,
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
symbol
.
power
,
]
symbol
.
expr_stmt
,
symbol
.
testlist
,
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
symbol
.
power
,
]
# comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
# | 'in' | 'not' 'in' | 'is' | 'is' 'not'
_cmp_types
=
{
token
.
LESS
:
'<'
,
token
.
GREATER
:
'>'
,
token
.
EQEQUAL
:
'=='
,
token
.
EQUAL
:
'=='
,
token
.
LESSEQUAL
:
'<='
,
token
.
GREATEREQUAL
:
'>='
,
token
.
NOTEQUAL
:
'!='
,
}
token
.
LESS
:
'<'
,
token
.
GREATER
:
'>'
,
token
.
EQEQUAL
:
'=='
,
token
.
EQUAL
:
'=='
,
token
.
LESSEQUAL
:
'<='
,
token
.
GREATEREQUAL
:
'>='
,
token
.
NOTEQUAL
:
'!='
,
}
_legal_node_types
=
[
symbol
.
funcdef
,
symbol
.
classdef
,
symbol
.
stmt
,
symbol
.
small_stmt
,
symbol
.
flow_stmt
,
symbol
.
simple_stmt
,
symbol
.
compound_stmt
,
symbol
.
expr_stmt
,
symbol
.
print_stmt
,
symbol
.
del_stmt
,
symbol
.
pass_stmt
,
symbol
.
break_stmt
,
symbol
.
continue_stmt
,
symbol
.
return_stmt
,
symbol
.
raise_stmt
,
symbol
.
import_stmt
,
symbol
.
global_stmt
,
symbol
.
exec_stmt
,
symbol
.
assert_stmt
,
symbol
.
if_stmt
,
symbol
.
while_stmt
,
symbol
.
for_stmt
,
symbol
.
try_stmt
,
symbol
.
suite
,
symbol
.
testlist
,
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
exprlist
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
symbol
.
power
,
symbol
.
atom
,
]
symbol
.
funcdef
,
symbol
.
classdef
,
symbol
.
stmt
,
symbol
.
small_stmt
,
symbol
.
flow_stmt
,
symbol
.
simple_stmt
,
symbol
.
compound_stmt
,
symbol
.
expr_stmt
,
symbol
.
print_stmt
,
symbol
.
del_stmt
,
symbol
.
pass_stmt
,
symbol
.
break_stmt
,
symbol
.
continue_stmt
,
symbol
.
return_stmt
,
symbol
.
raise_stmt
,
symbol
.
import_stmt
,
symbol
.
global_stmt
,
symbol
.
exec_stmt
,
symbol
.
assert_stmt
,
symbol
.
if_stmt
,
symbol
.
while_stmt
,
symbol
.
for_stmt
,
symbol
.
try_stmt
,
symbol
.
suite
,
symbol
.
testlist
,
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
exprlist
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
symbol
.
power
,
symbol
.
atom
,
]
_assign_types
=
[
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
]
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
]
Tools/compiler/compiler/transformer.py
View file @
572bdce4
...
...
@@ -118,1135 +118,1133 @@ def parse(buf):
return
Transformer
().
parsesuite
(
buf
)
def
asList
(
nodes
):
l
=
[]
for
item
in
nodes
:
if
hasattr
(
item
,
"asList"
):
l
.
append
(
item
.
asList
())
else
:
if
type
(
item
)
is
type
(
(
None
,
None
)
):
l
.
append
(
tuple
(
asList
(
item
)))
elif
type
(
item
)
is
type
(
[]
):
l
.
append
(
asList
(
item
))
else
:
l
.
append
(
item
)
return
l
l
=
[]
for
item
in
nodes
:
if
hasattr
(
item
,
"asList"
):
l
.
append
(
item
.
asList
())
else
:
if
type
(
item
)
is
type
(
(
None
,
None
)
):
l
.
append
(
tuple
(
asList
(
item
)))
elif
type
(
item
)
is
type
(
[]
):
l
.
append
(
asList
(
item
))
else
:
l
.
append
(
item
)
return
l
def
Node
(
*
args
):
kind
=
args
[
0
]
if
ast
.
nodes
.
has_key
(
kind
):
try
:
return
apply
(
ast
.
nodes
[
kind
],
args
[
1
:])
except
TypeError
:
print
ast
.
nodes
[
kind
],
len
(
args
),
args
raise
else
:
raise
error
,
"Can't find appropriate Node type."
#return apply(ast.Node, args)
kind
=
args
[
0
]
if
ast
.
nodes
.
has_key
(
kind
):
try
:
return
apply
(
ast
.
nodes
[
kind
],
args
[
1
:])
except
TypeError
:
print
ast
.
nodes
[
kind
],
len
(
args
),
args
raise
else
:
raise
error
,
"Can't find appropriate Node type."
#return apply(ast.Node, args)
class
Transformer
:
"""Utility object for transforming Python parse trees.
Exposes the following methods:
tree = transform(ast_tree)
tree = parsesuite(text)
tree = parseexpr(text)
tree = parsefile(fileob | filename)
"""
def
__init__
(
self
):
self
.
_dispatch
=
{
}
for
value
,
name
in
symbol
.
sym_name
.
items
():
if
hasattr
(
self
,
name
):
self
.
_dispatch
[
value
]
=
getattr
(
self
,
name
)
def
transform
(
self
,
tree
):
"""Transform an AST into a modified parse tree."""
if
type
(
tree
)
!=
type
(())
and
type
(
tree
)
!=
type
([]):
tree
=
parser
.
ast2tuple
(
tree
,
1
)
return
self
.
compile_node
(
tree
)
def
parsesuite
(
self
,
text
):
"""Return a modified parse tree for the given suite text."""
# Hack for handling non-native line endings on non-DOS like OSs.
text
=
string
.
replace
(
text
,
'
\
x0d
'
,
''
)
return
self
.
transform
(
parser
.
suite
(
text
))
def
parseexpr
(
self
,
text
):
"""Return a modified parse tree for the given expression text."""
return
self
.
transform
(
parser
.
expr
(
text
))
def
parsefile
(
self
,
file
):
"""Return a modified parse tree for the contents of the given file."""
if
type
(
file
)
==
type
(
''
):
file
=
open
(
file
)
return
self
.
parsesuite
(
file
.
read
())
# --------------------------------------------------------------
#
# PRIVATE METHODS
#
def
compile_node
(
self
,
node
):
### emit a line-number node?
n
=
node
[
0
]
if
n
==
symbol
.
single_input
:
return
self
.
single_input
(
node
[
1
:])
if
n
==
symbol
.
file_input
:
return
self
.
file_input
(
node
[
1
:])
if
n
==
symbol
.
eval_input
:
return
self
.
eval_input
(
node
[
1
:])
if
n
==
symbol
.
lambdef
:
return
self
.
lambdef
(
node
[
1
:])
if
n
==
symbol
.
funcdef
:
return
self
.
funcdef
(
node
[
1
:])
if
n
==
symbol
.
classdef
:
return
self
.
classdef
(
node
[
1
:])
raise
error
,
(
'unexpected node type'
,
n
)
def
single_input
(
self
,
node
):
### do we want to do anything about being "interactive" ?
# NEWLINE | simple_stmt | compound_stmt NEWLINE
n
=
node
[
0
][
0
]
if
n
!=
token
.
NEWLINE
:
return
self
.
com_stmt
(
node
[
0
])
return
Node
(
'pass'
)
def
file_input
(
self
,
nodelist
):
doc
=
self
.
get_docstring
(
nodelist
,
symbol
.
file_input
)
stmts
=
[
]
for
node
in
nodelist
:
if
node
[
0
]
!=
token
.
ENDMARKER
and
node
[
0
]
!=
token
.
NEWLINE
:
self
.
com_append_stmt
(
stmts
,
node
)
return
Node
(
'module'
,
doc
,
Node
(
'stmt'
,
stmts
))
def
eval_input
(
self
,
nodelist
):
# from the built-in function input()
### is this sufficient?
return
self
.
com_node
(
nodelist
[
0
])
def
funcdef
(
self
,
nodelist
):
# funcdef: 'def' NAME parameters ':' suite
# parameters: '(' [varargslist] ')'
lineno
=
nodelist
[
1
][
2
]
name
=
nodelist
[
1
][
1
]
args
=
nodelist
[
2
][
2
]
if
args
[
0
]
==
symbol
.
varargslist
:
names
,
defaults
,
flags
=
self
.
com_arglist
(
args
[
1
:])
else
:
names
=
defaults
=
()
flags
=
0
doc
=
self
.
get_docstring
(
nodelist
[
4
])
"""Utility object for transforming Python parse trees.
Exposes the following methods:
tree = transform(ast_tree)
tree = parsesuite(text)
tree = parseexpr(text)
tree = parsefile(fileob | filename)
"""
def
__init__
(
self
):
self
.
_dispatch
=
{
}
for
value
,
name
in
symbol
.
sym_name
.
items
():
if
hasattr
(
self
,
name
):
self
.
_dispatch
[
value
]
=
getattr
(
self
,
name
)
def
transform
(
self
,
tree
):
"""Transform an AST into a modified parse tree."""
if
type
(
tree
)
!=
type
(())
and
type
(
tree
)
!=
type
([]):
tree
=
parser
.
ast2tuple
(
tree
,
1
)
return
self
.
compile_node
(
tree
)
def
parsesuite
(
self
,
text
):
"""Return a modified parse tree for the given suite text."""
# Hack for handling non-native line endings on non-DOS like OSs.
text
=
string
.
replace
(
text
,
'
\
x0d
'
,
''
)
return
self
.
transform
(
parser
.
suite
(
text
))
def
parseexpr
(
self
,
text
):
"""Return a modified parse tree for the given expression text."""
return
self
.
transform
(
parser
.
expr
(
text
))
def
parsefile
(
self
,
file
):
"""Return a modified parse tree for the contents of the given file."""
if
type
(
file
)
==
type
(
''
):
file
=
open
(
file
)
return
self
.
parsesuite
(
file
.
read
())
# --------------------------------------------------------------
#
# PRIVATE METHODS
#
# code for function
code
=
self
.
com_node
(
nodelist
[
4
])
def
compile_node
(
self
,
node
):
### emit a line-number node?
n
=
node
[
0
]
if
n
==
symbol
.
single_input
:
return
self
.
single_input
(
node
[
1
:])
if
n
==
symbol
.
file_input
:
return
self
.
file_input
(
node
[
1
:])
if
n
==
symbol
.
eval_input
:
return
self
.
eval_input
(
node
[
1
:])
if
n
==
symbol
.
lambdef
:
return
self
.
lambdef
(
node
[
1
:])
if
n
==
symbol
.
funcdef
:
return
self
.
funcdef
(
node
[
1
:])
if
n
==
symbol
.
classdef
:
return
self
.
classdef
(
node
[
1
:])
raise
error
,
(
'unexpected node type'
,
n
)
def
single_input
(
self
,
node
):
### do we want to do anything about being "interactive" ?
# NEWLINE | simple_stmt | compound_stmt NEWLINE
n
=
node
[
0
][
0
]
if
n
!=
token
.
NEWLINE
:
return
self
.
com_stmt
(
node
[
0
])
return
Node
(
'pass'
)
def
file_input
(
self
,
nodelist
):
doc
=
self
.
get_docstring
(
nodelist
,
symbol
.
file_input
)
stmts
=
[
]
for
node
in
nodelist
:
if
node
[
0
]
!=
token
.
ENDMARKER
and
node
[
0
]
!=
token
.
NEWLINE
:
self
.
com_append_stmt
(
stmts
,
node
)
return
Node
(
'module'
,
doc
,
Node
(
'stmt'
,
stmts
))
def
eval_input
(
self
,
nodelist
):
# from the built-in function input()
### is this sufficient?
return
self
.
com_node
(
nodelist
[
0
])
def
funcdef
(
self
,
nodelist
):
# funcdef: 'def' NAME parameters ':' suite
# parameters: '(' [varargslist] ')'
lineno
=
nodelist
[
1
][
2
]
name
=
nodelist
[
1
][
1
]
args
=
nodelist
[
2
][
2
]
if
args
[
0
]
==
symbol
.
varargslist
:
names
,
defaults
,
flags
=
self
.
com_arglist
(
args
[
1
:])
else
:
names
=
defaults
=
()
flags
=
0
doc
=
self
.
get_docstring
(
nodelist
[
4
])
n
=
Node
(
'function'
,
name
,
names
,
defaults
,
flags
,
doc
,
code
)
n
.
lineno
=
lineno
return
n
# code for function
code
=
self
.
com_node
(
nodelist
[
4
])
def
lambdef
(
self
,
nodelist
):
# lambdef: 'lambda' [varargslist] ':' test
if
nodelist
[
2
][
0
]
==
symbol
.
varargslist
:
names
,
defaults
,
flags
=
self
.
com_arglist
(
nodelist
[
2
][
1
:])
else
:
names
=
defaults
=
()
flags
=
0
n
=
Node
(
'function'
,
name
,
names
,
defaults
,
flags
,
doc
,
code
)
n
.
lineno
=
lineno
return
n
# code for lambda
code
=
self
.
com_node
(
nodelist
[
-
1
])
def
lambdef
(
self
,
nodelist
):
# lambdef: 'lambda' [varargslist] ':' test
if
nodelist
[
2
][
0
]
==
symbol
.
varargslist
:
names
,
defaults
,
flags
=
self
.
com_arglist
(
nodelist
[
2
][
1
:])
else
:
names
=
defaults
=
()
flags
=
0
n
=
Node
(
'lambda'
,
names
,
defaults
,
flags
,
code
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
# code for lambda
code
=
self
.
com_node
(
nodelist
[
-
1
])
def
classdef
(
self
,
nodelist
):
# classdef: 'class' NAME ['(' testlist ')'] ':' suite
n
=
Node
(
'lambda'
,
names
,
defaults
,
flags
,
code
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
name
=
nodelist
[
1
][
1
]
doc
=
self
.
get_docstring
(
nodelist
[
-
1
])
if
nodelist
[
2
][
0
]
==
token
.
COLON
:
bases
=
[]
else
:
bases
=
self
.
com_bases
(
nodelist
[
3
])
# code for class
code
=
self
.
com_node
(
nodelist
[
-
1
])
n
=
Node
(
'class'
,
name
,
bases
,
doc
,
code
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
def
stmt
(
self
,
nodelist
):
return
self
.
com_stmt
(
nodelist
[
0
])
small_stmt
=
stmt
flow_stmt
=
stmt
compound_stmt
=
stmt
def
simple_stmt
(
self
,
nodelist
):
# small_stmt (';' small_stmt)* [';'] NEWLINE
stmts
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
),
2
):
self
.
com_append_stmt
(
stmts
,
nodelist
[
i
])
return
Node
(
'stmt'
,
stmts
)
def
parameters
(
self
,
nodelist
):
raise
error
def
varargslist
(
self
,
nodelist
):
raise
error
def
fpdef
(
self
,
nodelist
):
raise
error
def
fplist
(
self
,
nodelist
):
raise
error
def
dotted_name
(
self
,
nodelist
):
raise
error
def
comp_op
(
self
,
nodelist
):
raise
error
def
trailer
(
self
,
nodelist
):
raise
error
def
sliceop
(
self
,
nodelist
):
raise
error
def
argument
(
self
,
nodelist
):
raise
error
# --------------------------------------------------------------
#
# STATEMENT NODES (invoked by com_node())
#
def
expr_stmt
(
self
,
nodelist
):
# testlist ('=' testlist)*
exprNode
=
self
.
com_node
(
nodelist
[
-
1
])
if
len
(
nodelist
)
==
1
:
return
Node
(
'discard'
,
exprNode
)
nodes
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
)
-
2
,
2
):
nodes
.
append
(
self
.
com_assign
(
nodelist
[
i
],
OP_ASSIGN
))
n
=
Node
(
'assign'
,
nodes
,
exprNode
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
def
print_stmt
(
self
,
nodelist
):
# print: (test ',')* [test]
items
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
items
.
append
(
self
.
com_node
(
nodelist
[
i
]))
if
nodelist
[
-
1
][
0
]
==
token
.
COMMA
:
n
=
Node
(
'print'
,
items
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
n
=
Node
(
'printnl'
,
items
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
del_stmt
(
self
,
nodelist
):
return
self
.
com_assign
(
nodelist
[
1
],
OP_DELETE
)
def
pass_stmt
(
self
,
nodelist
):
# pass:
n
=
Node
(
'pass'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
break_stmt
(
self
,
nodelist
):
# break:
n
=
Node
(
'break'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
continue_stmt
(
self
,
nodelist
):
# continue
n
=
Node
(
'continue'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
return_stmt
(
self
,
nodelist
):
# return: [testlist]
if
len
(
nodelist
)
<
2
:
n
=
Node
(
'return'
,
Node
(
'const'
,
None
))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
n
=
Node
(
'return'
,
self
.
com_node
(
nodelist
[
1
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
raise_stmt
(
self
,
nodelist
):
# raise: [test [',' test [',' test]]]
if
len
(
nodelist
)
>
5
:
expr3
=
self
.
com_node
(
nodelist
[
5
])
else
:
expr3
=
None
if
len
(
nodelist
)
>
3
:
expr2
=
self
.
com_node
(
nodelist
[
3
])
else
:
expr2
=
None
if
len
(
nodelist
)
>
1
:
expr1
=
self
.
com_node
(
nodelist
[
1
])
else
:
expr1
=
None
n
=
Node
(
'raise'
,
expr1
,
expr2
,
expr3
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
import_stmt
(
self
,
nodelist
):
# import_stmt: 'import' dotted_as_name (',' dotted_as_name)* |
# from: 'from' dotted_name 'import'
# ('*' | import_as_name (',' import_as_name)*)
names
=
[]
is_as
=
0
if
nodelist
[
0
][
1
]
==
'from'
:
for
i
in
range
(
3
,
len
(
nodelist
),
2
):
names
.
append
(
self
.
com_import_as_name
(
nodelist
[
i
][
1
]))
n
=
Node
(
'from'
,
self
.
com_dotted_name
(
nodelist
[
1
]),
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
names
.
append
(
self
.
com_dotted_as_name
(
nodelist
[
i
]))
n
=
Node
(
'import'
,
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
global_stmt
(
self
,
nodelist
):
# global: NAME (',' NAME)*
names
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
names
.
append
(
nodelist
[
i
][
1
])
n
=
Node
(
'global'
,
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
exec_stmt
(
self
,
nodelist
):
# exec_stmt: 'exec' expr ['in' expr [',' expr]]
expr1
=
self
.
com_node
(
nodelist
[
1
])
if
len
(
nodelist
)
>=
4
:
expr2
=
self
.
com_node
(
nodelist
[
3
])
if
len
(
nodelist
)
>=
6
:
expr3
=
self
.
com_node
(
nodelist
[
5
])
else
:
expr3
=
None
else
:
expr2
=
expr3
=
None
def
classdef
(
self
,
nodelist
):
# classdef: 'class' NAME ['(' testlist ')'] ':' suite
n
=
Node
(
'exec'
,
expr1
,
expr2
,
expr3
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
name
=
nodelist
[
1
][
1
]
doc
=
self
.
get_docstring
(
nodelist
[
-
1
])
if
nodelist
[
2
][
0
]
==
token
.
COLON
:
bases
=
[]
else
:
bases
=
self
.
com_bases
(
nodelist
[
3
])
def
assert_stmt
(
self
,
nodelist
):
# 'assert': test, [',' test]
expr1
=
self
.
com_node
(
nodelist
[
1
])
if
(
len
(
nodelist
)
==
4
):
expr2
=
self
.
com_node
(
nodelist
[
3
])
else
:
expr2
=
Node
(
'name'
,
'None'
)
n
=
Node
(
'assert'
,
expr1
,
expr2
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
if_stmt
(
self
,
nodelist
):
# if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
tests
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
)
-
3
,
4
):
testNode
=
self
.
com_node
(
nodelist
[
i
+
1
])
suiteNode
=
self
.
com_node
(
nodelist
[
i
+
3
])
tests
.
append
((
testNode
,
suiteNode
))
if
len
(
nodelist
)
%
4
==
3
:
elseNode
=
self
.
com_node
(
nodelist
[
-
1
])
## elseNode.lineno = nodelist[-1][1][2]
else
:
elseNode
=
None
n
=
Node
(
'if'
,
tests
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
# code for class
code
=
self
.
com_node
(
nodelist
[
-
1
])
def
while_stmt
(
self
,
nodelist
):
# 'while' test ':' suite ['else' ':' suite]
n
=
Node
(
'class'
,
name
,
bases
,
doc
,
code
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
testNode
=
self
.
com_node
(
nodelist
[
1
])
bodyNode
=
self
.
com_node
(
nodelist
[
3
])
def
stmt
(
self
,
nodelist
):
return
self
.
com_stmt
(
nodelist
[
0
])
if
len
(
nodelist
)
>
4
:
elseNode
=
self
.
com_node
(
nodelist
[
6
])
else
:
elseNode
=
None
small_stmt
=
stmt
flow_stmt
=
stmt
compound_stmt
=
stmt
n
=
Node
(
'while'
,
testNode
,
bodyNode
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
simple_stmt
(
self
,
nodelist
):
# small_stmt (';' small_stmt)* [';'] NEWLINE
stmts
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
),
2
):
self
.
com_append_stmt
(
stmts
,
nodelist
[
i
])
return
Node
(
'stmt'
,
stmts
)
def
for_stmt
(
self
,
nodelist
):
# 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
def
parameters
(
self
,
nodelist
):
raise
error
assignNode
=
self
.
com_assign
(
nodelist
[
1
],
OP_ASSIGN
)
listNode
=
self
.
com_node
(
nodelist
[
3
])
bodyNode
=
self
.
com_node
(
nodelist
[
5
])
def
varargslist
(
self
,
nodelist
):
raise
error
if
len
(
nodelist
)
>
8
:
elseNode
=
self
.
com_node
(
nodelist
[
8
])
else
:
elseNode
=
None
n
=
Node
(
'for'
,
assignNode
,
listNode
,
bodyNode
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
try_stmt
(
self
,
nodelist
):
# 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
# | 'try' ':' suite 'finally' ':' suite
if
nodelist
[
3
][
0
]
!=
symbol
.
except_clause
:
return
self
.
com_try_finally
(
nodelist
)
return
self
.
com_try_except
(
nodelist
)
def
suite
(
self
,
nodelist
):
# simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
if
len
(
nodelist
)
==
1
:
return
self
.
com_stmt
(
nodelist
[
0
])
stmts
=
[
]
for
node
in
nodelist
:
if
node
[
0
]
==
symbol
.
stmt
:
self
.
com_append_stmt
(
stmts
,
node
)
return
Node
(
'stmt'
,
stmts
)
# --------------------------------------------------------------
#
# EXPRESSION NODES (invoked by com_node())
#
def
testlist
(
self
,
nodelist
):
# testlist: expr (',' expr)* [',']
# exprlist: expr (',' expr)* [',']
return
self
.
com_binary
(
'tuple'
,
nodelist
)
exprlist
=
testlist
def
test
(
self
,
nodelist
):
# and_test ('or' and_test)* | lambdef
if
len
(
nodelist
)
==
1
and
nodelist
[
0
][
0
]
==
symbol
.
lambdef
:
return
self
.
lambdef
(
nodelist
[
0
])
return
self
.
com_binary
(
'or'
,
nodelist
)
def
and_test
(
self
,
nodelist
):
# not_test ('and' not_test)*
return
self
.
com_binary
(
'and'
,
nodelist
)
def
not_test
(
self
,
nodelist
):
# 'not' not_test | comparison
result
=
self
.
com_node
(
nodelist
[
-
1
])
if
len
(
nodelist
)
==
2
:
n
=
Node
(
'not'
,
result
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
result
def
comparison
(
self
,
nodelist
):
# comparison: expr (comp_op expr)*
node
=
self
.
com_node
(
nodelist
[
0
])
if
len
(
nodelist
)
==
1
:
return
node
results
=
[
]
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
nl
=
nodelist
[
i
-
1
]
# comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
# | 'in' | 'not' 'in' | 'is' | 'is' 'not'
n
=
nl
[
1
]
if
n
[
0
]
==
token
.
NAME
:
type
=
n
[
1
]
if
len
(
nl
)
==
3
:
if
type
==
'not'
:
type
=
'not in'
else
:
type
=
'is not'
else
:
type
=
_cmp_types
[
n
[
0
]]
lineno
=
nl
[
1
][
2
]
results
.
append
((
type
,
self
.
com_node
(
nodelist
[
i
])))
# we need a special "compare" node so that we can distinguish
# 3 < x < 5 from (3 < x) < 5
# the two have very different semantics and results (note that the
# latter form is always true)
n
=
Node
(
'compare'
,
node
,
results
)
n
.
lineno
=
lineno
return
n
def
expr
(
self
,
nodelist
):
# xor_expr ('|' xor_expr)*
return
self
.
com_binary
(
'bitor'
,
nodelist
)
def
xor_expr
(
self
,
nodelist
):
# xor_expr ('^' xor_expr)*
return
self
.
com_binary
(
'bitxor'
,
nodelist
)
def
and_expr
(
self
,
nodelist
):
# xor_expr ('&' xor_expr)*
return
self
.
com_binary
(
'bitand'
,
nodelist
)
def
shift_expr
(
self
,
nodelist
):
# shift_expr ('<<'|'>>' shift_expr)*
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
LEFTSHIFT
:
node
=
Node
(
'<<'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'>>'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
arith_expr
(
self
,
nodelist
):
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
PLUS
:
node
=
Node
(
'+'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'-'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
term
(
self
,
nodelist
):
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
STAR
:
node
=
Node
(
'*'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
elif
nodelist
[
i
-
1
][
0
]
==
token
.
SLASH
:
node
=
Node
(
'/'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'%'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
factor
(
self
,
nodelist
):
t
=
nodelist
[
0
][
0
]
node
=
self
.
com_node
(
nodelist
[
-
1
])
if
t
==
token
.
PLUS
:
node
=
Node
(
'unary+'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
elif
t
==
token
.
MINUS
:
node
=
Node
(
'unary-'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
elif
t
==
token
.
TILDE
:
node
=
Node
(
'invert'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
return
node
def
power
(
self
,
nodelist
):
# power: atom trailer* ('**' factor)*
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
1
,
len
(
nodelist
)):
if
nodelist
[
i
][
0
]
==
token
.
DOUBLESTAR
:
n
=
Node
(
'power'
,
[
node
,
self
.
com_node
(
nodelist
[
i
+
1
])])
n
.
lineno
=
nodelist
[
i
][
2
]
def
fpdef
(
self
,
nodelist
):
raise
error
def
fplist
(
self
,
nodelist
):
raise
error
def
dotted_name
(
self
,
nodelist
):
raise
error
def
comp_op
(
self
,
nodelist
):
raise
error
def
trailer
(
self
,
nodelist
):
raise
error
def
sliceop
(
self
,
nodelist
):
raise
error
def
argument
(
self
,
nodelist
):
raise
error
# --------------------------------------------------------------
#
# STATEMENT NODES (invoked by com_node())
#
def
expr_stmt
(
self
,
nodelist
):
# testlist ('=' testlist)*
exprNode
=
self
.
com_node
(
nodelist
[
-
1
])
if
len
(
nodelist
)
==
1
:
return
Node
(
'discard'
,
exprNode
)
nodes
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
)
-
2
,
2
):
nodes
.
append
(
self
.
com_assign
(
nodelist
[
i
],
OP_ASSIGN
))
n
=
Node
(
'assign'
,
nodes
,
exprNode
)
n
.
lineno
=
nodelist
[
1
][
2
]
return
n
node
=
self
.
com_apply_trailer
(
node
,
nodelist
[
i
])
def
print_stmt
(
self
,
nodelist
):
# print: (test ',')* [test]
items
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
items
.
append
(
self
.
com_node
(
nodelist
[
i
]))
if
nodelist
[
-
1
][
0
]
==
token
.
COMMA
:
n
=
Node
(
'print'
,
items
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
n
=
Node
(
'printnl'
,
items
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
node
def
del_stmt
(
self
,
nodelist
):
return
self
.
com_assign
(
nodelist
[
1
],
OP_DELETE
)
def
atom
(
self
,
nodelist
):
t
=
nodelist
[
0
][
0
]
if
t
==
token
.
LPAR
:
if
nodelist
[
1
][
0
]
==
token
.
RPAR
:
n
=
Node
(
'tuple'
,
())
def
pass_stmt
(
self
,
nodelist
):
# pass:
n
=
Node
(
'pass'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
self
.
com_node
(
nodelist
[
1
])
if
t
==
token
.
LSQB
:
if
nodelist
[
1
][
0
]
==
token
.
RSQB
:
n
=
Node
(
'
list'
,
()
)
def
break_stmt
(
self
,
nodelist
)
:
# break
:
n
=
Node
(
'
break'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
self
.
com_list_constructor
(
nodelist
[
1
])
if
t
==
token
.
LBRACE
:
if
nodelist
[
1
][
0
]
==
token
.
RBRACE
:
return
Node
(
'dict'
,
())
return
self
.
com_dictmaker
(
nodelist
[
1
])
if
t
==
token
.
BACKQUOTE
:
n
=
Node
(
'backquote'
,
self
.
com_node
(
nodelist
[
1
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
NUMBER
:
### need to verify this matches compile.c
k
=
eval
(
nodelist
[
0
][
1
])
n
=
Node
(
'const'
,
k
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
STRING
:
### need to verify this matches compile.c
k
=
''
for
node
in
nodelist
:
k
=
k
+
eval
(
node
[
1
])
n
=
Node
(
'const'
,
k
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
NAME
:
### any processing to do?
n
=
Node
(
'name'
,
nodelist
[
0
][
1
])
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
raise
error
,
"unknown node type"
# --------------------------------------------------------------
#
# INTERNAL PARSING UTILITIES
#
def
com_node
(
self
,
node
):
# Note: compile.c has handling in com_node for del_stmt, pass_stmt,
# break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
# and compound_stmt.
# We'll just dispatch them.
#
# A ';' at the end of a line can make a NEWLINE token appear here,
# Render it harmless. (genc discards ('discard', ('const', xxxx)) Nodes)
#
if
node
[
0
]
==
token
.
NEWLINE
:
return
Node
(
'discard'
,
Node
(
'const'
,
None
))
def
continue_stmt
(
self
,
nodelist
):
# continue
n
=
Node
(
'continue'
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
node
[
0
]
not
in
_legal_node_types
:
raise
error
,
'illegal node passed to com_node: %s'
%
node
[
0
]
def
return_stmt
(
self
,
nodelist
):
# return: [testlist]
if
len
(
nodelist
)
<
2
:
n
=
Node
(
'return'
,
Node
(
'const'
,
None
))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
n
=
Node
(
'return'
,
self
.
com_node
(
nodelist
[
1
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
# print "dispatch", self._dispatch[node[0]].__name__, node
return
self
.
_dispatch
[
node
[
0
]](
node
[
1
:])
def
com_arglist
(
self
,
nodelist
):
# varargslist:
# (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME]
# | fpdef ['=' test] (',' fpdef ['=' test])* [',']
# | ('**'|'*' '*') NAME)
# fpdef: NAME | '(' fplist ')'
# fplist: fpdef (',' fpdef)* [',']
names
=
[
]
defaults
=
[
]
flags
=
0
i
=
0
while
i
<
len
(
nodelist
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
token
.
STAR
or
node
[
0
]
==
token
.
DOUBLESTAR
:
if
node
[
0
]
==
token
.
STAR
:
node
=
nodelist
[
i
+
1
]
if
node
[
0
]
==
token
.
NAME
:
names
.
append
(
node
[
1
])
flags
=
flags
|
CO_VARARGS
i
=
i
+
3
if
i
<
len
(
nodelist
):
# should be DOUBLESTAR or STAR STAR
if
nodelist
[
i
][
0
]
==
token
.
DOUBLESTAR
:
node
=
nodelist
[
i
+
1
]
else
:
node
=
nodelist
[
i
+
2
]
names
.
append
(
node
[
1
])
flags
=
flags
|
CO_VARKEYWORDS
break
# fpdef: NAME | '(' fplist ')'
names
.
append
(
self
.
com_fpdef
(
node
))
i
=
i
+
1
if
i
>=
len
(
nodelist
):
break
if
nodelist
[
i
][
0
]
==
token
.
EQUAL
:
defaults
.
append
(
self
.
com_node
(
nodelist
[
i
+
1
]))
i
=
i
+
2
elif
len
(
defaults
):
# Treat "(a=1, b)" as "(a=1, b=None)"
defaults
.
append
(
Node
(
'const'
,
None
))
i
=
i
+
1
return
names
,
defaults
,
flags
def
com_fpdef
(
self
,
node
):
# fpdef: NAME | '(' fplist ')'
if
node
[
1
][
0
]
==
token
.
LPAR
:
return
self
.
com_fplist
(
node
[
2
])
return
node
[
1
][
1
]
def
com_fplist
(
self
,
node
):
# fplist: fpdef (',' fpdef)* [',']
if
len
(
node
)
==
2
:
return
self
.
com_fpdef
(
node
[
1
])
list
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
list
.
append
(
self
.
com_fpdef
(
node
[
i
]))
return
tuple
(
list
)
def
com_dotted_name
(
self
,
node
):
# String together the dotted names and return the string
name
=
""
for
n
in
node
:
if
type
(
n
)
==
type
(())
and
n
[
0
]
==
1
:
name
=
name
+
n
[
1
]
+
'.'
return
name
[:
-
1
]
def
com_dotted_as_name
(
self
,
node
):
dot
=
self
.
com_dotted_name
(
node
[
1
])
if
len
(
node
)
==
2
:
return
dot
,
None
assert
node
[
2
][
1
]
==
'as'
assert
node
[
3
][
0
]
==
token
.
NAME
return
dot
,
node
[
3
][
1
]
def
com_import_as_name
(
self
,
node
):
if
node
[
0
]
==
token
.
NAME
:
return
node
[
1
],
None
assert
len
(
node
)
==
4
assert
node
[
2
][
1
]
==
'as'
assert
node
[
3
][
0
]
==
token
.
NAME
return
node
[
1
][
1
],
node
[
3
][
1
]
def
com_bases
(
self
,
node
):
bases
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
bases
.
append
(
self
.
com_node
(
node
[
i
]))
return
bases
def
com_try_finally
(
self
,
nodelist
):
# try_fin_stmt: "try" ":" suite "finally" ":" suite
n
=
Node
(
'tryfinally'
,
self
.
com_node
(
nodelist
[
2
]),
self
.
com_node
(
nodelist
[
5
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
com_try_except
(
self
,
nodelist
):
# try_except: 'try' ':' suite (except_clause ':' suite)* ['else' suite]
#tryexcept: [TryNode, [except_clauses], elseNode)]
stmt
=
self
.
com_node
(
nodelist
[
2
])
clauses
=
[]
elseNode
=
None
for
i
in
range
(
3
,
len
(
nodelist
),
3
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
symbol
.
except_clause
:
# except_clause: 'except' [expr [',' expr]] */
if
len
(
node
)
>
2
:
expr1
=
self
.
com_node
(
node
[
2
])
if
len
(
node
)
>
4
:
expr2
=
self
.
com_assign
(
node
[
4
],
OP_ASSIGN
)
else
:
def
raise_stmt
(
self
,
nodelist
):
# raise: [test [',' test [',' test]]]
if
len
(
nodelist
)
>
5
:
expr3
=
self
.
com_node
(
nodelist
[
5
])
else
:
expr3
=
None
if
len
(
nodelist
)
>
3
:
expr2
=
self
.
com_node
(
nodelist
[
3
])
else
:
expr2
=
None
if
len
(
nodelist
)
>
1
:
expr1
=
self
.
com_node
(
nodelist
[
1
])
else
:
expr1
=
expr2
=
None
clauses
.
append
((
expr1
,
expr2
,
self
.
com_node
(
nodelist
[
i
+
2
])))
if
node
[
0
]
==
token
.
NAME
:
elseNode
=
self
.
com_node
(
nodelist
[
i
+
2
])
n
=
Node
(
'tryexcept'
,
self
.
com_node
(
nodelist
[
2
]),
clauses
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
com_assign
(
self
,
node
,
assigning
):
# return a node suitable for use as an "lvalue"
# loop to avoid trivial recursion
while
1
:
t
=
node
[
0
]
if
t
==
symbol
.
exprlist
or
t
==
symbol
.
testlist
:
if
len
(
node
)
>
2
:
return
self
.
com_assign_tuple
(
node
,
assigning
)
node
=
node
[
1
]
elif
t
in
_assign_types
:
if
len
(
node
)
>
2
:
raise
SyntaxError
,
"can't assign to operator"
node
=
node
[
1
]
elif
t
==
symbol
.
power
:
if
node
[
1
][
0
]
!=
symbol
.
atom
:
raise
SyntaxError
,
"can't assign to operator"
if
len
(
node
)
>
2
:
primary
=
self
.
com_node
(
node
[
1
])
for
i
in
range
(
2
,
len
(
node
)
-
1
):
ch
=
node
[
i
]
if
ch
[
0
]
==
token
.
DOUBLESTAR
:
raise
SyntaxError
,
"can't assign to operator"
primary
=
self
.
com_apply_trailer
(
primary
,
ch
)
return
self
.
com_assign_trailer
(
primary
,
node
[
-
1
],
assigning
)
node
=
node
[
1
]
elif
t
==
symbol
.
atom
:
t
=
node
[
1
][
0
]
if
t
==
token
.
LPAR
:
node
=
node
[
2
]
if
node
[
0
]
==
token
.
RPAR
:
raise
SyntaxError
,
"can't assign to ()"
elif
t
==
token
.
LSQB
:
node
=
node
[
2
]
if
node
[
0
]
==
token
.
RSQB
:
raise
SyntaxError
,
"can't assign to []"
return
self
.
com_assign_list
(
node
,
assigning
)
elif
t
==
token
.
NAME
:
return
self
.
com_assign_name
(
node
[
1
],
assigning
)
expr1
=
None
n
=
Node
(
'raise'
,
expr1
,
expr2
,
expr3
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
import_stmt
(
self
,
nodelist
):
# import_stmt: 'import' dotted_as_name (',' dotted_as_name)* |
# from: 'from' dotted_name 'import'
# ('*' | import_as_name (',' import_as_name)*)
names
=
[]
is_as
=
0
if
nodelist
[
0
][
1
]
==
'from'
:
for
i
in
range
(
3
,
len
(
nodelist
),
2
):
names
.
append
(
self
.
com_import_as_name
(
nodelist
[
i
][
1
]))
n
=
Node
(
'from'
,
self
.
com_dotted_name
(
nodelist
[
1
]),
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
names
.
append
(
self
.
com_dotted_as_name
(
nodelist
[
i
]))
n
=
Node
(
'import'
,
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
global_stmt
(
self
,
nodelist
):
# global: NAME (',' NAME)*
names
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
names
.
append
(
nodelist
[
i
][
1
])
n
=
Node
(
'global'
,
names
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
exec_stmt
(
self
,
nodelist
):
# exec_stmt: 'exec' expr ['in' expr [',' expr]]
expr1
=
self
.
com_node
(
nodelist
[
1
])
if
len
(
nodelist
)
>=
4
:
expr2
=
self
.
com_node
(
nodelist
[
3
])
if
len
(
nodelist
)
>=
6
:
expr3
=
self
.
com_node
(
nodelist
[
5
])
else
:
expr3
=
None
else
:
raise
SyntaxError
,
"can't assign to literal"
else
:
raise
SyntaxError
,
"bad assignment"
def
com_assign_tuple
(
self
,
node
,
assigning
):
assigns
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
assigns
.
append
(
self
.
com_assign
(
node
[
i
],
assigning
))
return
Node
(
'ass_tuple'
,
assigns
)
def
com_assign_list
(
self
,
node
,
assigning
):
assigns
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
assigns
.
append
(
self
.
com_assign
(
node
[
i
],
assigning
))
return
Node
(
'ass_list'
,
assigns
)
def
com_assign_name
(
self
,
node
,
assigning
):
n
=
Node
(
'ass_name'
,
node
[
1
],
assigning
)
n
.
lineno
=
node
[
2
]
return
n
def
com_assign_trailer
(
self
,
primary
,
node
,
assigning
):
t
=
node
[
1
][
0
]
if
t
==
token
.
LPAR
:
raise
SyntaxError
,
"can't assign to function call"
if
t
==
token
.
DOT
:
return
self
.
com_assign_attr
(
primary
,
node
[
2
],
assigning
)
if
t
==
token
.
LSQB
:
return
self
.
com_subscriptlist
(
primary
,
node
[
2
],
assigning
)
raise
SyntaxError
,
"unknown trailer type: %s"
%
t
def
com_assign_attr
(
self
,
primary
,
node
,
assigning
):
return
Node
(
'ass_attr'
,
primary
,
node
[
1
],
assigning
)
def
com_binary
(
self
,
type
,
nodelist
):
"Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
if
len
(
nodelist
)
==
1
:
return
self
.
com_node
(
nodelist
[
0
])
items
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
),
2
):
items
.
append
(
self
.
com_node
(
nodelist
[
i
]))
return
Node
(
type
,
items
)
def
com_stmt
(
self
,
node
):
#pprint.pprint(node)
result
=
self
.
com_node
(
node
)
try
:
result
[
0
]
except
:
print
node
[
0
]
if
result
[
0
]
==
'stmt'
:
return
result
return
Node
(
'stmt'
,
[
result
])
def
com_append_stmt
(
self
,
stmts
,
node
):
result
=
self
.
com_node
(
node
)
try
:
result
[
0
]
except
:
print
node
if
result
[
0
]
==
'stmt'
:
stmts
[
len
(
stmts
):]
=
result
[
1
]
else
:
stmts
.
append
(
result
)
def
com_list_constructor
(
self
,
nodelist
):
values
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
values
.
append
(
self
.
com_node
(
nodelist
[
i
]))
return
Node
(
'list'
,
values
)
def
com_dictmaker
(
self
,
nodelist
):
# dictmaker: test ':' test (',' test ':' value)* [',']
items
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
4
):
items
.
append
((
self
.
com_node
(
nodelist
[
i
]),
self
.
com_node
(
nodelist
[
i
+
2
])))
return
Node
(
'dict'
,
items
)
def
com_apply_trailer
(
self
,
primaryNode
,
nodelist
):
t
=
nodelist
[
1
][
0
]
if
t
==
token
.
LPAR
:
return
self
.
com_call_function
(
primaryNode
,
nodelist
[
2
])
if
t
==
token
.
DOT
:
return
self
.
com_select_member
(
primaryNode
,
nodelist
[
2
])
if
t
==
token
.
LSQB
:
return
self
.
com_subscriptlist
(
primaryNode
,
nodelist
[
2
],
OP_APPLY
)
raise
SyntaxError
,
'unknown node type: %s'
%
t
def
com_select_member
(
self
,
primaryNode
,
nodelist
):
if
nodelist
[
0
]
!=
token
.
NAME
:
raise
SyntaxError
,
"member must be a name"
n
=
Node
(
'getattr'
,
primaryNode
,
nodelist
[
1
])
n
.
lineno
=
nodelist
[
2
]
return
n
def
com_call_function
(
self
,
primaryNode
,
nodelist
):
if
nodelist
[
0
]
==
token
.
RPAR
:
return
Node
(
'call_func'
,
primaryNode
,
[
])
args
=
[
]
kw
=
0
len_nodelist
=
len
(
nodelist
)
for
i
in
range
(
1
,
len_nodelist
,
2
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
token
.
STAR
or
node
[
0
]
==
token
.
DOUBLESTAR
:
break
kw
,
result
=
self
.
com_argument
(
node
,
kw
)
args
.
append
(
result
)
else
:
i
=
i
+
1
# No broken by star arg, so skip the last one we processed.
if
i
<
len_nodelist
and
nodelist
[
i
][
0
]
==
token
.
COMMA
:
# need to accept an application that looks like "f(a, b,)"
i
=
i
+
1
star_node
=
dstar_node
=
None
while
i
<
len_nodelist
:
tok
=
nodelist
[
i
]
ch
=
nodelist
[
i
+
1
]
i
=
i
+
3
if
tok
[
0
]
==
token
.
STAR
:
if
star_node
is
not
None
:
raise
SyntaxError
,
'already have the varargs indentifier'
star_node
=
self
.
com_node
(
ch
)
elif
tok
[
0
]
==
token
.
DOUBLESTAR
:
if
dstar_node
is
not
None
:
raise
SyntaxError
,
'already have the kwargs indentifier'
dstar_node
=
self
.
com_node
(
ch
)
expr2
=
expr3
=
None
n
=
Node
(
'exec'
,
expr1
,
expr2
,
expr3
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
assert_stmt
(
self
,
nodelist
):
# 'assert': test, [',' test]
expr1
=
self
.
com_node
(
nodelist
[
1
])
if
(
len
(
nodelist
)
==
4
):
expr2
=
self
.
com_node
(
nodelist
[
3
])
else
:
expr2
=
Node
(
'name'
,
'None'
)
n
=
Node
(
'assert'
,
expr1
,
expr2
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
if_stmt
(
self
,
nodelist
):
# if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
tests
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
)
-
3
,
4
):
testNode
=
self
.
com_node
(
nodelist
[
i
+
1
])
suiteNode
=
self
.
com_node
(
nodelist
[
i
+
3
])
tests
.
append
((
testNode
,
suiteNode
))
if
len
(
nodelist
)
%
4
==
3
:
elseNode
=
self
.
com_node
(
nodelist
[
-
1
])
## elseNode.lineno = nodelist[-1][1][2]
else
:
elseNode
=
None
n
=
Node
(
'if'
,
tests
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
while_stmt
(
self
,
nodelist
):
# 'while' test ':' suite ['else' ':' suite]
testNode
=
self
.
com_node
(
nodelist
[
1
])
bodyNode
=
self
.
com_node
(
nodelist
[
3
])
if
len
(
nodelist
)
>
4
:
elseNode
=
self
.
com_node
(
nodelist
[
6
])
else
:
elseNode
=
None
n
=
Node
(
'while'
,
testNode
,
bodyNode
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
for_stmt
(
self
,
nodelist
):
# 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
assignNode
=
self
.
com_assign
(
nodelist
[
1
],
OP_ASSIGN
)
listNode
=
self
.
com_node
(
nodelist
[
3
])
bodyNode
=
self
.
com_node
(
nodelist
[
5
])
if
len
(
nodelist
)
>
8
:
elseNode
=
self
.
com_node
(
nodelist
[
8
])
else
:
raise
SyntaxError
,
'unknown node type: %s'
%
tok
return
Node
(
'call_func'
,
primaryNode
,
args
,
star_node
,
dstar_node
)
def
com_argument
(
self
,
nodelist
,
kw
):
if
len
(
nodelist
)
==
2
:
if
kw
:
raise
SyntaxError
,
"non-keyword arg after keyword arg"
return
0
,
self
.
com_node
(
nodelist
[
1
])
result
=
self
.
com_node
(
nodelist
[
3
])
n
=
nodelist
[
1
]
while
len
(
n
)
==
2
and
n
[
0
]
!=
token
.
NAME
:
n
=
n
[
1
]
if
n
[
0
]
!=
token
.
NAME
:
raise
SyntaxError
,
"keyword can't be an expression (%s)"
%
n
[
0
]
node
=
Node
(
'keyword'
,
n
[
1
],
result
)
node
.
lineno
=
n
[
2
]
return
1
,
node
def
com_subscriptlist
(
self
,
primary
,
nodelist
,
assigning
):
# slicing: simple_slicing | extended_slicing
# simple_slicing: primary "[" short_slice "]"
# extended_slicing: primary "[" slice_list "]"
# slice_list: slice_item ("," slice_item)* [","]
# backwards compat slice for '[i:j]'
if
len
(
nodelist
)
==
2
:
sub
=
nodelist
[
1
]
if
(
sub
[
1
][
0
]
==
token
.
COLON
or
\
(
len
(
sub
)
>
2
and
sub
[
2
][
0
]
==
token
.
COLON
))
and
\
sub
[
-
1
][
0
]
!=
symbol
.
sliceop
:
return
self
.
com_slice
(
primary
,
sub
,
assigning
)
subscripts
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
subscripts
.
append
(
self
.
com_subscript
(
nodelist
[
i
]))
return
Node
(
'subscript'
,
primary
,
assigning
,
subscripts
)
def
com_subscript
(
self
,
node
):
# slice_item: expression | proper_slice | ellipsis
ch
=
node
[
1
]
if
ch
[
0
]
==
token
.
DOT
and
node
[
2
][
0
]
==
token
.
DOT
:
return
Node
(
'ellipsis'
)
if
ch
[
0
]
==
token
.
COLON
or
len
(
node
)
>
2
:
return
self
.
com_sliceobj
(
node
)
return
self
.
com_node
(
ch
)
def
com_sliceobj
(
self
,
node
):
# proper_slice: short_slice | long_slice
# short_slice: [lower_bound] ":" [upper_bound]
# long_slice: short_slice ":" [stride]
# lower_bound: expression
# upper_bound: expression
# stride: expression
elseNode
=
None
n
=
Node
(
'for'
,
assignNode
,
listNode
,
bodyNode
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
try_stmt
(
self
,
nodelist
):
# 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
# | 'try' ':' suite 'finally' ':' suite
if
nodelist
[
3
][
0
]
!=
symbol
.
except_clause
:
return
self
.
com_try_finally
(
nodelist
)
return
self
.
com_try_except
(
nodelist
)
def
suite
(
self
,
nodelist
):
# simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
if
len
(
nodelist
)
==
1
:
return
self
.
com_stmt
(
nodelist
[
0
])
stmts
=
[
]
for
node
in
nodelist
:
if
node
[
0
]
==
symbol
.
stmt
:
self
.
com_append_stmt
(
stmts
,
node
)
return
Node
(
'stmt'
,
stmts
)
# --------------------------------------------------------------
#
# EXPRESSION NODES (invoked by com_node())
#
# Note: a stride may be further slicing...
items
=
[
]
def
testlist
(
self
,
nodelist
):
# testlist: expr (',' expr)* [',']
# exprlist: expr (',' expr)* [',']
return
self
.
com_binary
(
'tuple'
,
nodelist
)
exprlist
=
testlist
def
test
(
self
,
nodelist
):
# and_test ('or' and_test)* | lambdef
if
len
(
nodelist
)
==
1
and
nodelist
[
0
][
0
]
==
symbol
.
lambdef
:
return
self
.
lambdef
(
nodelist
[
0
])
return
self
.
com_binary
(
'or'
,
nodelist
)
def
and_test
(
self
,
nodelist
):
# not_test ('and' not_test)*
return
self
.
com_binary
(
'and'
,
nodelist
)
def
not_test
(
self
,
nodelist
):
# 'not' not_test | comparison
result
=
self
.
com_node
(
nodelist
[
-
1
])
if
len
(
nodelist
)
==
2
:
n
=
Node
(
'not'
,
result
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
result
def
comparison
(
self
,
nodelist
):
# comparison: expr (comp_op expr)*
node
=
self
.
com_node
(
nodelist
[
0
])
if
len
(
nodelist
)
==
1
:
return
node
results
=
[
]
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
nl
=
nodelist
[
i
-
1
]
# comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
# | 'in' | 'not' 'in' | 'is' | 'is' 'not'
n
=
nl
[
1
]
if
n
[
0
]
==
token
.
NAME
:
type
=
n
[
1
]
if
len
(
nl
)
==
3
:
if
type
==
'not'
:
type
=
'not in'
else
:
type
=
'is not'
else
:
type
=
_cmp_types
[
n
[
0
]]
lineno
=
nl
[
1
][
2
]
results
.
append
((
type
,
self
.
com_node
(
nodelist
[
i
])))
# we need a special "compare" node so that we can distinguish
# 3 < x < 5 from (3 < x) < 5
# the two have very different semantics and results (note that the
# latter form is always true)
n
=
Node
(
'compare'
,
node
,
results
)
n
.
lineno
=
lineno
return
n
if
node
[
1
][
0
]
==
token
.
COLON
:
items
.
append
(
Node
(
'const'
,
None
))
i
=
2
else
:
items
.
append
(
self
.
com_node
(
node
[
1
]))
# i == 2 is a COLON
i
=
3
def
expr
(
self
,
nodelist
):
# xor_expr ('|' xor_expr)*
return
self
.
com_binary
(
'bitor'
,
nodelist
)
def
xor_expr
(
self
,
nodelist
):
# xor_expr ('^' xor_expr)*
return
self
.
com_binary
(
'bitxor'
,
nodelist
)
def
and_expr
(
self
,
nodelist
):
# xor_expr ('&' xor_expr)*
return
self
.
com_binary
(
'bitand'
,
nodelist
)
def
shift_expr
(
self
,
nodelist
):
# shift_expr ('<<'|'>>' shift_expr)*
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
LEFTSHIFT
:
node
=
Node
(
'<<'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'>>'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
arith_expr
(
self
,
nodelist
):
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
PLUS
:
node
=
Node
(
'+'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'-'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
term
(
self
,
nodelist
):
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
2
,
len
(
nodelist
),
2
):
right
=
self
.
com_node
(
nodelist
[
i
])
if
nodelist
[
i
-
1
][
0
]
==
token
.
STAR
:
node
=
Node
(
'*'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
elif
nodelist
[
i
-
1
][
0
]
==
token
.
SLASH
:
node
=
Node
(
'/'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
else
:
node
=
Node
(
'%'
,
[
node
,
right
])
node
.
lineno
=
nodelist
[
1
][
2
]
return
node
def
factor
(
self
,
nodelist
):
t
=
nodelist
[
0
][
0
]
node
=
self
.
com_node
(
nodelist
[
-
1
])
if
t
==
token
.
PLUS
:
node
=
Node
(
'unary+'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
elif
t
==
token
.
MINUS
:
node
=
Node
(
'unary-'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
elif
t
==
token
.
TILDE
:
node
=
Node
(
'invert'
,
node
)
node
.
lineno
=
nodelist
[
0
][
2
]
return
node
def
power
(
self
,
nodelist
):
# power: atom trailer* ('**' factor)*
node
=
self
.
com_node
(
nodelist
[
0
])
for
i
in
range
(
1
,
len
(
nodelist
)):
if
nodelist
[
i
][
0
]
==
token
.
DOUBLESTAR
:
n
=
Node
(
'power'
,
[
node
,
self
.
com_node
(
nodelist
[
i
+
1
])])
n
.
lineno
=
nodelist
[
i
][
2
]
return
n
node
=
self
.
com_apply_trailer
(
node
,
nodelist
[
i
])
return
node
def
atom
(
self
,
nodelist
):
t
=
nodelist
[
0
][
0
]
if
t
==
token
.
LPAR
:
if
nodelist
[
1
][
0
]
==
token
.
RPAR
:
n
=
Node
(
'tuple'
,
())
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
self
.
com_node
(
nodelist
[
1
])
if
t
==
token
.
LSQB
:
if
nodelist
[
1
][
0
]
==
token
.
RSQB
:
n
=
Node
(
'list'
,
())
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
return
self
.
com_list_constructor
(
nodelist
[
1
])
if
t
==
token
.
LBRACE
:
if
nodelist
[
1
][
0
]
==
token
.
RBRACE
:
return
Node
(
'dict'
,
())
return
self
.
com_dictmaker
(
nodelist
[
1
])
if
t
==
token
.
BACKQUOTE
:
n
=
Node
(
'backquote'
,
self
.
com_node
(
nodelist
[
1
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
NUMBER
:
### need to verify this matches compile.c
k
=
eval
(
nodelist
[
0
][
1
])
n
=
Node
(
'const'
,
k
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
STRING
:
### need to verify this matches compile.c
k
=
''
for
node
in
nodelist
:
k
=
k
+
eval
(
node
[
1
])
n
=
Node
(
'const'
,
k
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
if
t
==
token
.
NAME
:
### any processing to do?
n
=
Node
(
'name'
,
nodelist
[
0
][
1
])
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
raise
error
,
"unknown node type"
# --------------------------------------------------------------
#
# INTERNAL PARSING UTILITIES
#
if
i
<
len
(
node
)
and
node
[
i
][
0
]
==
symbol
.
test
:
items
.
append
(
self
.
com_node
(
node
[
i
]))
i
=
i
+
1
else
:
items
.
append
(
Node
(
'const'
,
None
))
# a short_slice has been built. look for long_slice now by looking
# for strides...
for
j
in
range
(
i
,
len
(
node
)):
ch
=
node
[
j
]
if
len
(
ch
)
==
2
:
items
.
append
(
Node
(
'const'
,
None
))
else
:
items
.
append
(
self
.
com_node
(
ch
[
2
]))
return
Node
(
'sliceobj'
,
items
)
def
com_slice
(
self
,
primary
,
node
,
assigning
):
# short_slice: [lower_bound] ":" [upper_bound]
lower
=
upper
=
None
if
len
(
node
)
==
3
:
if
node
[
1
][
0
]
==
token
.
COLON
:
upper
=
self
.
com_node
(
node
[
2
])
else
:
lower
=
self
.
com_node
(
node
[
1
])
elif
len
(
node
)
==
4
:
lower
=
self
.
com_node
(
node
[
1
])
upper
=
self
.
com_node
(
node
[
3
])
return
Node
(
'slice'
,
primary
,
assigning
,
lower
,
upper
)
def
get_docstring
(
self
,
node
,
n
=
None
):
if
n
is
None
:
n
=
node
[
0
]
node
=
node
[
1
:]
if
n
==
symbol
.
suite
:
if
len
(
node
)
==
1
:
return
self
.
get_docstring
(
node
[
0
])
for
sub
in
node
:
if
sub
[
0
]
==
symbol
.
stmt
:
return
self
.
get_docstring
(
sub
)
return
None
if
n
==
symbol
.
file_input
:
for
sub
in
node
:
if
sub
[
0
]
==
symbol
.
stmt
:
return
self
.
get_docstring
(
sub
)
return
None
if
n
==
symbol
.
atom
:
if
node
[
0
][
0
]
==
token
.
STRING
:
s
=
''
for
t
in
node
:
s
=
s
+
eval
(
t
[
1
])
return
s
return
None
if
n
==
symbol
.
stmt
or
n
==
symbol
.
simple_stmt
or
n
==
symbol
.
small_stmt
:
return
self
.
get_docstring
(
node
[
0
])
if
n
in
_doc_nodes
and
len
(
node
)
==
1
:
return
self
.
get_docstring
(
node
[
0
])
return
None
def
com_node
(
self
,
node
):
# Note: compile.c has handling in com_node for del_stmt, pass_stmt,
# break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
# and compound_stmt.
# We'll just dispatch them.
#
# A ';' at the end of a line can make a NEWLINE token appear here,
# Render it harmless. (genc discards ('discard', ('const', xxxx)) Nodes)
#
if
node
[
0
]
==
token
.
NEWLINE
:
return
Node
(
'discard'
,
Node
(
'const'
,
None
))
if
node
[
0
]
not
in
_legal_node_types
:
raise
error
,
'illegal node passed to com_node: %s'
%
node
[
0
]
# print "dispatch", self._dispatch[node[0]].__name__, node
return
self
.
_dispatch
[
node
[
0
]](
node
[
1
:])
def
com_arglist
(
self
,
nodelist
):
# varargslist:
# (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME]
# | fpdef ['=' test] (',' fpdef ['=' test])* [',']
# | ('**'|'*' '*') NAME)
# fpdef: NAME | '(' fplist ')'
# fplist: fpdef (',' fpdef)* [',']
names
=
[
]
defaults
=
[
]
flags
=
0
i
=
0
while
i
<
len
(
nodelist
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
token
.
STAR
or
node
[
0
]
==
token
.
DOUBLESTAR
:
if
node
[
0
]
==
token
.
STAR
:
node
=
nodelist
[
i
+
1
]
if
node
[
0
]
==
token
.
NAME
:
names
.
append
(
node
[
1
])
flags
=
flags
|
CO_VARARGS
i
=
i
+
3
if
i
<
len
(
nodelist
):
# should be DOUBLESTAR or STAR STAR
if
nodelist
[
i
][
0
]
==
token
.
DOUBLESTAR
:
node
=
nodelist
[
i
+
1
]
else
:
node
=
nodelist
[
i
+
2
]
names
.
append
(
node
[
1
])
flags
=
flags
|
CO_VARKEYWORDS
break
# fpdef: NAME | '(' fplist ')'
names
.
append
(
self
.
com_fpdef
(
node
))
i
=
i
+
1
if
i
>=
len
(
nodelist
):
break
if
nodelist
[
i
][
0
]
==
token
.
EQUAL
:
defaults
.
append
(
self
.
com_node
(
nodelist
[
i
+
1
]))
i
=
i
+
2
elif
len
(
defaults
):
# Treat "(a=1, b)" as "(a=1, b=None)"
defaults
.
append
(
Node
(
'const'
,
None
))
i
=
i
+
1
return
names
,
defaults
,
flags
def
com_fpdef
(
self
,
node
):
# fpdef: NAME | '(' fplist ')'
if
node
[
1
][
0
]
==
token
.
LPAR
:
return
self
.
com_fplist
(
node
[
2
])
return
node
[
1
][
1
]
def
com_fplist
(
self
,
node
):
# fplist: fpdef (',' fpdef)* [',']
if
len
(
node
)
==
2
:
return
self
.
com_fpdef
(
node
[
1
])
list
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
list
.
append
(
self
.
com_fpdef
(
node
[
i
]))
return
tuple
(
list
)
def
com_dotted_name
(
self
,
node
):
# String together the dotted names and return the string
name
=
""
for
n
in
node
:
if
type
(
n
)
==
type
(())
and
n
[
0
]
==
1
:
name
=
name
+
n
[
1
]
+
'.'
return
name
[:
-
1
]
def
com_dotted_as_name
(
self
,
node
):
dot
=
self
.
com_dotted_name
(
node
[
1
])
if
len
(
node
)
==
2
:
return
dot
,
None
assert
node
[
2
][
1
]
==
'as'
assert
node
[
3
][
0
]
==
token
.
NAME
return
dot
,
node
[
3
][
1
]
def
com_import_as_name
(
self
,
node
):
if
node
[
0
]
==
token
.
NAME
:
return
node
[
1
],
None
assert
len
(
node
)
==
4
assert
node
[
2
][
1
]
==
'as'
assert
node
[
3
][
0
]
==
token
.
NAME
return
node
[
1
][
1
],
node
[
3
][
1
]
def
com_bases
(
self
,
node
):
bases
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
bases
.
append
(
self
.
com_node
(
node
[
i
]))
return
bases
def
com_try_finally
(
self
,
nodelist
):
# try_fin_stmt: "try" ":" suite "finally" ":" suite
n
=
Node
(
'tryfinally'
,
self
.
com_node
(
nodelist
[
2
]),
self
.
com_node
(
nodelist
[
5
]))
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
com_try_except
(
self
,
nodelist
):
# try_except: 'try' ':' suite (except_clause ':' suite)* ['else' suite]
#tryexcept: [TryNode, [except_clauses], elseNode)]
stmt
=
self
.
com_node
(
nodelist
[
2
])
clauses
=
[]
elseNode
=
None
for
i
in
range
(
3
,
len
(
nodelist
),
3
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
symbol
.
except_clause
:
# except_clause: 'except' [expr [',' expr]] */
if
len
(
node
)
>
2
:
expr1
=
self
.
com_node
(
node
[
2
])
if
len
(
node
)
>
4
:
expr2
=
self
.
com_assign
(
node
[
4
],
OP_ASSIGN
)
else
:
expr2
=
None
else
:
expr1
=
expr2
=
None
clauses
.
append
((
expr1
,
expr2
,
self
.
com_node
(
nodelist
[
i
+
2
])))
if
node
[
0
]
==
token
.
NAME
:
elseNode
=
self
.
com_node
(
nodelist
[
i
+
2
])
n
=
Node
(
'tryexcept'
,
self
.
com_node
(
nodelist
[
2
]),
clauses
,
elseNode
)
n
.
lineno
=
nodelist
[
0
][
2
]
return
n
def
com_assign
(
self
,
node
,
assigning
):
# return a node suitable for use as an "lvalue"
# loop to avoid trivial recursion
while
1
:
t
=
node
[
0
]
if
t
==
symbol
.
exprlist
or
t
==
symbol
.
testlist
:
if
len
(
node
)
>
2
:
return
self
.
com_assign_tuple
(
node
,
assigning
)
node
=
node
[
1
]
elif
t
in
_assign_types
:
if
len
(
node
)
>
2
:
raise
SyntaxError
,
"can't assign to operator"
node
=
node
[
1
]
elif
t
==
symbol
.
power
:
if
node
[
1
][
0
]
!=
symbol
.
atom
:
raise
SyntaxError
,
"can't assign to operator"
if
len
(
node
)
>
2
:
primary
=
self
.
com_node
(
node
[
1
])
for
i
in
range
(
2
,
len
(
node
)
-
1
):
ch
=
node
[
i
]
if
ch
[
0
]
==
token
.
DOUBLESTAR
:
raise
SyntaxError
,
"can't assign to operator"
primary
=
self
.
com_apply_trailer
(
primary
,
ch
)
return
self
.
com_assign_trailer
(
primary
,
node
[
-
1
],
assigning
)
node
=
node
[
1
]
elif
t
==
symbol
.
atom
:
t
=
node
[
1
][
0
]
if
t
==
token
.
LPAR
:
node
=
node
[
2
]
if
node
[
0
]
==
token
.
RPAR
:
raise
SyntaxError
,
"can't assign to ()"
elif
t
==
token
.
LSQB
:
node
=
node
[
2
]
if
node
[
0
]
==
token
.
RSQB
:
raise
SyntaxError
,
"can't assign to []"
return
self
.
com_assign_list
(
node
,
assigning
)
elif
t
==
token
.
NAME
:
return
self
.
com_assign_name
(
node
[
1
],
assigning
)
else
:
raise
SyntaxError
,
"can't assign to literal"
else
:
raise
SyntaxError
,
"bad assignment"
def
com_assign_tuple
(
self
,
node
,
assigning
):
assigns
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
assigns
.
append
(
self
.
com_assign
(
node
[
i
],
assigning
))
return
Node
(
'ass_tuple'
,
assigns
)
def
com_assign_list
(
self
,
node
,
assigning
):
assigns
=
[
]
for
i
in
range
(
1
,
len
(
node
),
2
):
assigns
.
append
(
self
.
com_assign
(
node
[
i
],
assigning
))
return
Node
(
'ass_list'
,
assigns
)
def
com_assign_name
(
self
,
node
,
assigning
):
n
=
Node
(
'ass_name'
,
node
[
1
],
assigning
)
n
.
lineno
=
node
[
2
]
return
n
def
com_assign_trailer
(
self
,
primary
,
node
,
assigning
):
t
=
node
[
1
][
0
]
if
t
==
token
.
LPAR
:
raise
SyntaxError
,
"can't assign to function call"
if
t
==
token
.
DOT
:
return
self
.
com_assign_attr
(
primary
,
node
[
2
],
assigning
)
if
t
==
token
.
LSQB
:
return
self
.
com_subscriptlist
(
primary
,
node
[
2
],
assigning
)
raise
SyntaxError
,
"unknown trailer type: %s"
%
t
def
com_assign_attr
(
self
,
primary
,
node
,
assigning
):
return
Node
(
'ass_attr'
,
primary
,
node
[
1
],
assigning
)
def
com_binary
(
self
,
type
,
nodelist
):
"Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
if
len
(
nodelist
)
==
1
:
return
self
.
com_node
(
nodelist
[
0
])
items
=
[
]
for
i
in
range
(
0
,
len
(
nodelist
),
2
):
items
.
append
(
self
.
com_node
(
nodelist
[
i
]))
return
Node
(
type
,
items
)
def
com_stmt
(
self
,
node
):
#pprint.pprint(node)
result
=
self
.
com_node
(
node
)
try
:
result
[
0
]
except
:
print
node
[
0
]
if
result
[
0
]
==
'stmt'
:
return
result
return
Node
(
'stmt'
,
[
result
])
def
com_append_stmt
(
self
,
stmts
,
node
):
result
=
self
.
com_node
(
node
)
try
:
result
[
0
]
except
:
print
node
if
result
[
0
]
==
'stmt'
:
stmts
[
len
(
stmts
):]
=
result
[
1
]
else
:
stmts
.
append
(
result
)
def
com_list_constructor
(
self
,
nodelist
):
values
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
values
.
append
(
self
.
com_node
(
nodelist
[
i
]))
return
Node
(
'list'
,
values
)
def
com_dictmaker
(
self
,
nodelist
):
# dictmaker: test ':' test (',' test ':' value)* [',']
items
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
4
):
items
.
append
((
self
.
com_node
(
nodelist
[
i
]),
self
.
com_node
(
nodelist
[
i
+
2
])))
return
Node
(
'dict'
,
items
)
def
com_apply_trailer
(
self
,
primaryNode
,
nodelist
):
t
=
nodelist
[
1
][
0
]
if
t
==
token
.
LPAR
:
return
self
.
com_call_function
(
primaryNode
,
nodelist
[
2
])
if
t
==
token
.
DOT
:
return
self
.
com_select_member
(
primaryNode
,
nodelist
[
2
])
if
t
==
token
.
LSQB
:
return
self
.
com_subscriptlist
(
primaryNode
,
nodelist
[
2
],
OP_APPLY
)
raise
SyntaxError
,
'unknown node type: %s'
%
t
def
com_select_member
(
self
,
primaryNode
,
nodelist
):
if
nodelist
[
0
]
!=
token
.
NAME
:
raise
SyntaxError
,
"member must be a name"
n
=
Node
(
'getattr'
,
primaryNode
,
nodelist
[
1
])
n
.
lineno
=
nodelist
[
2
]
return
n
def
com_call_function
(
self
,
primaryNode
,
nodelist
):
if
nodelist
[
0
]
==
token
.
RPAR
:
return
Node
(
'call_func'
,
primaryNode
,
[
])
args
=
[
]
kw
=
0
len_nodelist
=
len
(
nodelist
)
for
i
in
range
(
1
,
len_nodelist
,
2
):
node
=
nodelist
[
i
]
if
node
[
0
]
==
token
.
STAR
or
node
[
0
]
==
token
.
DOUBLESTAR
:
break
kw
,
result
=
self
.
com_argument
(
node
,
kw
)
args
.
append
(
result
)
else
:
i
=
i
+
1
# No broken by star arg, so skip the last one we processed.
if
i
<
len_nodelist
and
nodelist
[
i
][
0
]
==
token
.
COMMA
:
# need to accept an application that looks like "f(a, b,)"
i
=
i
+
1
star_node
=
dstar_node
=
None
while
i
<
len_nodelist
:
tok
=
nodelist
[
i
]
ch
=
nodelist
[
i
+
1
]
i
=
i
+
3
if
tok
[
0
]
==
token
.
STAR
:
if
star_node
is
not
None
:
raise
SyntaxError
,
'already have the varargs indentifier'
star_node
=
self
.
com_node
(
ch
)
elif
tok
[
0
]
==
token
.
DOUBLESTAR
:
if
dstar_node
is
not
None
:
raise
SyntaxError
,
'already have the kwargs indentifier'
dstar_node
=
self
.
com_node
(
ch
)
else
:
raise
SyntaxError
,
'unknown node type: %s'
%
tok
return
Node
(
'call_func'
,
primaryNode
,
args
,
star_node
,
dstar_node
)
def
com_argument
(
self
,
nodelist
,
kw
):
if
len
(
nodelist
)
==
2
:
if
kw
:
raise
SyntaxError
,
"non-keyword arg after keyword arg"
return
0
,
self
.
com_node
(
nodelist
[
1
])
result
=
self
.
com_node
(
nodelist
[
3
])
n
=
nodelist
[
1
]
while
len
(
n
)
==
2
and
n
[
0
]
!=
token
.
NAME
:
n
=
n
[
1
]
if
n
[
0
]
!=
token
.
NAME
:
raise
SyntaxError
,
"keyword can't be an expression (%s)"
%
n
[
0
]
node
=
Node
(
'keyword'
,
n
[
1
],
result
)
node
.
lineno
=
n
[
2
]
return
1
,
node
def
com_subscriptlist
(
self
,
primary
,
nodelist
,
assigning
):
# slicing: simple_slicing | extended_slicing
# simple_slicing: primary "[" short_slice "]"
# extended_slicing: primary "[" slice_list "]"
# slice_list: slice_item ("," slice_item)* [","]
# backwards compat slice for '[i:j]'
if
len
(
nodelist
)
==
2
:
sub
=
nodelist
[
1
]
if
(
sub
[
1
][
0
]
==
token
.
COLON
or
\
(
len
(
sub
)
>
2
and
sub
[
2
][
0
]
==
token
.
COLON
))
and
\
sub
[
-
1
][
0
]
!=
symbol
.
sliceop
:
return
self
.
com_slice
(
primary
,
sub
,
assigning
)
subscripts
=
[
]
for
i
in
range
(
1
,
len
(
nodelist
),
2
):
subscripts
.
append
(
self
.
com_subscript
(
nodelist
[
i
]))
return
Node
(
'subscript'
,
primary
,
assigning
,
subscripts
)
def
com_subscript
(
self
,
node
):
# slice_item: expression | proper_slice | ellipsis
ch
=
node
[
1
]
if
ch
[
0
]
==
token
.
DOT
and
node
[
2
][
0
]
==
token
.
DOT
:
return
Node
(
'ellipsis'
)
if
ch
[
0
]
==
token
.
COLON
or
len
(
node
)
>
2
:
return
self
.
com_sliceobj
(
node
)
return
self
.
com_node
(
ch
)
def
com_sliceobj
(
self
,
node
):
# proper_slice: short_slice | long_slice
# short_slice: [lower_bound] ":" [upper_bound]
# long_slice: short_slice ":" [stride]
# lower_bound: expression
# upper_bound: expression
# stride: expression
#
# Note: a stride may be further slicing...
items
=
[
]
if
node
[
1
][
0
]
==
token
.
COLON
:
items
.
append
(
Node
(
'const'
,
None
))
i
=
2
else
:
items
.
append
(
self
.
com_node
(
node
[
1
]))
# i == 2 is a COLON
i
=
3
if
i
<
len
(
node
)
and
node
[
i
][
0
]
==
symbol
.
test
:
items
.
append
(
self
.
com_node
(
node
[
i
]))
i
=
i
+
1
else
:
items
.
append
(
Node
(
'const'
,
None
))
# a short_slice has been built. look for long_slice now by looking
# for strides...
for
j
in
range
(
i
,
len
(
node
)):
ch
=
node
[
j
]
if
len
(
ch
)
==
2
:
items
.
append
(
Node
(
'const'
,
None
))
else
:
items
.
append
(
self
.
com_node
(
ch
[
2
]))
return
Node
(
'sliceobj'
,
items
)
def
com_slice
(
self
,
primary
,
node
,
assigning
):
# short_slice: [lower_bound] ":" [upper_bound]
lower
=
upper
=
None
if
len
(
node
)
==
3
:
if
node
[
1
][
0
]
==
token
.
COLON
:
upper
=
self
.
com_node
(
node
[
2
])
else
:
lower
=
self
.
com_node
(
node
[
1
])
elif
len
(
node
)
==
4
:
lower
=
self
.
com_node
(
node
[
1
])
upper
=
self
.
com_node
(
node
[
3
])
return
Node
(
'slice'
,
primary
,
assigning
,
lower
,
upper
)
def
get_docstring
(
self
,
node
,
n
=
None
):
if
n
is
None
:
n
=
node
[
0
]
node
=
node
[
1
:]
if
n
==
symbol
.
suite
:
if
len
(
node
)
==
1
:
return
self
.
get_docstring
(
node
[
0
])
for
sub
in
node
:
if
sub
[
0
]
==
symbol
.
stmt
:
return
self
.
get_docstring
(
sub
)
return
None
if
n
==
symbol
.
file_input
:
for
sub
in
node
:
if
sub
[
0
]
==
symbol
.
stmt
:
return
self
.
get_docstring
(
sub
)
return
None
if
n
==
symbol
.
atom
:
if
node
[
0
][
0
]
==
token
.
STRING
:
s
=
''
for
t
in
node
:
s
=
s
+
eval
(
t
[
1
])
return
s
return
None
if
n
==
symbol
.
stmt
or
n
==
symbol
.
simple_stmt
or
n
==
symbol
.
small_stmt
:
return
self
.
get_docstring
(
node
[
0
])
if
n
in
_doc_nodes
and
len
(
node
)
==
1
:
return
self
.
get_docstring
(
node
[
0
])
return
None
_doc_nodes
=
[
symbol
.
expr_stmt
,
symbol
.
testlist
,
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
symbol
.
power
,
]
symbol
.
expr_stmt
,
symbol
.
testlist
,
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
symbol
.
power
,
]
# comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
# | 'in' | 'not' 'in' | 'is' | 'is' 'not'
_cmp_types
=
{
token
.
LESS
:
'<'
,
token
.
GREATER
:
'>'
,
token
.
EQEQUAL
:
'=='
,
token
.
EQUAL
:
'=='
,
token
.
LESSEQUAL
:
'<='
,
token
.
GREATEREQUAL
:
'>='
,
token
.
NOTEQUAL
:
'!='
,
}
token
.
LESS
:
'<'
,
token
.
GREATER
:
'>'
,
token
.
EQEQUAL
:
'=='
,
token
.
EQUAL
:
'=='
,
token
.
LESSEQUAL
:
'<='
,
token
.
GREATEREQUAL
:
'>='
,
token
.
NOTEQUAL
:
'!='
,
}
_legal_node_types
=
[
symbol
.
funcdef
,
symbol
.
classdef
,
symbol
.
stmt
,
symbol
.
small_stmt
,
symbol
.
flow_stmt
,
symbol
.
simple_stmt
,
symbol
.
compound_stmt
,
symbol
.
expr_stmt
,
symbol
.
print_stmt
,
symbol
.
del_stmt
,
symbol
.
pass_stmt
,
symbol
.
break_stmt
,
symbol
.
continue_stmt
,
symbol
.
return_stmt
,
symbol
.
raise_stmt
,
symbol
.
import_stmt
,
symbol
.
global_stmt
,
symbol
.
exec_stmt
,
symbol
.
assert_stmt
,
symbol
.
if_stmt
,
symbol
.
while_stmt
,
symbol
.
for_stmt
,
symbol
.
try_stmt
,
symbol
.
suite
,
symbol
.
testlist
,
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
exprlist
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
symbol
.
power
,
symbol
.
atom
,
]
symbol
.
funcdef
,
symbol
.
classdef
,
symbol
.
stmt
,
symbol
.
small_stmt
,
symbol
.
flow_stmt
,
symbol
.
simple_stmt
,
symbol
.
compound_stmt
,
symbol
.
expr_stmt
,
symbol
.
print_stmt
,
symbol
.
del_stmt
,
symbol
.
pass_stmt
,
symbol
.
break_stmt
,
symbol
.
continue_stmt
,
symbol
.
return_stmt
,
symbol
.
raise_stmt
,
symbol
.
import_stmt
,
symbol
.
global_stmt
,
symbol
.
exec_stmt
,
symbol
.
assert_stmt
,
symbol
.
if_stmt
,
symbol
.
while_stmt
,
symbol
.
for_stmt
,
symbol
.
try_stmt
,
symbol
.
suite
,
symbol
.
testlist
,
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
exprlist
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
symbol
.
power
,
symbol
.
atom
,
]
_assign_types
=
[
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
]
symbol
.
test
,
symbol
.
and_test
,
symbol
.
not_test
,
symbol
.
comparison
,
symbol
.
expr
,
symbol
.
xor_expr
,
symbol
.
and_expr
,
symbol
.
shift_expr
,
symbol
.
arith_expr
,
symbol
.
term
,
symbol
.
factor
,
]
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