mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-01-14 07:57:57 -05:00
154 lines
4.1 KiB
Rust
154 lines
4.1 KiB
Rust
use std::{mem::take, rc::Rc};
|
|
|
|
use crate::{
|
|
builtins::type_error_builtin::ToTypeError,
|
|
native_function::ThisWrapper,
|
|
operations::op_sub,
|
|
stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrame, StackFrameTrait},
|
|
vs_symbol::VsSymbol,
|
|
vs_value::{ToVal, Val},
|
|
LoadFunctionResult, ValTrait,
|
|
};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct CatStackFrame {
|
|
pub state: CatFrameState,
|
|
pub iter_result: Option<Val>,
|
|
pub args: Vec<Val>,
|
|
pub i: usize,
|
|
pub res: Vec<Val>,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum CatFrameState {
|
|
ReadNext,
|
|
MakingIterator,
|
|
Iterating(Val),
|
|
}
|
|
|
|
impl CatStackFrame {
|
|
pub fn from_args(args: Vec<Val>) -> Self {
|
|
Self {
|
|
state: CatFrameState::ReadNext,
|
|
iter_result: None,
|
|
args,
|
|
i: 0,
|
|
res: vec![],
|
|
}
|
|
}
|
|
|
|
fn read_next(&mut self) -> FrameStepResult {
|
|
let mut arg = match self.args.get_mut(self.i) {
|
|
None => {
|
|
return Ok(FrameStepOk::Pop(CallResult {
|
|
return_: take(&mut self.res).to_val(),
|
|
this: Val::Undefined,
|
|
}));
|
|
}
|
|
Some(arg) => take(arg),
|
|
};
|
|
|
|
self.i += 1;
|
|
|
|
if let Val::Array(mut arg) = arg {
|
|
match Rc::get_mut(&mut arg) {
|
|
Some(arg) => self.res.append(&mut arg.elements),
|
|
None => {
|
|
for item in &arg.elements {
|
|
self.res.push(item.clone());
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ok(FrameStepOk::Continue);
|
|
}
|
|
|
|
let make_iter = op_sub(&mut arg, &VsSymbol::ITERATOR.to_val())?;
|
|
|
|
match make_iter.load_function() {
|
|
LoadFunctionResult::NotAFunction => Err("Non-iterable cat argument".to_type_error()),
|
|
LoadFunctionResult::NativeFunction(fn_) => {
|
|
self.state = CatFrameState::Iterating(fn_(ThisWrapper::new(true, &mut arg), vec![])?);
|
|
Ok(FrameStepOk::Continue)
|
|
}
|
|
LoadFunctionResult::StackFrame(mut new_frame) => {
|
|
self.state = CatFrameState::MakingIterator;
|
|
new_frame.write_this(true, arg)?;
|
|
Ok(FrameStepOk::Push(new_frame))
|
|
}
|
|
}
|
|
}
|
|
|
|
fn apply_iter_result(
|
|
state: &mut CatFrameState,
|
|
res: &mut Vec<Val>,
|
|
iter_result: Val,
|
|
) -> Result<(), Val> {
|
|
let done = iter_result.sub(&"done".to_val())?.is_truthy();
|
|
|
|
if done {
|
|
*state = CatFrameState::ReadNext;
|
|
} else {
|
|
res.push(iter_result.sub(&"value".to_val())?);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl StackFrameTrait for CatStackFrame {
|
|
fn write_this(&mut self, _const: bool, _this: Val) -> Result<(), Val> {
|
|
Ok(())
|
|
}
|
|
|
|
fn write_param(&mut self, param: Val) {
|
|
self.args.push(param);
|
|
}
|
|
|
|
fn step(&mut self) -> FrameStepResult {
|
|
if let Some(iter_result) = take(&mut self.iter_result) {
|
|
Self::apply_iter_result(&mut self.state, &mut self.res, iter_result)?;
|
|
}
|
|
|
|
match &mut self.state {
|
|
CatFrameState::ReadNext => self.read_next(),
|
|
CatFrameState::MakingIterator => panic!("Unexpected step during MakingIterator"),
|
|
CatFrameState::Iterating(iter) => match iter.sub(&"next".to_val())?.load_function() {
|
|
LoadFunctionResult::NotAFunction => Err(".next was not a function".to_type_error()),
|
|
LoadFunctionResult::NativeFunction(fn_) => {
|
|
let iter_result = fn_(ThisWrapper::new(false, iter), vec![])?;
|
|
Self::apply_iter_result(&mut self.state, &mut self.res, iter_result)?;
|
|
Ok(FrameStepOk::Continue)
|
|
}
|
|
LoadFunctionResult::StackFrame(mut new_frame) => {
|
|
new_frame.write_this(false, iter.clone())?;
|
|
Ok(FrameStepOk::Push(new_frame))
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
fn apply_call_result(&mut self, call_result: CallResult) {
|
|
match &mut self.state {
|
|
CatFrameState::ReadNext => panic!("Unexpected call result during ReadNext"),
|
|
CatFrameState::MakingIterator => self.state = CatFrameState::Iterating(call_result.return_),
|
|
CatFrameState::Iterating(iter) => {
|
|
*iter = call_result.this;
|
|
self.iter_result = Some(call_result.return_);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_call_result(&mut self) -> CallResult {
|
|
panic!("Not appropriate for CatStackFrame");
|
|
}
|
|
|
|
fn catch_exception(&mut self, _exception: Val) -> bool {
|
|
false
|
|
}
|
|
|
|
fn clone_to_stack_frame(&self) -> StackFrame {
|
|
Box::new(self.clone())
|
|
}
|
|
}
|