pub mod compile;
pub mod exec;
use crate::env::Value;
use crate::eval::Expr;
use ndarray::Array2;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Opcode {
PushConst = 0, LoadVar = 1, StoreVar = 2, UpdateAns = 3, Pop = 4, Print = 5, LoadSlot = 6, StoreSlot = 7,
Add = 10,
Sub = 11,
Mul = 12,
Div = 13,
Pow = 14,
ElemMul = 15,
ElemDiv = 16,
ElemPow = 17,
Neg = 18,
Not = 20,
Eq = 21,
Ne = 22,
Lt = 23,
Le = 24,
Gt = 25,
Ge = 26,
And = 27,
Or = 28,
Jump = 30, JumpFalsy = 31, #[allow(dead_code)]
JumpTruthy = 32,
PushIter = 40,
IterNext = 41, PopIter = 42,
IterNextSlot = 43,
CallBuiltin = 50,
EvalExpr = 60,
IndexSetOp = 80,
DefineFunc = 75,
Return = 70,
}
pub struct Instr {
pub op: Opcode,
payload: [u8; 7],
}
const _INSTR_SIZE: () = assert!(std::mem::size_of::<Instr>() == 8);
impl Instr {
pub fn no_arg(op: Opcode) -> Self {
Self {
op,
payload: [0; 7],
}
}
pub fn with_u16(op: Opcode, v: u16) -> Self {
let mut p = [0u8; 7];
p[0..2].copy_from_slice(&v.to_le_bytes());
Self { op, payload: p }
}
pub fn with_i32(op: Opcode, v: i32) -> Self {
let mut p = [0u8; 7];
p[0..4].copy_from_slice(&v.to_le_bytes());
Self { op, payload: p }
}
pub fn with_u16_u8(op: Opcode, idx: u16, flag: u8) -> Self {
let mut p = [0u8; 7];
p[0..2].copy_from_slice(&idx.to_le_bytes());
p[2] = flag;
Self { op, payload: p }
}
pub fn with_u16_u16_u8(op: Opcode, a: u16, b: u16, c: u8) -> Self {
let mut p = [0u8; 7];
p[0..2].copy_from_slice(&a.to_le_bytes());
p[2..4].copy_from_slice(&b.to_le_bytes());
p[4] = c;
Self { op, payload: p }
}
pub fn with_u16_u16(op: Opcode, a: u16, b: u16) -> Self {
let mut p = [0u8; 7];
p[0..2].copy_from_slice(&a.to_le_bytes());
p[2..4].copy_from_slice(&b.to_le_bytes());
Self { op, payload: p }
}
pub fn with_u16_i32(op: Opcode, u: u16, i: i32) -> Self {
let mut p = [0u8; 7];
p[0..2].copy_from_slice(&u.to_le_bytes());
p[2..6].copy_from_slice(&i.to_le_bytes());
Self { op, payload: p }
}
pub fn u16_arg(&self) -> u16 {
u16::from_le_bytes(self.payload[0..2].try_into().unwrap())
}
pub fn i32_arg(&self) -> i32 {
i32::from_le_bytes(self.payload[0..4].try_into().unwrap())
}
pub fn u8_at(&self, i: usize) -> u8 {
self.payload[i]
}
pub fn u16_at(&self, i: usize) -> u16 {
u16::from_le_bytes(self.payload[i..i + 2].try_into().unwrap())
}
pub fn i32_at(&self, i: usize) -> i32 {
i32::from_le_bytes(self.payload[i..i + 4].try_into().unwrap())
}
pub fn set_i32(&mut self, v: i32) {
self.payload[0..4].copy_from_slice(&v.to_le_bytes());
}
pub fn set_u16_i32(&mut self, u: u16, i: i32) {
self.payload[0..2].copy_from_slice(&u.to_le_bytes());
self.payload[2..6].copy_from_slice(&i.to_le_bytes());
}
}
pub struct Chunk {
pub code: Vec<Instr>,
pub consts: Vec<Value>,
pub names: Vec<String>,
pub exprs: Vec<Expr>,
pub index_sets: Vec<Vec<Expr>>,
pub lines: Vec<usize>,
pub slot_names: Vec<String>,
}
impl Chunk {
pub fn new() -> Self {
Self {
code: Vec::new(),
consts: Vec::new(),
names: Vec::new(),
exprs: Vec::new(),
index_sets: Vec::new(),
lines: Vec::new(),
slot_names: Vec::new(),
}
}
pub fn add_const(&mut self, v: Value) -> u16 {
let idx = self.consts.len() as u16;
self.consts.push(v);
idx
}
pub fn name_idx(&mut self, name: &str) -> u16 {
if let Some(pos) = self.names.iter().position(|n| n == name) {
return pos as u16;
}
let idx = self.names.len() as u16;
self.names.push(name.to_string());
idx
}
pub fn add_expr(&mut self, e: Expr) -> u16 {
let idx = self.exprs.len() as u16;
self.exprs.push(e);
idx
}
}
impl Default for Chunk {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub enum CompileError {
Unsupported,
}
pub struct IterState {
vals: Vec<Value>,
pos: usize,
}
impl IterState {
pub fn from_value(val: Value) -> Result<Self, String> {
let vals = match val {
Value::Scalar(n) => vec![Value::Scalar(n)],
Value::Matrix(m) => {
let nrows = m.nrows();
let ncols = m.ncols();
(0..ncols)
.map(|j| {
if nrows == 1 {
Value::Scalar(m[[0, j]])
} else {
let mut col = Array2::zeros((nrows, 1));
for i in 0..nrows {
col[[i, 0]] = m[[i, j]];
}
Value::Matrix(Box::new(col))
}
})
.collect()
}
_ => return Err("'for': range must evaluate to a scalar or matrix".to_string()),
};
Ok(IterState { vals, pos: 0 })
}
pub fn next_val(&mut self) -> Option<Value> {
if self.pos < self.vals.len() {
let v = self.vals[self.pos].clone();
self.pos += 1;
Some(v)
} else {
None
}
}
}