[fine] List iteration... works?
A little hacky but it works!
This commit is contained in:
parent
13aaca36c8
commit
d5059dd450
4 changed files with 190 additions and 15 deletions
|
|
@ -1,7 +1,10 @@
|
|||
use std::cell::RefCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::compiler::{Export, Function, Instruction, Module};
|
||||
use crate::compiler::{
|
||||
Export, Function, Instruction, Module, EXTERN_BUILTIN_LIST_GET_ITERATOR,
|
||||
EXTERN_BUILTIN_LIST_ITERATOR_NEXT, EXTERN_BUILTIN_NOOP,
|
||||
};
|
||||
use crate::semantics::Type;
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
@ -33,8 +36,14 @@ pub enum VMErrorCode {
|
|||
StackExpectedFunction(StackValue),
|
||||
#[error("internal error: stack type mismatch ({0:?} is not object)")]
|
||||
StackExpectedObject(StackValue),
|
||||
#[error("internal error: stack type mismatch ({0:?} is not list)")]
|
||||
StackExpectedList(StackValue),
|
||||
#[error("internal error: stack type mismatch ({0:?} is not list iterator)")]
|
||||
StackExpectedListIterator(StackValue),
|
||||
#[error("internal error: slot {0} was out of range for object (type {1} with {2} slots)")]
|
||||
SlotOutOfRange(usize, Rc<str>, usize),
|
||||
#[error("internal error: the extern function with ID {0} was not registered")]
|
||||
UnregisteredExternFunction(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -65,6 +74,12 @@ impl Object {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ListIterator {
|
||||
list: Rc<Vec<StackValue>>,
|
||||
index: Cell<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum StackValue {
|
||||
Nothing,
|
||||
|
|
@ -75,6 +90,8 @@ pub enum StackValue {
|
|||
Function(Rc<Function>),
|
||||
ExternFunction(usize),
|
||||
Object(Rc<Object>),
|
||||
List(Rc<Vec<StackValue>>),
|
||||
ListIterator(Rc<ListIterator>),
|
||||
}
|
||||
|
||||
impl StackValue {
|
||||
|
|
@ -229,6 +246,10 @@ impl Frame {
|
|||
self.push_value(StackValue::Int(v));
|
||||
}
|
||||
|
||||
fn push_list(&mut self, value: Rc<Vec<StackValue>>) {
|
||||
self.push_value(StackValue::List(value));
|
||||
}
|
||||
|
||||
fn get_argument(&self, i: usize) -> Result<StackValue> {
|
||||
self.args
|
||||
.get(i)
|
||||
|
|
@ -320,6 +341,43 @@ impl Context {
|
|||
.map(|v| v.clone())
|
||||
.ok_or_else(|| VMErrorCode::FunctionOutOfRange(i)) // TODO: Test
|
||||
}
|
||||
|
||||
fn call_extern_function(&self, index: usize, args: &[StackValue]) -> Result<StackValue> {
|
||||
match index {
|
||||
EXTERN_BUILTIN_NOOP => Ok(StackValue::Nothing),
|
||||
EXTERN_BUILTIN_LIST_GET_ITERATOR => {
|
||||
let Some(list_value) = args.get(0) else {
|
||||
return Err(VMErrorCode::ArgumentOutOfRange(0));
|
||||
};
|
||||
let StackValue::List(list) = list_value else {
|
||||
return Err(VMErrorCode::StackExpectedList(list_value.clone()));
|
||||
};
|
||||
|
||||
Ok(StackValue::ListIterator(Rc::new(ListIterator {
|
||||
list: list.clone(),
|
||||
index: Cell::new(0),
|
||||
})))
|
||||
}
|
||||
EXTERN_BUILTIN_LIST_ITERATOR_NEXT => {
|
||||
let Some(iter_value) = args.get(0) else {
|
||||
return Err(VMErrorCode::ArgumentOutOfRange(0));
|
||||
};
|
||||
let StackValue::ListIterator(li) = iter_value else {
|
||||
return Err(VMErrorCode::StackExpectedListIterator(iter_value.clone()));
|
||||
};
|
||||
|
||||
let index = li.index.get();
|
||||
if index >= li.list.len() {
|
||||
Ok(StackValue::Nothing)
|
||||
} else {
|
||||
let result = li.list[index].clone();
|
||||
li.index.set(index + 1);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
_ => Err(VMErrorCode::UnregisteredExternFunction(index)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Flow {
|
||||
|
|
@ -451,7 +509,9 @@ fn eval_one(
|
|||
stack.push(frame);
|
||||
*index = 0;
|
||||
}
|
||||
FuncValue::ExternFunction(_) => todo!(),
|
||||
FuncValue::ExternFunction(i) => {
|
||||
f.push_value(c.call_extern_function(i, &args)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
Instruction::Return => match stack.pop() {
|
||||
|
|
@ -552,6 +612,13 @@ fn eval_one(
|
|||
let v = f.pop_value()?;
|
||||
f.push_bool(v.is_nothing());
|
||||
}
|
||||
Instruction::NewList(c) => {
|
||||
let mut v = Vec::with_capacity(c);
|
||||
for _ in 0..c {
|
||||
v.push(f.pop_value()?);
|
||||
}
|
||||
f.push_list(Rc::new(v));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Flow::Continue)
|
||||
|
|
@ -571,14 +638,14 @@ pub fn eval(
|
|||
let instruction = instructions[index];
|
||||
|
||||
// {
|
||||
// eprint!("{index}: {instruction:?} [");
|
||||
// for val in f.stack.iter().rev().take(3) {
|
||||
// eprint!("{val:?} ");
|
||||
// }
|
||||
// eprint!("{index}: [");
|
||||
// if f.stack.len() > 3 {
|
||||
// eprint!("...");
|
||||
// }
|
||||
// eprintln!("]");
|
||||
// for val in f.stack.iter().take(3) {
|
||||
// eprint!("{val:?} ");
|
||||
// }
|
||||
// eprintln!("] => {instruction:?}");
|
||||
// }
|
||||
|
||||
index += 1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue