aboutsummaryrefslogtreecommitdiffstats
path: root/asm
diff options
context:
space:
mode:
authorGravatar Peter McGoron 2023-02-08 13:56:39 +0000
committerGravatar Peter McGoron 2023-02-08 13:56:39 +0000
commite044a7b457da7468d2fb49ef658549ea1b4861af (patch)
treea7cdbb3a8b76e6fba3e935456672240d8d366f52 /asm
parentpython ffi: test parsing (diff)
test refactoring
Diffstat (limited to 'asm')
-rw-r--r--asm/creole.py35
-rw-r--r--asm/ffi.py12
-rw-r--r--asm/test.py56
3 files changed, 88 insertions, 15 deletions
diff --git a/asm/creole.py b/asm/creole.py
index 8e87b58..c1045c5 100644
--- a/asm/creole.py
+++ b/asm/creole.py
@@ -24,16 +24,32 @@ class ArgType(Enum):
def typecheck(self, s):
t = ArgType.gettype(s)
if self == ArgType.VAL:
- return t[0] == ArgType.REG or t[0] == ArgType.IMM
+ if t[0] == ArgType.REG or t[0] == ArgType.IMM:
+ return t
+ else:
+ return None
+ elif t[0] == self:
+ return t
else:
- return t[0] == self
+ return None
class OpcodeException(Exception):
pass
class TypecheckLenException(Exception):
- pass
+ def __init__(self, opcode, insargs, argtypelen):
+ self.opcode = opcode
+ self.insargs = insargs
+ self.argtypelen = argtypelen
+ def __str__(self):
+ return f'arguments {insargs} to opcode {self.opcode} not length {self.argtypelen}'
class TypecheckException(Exception):
- pass
+ def __init__(self, argtype, sarg, i, opcode):
+ self.argtype = argtype
+ self.sarg = sarg
+ self.i = i
+ self.opcode = opcode
+ def __str__(self):
+ return f'opcode {self.opcode} has invalid value {self.sarg} (expected {self.argtype} in position {self.i}'
class Instruction:
def __init__(self, opcode, argtypes):
if opcode > 0x7F or opcode < 0:
@@ -44,12 +60,15 @@ class Instruction:
def typecheck(self, sargs):
rargs = []
if len(sargs) != len(self.argtypes):
- raise TypecheckLenException(sargs, self.argtypes)
+ raise TypecheckLenException(self.opcode, sargs,
+ len(self.argtypes))
for i in range(0, len(sargs)):
- if not self.argtypes[i].typecheck(sargs[i]):
+ t = self.argtypes[i].typecheck(sargs[i])
+ if t is None:
raise TypecheckException(self.argtypes[i],
- sargs[i])
- rargs.append(ArgType.gettype(sargs[i]))
+ sargs[i],
+ i, self.opcode)
+ rargs.append(t)
return rargs
instructions = {
diff --git a/asm/ffi.py b/asm/ffi.py
index 87f6275..7468996 100644
--- a/asm/ffi.py
+++ b/asm/ffi.py
@@ -1,6 +1,18 @@
from ctypes import *
+from enum import Enum
dll = CDLL("./libcreole.so")
+class CompileRet(Enum):
+ COMPILE_OK = 0
+ OPCODE_READ_ERROR = 1
+ OPCODE_MALFORMED = 2
+ ARG_READ_ERROR = 3
+ ARG_MALFORMED = 4
+ LAST_READ_ERROR = 5
+ LAST_MALFORMED = 6
+ LABEL_OVERFLOW = 7
+ TYPE_ERROR = 8
+
class CIns(Structure):
_fields_ = [("opcode", c_int),
("w_flags", c_ubyte * 3),
diff --git a/asm/test.py b/asm/test.py
index dc07655..b9d6520 100644
--- a/asm/test.py
+++ b/asm/test.py
@@ -2,17 +2,57 @@ from creole import *
import unittest
import ffi
-class ProgramTest(unittest.TestCase):
- def test_oneline(self):
+class PushTest(unittest.TestCase):
+ def test_parse_push_reg(self):
p = Program()
- p.parse_asm_line("PUSH r0")
+ p.parse_asm_line("push r5")
b = p()
self.assertEqual(b, b'\x01\xC2\x80\x00')
+ ins = ffi.parse_line(b)
+ self.assertEqual(ins[0], instructions["push"].opcode)
+ self.assertEqual(ins[1][0], (1,5))
+
+ def test_parse_push_catch_typecheck_push_imm(self):
+ p = Program()
+ with self.assertRaises(TypecheckException) as cm:
+ p.parse_asm_line("push 0")
+ self.assertEqual(cm.exception.argtype, ArgType.REG)
+ self.assertEqual(cm.exception.sarg, '0')
+ self.assertEqual(cm.exception.i, 0)
+ self.assertEqual(cm.exception.opcode, 1)
+
+ def test_parse_push_catch_typecheck_push_lab(self):
+ p = Program()
+ with self.assertRaises(TypecheckException) as cm:
+ p.parse_asm_line("push l0")
+ self.assertEqual(cm.exception.argtype, ArgType.REG)
+ self.assertEqual(cm.exception.sarg, 'l0')
+ self.assertEqual(cm.exception.i, 0)
+ self.assertEqual(cm.exception.opcode, 1)
+
+ def test_parse_push_catch_typecheck_argument_overflow(self):
+ p = Program()
+ with self.assertRaises(TypecheckLenException) as cm:
+ p.parse_asm_line("push r1 r2")
+ self.assertEqual(cm.exception.opcode, 1)
+ self.assertEqual(cm.exception.insargs, ["r1", "r2"])
+ self.assertEqual(cm.exception.argtypelen, 1)
+
+ def test_parse_push_catch_typecheck_argument_underflow(self):
+ p = Program()
+ with self.assertRaises(TypecheckLenException) as cm:
+ p.parse_asm_line("push")
+ self.assertEqual(cm.exception.opcode, 1)
+ self.assertEqual(cm.exception.insargs, [])
+ self.assertEqual(cm.exception.argtypelen, 1)
+
def test_large_reg(self):
p = Program(regnum=0x8000000)
p.parse_asm_line("PUSH r134217727")
b = p()
self.assertEqual(b, b'\x01\xFC\x87\xbf\xbf\xbf\xbf\x00')
+
+class ProgramTest(unittest.TestCase):
def test_two(self):
p = Program()
p.parse_asm_line("PUSH r1")
@@ -39,12 +79,14 @@ class ProgramTest(unittest.TestCase):
b = p()
self.assertEqual(b, b_ex)
- def test_parse_reg(self):
+ def test_parse_imm(self):
p = Program()
- p.parse_asm_line("push r5")
+ p.parse_asm_line("add r1 23 3648")
ins = ffi.parse_line(p())
- self.assertEqual(ins[0], instructions["push"].opcode)
- self.assertEqual(ins[1][0], (1,5))
+ self.assertEqual(ins[0], instructions["add"].opcode)
+ self.assertEqual(ins[1][0], (1,1))
+ self.assertEqual(ins[1][1], (0,23))
+ self.assertEqual(ins[1][2], (0,3648))
if __name__ == "__main__":
unittest.main()