Files
Glint-Runtime/src/interpreter/reader.rs

355 lines
12 KiB
Rust

use super::opcodes::*;
use super::types::{InterpError, Value};
use compact_str::CompactString;
pub struct Reader<'a> {
pub data: &'a [u8],
pub pos: usize,
}
impl<'a> Reader<'a> {
#[inline(always)]
pub fn new(data: &'a [u8]) -> Self {
Self { data, pos: 0 }
}
#[inline(always)]
pub fn remaining(&self) -> usize {
self.data.len() - self.pos
}
#[inline(always)]
fn require(&self, n: usize) -> Result<(), InterpError> {
if self.pos + n > self.data.len() {
Err(InterpError::UnexpectedEof)
} else {
Ok(())
}
}
#[inline(always)]
pub fn read_byte(&mut self) -> Result<u8, InterpError> {
self.require(1)?;
let b = unsafe { *self.data.get_unchecked(self.pos) };
self.pos += 1;
Ok(b)
}
#[inline(always)]
pub fn read_u32(&mut self) -> Result<u32, InterpError> {
self.require(4)?;
let v = unsafe {
let ptr = self.data.as_ptr().add(self.pos) as *const [u8; 4];
u32::from_le_bytes(std::ptr::read_unaligned(ptr))
};
self.pos += 4;
Ok(v)
}
#[inline(always)]
pub fn read_i64(&mut self) -> Result<i64, InterpError> {
self.require(8)?;
let v = unsafe {
let ptr = self.data.as_ptr().add(self.pos) as *const [u8; 8];
i64::from_le_bytes(std::ptr::read_unaligned(ptr))
};
self.pos += 8;
Ok(v)
}
#[inline(always)]
pub fn read_f64(&mut self) -> Result<f64, InterpError> {
self.require(8)?;
let v = unsafe {
let ptr = self.data.as_ptr().add(self.pos) as *const [u8; 8];
f64::from_le_bytes(std::ptr::read_unaligned(ptr))
};
self.pos += 8;
Ok(v)
}
#[inline(always)]
pub fn read_str_ref(&mut self) -> Result<&'a str, InterpError> {
let len = self.read_u32()? as usize;
self.require(len)?;
let slice = &self.data[self.pos .. self.pos + len];
self.pos += len;
unsafe {
Ok(std::str::from_utf8_unchecked(slice))
}
}
#[inline(always)]
pub fn read_string(&mut self) -> Result<String, InterpError> {
self.read_str_ref().map(|s| s.to_owned())
}
#[inline(always)]
pub fn skip_string(&mut self) -> Result<(), InterpError> {
let len = self.read_u32()? as usize;
self.require(len)?;
self.pos += len;
Ok(())
}
pub fn read_value_as_string(&mut self, type_op: u8) -> Result<Option<String>, InterpError> {
let s = match type_op {
OP_PROP_STR | OP_PROP_COLOR | OP_PROP_FSPATH | OP_PROP_RHEI | OP_PROP_IDENT => {
Some(self.read_string()?)
}
OP_PROP_VAR => {
let name = self.read_str_ref()?;
let mut s = String::with_capacity(name.len() + 1);
s.push('$');
s.push_str(name);
Some(s)
}
OP_PROP_INT => Some(self.read_i64()?.to_string()),
OP_PROP_FLOAT => Some(self.read_f64()?.to_string()),
OP_PROP_BOOL => Some((self.read_byte()? != 0).to_string()),
OP_PROP_NULL => None,
OP_PROP_ARRAY => {
let items = self.read_array_as_strings()?;
Some(items.join(","))
}
OP_PROP_UNIT => {
let num = self.read_f64()?;
let unit = self.read_str_ref()?;
if num.fract() == 0.0 {
Some(format!("{}{}", num as i64, unit))
} else {
Some(format!("{}{}", num, unit))
}
}
OP_PROP_CALL => {
let name = self.read_string()?;
let arg_count = self.read_u32()? as usize;
let mut args = Vec::with_capacity(arg_count);
for _ in 0..arg_count {
let op = self.read_byte()?;
let val = self.read_value_as_string(op)?.unwrap_or_default();
args.push(val);
}
Some(format!("{}({})", name, args.join(",")))
}
_ => None,
};
Ok(s)
}
pub fn read_value(&mut self, type_op: u8) -> Result<Option<Value>, InterpError> {
let val = match type_op {
OP_PROP_STR | OP_PROP_COLOR | OP_PROP_FSPATH | OP_PROP_IDENT => {
Some(Value::Str(CompactString::new(self.read_string()?)))
}
OP_PROP_RHEI => {
let raw = self.read_string()?;
let mut s = String::with_capacity(super::rhei::RHEI_PREFIX.len() + raw.len());
s.push_str(super::rhei::RHEI_PREFIX);
s.push_str(&raw);
Some(Value::Str(CompactString::new(s)))
}
OP_PROP_VAR => {
let name = self.read_str_ref()?;
let mut s = String::with_capacity(name.len() + 1);
s.push('$');
s.push_str(name);
Some(Value::Str(CompactString::new(s)))
}
OP_PROP_INT => Some(Value::Int(self.read_i64()?)),
OP_PROP_FLOAT => Some(Value::Float(self.read_f64()?)),
OP_PROP_BOOL => Some(Value::Bool(self.read_byte()? != 0)),
OP_PROP_NULL => None,
OP_PROP_ARRAY => {
let items = self.read_array_as_values()?;
Some(Value::Array(items))
}
OP_PROP_UNIT => {
let num = self.read_f64()?;
let unit = self.read_str_ref()?;
let s = if num.fract() == 0.0 {
format!("{}{}", num as i64, unit)
} else {
format!("{}{}", num, unit)
};
Some(Value::Str(CompactString::new(s)))
}
OP_PROP_CALL => {
let name = self.read_string()?;
let arg_count = self.read_u32()? as usize;
let mut args = Vec::with_capacity(arg_count);
for _ in 0..arg_count {
let op = self.read_byte()?;
let val = self.read_value(op)?.unwrap_or(Value::None);
args.push(match val {
Value::Str(s) => s.to_string(),
Value::Int(i) => i.to_string(),
Value::Float(f) => f.to_string(),
Value::Bool(b) => b.to_string(),
_ => String::new(),
});
}
Some(Value::Str(CompactString::new(format!("{}({})", name, args.join(",")))))
}
_ => None,
};
Ok(val)
}
pub fn read_array_as_values(&mut self) -> Result<Vec<Value>, InterpError> {
let count = self.read_u32()? as usize;
let mut items = Vec::with_capacity(count);
for _ in 0..count {
let elem_op = self.read_byte()?;
if let Some(v) = self.read_value(elem_op)? {
items.push(v);
}
}
Ok(items)
}
pub fn read_array_as_strings(&mut self) -> Result<Vec<String>, InterpError> {
let count = self.read_u32()? as usize;
let mut items = Vec::with_capacity(count);
for _ in 0..count {
let elem_op = self.read_byte()?;
if let Some(s) = self.read_value_as_string(elem_op)? {
items.push(s);
}
}
Ok(items)
}
pub fn skip_value(&mut self, type_op: u8) -> Result<(), InterpError> {
match type_op {
OP_PROP_STR | OP_PROP_COLOR | OP_PROP_FSPATH | OP_PROP_VAR | OP_PROP_RHEI | OP_PROP_IDENT => {
self.skip_string()?;
}
OP_PROP_INT => { self.read_i64()?; }
OP_PROP_FLOAT => { self.read_f64()?; }
OP_PROP_BOOL => { self.read_byte()?; }
OP_PROP_NULL => {}
OP_PROP_ARRAY => {
let count = self.read_u32()?;
for _ in 0..count {
let elem_op = self.read_byte()?;
self.skip_value(elem_op)?;
}
}
OP_PROP_UNIT => {
self.read_f64()?;
self.skip_string()?;
}
OP_PROP_CALL => {
self.skip_string()?;
let arg_count = self.read_u32()?;
for _ in 0..arg_count {
let op = self.read_byte()?;
self.skip_value(op)?;
}
}
_ => {}
}
Ok(())
}
pub fn skip_opcode(&mut self, op: u8) -> Result<(), InterpError> {
match op {
OP_VERSION => { self.read_i64()?; }
OP_STYLE | OP_RHEI_BLK => { self.skip_string()?; }
OP_PROP_STR | OP_PROP_COLOR | OP_PROP_FSPATH | OP_PROP_VAR | OP_PROP_RHEI |
OP_PROP_INT | OP_PROP_FLOAT | OP_PROP_BOOL | OP_PROP_NULL | OP_PROP_ARRAY |
OP_PROP_CALL | OP_PROP_UNIT | OP_PROP_IDENT => {
self.skip_string()?;
self.skip_value(op)?;
}
OP_GLOBAL | OP_LET => {
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?;
}
OP_SINGLETON => {
self.skip_string()?;
let count = self.read_u32()?;
for _ in 0..count {
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?;
}
}
OP_COMPONENT => {
self.skip_string()?;
let params = self.read_u32()?;
for _ in 0..params {
self.skip_string()?;
self.skip_string()?;
}
self.skip_block()?;
}
OP_IF => {
let vop = self.read_byte()?;
self.skip_value(vop)?;
self.skip_block()?;
if self.read_byte()? == 1 { self.skip_block()?; }
}
OP_EACH => {
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?;
self.skip_block()?;
}
OP_ON => {
self.skip_string()?;
let args = self.read_u32()?;
for _ in 0..args {
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?;
}
self.skip_block()?;
}
OP_ELEM_PUSH => { self.skip_string()?; }
OP_CONTENT => {
let vop = self.read_byte()?;
self.skip_value(vop)?;
}
OP_STYLE_RULE => {
self.skip_string()?;
let count = self.read_u32()?;
for _ in 0..count {
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?;
}
}
OP_STYLE_ANIM => {
self.skip_string()?;
let frame_count = self.read_u32()?;
for _ in 0..frame_count {
self.skip_string()?;
let prop_count = self.read_u32()?;
for _ in 0..prop_count {
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?;
}
}
}
_ => {}
}
Ok(())
}
pub fn skip_block(&mut self) -> Result<(), InterpError> {
loop {
let op = self.read_byte()?;
if op == OP_END_BLOCK { return Ok(()); }
self.skip_opcode(op)?;
}
}
}