pub use stack::*;
use crate::*;
use crate::lang::*;
use crate::runtime::resolver::{SelectorError, Resolver, BlockAction};
use std::{cell::RefCell, error::Error, fmt::{Debug, Display}, ops::Deref, rc::Rc};
use smallvec::{SmallVec, smallvec};
use self::resolver::Weights;
pub(crate) mod format;
pub(crate) mod resolver;
mod output;
mod stack;
pub type RuntimeResult<T> = Result<T, RuntimeError>;
pub const MAX_STACK_SIZE: usize = 20000;
pub(crate) const CALL_STACK_INLINE_COUNT: usize = 4;
pub(crate) const VALUE_STACK_INLINE_COUNT: usize = 4;
pub struct VM<'rant> {
rng_stack: SmallVec<[Rc<RantRng>; 1]>,
engine: &'rant mut Rant,
program: &'rant RantProgram,
val_stack: SmallVec<[RantValue; VALUE_STACK_INLINE_COUNT]>,
call_stack: CallStack,
resolver: Resolver,
unwinds: SmallVec<[UnwindState; 1]>,
}
impl<'rant> VM<'rant> {
#[inline]
pub(crate) fn new(rng: Rc<RantRng>, engine: &'rant mut Rant, program: &'rant RantProgram) -> Self {
Self {
resolver: Resolver::new(&rng),
rng_stack: smallvec![rng],
engine,
program,
val_stack: Default::default(),
call_stack: Default::default(),
unwinds: Default::default(),
}
}
}
macro_rules! runtime_trace {
($fmt:literal) => {#[cfg(all(feature = "vm-trace", debug_assertions))]{
eprintln!("[vm-trace] {}", $fmt)
}};
($fmt:literal, $($args:expr),+) => {#[cfg(all(feature = "vm-trace", debug_assertions))]{
eprintln!("[vm-trace] {}", format!($fmt, $($args),+))
}};
}
macro_rules! runtime_error {
($err_type:expr) => {{
let e = $err_type;
return Err(RuntimeError {
description: e.to_string(),
error_type: e,
stack_trace: None,
})
}};
($err_type:expr, $desc:expr) => {
return Err(RuntimeError {
error_type: $err_type,
description: $desc.to_string(),
stack_trace: None,
})
};
}
pub enum Intent {
PrintLast,
ReturnLast,
ContinueLast,
BreakLast,
ImportLastAsModule { module_name: String, descope: usize },
CheckBlock,
SetVar { vname: Identifier, access_kind: AccessPathKind, },
DefVar { vname: Identifier, access_kind: AccessPathKind, is_const: bool },
BuildDynamicGetter {
path: Rc<AccessPath>, dynamic_key_count: usize, pending_exprs: Vec<Rc<Sequence>>,
override_print: bool, prefer_function: bool, fallback: Option<Rc<Sequence>>
},
GetValue { path: Rc<AccessPath>, dynamic_key_count: usize, override_print: bool, prefer_function: bool, fallback: Option<Rc<Sequence>> },
BuildDynamicSetter { path: Rc<AccessPath>, write_mode: VarWriteMode, expr_count: usize, pending_exprs: Vec<Rc<Sequence>>, val_source: SetterValueSource },
SetValue { path: Rc<AccessPath>, write_mode: VarWriteMode, expr_count: usize },
Invoke { arg_exprs: Rc<Vec<ArgumentExpr>>, eval_count: usize, flag: PrintFlag, is_temporal: bool, },
InvokeComposedStep {
steps: Rc<Vec<FunctionCall>>,
step_index: usize,
state: InvokeComposedStepState,
compval: Option<RantValue>,
flag: PrintFlag,
},
Call { argc: usize, flag: PrintFlag, override_print: bool },
CallTemporal { func: RantFunctionRef, args: Rc<Vec<RantValue>>, temporal_state: TemporalSpreadState, flag: PrintFlag, },
BuildList { init: Rc<Vec<Rc<Sequence>>>, index: usize, list: RantList },
BuildMap { init: Rc<Vec<(MapKeyExpr, Rc<Sequence>)>>, pair_index: usize, map: RantMap },
BuildWeightedBlock { block: Rc<Block>, weights: Weights, pop_next_weight: bool, },
RuntimeCall { function: Box<dyn FnOnce(&mut VM) -> RuntimeResult<()>>, interrupt: bool },
DropStaleUnwinds,
}
impl Intent {
fn name(&self) -> &'static str {
match self {
Intent::PrintLast => "print",
Intent::CheckBlock => "check_block",
Intent::SetVar { .. } => "set_var",
Intent::DefVar { .. } => "def_var",
Intent::BuildDynamicGetter { .. } => "build_dyn_getter",
Intent::GetValue { .. } => "get_value",
Intent::BuildDynamicSetter { .. } => "build_dyn_setter",
Intent::SetValue { .. } => "set_value",
Intent::Invoke { .. } => "invoke",
Intent::InvokeComposedStep { .. } => "invoke_composed_step",
Intent::Call { .. } => "call",
Intent::CallTemporal { .. } => "call_temporal",
Intent::BuildList { .. } => "build_list",
Intent::BuildMap { .. } => "build_map",
Intent::ImportLastAsModule { .. } => "load_module",
Intent::RuntimeCall { .. } => "runtime_call",
Intent::DropStaleUnwinds => "drop_stale_unwinds",
Intent::ReturnLast => "return_last",
Intent::ContinueLast => "continue_last",
Intent::BreakLast => "break_last",
Intent::BuildWeightedBlock { .. } => "build_weighted_block",
}
}
}
#[derive(Debug)]
pub enum InvokeComposedStepState {
EvaluatingFunc,
EvaluatingArgs {
num_evaluated: usize
},
PreTemporalCall {
step_function: RantFunctionRef,
temporal_state: TemporalSpreadState,
args: Vec<RantValue>,
},
PreCall {
step_function: RantFunctionRef,
args: Vec<RantValue>,
},
PostCall,
PostTemporalCall {
step_function: RantFunctionRef,
temporal_state: TemporalSpreadState,
args: Vec<RantValue>,
}
}
#[derive(Debug, Copy, Clone)]
pub enum VarWriteMode {
SetOnly,
Define,
DefineConst,
}
#[derive(Debug)]
enum SetterKey<'a> {
Index(i64),
Slice(Slice),
KeyRef(&'a str),
KeyString(InternalString),
}
#[derive(Debug)]
pub enum SetterValueSource {
FromExpression(Rc<Sequence>),
FromValue(RantValue),
Consumed
}
pub struct UnwindState {
pub handler: Option<RantFunctionRef>,
pub value_stack_size: usize,
pub block_stack_size: usize,
pub attr_stack_size: usize,
pub call_stack_size: usize,
}
impl<'rant> VM<'rant> {
pub(crate) fn run(&mut self) -> RuntimeResult<RantValue> {
let mut result = self.run_inner();
if let Err(err) = result.as_mut() {
err.stack_trace = Some(self.call_stack.gen_stack_trace());
}
result
}
pub(crate) fn run_with<A>(&mut self, args: A) -> RuntimeResult<RantValue>
where A: Into<Option<HashMap<String, RantValue>>>
{
if let Some(args) = args.into() {
for (k, v) in args {
self.def_var_value(&k, AccessPathKind::Local, v, true)?;
}
}
let mut result = self.run_inner();
if let Err(err) = result.as_mut() {
err.stack_trace = Some(self.call_stack.gen_stack_trace());
}
result
}
#[inline]
fn run_inner(&mut self) -> RuntimeResult<RantValue> {
self.push_frame_unchecked(self.program.root.clone(), true, StackFrameFlavor::FunctionBody);
while !self.is_stack_empty() {
match self.tick() {
Ok(true) => {
runtime_trace!("tick interrupted (stack @ {})", self.call_stack.len());
continue
},
Ok(false) => {
runtime_trace!("tick done (stack @ {})", self.call_stack.len());
},
Err(err) => {
if let Some(unwind) = self.unwind() {
if let Some(handler) = unwind.handler {
self.call_func(handler, vec![RantValue::String(err.to_string().into())], PrintFlag::None, false)?;
continue;
}
} else {
return Err(err)
}
}
}
}
debug_assert_eq!(self.val_stack.len(), 1, "value stack is imbalanced");
Ok(self.pop_val().unwrap_or_default())
}
#[inline(always)]
fn tick(&mut self) -> RuntimeResult<bool> {
runtime_trace!("tick start (stack @ {}: {})", self.call_stack.len(), self.call_stack.top().map_or("none".to_owned(), |top| top.to_string()));
while let Some(intent) = self.cur_frame_mut().take_intent() {
runtime_trace!("intent: {}", intent.name());
match intent {
Intent::PrintLast => {
let val = self.pop_val()?;
self.cur_frame_mut().write_value(val);
},
Intent::ReturnLast => {
let val = self.pop_val()?;
self.func_return(Some(val))?;
return Ok(true)
},
Intent::ContinueLast => {
let val = self.pop_val()?;
self.interrupt_repeater(Some(val), true)?;
return Ok(true)
},
Intent::BreakLast => {
let val = self.pop_val()?;
self.interrupt_repeater(Some(val), false)?;
return Ok(true)
},
Intent::CheckBlock => {
self.check_block()?;
},
Intent::BuildWeightedBlock { block, mut weights, mut pop_next_weight } => {
while weights.len() < block.elements.len() {
if pop_next_weight {
let weight_value = self.pop_val()?;
weights.push(match weight_value {
RantValue::Int(n) => n as f64,
RantValue::Float(n) => n,
other => runtime_error!(RuntimeErrorType::ArgumentError, format!("weight values cannot be of type '{}'", other.type_name())),
});
pop_next_weight = false;
continue
}
match &block.elements[weights.len()].weight {
Some(weight) => match weight {
BlockWeight::Dynamic(weight_expr) => {
let weight_expr = Rc::clone(weight_expr);
self.cur_frame_mut().push_intent_front(Intent::BuildWeightedBlock {
block,
weights,
pop_next_weight: true,
});
self.push_frame(weight_expr, true)?;
return Ok(true)
},
BlockWeight::Constant(weight_value) => {
weights.push(*weight_value);
},
},
None => {
weights.push(1.0);
},
}
}
self.push_block(block.as_ref(), Some(weights), block.flag)?;
},
Intent::SetVar { vname, access_kind } => {
let val = self.pop_val()?;
self.set_var_value(vname.as_str(), access_kind, val)?;
},
Intent::DefVar { vname, access_kind, is_const } => {
let val = self.pop_val()?;
self.def_var_value(vname.as_str(), access_kind, val, is_const)?;
},
Intent::BuildDynamicGetter {
path, dynamic_key_count, mut pending_exprs,
override_print, prefer_function, fallback } => {
if let Some(key_expr) = pending_exprs.pop() {
if pending_exprs.is_empty() {
self.cur_frame_mut().push_intent_front(Intent::GetValue { path, dynamic_key_count, override_print, prefer_function, fallback });
} else {
self.cur_frame_mut().push_intent_front(Intent::BuildDynamicGetter { path, dynamic_key_count, pending_exprs, override_print, prefer_function, fallback });
}
self.push_frame_flavored(Rc::clone(&key_expr), true, StackFrameFlavor::DynamicKeyExpression)?;
} else {
self.cur_frame_mut().push_intent_front(Intent::GetValue { path, dynamic_key_count, override_print, prefer_function, fallback });
}
return Ok(true)
},
Intent::GetValue { path, dynamic_key_count, override_print, prefer_function, fallback } => {
let getter_result = self.get_value(path, dynamic_key_count, override_print, prefer_function);
match (getter_result, fallback) {
(Ok(()), _) => {},
(Err(err), None) => return Err(err),
(Err(_), Some(fallback)) => {
if !override_print {
self.cur_frame_mut().push_intent_front(Intent::PrintLast);
}
self.push_frame(fallback, true)?;
return Ok(true)
}
}
},
Intent::Invoke { arg_exprs, eval_count, flag, is_temporal } => {
if eval_count < arg_exprs.len() {
let arg_expr = arg_exprs.get(arg_exprs.len() - eval_count - 1).unwrap();
let arg_seq = Rc::clone(&arg_expr.expr);
self.cur_frame_mut().push_intent_front(Intent::Invoke { arg_exprs, eval_count: eval_count + 1, flag, is_temporal, });
self.push_frame_flavored(arg_seq, true, StackFrameFlavor::ArgumentExpression)?;
return Ok(true)
} else {
let mut args = vec![];
for arg_expr in arg_exprs.iter() {
let arg = self.pop_val()?;
if matches!(arg_expr.spread_mode, ArgumentSpreadMode::Parametric) {
if let RantValue::List(list_ref) = &arg {
for spread_arg in list_ref.borrow().iter() {
args.push(spread_arg.clone());
}
continue
}
}
args.push(arg);
}
let func = match self.pop_val()? {
RantValue::Function(func) => {
func
},
other => runtime_error!(RuntimeErrorType::CannotInvokeValue, format!("cannot call '{}' value", other.type_name()))
};
if is_temporal {
let temporal_state = TemporalSpreadState::new(arg_exprs.as_slice(), args.as_slice());
if !temporal_state.is_empty() {
self.cur_frame_mut().push_intent_front(Intent::CallTemporal {
func,
temporal_state,
args: Rc::new(args),
flag
});
}
} else {
self.call_func(func, args, flag, false)?;
}
return Ok(true)
}
},
Intent::InvokeComposedStep {
steps,
step_index,
state,
compval,
flag
} => {
match state {
InvokeComposedStepState::EvaluatingFunc => {
let step = &steps[step_index];
let compval_copy = compval.clone();
self.cur_frame_mut().push_intent_front(Intent::InvokeComposedStep {
steps: Rc::clone(&steps),
step_index,
state: InvokeComposedStepState::EvaluatingArgs { num_evaluated: 0 },
compval,
flag,
});
match &step.target {
FunctionCallTarget::Path(path) => {
self.push_getter_intents(path, true, true, None);
},
FunctionCallTarget::Expression(expr) => {
self.push_frame(Rc::clone(expr), true)?;
if let Some(compval) = compval_copy {
self.def_compval(compval)?;
}
},
}
return Ok(true)
},
InvokeComposedStepState::EvaluatingArgs { num_evaluated } => {
let step = &steps[step_index];
let arg_exprs = &step.arguments;
let argc = arg_exprs.len();
if num_evaluated < argc {
let arg_expr = arg_exprs.get(argc - num_evaluated - 1).unwrap();
let arg_seq = Rc::clone(&arg_expr.expr);
let compval_copy = compval.clone();
self.cur_frame_mut().push_intent_front(Intent::InvokeComposedStep {
steps: Rc::clone(&steps),
step_index,
state: InvokeComposedStepState::EvaluatingArgs {
num_evaluated: num_evaluated + 1,
},
compval,
flag,
});
self.push_frame_flavored(arg_seq, true, StackFrameFlavor::ArgumentExpression)?;
if let Some(compval) = compval_copy {
self.def_compval(compval)?;
}
} else {
let mut args = vec![];
for arg_expr in arg_exprs.iter() {
let arg = self.pop_val()?;
if matches!(arg_expr.spread_mode, ArgumentSpreadMode::Parametric) {
if let RantValue::List(list_ref) = &arg {
for spread_arg in list_ref.borrow().iter() {
args.push(spread_arg.clone());
}
continue
}
}
args.push(arg);
}
let step_function = match self.pop_val()? {
RantValue::Function(func) => {
func
},
other => runtime_error!(RuntimeErrorType::CannotInvokeValue, format!("cannot call '{}' value", other.type_name()))
};
self.cur_frame_mut().push_intent_front(Intent::InvokeComposedStep {
state: if step.is_temporal {
InvokeComposedStepState::PreTemporalCall {
step_function,
temporal_state: TemporalSpreadState::new(arg_exprs.as_slice(), args.as_slice()),
args,
}
} else {
InvokeComposedStepState::PreCall { step_function, args }
},
steps,
step_index,
compval,
flag,
});
}
return Ok(true)
},
InvokeComposedStepState::PreCall { step_function, args } => {
self.cur_frame_mut().push_intent_front(Intent::InvokeComposedStep {
steps,
step_index,
state: InvokeComposedStepState::PostCall,
compval,
flag,
});
self.call_func(step_function, args, PrintFlag::None, true)?;
return Ok(true)
},
InvokeComposedStepState::PostCall => {
let next_compval = self.pop_val()?;
let next_step_index = step_index + 1;
if next_step_index < steps.len() {
self.cur_frame_mut().push_intent_front(Intent::InvokeComposedStep {
steps,
step_index: next_step_index,
state: InvokeComposedStepState::EvaluatingFunc,
compval: Some(next_compval),
flag,
});
return Ok(true)
} else {
self.cur_frame_mut().write_value(next_compval);
}
},
InvokeComposedStepState::PreTemporalCall { step_function, args, temporal_state } => {
let targs = args.iter().enumerate().map(|(arg_index, arg)| {
if let Some(tindex) = temporal_state.get(arg_index) {
if arg.is_indexable() {
if let Ok(tval) = arg.index_get(tindex as i64) {
return tval
}
}
}
arg.clone()
}).collect::<Vec<RantValue>>();
self.cur_frame_mut().push_intent_front(Intent::InvokeComposedStep {
steps,
step_index,
state: InvokeComposedStepState::PostTemporalCall {
step_function: Rc::clone(&step_function),
temporal_state,
args,
},
compval,
flag,
});
self.call_func(step_function, targs, PrintFlag::None, true)?;
return Ok(true)
},
InvokeComposedStepState::PostTemporalCall { step_function, args, mut temporal_state } => {
let next_compval = self.pop_val()?;
let next_step_index = step_index + 1;
let step_count = steps.len();
if temporal_state.increment() {
self.cur_frame_mut().push_intent_front(Intent::InvokeComposedStep {
steps: Rc::clone(&steps),
step_index,
state: InvokeComposedStepState::PreTemporalCall {
step_function,
temporal_state,
args,
},
compval,
flag,
})
}
if next_step_index < step_count {
self.cur_frame_mut().push_intent_front(Intent::InvokeComposedStep {
steps,
step_index: next_step_index,
state: InvokeComposedStepState::EvaluatingFunc,
compval: Some(next_compval),
flag,
});
return Ok(true)
} else {
self.cur_frame_mut().write_value(next_compval);
}
},
}
},
Intent::CallTemporal { func, args, mut temporal_state, flag } => {
let targs = args.iter().enumerate().map(|(arg_index, arg)| {
if let Some(tindex) = temporal_state.get(arg_index) {
if arg.is_indexable() {
if let Ok(tval) = arg.index_get(tindex as i64) {
return tval
}
}
}
arg.clone()
}).collect::<Vec<RantValue>>();
if temporal_state.increment() {
self.cur_frame_mut().push_intent_front(Intent::CallTemporal { func: Rc::clone(&func), args, temporal_state, flag });
}
self.call_func(func, targs, flag, false)?;
return Ok(true)
},
Intent::Call { argc, flag, override_print } => {
let mut args = vec![];
for _ in 0..argc {
args.push(self.pop_val()?);
}
let func = match self.pop_val()? {
RantValue::Function(func) => {
func
},
other => runtime_error!(RuntimeErrorType::CannotInvokeValue, format!("cannot call '{}' value", other.type_name()))
};
self.call_func(func, args, flag, override_print)?;
return Ok(true)
},
Intent::BuildDynamicSetter { path, write_mode, expr_count, mut pending_exprs, val_source } => {
match val_source {
SetterValueSource::FromExpression(expr) => {
self.cur_frame_mut().push_intent_front(Intent::BuildDynamicSetter { path, write_mode, expr_count, pending_exprs, val_source: SetterValueSource::Consumed });
self.push_frame(Rc::clone(&expr), true)?;
return Ok(true)
},
SetterValueSource::FromValue(val) => {
self.push_val(val)?;
},
SetterValueSource::Consumed => {}
}
if let Some(key_expr) = pending_exprs.pop() {
if pending_exprs.is_empty() {
self.cur_frame_mut().push_intent_front(Intent::SetValue { path, write_mode, expr_count });
} else {
self.cur_frame_mut().push_intent_front(Intent::BuildDynamicSetter { path, write_mode, expr_count, pending_exprs, val_source: SetterValueSource::Consumed });
}
self.push_frame_flavored(Rc::clone(&key_expr), true, StackFrameFlavor::DynamicKeyExpression)?;
} else {
self.cur_frame_mut().push_intent_front(Intent::SetValue { path, write_mode, expr_count });
}
return Ok(true)
},
Intent::SetValue { path, write_mode, expr_count } => {
self.set_value(path, write_mode, expr_count)?;
},
Intent::BuildList { init, index, mut list } => {
if index > 0 {
list.push(self.pop_val()?);
}
if index >= init.len() {
self.cur_frame_mut().write_value(RantValue::List(Rc::new(RefCell::new(list))))
} else {
self.cur_frame_mut().push_intent_front(Intent::BuildList { init: Rc::clone(&init), index: index + 1, list });
let val_expr = &init[index];
self.push_frame(Rc::clone(val_expr), true)?;
return Ok(true)
}
},
Intent::BuildMap { init, pair_index, mut map } => {
if pair_index > 0 {
let prev_pair = &init[pair_index - 1];
let key = match prev_pair {
(MapKeyExpr::Dynamic(_), _) => InternalString::from(self.pop_val()?.to_string()),
(MapKeyExpr::Static(key), _) => key.clone()
};
let val = self.pop_val()?;
map.raw_set(key.as_str(), val);
}
if pair_index >= init.len() {
self.cur_frame_mut().write_value(RantValue::Map(Rc::new(RefCell::new(map))));
} else {
self.cur_frame_mut().push_intent_front(Intent::BuildMap { init: Rc::clone(&init), pair_index: pair_index + 1, map });
let (key_expr, val_expr) = &init[pair_index];
if let MapKeyExpr::Dynamic(key_expr) = key_expr {
self.push_frame(Rc::clone(&key_expr), true)?;
}
self.push_frame(Rc::clone(val_expr), true)?;
return Ok(true)
}
},
Intent::ImportLastAsModule { module_name, descope } => {
let module = self.pop_val()?;
if let Some(RantValue::Map(module_cache_ref)) = self.engine.get_global(crate::MODULES_CACHE_KEY) {
module_cache_ref.borrow_mut().raw_set(&module_name, module.clone());
} else {
let mut cache = RantMap::new();
cache.raw_set(&module_name, module.clone());
self.engine.set_global(crate::MODULES_CACHE_KEY, RantValue::Map(Rc::new(RefCell::new(cache))));
}
self.def_var_value(&module_name, AccessPathKind::Descope(descope), module, true)?;
},
Intent::RuntimeCall { function, interrupt } => {
function(self)?;
if interrupt {
return Ok(true)
}
},
Intent::DropStaleUnwinds => {
while let Some(unwind) = self.unwinds.last() {
if unwind.call_stack_size >= self.call_stack.len() {
break
}
self.unwinds.pop();
}
}
}
}
runtime_trace!("intents finished");
while let Some(rst) = &self.cur_frame_mut().seq_next() {
match Rc::deref(rst) {
Rst::ListInit(elements) => {
self.cur_frame_mut().push_intent_front(Intent::BuildList { init: Rc::clone(elements), index: 0, list: RantList::new() });
return Ok(true)
},
Rst::MapInit(elements) => {
self.cur_frame_mut().push_intent_front(Intent::BuildMap { init: Rc::clone(elements), pair_index: 0, map: RantMap::new() });
return Ok(true)
},
Rst::Block(block) => {
self.pre_push_block(&block, block.flag)?;
return Ok(true)
},
Rst::VarDef(vname, access_kind, val_expr) => {
if let Some(val_expr) = val_expr {
self.cur_frame_mut().push_intent_front(Intent::DefVar { vname: vname.clone(), access_kind: *access_kind, is_const: false });
self.push_frame(Rc::clone(val_expr), true)?;
return Ok(true)
} else {
self.def_var_value(vname.as_str(), *access_kind, RantValue::Empty, false)?;
}
},
Rst::ConstDef(vname, access_kind, val_expr) => {
if let Some(val_expr) = val_expr {
self.cur_frame_mut().push_intent_front(Intent::DefVar { vname: vname.clone(), access_kind: *access_kind, is_const: true });
self.push_frame(Rc::clone(val_expr), true)?;
return Ok(true)
} else {
self.def_var_value(vname.as_str(), *access_kind, RantValue::Empty, true)?;
}
},
Rst::VarGet(path, fallback) => {
self.push_getter_intents(path, false, false, fallback.as_ref().map(Rc::clone));
return Ok(true)
},
Rst::VarSet(path, val_expr) => {
let exprs = path.dynamic_exprs();
if exprs.is_empty() {
self.cur_frame_mut().push_intent_front(Intent::SetValue { path: Rc::clone(&path), write_mode: VarWriteMode::SetOnly, expr_count: 0 });
self.push_frame(Rc::clone(&val_expr), true)?;
} else {
self.cur_frame_mut().push_intent_front(Intent::BuildDynamicSetter {
expr_count: exprs.len(),
write_mode: VarWriteMode::SetOnly,
path: Rc::clone(path),
pending_exprs: exprs,
val_source: SetterValueSource::FromExpression(Rc::clone(val_expr))
});
}
return Ok(true)
},
Rst::FuncDef(fdef) => {
let FunctionDef {
path,
body,
params,
capture_vars,
is_const,
} = fdef;
let mut captured_vars = vec![];
for capture_id in capture_vars.iter() {
let var = self.call_stack.get_var_mut(&mut self.engine, capture_id, AccessPathKind::Local)?;
var.make_by_ref();
captured_vars.push((capture_id.clone(), var.clone()));
}
let func = RantValue::Function(Rc::new(RantFunction {
params: Rc::clone(params),
body: RantFunctionInterface::User(Rc::clone(body)),
captured_vars,
min_arg_count: params.iter().take_while(|p| p.is_required()).count(),
vararg_start_index: params.iter()
.enumerate()
.find_map(|(i, p)| if p.varity.is_variadic() { Some(i) } else { None })
.unwrap_or_else(|| params.len()),
flavor: None,
}));
let dynamic_keys = path.dynamic_exprs();
self.cur_frame_mut().push_intent_front(Intent::BuildDynamicSetter {
expr_count: dynamic_keys.len(),
write_mode: if *is_const { VarWriteMode::DefineConst } else { VarWriteMode::Define },
pending_exprs: dynamic_keys,
path: Rc::clone(path),
val_source: SetterValueSource::FromValue(func)
});
return Ok(true)
},
Rst::Closure(closure_expr) => {
let ClosureExpr {
capture_vars,
expr,
params,
} = closure_expr;
let mut captured_vars = vec![];
for capture_id in capture_vars.iter() {
let var = self.call_stack.get_var_mut(&mut self.engine, capture_id, AccessPathKind::Local)?;
var.make_by_ref();
captured_vars.push((capture_id.clone(), var.clone()));
}
let func = RantValue::Function(Rc::new(RantFunction {
params: Rc::clone(params),
body: RantFunctionInterface::User(Rc::clone(&expr)),
captured_vars,
min_arg_count: params.iter().take_while(|p| p.is_required()).count(),
vararg_start_index: params.iter()
.enumerate()
.find_map(|(i, p)| if p.varity.is_variadic() { Some(i) } else { None })
.unwrap_or_else(|| params.len()),
flavor: None,
}));
self.cur_frame_mut().write_value(func);
},
Rst::FuncCall(fcall) => {
let FunctionCall {
target,
arguments,
flag,
is_temporal,
} = fcall;
match target {
FunctionCallTarget::Path(path) => {
self.cur_frame_mut().push_intent_front(Intent::Invoke {
eval_count: 0,
arg_exprs: Rc::clone(arguments),
flag: *flag,
is_temporal: *is_temporal,
});
self.push_getter_intents(path, true, true, None);
},
FunctionCallTarget::Expression(expr) => {
self.cur_frame_mut().push_intent_front(Intent::Invoke {
arg_exprs: Rc::clone(arguments),
eval_count: 0,
flag: *flag,
is_temporal: *is_temporal,
});
self.push_frame(Rc::clone(expr), true)?;
},
}
return Ok(true)
},
Rst::ComposedCall(compcall) => {
self.cur_frame_mut().push_intent_front(Intent::InvokeComposedStep {
steps: Rc::clone(&compcall.steps),
step_index: 0,
state: InvokeComposedStepState::EvaluatingFunc,
compval: None,
flag: compcall.flag,
});
return Ok(true)
},
Rst::ComposeValue => {
let compval = self.get_var_value(COMPOSE_VALUE_NAME, AccessPathKind::Local, false)?;
self.cur_frame_mut().write_value(compval);
},
Rst::DebugCursor(info) => {
self.cur_frame_mut().set_debug_info(info);
},
Rst::Fragment(frag) => self.cur_frame_mut().write_frag(frag),
Rst::Whitespace(ws) => self.cur_frame_mut().write_ws(ws),
Rst::Integer(n) => self.cur_frame_mut().write_value(RantValue::Int(*n)),
Rst::Float(n) => self.cur_frame_mut().write_value(RantValue::Float(*n)),
Rst::EmptyVal => self.cur_frame_mut().write_value(RantValue::Empty),
Rst::Boolean(b) => self.cur_frame_mut().write_value(RantValue::Boolean(*b)),
Rst::BlockValue(block) => self.cur_frame_mut().write_value(RantValue::Block(Rc::clone(block))),
Rst::Nop => {},
Rst::Return(expr) => {
if let Some(expr) = expr {
self.cur_frame_mut().push_intent_front(Intent::ReturnLast);
self.push_frame(Rc::clone(expr), true)?;
continue
} else {
self.func_return(None)?;
return Ok(true)
}
},
Rst::Continue(expr) => {
if let Some(expr) = expr {
self.cur_frame_mut().push_intent_front(Intent::ContinueLast);
self.push_frame(Rc::clone(expr), true)?;
continue
} else {
self.interrupt_repeater(None, true)?;
return Ok(true)
}
},
Rst::Break(expr) => {
if let Some(expr) = expr {
self.cur_frame_mut().push_intent_front(Intent::BreakLast);
self.push_frame(Rc::clone(expr), true)?;
continue
} else {
self.interrupt_repeater(None, false)?;
return Ok(true)
}
},
rst => {
runtime_error!(RuntimeErrorType::InternalError, format!("unsupported node type: '{}'", rst.display_name()));
},
}
}
runtime_trace!("frame done: {}", self.call_stack.len());
let mut last_frame = self.pop_frame()?;
if let Some(output) = last_frame.render_output_value() {
self.push_val(output)?;
}
Ok(false)
}
#[inline(always)]
pub fn push_getter_intents(&mut self, path: &Rc<AccessPath>, override_print: bool, prefer_function: bool, fallback: Option<Rc<Sequence>>) {
let dynamic_keys = path.dynamic_exprs();
self.cur_frame_mut().push_intent_front(if dynamic_keys.is_empty() {
Intent::GetValue {
path: Rc::clone(path),
dynamic_key_count: 0,
override_print,
prefer_function,
fallback,
}
} else {
Intent::BuildDynamicGetter {
dynamic_key_count: dynamic_keys.len(),
path: Rc::clone(path),
pending_exprs: dynamic_keys,
override_print,
prefer_function,
fallback,
}
});
}
#[inline]
pub fn call_func(&mut self, func: RantFunctionRef, mut args: Vec<RantValue>, flag: PrintFlag, override_print: bool) -> RuntimeResult<()> {
let argc = args.len();
let is_printing = !flag.is_sink();
let mut args = if func.is_variadic() {
if argc < func.min_arg_count {
runtime_error!(RuntimeErrorType::ArgumentMismatch, format!("arguments don't match; expected at least {}, found {}", func.min_arg_count, argc))
}
if !func.is_native() {
let mut condensed_args = args.drain(0..func.vararg_start_index).collect::<Vec<RantValue>>();
let vararg = RantValue::List(Rc::new(RefCell::new(args.into_iter().collect::<RantList>())));
condensed_args.push(vararg);
condensed_args
} else {
args
}
} else {
if argc < func.min_arg_count || argc > func.params.len() {
runtime_error!(RuntimeErrorType::ArgumentMismatch, format!("arguments don't match; expected {}, found {}", func.min_arg_count, argc))
}
args
};
if is_printing && !override_print {
self.cur_frame_mut().push_intent_front(Intent::PrintLast);
}
match &func.body {
RantFunctionInterface::Foreign(foreign_func) => {
let foreign_func = Rc::clone(foreign_func);
self.push_native_call_frame(Box::new(move |vm| foreign_func(vm, args)), is_printing, StackFrameFlavor::NativeCall)?;
},
RantFunctionInterface::User(user_func) => {
self.push_frame_flavored(Rc::clone(user_func), is_printing, func.flavor.unwrap_or(StackFrameFlavor::FunctionBody))?;
let mut args = args.drain(..);
for param in func.params.iter() {
self.call_stack.def_var_value(
self.engine,
param.name.as_str(),
AccessPathKind::Local,
args.next().unwrap_or(RantValue::Empty),
true,
)?;
}
for (capture_name, capture_var) in func.captured_vars.iter() {
self.call_stack.def_local_var(
capture_name.as_str(),
RantVar::clone(capture_var)
)?;
}
},
}
Ok(())
}
#[inline]
fn set_value(&mut self, path: Rc<AccessPath>, write_mode: VarWriteMode, dynamic_value_count: usize) -> RuntimeResult<()> {
let mut dynamic_values = vec![];
for _ in 0..dynamic_value_count {
dynamic_values.push(self.pop_val()?);
}
let setter_value = self.pop_val()?;
let access_kind = path.kind();
let mut path_iter = path.iter();
let mut dynamic_values = dynamic_values.drain(..);
let mut setter_target: Option<RantValue> = None;
let mut setter_key = match path_iter.next() {
Some(AccessPathComponent::Name(vname)) => {
Some(SetterKey::KeyRef(vname.as_str()))
},
Some(AccessPathComponent::DynamicKey(_)) => {
let key = InternalString::from(dynamic_values.next().unwrap().to_string());
Some(SetterKey::KeyString(key))
},
Some(AccessPathComponent::AnonymousValue(_)) => {
setter_target = Some(dynamic_values.next().unwrap());
None
},
_ => unreachable!()
};
for accessor in path_iter {
setter_target = match (&setter_target, &mut setter_key) {
(None, Some(SetterKey::KeyRef(key))) => Some(self.get_var_value(key, access_kind, false)?),
(None, Some(SetterKey::KeyString(key))) => Some(self.get_var_value(key.as_str(), access_kind, false)?),
(Some(_), None) => setter_target,
(Some(val), Some(SetterKey::Index(index))) => Some(val.index_get(*index).into_runtime_result()?),
(Some(val), Some(SetterKey::KeyRef(key))) => Some(val.key_get(key).into_runtime_result()?),
(Some(val), Some(SetterKey::KeyString(key))) => Some(val.key_get(key.as_str()).into_runtime_result()?),
(Some(val), Some(SetterKey::Slice(slice))) => Some(val.slice_get(slice).into_runtime_result()?),
_ => unreachable!()
};
setter_key = Some(match accessor {
AccessPathComponent::Name(key) => SetterKey::KeyRef(key.as_str()),
AccessPathComponent::Index(index) => SetterKey::Index(*index),
AccessPathComponent::Slice(slice) => {
let slice = match slice.as_static_slice(|_di| dynamic_values.next().unwrap()) {
Ok(slice) => slice,
Err(bad_bound_type) => runtime_error!(RuntimeErrorType::SliceError(SliceError::UnsupportedSliceBoundType(bad_bound_type))),
};
SetterKey::Slice(slice)
},
AccessPathComponent::DynamicKey(_) => {
match dynamic_values.next().unwrap() {
RantValue::Int(index) => {
SetterKey::Index(index)
},
key_val => {
let key = InternalString::from(key_val.to_string());
SetterKey::KeyString(key)
}
}
},
AccessPathComponent::AnonymousValue(_) => {
runtime_error!(RuntimeErrorType::InvalidOperation, "anonymous values may only appear as the first component in an access path")
}
})
}
macro_rules! def_or_set {
($vname:expr, $access_kind:expr, $value:expr) => {
match write_mode {
VarWriteMode::SetOnly => self.set_var_value($vname, $access_kind, $value)?,
VarWriteMode::Define => self.def_var_value($vname, $access_kind, $value, false)?,
VarWriteMode::DefineConst => self.def_var_value($vname, $access_kind, $value, true)?,
}
}
}
match (&mut setter_target, &setter_key) {
(None, Some(SetterKey::KeyRef(vname))) => {
def_or_set!(vname, access_kind, setter_value);
},
(None, Some(SetterKey::KeyString(vname))) => {
def_or_set!(vname.as_str(), access_kind, setter_value);
},
(Some(target), Some(SetterKey::Index(index))) => target.index_set(*index, setter_value).into_runtime_result()?,
(Some(target), Some(SetterKey::KeyRef(key))) => target.key_set(key, setter_value).into_runtime_result()?,
(Some(target), Some(SetterKey::KeyString(key))) => target.key_set(key.as_str(), setter_value).into_runtime_result()?,
(Some(target), Some(SetterKey::Slice(slice))) => target.slice_set(slice, setter_value).into_runtime_result()?,
_ => unreachable!()
}
Ok(())
}
#[inline]
fn get_value(&mut self, path: Rc<AccessPath>, dynamic_key_count: usize, override_print: bool, prefer_function: bool) -> RuntimeResult<()> {
let mut dynamic_keys = vec![];
for _ in 0..dynamic_key_count {
dynamic_keys.push(self.pop_val()?);
}
let mut path_iter = path.iter();
let mut dynamic_keys = dynamic_keys.drain(..);
let mut getter_value = match path_iter.next() {
Some(AccessPathComponent::Name(vname)) => {
self.get_var_value(vname.as_str(), path.kind(), prefer_function)?
},
Some(AccessPathComponent::DynamicKey(_)) => {
let key = dynamic_keys.next().unwrap().to_string();
self.get_var_value(key.as_str(), path.kind(), prefer_function)?
},
Some(AccessPathComponent::AnonymousValue(_)) => {
dynamic_keys.next().unwrap()
},
_ => unreachable!()
};
for accessor in path_iter {
match accessor {
AccessPathComponent::Name(key) => {
getter_value = match getter_value.key_get(key.as_str()) {
Ok(val) => val,
Err(err) => runtime_error!(RuntimeErrorType::KeyError(err))
};
},
AccessPathComponent::Index(index) => {
getter_value = match getter_value.index_get(*index) {
Ok(val) => val,
Err(err) => runtime_error!(RuntimeErrorType::IndexError(err))
}
},
AccessPathComponent::DynamicKey(_) => {
let key = dynamic_keys.next().unwrap();
match key {
RantValue::Int(index) => {
getter_value = match getter_value.index_get(index) {
Ok(val) => val,
Err(err) => runtime_error!(RuntimeErrorType::IndexError(err))
}
},
_ => {
getter_value = match getter_value.key_get(key.to_string().as_str()) {
Ok(val) => val,
Err(err) => runtime_error!(RuntimeErrorType::KeyError(err))
};
}
}
},
AccessPathComponent::Slice(slice) => {
let static_slice = match slice.as_static_slice(|_di| dynamic_keys.next().unwrap()) {
Ok(slice) => slice,
Err(bad_bound_type) => runtime_error!(RuntimeErrorType::SliceError(SliceError::UnsupportedSliceBoundType(bad_bound_type))),
};
getter_value = getter_value.slice_get(&static_slice).into_runtime_result()?;
},
AccessPathComponent::AnonymousValue(_) => {
runtime_error!(RuntimeErrorType::InvalidOperation, "anonymous values may only appear as the first component in an access path")
},
}
}
if override_print {
self.push_val(getter_value)?;
} else {
self.cur_frame_mut().write_value(getter_value);
}
Ok(())
}
pub fn check_block(&mut self) -> RuntimeResult<()> {
let mut is_printing = false;
let mut is_repeater = false;
let rng = self.rng_clone();
let next_element = if let Some(state) = self.resolver.active_block_mut() {
is_repeater = state.is_repeater();
if let Some(element) = state.next_element(rng.as_ref()).into_runtime_result()? {
is_printing = !state.flag().is_sink();
Some(element)
} else {
self.resolver.pop_block();
None
}
} else {
None
};
if let Some(element) = next_element {
self.cur_frame_mut().push_intent_front(Intent::CheckBlock);
match element {
BlockAction::Element(elem_seq) => {
if is_printing {
self.cur_frame_mut().push_intent_front(Intent::PrintLast);
}
self.push_frame_flavored(
Rc::clone(&elem_seq),
is_printing,
if is_repeater {
StackFrameFlavor::RepeaterElement
} else {
StackFrameFlavor::BlockElement
}
)?;
},
BlockAction::PipedElement { elem_func, pipe_func } => {
if is_printing {
self.cur_frame_mut().push_intent_front(Intent::PrintLast);
}
let flag = if is_printing {
PrintFlag::Hint
} else {
PrintFlag::Sink
};
self.call_func(pipe_func, vec![RantValue::Function(elem_func)], flag, true)?;
},
BlockAction::Separator(separator) => {
match separator {
RantValue::Function(sep_func) => {
self.push_val(RantValue::Function(sep_func))?;
self.cur_frame_mut().push_intent_front(Intent::Call {
argc: 0,
flag: if is_printing { PrintFlag::Hint } else { PrintFlag::Sink },
override_print: false
});
},
RantValue::Block(sep_block) => {
self.pre_push_block(&sep_block, sep_block.flag)?;
},
val => {
self.cur_frame_mut().write_value(val);
}
}
}
}
}
Ok(())
}
#[inline]
pub fn pre_push_block(&mut self, block: &Rc<Block>, flag: PrintFlag) -> RuntimeResult<()> {
if block.is_weighted {
self.cur_frame_mut().push_intent_front(Intent::BuildWeightedBlock {
block: Rc::clone(block),
weights: Weights::new(block.elements.len()),
pop_next_weight: false,
});
} else {
self.push_block(block, None, block.flag)?;
}
Ok(())
}
#[inline]
pub fn push_block(&mut self, block: &Block, weights: Option<Weights>, flag: PrintFlag) -> RuntimeResult<()> {
self.resolver.push_block(block, weights, flag);
self.check_block()?;
Ok(())
}
#[inline(always)]
fn def_compval(&mut self, compval: RantValue) -> RuntimeResult<()> {
self.call_stack.def_var_value(self.engine, COMPOSE_VALUE_NAME, AccessPathKind::Local, compval, true)
}
#[inline(always)]
pub(crate) fn set_var_value(&mut self, varname: &str, access: AccessPathKind, val: RantValue) -> RuntimeResult<()> {
self.call_stack.set_var_value(self.engine, varname, access, val)
}
#[inline(always)]
pub fn get_var_value(&self, varname: &str, access: AccessPathKind, prefer_function: bool) -> RuntimeResult<RantValue> {
self.call_stack.get_var_value(self.engine, varname, access, prefer_function)
}
#[inline(always)]
pub fn def_var_value(&mut self, varname: &str, access: AccessPathKind, val: RantValue, is_const: bool) -> RuntimeResult<()> {
self.call_stack.def_var_value(self.engine, varname, access, val, is_const)
}
#[inline(always)]
fn is_stack_empty(&self) -> bool {
self.call_stack.is_empty()
}
#[inline(always)]
pub fn push_val(&mut self, val: RantValue) -> RuntimeResult<usize> {
if self.val_stack.len() < MAX_STACK_SIZE {
self.val_stack.push(val);
Ok(self.val_stack.len())
} else {
runtime_error!(RuntimeErrorType::StackOverflow, "value stack has overflowed");
}
}
#[inline(always)]
pub fn pop_val(&mut self) -> RuntimeResult<RantValue> {
if let Some(val) = self.val_stack.pop() {
Ok(val)
} else {
runtime_error!(RuntimeErrorType::StackUnderflow, "value stack has underflowed");
}
}
#[inline(always)]
pub fn pop_frame(&mut self) -> RuntimeResult<StackFrame> {
runtime_trace!("pop_frame: {} -> {}", self.call_stack.len(), self.call_stack.len() - 1);
if let Some(frame) = self.call_stack.pop_frame() {
Ok(frame)
} else {
runtime_error!(RuntimeErrorType::StackUnderflow, "call stack has underflowed");
}
}
#[inline(always)]
fn push_frame_unchecked(&mut self, callee: Rc<Sequence>, use_output: bool, flavor: StackFrameFlavor) {
runtime_trace!("push_frame_unchecked");
let frame = StackFrame::new(
callee,
use_output,
self.call_stack.top().map(|last| last.output()).flatten()
).with_flavor(flavor);
self.call_stack.push_frame(frame);
}
#[inline(always)]
pub fn push_frame(&mut self, callee: Rc<Sequence>, use_output: bool) -> RuntimeResult<()> {
runtime_trace!("push_frame");
if self.call_stack.len() >= MAX_STACK_SIZE {
runtime_error!(RuntimeErrorType::StackOverflow, "call stack has overflowed");
}
let frame = StackFrame::new(
callee,
use_output,
self.call_stack.top().map(|last| last.output()).flatten()
);
self.call_stack.push_frame(frame);
Ok(())
}
pub fn push_native_call_frame(&mut self, callee: Box<dyn FnOnce(&mut VM) -> RuntimeResult<()>>, use_output: bool, flavor: StackFrameFlavor) -> RuntimeResult<()> {
runtime_trace!("push_native_call_frame");
if self.call_stack.len() >= MAX_STACK_SIZE {
runtime_error!(RuntimeErrorType::StackOverflow, "call stack has overflowed");
}
let last_frame = self.call_stack.top().unwrap();
let frame = StackFrame::new_native_call(
callee,
use_output,
self.call_stack.top().map(|last| last.output()).flatten(),
Rc::clone(last_frame.origin()),
last_frame.debug_pos(),
StackFrameFlavor::Original
).with_flavor(flavor);
self.call_stack.push_frame(frame);
Ok(())
}
#[inline(always)]
pub fn push_frame_flavored(&mut self, callee: Rc<Sequence>, use_output: bool, flavor: StackFrameFlavor) -> RuntimeResult<()> {
runtime_trace!("push_frame_flavored");
if self.call_stack.len() >= MAX_STACK_SIZE {
runtime_error!(RuntimeErrorType::StackOverflow, "call stack has overflowed");
}
let frame = StackFrame::new(
callee,
use_output,
self.call_stack.top().map(|last| last.output()).flatten()
).with_flavor(flavor);
self.call_stack.push_frame(frame);
Ok(())
}
#[inline]
pub fn interrupt_repeater(&mut self, break_val: Option<RantValue>, should_continue: bool) -> RuntimeResult<()> {
if let Some(block_depth) = self.call_stack.taste_for_first(StackFrameFlavor::RepeaterElement) {
if !should_continue {
self.resolver_mut().active_repeater_mut().unwrap().force_stop();
}
if let Some(break_val) = break_val {
for _ in 0..=block_depth {
self.pop_frame()?;
}
self.push_val(break_val)?;
} else {
for i in 0..=block_depth {
let mut old_frame = self.pop_frame()?;
if let Some(output) = old_frame.render_output_value() {
if i < block_depth {
self.cur_frame_mut().write_value(output);
} else {
self.push_val(output)?;
}
}
}
}
while !self.resolver().active_block().unwrap().is_repeater() {
self.resolver_mut().pop_block();
}
Ok(())
} else {
runtime_error!(RuntimeErrorType::ControlFlowError, "no reachable repeater to interrupt");
}
}
#[inline]
pub fn func_return(&mut self, ret_val: Option<RantValue>) -> RuntimeResult<()> {
runtime_trace!("func_return");
if let Some(block_depth) = self.call_stack.taste_for_first(StackFrameFlavor::FunctionBody) {
if let Some(break_val) = ret_val {
for _ in 0..=block_depth {
self.pop_frame()?;
}
self.push_val(break_val)?;
} else {
for i in 0..=block_depth {
let mut old_frame = self.pop_frame()?;
match old_frame.flavor() {
StackFrameFlavor::RepeaterElement | StackFrameFlavor::BlockElement => {
self.resolver_mut().pop_block();
},
_ => {}
}
if let Some(output) = old_frame.render_output_value() {
if i < block_depth {
self.cur_frame_mut().write_value(output);
} else {
self.push_val(output)?;
}
}
}
}
Ok(())
} else {
runtime_error!(RuntimeErrorType::ControlFlowError, "no reachable function to return from");
}
}
#[inline(always)]
pub fn cur_frame_mut(&mut self) -> &mut StackFrame {
self.call_stack.top_mut().unwrap()
}
#[inline(always)]
pub fn any_cur_frame_mut(&mut self) -> Option<&mut StackFrame> {
self.call_stack.top_mut()
}
#[inline(always)]
pub fn parent_frame_mut(&mut self, depth: usize) -> Option<&mut StackFrame> {
self.call_stack.parent_mut(depth)
}
#[inline(always)]
pub fn cur_frame(&self) -> &StackFrame {
self.call_stack.top().unwrap()
}
#[inline(always)]
pub fn rng(&self) -> &RantRng {
self.rng_stack.last().unwrap().as_ref()
}
#[inline(always)]
pub fn rng_clone(&self) -> Rc<RantRng> {
Rc::clone(self.rng_stack.last().unwrap())
}
#[inline]
pub fn push_rng(&mut self, rng: Rc<RantRng>) {
self.rng_stack.push(rng);
}
#[inline]
pub fn pop_rng(&mut self) -> Option<Rc<RantRng>> {
if self.rng_stack.len() <= 1 {
return None
}
self.rng_stack.pop()
}
#[inline(always)]
pub fn context(&self) -> &Rant {
&self.engine
}
#[inline(always)]
pub fn context_mut(&mut self) -> &mut Rant {
&mut self.engine
}
#[inline(always)]
pub fn resolver(&self) -> &Resolver {
&self.resolver
}
#[inline(always)]
pub fn resolver_mut(&mut self) -> &mut Resolver {
&mut self.resolver
}
#[inline(always)]
pub fn program(&self) -> &RantProgram {
self.program
}
#[inline]
pub fn push_unwind_state(&mut self, handler: Option<RantFunctionRef>) {
self.unwinds.push(UnwindState {
handler,
call_stack_size: self.call_stack.len(),
value_stack_size: self.val_stack.len(),
block_stack_size: self.resolver.block_stack_len(),
attr_stack_size: self.resolver.count_attrs(),
});
}
#[inline]
pub fn unwind(&mut self) -> Option<UnwindState> {
let state = self.unwinds.pop();
if let Some(state) = &state {
while self.call_stack.len() > state.call_stack_size {
self.call_stack.pop_frame();
}
while self.val_stack.len() > state.value_stack_size {
self.val_stack.pop();
}
while self.resolver.block_stack_len() > state.block_stack_size {
self.resolver.pop_block();
}
while self.resolver.count_attrs() > state.attr_stack_size {
self.resolver.pop_attrs();
}
}
state
}
}
pub(crate) trait IntoRuntimeResult<T> {
fn into_runtime_result(self) -> RuntimeResult<T>;
}
#[derive(Debug)]
pub struct RuntimeError {
pub error_type: RuntimeErrorType,
pub description: String,
pub stack_trace: Option<String>,
}
impl Error for RuntimeError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.error_type {
RuntimeErrorType::IndexError(err) => Some(err),
RuntimeErrorType::KeyError(err) => Some(err),
RuntimeErrorType::ValueError(err) => Some(err),
_ => None,
}
}
fn cause(&self) -> Option<&dyn Error> {
self.source()
}
}
impl Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}] {}", self.error_type, self.description)
}
}
#[derive(Debug)]
pub enum RuntimeErrorType {
StackOverflow,
StackUnderflow,
InvalidAccess,
InvalidOperation,
InternalError,
ArgumentMismatch,
ArgumentError,
CannotInvokeValue,
AssertError,
TypeError,
ValueError(ValueError),
IndexError(IndexError),
KeyError(KeyError),
SliceError(SliceError),
SelectorError(SelectorError),
ModuleLoadError(ModuleLoadError),
UserError,
ControlFlowError,
}
impl Display for RuntimeErrorType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match self {
RuntimeErrorType::StackOverflow => "stack overflow",
RuntimeErrorType::StackUnderflow => "stack underflow",
RuntimeErrorType::InvalidAccess => "invalid access",
RuntimeErrorType::InvalidOperation => "invalid operation",
RuntimeErrorType::InternalError => "external error",
RuntimeErrorType::ArgumentMismatch => "argument mismatch",
RuntimeErrorType::ArgumentError => "argument error",
RuntimeErrorType::CannotInvokeValue => "cannot invoke value",
RuntimeErrorType::UserError => "user error",
RuntimeErrorType::AssertError => "assertion error",
RuntimeErrorType::TypeError => "type error",
RuntimeErrorType::ValueError(_) => "value error",
RuntimeErrorType::IndexError(_) => "index error",
RuntimeErrorType::KeyError(_) => "key error",
RuntimeErrorType::SliceError(_) => "slice error",
RuntimeErrorType::SelectorError(_) => "selector error",
RuntimeErrorType::ModuleLoadError(_) => "module load error",
RuntimeErrorType::ControlFlowError => "control flow error",
})
}
}