start major work on function compilation

This commit is contained in:
Scott Richmond 2025-05-30 17:02:55 -04:00
parent 34ab24c4c9
commit b6f9b35b4c
2 changed files with 107 additions and 26 deletions

View File

@ -6,8 +6,8 @@ use chumsky::prelude::SimpleSpan;
use num_derive::{FromPrimitive, ToPrimitive}; use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use std::cell::OnceCell; use std::cell::OnceCell;
use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::string;
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)] #[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum Op { pub enum Op {
@ -948,40 +948,120 @@ impl Compiler {
Fn(name, body, doc) => { Fn(name, body, doc) => {
// first, declare the function // first, declare the function
// TODO: or, check if the function has already been declared! // 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 { let FnBody(fn_body) = &body.as_ref().0 else {
unreachable!() unreachable!()
}; };
let mut chunks = vec![]; let mut compilers: HashMap<usize, Compiler> = HashMap::new();
for clause in fn_body { for clause in fn_body {
let MatchClause(pattern, guard, clause_body) = &clause.0 else { let MatchClause(pattern, _, clause_body) = &clause.0 else {
unreachable!() unreachable!()
}; };
let TuplePattern(pattern) = &pattern.0 else { let TuplePattern(pattern) = &pattern.0 else {
unreachable!() unreachable!()
}; };
let arity = pattern.len(); 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 { if crate::DEBUG_COMPILE {
println!("==function: {name}=="); for (arity, compiler) in compilers.iter() {
compiler.disassemble(); 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 { let lfn = crate::value::LFn {
name, name,
doc: *doc, doc: *doc,
chunks, chunks: the_chunks,
closed: vec![], 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: close over everything accessed in the function
// TODO: pull the function off the stack, and set the OnceCell. // TODO: pull the function off the stack, and set the OnceCell.

View File

@ -57,25 +57,26 @@ pub fn run(src: &'static str) {
println!("\n\n") println!("\n\n")
} }
if DEBUG_RUN { // if DEBUG_RUN {
println!("=== vm run: test ==="); // println!("=== vm run: test ===");
} // }
let mut vm = Vm::new(&compiler.chunk); // let mut vm = Vm::new(&compiler.chunk);
let result = vm.run(); // let result = vm.run();
let output = match result { // let output = match result {
Ok(val) => val.show(&compiler.chunk), // Ok(val) => val.show(&compiler.chunk),
Err(panic) => format!("Ludus panicked! {panic}"), // Err(panic) => format!("Ludus panicked! {panic}"),
}; // };
vm.print_stack(); // vm.print_stack();
println!("{output}"); // println!("{output}");
} }
pub fn main() { pub fn main() {
env::set_var("RUST_BACKTRACE", "1"); env::set_var("RUST_BACKTRACE", "1");
let src = " let src = "
let (x as :keyword, y as :number) = (:ok, 42) fn foo () -> :bar
[x, y]
foo ()
"; ";
run(src); run(src);
} }