use crate::compiler::{
Instruction::{self, IConst},
InstructionI,
};
use crate::error::Error;
use crate::parser::{Expression, ExpressionI, Value, ValueI};
use std::fmt;
use std::mem;
#[cfg(feature = "unsafe-vars")]
use std::collections::BTreeMap;
macro_rules! get_expr {
($pslab:expr, $i_ref:ident) => {
match $pslab.exprs.get($i_ref.0) {
Some(expr_ref) => expr_ref,
None => &$pslab.def_expr,
}
};
}
macro_rules! get_val {
($pslab:expr, $i_ref:ident) => {
match $pslab.vals.get($i_ref.0) {
Some(val_ref) => val_ref,
None => &$pslab.def_val,
}
};
}
macro_rules! get_instr {
($cslab:expr, $i_ref:ident) => {
match $cslab.instrs.get($i_ref.0) {
Some(instr_ref) => instr_ref,
None => &$cslab.def_instr,
}
};
}
impl ExpressionI {
#[inline]
pub fn from(self, ps: &ParseSlab) -> &Expression {
get_expr!(ps, self)
}
}
impl ValueI {
#[inline]
pub fn from(self, ps: &ParseSlab) -> &Value {
get_val!(ps, self)
}
}
pub struct Slab {
pub ps: ParseSlab,
pub cs: CompileSlab,
}
pub struct ParseSlab {
pub(crate) exprs: Vec<Expression>,
pub(crate) vals: Vec<Value>,
pub(crate) def_expr: Expression,
pub(crate) def_val: Value,
pub(crate) char_buf: String,
#[cfg(feature = "unsafe-vars")]
pub(crate) unsafe_vars: BTreeMap<String, *const f64>,
}
pub struct CompileSlab {
pub(crate) instrs: Vec<Instruction>,
pub(crate) def_instr: Instruction,
}
impl ParseSlab {
#[inline]
pub fn get_expr(&self, expr_i: ExpressionI) -> &Expression {
self.exprs.get(expr_i.0).map_or(&self.def_expr, |expr_ref| expr_ref)
}
#[inline]
pub fn get_val(&self, val_i: ValueI) -> &Value {
self.vals.get(val_i.0).map_or(&self.def_val, |val_ref| val_ref)
}
#[inline]
pub(crate) fn push_expr(&mut self, expr: Expression) -> Result<ExpressionI, Error> {
let i = self.exprs.len();
if i >= self.exprs.capacity() {
return Err(Error::SlabOverflow);
}
self.exprs.push(expr);
Ok(ExpressionI(i))
}
#[inline]
pub(crate) fn push_val(&mut self, val: Value) -> Result<ValueI, Error> {
let i = self.vals.len();
if i >= self.vals.capacity() {
return Err(Error::SlabOverflow);
}
self.vals.push(val);
Ok(ValueI(i))
}
#[inline]
pub fn clear(&mut self) {
self.exprs.clear();
self.vals.clear();
}
#[cfg(feature = "unsafe-vars")]
#[allow(clippy::trivially_copy_pass_by_ref)]
pub unsafe fn add_unsafe_var(&mut self, name: String, ptr: &f64) {
self.unsafe_vars.insert(name, ptr as *const f64);
}
}
impl CompileSlab {
#[inline]
pub fn get_instr(&self, instr_i: InstructionI) -> &Instruction {
self.instrs.get(instr_i.0).map_or(&self.def_instr, |instr_ref| instr_ref)
}
pub(crate) fn push_instr(&mut self, instr: Instruction) -> InstructionI {
if self.instrs.capacity() == 0 {
self.instrs.reserve(32);
}
let i = self.instrs.len();
self.instrs.push(instr);
InstructionI(i)
}
pub(crate) fn take_instr(&mut self, i: InstructionI) -> Instruction {
if i.0 == self.instrs.len() - 1 {
self.instrs.pop().map_or(IConst(std::f64::NAN), |instr| instr)
} else {
self.instrs.get_mut(i.0).map_or(IConst(std::f64::NAN), |instr_ref| mem::replace(instr_ref, IConst(std::f64::NAN)))
}
}
#[inline]
pub fn clear(&mut self) {
self.instrs.clear();
}
}
impl Slab {
#[inline]
pub fn new() -> Self {
Self::with_capacity(64)
}
#[inline]
pub fn with_capacity(cap: usize) -> Self {
Self {
ps: ParseSlab {
exprs: Vec::with_capacity(cap),
vals: Vec::with_capacity(cap),
def_expr: Expression::default(),
def_val: Value::default(),
char_buf: String::with_capacity(64),
#[cfg(feature = "unsafe-vars")]
unsafe_vars: BTreeMap::new(),
},
cs: CompileSlab {
instrs: Vec::new(), def_instr: Instruction::default(),
},
}
}
#[inline]
pub fn clear(&mut self) {
self.ps.exprs.clear();
self.ps.vals.clear();
self.cs.instrs.clear();
}
}
fn write_indexed_list<T>(f: &mut fmt::Formatter, lst: &[T]) -> Result<(), fmt::Error>
where
T: fmt::Debug,
{
write!(f, "{{")?;
let mut nonempty = false;
for (i, x) in lst.iter().enumerate() {
if nonempty {
write!(f, ",")?;
}
nonempty = true;
write!(f, " {i}:{x:?}")?;
}
if nonempty {
write!(f, " ")?;
}
write!(f, "}}")?;
Ok(())
}
impl fmt::Debug for Slab {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Slab{{ exprs:")?;
write_indexed_list(f, &self.ps.exprs)?;
write!(f, ", vals:")?;
write_indexed_list(f, &self.ps.vals)?;
write!(f, ", instrs:")?;
write_indexed_list(f, &self.cs.instrs)?;
write!(f, " }}")?;
Ok(())
}
}
impl fmt::Debug for ParseSlab {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "ParseSlab{{ exprs:")?;
write_indexed_list(f, &self.exprs)?;
write!(f, ", vals:")?;
write_indexed_list(f, &self.vals)?;
write!(f, " }}")?;
Ok(())
}
}
impl fmt::Debug for CompileSlab {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "CompileSlab{{ instrs:")?;
write_indexed_list(f, &self.instrs)?;
write!(f, " }}")?;
Ok(())
}
}
impl Default for Slab {
fn default() -> Self {
Self::with_capacity(64)
}
}