store_subscript precedence fix and...

Allow format specifier "%p" to indicate a nonterminal name,
like "%c" allows.

store_subscr -> store_subscript to match Python AST a little closer.
This commit is contained in:
rocky
2019-05-02 06:43:53 -04:00
parent 32bc017e2e
commit 293e7b0367
7 changed files with 127 additions and 94 deletions

View File

@@ -127,11 +127,17 @@ def test_tables():
"Full entry: %s" % "Full entry: %s" %
(name, k, arg, typ, entry[arg], type(entry[arg]), entry) (name, k, arg, typ, entry[arg], type(entry[arg]), entry)
) )
assert len(tup) == 2 assert 2 <= len(tup) <= 3
for j, x in enumerate(tup): for j, x in enumerate(tup):
assert isinstance(x, int), ( if len(tup) == 3 and j == 1:
"%s[%s][%d][%d] type '%s' is '%s should be an int but is %s. Full entry: %s" % assert isinstance(x, str), (
(name, k, arg, j, typ, x, type(x), entry) "%s[%s][%d][%d] type '%s' is '%s should be an string but is %s. Full entry: %s" %
(name, k, arg, j, typ, x, type(x), entry)
)
else:
assert isinstance(x, int), (
"%s[%s][%d][%d] type '%s' is '%s should be an int but is %s. Full entry: %s" %
(name, k, arg, j, typ, x, type(x), entry)
) )
pass pass
arg += 1 arg += 1

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,11 @@
# From 3.6.8 idlelib/query.py
# Bug was handling parens around subscript
# RUNNABLE!
a = {'text': 1}
b = {'text': 3}
for widget, entry, expect in (
(a, b, 1),
(None, b, 3)
):
assert (widget or entry)['text'] == expect

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2015-2018 Rocky Bernstein # Copyright (c) 2015-2019 Rocky Bernstein
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org> # Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com> # Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 1999 John Aycock # Copyright (c) 1999 John Aycock
@@ -589,14 +589,14 @@ class PythonParser(GenericASTBuilder):
## designLists ::= ## designLists ::=
## Will need to redo semantic actiion ## Will need to redo semantic actiion
store ::= STORE_FAST store ::= STORE_FAST
store ::= STORE_NAME store ::= STORE_NAME
store ::= STORE_GLOBAL store ::= STORE_GLOBAL
store ::= STORE_DEREF store ::= STORE_DEREF
store ::= expr STORE_ATTR store ::= expr STORE_ATTR
store ::= store_subscr store ::= store_subscript
store_subscr ::= expr expr STORE_SUBSCR store_subscript ::= expr expr STORE_SUBSCR
store ::= unpack store ::= unpack
''' '''

View File

@@ -27,6 +27,78 @@ else:
maxint = sys.maxint maxint = sys.maxint
# Operator precidence
# See https://docs.python.org/2/reference/expressions.html
# or https://docs.python.org/3/reference/expressions.html
# for a list.
# Things at the top of this list below with low-value precidence will
# tend to have parenthesis around them. Things at the bottom
# of the list will tend not to have parenthesis around them.
PRECEDENCE = {
'list': 0,
'dict': 0,
'unary_convert': 0,
'dict_comp': 0,
'set_comp': 0,
'set_comp_expr': 0,
'list_comp': 0,
'generator_exp': 0,
'attribute': 2,
'subscript': 2,
'subscript2': 2,
'store_subscript': 2,
'delete_subscr': 2,
'slice0': 2,
'slice1': 2,
'slice2': 2,
'slice3': 2,
'buildslice2': 2,
'buildslice3': 2,
'call': 2,
'BINARY_POWER': 4,
'unary_expr': 6,
'BINARY_MULTIPLY': 8,
'BINARY_DIVIDE': 8,
'BINARY_TRUE_DIVIDE': 8,
'BINARY_FLOOR_DIVIDE': 8,
'BINARY_MODULO': 8,
'BINARY_ADD': 10,
'BINARY_SUBTRACT': 10,
'BINARY_LSHIFT': 12,
'BINARY_RSHIFT': 12,
'BINARY_AND': 14,
'BINARY_XOR': 16,
'BINARY_OR': 18,
'compare': 20,
'unary_not': 22,
'and': 24,
'ret_and': 24,
'or': 26,
'ret_or': 26,
'conditional': 28,
'conditional_lamdba': 28,
'conditional_not_lamdba': 28,
'conditionalnot': 28,
'ret_cond': 28,
'ret_cond_not': 28,
'_mklambda': 30,
'yield': 101,
'yield_from': 101
}
LINE_LENGTH = 80 LINE_LENGTH = 80
# Some parse trees created below are used for comparing code # Some parse trees created below are used for comparing code
@@ -150,15 +222,17 @@ TABLE_DIRECT = {
'DELETE_FAST': ( '%|del %{pattr}\n', ), 'DELETE_FAST': ( '%|del %{pattr}\n', ),
'DELETE_NAME': ( '%|del %{pattr}\n', ), 'DELETE_NAME': ( '%|del %{pattr}\n', ),
'DELETE_GLOBAL': ( '%|del %{pattr}\n', ), 'DELETE_GLOBAL': ( '%|del %{pattr}\n', ),
'delete_subscr': ( '%|del %c[%c]\n', 'delete_subscr': ( '%|del %p[%c]\n',
(0, 'expr'), (1, 'expr') ), (0, 'expr', PRECEDENCE['subscript']), (1, 'expr') ),
'subscript': ( '%c[%p]', 'subscript': ( '%p[%c]',
(0, 'expr'), (0, 'expr', PRECEDENCE['subscript']),
(1, 100) ),
'subscript2': ( '%c[%c]',
(0, 'expr'),
(1, 'expr') ), (1, 'expr') ),
'store_subscr': ( '%c[%c]', 0, 1), 'subscript2': ( '%p[%c]',
(0, 'expr', PRECEDENCE['subscript']),
(1, 'expr') ),
'store_subscript': ( '%p[%c]',
(0, 'expr', PRECEDENCE['subscript']),
(1, 'expr') ),
'STORE_FAST': ( '%{pattr}', ), 'STORE_FAST': ( '%{pattr}', ),
'STORE_NAME': ( '%{pattr}', ), 'STORE_NAME': ( '%{pattr}', ),
'STORE_GLOBAL': ( '%{pattr}', ), 'STORE_GLOBAL': ( '%{pattr}', ),
@@ -337,76 +411,6 @@ MAP = {
'exprlist': MAP_R0, 'exprlist': MAP_R0,
} }
# Operator precidence
# See https://docs.python.org/2/reference/expressions.html
# or https://docs.python.org/3/reference/expressions.html
# for a list.
# Things at the top of this list below with low-value precidence will
# tend to have parenthesis around them. Things at the bottom
# of the list will tend not to have parenthesis around them.
PRECEDENCE = {
'list': 0,
'dict': 0,
'unary_convert': 0,
'dict_comp': 0,
'set_comp': 0,
'set_comp_expr': 0,
'list_comp': 0,
'generator_exp': 0,
'attribute': 2,
'subscript': 2,
'subscript2': 2,
'slice0': 2,
'slice1': 2,
'slice2': 2,
'slice3': 2,
'buildslice2': 2,
'buildslice3': 2,
'call': 2,
'BINARY_POWER': 4,
'unary_expr': 6,
'BINARY_MULTIPLY': 8,
'BINARY_DIVIDE': 8,
'BINARY_TRUE_DIVIDE': 8,
'BINARY_FLOOR_DIVIDE': 8,
'BINARY_MODULO': 8,
'BINARY_ADD': 10,
'BINARY_SUBTRACT': 10,
'BINARY_LSHIFT': 12,
'BINARY_RSHIFT': 12,
'BINARY_AND': 14,
'BINARY_XOR': 16,
'BINARY_OR': 18,
'compare': 20,
'unary_not': 22,
'and': 24,
'ret_and': 24,
'or': 26,
'ret_or': 26,
'conditional': 28,
'conditional_lamdba': 28,
'conditional_not_lamdba': 28,
'conditionalnot': 28,
'ret_cond': 28,
'ret_cond_not': 28,
'_mklambda': 30,
'yield': 101,
'yield_from': 101
}
ASSIGN_TUPLE_PARAM = lambda param_name: \ ASSIGN_TUPLE_PARAM = lambda param_name: \
SyntaxTree('expr', [ Token('LOAD_FAST', pattr=param_name) ]) SyntaxTree('expr', [ Token('LOAD_FAST', pattr=param_name) ])

View File

@@ -88,7 +88,8 @@ Python.
# #
# %p like %c but sets the operator precedence. # %p like %c but sets the operator precedence.
# Its argument then is a tuple indicating the node # Its argument then is a tuple indicating the node
# index and the precidence value, an integer. # index and the precedence value, an integer. If 3 items are given,
# the second item is the nonterminal name and the precedence is given last.
# #
# %C evaluate children recursively, with sibling children separated by the # %C evaluate children recursively, with sibling children separated by the
# given string. It needs a 3-tuple: a starting node, the maximimum # given string. It needs a 3-tuple: a starting node, the maximimum
@@ -616,7 +617,7 @@ class SourceWalker(GenericASTTraversal, object):
node[-2][0].kind = 'build_tuple2' node[-2][0].kind = 'build_tuple2'
self.default(node) self.default(node)
n_store_subscr = n_subscript = n_delete_subscr n_store_subscript = n_subscript = n_delete_subscr
# Note: this node is only in Python 2.x # Note: this node is only in Python 2.x
# FIXME: figure out how to get this into customization # FIXME: figure out how to get this into customization
@@ -1873,7 +1874,18 @@ class SourceWalker(GenericASTTraversal, object):
arg += 1 arg += 1
elif typ == 'p': elif typ == 'p':
p = self.prec p = self.prec
(index, self.prec) = entry[arg] tup = entry[arg]
assert isinstance(tup, tuple)
if len(tup) == 3:
(index, nonterm_name, self.prec) = tup
assert node[index] == nonterm_name, (
"at %s[%d], expected '%s' node; got '%s'" % (
node.kind, arg, nonterm_name, node[index].kind)
)
else:
assert len(tup) == 2
(index, self.prec) = entry[arg]
self.preorder(node[index]) self.preorder(node[index])
self.prec = p self.prec = p
arg += 1 arg += 1