mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-25 23:49:17 +00:00
Check that the constraints on a routine match those of vector.
This commit is contained in:
parent
3010435add
commit
7d56705530
@ -5,6 +5,8 @@ History of SixtyPical
|
|||||||
-------
|
-------
|
||||||
|
|
||||||
* Added `routine` and `vector` types, and `copy` instruction.
|
* 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
|
0.5
|
||||||
---
|
---
|
||||||
|
@ -33,10 +33,9 @@ TODO
|
|||||||
|
|
||||||
For 0.6:
|
For 0.6:
|
||||||
|
|
||||||
* declared `inputs` `outputs` `trashes` on the `vector` type...
|
* `call` vector (generates an indirect JMP.)
|
||||||
* we need to get these 3 things onto the type, and also onto routine types
|
|
||||||
* `goto` (tail call) a routine or a vector.
|
* `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:
|
For 0.7:
|
||||||
|
|
||||||
|
20
eg/bad-vector.60p
Normal file
20
eg/bad-vector.60p
Normal file
@ -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
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
from sixtypical.ast import Program, Routine, Block, Instr
|
from sixtypical.ast import Program, Routine, Block, Instr
|
||||||
from sixtypical.model import (
|
from sixtypical.model import (
|
||||||
TYPE_BYTE, TYPE_BYTE_TABLE,
|
TYPE_BYTE, TYPE_BYTE_TABLE,
|
||||||
RoutineType, VectorType,
|
RoutineType, VectorType, ExecutableType,
|
||||||
ConstantRef, LocationRef,
|
ConstantRef, LocationRef,
|
||||||
REG_A, FLAG_Z, FLAG_N, FLAG_V, FLAG_C
|
REG_A, FLAG_Z, FLAG_N, FLAG_V, FLAG_C
|
||||||
)
|
)
|
||||||
@ -37,6 +37,10 @@ class TypeMismatchError(StaticAnalysisError):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class IncompatibleConstraintsError(StaticAnalysisError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Context():
|
class Context():
|
||||||
"""
|
"""
|
||||||
A location is touched if it was changed (or even potentially
|
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:
|
if instr.block2 is not None:
|
||||||
analyze_block(instr.block2, context2, routines)
|
analyze_block(instr.block2, context2, routines)
|
||||||
# TODO may we need to deal with touched separately here too?
|
# 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():
|
for ref in context1.each_meaningful():
|
||||||
context2.assert_meaningful(ref, exception_class=InconsistentInitializationError)
|
context2.assert_meaningful(ref, exception_class=InconsistentInitializationError)
|
||||||
for ref in context2.each_meaningful():
|
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?
|
# NB I *think* that's enough... but it might not be?
|
||||||
elif opcode == 'copy':
|
elif opcode == 'copy':
|
||||||
|
# check that their types are basically compatible
|
||||||
if src.type == dest.type:
|
if src.type == dest.type:
|
||||||
pass
|
pass
|
||||||
elif isinstance(src.type, RoutineType) and isinstance(dest.type, VectorType):
|
elif isinstance(src.type, ExecutableType) and \
|
||||||
|
isinstance(dest.type, VectorType):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise TypeMismatchError((src, dest))
|
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.assert_meaningful(src)
|
||||||
context.set_written(dest)
|
context.set_written(dest)
|
||||||
context.set_touched(REG_A, FLAG_Z, FLAG_N)
|
context.set_touched(REG_A, FLAG_Z, FLAG_N)
|
||||||
|
@ -19,13 +19,13 @@ TYPE_BYTE = Type('byte')
|
|||||||
TYPE_BYTE_TABLE = Type('byte table')
|
TYPE_BYTE_TABLE = Type('byte table')
|
||||||
|
|
||||||
|
|
||||||
class InteractionConstrainedType(Type):
|
class ExecutableType(Type):
|
||||||
"""Used for routines and vectors."""
|
"""Used for routines and vectors."""
|
||||||
def __init__(self, name, inputs=None, outputs=None, trashes=None):
|
def __init__(self, name, inputs=None, outputs=None, trashes=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.inputs = inputs or []
|
self.inputs = inputs or set()
|
||||||
self.outputs = outputs or []
|
self.outputs = outputs or set()
|
||||||
self.trashes = trashes or []
|
self.trashes = trashes or set()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'RoutineType(%r, inputs=%r, outputs=%r, trashes=%r)' % (
|
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)
|
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."""
|
"""This memory location contains the code for a routine."""
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(RoutineType, self).__init__('routine', **kwargs)
|
super(RoutineType, self).__init__('routine', **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class VectorType(InteractionConstrainedType):
|
class VectorType(ExecutableType):
|
||||||
"""This memory location contains the address of a routine."""
|
"""This memory location contains the address of a routine."""
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(VectorType, self).__init__('vector', **kwargs)
|
super(VectorType, self).__init__('vector', **kwargs)
|
||||||
|
@ -149,15 +149,15 @@ class Parser(object):
|
|||||||
return Defn(name=name, addr=addr, location=location)
|
return Defn(name=name, addr=addr, location=location)
|
||||||
|
|
||||||
def constraints(self):
|
def constraints(self):
|
||||||
inputs = []
|
inputs = set()
|
||||||
outputs = []
|
outputs = set()
|
||||||
trashes = []
|
trashes = set()
|
||||||
if self.scanner.consume('inputs'):
|
if self.scanner.consume('inputs'):
|
||||||
inputs = self.locexprs()
|
inputs = set(self.locexprs())
|
||||||
if self.scanner.consume('outputs'):
|
if self.scanner.consume('outputs'):
|
||||||
outputs = self.locexprs()
|
outputs = set(self.locexprs())
|
||||||
if self.scanner.consume('trashes'):
|
if self.scanner.consume('trashes'):
|
||||||
trashes = self.locexprs()
|
trashes = set(self.locexprs())
|
||||||
return (inputs, outputs, trashes)
|
return (inputs, outputs, trashes)
|
||||||
|
|
||||||
def routine(self):
|
def routine(self):
|
||||||
|
@ -1094,4 +1094,28 @@ But not if the vector is declared inappropriately.
|
|||||||
| {
|
| {
|
||||||
| copy foo, vec
|
| 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
|
||||||
|
Loading…
Reference in New Issue
Block a user