From b6f9b35b4c8b2b88971166c47c20167457e68f57 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Fri, 30 May 2025 17:02:55 -0400 Subject: [PATCH] start major work on function compilation --- src/compiler.rs | 106 ++++++++++++++++++++++++++++++++++++++++++------ src/main.rs | 27 ++++++------ 2 files changed, 107 insertions(+), 26 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 4df31e2..965052b 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -6,8 +6,8 @@ use chumsky::prelude::SimpleSpan; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::FromPrimitive; use std::cell::OnceCell; +use std::collections::HashMap; use std::rc::Rc; -use std::string; #[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum Op { @@ -948,40 +948,120 @@ impl Compiler { Fn(name, body, doc) => { // first, declare the function // TODO: or, check if the function has already been declared! - let init_val = Value::Fn(Rc::new(OnceCell::new())); - self.emit_constant(init_val); - self.bind(name); - let FnBody(fn_body) = &body.as_ref().0 else { unreachable!() }; - let mut chunks = vec![]; + let mut compilers: HashMap = HashMap::new(); for clause in fn_body { - let MatchClause(pattern, guard, clause_body) = &clause.0 else { + let MatchClause(pattern, _, clause_body) = &clause.0 else { unreachable!() }; let TuplePattern(pattern) = &pattern.0 else { unreachable!() }; + let arity = pattern.len(); + + let compiler = match compilers.get_mut(&arity) { + Some(compiler) => compiler, + None => { + let mut compiler = Compiler::new(clause, self.name, self.src); + compiler.emit_op(Op::Load); + compiler.stack_depth += arity; + compiler.scope_depth += 1; + compiler.emit_op(Op::ResetMatch); + compiler.match_depth = arity; + compilers.insert(arity, compiler); + compilers.get_mut(&arity).unwrap() + } + }; + + let mut tup_jump_idxes = vec![]; + for member in pattern { + compiler.match_depth -= 1; + compiler.emit_op(Op::MatchDepth); + compiler.emit_byte(compiler.match_depth); + compiler.visit(member); + compiler.emit_op(Op::JumpIfNoMatch); + tup_jump_idxes.push(compiler.len()); + compiler.emit_byte(0xff); + } + compiler.emit_op(Op::Jump); + let jump_idx = compiler.len(); + compiler.emit_byte(0xff); + for idx in tup_jump_idxes { + compiler.chunk.bytecode[idx] = compiler.len() as u8 - idx as u8 - 2; + } + for _ in 0..arity { + compiler.emit_op(Op::Pop); + } + compiler.chunk.bytecode[jump_idx] = compiler.len() as u8 - jump_idx as u8 - 1; + compiler.emit_op(Op::JumpIfNoMatch); + let jnm_idx = compiler.len(); + compiler.emit_byte(0xff); + compiler.visit(clause_body); + compiler.emit_op(Op::Store); + compiler.scope_depth -= 1; + while let Some(binding) = compiler.bindings.last() { + if binding.depth > compiler.scope_depth { + compiler.bindings.pop(); + } else { + break; + } + } + while compiler.stack_depth > arity { + compiler.pop(); + } + compiler.stack_depth = 0; + compiler.emit_op(Op::Jump); + compiler.emit_byte(0xff); + compiler.chunk.bytecode[jnm_idx] = compiler.len() as u8 - jnm_idx as u8; + compiler.scope_depth -= 1; } - // compile the function - let mut compiler = Compiler::new(body, self.name, self.src); - compiler.compile(); if crate::DEBUG_COMPILE { - println!("==function: {name}=="); - compiler.disassemble(); + for (arity, compiler) in compilers.iter() { + println!("==function clause: {name}/{arity}=="); + compiler.disassemble(); + } + } + + // let mut the_chunks = vec![]; + + // for (arity, chunks) in chunks.iter() { + // let mut jump_len: u8 = 0; + // for chunk in chunks.iter().rev() { + // let chunk_len = chunk.bytecode.len(); + // chunk.bytecode[chunk_len - 1] = jump_len; + // jump_len += chunk_len as u8; + // } + // let the_chunk = chunks.into_iter().fold(vec![], |chunks, chunk| { + // chunks.append(); + // chunks + // }); + // the_chunks.push((arity, the_chunk)) + // } + // + // + let mut the_chunks = vec![]; + + for (arity, compiler) in compilers.into_iter() { + the_chunks.push((arity as u8, compiler.chunk)); } let lfn = crate::value::LFn { name, doc: *doc, - chunks, + chunks: the_chunks, closed: vec![], }; + let cell = OnceCell::new(); + let _ = cell.set(lfn); + let init_val = Value::Fn(Rc::new(cell)); + self.emit_constant(init_val); + self.bind(name); // TODO: close over everything accessed in the function // TODO: pull the function off the stack, and set the OnceCell. diff --git a/src/main.rs b/src/main.rs index 34bbed9..4dbf529 100644 --- a/src/main.rs +++ b/src/main.rs @@ -57,25 +57,26 @@ pub fn run(src: &'static str) { println!("\n\n") } - if DEBUG_RUN { - println!("=== vm run: test ==="); - } + // if DEBUG_RUN { + // println!("=== vm run: test ==="); + // } - let mut vm = Vm::new(&compiler.chunk); - let result = vm.run(); - let output = match result { - Ok(val) => val.show(&compiler.chunk), - Err(panic) => format!("Ludus panicked! {panic}"), - }; - vm.print_stack(); - println!("{output}"); + // let mut vm = Vm::new(&compiler.chunk); + // let result = vm.run(); + // let output = match result { + // Ok(val) => val.show(&compiler.chunk), + // Err(panic) => format!("Ludus panicked! {panic}"), + // }; + // vm.print_stack(); + // println!("{output}"); } pub fn main() { env::set_var("RUST_BACKTRACE", "1"); let src = " -let (x as :keyword, y as :number) = (:ok, 42) -[x, y] +fn foo () -> :bar + +foo () "; run(src); }