various fixes

This commit is contained in:
Irmen de Jong 2018-01-21 18:17:39 +01:00
parent ab71a15007
commit fbf52d773f
6 changed files with 49 additions and 28 deletions

View File

@ -101,7 +101,10 @@ class PlyParser:
raise ParseError("invalid number of arguments ({:d}, required: {:d})"
.format(len(call.arguments.nodes), len(subdef.param_spec)), call.sourceref)
for arg, param in zip(call.arguments.nodes, subdef.param_spec):
if arg.name and arg.name != param[0]:
if arg.name:
if not param[0]:
raise ParseError("parameter is unnamed but name was used", arg.sourceref)
if arg.name != param[0]:
raise ParseError("parameter name mismatch", arg.sourceref)
def check_and_merge_zeropages(self, module: Module) -> None:
@ -111,7 +114,7 @@ class PlyParser:
if block.name == "ZP": # type: ignore
if zeropage:
# merge other ZP block into first ZP block
for node in block.nodes:
for node in block.scope.nodes:
if isinstance(node, Directive):
zeropage.scope.add_node(node, 0)
elif isinstance(node, VarDef):
@ -172,7 +175,7 @@ class PlyParser:
lvalue_types = set(datatype_of(lv, node.my_scope()) for lv in node.left.nodes)
if len(lvalue_types) == 1:
_, newright = coerce_constant_value(lvalue_types.pop(), node.right, node.sourceref)
if isinstance(newright, (Register, LiteralValue, Expression)):
if isinstance(newright, (Register, LiteralValue, Expression, Dereference, SymbolName, SubCall)):
node.right = newright
else:
raise TypeError("invalid coerced constant type", newright)

View File

@ -247,6 +247,8 @@ def _format_string(value: str, screencodes: bool = False) -> str:
def _numeric_value_str(value: Any, as_hex: bool=False) -> str:
if isinstance(value, LiteralValue):
value = value.value
if isinstance(value, bool):
return "1" if value else "0"
if type(value) is int:

View File

@ -73,11 +73,11 @@ class AstNode:
if isinstance(scope, Scope):
return scope
scope = scope.parent
raise LookupError("no scope found in node ancestry")
raise LookupError("no scope found in node ancestry", self)
def all_nodes(self, *nodetypes: type) -> Generator['AstNode', None, None]:
nodetypes = nodetypes or (AstNode, )
for node in self.nodes:
for node in list(self.nodes):
if isinstance(node, nodetypes): # type: ignore
yield node
for node in self.nodes:
@ -121,7 +121,10 @@ class Scope(AstNode):
def save_registers(self) -> bool:
if self._save_registers is not None:
return self._save_registers
try:
return self.my_scope().save_registers
except LookupError:
return False
@save_registers.setter
def save_registers(self, save: bool) -> None:
@ -507,7 +510,7 @@ class Goto(AstNode):
return self.nodes[1] if len(self.nodes) == 2 else None # type: ignore
@attr.s(cmp=False, slots=True)
@attr.s(cmp=False, slots=True, repr=False)
class CallArgument(AstNode):
# one subnode: the value (Expression)
name = attr.ib(type=str, default=None)
@ -553,12 +556,12 @@ class VarDef(AstNode):
zp_address = attr.ib(type=int, default=None, init=False) # the address in the zero page if this var is there, will be set later
@property
def value(self) -> Union[LiteralValue, Expression]:
def value(self) -> Union[LiteralValue, Expression, AddressOf, SymbolName]:
return self.nodes[0] if self.nodes else None # type: ignore
@value.setter
def value(self, value: Union[LiteralValue, Expression]) -> None:
assert isinstance(value, (LiteralValue, Expression))
def value(self, value: Union[LiteralValue, Expression, AddressOf, SymbolName]) -> None:
assert isinstance(value, (LiteralValue, Expression, AddressOf, SymbolName))
if self.nodes:
self.nodes[0] = value
else:
@ -634,8 +637,8 @@ class Assignment(AstNode):
return self.nodes[1] # type: ignore
@right.setter
def right(self, rvalue: Union[Register, LiteralValue, Expression]) -> None:
assert isinstance(rvalue, (Register, LiteralValue, Expression))
def right(self, rvalue: Union[Register, LiteralValue, Expression, Dereference, SymbolName, SubCall]) -> None:
assert isinstance(rvalue, (Register, LiteralValue, Expression, Dereference, SymbolName, SubCall))
self.nodes[1] = rvalue
@ -704,10 +707,16 @@ def coerce_constant_value(datatype: DataType, value: AstNode,
raise TypeError("cannot assign '{:s}' to {:s}".format(type(value.value).__name__, datatype.name.lower()), sourceref)
elif isinstance(value, (Expression, SubCall)):
return False, value
elif isinstance(value, SymbolName):
symboldef = value.my_scope().lookup(value.name)
if isinstance(symboldef, VarDef) and symboldef.vartype == VarType.CONST:
return True, symboldef.value
elif isinstance(value, AddressOf):
raise NotImplementedError("addressof const coerce", value) # XXX implement this
if datatype == DataType.WORD and not isinstance(value, (LiteralValue, Dereference, Register, SymbolName, AddressOf)):
raise TypeError("cannot assign '{:s}' to {:s}".format(type(value).__name__, datatype.name.lower()), sourceref)
elif datatype in (DataType.BYTE, DataType.WORD, DataType.FLOAT) \
and not isinstance(value, (LiteralValue, Dereference, Register, SymbolName)):
and not isinstance(value, (LiteralValue, Dereference, Register, SymbolName, AddressOf)):
raise TypeError("cannot assign '{:s}' to {:s}".format(type(value).__name__, datatype.name.lower()), sourceref)
return False, value
@ -734,6 +743,8 @@ def process_constant_expression(expr: Any, sourceref: SourceRef, symbolscope: Sc
value = value.value
if isinstance(value, Expression):
raise ExpressionEvaluationError("circular reference?", expr.sourceref)
elif isinstance(value, LiteralValue):
return value
elif isinstance(value, (int, float, str, bool)):
raise TypeError("symbol value node should not be a python primitive value", expr)
else:
@ -1199,10 +1210,11 @@ def p_call_subroutine(p):
"""
subroutine_call : calltarget preserveregs_opt '(' call_arguments_opt ')'
"""
p[0] = SubCall(sourceref=_token_sref(p, 3))
sref = _token_sref(p, 3)
p[0] = SubCall(sourceref=sref)
p[0].nodes.append(p[1])
p[0].nodes.append(p[2])
p[0].nodes.append(CallArguments(nodes=p[4] or [], sourceref=p[0].sourceref))
p[0].nodes.append(CallArguments(nodes=p[4] or [], sourceref=sref))
def p_preserveregs_opt(p):
@ -1249,7 +1261,11 @@ def p_call_argument(p):
p[0] = CallArgument(sourceref=_token_sref(p, 1))
p[0].nodes.append(p[1])
elif len(p) == 4:
p[0] = CallArgument(name=p[1], sourceref=_token_sref(p, 1))
if isinstance(p[1], AstNode):
sref = p[1].sourceref
else:
sref = _token_sref(p, 2)
p[0] = CallArgument(name=p[1], sourceref=sref)
p[0].nodes.append(p[3])

View File

@ -32,11 +32,9 @@ bar: goto $c000
; ----
goto sub1
return sub2 ( )
return sub2 ()
return sub2 (1 )
return sub3 (3)
return sub3 (XY="hello")
return sub3 ("hello")
return sub3 ("hello, there")
return sub4 (string="hello, there", other = 42)
return sub4 ("hello", 42)
@ -77,7 +75,7 @@ bar: goto $c000
sub1!()
sub2!(11)
sub3 !(3)
sub3! (XY="hello")
sub3! ("hello")
sub3! ("hello, there")
sub4! ("hello", 42)
sub4! ("hello", other=42)
@ -113,7 +111,7 @@ bar: goto $c000
sub1()
sub2(11)
sub3 (3)
sub3 (XY="hello")
sub3 ("hello")
sub3 ("hello, there")
sub4 ("hello", 42)
sub4 ("hello", other= 42)

View File

@ -29,6 +29,8 @@
~ ZP {
; will be merged with other ZP blocks!
var zpvar1b = $88
; @todo should not need %noreturn because is zeropage
}
@ -190,7 +192,7 @@ start:
XY = membyte2
XY = memword1
XY = sin
XY = &sin
; XY = &sin ; @todo not yet implemented
[$c000] = A
@ -214,7 +216,7 @@ start:
[$c000.word] = ""
[$c000.word] = uninitbyte1
[$c000.word] = membyte2
[$c000.word] = &membyte2
; [$c000.word] = &membyte2 ; @todo not yet implemented
[$c000.word] = [cword2]
[$c000.word] = memword1
[$c000.float] = 65535
@ -228,7 +230,7 @@ start:
[$c112.word] = [$c223.byte]
[$c222.word] = [$c333.word]
[$c333.word] = sin
[$c333.word] = &sin
; [$c333.word] = &sin ; @todo not yet implemented
SC = 0
@ -264,7 +266,8 @@ start:
uninitfloat = 9.8765
uninitfloat = '@'
initword1 = sin
initword1 = &sin
; initword1 = &sin ; @todo not yet implemented
membyte1 = A
membyte1 = cbyte3
@ -279,7 +282,7 @@ start:
memword1 = 2233
memfloat = 3.4567
memword1 = sin
memword1 = &sin
; memword1 = &sin ; @todo not yet implemented
membyte1 = A
memword1 = A

View File

@ -106,7 +106,6 @@ sub goodbye ()->() {
xxxxxx++
y++
xxxxxx = q *4
xxxxxx = qqqqq *44 ;@todo symbol error
c64scr.print_string("\nThanks for playing. Bye!\n")
return