From 7d56705530f2ef47e9eb7115a97bd73c059c7608 Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Mon, 19 Oct 2015 19:17:27 +0100 Subject: [PATCH] Check that the constraints on a routine match those of vector. --- HISTORY.markdown | 2 ++ README.markdown | 5 ++--- eg/bad-vector.60p | 20 ++++++++++++++++++++ src/sixtypical/analyzer.py | 24 ++++++++++++++++++++++-- src/sixtypical/model.py | 12 ++++++------ src/sixtypical/parser.py | 12 ++++++------ tests/SixtyPical Analysis.md | 26 +++++++++++++++++++++++++- 7 files changed, 83 insertions(+), 18 deletions(-) create mode 100644 eg/bad-vector.60p diff --git a/HISTORY.markdown b/HISTORY.markdown index 7539862..d281041 100644 --- a/HISTORY.markdown +++ b/HISTORY.markdown @@ -5,6 +5,8 @@ History of SixtyPical ------- * Added `routine` and `vector` types, and `copy` instruction. +* Both routines and vectors can declare `inputs`, `outputs`, and `trashes`, + and these must be compatible to assign a routine or vector to a vector. 0.5 --- diff --git a/README.markdown b/README.markdown index 7b1d9bf..3831af3 100644 --- a/README.markdown +++ b/README.markdown @@ -33,10 +33,9 @@ TODO For 0.6: -* declared `inputs` `outputs` `trashes` on the `vector` type... - * we need to get these 3 things onto the type, and also onto routine types +* `call` vector (generates an indirect JMP.) * `goto` (tail call) a routine or a vector. -* A more involved demo for the C64 — one that sets up an interrupt. +* A more involved demo for the C64 — one that sets up an interrupt? For 0.7: diff --git a/eg/bad-vector.60p b/eg/bad-vector.60p new file mode 100644 index 0000000..3671924 --- /dev/null +++ b/eg/bad-vector.60p @@ -0,0 +1,20 @@ +vector vec + inputs y + outputs y + trashes z, n + +routine foo + inputs x + outputs x + trashes z, n +{ + inc x +} + +routine main + inputs foo + outputs vec + trashes a, z, n +{ + copy foo, vec +} diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index 8babfbd..06593fa 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -3,7 +3,7 @@ from sixtypical.ast import Program, Routine, Block, Instr from sixtypical.model import ( TYPE_BYTE, TYPE_BYTE_TABLE, - RoutineType, VectorType, + RoutineType, VectorType, ExecutableType, ConstantRef, LocationRef, REG_A, FLAG_Z, FLAG_N, FLAG_V, FLAG_C ) @@ -37,6 +37,10 @@ class TypeMismatchError(StaticAnalysisError): pass +class IncompatibleConstraintsError(StaticAnalysisError): + pass + + class Context(): """ A location is touched if it was changed (or even potentially @@ -209,6 +213,8 @@ def analyze_instr(instr, context, routines): if instr.block2 is not None: analyze_block(instr.block2, context2, routines) # TODO may we need to deal with touched separately here too? + # probably not; if it wasn't meaningful in the first place, it + # doesn't really matter if you modified it or not, coming out. for ref in context1.each_meaningful(): context2.assert_meaningful(ref, exception_class=InconsistentInitializationError) for ref in context2.each_meaningful(): @@ -225,12 +231,26 @@ def analyze_instr(instr, context, routines): # NB I *think* that's enough... but it might not be? elif opcode == 'copy': + # check that their types are basically compatible if src.type == dest.type: pass - elif isinstance(src.type, RoutineType) and isinstance(dest.type, VectorType): + elif isinstance(src.type, ExecutableType) and \ + isinstance(dest.type, VectorType): pass else: raise TypeMismatchError((src, dest)) + + # if dealing with routines and vectors, + # check that they're not incompatible + if isinstance(src.type, ExecutableType) and \ + isinstance(dest.type, VectorType): + if not (src.type.inputs <= dest.type.inputs): + raise IncompatibleConstraintsError(src.type.inputs - dest.type.inputs) + if not (src.type.outputs <= dest.type.outputs): + raise IncompatibleConstraintsError(src.type.outputs - dest.type.outputs) + if not (src.type.trashes <= dest.type.trashes): + raise IncompatibleConstraintsError(src.type.trashes - dest.type.trashes) + context.assert_meaningful(src) context.set_written(dest) context.set_touched(REG_A, FLAG_Z, FLAG_N) diff --git a/src/sixtypical/model.py b/src/sixtypical/model.py index 3c356df..ea174f4 100644 --- a/src/sixtypical/model.py +++ b/src/sixtypical/model.py @@ -19,13 +19,13 @@ TYPE_BYTE = Type('byte') TYPE_BYTE_TABLE = Type('byte table') -class InteractionConstrainedType(Type): +class ExecutableType(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 [] + self.inputs = inputs or set() + self.outputs = outputs or set() + self.trashes = trashes or set() def __repr__(self): return 'RoutineType(%r, inputs=%r, outputs=%r, trashes=%r)' % ( @@ -44,13 +44,13 @@ class InteractionConstrainedType(Type): return hash(self.name) ^ hash(self.inputs) ^ hash(self.outputs) ^ hash(self.trashes) -class RoutineType(InteractionConstrainedType): +class RoutineType(ExecutableType): """This memory location contains the code for a routine.""" def __init__(self, **kwargs): super(RoutineType, self).__init__('routine', **kwargs) -class VectorType(InteractionConstrainedType): +class VectorType(ExecutableType): """This memory location contains the address of a routine.""" def __init__(self, **kwargs): super(VectorType, self).__init__('vector', **kwargs) diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index ee30dc9..46b246a 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -149,15 +149,15 @@ class Parser(object): return Defn(name=name, addr=addr, location=location) def constraints(self): - inputs = [] - outputs = [] - trashes = [] + inputs = set() + outputs = set() + trashes = set() if self.scanner.consume('inputs'): - inputs = self.locexprs() + inputs = set(self.locexprs()) if self.scanner.consume('outputs'): - outputs = self.locexprs() + outputs = set(self.locexprs()) if self.scanner.consume('trashes'): - trashes = self.locexprs() + trashes = set(self.locexprs()) return (inputs, outputs, trashes) def routine(self): diff --git a/tests/SixtyPical Analysis.md b/tests/SixtyPical Analysis.md index f514576..cf5276a 100644 --- a/tests/SixtyPical Analysis.md +++ b/tests/SixtyPical Analysis.md @@ -1094,4 +1094,28 @@ But not if the vector is declared inappropriately. | { | copy foo, vec | } - ? IllegalWriteError + ? IncompatibleConstraintsError + +Routines are read-only. + + | vector vec + | inputs x + | outputs x + | trashes z, n + | + | routine foo + | inputs x + | outputs x + | trashes z, n + | { + | inc x + | } + | + | routine main + | inputs foo + | outputs vec + | trashes a, z, n + | { + | copy vec, foo + | } + ? TypeMismatchError