#![allow(dead_code)]
#[derive(Clone)]
pub struct UDF {
pub nbr_args: u8,
pub instructions: Vec<IR>,
pub default_args: Vec<u16>,
}
pub struct Cmd {
idx: u16, args: Vec<Index>,
}
#[derive(Clone, Debug)]
pub enum Index {
Loc(u8),
Arg(u8),
Cmd(u16),
Expr(u16),
Udf(u16),
Const(u16),
}
pub const GLOB_VAR_INDIC: u8 = '\\' as u8;
pub const LOCL_VAR_INDIC: u8 = '$' as u8;
#[derive(Clone)]
pub enum IR {
LocalAssignement(u8, Index), GlobalAssignement(u16, Index), UdfCall(u16, Vec<Index>),
CmdCall(u16, Vec<Index>),
BuiltinCall(u16, Vec<Index>),
}
#[derive(Debug, Clone)]
pub struct Expr {
pub data: Vec<u8>,
}
impl Expr {
pub fn new(data: Vec<u8>) -> Self {
Self { data }
}
pub fn from_str(
value: &str,
locals: &NameToLocalVar,
globals: &NameToIndex,
) -> Result<Expr, String> {
let mut idx = 0;
let val = value.as_bytes();
let len = val.len();
let mut res: Vec<u8> = Vec::with_capacity(len);
while idx < len {
while idx < len && val[idx] != '$' as u8 {
res.push(val[idx]);
idx += 1;
}
idx += 1;
if idx >= len {
break;
}
if val[idx] == '{' as u8 {
idx += 1;
let start = idx;
while val[idx] != '}' as u8 {
idx += 1;
}
let var_name = &val[start..idx];
let var_name = std::str::from_utf8(var_name).unwrap();
idx += 1;
if let Some(idx) = globals.get(var_name) {
res.push(GLOB_VAR_INDIC);
let bytes = idx.to_be_bytes();
res.push(bytes[0]);
res.push(bytes[1]);
} else if let Some(idx) = locals.get(var_name) {
res.push(LOCL_VAR_INDIC);
res.push(*idx);
} else {
return Err(format!("undefined variable {}", var_name));
}
}
}
Ok(Expr::new(res))
}
}
pub type NameToLocalVar = std::collections::HashMap<String, u8>;
pub type NameToIndex = std::collections::HashMap<String, u16>;
pub type IndexResult = Result<Index, String>;
pub type IRResult = Result<IR, String>;
impl UDF {
pub fn defaults() -> Self {
let nbr_args = 0;
let instructions: Vec<IR> = Vec::new();
let default_args: Vec<u16> = Vec::new();
Self {
nbr_args,
instructions,
default_args,
}
}
pub fn min_args(&self) -> u8 {
self.nbr_args - self.default_args.len() as u8
}
}