#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use bitflags::bitflags;
bitflags! {
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StepFlags: u8 {
const SKIP_IF_UNIT = 0b_0000_0001;
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Step {
Index {
operand: u16,
flags: StepFlags,
pos: rhai::Position,
bracket: rhai::Position,
},
Property {
name: u32,
getter: u32,
setter: u32,
flags: StepFlags,
pos: rhai::Position,
},
Method {
name: u32,
argc: u8,
operand: u16,
flags: StepFlags,
pos: rhai::Position,
},
}
impl Step {
#[must_use]
pub fn pos(&self) -> rhai::Position {
match self {
Step::Index { pos, .. } | Step::Property { pos, .. } | Step::Method { pos, .. } => *pos,
}
}
#[must_use]
pub fn position_slots(&self) -> u32 {
match self {
Step::Index { .. } => 2,
Step::Property { .. } | Step::Method { .. } => 1,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Tail {
Read,
Assign {
op: Option<u32>,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Root {
Local {
slot: u16,
name: u32,
},
Named {
name: u32,
pos: rhai::Position,
},
This {
pos: rhai::Position,
},
Temporary,
}
impl Root {
#[must_use]
pub fn position_slots(&self) -> u32 {
match self {
Root::Named { .. } | Root::This { .. } => 1,
Root::Local { .. } | Root::Temporary => 0,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Chain {
pub root: Root,
pub steps: Vec<Step>,
pub tail: Tail,
pub operands: u16,
}
impl Chain {
#[must_use]
pub fn assigns(&self) -> bool {
matches!(self.tail, Tail::Assign { .. })
}
#[must_use]
pub fn roots_on_stack(&self) -> bool {
match self.root {
Root::Local { .. } | Root::Named { .. } | Root::This { .. } => false,
Root::Temporary => true,
}
}
#[must_use]
pub fn consumes(&self) -> usize {
self.operands as usize + usize::from(self.roots_on_stack()) + usize::from(self.assigns())
}
#[must_use]
pub fn position_slots(&self) -> u32 {
self.root.position_slots() + self.steps.iter().map(Step::position_slots).sum::<u32>()
}
#[must_use]
pub fn step_slot(&self, index: usize) -> Option<u32> {
(index < self.steps.len()).then(|| {
self.root.position_slots()
+ self.steps[..index]
.iter()
.map(Step::position_slots)
.sum::<u32>()
})
}
pub fn positions(&self) -> impl Iterator<Item = rhai::Position> + '_ {
let root = match self.root {
Root::Named { pos, .. } | Root::This { pos } => Some(pos),
Root::Local { .. } | Root::Temporary => None,
};
root.into_iter().chain(
self.steps
.iter()
.flat_map(|step| match step {
Step::Index { pos, bracket, .. } => [Some(*pos), Some(*bracket)],
Step::Property { pos, .. } | Step::Method { pos, .. } => [Some(*pos), None],
})
.flatten(),
)
}
pub fn positions_mut(&mut self) -> impl Iterator<Item = &mut rhai::Position> {
let Self { root, steps, .. } = self;
let root = match root {
Root::Named { pos, .. } | Root::This { pos } => Some(pos),
Root::Local { .. } | Root::Temporary => None,
};
root.into_iter().chain(
steps
.iter_mut()
.flat_map(|step| match step {
Step::Index { pos, bracket, .. } => [Some(pos), Some(bracket)],
Step::Property { pos, .. } | Step::Method { pos, .. } => [Some(pos), None],
})
.flatten(),
)
}
#[must_use]
pub fn mutates(&self) -> bool {
matches!(self.tail, Tail::Assign { .. })
|| self
.steps
.iter()
.any(|step| matches!(step, Step::Method { .. }))
}
}