diff --git a/README.markdown b/README.markdown index 897d0bd..7b1d9bf 100644 --- a/README.markdown +++ b/README.markdown @@ -33,7 +33,8 @@ TODO For 0.6: -* declared `inputs` `outputs` `trashes` on the `vector` type. +* declared `inputs` `outputs` `trashes` on the `vector` type... + * we need to get these 3 things onto the type, and also onto routine types * `goto` (tail call) a routine or a vector. * A more involved demo for the C64 — one that sets up an interrupt. diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index 96c88ba..518a831 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -2,7 +2,8 @@ from sixtypical.ast import Program, Routine, Block, Instr from sixtypical.model import ( - TYPE_BYTE, TYPE_BYTE_TABLE, TYPE_ROUTINE, TYPE_VECTOR, + TYPE_BYTE, TYPE_BYTE_TABLE, + RoutineType, VectorType, ConstantRef, LocationRef, REG_A, FLAG_Z, FLAG_N, FLAG_V, FLAG_C ) @@ -224,7 +225,7 @@ def analyze_instr(instr, context, routines): elif opcode == 'copy': if src.type == dest.type: pass - elif src.type == TYPE_ROUTINE and dest.type == TYPE_VECTOR: + elif isinstance(src.type, RoutineType) and isinstance(dest.type, VectorType): pass else: raise TypeMismatchError((src, dest)) diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index b648400..9be5a7a 100644 --- a/src/sixtypical/compiler.py +++ b/src/sixtypical/compiler.py @@ -3,7 +3,8 @@ from sixtypical.ast import Program, Routine, Block, Instr from sixtypical.model import ( ConstantRef, LocationRef, - TYPE_BIT, TYPE_ROUTINE, TYPE_VECTOR, + TYPE_BIT, + RoutineType, VectorType, REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C ) from sixtypical.emitter import Byte, Label, Offset @@ -242,7 +243,8 @@ class Compiler(object): self.compile_block(instr.block) self.emitter.emit(CLI()) elif opcode == 'copy': - if src.type in (TYPE_ROUTINE, TYPE_VECTOR) and dest.type == TYPE_VECTOR: + if isinstance(src.type, (RoutineType, VectorType)) and \ + isinstance(dest.type, VectorType): src_label = self.labels[src.name] dest_label = self.labels[dest.name] self.emitter.emit(LDA(Absolute(src_label))) diff --git a/src/sixtypical/model.py b/src/sixtypical/model.py index 46fe528..3c356df 100644 --- a/src/sixtypical/model.py +++ b/src/sixtypical/model.py @@ -17,8 +17,43 @@ class Type(object): TYPE_BIT = Type('bit') TYPE_BYTE = Type('byte') TYPE_BYTE_TABLE = Type('byte table') -TYPE_ROUTINE = Type('routine') -TYPE_VECTOR = Type('vector') # the mem loc contains an address of a routine + + +class InteractionConstrainedType(Type): + """Used for routines and vectors.""" + def __init__(self, name, inputs=None, outputs=None, trashes=None): + self.name = name + self.inputs = inputs or [] + self.outputs = outputs or [] + self.trashes = trashes or [] + + def __repr__(self): + return 'RoutineType(%r, inputs=%r, outputs=%r, trashes=%r)' % ( + self.name, self.inputs, self.outputs, self.trashes + ) + + def __eq__(self, other): + return isinstance(other, RoutineType) and ( + other.name == self.name and + other.inputs == self.inputs and + other.outputs == self.outputs and + other.trashes == self.trashes + ) + + def __hash__(self): + return hash(self.name) ^ hash(self.inputs) ^ hash(self.outputs) ^ hash(self.trashes) + + +class RoutineType(InteractionConstrainedType): + """This memory location contains the code for a routine.""" + def __init__(self, **kwargs): + super(RoutineType, self).__init__('routine', **kwargs) + + +class VectorType(InteractionConstrainedType): + """This memory location contains the address of a routine.""" + def __init__(self, **kwargs): + super(VectorType, self).__init__('vector', **kwargs) class Ref(object): diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index ea26f4d..42095b6 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -4,7 +4,8 @@ import re from sixtypical.ast import Program, Defn, Routine, Block, Instr from sixtypical.model import ( - TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, TYPE_ROUTINE, TYPE_VECTOR, + TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, + RoutineType, VectorType, LocationRef, ConstantRef ) @@ -115,7 +116,13 @@ class Parser(object): name = routine.name if name in self.symbols: raise SyntaxError(name) - self.symbols[name] = SymEntry(routine, LocationRef(TYPE_ROUTINE, name)) + ref = LocationRef( + RoutineType(inputs=routine.inputs, + outputs=routine.outputs, + trashes=routine.trashes + ), name + ) + self.symbols[name] = SymEntry(routine, ref) routines.append(routine) self.scanner.check_type('EOF') return Program(defns=defns, routines=routines) @@ -128,13 +135,15 @@ class Parser(object): type = TYPE_BYTE_TABLE else: self.scanner.expect('vector') - type = TYPE_VECTOR + type = 'vector' self.scanner.check_type('identifier') name = self.scanner.token self.scanner.scan() (inputs, outputs, trashes) = self.constraints() - if type != TYPE_VECTOR and (inputs or outputs or trashes): + if type == 'vector': + type = VectorType(inputs=inputs, outputs=outputs, trashes=trashes) + elif inputs or outputs or trashes: raise SyntaxError("Cannot apply constraints to non-vector type") addr = None @@ -260,7 +269,7 @@ class Parser(object): self.scanner.scan() if name not in self.symbols: raise SyntaxError('Undefined routine "%s"' % name) - if self.symbols[name].model.type != TYPE_ROUTINE: + if not isinstance(self.symbols[name].model.type, RoutineType): raise SyntaxError('Illegal call of non-routine "%s"' % name) return Instr(opcode=opcode, name=name, dest=None, src=None) elif self.scanner.token in ("copy",):