Skip to content

Commit

Permalink
linter integrated into ir (#19)
Browse files Browse the repository at this point in the history
* linter integrated into ir at its most basic level.
  • Loading branch information
coffeebe4code committed May 27, 2024
1 parent 82ebb00 commit e2759e5
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 194 deletions.
2 changes: 1 addition & 1 deletion ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ impl Expr {
#[macro_export]
macro_rules! expr {
($val:ident, $($inner:tt)*) => {
Box::new(Expr::$val($val::new($($inner)*)))
Box::new(Expr::$val(ast::$val::new($($inner)*)))
};
}

Expand Down
2 changes: 2 additions & 0 deletions ir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ symtable = { path="../symtable" }
token = { path="../token" }
perror = { path="../perror" }
lexer = { path="../lexer" }
linter = { path="../linter" }
types = { path="../types" }
cranelift-frontend = "0"
cranelift-codegen = "0"
146 changes: 87 additions & 59 deletions ir/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use ast::*;
use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::entities::FuncRef;
use cranelift_codegen::ir::function::DisplayFunction;
Expand All @@ -11,40 +10,40 @@ use cranelift_codegen::verifier::verify_function;
use cranelift_frontend::*;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use perror::*;
use std::rc::Rc;
use symtable::*;
use token::*;
use types::*;

pub struct IRSource {
pub struct IRSource<'tt> {
package: u32,
fname: u32,
variables: u32,
scope: SymTable,
t_scope: &'tt TypeTable,
}

impl IRSource {
pub fn new(package: u32, scope: SymTable) -> Self {
impl<'tt> IRSource<'tt> {
pub fn new(package: u32, scope: SymTable, t_scope: &'tt TypeTable) -> Self {
IRSource {
package,
fname: 0,
variables: 0,
scope,
t_scope,
}
}
pub fn handle_decl(
pub fn handle_const_init(
&mut self,
op: &InnerDecl,
op: &Initialization,
builder: &mut FunctionBuilder,
) -> ResultFir<Variable> {
let result = self.add_var();
builder.declare_var(result, I64);
let temp = self.recurse(&op.expr, builder).unwrap();
let temp = self.recurse(&op.right, builder).unwrap();
// todo:: optimization: not all paths need declare var if value is only ever read. or something similar, this statement is in the same ballpark, but might not be totally correct
let x = builder.use_var(temp);

self.scope.table.insert(
op.identifier.into_symbol().val.slice.to_string(),
temp.as_u32(),
);
self.scope.table.insert(op.left.clone(), temp.as_u32());
builder.def_var(temp, x);
Ok(temp)
}
Expand All @@ -53,19 +52,14 @@ impl IRSource {
op: &Invoke,
builder: &mut FunctionBuilder,
) -> ResultFir<Variable> {
let mut args: Vec<Value> = vec![];
if op.args.is_some() {
args = op
.args
.as_ref()
.unwrap()
.iter()
.map(|x| {
let result = self.recurse(&x, builder).unwrap();
return builder.use_var(result).clone();
})
.collect::<Vec<Value>>();
}
let args: Vec<Value> = op
.args
.iter()
.map(|x| {
let result = self.recurse(&x, builder).unwrap();
return builder.use_var(result).clone();
})
.collect::<Vec<Value>>();
// todo:: get this correct with funcref. on how to get this from slt?
let call = builder.ins().call(FuncRef::from_u32(0), args.as_slice());
let result = self.add_var();
Expand All @@ -87,33 +81,59 @@ impl IRSource {
.collect();
Ok(*temp.last().unwrap())
}
pub fn handle_ret(&mut self, op: &RetOp, builder: &mut FunctionBuilder) -> ResultFir<Variable> {
let temp = self.recurse(&op.expr, builder).unwrap();
pub fn handle_ret_void(&mut self, builder: &mut FunctionBuilder) -> ResultFir<Variable> {
builder.ins().return_(&[]);
Ok(Variable::from_u32(0))
}
pub fn handle_ret(
&mut self,
op: &UnaryOp,
builder: &mut FunctionBuilder,
) -> ResultFir<Variable> {
let temp = self.recurse(&op.val, builder).unwrap();
let arg = builder.use_var(temp);
builder.ins().return_(&[arg]);
Ok(temp)
}
pub fn handle_sym(&self, op: &Symbol) -> ResultFir<Variable> {
pub fn handle_sym(&self, op: &SymbolAccess) -> ResultFir<Variable> {
Ok(Variable::from_u32(
*self.scope.table.get(&op.val.slice).unwrap(),
*self.scope.table.get(&op.ident).unwrap(),
))
}
pub fn handle_num(
pub fn handle_u64(&mut self, num: u64, builder: &mut FunctionBuilder) -> ResultFir<Variable> {
let result = self.add_var();
builder.declare_var(result, I64);
let temp = builder
.ins()
.iconst(I64, i64::from_ne_bytes(num.to_ne_bytes()));
builder.def_var(result, temp);
Ok(result)
}
pub fn handle_i64(&mut self, num: i64, builder: &mut FunctionBuilder) -> ResultFir<Variable> {
let result = self.add_var();
builder.declare_var(result, I64);
let temp = builder.ins().iconst(I64, num);
builder.def_var(result, temp);
Ok(result)
}
pub fn handle_minus(
&mut self,
num: &Number,
num: &BinaryOp,
builder: &mut FunctionBuilder,
) -> ResultFir<Variable> {
let result = self.add_var();
builder.declare_var(result, I64);
let temp = builder
.ins()
.iconst(I64, num.val.slice.parse::<i64>().unwrap());
let left = self.recurse(&num.left, builder).unwrap();
let right = self.recurse(&num.right, builder).unwrap();
let arg1 = builder.use_var(left);
let arg2 = builder.use_var(right);
let temp = builder.ins().isub(arg1, arg2);
builder.def_var(result, temp);
Ok(result)
}
pub fn handle_bin(
pub fn handle_plus(
&mut self,
num: &BinOp,
num: &BinaryOp,
builder: &mut FunctionBuilder,
) -> ResultFir<Variable> {
let result = self.add_var();
Expand All @@ -122,45 +142,47 @@ impl IRSource {
let right = self.recurse(&num.right, builder).unwrap();
let arg1 = builder.use_var(left);
let arg2 = builder.use_var(right);
let temp = match num.op.token {
Token::Plus => builder.ins().iadd(arg1, arg2),
Token::Dash => builder.ins().isub(arg1, arg2),
Token::Asterisk => builder.ins().imul(arg1, arg2),
Token::Slash => builder.ins().udiv(arg1, arg2),
_ => panic!("invalid binary operand"),
};
let temp = builder.ins().iadd(arg1, arg2);
builder.def_var(result, temp);
Ok(result)
}
pub fn recurse(&mut self, expr: &Expr, builder: &mut FunctionBuilder) -> ResultFir<Variable> {
pub fn recurse(
&mut self,
expr: &TypeTree,
builder: &mut FunctionBuilder,
) -> ResultFir<Variable> {
match expr {
Expr::Block(op) => self.handle_block(&op, builder),
Expr::Invoke(op) => self.handle_invoke(&op, builder),
Expr::BinOp(op) => self.handle_bin(&op, builder),
Expr::RetOp(op) => self.handle_ret(&op, builder),
Expr::Number(op) => self.handle_num(&op, builder),
Expr::InnerDecl(op) => self.handle_decl(&op, builder),
Expr::Symbol(op) => self.handle_sym(&op),
TypeTree::Block(op) => self.handle_block(&op, builder),
TypeTree::Invoke(op) => self.handle_invoke(&op, builder),
TypeTree::Plus(op) => self.handle_plus(&op, builder),
TypeTree::Minus(op) => self.handle_minus(&op, builder),
TypeTree::Return(op) => self.handle_ret(&op, builder),
TypeTree::ReturnVoid(_) => self.handle_ret_void(builder),
TypeTree::ConstInit(op) => self.handle_const_init(&op, builder),
TypeTree::SymbolAccess(op) => self.handle_sym(&op),
TypeTree::U64(op) => self.handle_u64(*op, builder),
TypeTree::I64(op) => self.handle_i64(*op, builder),
_ => panic!("developer error unexpected expression {:?}", expr),
}
}
pub fn begin(&mut self, func_def: FuncDecl) -> Function {
pub fn begin(&mut self, func_def: Rc<Box<TypeTree>>) -> Function {
let mut ctx = FunctionBuilderContext::new();
let mut sig = Signature::new(CallConv::SystemV);
let name = UserFuncName::user(self.package, self.fname);
let func_init = func_def.into_func_init();
// todo:: types need to be worked out, params and returns defined
if let Some(val) = func_def.args {
val.iter()
.for_each(|_x| sig.params.push(AbiParam::new(I64)));
}
func_init
.args
.iter()
.for_each(|_x| sig.params.push(AbiParam::new(I64)));
sig.returns.push(AbiParam::new(I64));
let mut func = Function::with_name_signature(name, sig);
self.fname += 1;
let mut builder = FunctionBuilder::new(&mut func, &mut ctx);
let root_block = builder.create_block();
builder.append_block_params_for_function_params(root_block);
builder.switch_to_block(root_block);
let _result = self.recurse(&func_def.block, &mut builder);
let _result = self.recurse(&func_init.block, &mut builder);
builder.seal_block(root_block);
builder.finalize();
func
Expand All @@ -183,7 +205,10 @@ impl IRSource {
#[cfg(test)]
mod tests {
use super::*;
use ast::*;
use lexer::*;
use linter::*;
use token::*;
#[test]
fn it_should_build_ret_5() {
let func_def = FuncDecl::new(
Expand Down Expand Up @@ -237,8 +262,11 @@ mod tests {
),
None,
);
let mut fir = IRSource::new(0, SymTable::new());
let result = fir.begin(func_def);
let mut type_table = TypeTable::new();
let mut linter = LintSource::new("test", &mut type_table);
let linter_result = linter.check_func_decl(&func_def).unwrap();
let mut fir = IRSource::new(0, SymTable::new(), &linter.ttbl);
let result = fir.begin(linter_result.0);
/*
* function u0:0() -> i64 system_v
* {
Expand Down
Loading

0 comments on commit e2759e5

Please sign in to comment.