mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-14 17:35:03 +01:00
improve compiling jumping around
This commit is contained in:
parent
30cad34231
commit
a4dfbb5cd3
1 changed files with 74 additions and 39 deletions
113
src/compile.rs
113
src/compile.rs
|
|
@ -14,7 +14,7 @@ use bumpalo::Bump;
|
|||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
type CResult<T> = Result<T, CompilerError>;
|
||||
type CResult<T = ()> = Result<T, CompilerError>;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct Env<'ast> {
|
||||
|
|
@ -78,7 +78,7 @@ pub fn compile<'ast, 'bc, 'gc>(
|
|||
}
|
||||
|
||||
impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
||||
fn compile(&mut self, ast: &'ast Program<'ast>) -> CResult<()> {
|
||||
fn compile(&mut self, ast: &'ast Program<'ast>) -> CResult {
|
||||
let global_block = FnBlock {
|
||||
code: Vec::new_in(self.bump),
|
||||
stack_sizes: Vec::new_in(self.bump),
|
||||
|
|
@ -95,7 +95,7 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_stmts(&mut self, stmts: &'ast [Stmt]) -> CResult<()> {
|
||||
fn compile_stmts(&mut self, stmts: &'ast [Stmt]) -> CResult {
|
||||
for stmt in stmts {
|
||||
match stmt {
|
||||
Stmt::Declaration(inner) => self.compile_declaration(inner),
|
||||
|
|
@ -115,7 +115,7 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_declaration(&mut self, declaration: &'ast Declaration<'ast>) -> CResult<()> {
|
||||
fn compile_declaration(&mut self, declaration: &'ast Declaration<'ast>) -> CResult {
|
||||
// Compile the expression, the result of the expression will be the last thing left on the stack
|
||||
self.compile_expr(&declaration.init)?;
|
||||
// Now just remember that the value at this stack location is this variable name
|
||||
|
|
@ -127,7 +127,7 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_assignment(&mut self, assignment: &Assignment) -> CResult<()> {
|
||||
fn compile_assignment(&mut self, assignment: &Assignment) -> CResult {
|
||||
let local = match &assignment.lhs {
|
||||
Expr::Ident(ident) => ident,
|
||||
_ => todo!(),
|
||||
|
|
@ -146,17 +146,17 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_fn_decl(&mut self, _: &FnDecl) -> CResult<()> {
|
||||
fn compile_fn_decl(&mut self, _: &FnDecl) -> CResult {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn compile_if(&mut self, if_stmt: &'ast IfStmt) -> CResult<()> {
|
||||
fn compile_if(&mut self, if_stmt: &'ast IfStmt) -> CResult {
|
||||
/*
|
||||
0 PushVal (true)
|
||||
╭─1 JumpCond (2)
|
||||
│ 2 // it is true
|
||||
╭│─4 Jmp (1) │this is optional only for else
|
||||
│╰>5 // it it false │
|
||||
╭│─4 Jmp (1) │ this is optional only for else
|
||||
│╰>5 // it it false │
|
||||
╰─>7 // continue here
|
||||
*/
|
||||
|
||||
|
|
@ -170,10 +170,9 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
if let Some(else_part) = if_stmt.else_part {
|
||||
let else_skip_jmp_idx = self.push_instr(Instr::Jmp(0), StackChange::None, if_stmt.span);
|
||||
|
||||
let block = &mut self.blocks[self.current_block];
|
||||
let next_index = block.code.len();
|
||||
let jmp_pos = (next_index - 1) - jmp_idx;
|
||||
block.code[jmp_idx] = Instr::JumpFalse(jmp_pos as isize);
|
||||
let jmp_pos = self.forward_jmp_offset(jmp_idx as isize);
|
||||
|
||||
self.change_instr(jmp_idx, Instr::JumpFalse(jmp_pos));
|
||||
|
||||
match else_part {
|
||||
ElsePart::Else(block, _) => {
|
||||
|
|
@ -184,53 +183,67 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
let block = &mut self.blocks[self.current_block];
|
||||
let next_index = block.code.len();
|
||||
let jmp_pos = (next_index - else_skip_jmp_idx) - 1;
|
||||
block.code[else_skip_jmp_idx] = Instr::Jmp(jmp_pos as isize);
|
||||
let jmp_pos = self.forward_jmp_offset(else_skip_jmp_idx as isize);
|
||||
|
||||
self.change_instr(else_skip_jmp_idx, Instr::Jmp(jmp_pos));
|
||||
} else {
|
||||
let block = &mut self.blocks[self.current_block];
|
||||
let next_index = block.code.len();
|
||||
let jmp_pos = (next_index - 1) - jmp_idx;
|
||||
block.code[jmp_idx] = Instr::JumpFalse(jmp_pos as isize);
|
||||
let jmp_pos = self.forward_jmp_offset(jmp_idx as isize);
|
||||
self.change_instr(jmp_idx, Instr::JumpFalse(jmp_pos));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_loop(&mut self, ast_block: &'ast Block, span: Span) -> CResult<()> {
|
||||
fn compile_loop(&mut self, ast_block: &'ast Block, span: Span) -> CResult {
|
||||
/*
|
||||
╭>0 // do things
|
||||
╰─1 JMP (-2),
|
||||
*/
|
||||
|
||||
let block = &self.blocks[self.current_block];
|
||||
let first_stmt_idx = block.code.len() as isize;
|
||||
let first_stmt_idx = self.code_len();
|
||||
self.compile_block(ast_block)?;
|
||||
|
||||
let block = &self.blocks[self.current_block];
|
||||
let jmp_index = block.code.len() as isize;
|
||||
|
||||
let jmp_offset = -(jmp_index - first_stmt_idx + 1);
|
||||
let jmp_offset = self.back_jmp_offset(first_stmt_idx);
|
||||
|
||||
self.push_instr(Instr::Jmp(jmp_offset), StackChange::None, span);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_while(&mut self, _: &WhileStmt) -> CResult<()> {
|
||||
fn compile_while(&mut self, while_stmt: &'ast WhileStmt) -> CResult {
|
||||
/*
|
||||
╭─>0 PushVal (true)
|
||||
│╭─1 JmpFalse (2)
|
||||
││ 2 // body
|
||||
╰│─3 Jmp (-3)
|
||||
╰>4 // continue here
|
||||
*/
|
||||
|
||||
let cond_index = self.code_len();
|
||||
self.compile_expr(&while_stmt.cond)?;
|
||||
|
||||
let cond_jmp_index = self.push_instr(Instr::Jmp(0), StackChange::Shrink, while_stmt.span);
|
||||
|
||||
self.compile_block(&while_stmt.body)?;
|
||||
|
||||
let index_of_jmp = self.code_len();
|
||||
let jmp_offset = -(index_of_jmp - (cond_index as isize) + 1);
|
||||
self.push_instr(Instr::Jmp(jmp_offset), StackChange::None, while_stmt.span);
|
||||
|
||||
let skip_amount = self.back_jmp_offset(cond_jmp_index as isize);
|
||||
self.change_instr(cond_jmp_index, Instr::Jmp(skip_amount));
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn compile_break(&mut self, _: Span) -> CResult<()> {
|
||||
fn compile_break(&mut self, _: Span) -> CResult {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn compile_return(&mut self, _: &Option<Expr>, _: Span) -> CResult<()> {
|
||||
fn compile_return(&mut self, _: &Option<Expr>, _: Span) -> CResult {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn compile_print(&mut self, expr: &Expr, span: Span) -> CResult<()> {
|
||||
fn compile_print(&mut self, expr: &Expr, span: Span) -> CResult {
|
||||
self.compile_expr(expr)?;
|
||||
|
||||
self.push_instr(Instr::Print, StackChange::Shrink, span);
|
||||
|
|
@ -238,7 +251,7 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_block(&mut self, block: &'ast Block) -> CResult<()> {
|
||||
fn compile_block(&mut self, block: &'ast Block) -> CResult {
|
||||
let next_env = Env::new_inner(self.env.clone());
|
||||
self.env = next_env;
|
||||
|
||||
|
|
@ -249,7 +262,7 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_expr(&mut self, expr: &Expr) -> CResult<()> {
|
||||
fn compile_expr(&mut self, expr: &Expr) -> CResult {
|
||||
match expr {
|
||||
Expr::Ident(inner) => self.compile_expr_ident(inner),
|
||||
Expr::Literal(inner) => self.compile_expr_literal(inner),
|
||||
|
|
@ -259,13 +272,13 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
fn compile_expr_ident(&mut self, name: &Ident) -> CResult<()> {
|
||||
fn compile_expr_ident(&mut self, name: &Ident) -> CResult {
|
||||
let offset = self.env.borrow().lookup_local(name)?;
|
||||
self.push_instr(Instr::Load(offset), StackChange::Grow, name.span);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_expr_literal(&mut self, lit: &Literal) -> CResult<()> {
|
||||
fn compile_expr_literal(&mut self, lit: &Literal) -> CResult {
|
||||
let value = match lit {
|
||||
Literal::String(str, _) => Value::String(*str),
|
||||
Literal::Number(num, _) => Value::Num(*num),
|
||||
|
|
@ -286,7 +299,7 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_expr_unary(&mut self, unary: &UnaryOp) -> CResult<()> {
|
||||
fn compile_expr_unary(&mut self, unary: &UnaryOp) -> CResult {
|
||||
self.compile_expr(&unary.expr)?;
|
||||
|
||||
// not and neg compile to the same instruction
|
||||
|
|
@ -295,7 +308,7 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_expr_binary(&mut self, binary: &BinaryOp) -> CResult<()> {
|
||||
fn compile_expr_binary(&mut self, binary: &BinaryOp) -> CResult {
|
||||
self.compile_expr(&binary.lhs)?;
|
||||
self.compile_expr(&binary.rhs)?;
|
||||
|
||||
|
|
@ -320,7 +333,7 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_expr_call(&mut self, _: &Call) -> CResult<()> {
|
||||
fn compile_expr_call(&mut self, _: &Call) -> CResult {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
|
@ -330,6 +343,28 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> {
|
|||
*block.stack_sizes.last().expect("empty stack") - 1
|
||||
}
|
||||
|
||||
/// source is implicitly: self.code_len()
|
||||
fn back_jmp_offset(&self, target: isize) -> isize {
|
||||
let source = self.code_len();
|
||||
-(source - target + 1)
|
||||
}
|
||||
|
||||
/// target is implicitly: self.code_len()
|
||||
fn forward_jmp_offset(&self, source: isize) -> isize {
|
||||
let target = self.code_len();
|
||||
target - (source) - 1
|
||||
}
|
||||
|
||||
fn code_len(&self) -> isize {
|
||||
let block = &self.blocks[self.current_block];
|
||||
block.code.len() as isize
|
||||
}
|
||||
|
||||
fn change_instr(&mut self, index: usize, instr: Instr) {
|
||||
let block = &mut self.blocks[self.current_block];
|
||||
block.code[index] = instr;
|
||||
}
|
||||
|
||||
/// Pushes an instruction and returns the index of the new instruction
|
||||
fn push_instr(&mut self, instr: Instr, stack_change: StackChange, span: Span) -> usize {
|
||||
let block = &mut self.blocks[self.current_block];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue