class NextException(Exception):
pass
+# variables are boxed for easy referencing and/or subscripting
+class Variable:
+ def __init__(self, value):
+ self.value = value
+
class Context:
def __init__(
self,
f'?UNDEF\'D STATEMENT ERROR IN {self.line_number():d}'
)
+ def find_variable(self, name):
+ # variable is created and initialized to 0 if not existent
+ variable = self.variables.get(name)
+ if variable is None:
+ variable = Variable(
+ '' if name[-1] == '$' else 0 if name[-1] == '%' else 0.
+ )
+ self.variables[name] = variable
+ return variable
+
def factory(tag, *args, **kwargs):
return tag_to_class[tag](*args, **kwargs)
@method(NodeStatementLet)
def execute(self, context):
name = self.children[0].str_value
- value = self.children[1].evaluate(context)
if name[-1] == '$':
- if not isinstance(value, str):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value = self.children[1].evaluate_str(context)
else:
- if not isinstance(value, float):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
- if name[-1] == '%':
+ value = self.children[1].evaluate_float(context)
+ if name[-1] == '$':
value = data_types.cint(value)
- context.variables[name] = value
+ context.find_variable(name).value = value
@method(NodeStatementPrint)
def execute(self, context):
for i in self.children:
@method(NodeStatementFor)
def execute(self, context):
name = self.children[0].str_value
- start = self.children[1].evaluate(context)
- end = self.children[2].evaluate(context)
+ if name[-1] == '$':
+ raise Exception(
+ f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
+ )
+ if name[-1] == '%':
+ raise Exception(
+ f'?SYNTAX ERROR IN {context.line_number():d}'
+ )
+ variable = context.find_variable(name)
+
+ variable.value = self.children[1].evaluate_float(context)
+ end = self.children[2].evaluate_float(context)
step = (
- self.children[3].evaluate(context)
+ self.children[3].evaluate_float(context)
if len(self.children) >= 4 else
1.
)
- if (
- name[-1] in '$%' or
- not isinstance(start, float) or
- not isinstance(end, float) or
- not isinstance(step, float)
- ):
- # interestingly, real applesoft treats % (but not $) as syntax error
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
- context.variables[name] = start
i = context.i
j = context.j
f'?NEXT WITHOUT FOR ERROR IN {context.line_number():d}'
)
- context.variables[name] += step
- if context.variables[name] > end:
+ variable.value += step
+ if variable.value > end:
break
context.i = i
)
if name[-1] == '%':
value = data_types.cint(value)
- context.variables[name] = value
+ context.find_variable(name).value = value
@method(NodeStatementRestore)
def execute(self, context):
context.k = (
apple_io.flash()
@method(NodeStatementHTab)
def execute(self, context):
- value = self.children[0].evaluate(context)
- if not isinstance(value, float):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value = self.children[0].evaluate_float(context)
apple_io.htab(data_types.cint(value))
@method(NodeStatementVTab)
def execute(self, context):
- value = self.children[0].evaluate(context)
- if not isinstance(value, float):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value = self.children[0].evaluate_float(context)
apple_io.vtab(data_types.cint(value))
@method(NodeStatementGet)
def execute(self, context):
raise Exception(
f'?SYNTAX ERROR IN {context.line_number():d}'
)
- context.variables[name] = value
+ context.find_variable(name).value = value
@method(NodeStatementInput)
def execute(self, context):
apple_io._print(
value = data_types.val(value)
if name[-1] == '%':
value = data_types.cint(value)
- context.variables[name] = value
+ context.find_variable(name).value = value
del execute
@method(NodeExpression)
raise NotImplementedError()
@method(NodeExpressionOr)
def evaluate(self, context):
- value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if not isinstance(value0, float) or not isinstance(value1, float):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value0 = self.children[0].evaluate_float(context)
+ value1 = self.children[1].evaluate_float(context)
return float(value0 != 0. or value1 != 0.)
@method(NodeExpressionAnd)
def evaluate(self, context):
- value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if not isinstance(value0, float) or not isinstance(value1, float):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value0 = self.children[0].evaluate_float(context)
+ value1 = self.children[1].evaluate_float(context)
return float(value0 != 0. and value1 != 0.)
@method(NodeExpressionLT)
def evaluate(self, context):
value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if (
- (not isinstance(value0, str) or not isinstance(value1, str)) and
- (not isinstance(value0, float) or not isinstance(value1, float))
- ):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value1 = (
+ self.children[1].evaluate_float(context)
+ if isinstance(value0, float) else
+ self.children[1].evaluate_str(context)
+ )
return float(value0 < value1)
@method(NodeExpressionEqual)
def evaluate(self, context):
value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if (
- (not isinstance(value0, str) or not isinstance(value1, str)) and
- (not isinstance(value0, float) or not isinstance(value1, float))
- ):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value1 = (
+ self.children[1].evaluate_float(context)
+ if isinstance(value0, float) else
+ self.children[1].evaluate_str(context)
+ )
return float(value0 == value1)
@method(NodeExpressionGT)
def evaluate(self, context):
value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if (
- (not isinstance(value0, str) or not isinstance(value1, str)) and
- (not isinstance(value0, float) or not isinstance(value1, float))
- ):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value1 = (
+ self.children[1].evaluate_float(context)
+ if isinstance(value0, float) else
+ self.children[1].evaluate_str(context)
+ )
return float(value0 > value1)
@method(NodeExpressionGE)
def evaluate(self, context):
value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if (
- (not isinstance(value0, str) or not isinstance(value1, str)) and
- (not isinstance(value0, float) or not isinstance(value1, float))
- ):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value1 = (
+ self.children[1].evaluate_float(context)
+ if isinstance(value0, float) else
+ self.children[1].evaluate_str(context)
+ )
return float(value0 >= value1)
@method(NodeExpressionLE)
def evaluate(self, context):
value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if (
- (not isinstance(value0, str) or not isinstance(value1, str)) and
- (not isinstance(value0, float) or not isinstance(value1, float))
- ):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value1 = (
+ self.children[1].evaluate_float(context)
+ if isinstance(value0, float) else
+ self.children[1].evaluate_str(context)
+ )
return float(value0 <= value1)
@method(NodeExpressionNE)
def evaluate(self, context):
value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if (
- (not isinstance(value0, str) or not isinstance(value1, str)) and
- (not isinstance(value0, float) or not isinstance(value1, float))
- ):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value1 = (
+ self.children[1].evaluate_float(context)
+ if isinstance(value0, float) else
+ self.children[1].evaluate_str(context)
+ )
return float(value0 != value1)
@method(NodeExpressionAdd)
def evaluate(self, context):
value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if (
- (not isinstance(value0, str) or not isinstance(value1, str)) and
- (not isinstance(value0, float) or not isinstance(value1, float))
- ):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value1 = (
+ self.children[1].evaluate_float(context)
+ if isinstance(value0, float) else
+ self.children[1].evaluate_str(context)
+ )
return value0 + value1
@method(NodeExpressionSubtract)
def evaluate(self, context):
- value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if not isinstance(value0, float) or not isinstance(value1, float):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value0 = self.children[0].evaluate_float(context)
+ value1 = self.children[1].evaluate_float(context)
return value0 - value1
@method(NodeExpressionMultiply)
def evaluate(self, context):
- value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if not isinstance(value0, float) or not isinstance(value1, float):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value0 = self.children[0].evaluate_float(context)
+ value1 = self.children[1].evaluate_float(context)
return value0 * value1
@method(NodeExpressionDivide)
def evaluate(self, context):
- value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if not isinstance(value0, float) or not isinstance(value1, float):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value0 = self.children[0].evaluate_float(context)
+ value1 = self.children[1].evaluate_float(context)
return value0 / value1
@method(NodeExpressionPower)
def evaluate(self, context):
- value0 = self.children[0].evaluate(context)
- value1 = self.children[1].evaluate(context)
- if not isinstance(value0, float) or not isinstance(value1, float):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value0 = self.children[0].evaluate_float(context)
+ value1 = self.children[1].evaluate_float(context)
return value0 ** value1
@method(NodeExpressionSign)
def evaluate(self, context):
- value = self.children[0].evaluate(context)
- if not isinstance(value, float):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value = self.children[0].evaluate_float(context)
return self.sign * value
@method(NodeExpressionNot)
def evaluate(self, context):
- value = self.children[0].evaluate(context)
- if not isinstance(value, float):
- raise Exception(
- f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
- )
+ value = self.children[0].evaluate_float(context)
return float(value == 0.)
@method(NodeExpressionIntLiteral)
def evaluate(self, context):
@method(NodeExpressionVariable)
def evaluate(self, context):
name = self.children[0].str_value
- if name[-1] == '$':
- value = context.variables.get(name, '')
- elif name[-1] == '%':
- value = float(context.variables.get(name, 0))
- else:
- value = context.variables.get(name, 0.)
- return value
+ return context.find_variable(name).value
@method(NodeExpressionStrDollar)
def evaluate(self, context):
- value = self.children[0].evaluate(context)
+ value = self.children[0].evaluate_float(context)
+ return data_types.str_dollar(value)
+@method(NodeExpressionVal)
+def evaluate(self, context):
+ value = self.children[0].evaluate_str(context)
+ return data_types.val(value)
+del evaluate
+
+@method(NodeExpression)
+def evaluate_float(self, context):
+ value = self.evaluate(context)
if not isinstance(value, float):
raise Exception(
f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
)
- return data_types.str_dollar(value)
-@method(NodeExpressionVal)
-def evaluate(self, context):
- value = self.children[0].evaluate(context)
+ return value
+del evaluate_float
+
+@method(NodeExpression)
+def evaluate_str(self, context):
+ value = self.evaluate(context)
if not isinstance(value, str):
raise Exception(
f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
)
- return data_types.val(value)
-del evaluate
+ return value
+del evaluate_str