Handle if not else in lambdas...

Fixes #170
This commit is contained in:
rocky
2018-04-25 12:57:09 -04:00
parent 0154c87d63
commit 41a50b5e46
17 changed files with 99 additions and 67 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -2,7 +2,8 @@
# lambda's have to be more or less on a line
f = lambda x: 1 if x<2 else 3
f(5)
assert f(3) == 3
assert f(1) == 1
# If that wasn't enough ...
# Python will create dead code
@@ -10,10 +11,18 @@ f(5)
# not to include the else expression
g = lambda: 1 if True else 3
g()
assert g() == 1
h = lambda: 1 if False else 3
h()
assert h() == 3
# From 2.7 test_builtin
lambda c: 'a' <= c <= 'z', 'Hello World'
i = lambda c: 'a' <= c <= 'z', 'Hello World'
assert i[0]('a') == True
assert i[0]('A') == False
# Issue #170. Bug is needing an "conditional_not_lambda" grammar rule
# in addition the the "conditional_lambda" rule
j = lambda a: False if not a else True
assert j(True) == True
assert j(False) == False

View File

@@ -75,8 +75,12 @@ class Python25Parser(Python26Parser):
setupwithas ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 setup_finally
stmt ::= classdefdeco
stmt ::= conditional_lambda
stmt ::= conditional_not_lambda
conditional_lambda ::= expr jmp_false_then expr return_if_lambda
return_stmt_lambda LAMBDA_MARKER
conditional_not_lambda
::= expr jmp_true_then expr return_if_lambda
return_stmt_lambda LAMBDA_MARKER
""")
super(Python25Parser, self).customize_grammar_rules(tokens, customize)
if self.version == 2.5:

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2017 Rocky Bernstein
# Copyright (c) 2017-2018 Rocky Bernstein
"""
spark grammar differences over Python2 for Python 2.6.
"""
@@ -289,8 +289,12 @@ class Python26Parser(Python2Parser):
return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP
stmt ::= conditional_lambda
stmt ::= conditional_not_lambda
conditional_lambda ::= expr jmp_false_then expr return_if_lambda
return_stmt_lambda LAMBDA_MARKER
conditional_not_lambda ::=
expr jmp_true_then expr return_if_lambda
return_stmt_lambda LAMBDA_MARKER
# conditional_true are for conditions which always evaluate true
# There is dead or non-optional remnants of the condition code though,

View File

@@ -158,8 +158,12 @@ class Python27Parser(Python2Parser):
# Common with 2.6
return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM
stmt ::= conditional_lambda
stmt ::= conditional_not_lambda
conditional_lambda ::= expr jmp_false expr return_if_lambda
return_stmt_lambda LAMBDA_MARKER
conditional_not_lambda
::= expr jmp_true expr return_if_lambda
return_stmt_lambda LAMBDA_MARKER
kv3 ::= expr expr STORE_MAP
"""

View File

@@ -334,6 +334,17 @@ class Python3Parser(PythonParser):
def p_stmt3(self, args):
"""
stmt ::= conditional_lambda
stmt ::= conditional_not_lambda
conditional_lambda ::= expr jmp_false expr return_if_lambda
return_stmt_lambda LAMBDA_MARKER
conditional_not_lambda
::= expr jmp_true expr return_if_lambda
return_stmt_lambda LAMBDA_MARKER
return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA
return_if_lambda ::= RETURN_END_IF_LAMBDA
stmt ::= return_closure
return_closure ::= LOAD_CLOSURE RETURN_VALUE RETURN_LAST
@@ -580,12 +591,16 @@ class Python3Parser(PythonParser):
self.addRule("""
stmt ::= assign3_pypy
stmt ::= assign2_pypy
assign3_pypy ::= expr expr expr store store store
assign2_pypy ::= expr expr store store
return_if_lambda ::= RETURN_END_IF_LAMBDA
stmt ::= conditional_lambda
assign3_pypy ::= expr expr expr store store store
assign2_pypy ::= expr expr store store
return_if_lambda ::= RETURN_END_IF_LAMBDA
stmt ::= conditional_lambda
stmt ::= conditional_not_lambda
conditional_lambda ::= expr jmp_false expr return_if_lambda
return_lambda LAMBDA_MARKER
conditional_not_lambda
::= expr jmp_true expr return_if_lambda
return_lambda LAMBDA_MARKER
""", nop_func)
n = len(tokens)

View File

@@ -36,13 +36,6 @@ class Python36Parser(Python35Parser):
# 3.6 redoes how return_closure works. FIXME: Isolate to LOAD_CLOSURE
return_closure ::= LOAD_CLOSURE DUP_TOP STORE_NAME RETURN_VALUE RETURN_LAST
stmt ::= conditional_lambda
conditional_lambda ::= expr jmp_false expr return_if_lambda
return_stmt_lambda LAMBDA_MARKER
return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA
return_if_lambda ::= RETURN_END_IF_LAMBDA
for_block ::= l_stmts_opt come_from_loops JUMP_BACK
come_from_loops ::= COME_FROM_LOOP*

View File

@@ -209,7 +209,12 @@ TABLE_DIRECT = {
'ret_cond': ( '%p if %p else %p', (2, 27), (0, 27), (-1, 27) ),
'conditionalnot': ( '%p if not %p else %p', (2, 27), (0, 22), (4, 27) ),
'ret_cond_not': ( '%p if not %p else %p', (2, 27), (0, 22), (-1, 27) ),
'conditional_lambda': ( '%c if %c else %c', 2, 0, 4),
'conditional_lambda':
( '%c if %c else %c',
(2, 'expr'), 0, 4 ),
'conditional_not_lambda':
( '%c if not %c else %c',
(2, 'expr'), 0, 4 ),
'compare_single': ( '%p %[-1]{pattr.replace("-", " ")} %p', (0, 19), (1, 19) ),
'compare_chained': ( '%p %p', (0, 29), (1, 30)),
@@ -321,71 +326,69 @@ MAP = {
# 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
# Things at the top of this lnist 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,
'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,
'attribute': 2,
'subscript': 2,
'subscript2': 2,
'slice0': 2,
'slice1': 2,
'slice2': 2,
'slice3': 2,
'buildslice2': 2,
'buildslice3': 2,
'call': 2,
'BINARY_POWER': 4,
'BINARY_POWER': 4,
'unary_expr': 6,
'unary_expr': 6,
'BINARY_MULTIPLY': 8,
'BINARY_DIVIDE': 8,
'BINARY_TRUE_DIVIDE': 8,
'BINARY_FLOOR_DIVIDE': 8,
'BINARY_MODULO': 8,
'BINARY_MULTIPLY': 8,
'BINARY_DIVIDE': 8,
'BINARY_TRUE_DIVIDE': 8,
'BINARY_FLOOR_DIVIDE': 8,
'BINARY_MODULO': 8,
'BINARY_ADD': 10,
'BINARY_SUBTRACT': 10,
'BINARY_ADD': 10,
'BINARY_SUBTRACT': 10,
'BINARY_LSHIFT': 12,
'BINARY_RSHIFT': 12,
'BINARY_LSHIFT': 12,
'BINARY_RSHIFT': 12,
'BINARY_AND': 14,
'BINARY_AND': 14,
'BINARY_XOR': 16,
'BINARY_OR': 18,
'BINARY_XOR': 16,
'compare': 20,
'unary_not': 22,
'and': 24,
'ret_and': 24,
'BINARY_OR': 18,
'or': 26,
'ret_or': 26,
'compare': 20,
'conditional': 28,
'conditional_lamdba': 28,
'conditional_not_lamdba': 28,
'conditionalnot': 28,
'ret_cond': 28,
'ret_cond_not': 28,
'unary_not': 22,
'_mklambda': 30,
'and': 24,
'ret_and': 24,
'or': 26,
'ret_or': 26,
'conditional': 28,
'conditional_lamdba': 28,
'conditionalnot': 28,
'ret_cond': 28,
'ret_cond_not': 28,
'_mklambda': 30,
'yield': 101,
'yield_from': 101
'yield': 101,
'yield_from': 101
}
ASSIGN_TUPLE_PARAM = lambda param_name: \