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_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<usize, Compiler> = 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}==");
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.

View File

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