diff --git a/examples/easiest.rs b/examples/easiest.rs index 09dd5d0..855a6a1 100644 --- a/examples/easiest.rs +++ b/examples/easiest.rs @@ -1,6 +1,6 @@ use reid::compile; -pub static EASIEST: &str = include_str!("./reid/easiest.reid"); +pub static EASIEST: &str = include_str!("./reid/easy.reid"); fn main() { let text = match compile(EASIEST) { diff --git a/examples/reid/easiest.reid b/examples/reid/easiest.reid index c3239cd..101bae3 100644 --- a/examples/reid/easiest.reid +++ b/examples/reid/easiest.reid @@ -9,6 +9,6 @@ fn somethingelse() { fn main() { let hello = 32 + 2 + 4; let beep = - hello + 100; + hello + 100 + somethingelse(); return beep; } \ No newline at end of file diff --git a/examples/reid/easy.reid b/examples/reid/easy.reid index 268781d..f5a77dc 100644 --- a/examples/reid/easy.reid +++ b/examples/reid/easy.reid @@ -2,11 +2,11 @@ import std::print; -let test = 5; -let simpleAdd = 2 + 2; -let arithmetic = 3 + 2 * 5 + 1 * 2; -let multiplier = 5 * 2; +fn main() { + let test = 5; + let simpleAdd = 2 + 2; + let arithmetic = 3 + 2 * 5 + 1 * 2; + let multiplier = 5 * 2; -let result = arithmetic + multiplier * arithmetic; -print(result); -function(one, two); \ No newline at end of file + return arithmetic + multiplier * arithmetic; +} \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index 3f52952..9450e2f 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -101,7 +101,7 @@ fn parse_binop_rhs( } #[derive(Debug, Clone)] -pub struct FunctionCallExpression(String, Vec); +pub struct FunctionCallExpression(pub String, pub Vec); impl Parse for FunctionCallExpression { fn parse(mut stream: TokenStream) -> Result { @@ -184,7 +184,7 @@ impl Parse for FunctionDefinition { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct FunctionSignature { pub name: String, } diff --git a/src/codegen.rs b/src/codegen.rs index 9ee0211..0d3df4b 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,28 +1,29 @@ use std::collections::{hash_map, HashMap}; use crate::{ - ast::{BinaryOperator, BlockLevelStatement, Expression, FunctionDefinition, TopLevelStatement}, - llvm_ir::{self, IRBlock, IRModule, IRValue, IRValueType}, + ast::{ + BinaryOperator, BlockLevelStatement, Expression, FunctionCallExpression, + FunctionDefinition, FunctionSignature, TopLevelStatement, + }, + llvm_ir::{self, IRBlock, IRFunction, IRModule, IRValue, IRValueType}, }; -pub struct Scope<'a> { - pub block: IRBlock<'a>, +#[derive(Clone)] +pub struct ScopeData { named_vars: HashMap, + defined_functions: HashMap)>, } -impl<'a> Scope<'a> { - pub fn from(block: IRBlock<'a>) -> Self { - Scope { - block, - named_vars: HashMap::new(), - } +impl ScopeData { + pub fn inner<'a>(&'a mut self, block: IRBlock<'a>) -> Scope { + Scope { block, data: self } } - pub fn get(&self, name: &String) -> Option<&IRValue> { + pub fn var(&self, name: &String) -> Option<&IRValue> { self.named_vars.get(name) } - pub fn set(&mut self, name: &str, val: IRValue) -> Result<(), Error> { + pub fn set_var(&mut self, name: &str, val: IRValue) -> Result<(), Error> { if let hash_map::Entry::Vacant(e) = self.named_vars.entry(name.to_owned()) { e.insert(val); Ok(()) @@ -30,25 +31,83 @@ impl<'a> Scope<'a> { Err(Error::VariableAlreadyDefined(name.to_owned())) } } + + pub fn function( + &mut self, + name: &String, + ) -> Option<&mut (FunctionSignature, Option)> { + self.defined_functions.get_mut(name) + } + + pub fn set_function_signature( + &mut self, + name: &str, + sig: FunctionSignature, + ir: IRFunction, + ) -> Result<(), Error> { + if let hash_map::Entry::Vacant(e) = self.defined_functions.entry(name.to_owned()) { + e.insert((sig, Some(ir))); + Ok(()) + } else { + Err(Error::VariableAlreadyDefined(name.to_owned())) + } + } +} + +pub struct Scope<'a, 'b> { + pub block: IRBlock<'a>, + pub data: &'b mut ScopeData, +} + +pub fn codegen_from_statements(statements: Vec) -> Result { + let mut module = IRModule::new("testmod"); + + let mut scope = ScopeData { + defined_functions: HashMap::new(), + named_vars: HashMap::new(), + }; + + for statement in &statements { + match statement { + TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, _)) => { + let function = module.create_func(&sig.name, IRValueType::I32); + scope.set_function_signature(&sig.name.clone(), sig.clone(), function)?; + } + TopLevelStatement::Import(_) => {} + } + } + + for statement in &statements { + statement.codegen(&mut module, &mut scope)?; + } + + Ok(module) } impl TopLevelStatement { - pub fn codegen(&self, module: &mut IRModule) -> Result<(), Error> { + pub fn codegen(&self, module: &mut IRModule, root_data: &mut ScopeData) -> Result<(), Error> { match self { TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, block)) => { - let func = module.create_func(&sig.name, IRValueType::I32); - let mut scope = Scope::from(module.create_block()); + if let Some((_, ir)) = root_data.function(&sig.name) { + if let Some(ir) = ir.take() { + let mut scope = root_data.inner(module.create_block()); - for statement in &block.0 { - statement.codegen(&mut scope)?; - } + for statement in &block.0 { + statement.codegen(&mut scope)?; + } - let value = if let Some(exp) = &block.1 { - exp.codegen(&mut scope)? + let value = if let Some(exp) = &block.1 { + exp.codegen(&mut scope)? + } else { + panic!("Void-return type function not yet implemented!"); + }; + ir.add_definition(value, scope.block); + } else { + Err(Error::FunctionAlreadyDefined(sig.name.clone()))? + } } else { - panic!("Void-return type function not yet implemented!"); - }; - func.add_definition(value, scope.block); + panic!("Function was not declared before it's definition") + } } TopLevelStatement::Import(_) => {} } @@ -61,7 +120,7 @@ impl BlockLevelStatement { match self { BlockLevelStatement::Let(let_statement) => { let val = let_statement.1.codegen(scope)?; - scope.set(&let_statement.0, val)?; + scope.data.set_var(&let_statement.0, val)?; Ok(()) } BlockLevelStatement::Return(_) => panic!("Should never happen"), @@ -81,12 +140,24 @@ impl Expression { let rhs = rhs.codegen(scope)?; Ok(scope.block.add(lhs, rhs)?) } - BinaryOperator::Mult => panic!("Not implemented!"), + BinaryOperator::Mult => { + let lhs = lhs.codegen(scope)?; + let rhs = rhs.codegen(scope)?; + Ok(scope.block.mul(lhs, rhs)?) + } }, - BlockExpr(_) => panic!("Not implemented!"), - FunctionCall(_) => panic!("Not implemented!"), + BlockExpr(_) => panic!("(BlockExpr) Not implemented!"), + FunctionCall(fc) => { + let FunctionCallExpression(name, _) = &**fc; + if let Some((sig, _)) = scope.data.function(name) { + Ok(scope.block.function_call(sig)?) + } else { + Err(Error::UndefinedFunction(name.clone()))? + } + } VariableName(name) => scope - .get(name) + .data + .var(name) .cloned() .ok_or(Error::UndefinedVariable(name.clone())), Literal(lit) => Ok(scope.block.get_const(lit)), @@ -100,6 +171,10 @@ pub enum Error { VariableAlreadyDefined(String), #[error("Variable '{0}' not yet defined")] UndefinedVariable(String), + #[error("Function '{0}' not defined")] + UndefinedFunction(String), + #[error("Function '{0}' already defined")] + FunctionAlreadyDefined(String), #[error(transparent)] Deeper(#[from] llvm_ir::Error), } diff --git a/src/lib.rs b/src/lib.rs index 831c890..7b4143e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,7 @@ -use crate::{ast::TopLevelStatement, lexer::Token, llvm_ir::IRModule, token_stream::TokenStream}; +use crate::{ + ast::TopLevelStatement, codegen::codegen_from_statements, lexer::Token, llvm_ir::IRModule, + token_stream::TokenStream, +}; mod ast; mod codegen; @@ -37,10 +40,7 @@ pub fn compile(source: &str) -> Result { statements.push(statement); } - let mut module = IRModule::new("testmod"); - for statement in statements { - statement.codegen(&mut module)?; - } + let mut module = codegen_from_statements(statements)?; let text = module.print_to_string().unwrap(); Ok(text.to_owned()) } diff --git a/src/llvm_ir.rs b/src/llvm_ir.rs index 47151b3..c530511 100644 --- a/src/llvm_ir.rs +++ b/src/llvm_ir.rs @@ -3,7 +3,7 @@ use std::mem; use llvm_sys::{core::*, prelude::*, LLVMBuilder, LLVMContext, LLVMModule}; -use crate::ast::Literal; +use crate::ast::{FunctionSignature, Literal}; macro_rules! cstr { ($string:expr) => { @@ -11,19 +11,6 @@ macro_rules! cstr { }; } -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum IRValueType { - I32, -} - -impl IRValueType { - unsafe fn get_llvm_type(&self, codegen: &mut IRModule) -> LLVMTypeRef { - match *self { - Self::I32 => LLVMInt32TypeInContext(codegen.context), - } - } -} - #[derive(Clone, Debug)] #[must_use = "value contains raw pointer and must be inserted somewhere"] pub struct IRValue(IRValueType, LLVMValueRef); @@ -96,6 +83,20 @@ impl Drop for IRModule { } } +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum IRValueType { + I32, +} + +impl IRValueType { + unsafe fn get_llvm_type(&self, codegen: &mut IRModule) -> LLVMTypeRef { + match *self { + Self::I32 => LLVMInt32TypeInContext(codegen.context), + } + } +} + +#[derive(Clone, Debug)] pub struct IRFunction { value: IRValue, } @@ -154,6 +155,45 @@ impl<'a> IRBlock<'a> { } } } + + pub fn mul(&mut self, lhs: IRValue, rhs: IRValue) -> Result { + unsafe { + if lhs.0 == rhs.0 { + Ok(IRValue( + lhs.0, + LLVMBuildMul(self.module.builder, lhs.1, rhs.1, cstr!("tmpadd")), + )) + } else { + Err(Error::TypeMismatch(lhs.0, rhs.0)) + } + } + } + + pub fn function_call(&mut self, callee: &FunctionSignature) -> Result { + unsafe { + let function = LLVMGetNamedFunction( + self.module.module, + into_cstring(callee.name.clone()).as_ptr(), + ); + + let ret_t = LLVMInt32TypeInContext(self.module.context); + let mut argts = []; + let mut args = []; + + let fun_t = LLVMFunctionType(ret_t, argts.as_mut_ptr(), argts.len() as u32, 0); + + let call = LLVMBuildCall2( + self.module.builder, + fun_t, + function, + args.as_mut_ptr(), + args.len() as u32, + into_cstring(&callee.name).as_ptr(), + ); + + Ok(IRValue(IRValueType::I32, call)) + } + } } #[derive(Debug, thiserror::Error)]