diff --git a/examples/easiest.rs b/examples/easiest.rs index 855a6a1..09dd5d0 100644 --- a/examples/easiest.rs +++ b/examples/easiest.rs @@ -1,6 +1,6 @@ use reid::compile; -pub static EASIEST: &str = include_str!("./reid/easy.reid"); +pub static EASIEST: &str = include_str!("./reid/easiest.reid"); fn main() { let text = match compile(EASIEST) { diff --git a/examples/reid/easiest.reid b/examples/reid/easiest.reid index 101bae3..dce07b9 100644 --- a/examples/reid/easiest.reid +++ b/examples/reid/easiest.reid @@ -7,8 +7,9 @@ fn somethingelse() { } fn main() { - let hello = 32 + 2 + 4; - let beep = - hello + 100 + somethingelse(); + let hello = 32 + { + 2 + somethingelse() + }; + let beep = hello + 5; return beep; } \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index 9450e2f..f7a6c6b 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -201,19 +201,42 @@ impl Parse for FunctionSignature { } } +#[derive(Debug, Clone, Copy)] +pub enum ReturnType { + Soft, + Hard, +} + #[derive(Debug, Clone)] -pub struct Block(pub Vec, pub Option); +pub struct Block( + pub Vec, + pub Option<(ReturnType, Expression)>, +); impl Parse for Block { fn parse(mut stream: TokenStream) -> Result { let mut statements = Vec::new(); let mut return_stmt = None; stream.expect(Token::BraceOpen)?; + while !matches!(stream.peek(), Some(Token::BraceClose)) { + if let Some((r_type, e)) = return_stmt.take() { + println!("Oh no, does this statement lack ;"); + dbg!(r_type, e); + } let statement = stream.parse()?; - if let BlockLevelStatement::Return(e) = &statement { - return_stmt = Some(e.clone()); - break; // Return has to be the last statement + if let BlockLevelStatement::Return((r_type, e)) = &statement { + match r_type { + ReturnType::Hard => { + return_stmt = Some((*r_type, e.clone())); + break; // Return has to be the last statement + // TODO: Make a mechanism that "can" parse even after this + } + ReturnType::Soft => { + return_stmt = Some((*r_type, e.clone())); + continue; // In theory possible to have lines after a soft return + } + }; } statements.push(statement); } @@ -227,7 +250,7 @@ pub enum BlockLevelStatement { Let(LetStatement), Import(ImportStatement), Expression(Expression), - Return(Expression), + Return((ReturnType, Expression)), } impl Parse for BlockLevelStatement { @@ -240,12 +263,15 @@ impl Parse for BlockLevelStatement { stream.next(); let exp = stream.parse()?; stream.expect(Token::Semi)?; - Stmt::Return(exp) + Stmt::Return((ReturnType::Hard, exp)) } _ => { if let Ok(e) = stream.parse() { - stream.expect(Token::Semi)?; - Stmt::Expression(e) + if stream.expect(Token::Semi).is_ok() { + Stmt::Expression(e) + } else { + Stmt::Return((ReturnType::Soft, e)) + } } else { Err(stream.expected_err("expression")?)? } diff --git a/src/codegen.rs b/src/codegen.rs index 0d3df4b..a7f4f15 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -2,8 +2,8 @@ use std::collections::{hash_map, HashMap}; use crate::{ ast::{ - BinaryOperator, BlockLevelStatement, Expression, FunctionCallExpression, - FunctionDefinition, FunctionSignature, TopLevelStatement, + BinaryOperator, Block, BlockLevelStatement, Expression, FunctionCallExpression, + FunctionDefinition, FunctionSignature, ReturnType, TopLevelStatement, }, llvm_ir::{self, IRBlock, IRFunction, IRModule, IRValue, IRValueType}, }; @@ -15,8 +15,11 @@ pub struct ScopeData { } impl ScopeData { - pub fn inner<'a>(&'a mut self, block: IRBlock<'a>) -> Scope { - Scope { block, data: self } + pub fn inner<'a, 'b>(&self, block: &'b mut IRBlock<'a>) -> Scope<'a, 'b> { + Scope { + block, + data: self.clone(), + } } pub fn var(&self, name: &String) -> Option<&IRValue> { @@ -55,8 +58,17 @@ impl ScopeData { } pub struct Scope<'a, 'b> { - pub block: IRBlock<'a>, - pub data: &'b mut ScopeData, + pub block: &'b mut IRBlock<'a>, + pub data: ScopeData, +} + +impl<'a, 'b> Scope<'a, 'b> { + pub fn inner<'c>(&'c mut self) -> Scope<'a, 'c> { + Scope { + block: self.block, + data: self.data.clone(), + } + } } pub fn codegen_from_statements(statements: Vec) -> Result { @@ -89,19 +101,16 @@ impl TopLevelStatement { match self { TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, 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()); + if let Some(ir_function) = ir.take() { + let mut ir_block = module.create_block(); + let mut scope = root_data.inner(&mut ir_block); - for statement in &block.0 { - statement.codegen(&mut scope)?; - } - - let value = if let Some(exp) = &block.1 { - exp.codegen(&mut scope)? - } else { - panic!("Void-return type function not yet implemented!"); + let (_, value) = match block.codegen(&mut scope)? { + Some(v) => v, + None => panic!("Void-return type function not yet implemented!"), }; - ir.add_definition(value, scope.block); + + ir_function.add_definition(value, ir_block); } else { Err(Error::FunctionAlreadyDefined(sig.name.clone()))? } @@ -115,6 +124,22 @@ impl TopLevelStatement { } } +impl Block { + pub fn codegen(&self, scope: &mut Scope) -> Result, Error> { + for statement in &self.0 { + statement.codegen(scope)?; + } + + let value = if let Some((rt, exp)) = &self.1 { + Some((*rt, exp.codegen(scope)?)) + } else { + None + }; + + Ok(value) + } +} + impl BlockLevelStatement { pub fn codegen(&self, scope: &mut Scope) -> Result<(), Error> { match self { @@ -146,7 +171,19 @@ impl Expression { Ok(scope.block.mul(lhs, rhs)?) } }, - BlockExpr(_) => panic!("(BlockExpr) Not implemented!"), + BlockExpr(block) => { + let mut inner = scope.inner(); + + Ok(match block.codegen(&mut inner)? { + Some((r_type, value)) => match r_type { + ReturnType::Soft => value, + ReturnType::Hard => { + panic!("Hard returns in inner blocks not supported yet") + } + }, + None => panic!("Void-return type block not yet implemented!"), + }) + } FunctionCall(fc) => { let FunctionCallExpression(name, _) = &**fc; if let Some((sig, _)) = scope.data.function(name) { diff --git a/src/lib.rs b/src/lib.rs index 7b4143e..afbc452 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ use crate::{ - ast::TopLevelStatement, codegen::codegen_from_statements, lexer::Token, llvm_ir::IRModule, + ast::TopLevelStatement, codegen::codegen_from_statements, lexer::Token, token_stream::TokenStream, }; diff --git a/src/llvm_ir.rs b/src/llvm_ir.rs index c530511..d0c754f 100644 --- a/src/llvm_ir.rs +++ b/src/llvm_ir.rs @@ -15,6 +15,19 @@ macro_rules! cstr { #[must_use = "value contains raw pointer and must be inserted somewhere"] pub struct IRValue(IRValueType, LLVMValueRef); +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum IRValueType { + I32, +} + +impl IRValueType { + unsafe fn get_llvm_type(&self, module: &mut IRModule) -> LLVMTypeRef { + match *self { + Self::I32 => LLVMInt32TypeInContext(module.context), + } + } +} + fn into_cstring>(value: T) -> CString { let string = value.into(); unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } @@ -83,19 +96,6 @@ 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,