mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-04-18 03:00:27 -04:00
Generators make regular calls and regular returns
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
use std::{fmt, rc::Rc};
|
||||
use std::{fmt, mem::take, rc::Rc};
|
||||
|
||||
use num_bigint::BigInt;
|
||||
|
||||
use crate::{
|
||||
builtins::{error_builtin::ToError, type_error_builtin::ToTypeError},
|
||||
iteration::{iteration_result::IterationResult, return_this::RETURN_THIS},
|
||||
native_function::{native_fn, NativeFunction},
|
||||
stack_frame::StackFrame,
|
||||
native_frame_function::NativeFrameFunction,
|
||||
stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrame, StackFrameTrait},
|
||||
vs_array::VsArray,
|
||||
vs_class::VsClass,
|
||||
vs_symbol::VsSymbol,
|
||||
@@ -14,15 +14,12 @@ use crate::{
|
||||
LoadFunctionResult, ValTrait,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Generator {
|
||||
#[allow(dead_code)] // TODO
|
||||
frame: StackFrame,
|
||||
|
||||
#[allow(dead_code)] // TODO
|
||||
stack: Vec<StackFrame>,
|
||||
|
||||
done: bool,
|
||||
}
|
||||
|
||||
impl Generator {
|
||||
@@ -30,7 +27,6 @@ impl Generator {
|
||||
return Generator {
|
||||
frame,
|
||||
stack: vec![],
|
||||
done: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -112,34 +108,78 @@ impl fmt::Display for Generator {
|
||||
}
|
||||
}
|
||||
|
||||
// We can't use a native function for this. It needs to make a new frame which implements step by
|
||||
// stepping the contained stack.
|
||||
//
|
||||
// Note that next() requires copying the stack in the general case since exceptions must revert the
|
||||
// iterator. One practical solution for this might be to detect when the generator is in a state
|
||||
// where it doesn't use the result of the yield expression and reason that a subsequent next() call
|
||||
// must have the same output, therefore it can store the generated exception in that case instead of
|
||||
// needing to copy.
|
||||
//
|
||||
static NEXT: NativeFunction = native_fn(|mut this, _| {
|
||||
let dynamic = match this.get_mut()? {
|
||||
Val::Dynamic(dynamic) => dynamic,
|
||||
_ => return Err("TODO: indirection".to_error()),
|
||||
};
|
||||
static NEXT: NativeFrameFunction = NativeFrameFunction {
|
||||
make_frame: || Box::new(GeneratorFrame::default()),
|
||||
};
|
||||
|
||||
let generator = dynamic_make_mut(dynamic)
|
||||
.as_any_mut()
|
||||
.downcast_mut::<Generator>()
|
||||
.ok_or_else(|| "Generator.next called on different object".to_type_error())?;
|
||||
#[derive(Clone, Default)]
|
||||
struct GeneratorFrame {
|
||||
generator: Generator,
|
||||
}
|
||||
|
||||
let done = generator.done;
|
||||
generator.done = true;
|
||||
impl GeneratorFrame {}
|
||||
|
||||
Ok(
|
||||
IterationResult {
|
||||
value: "TODO".to_val(),
|
||||
done,
|
||||
impl StackFrameTrait for GeneratorFrame {
|
||||
fn write_this(&mut self, const_: bool, this: Val) -> Result<(), Val> {
|
||||
let mut dynamic = match this {
|
||||
Val::Dynamic(dynamic) => dynamic,
|
||||
_ => return Err("TODO: indirection".to_error()),
|
||||
};
|
||||
|
||||
if const_ {
|
||||
return Err("Cannot call Generator.next on a const generator".to_type_error());
|
||||
}
|
||||
.to_dynamic_val(),
|
||||
)
|
||||
});
|
||||
|
||||
let mut generator = dynamic_make_mut(&mut dynamic)
|
||||
.as_any_mut()
|
||||
.downcast_mut::<Generator>()
|
||||
.ok_or_else(|| "Generator.next called on different object".to_type_error())?;
|
||||
|
||||
self.generator = take(&mut generator);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_param(&mut self, _param: Val) {
|
||||
panic!("TODO: results of yield expressions")
|
||||
}
|
||||
|
||||
fn step(&mut self) -> FrameStepResult {
|
||||
let fsr = self.generator.frame.step();
|
||||
|
||||
match fsr {
|
||||
Err(_) => Err("TODO: exceptions inside generators".to_error()),
|
||||
Ok(FrameStepOk::Continue) | Ok(FrameStepOk::Push(_)) => fsr,
|
||||
Ok(FrameStepOk::Pop(call_result)) => Ok(FrameStepOk::Pop(CallResult {
|
||||
return_: IterationResult {
|
||||
value: call_result.return_, // TODO: Assert call_result.this is undefined?
|
||||
done: true,
|
||||
}
|
||||
.to_dynamic_val(),
|
||||
this: take(&mut self.generator).to_dynamic_val(),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_call_result(&mut self, call_result: CallResult) {
|
||||
self.generator.frame.apply_call_result(call_result)
|
||||
}
|
||||
|
||||
fn get_call_result(&mut self) -> CallResult {
|
||||
panic!("Not appropriate for GeneratorFrame")
|
||||
}
|
||||
|
||||
fn catch_exception(&mut self, exception: Val) -> bool {
|
||||
self.generator.frame.catch_exception(exception)
|
||||
}
|
||||
|
||||
fn clone_to_stack_frame(&self) -> StackFrame {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,3 +31,41 @@ impl Clone for StackFrame {
|
||||
self.clone_to_stack_frame()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for StackFrame {
|
||||
fn default() -> Self {
|
||||
Box::new(VoidStackFrame {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct VoidStackFrame {}
|
||||
|
||||
impl StackFrameTrait for VoidStackFrame {
|
||||
fn write_this(&mut self, _const: bool, _this: Val) -> Result<(), Val> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_param(&mut self, _param: Val) {}
|
||||
|
||||
fn step(&mut self) -> FrameStepResult {
|
||||
Ok(FrameStepOk::Continue)
|
||||
}
|
||||
|
||||
fn apply_call_result(&mut self, _call_result: CallResult) {}
|
||||
|
||||
fn get_call_result(&mut self) -> CallResult {
|
||||
CallResult {
|
||||
return_: Val::Void,
|
||||
this: Val::Void,
|
||||
}
|
||||
}
|
||||
|
||||
fn catch_exception(&mut self, _exception: Val) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn clone_to_stack_frame(&self) -> StackFrame {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user