Commit 572bdce4 authored by Jeremy Hylton's avatar Jeremy Hylton

change 2-space indent to 4-space indent

parent 9c36a416
...@@ -118,1135 +118,1133 @@ def parse(buf): ...@@ -118,1135 +118,1133 @@ def parse(buf):
return Transformer().parsesuite(buf) return Transformer().parsesuite(buf)
def asList(nodes): def asList(nodes):
l = [] l = []
for item in nodes: for item in nodes:
if hasattr(item, "asList"): if hasattr(item, "asList"):
l.append(item.asList()) l.append(item.asList())
else: else:
if type(item) is type( (None, None) ): if type(item) is type( (None, None) ):
l.append(tuple(asList(item))) l.append(tuple(asList(item)))
elif type(item) is type( [] ): elif type(item) is type( [] ):
l.append(asList(item)) l.append(asList(item))
else: else:
l.append(item) l.append(item)
return l return l
def Node(*args): def Node(*args):
kind = args[0] kind = args[0]
if ast.nodes.has_key(kind): if ast.nodes.has_key(kind):
try: try:
return apply(ast.nodes[kind], args[1:]) return apply(ast.nodes[kind], args[1:])
except TypeError: except TypeError:
print ast.nodes[kind], len(args), args print ast.nodes[kind], len(args), args
raise raise
else: else:
raise error, "Can't find appropriate Node type." raise error, "Can't find appropriate Node type."
#return apply(ast.Node, args) #return apply(ast.Node, args)
class Transformer: class Transformer:
"""Utility object for transforming Python parse trees. """Utility object for transforming Python parse trees.
Exposes the following methods: Exposes the following methods:
tree = transform(ast_tree) tree = transform(ast_tree)
tree = parsesuite(text) tree = parsesuite(text)
tree = parseexpr(text) tree = parseexpr(text)
tree = parsefile(fileob | filename) tree = parsefile(fileob | filename)
""" """
def __init__(self): def __init__(self):
self._dispatch = { } self._dispatch = { }
for value, name in symbol.sym_name.items(): for value, name in symbol.sym_name.items():
if hasattr(self, name): if hasattr(self, name):
self._dispatch[value] = getattr(self, name) self._dispatch[value] = getattr(self, name)
def transform(self, tree): def transform(self, tree):
"""Transform an AST into a modified parse tree.""" """Transform an AST into a modified parse tree."""
if type(tree) != type(()) and type(tree) != type([]): if type(tree) != type(()) and type(tree) != type([]):
tree = parser.ast2tuple(tree,1) tree = parser.ast2tuple(tree,1)
return self.compile_node(tree) return self.compile_node(tree)
def parsesuite(self, text): def parsesuite(self, text):
"""Return a modified parse tree for the given suite text.""" """Return a modified parse tree for the given suite text."""
# Hack for handling non-native line endings on non-DOS like OSs. # Hack for handling non-native line endings on non-DOS like OSs.
text = string.replace(text, '\x0d', '') text = string.replace(text, '\x0d', '')
return self.transform(parser.suite(text)) return self.transform(parser.suite(text))
def parseexpr(self, text): def parseexpr(self, text):
"""Return a modified parse tree for the given expression text.""" """Return a modified parse tree for the given expression text."""
return self.transform(parser.expr(text)) return self.transform(parser.expr(text))
def parsefile(self, file): def parsefile(self, file):
"""Return a modified parse tree for the contents of the given file.""" """Return a modified parse tree for the contents of the given file."""
if type(file) == type(''): if type(file) == type(''):
file = open(file) file = open(file)
return self.parsesuite(file.read()) return self.parsesuite(file.read())
# -------------------------------------------------------------- # --------------------------------------------------------------
# #
# PRIVATE METHODS # 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])
# code for function def compile_node(self, node):
code = self.com_node(nodelist[4]) ### 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) # code for function
n.lineno = lineno code = self.com_node(nodelist[4])
return n
def lambdef(self, nodelist): n = Node('function', name, names, defaults, flags, doc, code)
# lambdef: 'lambda' [varargslist] ':' test n.lineno = lineno
if nodelist[2][0] == symbol.varargslist: return n
names, defaults, flags = self.com_arglist(nodelist[2][1:])
else:
names = defaults = ()
flags = 0
# code for lambda def lambdef(self, nodelist):
code = self.com_node(nodelist[-1]) # 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) # code for lambda
n.lineno = nodelist[1][2] code = self.com_node(nodelist[-1])
return n
def classdef(self, nodelist): n = Node('lambda', names, defaults, flags, code)
# classdef: 'class' NAME ['(' testlist ')'] ':' suite n.lineno = nodelist[1][2]
return n
name = nodelist[1][1] def classdef(self, nodelist):
doc = self.get_docstring(nodelist[-1]) # classdef: 'class' NAME ['(' testlist ')'] ':' suite
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
n = Node('exec', expr1, expr2, expr3) name = nodelist[1][1]
n.lineno = nodelist[0][2] doc = self.get_docstring(nodelist[-1])
return n if nodelist[2][0] == token.COLON:
bases = []
else:
bases = self.com_bases(nodelist[3])
def assert_stmt(self, nodelist): # code for class
# 'assert': test, [',' test] code = self.com_node(nodelist[-1])
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): n = Node('class', name, bases, doc, code)
# 'while' test ':' suite ['else' ':' suite] n.lineno = nodelist[1][2]
return n
testNode = self.com_node(nodelist[1]) def stmt(self, nodelist):
bodyNode = self.com_node(nodelist[3]) return self.com_stmt(nodelist[0])
if len(nodelist) > 4: small_stmt = stmt
elseNode = self.com_node(nodelist[6]) flow_stmt = stmt
else: compound_stmt = stmt
elseNode = None
n = Node('while', testNode, bodyNode, elseNode) def simple_stmt(self, nodelist):
n.lineno = nodelist[0][2] # small_stmt (';' small_stmt)* [';'] NEWLINE
return n 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): def parameters(self, nodelist):
# 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] raise error
assignNode = self.com_assign(nodelist[1], OP_ASSIGN) def varargslist(self, nodelist):
listNode = self.com_node(nodelist[3]) raise error
bodyNode = self.com_node(nodelist[5])
if len(nodelist) > 8: def fpdef(self, nodelist):
elseNode = self.com_node(nodelist[8]) raise error
else:
elseNode = None def fplist(self, nodelist):
raise error
n = Node('for', assignNode, listNode, bodyNode, elseNode)
n.lineno = nodelist[0][2] def dotted_name(self, nodelist):
return n raise error
def try_stmt(self, nodelist): def comp_op(self, nodelist):
# 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] raise error
# | 'try' ':' suite 'finally' ':' suite
if nodelist[3][0] != symbol.except_clause: def trailer(self, nodelist):
return self.com_try_finally(nodelist) raise error
return self.com_try_except(nodelist) def sliceop(self, nodelist):
raise error
def suite(self, nodelist):
# simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT def argument(self, nodelist):
if len(nodelist) == 1: raise error
return self.com_stmt(nodelist[0])
# --------------------------------------------------------------
stmts = [ ] #
for node in nodelist: # STATEMENT NODES (invoked by com_node())
if node[0] == symbol.stmt: #
self.com_append_stmt(stmts, node)
return Node('stmt', stmts) def expr_stmt(self, nodelist):
# testlist ('=' testlist)*
# -------------------------------------------------------------- exprNode = self.com_node(nodelist[-1])
# if len(nodelist) == 1:
# EXPRESSION NODES (invoked by com_node()) return Node('discard', exprNode)
# nodes = [ ]
for i in range(0, len(nodelist) - 2, 2):
def testlist(self, nodelist): nodes.append(self.com_assign(nodelist[i], OP_ASSIGN))
# testlist: expr (',' expr)* [','] n = Node('assign', nodes, exprNode)
# exprlist: expr (',' expr)* [','] n.lineno = nodelist[1][2]
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]
return n 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): def pass_stmt(self, nodelist):
t = nodelist[0][0] # pass:
if t == token.LPAR: n = Node('pass')
if nodelist[1][0] == token.RPAR:
n = Node('tuple', ())
n.lineno = nodelist[0][2] n.lineno = nodelist[0][2]
return n return n
return self.com_node(nodelist[1])
if t == token.LSQB: def break_stmt(self, nodelist):
if nodelist[1][0] == token.RSQB: # break:
n = Node('list', ()) n = Node('break')
n.lineno = nodelist[0][2] n.lineno = nodelist[0][2]
return n 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.
# def continue_stmt(self, nodelist):
# A ';' at the end of a line can make a NEWLINE token appear here, # continue
# Render it harmless. (genc discards ('discard', ('const', xxxx)) Nodes) n = Node('continue')
# n.lineno = nodelist[0][2]
if node[0] == token.NEWLINE: return n
return Node('discard', Node('const', None))
if node[0] not in _legal_node_types: def return_stmt(self, nodelist):
raise error, 'illegal node passed to com_node: %s' % node[0] # 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 def raise_stmt(self, nodelist):
return self._dispatch[node[0]](node[1:]) # raise: [test [',' test [',' test]]]
if len(nodelist) > 5:
def com_arglist(self, nodelist): expr3 = self.com_node(nodelist[5])
# varargslist: else:
# (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME] expr3 = None
# | fpdef ['=' test] (',' fpdef ['=' test])* [','] if len(nodelist) > 3:
# | ('**'|'*' '*') NAME) expr2 = self.com_node(nodelist[3])
# fpdef: NAME | '(' fplist ')' else:
# 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 expr2 = None
if len(nodelist) > 1:
expr1 = self.com_node(nodelist[1])
else: else:
expr1 = expr2 = None expr1 = None
clauses.append((expr1, expr2, self.com_node(nodelist[i+2]))) n = Node('raise', expr1, expr2, expr3)
n.lineno = nodelist[0][2]
if node[0] == token.NAME: return n
elseNode = self.com_node(nodelist[i+2])
n = Node('tryexcept', self.com_node(nodelist[2]), clauses, elseNode) def import_stmt(self, nodelist):
n.lineno = nodelist[0][2] # import_stmt: 'import' dotted_as_name (',' dotted_as_name)* |
return n # from: 'from' dotted_name 'import'
# ('*' | import_as_name (',' import_as_name)*)
def com_assign(self, node, assigning): names = []
# return a node suitable for use as an "lvalue" is_as = 0
# loop to avoid trivial recursion if nodelist[0][1] == 'from':
while 1: for i in range(3, len(nodelist), 2):
t = node[0] names.append(self.com_import_as_name(nodelist[i][1]))
if t == symbol.exprlist or t == symbol.testlist: n = Node('from', self.com_dotted_name(nodelist[1]), names)
if len(node) > 2: n.lineno = nodelist[0][2]
return self.com_assign_tuple(node, assigning) return n
node = node[1]
elif t in _assign_types: for i in range(1, len(nodelist), 2):
if len(node) > 2: names.append(self.com_dotted_as_name(nodelist[i]))
raise SyntaxError, "can't assign to operator" n = Node('import', names)
node = node[1] n.lineno = nodelist[0][2]
elif t == symbol.power: return n
if node[1][0] != symbol.atom:
raise SyntaxError, "can't assign to operator" def global_stmt(self, nodelist):
if len(node) > 2: # global: NAME (',' NAME)*
primary = self.com_node(node[1]) names = [ ]
for i in range(2, len(node)-1): for i in range(1, len(nodelist), 2):
ch = node[i] names.append(nodelist[i][1])
if ch[0] == token.DOUBLESTAR: n = Node('global', names)
raise SyntaxError, "can't assign to operator" n.lineno = nodelist[0][2]
primary = self.com_apply_trailer(primary, ch) return n
return self.com_assign_trailer(primary, node[-1], assigning)
node = node[1] def exec_stmt(self, nodelist):
elif t == symbol.atom: # exec_stmt: 'exec' expr ['in' expr [',' expr]]
t = node[1][0] expr1 = self.com_node(nodelist[1])
if t == token.LPAR: if len(nodelist) >= 4:
node = node[2] expr2 = self.com_node(nodelist[3])
if node[0] == token.RPAR: if len(nodelist) >= 6:
raise SyntaxError, "can't assign to ()" expr3 = self.com_node(nodelist[5])
elif t == token.LSQB: else:
node = node[2] expr3 = None
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: else:
raise SyntaxError, "can't assign to literal" expr2 = expr3 = None
else:
raise SyntaxError, "bad assignment" n = Node('exec', expr1, expr2, expr3)
n.lineno = nodelist[0][2]
def com_assign_tuple(self, node, assigning): return n
assigns = [ ]
for i in range(1, len(node), 2): def assert_stmt(self, nodelist):
assigns.append(self.com_assign(node[i], assigning)) # 'assert': test, [',' test]
return Node('ass_tuple', assigns) expr1 = self.com_node(nodelist[1])
if (len(nodelist) == 4):
def com_assign_list(self, node, assigning): expr2 = self.com_node(nodelist[3])
assigns = [ ] else:
for i in range(1, len(node), 2): expr2 = Node('name', 'None')
assigns.append(self.com_assign(node[i], assigning)) n = Node('assert', expr1, expr2)
return Node('ass_list', assigns) n.lineno = nodelist[0][2]
return n
def com_assign_name(self, node, assigning):
n = Node('ass_name', node[1], assigning) def if_stmt(self, nodelist):
n.lineno = node[2] # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
return n tests = [ ]
for i in range(0, len(nodelist) - 3, 4):
def com_assign_trailer(self, primary, node, assigning): testNode = self.com_node(nodelist[i + 1])
t = node[1][0] suiteNode = self.com_node(nodelist[i + 3])
if t == token.LPAR: tests.append((testNode, suiteNode))
raise SyntaxError, "can't assign to function call"
if t == token.DOT: if len(nodelist) % 4 == 3:
return self.com_assign_attr(primary, node[2], assigning) elseNode = self.com_node(nodelist[-1])
if t == token.LSQB: ## elseNode.lineno = nodelist[-1][1][2]
return self.com_subscriptlist(primary, node[2], assigning) else:
raise SyntaxError, "unknown trailer type: %s" % t elseNode = None
n = Node('if', tests, elseNode)
def com_assign_attr(self, primary, node, assigning): n.lineno = nodelist[0][2]
return Node('ass_attr', primary, node[1], assigning) return n
def com_binary(self, type, nodelist): def while_stmt(self, nodelist):
"Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])." # 'while' test ':' suite ['else' ':' suite]
if len(nodelist) == 1:
return self.com_node(nodelist[0]) testNode = self.com_node(nodelist[1])
items = [ ] bodyNode = self.com_node(nodelist[3])
for i in range(0, len(nodelist), 2):
items.append(self.com_node(nodelist[i])) if len(nodelist) > 4:
return Node(type, items) elseNode = self.com_node(nodelist[6])
else:
def com_stmt(self, node): elseNode = None
#pprint.pprint(node)
result = self.com_node(node) n = Node('while', testNode, bodyNode, elseNode)
try: n.lineno = nodelist[0][2]
result[0] return n
except:
print node[0] def for_stmt(self, nodelist):
if result[0] == 'stmt': # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
return result
return Node('stmt', [ result ]) assignNode = self.com_assign(nodelist[1], OP_ASSIGN)
listNode = self.com_node(nodelist[3])
def com_append_stmt(self, stmts, node): bodyNode = self.com_node(nodelist[5])
result = self.com_node(node)
try: if len(nodelist) > 8:
result[0] elseNode = self.com_node(nodelist[8])
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: else:
raise SyntaxError, 'unknown node type: %s' % tok elseNode = None
return Node('call_func', primaryNode, args, star_node, dstar_node) n = Node('for', assignNode, listNode, bodyNode, elseNode)
n.lineno = nodelist[0][2]
def com_argument(self, nodelist, kw): return n
if len(nodelist) == 2:
if kw: def try_stmt(self, nodelist):
raise SyntaxError, "non-keyword arg after keyword arg" # 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
return 0, self.com_node(nodelist[1]) # | 'try' ':' suite 'finally' ':' suite
result = self.com_node(nodelist[3]) if nodelist[3][0] != symbol.except_clause:
n = nodelist[1] return self.com_try_finally(nodelist)
while len(n) == 2 and n[0] != token.NAME:
n = n[1] return self.com_try_except(nodelist)
if n[0] != token.NAME:
raise SyntaxError, "keyword can't be an expression (%s)"%n[0] def suite(self, nodelist):
node = Node('keyword', n[1], result) # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
node.lineno = n[2] if len(nodelist) == 1:
return 1, node return self.com_stmt(nodelist[0])
def com_subscriptlist(self, primary, nodelist, assigning): stmts = [ ]
# slicing: simple_slicing | extended_slicing for node in nodelist:
# simple_slicing: primary "[" short_slice "]" if node[0] == symbol.stmt:
# extended_slicing: primary "[" slice_list "]" self.com_append_stmt(stmts, node)
# slice_list: slice_item ("," slice_item)* [","] return Node('stmt', stmts)
# backwards compat slice for '[i:j]' # --------------------------------------------------------------
if len(nodelist) == 2: #
sub = nodelist[1] # EXPRESSION NODES (invoked by com_node())
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 = [ ] 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: def expr(self, nodelist):
items.append(Node('const', None)) # xor_expr ('|' xor_expr)*
i = 2 return self.com_binary('bitor', nodelist)
else:
items.append(self.com_node(node[1])) def xor_expr(self, nodelist):
# i == 2 is a COLON # xor_expr ('^' xor_expr)*
i = 3 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: def com_node(self, node):
items.append(self.com_node(node[i])) # Note: compile.c has handling in com_node for del_stmt, pass_stmt,
i = i + 1 # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
else: # and compound_stmt.
items.append(Node('const', None)) # We'll just dispatch them.
# a short_slice has been built. look for long_slice now by looking #
# for strides... # A ';' at the end of a line can make a NEWLINE token appear here,
for j in range(i, len(node)): # Render it harmless. (genc discards ('discard', ('const', xxxx)) Nodes)
ch = node[j] #
if len(ch) == 2: if node[0] == token.NEWLINE:
items.append(Node('const', None)) return Node('discard', Node('const', None))
else:
items.append(self.com_node(ch[2])) if node[0] not in _legal_node_types:
raise error, 'illegal node passed to com_node: %s' % node[0]
return Node('sliceobj', items)
# print "dispatch", self._dispatch[node[0]].__name__, node
def com_slice(self, primary, node, assigning): return self._dispatch[node[0]](node[1:])
# short_slice: [lower_bound] ":" [upper_bound]
lower = upper = None def com_arglist(self, nodelist):
if len(node) == 3: # varargslist:
if node[1][0] == token.COLON: # (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME]
upper = self.com_node(node[2]) # | fpdef ['=' test] (',' fpdef ['=' test])* [',']
else: # | ('**'|'*' '*') NAME)
lower = self.com_node(node[1]) # fpdef: NAME | '(' fplist ')'
elif len(node) == 4: # fplist: fpdef (',' fpdef)* [',']
lower = self.com_node(node[1]) names = [ ]
upper = self.com_node(node[3]) defaults = [ ]
return Node('slice', primary, assigning, lower, upper) flags = 0
def get_docstring(self, node, n=None): i = 0
if n is None: while i < len(nodelist):
n = node[0] node = nodelist[i]
node = node[1:] if node[0] == token.STAR or node[0] == token.DOUBLESTAR:
if n == symbol.suite: if node[0] == token.STAR:
if len(node) == 1: node = nodelist[i+1]
return self.get_docstring(node[0]) if node[0] == token.NAME:
for sub in node: names.append(node[1])
if sub[0] == symbol.stmt: flags = flags | CO_VARARGS
return self.get_docstring(sub) i = i + 3
return None
if n == symbol.file_input: if i < len(nodelist):
for sub in node: # should be DOUBLESTAR or STAR STAR
if sub[0] == symbol.stmt: if nodelist[i][0] == token.DOUBLESTAR:
return self.get_docstring(sub) node = nodelist[i+1]
return None else:
if n == symbol.atom: node = nodelist[i+2]
if node[0][0] == token.STRING: names.append(node[1])
s = '' flags = flags | CO_VARKEYWORDS
for t in node:
s = s + eval(t[1]) break
return s
return None # fpdef: NAME | '(' fplist ')'
if n == symbol.stmt or n == symbol.simple_stmt or n == symbol.small_stmt: names.append(self.com_fpdef(node))
return self.get_docstring(node[0])
if n in _doc_nodes and len(node) == 1: i = i + 1
return self.get_docstring(node[0]) if i >= len(nodelist):
return None 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 = [ _doc_nodes = [
symbol.expr_stmt, symbol.expr_stmt,
symbol.testlist, symbol.testlist,
symbol.test, symbol.test,
symbol.and_test, symbol.and_test,
symbol.not_test, symbol.not_test,
symbol.comparison, symbol.comparison,
symbol.expr, symbol.expr,
symbol.xor_expr, symbol.xor_expr,
symbol.and_expr, symbol.and_expr,
symbol.shift_expr, symbol.shift_expr,
symbol.arith_expr, symbol.arith_expr,
symbol.term, symbol.term,
symbol.factor, symbol.factor,
symbol.power, symbol.power,
] ]
# comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '==' # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
# | 'in' | 'not' 'in' | 'is' | 'is' 'not' # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
_cmp_types = { _cmp_types = {
token.LESS : '<', token.LESS : '<',
token.GREATER : '>', token.GREATER : '>',
token.EQEQUAL : '==', token.EQEQUAL : '==',
token.EQUAL : '==', token.EQUAL : '==',
token.LESSEQUAL : '<=', token.LESSEQUAL : '<=',
token.GREATEREQUAL : '>=', token.GREATEREQUAL : '>=',
token.NOTEQUAL : '!=', token.NOTEQUAL : '!=',
} }
_legal_node_types = [ _legal_node_types = [
symbol.funcdef, symbol.funcdef,
symbol.classdef, symbol.classdef,
symbol.stmt, symbol.stmt,
symbol.small_stmt, symbol.small_stmt,
symbol.flow_stmt, symbol.flow_stmt,
symbol.simple_stmt, symbol.simple_stmt,
symbol.compound_stmt, symbol.compound_stmt,
symbol.expr_stmt, symbol.expr_stmt,
symbol.print_stmt, symbol.print_stmt,
symbol.del_stmt, symbol.del_stmt,
symbol.pass_stmt, symbol.pass_stmt,
symbol.break_stmt, symbol.break_stmt,
symbol.continue_stmt, symbol.continue_stmt,
symbol.return_stmt, symbol.return_stmt,
symbol.raise_stmt, symbol.raise_stmt,
symbol.import_stmt, symbol.import_stmt,
symbol.global_stmt, symbol.global_stmt,
symbol.exec_stmt, symbol.exec_stmt,
symbol.assert_stmt, symbol.assert_stmt,
symbol.if_stmt, symbol.if_stmt,
symbol.while_stmt, symbol.while_stmt,
symbol.for_stmt, symbol.for_stmt,
symbol.try_stmt, symbol.try_stmt,
symbol.suite, symbol.suite,
symbol.testlist, symbol.testlist,
symbol.test, symbol.test,
symbol.and_test, symbol.and_test,
symbol.not_test, symbol.not_test,
symbol.comparison, symbol.comparison,
symbol.exprlist, symbol.exprlist,
symbol.expr, symbol.expr,
symbol.xor_expr, symbol.xor_expr,
symbol.and_expr, symbol.and_expr,
symbol.shift_expr, symbol.shift_expr,
symbol.arith_expr, symbol.arith_expr,
symbol.term, symbol.term,
symbol.factor, symbol.factor,
symbol.power, symbol.power,
symbol.atom, symbol.atom,
] ]
_assign_types = [ _assign_types = [
symbol.test, symbol.test,
symbol.and_test, symbol.and_test,
symbol.not_test, symbol.not_test,
symbol.comparison, symbol.comparison,
symbol.expr, symbol.expr,
symbol.xor_expr, symbol.xor_expr,
symbol.and_expr, symbol.and_expr,
symbol.shift_expr, symbol.shift_expr,
symbol.arith_expr, symbol.arith_expr,
symbol.term, symbol.term,
symbol.factor, symbol.factor,
] ]
...@@ -118,1135 +118,1133 @@ def parse(buf): ...@@ -118,1135 +118,1133 @@ def parse(buf):
return Transformer().parsesuite(buf) return Transformer().parsesuite(buf)
def asList(nodes): def asList(nodes):
l = [] l = []
for item in nodes: for item in nodes:
if hasattr(item, "asList"): if hasattr(item, "asList"):
l.append(item.asList()) l.append(item.asList())
else: else:
if type(item) is type( (None, None) ): if type(item) is type( (None, None) ):
l.append(tuple(asList(item))) l.append(tuple(asList(item)))
elif type(item) is type( [] ): elif type(item) is type( [] ):
l.append(asList(item)) l.append(asList(item))
else: else:
l.append(item) l.append(item)
return l return l
def Node(*args): def Node(*args):
kind = args[0] kind = args[0]
if ast.nodes.has_key(kind): if ast.nodes.has_key(kind):
try: try:
return apply(ast.nodes[kind], args[1:]) return apply(ast.nodes[kind], args[1:])
except TypeError: except TypeError:
print ast.nodes[kind], len(args), args print ast.nodes[kind], len(args), args
raise raise
else: else:
raise error, "Can't find appropriate Node type." raise error, "Can't find appropriate Node type."
#return apply(ast.Node, args) #return apply(ast.Node, args)
class Transformer: class Transformer:
"""Utility object for transforming Python parse trees. """Utility object for transforming Python parse trees.
Exposes the following methods: Exposes the following methods:
tree = transform(ast_tree) tree = transform(ast_tree)
tree = parsesuite(text) tree = parsesuite(text)
tree = parseexpr(text) tree = parseexpr(text)
tree = parsefile(fileob | filename) tree = parsefile(fileob | filename)
""" """
def __init__(self): def __init__(self):
self._dispatch = { } self._dispatch = { }
for value, name in symbol.sym_name.items(): for value, name in symbol.sym_name.items():
if hasattr(self, name): if hasattr(self, name):
self._dispatch[value] = getattr(self, name) self._dispatch[value] = getattr(self, name)
def transform(self, tree): def transform(self, tree):
"""Transform an AST into a modified parse tree.""" """Transform an AST into a modified parse tree."""
if type(tree) != type(()) and type(tree) != type([]): if type(tree) != type(()) and type(tree) != type([]):
tree = parser.ast2tuple(tree,1) tree = parser.ast2tuple(tree,1)
return self.compile_node(tree) return self.compile_node(tree)
def parsesuite(self, text): def parsesuite(self, text):
"""Return a modified parse tree for the given suite text.""" """Return a modified parse tree for the given suite text."""
# Hack for handling non-native line endings on non-DOS like OSs. # Hack for handling non-native line endings on non-DOS like OSs.
text = string.replace(text, '\x0d', '') text = string.replace(text, '\x0d', '')
return self.transform(parser.suite(text)) return self.transform(parser.suite(text))
def parseexpr(self, text): def parseexpr(self, text):
"""Return a modified parse tree for the given expression text.""" """Return a modified parse tree for the given expression text."""
return self.transform(parser.expr(text)) return self.transform(parser.expr(text))
def parsefile(self, file): def parsefile(self, file):
"""Return a modified parse tree for the contents of the given file.""" """Return a modified parse tree for the contents of the given file."""
if type(file) == type(''): if type(file) == type(''):
file = open(file) file = open(file)
return self.parsesuite(file.read()) return self.parsesuite(file.read())
# -------------------------------------------------------------- # --------------------------------------------------------------
# #
# PRIVATE METHODS # 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])
# code for function def compile_node(self, node):
code = self.com_node(nodelist[4]) ### 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) # code for function
n.lineno = lineno code = self.com_node(nodelist[4])
return n
def lambdef(self, nodelist): n = Node('function', name, names, defaults, flags, doc, code)
# lambdef: 'lambda' [varargslist] ':' test n.lineno = lineno
if nodelist[2][0] == symbol.varargslist: return n
names, defaults, flags = self.com_arglist(nodelist[2][1:])
else:
names = defaults = ()
flags = 0
# code for lambda def lambdef(self, nodelist):
code = self.com_node(nodelist[-1]) # 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) # code for lambda
n.lineno = nodelist[1][2] code = self.com_node(nodelist[-1])
return n
def classdef(self, nodelist): n = Node('lambda', names, defaults, flags, code)
# classdef: 'class' NAME ['(' testlist ')'] ':' suite n.lineno = nodelist[1][2]
return n
name = nodelist[1][1] def classdef(self, nodelist):
doc = self.get_docstring(nodelist[-1]) # classdef: 'class' NAME ['(' testlist ')'] ':' suite
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
n = Node('exec', expr1, expr2, expr3) name = nodelist[1][1]
n.lineno = nodelist[0][2] doc = self.get_docstring(nodelist[-1])
return n if nodelist[2][0] == token.COLON:
bases = []
else:
bases = self.com_bases(nodelist[3])
def assert_stmt(self, nodelist): # code for class
# 'assert': test, [',' test] code = self.com_node(nodelist[-1])
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): n = Node('class', name, bases, doc, code)
# 'while' test ':' suite ['else' ':' suite] n.lineno = nodelist[1][2]
return n
testNode = self.com_node(nodelist[1]) def stmt(self, nodelist):
bodyNode = self.com_node(nodelist[3]) return self.com_stmt(nodelist[0])
if len(nodelist) > 4: small_stmt = stmt
elseNode = self.com_node(nodelist[6]) flow_stmt = stmt
else: compound_stmt = stmt
elseNode = None
n = Node('while', testNode, bodyNode, elseNode) def simple_stmt(self, nodelist):
n.lineno = nodelist[0][2] # small_stmt (';' small_stmt)* [';'] NEWLINE
return n 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): def parameters(self, nodelist):
# 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] raise error
assignNode = self.com_assign(nodelist[1], OP_ASSIGN) def varargslist(self, nodelist):
listNode = self.com_node(nodelist[3]) raise error
bodyNode = self.com_node(nodelist[5])
if len(nodelist) > 8: def fpdef(self, nodelist):
elseNode = self.com_node(nodelist[8]) raise error
else:
elseNode = None def fplist(self, nodelist):
raise error
n = Node('for', assignNode, listNode, bodyNode, elseNode)
n.lineno = nodelist[0][2] def dotted_name(self, nodelist):
return n raise error
def try_stmt(self, nodelist): def comp_op(self, nodelist):
# 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] raise error
# | 'try' ':' suite 'finally' ':' suite
if nodelist[3][0] != symbol.except_clause: def trailer(self, nodelist):
return self.com_try_finally(nodelist) raise error
return self.com_try_except(nodelist) def sliceop(self, nodelist):
raise error
def suite(self, nodelist):
# simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT def argument(self, nodelist):
if len(nodelist) == 1: raise error
return self.com_stmt(nodelist[0])
# --------------------------------------------------------------
stmts = [ ] #
for node in nodelist: # STATEMENT NODES (invoked by com_node())
if node[0] == symbol.stmt: #
self.com_append_stmt(stmts, node)
return Node('stmt', stmts) def expr_stmt(self, nodelist):
# testlist ('=' testlist)*
# -------------------------------------------------------------- exprNode = self.com_node(nodelist[-1])
# if len(nodelist) == 1:
# EXPRESSION NODES (invoked by com_node()) return Node('discard', exprNode)
# nodes = [ ]
for i in range(0, len(nodelist) - 2, 2):
def testlist(self, nodelist): nodes.append(self.com_assign(nodelist[i], OP_ASSIGN))
# testlist: expr (',' expr)* [','] n = Node('assign', nodes, exprNode)
# exprlist: expr (',' expr)* [','] n.lineno = nodelist[1][2]
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]
return n 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): def pass_stmt(self, nodelist):
t = nodelist[0][0] # pass:
if t == token.LPAR: n = Node('pass')
if nodelist[1][0] == token.RPAR:
n = Node('tuple', ())
n.lineno = nodelist[0][2] n.lineno = nodelist[0][2]
return n return n
return self.com_node(nodelist[1])
if t == token.LSQB: def break_stmt(self, nodelist):
if nodelist[1][0] == token.RSQB: # break:
n = Node('list', ()) n = Node('break')
n.lineno = nodelist[0][2] n.lineno = nodelist[0][2]
return n 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.
# def continue_stmt(self, nodelist):
# A ';' at the end of a line can make a NEWLINE token appear here, # continue
# Render it harmless. (genc discards ('discard', ('const', xxxx)) Nodes) n = Node('continue')
# n.lineno = nodelist[0][2]
if node[0] == token.NEWLINE: return n
return Node('discard', Node('const', None))
if node[0] not in _legal_node_types: def return_stmt(self, nodelist):
raise error, 'illegal node passed to com_node: %s' % node[0] # 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 def raise_stmt(self, nodelist):
return self._dispatch[node[0]](node[1:]) # raise: [test [',' test [',' test]]]
if len(nodelist) > 5:
def com_arglist(self, nodelist): expr3 = self.com_node(nodelist[5])
# varargslist: else:
# (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME] expr3 = None
# | fpdef ['=' test] (',' fpdef ['=' test])* [','] if len(nodelist) > 3:
# | ('**'|'*' '*') NAME) expr2 = self.com_node(nodelist[3])
# fpdef: NAME | '(' fplist ')' else:
# 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 expr2 = None
if len(nodelist) > 1:
expr1 = self.com_node(nodelist[1])
else: else:
expr1 = expr2 = None expr1 = None
clauses.append((expr1, expr2, self.com_node(nodelist[i+2]))) n = Node('raise', expr1, expr2, expr3)
n.lineno = nodelist[0][2]
if node[0] == token.NAME: return n
elseNode = self.com_node(nodelist[i+2])
n = Node('tryexcept', self.com_node(nodelist[2]), clauses, elseNode) def import_stmt(self, nodelist):
n.lineno = nodelist[0][2] # import_stmt: 'import' dotted_as_name (',' dotted_as_name)* |
return n # from: 'from' dotted_name 'import'
# ('*' | import_as_name (',' import_as_name)*)
def com_assign(self, node, assigning): names = []
# return a node suitable for use as an "lvalue" is_as = 0
# loop to avoid trivial recursion if nodelist[0][1] == 'from':
while 1: for i in range(3, len(nodelist), 2):
t = node[0] names.append(self.com_import_as_name(nodelist[i][1]))
if t == symbol.exprlist or t == symbol.testlist: n = Node('from', self.com_dotted_name(nodelist[1]), names)
if len(node) > 2: n.lineno = nodelist[0][2]
return self.com_assign_tuple(node, assigning) return n
node = node[1]
elif t in _assign_types: for i in range(1, len(nodelist), 2):
if len(node) > 2: names.append(self.com_dotted_as_name(nodelist[i]))
raise SyntaxError, "can't assign to operator" n = Node('import', names)
node = node[1] n.lineno = nodelist[0][2]
elif t == symbol.power: return n
if node[1][0] != symbol.atom:
raise SyntaxError, "can't assign to operator" def global_stmt(self, nodelist):
if len(node) > 2: # global: NAME (',' NAME)*
primary = self.com_node(node[1]) names = [ ]
for i in range(2, len(node)-1): for i in range(1, len(nodelist), 2):
ch = node[i] names.append(nodelist[i][1])
if ch[0] == token.DOUBLESTAR: n = Node('global', names)
raise SyntaxError, "can't assign to operator" n.lineno = nodelist[0][2]
primary = self.com_apply_trailer(primary, ch) return n
return self.com_assign_trailer(primary, node[-1], assigning)
node = node[1] def exec_stmt(self, nodelist):
elif t == symbol.atom: # exec_stmt: 'exec' expr ['in' expr [',' expr]]
t = node[1][0] expr1 = self.com_node(nodelist[1])
if t == token.LPAR: if len(nodelist) >= 4:
node = node[2] expr2 = self.com_node(nodelist[3])
if node[0] == token.RPAR: if len(nodelist) >= 6:
raise SyntaxError, "can't assign to ()" expr3 = self.com_node(nodelist[5])
elif t == token.LSQB: else:
node = node[2] expr3 = None
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: else:
raise SyntaxError, "can't assign to literal" expr2 = expr3 = None
else:
raise SyntaxError, "bad assignment" n = Node('exec', expr1, expr2, expr3)
n.lineno = nodelist[0][2]
def com_assign_tuple(self, node, assigning): return n
assigns = [ ]
for i in range(1, len(node), 2): def assert_stmt(self, nodelist):
assigns.append(self.com_assign(node[i], assigning)) # 'assert': test, [',' test]
return Node('ass_tuple', assigns) expr1 = self.com_node(nodelist[1])
if (len(nodelist) == 4):
def com_assign_list(self, node, assigning): expr2 = self.com_node(nodelist[3])
assigns = [ ] else:
for i in range(1, len(node), 2): expr2 = Node('name', 'None')
assigns.append(self.com_assign(node[i], assigning)) n = Node('assert', expr1, expr2)
return Node('ass_list', assigns) n.lineno = nodelist[0][2]
return n
def com_assign_name(self, node, assigning):
n = Node('ass_name', node[1], assigning) def if_stmt(self, nodelist):
n.lineno = node[2] # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
return n tests = [ ]
for i in range(0, len(nodelist) - 3, 4):
def com_assign_trailer(self, primary, node, assigning): testNode = self.com_node(nodelist[i + 1])
t = node[1][0] suiteNode = self.com_node(nodelist[i + 3])
if t == token.LPAR: tests.append((testNode, suiteNode))
raise SyntaxError, "can't assign to function call"
if t == token.DOT: if len(nodelist) % 4 == 3:
return self.com_assign_attr(primary, node[2], assigning) elseNode = self.com_node(nodelist[-1])
if t == token.LSQB: ## elseNode.lineno = nodelist[-1][1][2]
return self.com_subscriptlist(primary, node[2], assigning) else:
raise SyntaxError, "unknown trailer type: %s" % t elseNode = None
n = Node('if', tests, elseNode)
def com_assign_attr(self, primary, node, assigning): n.lineno = nodelist[0][2]
return Node('ass_attr', primary, node[1], assigning) return n
def com_binary(self, type, nodelist): def while_stmt(self, nodelist):
"Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])." # 'while' test ':' suite ['else' ':' suite]
if len(nodelist) == 1:
return self.com_node(nodelist[0]) testNode = self.com_node(nodelist[1])
items = [ ] bodyNode = self.com_node(nodelist[3])
for i in range(0, len(nodelist), 2):
items.append(self.com_node(nodelist[i])) if len(nodelist) > 4:
return Node(type, items) elseNode = self.com_node(nodelist[6])
else:
def com_stmt(self, node): elseNode = None
#pprint.pprint(node)
result = self.com_node(node) n = Node('while', testNode, bodyNode, elseNode)
try: n.lineno = nodelist[0][2]
result[0] return n
except:
print node[0] def for_stmt(self, nodelist):
if result[0] == 'stmt': # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
return result
return Node('stmt', [ result ]) assignNode = self.com_assign(nodelist[1], OP_ASSIGN)
listNode = self.com_node(nodelist[3])
def com_append_stmt(self, stmts, node): bodyNode = self.com_node(nodelist[5])
result = self.com_node(node)
try: if len(nodelist) > 8:
result[0] elseNode = self.com_node(nodelist[8])
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: else:
raise SyntaxError, 'unknown node type: %s' % tok elseNode = None
return Node('call_func', primaryNode, args, star_node, dstar_node) n = Node('for', assignNode, listNode, bodyNode, elseNode)
n.lineno = nodelist[0][2]
def com_argument(self, nodelist, kw): return n
if len(nodelist) == 2:
if kw: def try_stmt(self, nodelist):
raise SyntaxError, "non-keyword arg after keyword arg" # 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
return 0, self.com_node(nodelist[1]) # | 'try' ':' suite 'finally' ':' suite
result = self.com_node(nodelist[3]) if nodelist[3][0] != symbol.except_clause:
n = nodelist[1] return self.com_try_finally(nodelist)
while len(n) == 2 and n[0] != token.NAME:
n = n[1] return self.com_try_except(nodelist)
if n[0] != token.NAME:
raise SyntaxError, "keyword can't be an expression (%s)"%n[0] def suite(self, nodelist):
node = Node('keyword', n[1], result) # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
node.lineno = n[2] if len(nodelist) == 1:
return 1, node return self.com_stmt(nodelist[0])
def com_subscriptlist(self, primary, nodelist, assigning): stmts = [ ]
# slicing: simple_slicing | extended_slicing for node in nodelist:
# simple_slicing: primary "[" short_slice "]" if node[0] == symbol.stmt:
# extended_slicing: primary "[" slice_list "]" self.com_append_stmt(stmts, node)
# slice_list: slice_item ("," slice_item)* [","] return Node('stmt', stmts)
# backwards compat slice for '[i:j]' # --------------------------------------------------------------
if len(nodelist) == 2: #
sub = nodelist[1] # EXPRESSION NODES (invoked by com_node())
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 = [ ] 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: def expr(self, nodelist):
items.append(Node('const', None)) # xor_expr ('|' xor_expr)*
i = 2 return self.com_binary('bitor', nodelist)
else:
items.append(self.com_node(node[1])) def xor_expr(self, nodelist):
# i == 2 is a COLON # xor_expr ('^' xor_expr)*
i = 3 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: def com_node(self, node):
items.append(self.com_node(node[i])) # Note: compile.c has handling in com_node for del_stmt, pass_stmt,
i = i + 1 # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
else: # and compound_stmt.
items.append(Node('const', None)) # We'll just dispatch them.
# a short_slice has been built. look for long_slice now by looking #
# for strides... # A ';' at the end of a line can make a NEWLINE token appear here,
for j in range(i, len(node)): # Render it harmless. (genc discards ('discard', ('const', xxxx)) Nodes)
ch = node[j] #
if len(ch) == 2: if node[0] == token.NEWLINE:
items.append(Node('const', None)) return Node('discard', Node('const', None))
else:
items.append(self.com_node(ch[2])) if node[0] not in _legal_node_types:
raise error, 'illegal node passed to com_node: %s' % node[0]
return Node('sliceobj', items)
# print "dispatch", self._dispatch[node[0]].__name__, node
def com_slice(self, primary, node, assigning): return self._dispatch[node[0]](node[1:])
# short_slice: [lower_bound] ":" [upper_bound]
lower = upper = None def com_arglist(self, nodelist):
if len(node) == 3: # varargslist:
if node[1][0] == token.COLON: # (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME]
upper = self.com_node(node[2]) # | fpdef ['=' test] (',' fpdef ['=' test])* [',']
else: # | ('**'|'*' '*') NAME)
lower = self.com_node(node[1]) # fpdef: NAME | '(' fplist ')'
elif len(node) == 4: # fplist: fpdef (',' fpdef)* [',']
lower = self.com_node(node[1]) names = [ ]
upper = self.com_node(node[3]) defaults = [ ]
return Node('slice', primary, assigning, lower, upper) flags = 0
def get_docstring(self, node, n=None): i = 0
if n is None: while i < len(nodelist):
n = node[0] node = nodelist[i]
node = node[1:] if node[0] == token.STAR or node[0] == token.DOUBLESTAR:
if n == symbol.suite: if node[0] == token.STAR:
if len(node) == 1: node = nodelist[i+1]
return self.get_docstring(node[0]) if node[0] == token.NAME:
for sub in node: names.append(node[1])
if sub[0] == symbol.stmt: flags = flags | CO_VARARGS
return self.get_docstring(sub) i = i + 3
return None
if n == symbol.file_input: if i < len(nodelist):
for sub in node: # should be DOUBLESTAR or STAR STAR
if sub[0] == symbol.stmt: if nodelist[i][0] == token.DOUBLESTAR:
return self.get_docstring(sub) node = nodelist[i+1]
return None else:
if n == symbol.atom: node = nodelist[i+2]
if node[0][0] == token.STRING: names.append(node[1])
s = '' flags = flags | CO_VARKEYWORDS
for t in node:
s = s + eval(t[1]) break
return s
return None # fpdef: NAME | '(' fplist ')'
if n == symbol.stmt or n == symbol.simple_stmt or n == symbol.small_stmt: names.append(self.com_fpdef(node))
return self.get_docstring(node[0])
if n in _doc_nodes and len(node) == 1: i = i + 1
return self.get_docstring(node[0]) if i >= len(nodelist):
return None 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 = [ _doc_nodes = [
symbol.expr_stmt, symbol.expr_stmt,
symbol.testlist, symbol.testlist,
symbol.test, symbol.test,
symbol.and_test, symbol.and_test,
symbol.not_test, symbol.not_test,
symbol.comparison, symbol.comparison,
symbol.expr, symbol.expr,
symbol.xor_expr, symbol.xor_expr,
symbol.and_expr, symbol.and_expr,
symbol.shift_expr, symbol.shift_expr,
symbol.arith_expr, symbol.arith_expr,
symbol.term, symbol.term,
symbol.factor, symbol.factor,
symbol.power, symbol.power,
] ]
# comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '==' # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
# | 'in' | 'not' 'in' | 'is' | 'is' 'not' # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
_cmp_types = { _cmp_types = {
token.LESS : '<', token.LESS : '<',
token.GREATER : '>', token.GREATER : '>',
token.EQEQUAL : '==', token.EQEQUAL : '==',
token.EQUAL : '==', token.EQUAL : '==',
token.LESSEQUAL : '<=', token.LESSEQUAL : '<=',
token.GREATEREQUAL : '>=', token.GREATEREQUAL : '>=',
token.NOTEQUAL : '!=', token.NOTEQUAL : '!=',
} }
_legal_node_types = [ _legal_node_types = [
symbol.funcdef, symbol.funcdef,
symbol.classdef, symbol.classdef,
symbol.stmt, symbol.stmt,
symbol.small_stmt, symbol.small_stmt,
symbol.flow_stmt, symbol.flow_stmt,
symbol.simple_stmt, symbol.simple_stmt,
symbol.compound_stmt, symbol.compound_stmt,
symbol.expr_stmt, symbol.expr_stmt,
symbol.print_stmt, symbol.print_stmt,
symbol.del_stmt, symbol.del_stmt,
symbol.pass_stmt, symbol.pass_stmt,
symbol.break_stmt, symbol.break_stmt,
symbol.continue_stmt, symbol.continue_stmt,
symbol.return_stmt, symbol.return_stmt,
symbol.raise_stmt, symbol.raise_stmt,
symbol.import_stmt, symbol.import_stmt,
symbol.global_stmt, symbol.global_stmt,
symbol.exec_stmt, symbol.exec_stmt,
symbol.assert_stmt, symbol.assert_stmt,
symbol.if_stmt, symbol.if_stmt,
symbol.while_stmt, symbol.while_stmt,
symbol.for_stmt, symbol.for_stmt,
symbol.try_stmt, symbol.try_stmt,
symbol.suite, symbol.suite,
symbol.testlist, symbol.testlist,
symbol.test, symbol.test,
symbol.and_test, symbol.and_test,
symbol.not_test, symbol.not_test,
symbol.comparison, symbol.comparison,
symbol.exprlist, symbol.exprlist,
symbol.expr, symbol.expr,
symbol.xor_expr, symbol.xor_expr,
symbol.and_expr, symbol.and_expr,
symbol.shift_expr, symbol.shift_expr,
symbol.arith_expr, symbol.arith_expr,
symbol.term, symbol.term,
symbol.factor, symbol.factor,
symbol.power, symbol.power,
symbol.atom, symbol.atom,
] ]
_assign_types = [ _assign_types = [
symbol.test, symbol.test,
symbol.and_test, symbol.and_test,
symbol.not_test, symbol.not_test,
symbol.comparison, symbol.comparison,
symbol.expr, symbol.expr,
symbol.xor_expr, symbol.xor_expr,
symbol.and_expr, symbol.and_expr,
symbol.shift_expr, symbol.shift_expr,
symbol.arith_expr, symbol.arith_expr,
symbol.term, symbol.term,
symbol.factor, symbol.factor,
] ]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment