use std::sync::atomic::AtomicU64;
use std::sync::Arc;
use tishlang_core::Value;
#[derive(Debug, Default)]
pub struct InlineCaches(pub Vec<AtomicU64>);
impl Clone for InlineCaches {
fn clone(&self) -> Self {
InlineCaches(self.0.iter().map(|_| AtomicU64::new(0)).collect())
}
}
#[derive(Debug, Clone)]
pub enum Constant {
Number(f64),
String(Arc<str>),
Bool(bool),
Null,
Closure(usize),
}
impl Constant {
pub fn to_value(&self) -> Value {
match self {
Constant::Number(n) => Value::Number(*n),
Constant::String(s) => Value::String(tishlang_core::ArcStr::from(s.as_ref())),
Constant::Bool(b) => Value::Bool(*b),
Constant::Null => Value::Null,
Constant::Closure(_) => {
unreachable!("Closure constant should be handled by VM")
}
}
}
}
#[derive(Debug, Clone)]
pub struct Chunk {
pub code: Vec<u8>,
pub constants: Vec<Constant>,
pub names: Vec<Arc<str>>,
pub nested: Vec<Chunk>,
pub rest_param_index: u16,
pub param_count: u16,
pub num_slots: u16,
pub slot_based: bool,
pub inline_caches: InlineCaches,
pub lines: Vec<(u32, u32)>,
pub source: Option<Arc<str>>,
}
impl Chunk {
pub fn new() -> Self {
Self {
code: Vec::new(),
constants: Vec::new(),
names: Vec::new(),
nested: Vec::new(),
rest_param_index: super::NO_REST_PARAM,
param_count: 0,
num_slots: 0,
slot_based: false,
inline_caches: InlineCaches::default(),
lines: Vec::new(),
source: None,
}
}
pub fn mark_line(&mut self, offset: usize, line: u32) {
if line == 0 {
return;
}
match self.lines.last() {
Some(&(_, last_line)) if last_line == line => {}
_ => self.lines.push((offset as u32, line)),
}
}
pub fn line_at(&self, offset: usize) -> Option<u32> {
if self.lines.is_empty() {
return None;
}
let off = offset as u32;
let idx = self.lines.partition_point(|&(o, _)| o <= off);
if idx == 0 {
Some(self.lines[0].1)
} else {
Some(self.lines[idx - 1].1)
}
}
pub fn write_u8(&mut self, b: u8) {
self.code.push(b);
}
pub fn write_u16(&mut self, n: u16) {
self.code.extend_from_slice(&n.to_be_bytes());
}
pub fn add_constant(&mut self, c: Constant) -> u16 {
let idx = self.constants.len();
self.constants.push(c);
idx as u16
}
pub fn add_name(&mut self, name: Arc<str>) -> u16 {
if let Some(idx) = self.names.iter().position(|n| n.as_ref() == name.as_ref()) {
return idx as u16;
}
let idx = self.names.len();
self.names.push(name);
self.inline_caches.0.push(AtomicU64::new(0)); idx as u16
}
pub fn add_nested(&mut self, chunk: Chunk) -> usize {
let idx = self.nested.len();
self.nested.push(chunk);
idx
}
}
impl Default for Chunk {
fn default() -> Self {
Self::new()
}
}