mirror of
https://github.com/irmen/prog8.git
synced 2025-08-14 22:27:48 +00:00
fixed some optimization destroying parent
This commit is contained in:
@@ -242,6 +242,7 @@ class Optimizer:
|
|||||||
new_stmt = IncrDecr(operator="++" if assignment.operator == "+=" else "--",
|
new_stmt = IncrDecr(operator="++" if assignment.operator == "+=" else "--",
|
||||||
howmuch=howmuch.value, sourceref=assignment.sourceref)
|
howmuch=howmuch.value, sourceref=assignment.sourceref)
|
||||||
new_stmt.target = assignment.left
|
new_stmt.target = assignment.left
|
||||||
|
new_stmt.target.parent = new_stmt
|
||||||
assignment.my_scope().replace_node(assignment, new_stmt)
|
assignment.my_scope().replace_node(assignment, new_stmt)
|
||||||
self.optimizations_performed = True
|
self.optimizations_performed = True
|
||||||
if assignment.right.value == 1 and assignment.operator in ("/=", "//=", "*="):
|
if assignment.right.value == 1 and assignment.operator in ("/=", "//=", "*="):
|
||||||
@@ -265,17 +266,23 @@ class Optimizer:
|
|||||||
@no_type_check
|
@no_type_check
|
||||||
def _make_aug_assign(self, old_assign: Assignment, target: Union[TargetRegisters, Register, SymbolName, Dereference],
|
def _make_aug_assign(self, old_assign: Assignment, target: Union[TargetRegisters, Register, SymbolName, Dereference],
|
||||||
value: Union[int, float], operator: str) -> AugAssignment:
|
value: Union[int, float], operator: str) -> AugAssignment:
|
||||||
|
assert isinstance(target, (TargetRegisters, Register, SymbolName, Dereference))
|
||||||
a = AugAssignment(operator=operator, sourceref=old_assign.sourceref)
|
a = AugAssignment(operator=operator, sourceref=old_assign.sourceref)
|
||||||
a.nodes.append(target)
|
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
|
a.parent = old_assign.parent
|
||||||
return a
|
return a
|
||||||
|
|
||||||
@no_type_check
|
@no_type_check
|
||||||
def _make_incrdecr(self, old_stmt: AstNode, target: Union[TargetRegisters, Register, SymbolName, Dereference],
|
def _make_incrdecr(self, old_stmt: AstNode, target: Union[TargetRegisters, Register, SymbolName, Dereference],
|
||||||
howmuch: Union[int, float], operator: str) -> IncrDecr:
|
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 = IncrDecr(operator=operator, howmuch=howmuch, sourceref=old_stmt.sourceref)
|
||||||
a.nodes.append(target)
|
a.nodes.append(target)
|
||||||
|
target.parent = a
|
||||||
a.parent = old_stmt.parent
|
a.parent = old_stmt.parent
|
||||||
return a
|
return a
|
||||||
|
|
||||||
@@ -341,7 +348,7 @@ class Optimizer:
|
|||||||
# the comparison operator and rvalue (0) will be removed and the if-status changed accordingly
|
# the comparison operator and rvalue (0) will be removed and the if-status changed accordingly
|
||||||
for goto in self.module.all_nodes(Goto):
|
for goto in self.module.all_nodes(Goto):
|
||||||
if isinstance(goto.condition, Expression):
|
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:
|
# if cond and isinstance(cond.rvalue, (int, float)) and cond.rvalue.value == 0:
|
||||||
# simplified = False
|
# simplified = False
|
||||||
# if cond.ifstatus in ("true", "ne"):
|
# 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)
|
raise ExpressionEvaluationError("can only use math- or builtin function", expr.sourceref)
|
||||||
elif isinstance(expr.target, Dereference): # '[...](1,2,3)'
|
elif isinstance(expr.target, Dereference): # '[...](1,2,3)'
|
||||||
raise ExpressionEvaluationError("dereferenced value call is not a constant value", expr.sourceref)
|
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)
|
raise ExpressionEvaluationError("immediate address call is not a constant value", expr.sourceref)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("weird call target", expr.target)
|
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():
|
if expr.is_compile_constant():
|
||||||
return LiteralValue(value=expr.const_value(), sourceref=sourceref) # type: ignore
|
return LiteralValue(value=expr.const_value(), sourceref=sourceref) # type: ignore
|
||||||
elif isinstance(expr, SymbolName):
|
elif isinstance(expr, SymbolName):
|
||||||
try:
|
if expr.is_compile_constant():
|
||||||
return _process_constant_expression(expr, sourceref)
|
try:
|
||||||
except ExpressionEvaluationError:
|
return _process_constant_expression(expr, sourceref)
|
||||||
return expr
|
except ExpressionEvaluationError:
|
||||||
|
pass
|
||||||
|
return expr
|
||||||
elif isinstance(expr, AddressOf):
|
elif isinstance(expr, AddressOf):
|
||||||
try:
|
if expr.is_compile_constant():
|
||||||
return _process_constant_expression(expr, sourceref)
|
try:
|
||||||
except ExpressionEvaluationError:
|
return _process_constant_expression(expr, sourceref)
|
||||||
return expr
|
except ExpressionEvaluationError:
|
||||||
|
pass
|
||||||
|
return expr
|
||||||
elif isinstance(expr, SubCall):
|
elif isinstance(expr, SubCall):
|
||||||
try:
|
try:
|
||||||
return _process_constant_expression(expr, sourceref)
|
return _process_constant_expression(expr, sourceref)
|
||||||
@@ -520,11 +531,7 @@ def _process_dynamic_expression(expr: Expression, sourceref: SourceRef) -> Expre
|
|||||||
if isinstance(expr.target, SymbolName):
|
if isinstance(expr.target, SymbolName):
|
||||||
check_symbol_definition(expr.target.name, expr.my_scope(), expr.target.sourceref)
|
check_symbol_definition(expr.target.name, expr.my_scope(), expr.target.sourceref)
|
||||||
return expr
|
return expr
|
||||||
elif isinstance(expr, Register):
|
elif isinstance(expr, (Register, Dereference)):
|
||||||
return expr
|
|
||||||
elif isinstance(expr, Dereference):
|
|
||||||
if isinstance(expr.operand, SymbolName):
|
|
||||||
check_symbol_definition(expr.operand.name, expr.my_scope(), expr.operand.sourceref)
|
|
||||||
return expr
|
return expr
|
||||||
elif isinstance(expr, ExpressionWithOperator):
|
elif isinstance(expr, ExpressionWithOperator):
|
||||||
if expr.unary:
|
if expr.unary:
|
||||||
|
@@ -159,7 +159,7 @@ class Scope(AstNode):
|
|||||||
if node.name in self.symbols:
|
if node.name in self.symbols:
|
||||||
raise ParseError("symbol '{}' already defined at {}".format(node.name, self.symbols[node.name].sourceref), node.sourceref)
|
raise ParseError("symbol '{}' already defined at {}".format(node.name, self.symbols[node.name].sourceref), node.sourceref)
|
||||||
self.symbols[node.name] = node
|
self.symbols[node.name] = node
|
||||||
elif isinstance(node, Block):
|
elif isinstance(node, (Block, Scope)):
|
||||||
if node.name:
|
if node.name:
|
||||||
if node.name != "ZP" and node.name in self.symbols:
|
if node.name != "ZP" and node.name in self.symbols:
|
||||||
raise ParseError("symbol '{}' already defined at {}"
|
raise ParseError("symbol '{}' already defined at {}"
|
||||||
@@ -608,11 +608,11 @@ class ExpressionWithOperator(Expression):
|
|||||||
|
|
||||||
@attr.s(cmp=False, repr=False)
|
@attr.s(cmp=False, repr=False)
|
||||||
class Goto(AstNode):
|
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)
|
if_stmt = attr.ib(default=None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target(self) -> Union[SymbolName, int, Dereference]:
|
def target(self) -> Union[SymbolName, LiteralValue, Dereference]:
|
||||||
return self.nodes[0] # type: ignore
|
return self.nodes[0] # type: ignore
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -1335,7 +1335,10 @@ def p_goto(p):
|
|||||||
goto : GOTO calltarget
|
goto : GOTO calltarget
|
||||||
"""
|
"""
|
||||||
p[0] = Goto(sourceref=_token_sref(p, 1))
|
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):
|
def p_conditional_goto_plain(p):
|
||||||
|
@@ -322,17 +322,22 @@ def test_symbol_lookup():
|
|||||||
scope_inner
|
scope_inner
|
||||||
], level="block", sourceref=sref)
|
], level="block", sourceref=sref)
|
||||||
scope_outer.name = "outer"
|
scope_outer.name = "outer"
|
||||||
scope_outer.define_builtin_functions()
|
|
||||||
var1.parent = label1.parent = scope_inner.parent = scope_outer
|
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_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 label1.my_scope() is scope_outer
|
||||||
assert var1.my_scope() is scope_outer
|
assert var1.my_scope() is scope_outer
|
||||||
assert scope_inner.my_scope() is scope_outer
|
assert scope_inner.my_scope() is scope_outer
|
||||||
assert label2.my_scope() is scope_inner
|
assert label2.my_scope() is scope_inner
|
||||||
assert var2.my_scope() is scope_inner
|
assert var2.my_scope() is scope_inner
|
||||||
|
assert scope_outer.my_scope() is scope_topmost
|
||||||
with pytest.raises(LookupError):
|
with pytest.raises(LookupError):
|
||||||
scope_outer.my_scope()
|
scope_topmost.my_scope()
|
||||||
with pytest.raises(UndefinedSymbolError):
|
with pytest.raises(UndefinedSymbolError):
|
||||||
scope_inner.lookup("unexisting")
|
scope_inner.lookup("unexisting")
|
||||||
with pytest.raises(UndefinedSymbolError):
|
with pytest.raises(UndefinedSymbolError):
|
||||||
@@ -353,3 +358,12 @@ def test_symbol_lookup():
|
|||||||
builtin_func = scope_inner.lookup("max")
|
builtin_func = scope_inner.lookup("max")
|
||||||
assert isinstance(builtin_func, BuiltinFunction)
|
assert isinstance(builtin_func, BuiltinFunction)
|
||||||
assert builtin_func.name == "max" and builtin_func.func is max
|
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
|
||||||
|
Reference in New Issue
Block a user