mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
astnode properties fix
This commit is contained in:
parent
6696887f0e
commit
44c0d243ef
@ -129,7 +129,3 @@ def preserving_registers(registers: Set[str], scope: Scope, out: Callable, loads
|
||||
yield
|
||||
|
||||
|
||||
@no_type_check
|
||||
def scoped_name(node_with_name: AstNode, current_scope: Scope) -> str:
|
||||
node_scope = node_with_name.my_scope()
|
||||
return node_with_name.name if node_scope is current_scope else node_scope.name + "." + node_with_name.name
|
||||
|
@ -7,9 +7,9 @@ is quite frequent and this generates assembly code tweaked for this case.
|
||||
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||
"""
|
||||
|
||||
from ..plyparse import VarDef, Register, IncrDecr, SymbolName, Dereference, LiteralValue
|
||||
from ..plyparse import VarDef, Register, IncrDecr, SymbolName, Dereference, LiteralValue, scoped_name
|
||||
from ..datatypes import VarType, DataType, REGISTER_BYTES
|
||||
from . import CodeError, preserving_registers, to_hex, Context, scoped_name
|
||||
from . import CodeError, preserving_registers, to_hex, Context
|
||||
|
||||
|
||||
def generate_incrdecr(ctx: Context) -> None:
|
||||
|
@ -36,7 +36,7 @@ class Optimizer:
|
||||
# @todo expression optimization: reduce expression nesting / flattening of parenthesis
|
||||
# @todo expression optimization: simplify logical expression when a term makes it always true or false
|
||||
# @todo expression optimization: optimize some simple multiplications into shifts (A*=8 -> A<<3)
|
||||
self.create_aug_assignments()
|
||||
# @todo expression optimization: create augmented assignment from assignment that only refers to its lvalue (A=A+10, A=4*A, ...)
|
||||
self.optimize_assignments()
|
||||
self.remove_superfluous_assignments()
|
||||
# @todo optimize addition with self into shift 1 (A+=A -> A<<=1)
|
||||
@ -132,39 +132,6 @@ class Optimizer:
|
||||
raise TypeError("same_target called with invalid type(s)", node1, node2)
|
||||
return False
|
||||
|
||||
@no_type_check
|
||||
def create_aug_assignments(self) -> None:
|
||||
# create augmented assignments from regular assignment that only refers to the lvalue
|
||||
# A=A+10, A=10+A -> A+=10, A=A*4, A=4*A -> A*=4, etc
|
||||
for assignment in self.module.all_nodes(Assignment):
|
||||
if len(assignment.left.nodes) > 1:
|
||||
continue
|
||||
if not isinstance(assignment.right, ExpressionWithOperator) or assignment.right.unary:
|
||||
continue
|
||||
expr = assignment.right
|
||||
if expr.operator in ('-', '/', '//', '**', '<<', '>>', '&'): # non-associative operators
|
||||
if isinstance(expr.right, (LiteralValue, SymbolName)) and self._same_target(assignment.left, expr.left):
|
||||
num_val = expr.right.const_value()
|
||||
operator = expr.operator + '='
|
||||
aug_assign = self._make_aug_assign(assignment, assignment.left.nodes[0], num_val, operator)
|
||||
assignment.my_scope().replace_node(assignment, aug_assign)
|
||||
self.optimizations_performed = True
|
||||
continue
|
||||
if expr.operator not in ('+', '*', '|', '^'): # associative operators
|
||||
continue
|
||||
if isinstance(expr.right, (LiteralValue, SymbolName)) and self._same_target(assignment.left, expr.left):
|
||||
num_val = expr.right.const_value()
|
||||
operator = expr.operator + '='
|
||||
aug_assign = self._make_aug_assign(assignment, assignment.left.nodes[0], num_val, operator)
|
||||
assignment.my_scope().replace_node(assignment, aug_assign)
|
||||
self.optimizations_performed = True
|
||||
elif isinstance(expr.left, (LiteralValue, SymbolName)) and self._same_target(assignment.left, expr.right):
|
||||
num_val = expr.left.const_value()
|
||||
operator = expr.operator + '='
|
||||
aug_assign = self._make_aug_assign(assignment, assignment.left.nodes[0], num_val, operator)
|
||||
assignment.my_scope().replace_node(assignment, aug_assign)
|
||||
self.optimizations_performed = True
|
||||
|
||||
def remove_superfluous_assignments(self) -> None:
|
||||
# remove consecutive assignment statements to the same target, only keep the last value (only if its a constant!)
|
||||
# this is NOT done for memory mapped variables because these often represent a volatile register of some sort!
|
||||
|
@ -70,14 +70,12 @@ class UndefinedSymbolError(LookupError):
|
||||
start = "start"
|
||||
|
||||
|
||||
@attr.s(repr=False, cmp=False, slots=True)
|
||||
class AstNode:
|
||||
# all ast nodes have: sourceref, parent, and nodes (=list of zero or more sub-nodes)
|
||||
__slots__ = ["sourceref", "parent", "nodes"]
|
||||
|
||||
def __init__(self, sourceref: SourceRef) -> None:
|
||||
self.sourceref = sourceref
|
||||
self.parent = None # type: AstNode # will be hooked up later
|
||||
self.nodes = [] # type: List[AstNode]
|
||||
sourceref = attr.ib(type=SourceRef, init=True)
|
||||
parent = attr.ib(type='AstNode', init=False, default=None) # will be hooked up later
|
||||
nodes = attr.ib(type=List['AstNode'], init=False, default=attr.Factory(list))
|
||||
|
||||
@property
|
||||
def lineref(self) -> str:
|
||||
@ -139,7 +137,7 @@ class Directive(AstNode):
|
||||
@attr.s(cmp=False, slots=True, repr=False)
|
||||
class Scope(AstNode):
|
||||
# has zero or more subnodes
|
||||
level = attr.ib(type=str, init=True)
|
||||
level = attr.ib(type=str, init=True) # type: ignore
|
||||
nodes = attr.ib(type=list, init=True) # requires nodes in __init__
|
||||
symbols = attr.ib(init=False)
|
||||
name = attr.ib(init=False) # will be set by enclosing block, or subroutine etc.
|
||||
@ -400,20 +398,20 @@ class Register(Expression):
|
||||
|
||||
@attr.s(cmp=False)
|
||||
class PreserveRegs(AstNode):
|
||||
registers = attr.ib(type=str)
|
||||
registers = attr.ib(type=str) # type: ignore
|
||||
# no subnodes.
|
||||
|
||||
|
||||
@attr.s(cmp=False, repr=False)
|
||||
class InlineAssembly(AstNode):
|
||||
# no subnodes.
|
||||
assembly = attr.ib(type=str)
|
||||
assembly = attr.ib(type=str) # type: ignore
|
||||
|
||||
|
||||
@attr.s(cmp=False, slots=True)
|
||||
class DatatypeNode(AstNode):
|
||||
# no subnodes.
|
||||
name = attr.ib(type=str)
|
||||
name = attr.ib(type=str) # type: ignore
|
||||
dimensions = attr.ib(type=list, default=None, validator=dimensions_validator) # if set, 1 or more dimensions (ints)
|
||||
|
||||
def to_enum(self):
|
||||
@ -436,14 +434,14 @@ class BuiltinFunction(AstNode):
|
||||
# This is a pseudo-node that will be artificially injected in the top-most scope,
|
||||
# to represent all supported built-in functions or math-functions.
|
||||
# No child nodes.
|
||||
name = attr.ib(type=str)
|
||||
name = attr.ib(type=str) # type: ignore
|
||||
func = attr.ib(type=Callable)
|
||||
|
||||
|
||||
@attr.s(cmp=False, repr=False)
|
||||
class Subroutine(AstNode):
|
||||
# one subnode: the Scope.
|
||||
name = attr.ib(type=str)
|
||||
name = attr.ib(type=str) # type: ignore
|
||||
param_spec = attr.ib(type=list)
|
||||
result_spec = attr.ib(type=list)
|
||||
address = attr.ib(type=int, default=None, validator=validate_address)
|
||||
@ -552,7 +550,7 @@ class IncrDecr(AstNode):
|
||||
# increment or decrement something by a small CONSTANT value (1..255)
|
||||
# larger values will be treated/converted as an augmented assignment += or -=.
|
||||
# one subnode: target (Register, SymbolName, or Dereference).
|
||||
operator = attr.ib(type=str, validator=attr.validators.in_(["++", "--"]))
|
||||
operator = attr.ib(type=str, validator=attr.validators.in_(["++", "--"])) # type: ignore
|
||||
howmuch = attr.ib(default=1)
|
||||
|
||||
@property
|
||||
@ -730,7 +728,7 @@ class CallArgument(AstNode):
|
||||
@attr.s(cmp=False)
|
||||
class CallArguments(AstNode):
|
||||
# subnodes are zero or more subroutine call arguments (CallArgument)
|
||||
nodes = attr.ib(type=list, init=True) # requires nodes in __init__
|
||||
nodes = attr.ib(type=list, init=True) # type: ignore # requires nodes in __init__
|
||||
|
||||
|
||||
@attr.s(cmp=False, repr=False)
|
||||
@ -772,7 +770,7 @@ class SubCall(Expression):
|
||||
@attr.s(cmp=False, slots=True, repr=False)
|
||||
class VarDef(AstNode):
|
||||
# zero or one subnode: value (Expression).
|
||||
name = attr.ib(type=str)
|
||||
name = attr.ib(type=str) # type: ignore
|
||||
vartype = attr.ib()
|
||||
datatype = attr.ib()
|
||||
size = attr.ib(type=list, default=None)
|
||||
@ -872,7 +870,7 @@ class Assignment(AstNode):
|
||||
@attr.s(cmp=False, slots=True, repr=False)
|
||||
class AugAssignment(AstNode):
|
||||
# has two subnodes: left (=Register, SymbolName, or Dereference) and right (=Expression)
|
||||
operator = attr.ib(type=str)
|
||||
operator = attr.ib(type=str) # type: ignore
|
||||
|
||||
@property
|
||||
def left(self) -> Union[Register, SymbolName, Dereference]:
|
||||
@ -973,6 +971,12 @@ def check_symbol_definition(name: str, scope: Scope, sref: SourceRef) -> Any:
|
||||
raise ParseError(str(x), sref)
|
||||
|
||||
|
||||
@no_type_check
|
||||
def scoped_name(node_with_name: AstNode, current_scope: Scope) -> str:
|
||||
node_scope = node_with_name.my_scope()
|
||||
return node_with_name.name if node_scope is current_scope else node_scope.name + "." + node_with_name.name
|
||||
|
||||
|
||||
# ----------------- PLY parser definition follows ----------------------
|
||||
|
||||
def p_start(p):
|
||||
|
5
todo.ill
5
todo.ill
@ -7,15 +7,14 @@
|
||||
start:
|
||||
counter ++
|
||||
main.counter ++
|
||||
; @
|
||||
|
||||
todo float augassign
|
||||
; @todo float augassign
|
||||
flt += 1000.1
|
||||
flt *= 2.34
|
||||
flt *= flt
|
||||
|
||||
;[border] &= 2 ; @todo augassign on dereference
|
||||
|
||||
flt = flt+ 1 ; @todo optimize into augassign
|
||||
XY*=3 ; @todo operator
|
||||
XY=XY/0 ; @todo zerodiv (during expression to code generation) @todo operator
|
||||
XY=XY//0 ; @todo zerodiv (during expression to code generation) @todo operator
|
||||
|
Loading…
x
Reference in New Issue
Block a user