mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-16 10:25:02 +01:00
more function things
This commit is contained in:
parent
ff6b4703ab
commit
912fa48b1d
1 changed files with 39 additions and 16 deletions
|
|
@ -16,16 +16,27 @@ use std::rc::Rc;
|
||||||
|
|
||||||
type CResult<T = ()> = Result<T, CompilerError>;
|
type CResult<T = ()> = Result<T, CompilerError>;
|
||||||
|
|
||||||
|
enum OuterEnvKind {
|
||||||
|
Block,
|
||||||
|
Closure,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct Env {
|
struct Env {
|
||||||
locals: HashMap<Symbol, usize>,
|
locals: HashMap<Symbol, usize>,
|
||||||
outer: Option<Rc<RefCell<Env>>>,
|
outer: Option<Rc<RefCell<Env>>>,
|
||||||
|
outer_kind: OuterEnvKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Env {
|
impl Env {
|
||||||
fn lookup_local(&self, name: &Ident) -> CResult<usize> {
|
fn lookup_local(&self, name: &Ident) -> CResult<usize> {
|
||||||
fn lookup_inner(env: &Env, name: &Ident) -> Option<usize> {
|
fn lookup_inner(env: &Env, name: &Ident) -> Option<usize> {
|
||||||
env.locals.get(&name.sym).copied().or_else(|| {
|
env.locals.get(&name.sym).copied().or_else(|| {
|
||||||
|
// TODO: closure handling 👀
|
||||||
|
if env.outer_kind == OuterEnvKind::Closure {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
env.outer
|
env.outer
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|outer| lookup_inner(&outer.borrow(), name))
|
.and_then(|outer| lookup_inner(&outer.borrow(), name))
|
||||||
|
|
@ -40,10 +51,11 @@ impl Env {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_inner(outer: Rc<RefCell<Self>>) -> Rc<RefCell<Self>> {
|
fn new_inner(outer: Rc<RefCell<Self>>, outer_kind: OuterEnvKind) -> Rc<RefCell<Self>> {
|
||||||
Rc::new(RefCell::new(Self {
|
Rc::new(RefCell::new(Self {
|
||||||
locals: HashMap::default(),
|
locals: HashMap::default(),
|
||||||
outer: Some(outer),
|
outer: Some(outer),
|
||||||
|
outer_kind,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -51,7 +63,7 @@ impl Env {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Compiler<'bc, 'gc> {
|
struct Compiler<'bc, 'gc> {
|
||||||
blocks: Vec<'bc, FnBlock<'bc>>,
|
blocks: Vec<'bc, FnBlock<'bc>>,
|
||||||
current_block: usize,
|
current_block_idx: usize,
|
||||||
bump: &'bc Bump,
|
bump: &'bc Bump,
|
||||||
/// the current local variables that are in scope, only needed for compiling
|
/// the current local variables that are in scope, only needed for compiling
|
||||||
env: Rc<RefCell<Env>>,
|
env: Rc<RefCell<Env>>,
|
||||||
|
|
@ -70,7 +82,7 @@ pub fn compile<'ast, 'bc, 'gc>(
|
||||||
) -> Result<&'bc [FnBlock<'bc>], CompilerError> {
|
) -> Result<&'bc [FnBlock<'bc>], CompilerError> {
|
||||||
let mut compiler = Compiler {
|
let mut compiler = Compiler {
|
||||||
blocks: Vec::new_in(bytecode_bump),
|
blocks: Vec::new_in(bytecode_bump),
|
||||||
current_block: 0,
|
current_block_idx: 0,
|
||||||
bump: bytecode_bump,
|
bump: bytecode_bump,
|
||||||
env: Rc::new(RefCell::new(Env::default())),
|
env: Rc::new(RefCell::new(Env::default())),
|
||||||
rt,
|
rt,
|
||||||
|
|
@ -92,13 +104,13 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
|
||||||
arity: 0,
|
arity: 0,
|
||||||
};
|
};
|
||||||
self.blocks.push(global_block);
|
self.blocks.push(global_block);
|
||||||
self.current_block = self.blocks.len() - 1;
|
self.current_block_idx = self.blocks.len() - 1;
|
||||||
|
|
||||||
self.compile_fn(ast)?;
|
self.compile_fn_body(ast)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_fn(&mut self, block: &Block) -> CResult {
|
fn compile_fn_body(&mut self, block: &Block) -> CResult {
|
||||||
// padding for backwards jumps
|
// padding for backwards jumps
|
||||||
self.push_instr(Instr::Nop, StackChange::None, block.span);
|
self.push_instr(Instr::Nop, StackChange::None, block.span);
|
||||||
|
|
||||||
|
|
@ -171,15 +183,26 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
|
||||||
})?,
|
})?,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// set the new block as the current block
|
||||||
let new_block_idx = self.blocks.len();
|
let new_block_idx = self.blocks.len();
|
||||||
self.blocks.push(block);
|
self.blocks.push(block);
|
||||||
let old_block = self.current_block;
|
let old_block_idx = self.current_block_idx;
|
||||||
self.current_block = new_block_idx;
|
self.current_block_idx = new_block_idx;
|
||||||
|
|
||||||
self.compile_fn(&decl.body)?;
|
// compile the body with a captured environment
|
||||||
|
let inner_env = Env::new_inner(self.env.clone(), OuterEnvKind::Closure);
|
||||||
|
self.env = inner_env;
|
||||||
|
|
||||||
self.current_block = old_block;
|
// todo push params as locals
|
||||||
|
|
||||||
|
self.compile_fn_body(&decl.body)?;
|
||||||
|
|
||||||
|
let outer = self.env.borrow().outer.clone().expect("outer env got lost");
|
||||||
|
self.env = outer;
|
||||||
|
|
||||||
|
self.current_block_idx = old_block_idx;
|
||||||
|
|
||||||
|
// save the function as a local variable
|
||||||
self.push_instr(
|
self.push_instr(
|
||||||
Instr::PushVal(Value::Function(new_block_idx)),
|
Instr::PushVal(Value::Function(new_block_idx)),
|
||||||
StackChange::Grow,
|
StackChange::Grow,
|
||||||
|
|
@ -316,7 +339,7 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_block(&mut self, block: &Block) -> CResult {
|
fn compile_block(&mut self, block: &Block) -> CResult {
|
||||||
let next_env = Env::new_inner(self.env.clone());
|
let next_env = Env::new_inner(self.env.clone(), OuterEnvKind::Block);
|
||||||
self.env = next_env;
|
self.env = next_env;
|
||||||
|
|
||||||
self.compile_stmts(&block.stmts)?;
|
self.compile_stmts(&block.stmts)?;
|
||||||
|
|
@ -446,7 +469,7 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_stack_top(&self) -> usize {
|
fn current_stack_top(&self) -> usize {
|
||||||
let block = &self.blocks[self.current_block];
|
let block = &self.blocks[self.current_block_idx];
|
||||||
// we want the stack position, not the size, so the `- 1`
|
// we want the stack position, not the size, so the `- 1`
|
||||||
*block.stack_sizes.last().expect("empty stack") - 1
|
*block.stack_sizes.last().expect("empty stack") - 1
|
||||||
}
|
}
|
||||||
|
|
@ -464,23 +487,23 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn code_len(&self) -> isize {
|
fn code_len(&self) -> isize {
|
||||||
let block = &self.blocks[self.current_block];
|
let block = &self.blocks[self.current_block_idx];
|
||||||
block.code.len() as isize
|
block.code.len() as isize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_stack_size(&self) -> usize {
|
fn current_stack_size(&self) -> usize {
|
||||||
let block = &self.blocks[self.current_block];
|
let block = &self.blocks[self.current_block_idx];
|
||||||
block.stack_sizes.last().copied().unwrap_or(0)
|
block.stack_sizes.last().copied().unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_instr(&mut self, index: usize, instr: Instr) {
|
fn change_instr(&mut self, index: usize, instr: Instr) {
|
||||||
let block = &mut self.blocks[self.current_block];
|
let block = &mut self.blocks[self.current_block_idx];
|
||||||
block.code[index] = instr;
|
block.code[index] = instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes an instruction and returns the index of the new instruction
|
/// Pushes an instruction and returns the index of the new instruction
|
||||||
fn push_instr(&mut self, instr: Instr, stack_change: StackChange, span: Span) -> usize {
|
fn push_instr(&mut self, instr: Instr, stack_change: StackChange, span: Span) -> usize {
|
||||||
let block = &mut self.blocks[self.current_block];
|
let block = &mut self.blocks[self.current_block_idx];
|
||||||
let stack_top = block.stack_sizes.last().copied().unwrap_or(0);
|
let stack_top = block.stack_sizes.last().copied().unwrap_or(0);
|
||||||
let new_stack_top = stack_top as isize + stack_change.as_isize();
|
let new_stack_top = stack_top as isize + stack_change.as_isize();
|
||||||
assert!(new_stack_top >= 0, "instruction popped stack below 0");
|
assert!(new_stack_top >= 0, "instruction popped stack below 0");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue