diff --git a/src/llvm/ast_ir.rs b/src/llvm/ast_ir.rs index 1126d72..5e6948e 100644 --- a/src/llvm/ast_ir.rs +++ b/src/llvm/ast_ir.rs @@ -1,7 +1,7 @@ use crate::{ grammar::ast::{ class, - expr::{Expr, Self_}, + expr::{Dispatch, DispatchExpr, Expr, Return, Self_}, Type, }, llvm::ir, @@ -30,25 +30,69 @@ impl Expr { .const_int(*e, false), ); } + Expr::Dispatch(e) => { + return e.emit_llvm_ir(ir_genrator); + } + Expr::Self_(_) => { + return ir_genrator + .env + .curr_function + .unwrap() + .get_first_param() + .unwrap(); + } + + Expr::Return(e) => { + return e.emit_llvm_ir(ir_genrator); + } + _ => {} } - unreachable!() + ir_genrator.get_llvm_type(LLVMType::I32).const_zero() + } +} + +impl Dispatch { + pub fn emit_llvm_ir<'a>(&self, ir_genrator: &'a IrGenerator) -> BasicValueEnum<'a> { + match &self.expr { + DispatchExpr::Field(field) => { + let off = ir_genrator + .env + .var_env + .get(&ir_genrator.env.curr_class) + .unwrap() + .find(field) + .unwrap() + .into_offset(); + + let target = self.target.emit_llvm_ir(ir_genrator); + let result = ir_genrator + .builder + .build_struct_gep(target.into_pointer_value(), off, "a") + .unwrap(); + return result.into(); + } + DispatchExpr::Method(_) => {} + } + unimplemented!() } } -// impl EmitLLVMIR<'_> for Expr { -// fn emit_llvm_ir>(&self, ir_genrator: &mut IrGenerator) -> V { -// todo!() -// } -// } -// impl EmitLLVMIR for { -// } +impl Return { + pub fn emit_llvm_ir<'a>(&self, ir_genrator: &'a IrGenerator) -> BasicValueEnum<'a> { + if let Some(e) = self.val.as_deref() { + ir_genrator + .builder + .build_return(Some(&e.emit_llvm_ir(ir_genrator))); + } else { + ir_genrator.builder.build_return(None); + } + ir_genrator.get_llvm_type(LLVMType::I32).const_zero() + } +} impl Class { - pub fn emit_llvm_type<'a>( - &self, - ir_genrator: &'a mut IrGenerator, - ) { + pub fn emit_llvm_type<'a>(&self, ir_genrator: &'a mut IrGenerator) { //* class prototype */ //* NULL flag //* _dispatch_table @@ -88,6 +132,13 @@ impl Class { .env .field_offset_map .insert((self.name.clone(), attr.name.clone()), offset); + + ir_genrator + .env + .var_env + .get_mut(&self.name) + .unwrap() + .add(&attr.name, &super::env::VarEnv::Field(offset)); offset += 1; } diff --git a/src/llvm/env.rs b/src/llvm/env.rs new file mode 100644 index 0000000..287397a --- /dev/null +++ b/src/llvm/env.rs @@ -0,0 +1,80 @@ +use std::collections::HashMap; + +use crate::{ + grammar::ast::{Identifier, Type}, + utils::table::SymbolTable, +}; + +use inkwell::{ + basic_block::BasicBlock, + types::StructType, + values::{BasicValueEnum, FunctionValue}, +}; + +#[derive(Clone, Eq)] +pub enum VarEnv<'a> { + //* class's field offset */ + Field(u32), + //* */ + Value(BasicValueEnum<'a>), +} + +impl PartialEq for VarEnv<'_> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Field(l0), Self::Field(r0)) => l0 == r0, + (Self::Value(l0), Self::Value(r0)) => l0 == r0, + _ => false, + } + } +} +impl VarEnv<'_> { + pub fn into_offset(&self) -> u32 { + if let Self::Field(off) = self { + return *off; + } + panic!("error") + } +} + +pub struct Env<'a> { + //* (class, field) -> offset */ + pub field_offset_map: HashMap<(Type, Type), u32>, + + //* (class, method) -> offset of method table */ + pub method_offset_map: HashMap<(Type, Type), usize>, + + //* for struct place holder */ + pub struct_type_place_holders: HashMap>, + + //* curr class */ + pub curr_class: Type, + + pub curr_function: Option>, + + pub curr_block: Option>, + + //* */ + // pub var_env: HashMap>>, + pub var_env: HashMap>>, + // pub var_env: SymbolTable>, +} + +impl Env<'_> { + pub fn new() -> Self { + Env { + field_offset_map: HashMap::new(), + method_offset_map: HashMap::new(), + struct_type_place_holders: HashMap::new(), + curr_class: String::from(""), + curr_function: None, + curr_block: None, + // var_env: SymbolTable::new(), + var_env: HashMap::new(), + } + } + + pub fn get_curr_env(&mut self) -> &SymbolTable> { + self.var_env.get_mut(&self.curr_class).unwrap() + } +} diff --git a/src/llvm/ir.rs b/src/llvm/ir.rs index 0e38fc4..b8ccdd4 100644 --- a/src/llvm/ir.rs +++ b/src/llvm/ir.rs @@ -1,4 +1,4 @@ -use std::{borrow::BorrowMut, collections::HashMap, fmt::format, hash::Hash, ops::Deref}; +use std::ops::Deref; use inkwell::{ builder::Builder, @@ -10,16 +10,15 @@ use inkwell::{ }; use crate::{ - grammar::ast::{ - class::{self, Class, Feature, ParamDecl}, - Type, - }, - utils::table::{ClassTable, Tables}, - DISPATCH_TABLE_OFFSET, OBJECT, + grammar::ast::class::{Class, Feature}, + utils::table::{ClassTable, SymbolTable, Tables}, + OBJECT, }; -use super::types::LLVMType; -#[derive(Debug)] +use super::{ + env::{Env, VarEnv}, + types::LLVMType, +}; /// class prototype /// class method table prototype /// class init method @@ -34,29 +33,6 @@ pub struct IrGenerator<'ctx> { pub tables: Tables, pub env: Env<'ctx>, } -#[derive(Debug)] -pub struct Env<'a> { - // pub function_table: HashMap>, - - //* (class, field) -> offset */ - pub field_offset_map: HashMap<(Type, Type), u32>, - - //* (class, method) -> offset of method table */ - pub method_offset_map: HashMap<(Type, Type), usize>, - - //* */ - pub struct_type_place_holders: HashMap>, -} - -impl Env<'_> { - pub fn new() -> Self { - Env { - field_offset_map: HashMap::new(), - method_offset_map: HashMap::new(), - struct_type_place_holders: HashMap::new(), - } - } -} impl<'ctx> IrGenerator<'ctx> { pub fn new( @@ -82,13 +58,9 @@ impl<'ctx> IrGenerator<'ctx> { //* for placeholder */ self.gen_placeholders(); - //* generate class prototypes */ - let classes = self.classes.clone(); - for class in &classes { - class.emit_llvm_type(self); - } //* generate method ir */ self.gen_methods(); + //* generate main function */ self.gen_main(); @@ -111,8 +83,34 @@ impl<'ctx> IrGenerator<'ctx> { .struct_type_place_holders .insert(class.name.clone(), self.ctx.opaque_struct_type(&class.name)); } - //* first is init_method*/ - self.gen_init_method(); + //* for init_method place holder*/ + self.gen_method_placeholder(); + + //* generate class prototypes */ + //* methods placeholder */ + let classes = self.classes.clone(); + for class in &classes { + self.env + .var_env + .insert(class.name.clone(), SymbolTable::new()); + self.env.var_env.get_mut(&class.name).unwrap().enter_scope(); + class.emit_llvm_type(self); + } + + //* for inkwell's bug */ + //* for string const placeholder */ + let function = self.module.add_function( + "_placeholder", + self.ctx.void_type().fn_type(&[], false), + None, + ); + let entry_block = self.ctx.append_basic_block(function, "entry"); + self.builder.position_at_end(entry_block); + + //* for string constant */ + self.gen_constant(); + + self.builder.build_return(None); } fn gen_main(&self) { @@ -123,18 +121,14 @@ impl<'ctx> IrGenerator<'ctx> { let zero = self.ctx.i32_type().const_int(0, false); self.builder.position_at_end(main_entry_block); - //* for string constant */ - //* for inkwell's bug */ - self.gen_constant(); - let _ = self .builder .build_malloc(self.module.get_struct_type("Main").unwrap(), "m"); self.builder.build_return(Some(&zero)); } - fn gen_init_method(&self) { - //* for place holder */ + fn gen_method_placeholder(&self) { + //* for method place holder */ for class in &self.classes { self.module.add_function( &format!("{}.init", &class.name), @@ -146,6 +140,30 @@ impl<'ctx> IrGenerator<'ctx> { ), None, ); + for f in &class.features { + if let Feature::Method(method) = f { + let mut params: Vec = method + .param + .deref() + .iter() + .map(|param| { + self.get_llvm_type(LLVMType::from_string_to_llvm_type(¶m.1)) + .into() + }) + .collect(); + params.insert( + 0, + self.get_llvm_type(LLVMType::from_string_to_llvm_type(&class.name)) + .into(), + ); + + self.module.add_function( + &format!("{}.{}", &class.name, method.name), + self.get_funtion_type(params.as_slice(), None), + None, + ); + } + } } } @@ -185,14 +203,18 @@ impl<'ctx> IrGenerator<'ctx> { let val = e.emit_llvm_ir(self); let off = self .env - .field_offset_map - .get(&(class.name.clone(), attr.name.clone())) - .unwrap(); + .var_env + .get(&class.name.clone()) + .unwrap() + .find(&attr.name) + .unwrap() + .into_offset(); + let ptr = self .builder .build_struct_gep( init_method.get_first_param().unwrap().into_pointer_value(), - *off, + off, "val", ) .unwrap(); @@ -203,28 +225,42 @@ impl<'ctx> IrGenerator<'ctx> { self.builder.build_return(None); } + + //* emit methods */ for class in &self.classes { + //* curr class */ + self.env.curr_class = class.name.clone(); + for f in &class.features { if let Feature::Method(method) = f { - let mut params: Vec = method - .param - .deref() - .iter() - .map(|param| { - self.get_llvm_type(LLVMType::from_string_to_llvm_type(¶m.1)) - .into() - }) - .collect(); - params.insert( - 0, - self.get_llvm_type(LLVMType::from_string_to_llvm_type(&class.name)) - .into(), - ); - self.module.add_function( - &format!("{}.{}", &class.name, method.name), - self.get_funtion_type(params.as_slice(), None), - None, - ); + self.env.var_env.get_mut(&class.name).unwrap().enter_scope(); + + let m = self + .module + .get_function(&format!("{}.{}", &class.name, &method.name)) + .unwrap(); + self.env.curr_function = Some(m); + + for p in method.param.deref().iter().enumerate() { + self.env.var_env.get_mut(&class.name).unwrap().add( + &p.1 .0, + &VarEnv::Value(m.get_nth_param(p.0.try_into().unwrap()).unwrap()), + ); + } + let entry_block = self + .ctx + .append_basic_block(self.env.curr_function.unwrap(), "entry"); + + self.env.curr_block = Some(entry_block); + self.builder.position_at_end(self.env.curr_block.unwrap()); + + if let Some(exps) = method.body.deref() { + for e in exps { + e.emit_llvm_ir(&self); + } + } + + self.env.var_env.get_mut(&class.name).unwrap().exit_scope(); } } } diff --git a/src/llvm/mod.rs b/src/llvm/mod.rs index 10774d5..2f9ddec 100644 --- a/src/llvm/mod.rs +++ b/src/llvm/mod.rs @@ -2,3 +2,4 @@ pub mod ast_ir; pub mod ir; pub mod types; pub mod utils; +pub mod env; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 4bc5114..bcbe5e5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -238,7 +238,6 @@ fn compile<'a>(files: Vec) { "{}", "🎺 Congratulations you passped the semantic check!".green() ); - let ctx = Context::create(); let module = ctx.create_module("test"); let builder = ctx.create_builder(); diff --git a/src/utils/table.rs b/src/utils/table.rs index 1e92c56..2f1e9d7 100644 --- a/src/utils/table.rs +++ b/src/utils/table.rs @@ -219,16 +219,11 @@ impl ClassTable { } } -pub struct SymbolTable< - K: PartialEq + Eq + Hash + Clone + Display, - V: PartialEq + Eq + Clone + Display, -> { +pub struct SymbolTable { pub scopes: Vec>, } -impl - SymbolTable -{ +impl SymbolTable { pub fn new() -> SymbolTable { SymbolTable { scopes: Vec::new() } } @@ -271,11 +266,11 @@ impl { +pub struct Scope { pub type_map: HashMap, } -impl Scope { +impl Scope { pub fn add(&mut self, k: &K, v: &V) { self.type_map.insert(k.clone(), v.clone()); }