WIP ISA Unit tests
Some checks failed
per-push tests / build (push) Successful in 2m55s
per-push tests / test-utility (push) Failing after 1m29s
per-push tests / test-frontend (push) Failing after 1m31s
per-push tests / timed-decomposer-parse (push) Has been skipped
per-push tests / test-backend (push) Failing after 1m4s
Some checks failed
per-push tests / build (push) Successful in 2m55s
per-push tests / test-utility (push) Failing after 1m29s
per-push tests / test-frontend (push) Failing after 1m31s
per-push tests / timed-decomposer-parse (push) Has been skipped
per-push tests / test-backend (push) Failing after 1m4s
Signed-off-by: Ava Affine <ava@sunnypup.io>
This commit is contained in:
parent
609e65a8db
commit
034913e40e
2 changed files with 252 additions and 128 deletions
|
|
@ -278,4 +278,12 @@ mod tests {
|
|||
assert_eq!(g[1], 1);
|
||||
assert_eq!(g[2], 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stack_idx_zero() {
|
||||
let mut g = StackStack::<i8>::new();
|
||||
g.add_stack();
|
||||
g.push_current_stack(2);
|
||||
assert_eq!(g[0], 2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
368
hyphae/src/vm.rs
368
hyphae/src/vm.rs
|
|
@ -62,7 +62,11 @@ pub struct VM {
|
|||
impl From<Program> for VM {
|
||||
fn from(value: Program) -> Self {
|
||||
VM{
|
||||
stack: StackStack::new(),
|
||||
stack: {
|
||||
let mut s = StackStack::new();
|
||||
s.add_stack();
|
||||
s
|
||||
},
|
||||
symtab: QuickMap::new(),
|
||||
prog: value,
|
||||
traps: vec![],
|
||||
|
|
@ -588,123 +592,13 @@ impl VM {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::array;
|
||||
use super::*;
|
||||
use crate::instr;
|
||||
|
||||
const ISA_TESTS: [Option<Vec<(VM, TestResult)>>; instr::TOTAL_INSTRUCTIONS] = [
|
||||
// TRAP
|
||||
None,
|
||||
// BIND
|
||||
None,
|
||||
// UNBIND
|
||||
None,
|
||||
// BOUND
|
||||
None,
|
||||
// PUSH
|
||||
None,
|
||||
// POP
|
||||
None,
|
||||
// ENTER
|
||||
None,
|
||||
// EXIT
|
||||
None,
|
||||
// LOAD
|
||||
None,
|
||||
// DUPL
|
||||
None,
|
||||
// CLEAR
|
||||
None,
|
||||
// NOP
|
||||
None,
|
||||
// HALT
|
||||
None,
|
||||
// PANIC
|
||||
None,
|
||||
// JMP
|
||||
None,
|
||||
// JMPIF
|
||||
None,
|
||||
// EQ
|
||||
None,
|
||||
// LT
|
||||
None,
|
||||
// GT
|
||||
None,
|
||||
// LTE
|
||||
None,
|
||||
// GTE
|
||||
None,
|
||||
// BOOL_NOT
|
||||
None,
|
||||
// BOOL_AND
|
||||
None,
|
||||
// BOOL_OR
|
||||
None,
|
||||
// BYTE_AND
|
||||
None,
|
||||
// BYTE_OR
|
||||
None,
|
||||
// XOR
|
||||
None,
|
||||
// BYTE_NOT
|
||||
None,
|
||||
// ADD
|
||||
None,
|
||||
// SUB
|
||||
None,
|
||||
// MUL
|
||||
None,
|
||||
// FDIV
|
||||
None,
|
||||
// IDIV
|
||||
None,
|
||||
// POW
|
||||
None,
|
||||
// MODULO
|
||||
None,
|
||||
// REM
|
||||
None,
|
||||
// INC
|
||||
None,
|
||||
// DEC
|
||||
None,
|
||||
// CTON
|
||||
None,
|
||||
// NTOC
|
||||
None,
|
||||
// NTOI
|
||||
None,
|
||||
// NTOE
|
||||
None,
|
||||
// CONST
|
||||
None,
|
||||
// MKVEC
|
||||
None,
|
||||
// MKBVEC
|
||||
None,
|
||||
// INDEX
|
||||
None,
|
||||
// LENGTH
|
||||
None,
|
||||
// SUBSL
|
||||
None,
|
||||
// INSER
|
||||
None,
|
||||
// CONS
|
||||
None,
|
||||
// CAR
|
||||
None,
|
||||
// CDR
|
||||
None,
|
||||
// CONCAT
|
||||
None,
|
||||
// S_APPEND
|
||||
None,
|
||||
];
|
||||
use crate::instr as i;
|
||||
use crate::util::{Program, Instruction, Operand};
|
||||
use core::ops::Deref;
|
||||
|
||||
fn has_stack(state: &VM, idx: usize, target: Gc<Datum>) -> bool {
|
||||
*(state.stack[idx]) == *target
|
||||
state.stack[idx].deref() == target.deref()
|
||||
}
|
||||
|
||||
fn has_sym(state: &VM, sym: &str, operand: Option<Operand>) -> bool {
|
||||
|
|
@ -740,6 +634,7 @@ mod tests {
|
|||
fn chk_stack(&self, state: &VM) -> bool {
|
||||
for i in &self.stack {
|
||||
if !has_stack(&state, i.0, i.1.clone()) {
|
||||
print!("expected stack to have {:?} at {}\n", *i.1, i.0);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -755,7 +650,7 @@ mod tests {
|
|||
true
|
||||
}
|
||||
|
||||
fn test_passes(&self, state: VM) -> bool {
|
||||
fn test_passes(&self, state: &VM) -> bool {
|
||||
(self.expr.is_none() || self.chk_expr(&state)) &&
|
||||
(self.stack.is_empty() || self.chk_stack(&state)) &&
|
||||
(self.syms.is_empty() || self.chk_syms(&state)) &&
|
||||
|
|
@ -764,18 +659,239 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn run_isa_tests() {
|
||||
for i in &ISA_TESTS.to_vec() {
|
||||
let Some(test_case) = i else {
|
||||
assert!(false); // dont let untested instructions happen
|
||||
return
|
||||
fn isa_trap_tests() {
|
||||
let mut vm = VM::from(Program(vec![
|
||||
Instruction(i::TRAP, vec![Operand(Address::Numer, 0)])
|
||||
])).with_traps(Some(vec![
|
||||
Arc::from(|state: &mut VM| {
|
||||
state.expr = Datum::Bool(true).into()
|
||||
})
|
||||
])).to_owned();
|
||||
|
||||
let case = TestResult{
|
||||
expr: Some(Datum::Bool(true).into()),
|
||||
stack: vec![],
|
||||
syms: vec![],
|
||||
errr: None,
|
||||
};
|
||||
|
||||
for i in test_case {
|
||||
let (mut vm, result) = (i.0.clone(), i.1.clone());
|
||||
vm.run_program();
|
||||
assert!(result.test_passes(vm));
|
||||
}
|
||||
}
|
||||
assert!(case.test_passes(&vm));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn isa_symtable_tests() {
|
||||
let mut vm = VM::from(Program(vec![
|
||||
Instruction(i::BIND, vec![Operand(Address::Stack, 0),
|
||||
Operand(Address::Stack, 1)]),
|
||||
])).with_stack(Some({
|
||||
let mut i = StackStack::<Gc<Datum>>::new();
|
||||
i.push_current_stack(Datum::String("test".into()).into());
|
||||
i.push_current_stack(Datum::String("value".into()).into());
|
||||
i
|
||||
})).to_owned();
|
||||
|
||||
let case = TestResult{
|
||||
expr: None,
|
||||
stack: vec![
|
||||
(0, Datum::String("test".into()).into()),
|
||||
(1, Datum::String("value".into()).into()),
|
||||
],
|
||||
syms: vec![("test", Some(Operand(Address::Stack, 1)))],
|
||||
errr: None,
|
||||
};
|
||||
|
||||
vm.run_program();
|
||||
assert!(case.test_passes(&vm));
|
||||
|
||||
let mut vm = VM::from(Program(vec![
|
||||
Instruction(i::BIND, vec![Operand(Address::Stack, 0),
|
||||
Operand(Address::Stack, 1)]),
|
||||
Instruction(i::BOUND, vec![Operand(Address::Stack, 0)])
|
||||
])).with_stack(Some({
|
||||
let mut i = StackStack::<Gc<Datum>>::new();
|
||||
i.push_current_stack(Datum::String("test".into()).into());
|
||||
i.push_current_stack(Datum::String("value".into()).into());
|
||||
i
|
||||
})).to_owned();
|
||||
|
||||
let case = TestResult{
|
||||
expr: Some(Datum::Bool(true).into()),
|
||||
stack: vec![
|
||||
(0, Datum::String("test".into()).into()),
|
||||
(1, Datum::String("value".into()).into()),
|
||||
],
|
||||
syms: vec![("test", Some(Operand(Address::Stack, 1)))],
|
||||
errr: None,
|
||||
};
|
||||
|
||||
vm.run_program();
|
||||
assert!(case.test_passes(&vm));
|
||||
|
||||
let mut vm = VM::from(Program(vec![
|
||||
Instruction(i::BIND, vec![Operand(Address::Stack, 0),
|
||||
Operand(Address::Stack, 1)]),
|
||||
Instruction(i::UNBIND, vec![Operand(Address::Stack, 0)])
|
||||
])).with_stack(Some({
|
||||
let mut i = StackStack::<Gc<Datum>>::new();
|
||||
i.push_current_stack(Datum::String("test".into()).into());
|
||||
i.push_current_stack(Datum::String("value".into()).into());
|
||||
i
|
||||
})).to_owned();
|
||||
|
||||
TestResult{
|
||||
expr: None,
|
||||
stack: vec![
|
||||
(0, Datum::String("test".into()).into()),
|
||||
(1, Datum::String("value".into()).into()),
|
||||
],
|
||||
syms: vec![("test", None)],
|
||||
errr: None,
|
||||
};
|
||||
|
||||
vm.run_program();
|
||||
assert!(case.test_passes(&vm));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn isa_stack_tests() {
|
||||
let mut vm = VM::from(Program(vec![
|
||||
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
|
||||
Operand(Address::Numer, 4)]),
|
||||
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)])
|
||||
]));
|
||||
|
||||
let case = TestResult{
|
||||
expr: None,
|
||||
stack: vec![
|
||||
(0, Datum::Number(Number::Fra(Fraction(4, 1))).into())
|
||||
],
|
||||
syms: vec![],
|
||||
errr: None,
|
||||
};
|
||||
|
||||
vm.run_program();
|
||||
assert!(case.test_passes(&vm));
|
||||
|
||||
let mut vm = VM::from(Program(vec![
|
||||
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
|
||||
Operand(Address::Numer, 4)]),
|
||||
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]),
|
||||
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
|
||||
Operand(Address::Numer, 5)]),
|
||||
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]),
|
||||
Instruction(i::POP, vec![])
|
||||
]));
|
||||
|
||||
let case = TestResult{
|
||||
expr: None,
|
||||
stack: vec![
|
||||
(0, Datum::Number(Number::Fra(Fraction(4, 1))).into())
|
||||
],
|
||||
syms: vec![],
|
||||
errr: None,
|
||||
};
|
||||
|
||||
vm.run_program();
|
||||
assert!(case.test_passes(&vm));
|
||||
|
||||
let mut vm = VM::from(Program(vec![
|
||||
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
|
||||
Operand(Address::Numer, 4)]),
|
||||
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]),
|
||||
Instruction(i::ENTER, vec![]),
|
||||
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
|
||||
Operand(Address::Numer, 5)]),
|
||||
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]),
|
||||
]));
|
||||
|
||||
let case = TestResult{
|
||||
expr: None,
|
||||
stack: vec![
|
||||
(0, Datum::Number(Number::Fra(Fraction(4, 1))).into()),
|
||||
(0, Datum::Number(Number::Fra(Fraction(5, 1))).into())
|
||||
],
|
||||
syms: vec![],
|
||||
errr: None,
|
||||
};
|
||||
|
||||
vm.run_program();
|
||||
assert!(case.test_passes(&vm));
|
||||
|
||||
let mut vm = VM::from(Program(vec![
|
||||
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
|
||||
Operand(Address::Numer, 4)]),
|
||||
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]),
|
||||
Instruction(i::ENTER, vec![]),
|
||||
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
|
||||
Operand(Address::Numer, 5)]),
|
||||
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]),
|
||||
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
|
||||
Operand(Address::Numer, 5)]),
|
||||
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]),
|
||||
Instruction(i::EXIT, vec![]),
|
||||
]));
|
||||
|
||||
let case = TestResult{
|
||||
expr: None,
|
||||
stack: vec![
|
||||
(0, Datum::Number(Number::Fra(Fraction(4, 1))).into()),
|
||||
],
|
||||
syms: vec![],
|
||||
errr: None,
|
||||
};
|
||||
|
||||
vm.run_program();
|
||||
assert!(case.test_passes(&vm));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn isa_nop_halt_panic() {
|
||||
let mut vm = VM::from(Program(vec![
|
||||
Instruction(i::NOP, vec![])
|
||||
]));
|
||||
|
||||
let case = TestResult{
|
||||
expr: None,
|
||||
stack: vec![],
|
||||
syms: vec![],
|
||||
errr: None,
|
||||
};
|
||||
|
||||
vm.run_program();
|
||||
assert!(case.test_passes(&vm));
|
||||
|
||||
let mut vm = VM::from(Program(vec![
|
||||
Instruction(i::HALT, vec![]),
|
||||
Instruction(i::PUSH, vec![Operand(Address::Numer, 1)])
|
||||
]));
|
||||
|
||||
let case = TestResult{
|
||||
expr: None,
|
||||
stack: vec![],
|
||||
syms: vec![],
|
||||
errr: None,
|
||||
};
|
||||
|
||||
vm.run_program();
|
||||
assert!(case.test_passes(&vm));
|
||||
|
||||
let mut vm = VM::from(Program(vec![
|
||||
Instruction(i::PANIC, vec![Operand(Address::Stack, 0)])
|
||||
])).with_stack({
|
||||
let mut i = StackStack::<Gc<Datum>>::new();
|
||||
i.push_current_stack(Datum::String("testerr".into()).into());
|
||||
Some(i)
|
||||
}).to_owned();
|
||||
|
||||
let case = TestResult{
|
||||
expr: None,
|
||||
stack: vec![],
|
||||
syms: vec![],
|
||||
errr: Some("testerr"),
|
||||
};
|
||||
|
||||
vm.run_program();
|
||||
assert!(case.test_passes(&vm));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue