Finished WIP (rebase this)
All checks were successful
per-push tests / build (push) Successful in 34s
per-push tests / test-frontend (push) Successful in 31s
per-push tests / test-utility (push) Successful in 36s
per-push tests / test-backend (push) Successful in 30s
per-push tests / timed-decomposer-parse (push) Successful in 34s
All checks were successful
per-push tests / build (push) Successful in 34s
per-push tests / test-frontend (push) Successful in 31s
per-push tests / test-utility (push) Successful in 36s
per-push tests / test-backend (push) Successful in 30s
per-push tests / timed-decomposer-parse (push) Successful in 34s
Signed-off-by: Ava Affine <ava@sunnypup.io>
This commit is contained in:
parent
1359ebdded
commit
63aa66952f
3 changed files with 151 additions and 107 deletions
|
|
@ -53,7 +53,13 @@ description = "delete current stack frame"
|
||||||
name = "load"
|
name = "load"
|
||||||
args = ["src", "dest"]
|
args = ["src", "dest"]
|
||||||
output = ""
|
output = ""
|
||||||
description = "copies src into dest"
|
description = "shallow copies src into dest"
|
||||||
|
|
||||||
|
[[instructions]]
|
||||||
|
name = "dupl"
|
||||||
|
args = ["src", "dest"]
|
||||||
|
output = ""
|
||||||
|
description = "deep copies src into dest"
|
||||||
|
|
||||||
[[instructions]]
|
[[instructions]]
|
||||||
name = "clear"
|
name = "clear"
|
||||||
|
|
@ -247,6 +253,12 @@ args = ["src"]
|
||||||
output = ""
|
output = ""
|
||||||
description = "mutates a number datum into its inexact form"
|
description = "mutates a number datum into its inexact form"
|
||||||
|
|
||||||
|
[[instructions]]
|
||||||
|
name = "const"
|
||||||
|
args = ["dst", "data"]
|
||||||
|
output = ""
|
||||||
|
description = "sets dst location to constant integer data"
|
||||||
|
|
||||||
[[instructions]]
|
[[instructions]]
|
||||||
name = "mkvec"
|
name = "mkvec"
|
||||||
args = []
|
args = []
|
||||||
|
|
@ -300,4 +312,3 @@ name = "cdr"
|
||||||
args = ["list"]
|
args = ["list"]
|
||||||
output = "returns last element in cons cell"
|
output = "returns last element in cons cell"
|
||||||
description = "takes an AST and returns last element in top level cons cell"
|
description = "takes an AST and returns last element in top level cons cell"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,18 +39,6 @@ use organelle::Number;
|
||||||
* function to pass around heap allocated Rcs.
|
* function to pass around heap allocated Rcs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
pub enum Datum {
|
|
||||||
Number(Number),
|
|
||||||
Bool(bool),
|
|
||||||
Cons(Cons),
|
|
||||||
Symbol(String),
|
|
||||||
Char(u8),
|
|
||||||
String(Vec<u8>),
|
|
||||||
Vector(RefCell<Vec<Gc<Datum>>>),
|
|
||||||
ByteVector(RefCell<Vec<u8>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Gc
|
/* Gc
|
||||||
* This is a heap allocated Rc passed around such that it fits into
|
* This is a heap allocated Rc passed around such that it fits into
|
||||||
* a physical register. The pointer is to a Box<Rc<T>>, but custom
|
* a physical register. The pointer is to a Box<Rc<T>>, but custom
|
||||||
|
|
@ -78,6 +66,7 @@ impl<T: PartialEq> PartialEq for Gc<T> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.deref().eq(other.deref())
|
self.deref().eq(other.deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ne(&self, other: &Self) -> bool {
|
fn ne(&self, other: &Self) -> bool {
|
||||||
self.deref().ne(other.deref())
|
self.deref().ne(other.deref())
|
||||||
}
|
}
|
||||||
|
|
@ -143,6 +132,19 @@ impl<T: Clone> Gc<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub enum Datum {
|
||||||
|
Number(Number),
|
||||||
|
Bool(bool),
|
||||||
|
Cons(Cons),
|
||||||
|
Symbol(String),
|
||||||
|
Char(u8),
|
||||||
|
String(Vec<u8>),
|
||||||
|
Vector(RefCell<Vec<Gc<Datum>>>),
|
||||||
|
ByteVector(RefCell<Vec<u8>>),
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct Cons(pub Option<Gc<Datum>>, pub Option<Gc<Datum>>);
|
pub struct Cons(pub Option<Gc<Datum>>, pub Option<Gc<Datum>>);
|
||||||
|
|
||||||
|
|
|
||||||
217
hyphae/src/vm.rs
217
hyphae/src/vm.rs
|
|
@ -27,7 +27,6 @@ use crate::heap::{Gc, Datum};
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use alloc::rc::Rc;
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use alloc::borrow::ToOwned;
|
use alloc::borrow::ToOwned;
|
||||||
|
|
@ -39,7 +38,7 @@ const NUM_OPERAND_REGISTERS: usize = 4;
|
||||||
|
|
||||||
pub struct VM {
|
pub struct VM {
|
||||||
// execution environment
|
// execution environment
|
||||||
pub stack: StackStack<Datum>,
|
pub stack: StackStack<Gc<Datum>>,
|
||||||
pub symtab: QuickMap<Operand>,
|
pub symtab: QuickMap<Operand>,
|
||||||
pub prog: Program,
|
pub prog: Program,
|
||||||
pub fds: Vec<u64>,
|
pub fds: Vec<u64>,
|
||||||
|
|
@ -52,7 +51,7 @@ pub struct VM {
|
||||||
// control flow registers
|
// control flow registers
|
||||||
pub retn: usize,
|
pub retn: usize,
|
||||||
pub ictr: usize,
|
pub ictr: usize,
|
||||||
pub errr: Datum,
|
pub errr: Gc<Datum>,
|
||||||
|
|
||||||
// state
|
// state
|
||||||
pub running: bool,
|
pub running: bool,
|
||||||
|
|
@ -86,13 +85,14 @@ impl VM {
|
||||||
{
|
{
|
||||||
self.running = false;
|
self.running = false;
|
||||||
self.err_state = true;
|
self.err_state = true;
|
||||||
self.errr = Datum::String($err.as_bytes().to_vec());
|
self.errr = Datum::String($err.as_bytes().to_vec()).into();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! deref {
|
// get or set according to addressing mode
|
||||||
|
macro_rules! access {
|
||||||
( $oper:expr ) => {
|
( $oper:expr ) => {
|
||||||
match $oper.0 {
|
match $oper.0 {
|
||||||
Address::Expr => &self.expr,
|
Address::Expr => &self.expr,
|
||||||
|
|
@ -101,23 +101,19 @@ impl VM {
|
||||||
Address::Oper3 => &self.oper[2],
|
Address::Oper3 => &self.oper[2],
|
||||||
Address::Oper4 => &self.oper[3],
|
Address::Oper4 => &self.oper[3],
|
||||||
Address::Stack => &self.stack[$oper.1],
|
Address::Stack => &self.stack[$oper.1],
|
||||||
Address::Numer => e!("attempt to dereference constant numeric data"),
|
Address::Numer => e!("cannot access constant numeric"),
|
||||||
Address::Instr => e!("bad access to instruction data"),
|
Address::Instr => e!("bad access to instruction data"),
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! deref_mut {
|
( $data:expr, $target:expr ) => {
|
||||||
( $oper:expr ) => {
|
match $data.0 {
|
||||||
match $oper.0 {
|
Address::Expr => self.expr = $target,
|
||||||
Address::Expr => &mut self.expr,
|
Address::Oper1 => self.oper[0] = $target,
|
||||||
Address::Oper1 => &mut self.oper[0],
|
Address::Oper2 => self.oper[1] = $target,
|
||||||
Address::Oper2 => &mut self.oper[1],
|
Address::Oper3 => self.oper[2] = $target,
|
||||||
Address::Oper3 => &mut self.oper[2],
|
Address::Oper4 => self.oper[3] = $target,
|
||||||
Address::Oper4 => &mut self.oper[3],
|
_ => e!("attempted mutation of immutable address"),
|
||||||
Address::Instr => e!("bad mutable access to instruction data"),
|
|
||||||
// Stack, Numer
|
|
||||||
_ => e!("mutable access to immutable data"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -138,10 +134,10 @@ impl VM {
|
||||||
|
|
||||||
macro_rules! lr_oper {
|
macro_rules! lr_oper {
|
||||||
( $in_type:ident, $oper:tt, $out_type:ident ) => {
|
( $in_type:ident, $oper:tt, $out_type:ident ) => {
|
||||||
self.expr = Datum::$out_type(*match deref!(&instr.1[0]){
|
self.expr = Datum::$out_type(match **access!(&instr.1[0]){
|
||||||
Datum::$in_type(l) => l,
|
Datum::$in_type(l) => l,
|
||||||
_ => e!("illegal argument to instruction"),
|
_ => e!("illegal argument to instruction"),
|
||||||
} $oper *match deref!(&instr.1[1]){
|
} $oper match **access!(&instr.1[1]){
|
||||||
Datum::$in_type(l) => l,
|
Datum::$in_type(l) => l,
|
||||||
_ => e!("illegal argument to instruction"),
|
_ => e!("illegal argument to instruction"),
|
||||||
}).into()
|
}).into()
|
||||||
|
|
@ -163,38 +159,40 @@ impl VM {
|
||||||
|
|
||||||
// symtable ops
|
// symtable ops
|
||||||
i::BIND => {
|
i::BIND => {
|
||||||
let Datum::String(tag) = deref!(&instr.1[0]) else {
|
let Datum::String(ref tag) = **access!(&instr.1[0]) else {
|
||||||
e!("illegal argument to BIND instruction");
|
e!("illegal argument to BIND instruction");
|
||||||
};
|
};
|
||||||
let tag = unsafe { str::from_utf8_unchecked(&tag).to_owned() };
|
let tag = unsafe { str::from_utf8_unchecked(tag).to_owned() };
|
||||||
self.symtab.insert(tag, instr.1[1].clone());
|
self.symtab.insert(tag, instr.1[1].clone());
|
||||||
},
|
},
|
||||||
|
|
||||||
i::UNBIND => {
|
i::UNBIND => {
|
||||||
let Datum::String(tag) = deref!(&instr.1[0]) else {
|
let Datum::String(ref tag) = **access!(&instr.1[0]) else {
|
||||||
e!("illegal argument to UNBIND instruction");
|
e!("illegal argument to UNBIND instruction");
|
||||||
};
|
};
|
||||||
let tag = unsafe { str::from_utf8_unchecked(&tag) };
|
let tag = unsafe { str::from_utf8_unchecked(tag) };
|
||||||
self.symtab.remove(&tag);
|
self.symtab.remove(tag);
|
||||||
},
|
},
|
||||||
|
|
||||||
i::BOUND => {
|
i::BOUND => {
|
||||||
let Datum::String(tag) = deref!(&instr.1[0]) else {
|
let Datum::String(ref tag) = **access!(&instr.1[0]) else {
|
||||||
e!("illegal argument to BOUND instruction");
|
e!("illegal argument to BOUND instruction");
|
||||||
};
|
};
|
||||||
let tag = unsafe { str::from_utf8_unchecked(&tag) };
|
let tag = unsafe { str::from_utf8_unchecked(tag) };
|
||||||
self.symtab.contains_key(&tag);
|
self.symtab.contains_key(tag);
|
||||||
},
|
},
|
||||||
|
|
||||||
// stack ops
|
// stack ops
|
||||||
i::PUSH => self.stack.push_current_stack(deref!(&instr.1[0]).clone()),
|
i::PUSH => self.stack.push_current_stack(
|
||||||
|
access!(&instr.1[0]).clone()),
|
||||||
i::POP => _ = self.stack.pop_current_stack(),
|
i::POP => _ = self.stack.pop_current_stack(),
|
||||||
i::ENTER => self.stack.add_stack(),
|
i::ENTER => self.stack.add_stack(),
|
||||||
i::EXIT => self.stack.destroy_top_stack(),
|
i::EXIT => self.stack.destroy_top_stack(),
|
||||||
|
|
||||||
// movement ops
|
// movement ops
|
||||||
i::LOAD => *deref_mut!(&instr.1[1]) = deref!(&instr.1[0]).clone(),
|
i::LOAD => access!(&instr.1[1], access!(&instr.1[0]).clone()),
|
||||||
i::CLEAR => *deref_mut!(&instr.1[0]) = Datum::None,
|
i::DUPL => access!(&instr.1[1], access!(&instr.1[0]).deep_copy()),
|
||||||
|
i::CLEAR => access!(&instr.1[0], Datum::None.into()),
|
||||||
|
|
||||||
// control flow ops
|
// control flow ops
|
||||||
i::NOP => (),
|
i::NOP => (),
|
||||||
|
|
@ -202,7 +200,7 @@ impl VM {
|
||||||
i::PANIC => {
|
i::PANIC => {
|
||||||
self.running = false;
|
self.running = false;
|
||||||
self.err_state = false;
|
self.err_state = false;
|
||||||
self.errr = deref!(&instr.1[0]).clone()
|
self.errr = access!(&instr.1[0]).clone();
|
||||||
},
|
},
|
||||||
|
|
||||||
i::JMP => {
|
i::JMP => {
|
||||||
|
|
@ -217,7 +215,7 @@ impl VM {
|
||||||
|
|
||||||
// boolean ops
|
// boolean ops
|
||||||
i::EQ => self.expr =
|
i::EQ => self.expr =
|
||||||
Datum::Bool(*deref!(&instr.1[0]) == *deref!(&instr.1[1])).into(),
|
Datum::Bool(*access!(&instr.1[0]) == *access!(&instr.1[1])).into(),
|
||||||
i::LT => lr_oper!(Number, <, Bool),
|
i::LT => lr_oper!(Number, <, Bool),
|
||||||
i::GT => lr_oper!(Number, >, Bool),
|
i::GT => lr_oper!(Number, >, Bool),
|
||||||
i::LTE => lr_oper!(Number, <=, Bool),
|
i::LTE => lr_oper!(Number, <=, Bool),
|
||||||
|
|
@ -253,11 +251,11 @@ impl VM {
|
||||||
i::MUL => lr_oper!(Number, *, Number),
|
i::MUL => lr_oper!(Number, *, Number),
|
||||||
i::FDIV => lr_oper!(Number, /, Number),
|
i::FDIV => lr_oper!(Number, /, Number),
|
||||||
i::IDIV => {
|
i::IDIV => {
|
||||||
let Datum::Number(l) = deref!(&instr.1[0]) else {
|
let Datum::Number(ref l) = **access!(&instr.1[0]) else {
|
||||||
e!("illegal argument to IDIV instruction");
|
e!("illegal argument to IDIV instruction");
|
||||||
};
|
};
|
||||||
|
|
||||||
let Datum::Number(r) = deref!(&instr.1[1]) else {
|
let Datum::Number(ref r) = **access!(&instr.1[1]) else {
|
||||||
e!("illgal argument to IDIV instruction");
|
e!("illgal argument to IDIV instruction");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -273,57 +271,83 @@ impl VM {
|
||||||
},
|
},
|
||||||
|
|
||||||
i::POW => {
|
i::POW => {
|
||||||
let Datum::Number(l) = deref!(&instr.1[0]) else {
|
let Datum::Number(ref l) = **access!(&instr.1[0]) else {
|
||||||
e!("illegal argument to POW instruction");
|
e!("illegal argument to POW instruction");
|
||||||
};
|
};
|
||||||
|
|
||||||
let Datum::Number(r) = deref!(&instr.1[1]) else {
|
let Datum::Number(ref r) = **access!(&instr.1[1]) else {
|
||||||
e!("illgal argument to POW instruction");
|
e!("illgal argument to POW instruction");
|
||||||
};
|
};
|
||||||
|
|
||||||
self.expr = Datum::Number((*l).pow(*r)).into();
|
self.expr = Datum::Number(l.clone().pow(r.clone())).into();
|
||||||
},
|
},
|
||||||
|
|
||||||
i::INC => if let Datum::Number(src) = deref_mut!(&instr.1[0]) {
|
i::INC => access!(&instr.1[0], {
|
||||||
*src = *src + Number::Fra(Fraction(1, 1));
|
if let Datum::Number(src) = **access!(&instr.1[0]) {
|
||||||
} else {
|
Datum::Number(src + Number::Fra(Fraction(1, 1))).into()
|
||||||
|
} else {
|
||||||
e!("illegal argument to INC instruction");
|
e!("illegal argument to INC instruction");
|
||||||
},
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
i::DEC => if let Datum::Number(src) = deref_mut!(&instr.1[0]) {
|
i::DEC => access!(&instr.1[0], {
|
||||||
*src = *src - Number::Fra(Fraction(1, 1));
|
if let Datum::Number(src) = **access!(&instr.1[0]) {
|
||||||
} else {
|
Datum::Number(src - Number::Fra(Fraction(1, 1))).into()
|
||||||
|
} else {
|
||||||
e!("illegal argument to INC instruction");
|
e!("illegal argument to INC instruction");
|
||||||
},
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
// byte/char to and from number conversions
|
// byte/char to and from number conversions
|
||||||
i::CTON => {
|
i::CTON => access!(&instr.1[0], {
|
||||||
let src = deref_mut!(&instr.1[0]);
|
if let Datum::Char(schr) = **access!(&instr.1[0]) {
|
||||||
if let Datum::Char(schr) = src {
|
Datum::Number(Number::Fra(Fraction(schr as isize, 1))).into()
|
||||||
*src = Datum::Number(Number::Fra(Fraction(*schr as isize, 1)));
|
|
||||||
} else {
|
} else {
|
||||||
e!("illegal argument to CTON instruction");
|
e!("illegal argument to INC instruction");
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
|
|
||||||
i::NTOC => {
|
i::NTOC => access!(&instr.1[0], {
|
||||||
let src = deref_mut!(&instr.1[0]);
|
if let Datum::Number(snum) = **access!(&instr.1[0]) {
|
||||||
if let Datum::Number(snum) = src {
|
|
||||||
let n = snum.make_inexact();
|
let n = snum.make_inexact();
|
||||||
if !snum.is_exact() || n.0.fract() != 0.0 || n.0 > u8::MAX.into() || n.0 < 0.0 {
|
if !snum.is_exact() || n.0.fract() != 0.0 ||
|
||||||
e!("input to NTOC cannot cleanly convert");
|
n.0 > u8::MAX.into() || n.0 < 0.0 {
|
||||||
}
|
e!("input to NTOC cannot cleanly convert");
|
||||||
*src = Datum::Char(n.0.trunc() as u64 as u8);
|
}
|
||||||
|
Datum::Char(n.0.trunc() as u64 as u8).into()
|
||||||
} else {
|
} else {
|
||||||
e!("illegal argument to NTOC instruction");
|
e!("illegal argument to INC instruction");
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
i::NTOI => {
|
||||||
|
let src = access!(&instr.1[0]);
|
||||||
|
if let Datum::Number(snum) = **src {
|
||||||
|
access!(&instr.1[0],
|
||||||
|
Datum::Number(snum.make_inexact().into()).into())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
i::NTOE => {
|
||||||
|
let src = access!(&instr.1[0]);
|
||||||
|
if let Datum::Number(snum) = **src {
|
||||||
|
access!(&instr.1[0], Datum::Number(snum.make_inexact().into())
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
i::CONST => access!(&instr.1[0], {
|
||||||
|
let Operand(Address::Numer, num) = instr.1[0] else {
|
||||||
|
e!("illegal argument to CONST instruction");
|
||||||
|
};
|
||||||
|
|
||||||
|
Datum::Number(Number::Fra(Fraction(num as isize, 1))).into()
|
||||||
|
}),
|
||||||
|
|
||||||
i::MKVEC => self.expr = Datum::Vector(RefCell::from(vec![])).into(),
|
i::MKVEC => self.expr = Datum::Vector(RefCell::from(vec![])).into(),
|
||||||
i::MKBVEC => self.expr = Datum::ByteVector(RefCell::from(vec![])).into(),
|
i::MKBVEC => self.expr = Datum::ByteVector(RefCell::from(vec![])).into(),
|
||||||
i::INDEX => {
|
i::INDEX => {
|
||||||
let Datum::Number(idx) = deref!(&instr.1[1]) else {
|
let Datum::Number(ref idx) = **access!(&instr.1[1]) else {
|
||||||
e!("illegal argument to INDEX instruction");
|
e!("illegal argument to INDEX instruction");
|
||||||
};
|
};
|
||||||
let idx = idx.make_inexact();
|
let idx = idx.make_inexact();
|
||||||
|
|
@ -332,40 +356,43 @@ impl VM {
|
||||||
}
|
}
|
||||||
let idx = idx.0.trunc() as usize;
|
let idx = idx.0.trunc() as usize;
|
||||||
|
|
||||||
match deref!(&instr.1[0]) {
|
match **access!(&instr.1[0]) {
|
||||||
Datum::Vector(v) => {
|
Datum::Vector(ref v) => {
|
||||||
let a = (*v.borrow()[idx].clone()).clone();
|
let a = (*v.borrow()[idx].clone()).clone();
|
||||||
self.expr = a.into();
|
self.expr = a.into();
|
||||||
},
|
},
|
||||||
Datum::ByteVector(bv) => {
|
Datum::ByteVector(ref bv) => {
|
||||||
let a = Datum::Char(bv.borrow()[idx]);
|
let a = Datum::Char(bv.borrow()[idx]);
|
||||||
self.expr = a.into();
|
self.expr = a.into();
|
||||||
},
|
},
|
||||||
Datum::Cons(l) => self.expr = l[idx].clone(),
|
Datum::Cons(ref l) => self.expr = l[idx].clone(),
|
||||||
_ => e!("illegal argument to INDEX instruction")
|
_ => e!("illegal argument to INDEX instruction")
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
i::LENGTH => match deref!(&instr.1[0]) {
|
i::LENGTH => match **access!(&instr.1[0]) {
|
||||||
Datum::Vector(v) => {
|
Datum::Vector(ref v) => {
|
||||||
let a = Datum::Number(Number::Fra(Fraction(v.borrow().len() as isize, 1)));
|
let a = Datum::Number(Number::Fra(Fraction(
|
||||||
|
v.borrow().len() as isize, 1)));
|
||||||
self.expr = a.into();
|
self.expr = a.into();
|
||||||
},
|
},
|
||||||
Datum::ByteVector(bv) => {
|
Datum::ByteVector(ref bv) => {
|
||||||
let a = Datum::Number(Number::Fra(Fraction(bv.borrow().len() as isize, 1)));
|
let a = Datum::Number(Number::Fra(Fraction(
|
||||||
|
bv.borrow().len() as isize, 1)));
|
||||||
self.expr = a.into();
|
self.expr = a.into();
|
||||||
},
|
},
|
||||||
Datum::Cons(l) => self.expr =
|
Datum::Cons(ref l) => self.expr =
|
||||||
Datum::Number(Number::Fra(Fraction(l.len() as isize, 1))).into(),
|
Datum::Number(Number::Fra(Fraction(l.len() as isize, 1)))
|
||||||
|
.into(),
|
||||||
_ => e!("illegal argument to LENGTH instruction"),
|
_ => e!("illegal argument to LENGTH instruction"),
|
||||||
},
|
},
|
||||||
|
|
||||||
i::SUBSL => {
|
i::SUBSL => {
|
||||||
let Datum::Number(st) = deref!(&instr.1[1]) else {
|
let Datum::Number(ref st) = **access!(&instr.1[1]) else {
|
||||||
e!("illegal argument to SUBSL instruction");
|
e!("illegal argument to SUBSL instruction");
|
||||||
};
|
};
|
||||||
|
|
||||||
let Datum::Number(ed) = deref!(&instr.1[2]) else {
|
let Datum::Number(ref ed) = **access!(&instr.1[2]) else {
|
||||||
e!("illegal argument to SUBSL instruction");
|
e!("illegal argument to SUBSL instruction");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -383,25 +410,24 @@ impl VM {
|
||||||
let st = st.0.trunc() as usize;
|
let st = st.0.trunc() as usize;
|
||||||
let ed = ed.0.trunc() as usize;
|
let ed = ed.0.trunc() as usize;
|
||||||
|
|
||||||
match deref!(&instr.1[0]) {
|
match **access!(&instr.1[0]) {
|
||||||
Datum::Vector(v) => {
|
Datum::Vector(ref v) => {
|
||||||
let a = Datum::Vector(RefCell::from(v.borrow()[st..ed].to_vec()));
|
let a = Datum::Vector(RefCell::from(v.borrow()[st..ed].to_vec()));
|
||||||
self.expr = a.into();
|
self.expr = a.into();
|
||||||
},
|
},
|
||||||
Datum::ByteVector(bv) => {
|
Datum::ByteVector(ref bv) => {
|
||||||
let a = Datum::ByteVector(RefCell::from(bv.borrow()[st..ed].to_vec()));
|
let a = Datum::ByteVector(RefCell::from(bv.borrow()[st..ed].to_vec()));
|
||||||
self.expr = a.into();
|
self.expr = a.into();
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: do I deep copy the subslice?
|
Datum::Cons(ref a) => self.expr =
|
||||||
Datum::Cons(a) => self.expr =
|
|
||||||
Datum::Cons(a.subsl(st as isize, ed as isize)).into(),
|
Datum::Cons(a.subsl(st as isize, ed as isize)).into(),
|
||||||
_ => e!("illegal argument to SUBSL instruction")
|
_ => e!("illegal argument to SUBSL instruction")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
i::INSER => {
|
i::INSER => {
|
||||||
let Datum::Number(idx) = deref!(&instr.1[2]) else {
|
let Datum::Number(ref idx) = **access!(&instr.1[2]) else {
|
||||||
e!("illegal argument to INSER instruction");
|
e!("illegal argument to INSER instruction");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -412,35 +438,40 @@ impl VM {
|
||||||
|
|
||||||
let idx = idx.0.trunc() as usize;
|
let idx = idx.0.trunc() as usize;
|
||||||
|
|
||||||
match deref!(&instr.1[0]) {
|
match **access!(&instr.1[0]) {
|
||||||
Datum::Vector(v) => {
|
Datum::Vector(ref v) => {
|
||||||
v.borrow_mut().insert(idx, deref!(&instr.1[1]).clone().into());
|
v.borrow_mut()
|
||||||
|
.insert(idx, access!(&instr.1[1])
|
||||||
|
.deep_copy());
|
||||||
},
|
},
|
||||||
Datum::ByteVector(bv) => {
|
Datum::ByteVector(ref bv) => {
|
||||||
let Datum::Char(b) = deref!(&instr.1[1]) else {
|
let Datum::Char(b) = **access!(&instr.1[1]) else {
|
||||||
e!("INSER instruction can only insert a byte into a bytevector");
|
e!("INSER instruction can only insert a byte into a bytevector");
|
||||||
};
|
};
|
||||||
bv.borrow_mut().insert(idx, *b);
|
bv.borrow_mut().insert(idx, b);
|
||||||
},
|
},
|
||||||
_ => e!("illegal argument to INSER instruction")
|
_ => e!("illegal argument to INSER instruction")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
i::CAR => {
|
i::CAR => {
|
||||||
let Datum::Cons(arg) = deref!(&instr.1[0]) else {
|
let Datum::Cons(ref arg) = **access!(&instr.1[0]) else {
|
||||||
e!("illegal argument to CAR instruction");
|
e!("illegal argument to CAR instruction");
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: need a none type dont we now
|
self.expr = arg.clone().0
|
||||||
self.expr = (*arg.0).clone();
|
.or(Some(Datum::None.into()))
|
||||||
|
.expect("CAR instruction option consistency");
|
||||||
},
|
},
|
||||||
|
|
||||||
i::CDR => {
|
i::CDR => {
|
||||||
let Datum::Cons(arg) = deref!(&instr.1[0]) else {
|
let Datum::Cons(ref arg) = **access!(&instr.1[0]) else {
|
||||||
e!("illegal argument to CAR instruction");
|
e!("illegal argument to CAR instruction");
|
||||||
};
|
};
|
||||||
|
|
||||||
self.expr = (*arg.1).clone();
|
self.expr = arg.clone().1
|
||||||
|
.or(Some(Datum::None.into()))
|
||||||
|
.expect("CDR instruction option consistency");
|
||||||
},
|
},
|
||||||
|
|
||||||
i::CONS => {
|
i::CONS => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue