mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-14 17:35:03 +01:00
function things
This commit is contained in:
parent
f23662c1f9
commit
e15967e24c
5 changed files with 117 additions and 36 deletions
|
|
@ -7,7 +7,7 @@ use crate::errors::Span;
|
|||
use crate::gc::Symbol;
|
||||
use bumpalo::collections::Vec;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct Ident {
|
||||
pub sym: Symbol,
|
||||
pub span: Span,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
//! to the length before the call. This means the interpreter has to do some bookkeeping, but it has
|
||||
//! to do that anyways.
|
||||
//!
|
||||
//! It is the compilers job to generate the correct loading of the arguments and assure that the aritiy
|
||||
//! It is the compilers job to generate the correct loading of the arguments and assure that the arity
|
||||
//! is correct before the `Call` instruction.
|
||||
//!
|
||||
//!
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
//!
|
||||
//! When a call happens, the current stack offset is pushed onto the stack as a `Value::Native` and
|
||||
//! the element before it is stored as the new offset.
|
||||
//! Then all parameters are pushed onto the stack, from last to first.
|
||||
//! Then all parameters are pushed onto the stack, from first to last
|
||||
//! Afterwards, execution of the code is started. A function always has to return, and compiler
|
||||
//! inserts `return null` at the end of every function implicitly.
|
||||
//!
|
||||
|
|
@ -41,12 +41,12 @@
|
|||
//! returned value.
|
||||
//!
|
||||
//! ```text
|
||||
//! old stack offset─╮
|
||||
//! ╭─Parameters─╮ │ old FnBlock index─╮ local─╮
|
||||
//! v v v v v
|
||||
//! ───────┬─────────┬──────────┬─────────────┬────────────┬────────────┬─────────╮
|
||||
//! Num(6) │ Num(5) │ Num(6) │ NativeU(20) │ NativeU(4) │ NativeU(1) │ Num(5) │
|
||||
//! ───────┴─────────┴──────────┴─────────────┴────────────┴────────────┴─────────╯
|
||||
//! old stack offset─╮
|
||||
//! ╭─Parameters─╮ │ old Function─╮ local─╮
|
||||
//! v v v v v
|
||||
//! ───────┬─────────┬──────────┬─────────────┬────────────┬──────────┬─────────╮
|
||||
//! Num(6) │ Num(5) │ Num(6) │ NativeU(20) │ NativeU(4) │ Function │ Num(5) │
|
||||
//! ───────┴─────────┴──────────┴─────────────┴────────────┴──────────┴─────────╯
|
||||
//! ^ ╰────────────────────────────────────────────────────────────────── current stack frame
|
||||
//! │ ^
|
||||
//! ╰─ old local ╰─old PC
|
||||
|
|
@ -67,7 +67,7 @@ use debug2::Formatter;
|
|||
#[derive(Debug)]
|
||||
pub struct FnBlock<'bc> {
|
||||
/// The bytecode of the function
|
||||
pub code: Vec<'bc, Instr<'bc>>,
|
||||
pub code: Vec<'bc, Instr>,
|
||||
/// The sizes of the stack required by the function after the instruction at the same index. This is only used
|
||||
/// during compilation to calculate local variable offsets.
|
||||
pub stack_sizes: Vec<'bc, usize>,
|
||||
|
|
@ -90,10 +90,12 @@ impl debug2::Debug for FnBlock<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type Function = usize;
|
||||
|
||||
/// A bytecode instruction. For more details on the structure of the bytecode, read the module level docs [`bytecode`](`self`)
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cfg_attr(feature = "pretty", derive(debug2::Debug))]
|
||||
pub enum Instr<'bc> {
|
||||
pub enum Instr {
|
||||
/// An operation that does nothing.
|
||||
Nop,
|
||||
|
||||
|
|
@ -129,7 +131,8 @@ pub enum Instr<'bc> {
|
|||
/// Same as `JmpFalse`, but unconditional
|
||||
Jmp(isize),
|
||||
|
||||
Call(&'bc FnBlock<'bc>),
|
||||
/// Calls the function at the top of the stack, after the parameters
|
||||
Call,
|
||||
|
||||
Return,
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! The compiler that compiles the AST down to bytecode
|
||||
|
||||
use crate::ast::{
|
||||
Assignment, BinaryOp, BinaryOpKind, Block, Call, Declaration, ElsePart, Expr, FnDecl, Ident,
|
||||
IfStmt, Literal, Program, Stmt, UnaryOp, WhileStmt,
|
||||
Assignment, BinaryOp, BinaryOpKind, Block, Call, CallKind, Declaration, ElsePart, Expr, FnDecl,
|
||||
Ident, IfStmt, Literal, Program, Stmt, UnaryOp, WhileStmt,
|
||||
};
|
||||
use crate::bytecode::{FnBlock, Instr};
|
||||
use crate::errors::{CompilerError, Span};
|
||||
|
|
@ -11,6 +11,7 @@ use crate::vm::Value;
|
|||
use crate::{HashMap, RtAlloc};
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use std::borrow::BorrowMut;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -152,8 +153,25 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_fn_decl(&mut self, _: &FnDecl) -> CResult {
|
||||
todo!()
|
||||
fn compile_fn_decl(&mut self, decl: &FnDecl) -> CResult {
|
||||
let block = FnBlock {
|
||||
code: Vec::new_in(self.bump),
|
||||
stack_sizes: Vec::new_in(self.bump),
|
||||
spans: Vec::new_in(self.bump),
|
||||
arity: decl.params.len().try_into().map_err(|_| {
|
||||
CompilerError::new(
|
||||
decl.params[u8::MAX as usize]
|
||||
.span
|
||||
.extend(decl.params.last().unwrap().span),
|
||||
"Too many parameters".to_string(),
|
||||
)
|
||||
})?,
|
||||
};
|
||||
|
||||
self.blocks.push(block);
|
||||
self.current_block = self.blocks.len() - 1;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_if(&mut self, if_stmt: &IfStmt) -> CResult {
|
||||
|
|
@ -214,7 +232,6 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
|
|||
self.compile_block(ast_block)?;
|
||||
|
||||
self.shrink_stack(pre_loop_stack_size, span);
|
||||
|
||||
let jmp_offset = self.back_jmp_offset(first_stmt_idx);
|
||||
self.push_instr(Instr::Jmp(jmp_offset), StackChange::None, span);
|
||||
|
||||
|
|
@ -358,8 +375,27 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_expr_call(&mut self, _: &Call) -> CResult {
|
||||
todo!()
|
||||
fn compile_expr_call(&mut self, call: &Call) -> CResult {
|
||||
let params = match &call.kind {
|
||||
CallKind::Fn(params) => params,
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
let name = match &call.callee {
|
||||
Expr::Ident(ident) => ident,
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
let offset = self.env.borrow().lookup_local(name)?;
|
||||
|
||||
for param in params {
|
||||
self.compile_expr(param)?;
|
||||
}
|
||||
|
||||
self.push_instr(Instr::Load(offset), StackChange::Grow, call.span);
|
||||
self.push_instr(Instr::Call, StackChange::Grow, call.span);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn shrink_stack(&mut self, jmp_target_stack_size: usize, span: Span) {
|
||||
|
|
@ -415,13 +451,13 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
|
|||
block.stack_sizes.last().copied().unwrap_or(0)
|
||||
}
|
||||
|
||||
fn change_instr(&mut self, index: usize, instr: Instr<'bc>) {
|
||||
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<'bc>, 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 stack_top = block.stack_sizes.last().copied().unwrap_or(0);
|
||||
let new_stack_top = stack_top as isize + stack_change.as_isize();
|
||||
|
|
|
|||
55
src/vm.rs
55
src/vm.rs
|
|
@ -1,4 +1,4 @@
|
|||
use crate::bytecode::{FnBlock, Instr};
|
||||
use crate::bytecode::{FnBlock, Function, Instr};
|
||||
use crate::gc::{Object, RtAlloc, Symbol};
|
||||
use crate::Config;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
|
|
@ -16,6 +16,8 @@ pub fn execute<'bc>(
|
|||
let mut vm = Vm {
|
||||
blocks: bytecode,
|
||||
current: bytecode.first().ok_or("no bytecode found")?,
|
||||
current_block_index: 0,
|
||||
stack_offset: 0,
|
||||
pc: 0,
|
||||
stack: Vec::with_capacity(1024 << 5),
|
||||
_alloc: alloc,
|
||||
|
|
@ -41,20 +43,18 @@ pub enum Value {
|
|||
Array,
|
||||
/// A map from string to value
|
||||
Object(Object),
|
||||
/// A first-class function object
|
||||
Function(Function),
|
||||
/// A value that is stored by the vm for bookkeeping and should never be accessed for anything else
|
||||
NativeU(usize),
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const _: [(); 24] = [(); std::mem::size_of::<Value>()];
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Ptr(NonNull<()>);
|
||||
|
||||
const _: () = _check_val_size();
|
||||
const fn _check_val_size() {
|
||||
if std::mem::size_of::<Value>() != 24 {
|
||||
panic!("value got bigger!");
|
||||
}
|
||||
}
|
||||
|
||||
const TRUE: Value = Value::Bool(true);
|
||||
const FALSE: Value = Value::Bool(false);
|
||||
|
||||
|
|
@ -67,7 +67,11 @@ struct Vm<'bc, 'io> {
|
|||
step: bool,
|
||||
|
||||
// -- local to the current function
|
||||
/// The current function
|
||||
current: &'bc FnBlock<'bc>,
|
||||
current_block_index: usize,
|
||||
/// The offset of the first parameter of the current function
|
||||
stack_offset: usize,
|
||||
/// Index of the instruction currently being executed
|
||||
pc: usize,
|
||||
}
|
||||
|
|
@ -96,9 +100,9 @@ impl<'bc> Vm<'bc, '_> {
|
|||
Instr::Nop => {}
|
||||
Instr::Store(index) => {
|
||||
let val = self.stack.pop().unwrap();
|
||||
self.stack[index] = val;
|
||||
self.stack[self.stack_offset + index] = val;
|
||||
}
|
||||
Instr::Load(index) => self.stack.push(self.stack[index]),
|
||||
Instr::Load(index) => self.stack.push(self.stack[self.stack_offset + index]),
|
||||
Instr::PushVal(value) => self.stack.push(value),
|
||||
Instr::Neg => {
|
||||
let val = self.stack.pop().unwrap();
|
||||
|
|
@ -185,7 +189,7 @@ impl<'bc> Vm<'bc, '_> {
|
|||
}
|
||||
}
|
||||
Instr::Jmp(pos) => self.pc = (self.pc as isize + pos) as usize,
|
||||
Instr::Call(_) => todo!(),
|
||||
Instr::Call => self.call()?,
|
||||
Instr::Return => todo!(),
|
||||
Instr::ShrinkStack(size) => {
|
||||
assert!(self.stack.len() >= size);
|
||||
|
|
@ -210,6 +214,34 @@ impl<'bc> Vm<'bc, '_> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn call(&mut self) -> VmResult {
|
||||
let old_offset = self.stack_offset;
|
||||
let old_idx = self.current_block_index;
|
||||
let function = self.stack.pop().unwrap();
|
||||
if let Value::Function(func) = function {
|
||||
let fn_block = &self.blocks[func];
|
||||
|
||||
let new_stack_frame_start = self.stack.len() - fn_block.arity as usize;
|
||||
self.stack_offset = new_stack_frame_start;
|
||||
|
||||
self.stack.push(Value::NativeU(old_offset));
|
||||
self.stack.push(Value::NativeU(self.pc));
|
||||
self.stack.push(Value::Function(old_idx));
|
||||
|
||||
self.current_block_index = func;
|
||||
self.current = fn_block;
|
||||
|
||||
self.pc = 0;
|
||||
|
||||
// TODO don't be recursive like this
|
||||
self.execute_function()?;
|
||||
} else {
|
||||
return Err("not a function");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn type_error(&self) -> VmError {
|
||||
"bad type"
|
||||
}
|
||||
|
|
@ -240,6 +272,7 @@ impl Display for Value {
|
|||
Value::String(str) => f.write_str(str.as_str()),
|
||||
Value::Array => todo!(),
|
||||
Value::Object(_) => todo!(),
|
||||
Value::Function(_) => f.write_str("[function]"),
|
||||
Value::NativeU(_) => panic!("Called display on native value!"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
17
test.dil
17
test.dil
|
|
@ -1,5 +1,14 @@
|
|||
let i = 0;
|
||||
let x = 5;
|
||||
|
||||
while i < 1000 {
|
||||
i = i + 1;
|
||||
}
|
||||
x(5, 6, 7);
|
||||
|
||||
fn hi(a, b,c,ds,gds,fdsa,fds,fd,sf,ds,fd,fd,fd,d,fd,fd,f,df,df,d,fd
|
||||
,fd,f,fd,fd,fd,fd,fd,f,a, b,c,ds,gds,fdsa,fds,fd,sf,ds,fd,fd,fd,d,fd,
|
||||
fd,f,df,df,d,fd,fd,f,fd,fd,fd,fd,fd,f,a, b,c,ds,gds,fdsa,fds,fd,sf,ds,
|
||||
fd,fd,fd,d,fd,fd,f,df,df,d,fd,fd,f,fd,fd,fd,fd,fd,f,a, b,c,ds,gds,fdsa,
|
||||
fds,fd,sf,ds,fd,fd,fd,d,fd,fd,f,df,df,d,fd,fd,f,fd,fd,fd,fd,fd,f,a, b,c,ds,
|
||||
gds,fdsa,fds,fd,sf,ds,fd,fd,fd,d,fd,fd,f,df,df,d,fd,fd,f,fd,fd,fd,fd,fd,f,df,
|
||||
df,d,fd,fd,f,fd,fd,fd,fd,fd,f,df,df,d,fd,fd,f,fd,fd,fd,fd,f,df,df,d,fd,fd,f,
|
||||
fd,fd,fd,fd,fd,f,df,df,d,fd,fd,f,fd,fd,fd,fd,f,df,df,d,fd,fd,f,fd,fd,fd,fd,
|
||||
fd,f,df,df,d,fd,fd,f,fd,fd,fd,fd,f,df,df,d,fd,fd,f,fd,fd,fd,fd,fd,f,df,df,d,
|
||||
fd,fd,f,fd,fd,fd,fd,f,df,df,d,fd,fd,f,fd,fd,fd,fd,fd,f,df,df,d,fd,fd,f,fd,fd,fd) {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue