[fine] List iteration... works?

A little hacky but it works!
This commit is contained in:
John Doty 2024-02-08 22:25:00 -08:00
parent 13aaca36c8
commit d5059dd450
4 changed files with 190 additions and 15 deletions

View file

@ -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;