[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

@ -7,6 +7,12 @@ use crate::{
tokens::TokenKind,
};
pub const EXTERN_BUILTIN_NOOP: usize = 0;
pub const EXTERN_BUILTIN_LIST_GET_ITERATOR: usize = 1;
pub const EXTERN_BUILTIN_LIST_ITERATOR_NEXT: usize = 2;
pub const EXTERN_USER_FIRST: usize = 100000;
// TODO: If I were cool this would by actual bytecode.
// But I'm not cool.
#[derive(Debug, Clone, Copy)]
@ -55,6 +61,7 @@ pub enum Instruction {
StoreModule(usize),
StoreSlot(usize),
StringAdd,
NewList(usize),
}
pub enum Export {
@ -153,10 +160,6 @@ struct Compiler<'a> {
}
impl<'a> Compiler<'a> {
pub fn type_of(&self, t: TreeRef) -> Type {
self.semantics.type_of(t)
}
fn add_string(&mut self, result: String) -> usize {
let index = self.function.strings.len();
self.function.strings.push(result.into());
@ -307,6 +310,8 @@ fn compile_expression(c: &mut Compiler, t: TreeRef) {
TreeKind::GroupingExpression => compile_grouping(c, tree),
TreeKind::Identifier => compile_identifier_expression(c, t, tree),
TreeKind::IsExpression => compile_is_expression(c, tree),
TreeKind::ListConstructor => compile_list_constructor(c, tree),
TreeKind::ListConstructorElement => compile_list_constructor_element(c, tree),
TreeKind::LiteralExpression => compile_literal(c, t, tree),
TreeKind::MemberAccess => compile_member_access(c, t, tree),
TreeKind::NewObjectExpression => compile_new_object_expression(c, t, tree),
@ -322,7 +327,7 @@ fn compile_expression(c: &mut Compiler, t: TreeRef) {
fn compile_literal(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
let tok = tr.nth_token(0)?;
match c.type_of(t) {
match c.semantics.type_of(t) {
Type::F64 => c.push(Instruction::PushFloat(tok.as_str().parse().unwrap())),
Type::Bool => c.push(if tok.kind == TokenKind::True {
Instruction::PushTrue
@ -969,12 +974,31 @@ fn compile_self_reference(c: &mut Compiler) -> CR {
OK
}
fn compile_list_constructor(c: &mut Compiler, tree: &Tree) -> CR {
let mut children: Vec<_> = tree
.children_of_kind(c.syntax, TreeKind::ListConstructorElement)
.collect();
children.reverse();
let count = children.len();
for child in children {
compile_expression(c, child);
}
c.push(Instruction::NewList(count));
OK
}
fn compile_list_constructor_element(c: &mut Compiler, tree: &Tree) -> CR {
compile_expression(c, tree.nth_tree(0)?);
OK
}
fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
let tree = &c.semantics.tree()[t];
let cr = match tree.kind {
TreeKind::Block => compile_block_statement(c, t, gen_value),
TreeKind::ClassDecl => compile_class_declaration(c, t, tree, gen_value),
TreeKind::ExpressionStatement => compile_expression_statement(c, tree, gen_value),
TreeKind::ForStatement => compile_for_statement(c, tree, gen_value),
TreeKind::FunctionDecl => compile_function_declaration(c, t, tree, gen_value),
TreeKind::IfStatement => compile_if_statement(c, tree, gen_value),
TreeKind::LetStatement => compile_let_statement(c, t, tree, gen_value),
@ -1180,3 +1204,86 @@ fn compile_return_statement(c: &mut Compiler, tree: &Tree) -> CR {
c.push(Instruction::Return);
OK
}
fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
// Figure out the variable.
let vt = tree.nth_tree(1)?;
let var = &c.syntax[vt];
let id = var.nth_token(0)?;
let body = tree.nth_tree(4)?;
let env = c.semantics.environment_of(body);
let Some(variable_decl) = env.bind(id) else {
ice!(c, body, "Unable to bind {id} in loop body");
};
let variable_slot = match variable_decl {
Declaration::Variable {
location, index, ..
} => {
compiler_assert_eq!(
c,
vt,
*location,
Location::Local,
"expected loop variable to be local"
);
*index
}
_ => ice!(c, vt, "loop variable was not a variable"),
};
// Figure out the generator.
let iterable = tree.nth_tree(3)?;
compile_expression(c, iterable);
// call 'get_iterator'
let iterable_typ = c.semantics.type_of(iterable);
match iterable_typ {
Type::List(_) => {
c.push(Instruction::LoadExternFunction(
EXTERN_BUILTIN_LIST_GET_ITERATOR,
));
c.push(Instruction::Call(1));
}
_ => return None, // TODO: Bind and call get_iterator() on type of iterable
}
// iterate
// (Stack is clear except for the iterator.)
let loop_top = c.push(Instruction::Dup); // Save the iterator
match iterable_typ {
Type::List(_) => {
c.push(Instruction::LoadExternFunction(
EXTERN_BUILTIN_LIST_ITERATOR_NEXT,
));
}
_ => return None, // TODO: Bind and call next() on type of iterator
}
c.push(Instruction::Call(1)); // Call 'next'
c.push(Instruction::Dup); // Save the result
c.push(Instruction::IsNothing); // Check to see if iteration is done
let jump_to_end = c.push(Instruction::JumpTrue(0));
c.push(Instruction::StoreLocal(variable_slot)); // Store the value
// (Stack is clear except for the iterator.)
compile_statement(c, body, false); // Run the body
// (Stack is clear except for the iterator.)
c.push(Instruction::Jump(loop_top));
// Clean up the loop.
c.patch(jump_to_end, |i| Instruction::JumpTrue(i));
c.push(Instruction::Discard); // Drop the unused value
c.push(Instruction::Discard); // Drop the iterator
if gen_value {
c.push(Instruction::PushNothing);
}
OK
}