fixed some optimization destroying parent

This commit is contained in:
Irmen de Jong 2018-01-31 00:28:21 +01:00
parent 9b23bfb85c
commit dd96cd506d
3 changed files with 47 additions and 23 deletions

View File

@ -242,6 +242,7 @@ class Optimizer:
new_stmt = IncrDecr(operator="++" if assignment.operator == "+=" else "--",
howmuch=howmuch.value, sourceref=assignment.sourceref)
new_stmt.target = assignment.left
new_stmt.target.parent = new_stmt
assignment.my_scope().replace_node(assignment, new_stmt)
self.optimizations_performed = True
if assignment.right.value == 1 and assignment.operator in ("/=", "//=", "*="):
@ -265,17 +266,23 @@ class Optimizer:
@no_type_check
def _make_aug_assign(self, old_assign: Assignment, target: Union[TargetRegisters, Register, SymbolName, Dereference],
value: Union[int, float], operator: str) -> AugAssignment:
assert isinstance(target, (TargetRegisters, Register, SymbolName, Dereference))
a = AugAssignment(operator=operator, sourceref=old_assign.sourceref)
a.nodes.append(target)
a.nodes.append(LiteralValue(value=value, sourceref=old_assign.sourceref))
target.parent = a
lv = LiteralValue(value=value, sourceref=old_assign.sourceref)
a.nodes.append(lv)
lv.parent = a
a.parent = old_assign.parent
return a
@no_type_check
def _make_incrdecr(self, old_stmt: AstNode, target: Union[TargetRegisters, Register, SymbolName, Dereference],
howmuch: Union[int, float], operator: str) -> IncrDecr:
assert isinstance(target, (TargetRegisters, Register, SymbolName, Dereference))
a = IncrDecr(operator=operator, howmuch=howmuch, sourceref=old_stmt.sourceref)
a.nodes.append(target)
target.parent = a
a.parent = old_stmt.parent
return a
@ -341,7 +348,7 @@ class Optimizer:
# the comparison operator and rvalue (0) will be removed and the if-status changed accordingly
for goto in self.module.all_nodes(Goto):
if isinstance(goto.condition, Expression):
print("NOT IMPLEMENTED YET: optimize goto conditionals", goto.condition) # @todo
pass # @todo optimize goto conditionals
# if cond and isinstance(cond.rvalue, (int, float)) and cond.rvalue.value == 0:
# simplified = False
# if cond.ifstatus in ("true", "ne"):
@ -456,7 +463,7 @@ def _process_constant_expression(expr: Expression, sourceref: SourceRef) -> Lite
raise ExpressionEvaluationError("can only use math- or builtin function", expr.sourceref)
elif isinstance(expr.target, Dereference): # '[...](1,2,3)'
raise ExpressionEvaluationError("dereferenced value call is not a constant value", expr.sourceref)
elif type(expr.target) is int: # '64738()'
elif isinstance(expr.target, LiteralValue) and type(expr.target.value) is int: # '64738()'
raise ExpressionEvaluationError("immediate address call is not a constant value", expr.sourceref)
else:
raise NotImplementedError("weird call target", expr.target)
@ -504,15 +511,19 @@ def _process_dynamic_expression(expr: Expression, sourceref: SourceRef) -> Expre
if expr.is_compile_constant():
return LiteralValue(value=expr.const_value(), sourceref=sourceref) # type: ignore
elif isinstance(expr, SymbolName):
try:
return _process_constant_expression(expr, sourceref)
except ExpressionEvaluationError:
return expr
if expr.is_compile_constant():
try:
return _process_constant_expression(expr, sourceref)
except ExpressionEvaluationError:
pass
return expr
elif isinstance(expr, AddressOf):
try:
return _process_constant_expression(expr, sourceref)
except ExpressionEvaluationError:
return expr
if expr.is_compile_constant():
try:
return _process_constant_expression(expr, sourceref)
except ExpressionEvaluationError:
pass
return expr
elif isinstance(expr, SubCall):
try:
return _process_constant_expression(expr, sourceref)
@ -520,11 +531,7 @@ def _process_dynamic_expression(expr: Expression, sourceref: SourceRef) -> Expre
if isinstance(expr.target, SymbolName):
check_symbol_definition(expr.target.name, expr.my_scope(), expr.target.sourceref)
return expr
elif isinstance(expr, Register):
return expr
elif isinstance(expr, Dereference):
if isinstance(expr.operand, SymbolName):
check_symbol_definition(expr.operand.name, expr.my_scope(), expr.operand.sourceref)
elif isinstance(expr, (Register, Dereference)):
return expr
elif isinstance(expr, ExpressionWithOperator):
if expr.unary:

View File

@ -159,7 +159,7 @@ class Scope(AstNode):
if node.name in self.symbols:
raise ParseError("symbol '{}' already defined at {}".format(node.name, self.symbols[node.name].sourceref), node.sourceref)
self.symbols[node.name] = node
elif isinstance(node, Block):
elif isinstance(node, (Block, Scope)):
if node.name:
if node.name != "ZP" and node.name in self.symbols:
raise ParseError("symbol '{}' already defined at {}"
@ -608,11 +608,11 @@ class ExpressionWithOperator(Expression):
@attr.s(cmp=False, repr=False)
class Goto(AstNode):
# one or two subnodes: target (SymbolName, int or Dereference) and optionally: condition (Expression)
# one or two subnodes: target (SymbolName, integer LiteralValue, or Dereference) and optionally: condition (Expression)
if_stmt = attr.ib(default=None)
@property
def target(self) -> Union[SymbolName, int, Dereference]:
def target(self) -> Union[SymbolName, LiteralValue, Dereference]:
return self.nodes[0] # type: ignore
@property
@ -1335,7 +1335,10 @@ def p_goto(p):
goto : GOTO calltarget
"""
p[0] = Goto(sourceref=_token_sref(p, 1))
p[0].nodes.append(p[2])
target = p[2]
if isinstance(target, int):
target = LiteralValue(value=target, sourceref=p[0].sourceref)
p[0].nodes.append(target)
def p_conditional_goto_plain(p):

View File

@ -322,17 +322,22 @@ def test_symbol_lookup():
scope_inner
], level="block", sourceref=sref)
scope_outer.name = "outer"
scope_outer.define_builtin_functions()
var1.parent = label1.parent = scope_inner.parent = scope_outer
scope_topmost = Scope(nodes=[scope_outer], level="module", sourceref=sref)
scope_topmost.name = "topmost"
scope_outer.parent = scope_topmost
scope_topmost.define_builtin_functions()
assert scope_inner.parent_scope is scope_outer
assert scope_outer.parent_scope is None
assert scope_outer.parent_scope is scope_topmost
assert scope_topmost.parent_scope is None
assert label1.my_scope() is scope_outer
assert var1.my_scope() is scope_outer
assert scope_inner.my_scope() is scope_outer
assert label2.my_scope() is scope_inner
assert var2.my_scope() is scope_inner
assert scope_outer.my_scope() is scope_topmost
with pytest.raises(LookupError):
scope_outer.my_scope()
scope_topmost.my_scope()
with pytest.raises(UndefinedSymbolError):
scope_inner.lookup("unexisting")
with pytest.raises(UndefinedSymbolError):
@ -353,3 +358,12 @@ def test_symbol_lookup():
builtin_func = scope_inner.lookup("max")
assert isinstance(builtin_func, BuiltinFunction)
assert builtin_func.name == "max" and builtin_func.func is max
# test dotted names:
with pytest.raises(UndefinedSymbolError):
scope_inner.lookup("noscope.nosymbol.nothing")
assert scope_inner.lookup("outer.inner.var2") is var2
with pytest.raises(UndefinedSymbolError):
scope_inner.lookup("outer.inner.var1")
with pytest.raises(UndefinedSymbolError):
scope_inner.lookup("outer.var2")
assert scope_inner.lookup("outer.var1") is var1