Add necessary codegen for easy.reid
This commit is contained in:
		
							parent
							
								
									e00d9afc7b
								
							
						
					
					
						commit
						6448b0c438
					
				| @ -362,7 +362,7 @@ impl Parse for Block { | ||||
|                 statements.push(BlockLevelStatement::Expression(e)); | ||||
|             } | ||||
|             let statement = stream.parse()?; | ||||
|             if let BlockLevelStatement::Return((r_type, e)) = &statement { | ||||
|             if let BlockLevelStatement::Return(r_type, e) = &statement { | ||||
|                 match r_type { | ||||
|                     ReturnType::Hard => { | ||||
|                         return_stmt = Some((*r_type, e.clone())); | ||||
| @ -387,7 +387,7 @@ pub enum BlockLevelStatement { | ||||
|     Let(LetStatement), | ||||
|     Import(ImportStatement), | ||||
|     Expression(Expression), | ||||
|     Return((ReturnType, Expression)), | ||||
|     Return(ReturnType, Expression), | ||||
| } | ||||
| 
 | ||||
| impl Parse for BlockLevelStatement { | ||||
| @ -400,14 +400,14 @@ impl Parse for BlockLevelStatement { | ||||
|                 stream.next(); | ||||
|                 let exp = stream.parse()?; | ||||
|                 stream.expect(Token::Semi)?; | ||||
|                 Stmt::Return((ReturnType::Hard, exp)) | ||||
|                 Stmt::Return(ReturnType::Hard, exp) | ||||
|             } | ||||
|             _ => { | ||||
|                 if let Ok(e) = stream.parse() { | ||||
|                     if stream.expect(Token::Semi).is_ok() { | ||||
|                         Stmt::Expression(e) | ||||
|                     } else { | ||||
|                         Stmt::Return((ReturnType::Soft, e)) | ||||
|                         Stmt::Return(ReturnType::Soft, e) | ||||
|                     } | ||||
|                 } else { | ||||
|                     Err(stream.expected_err("expression")?)? | ||||
|  | ||||
| @ -12,6 +12,50 @@ fn into_cstring<T: Into<String>>(value: T) -> CString { | ||||
|     unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } | ||||
| } | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug)] | ||||
| pub enum Error { | ||||
|     #[error("Type mismatch: {0:?} vs {1:?}")] | ||||
|     TypeMismatch(IRType, IRType), | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, Eq, PartialEq)] | ||||
| pub enum IRType { | ||||
|     I32, | ||||
| } | ||||
| 
 | ||||
| impl IRType { | ||||
|     fn in_context(&self, context: &mut IRContext) -> *mut LLVMType { | ||||
|         use IRType::*; | ||||
|         unsafe { | ||||
|             return match self { | ||||
|                 I32 => LLVMInt32TypeInContext(context.context), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct IRValue(pub IRType, *mut LLVMValue); | ||||
| 
 | ||||
| impl IRValue { | ||||
|     pub fn from_literal(literal: &ast::Literal, block: &mut IRBlock) -> Self { | ||||
|         use ast::Literal; | ||||
|         match literal { | ||||
|             Literal::I32(v) => { | ||||
|                 let ir_type = IRType::I32; | ||||
|                 unsafe { | ||||
|                     let ir_value = LLVMConstInt( | ||||
|                         ir_type.in_context(block.function.module.context), | ||||
|                         mem::transmute(*v as i64), | ||||
|                         1, | ||||
|                     ); | ||||
|                     return IRValue(ir_type, ir_value); | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct IRContext { | ||||
|     context: *mut LLVMContext, | ||||
|     builder: *mut LLVMBuilder, | ||||
| @ -71,22 +115,6 @@ impl<'a> Drop for IRModule<'a> { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub enum IRType { | ||||
|     I32, | ||||
| } | ||||
| 
 | ||||
| impl IRType { | ||||
|     fn in_context(&self, context: &mut IRContext) -> *mut LLVMType { | ||||
|         use IRType::*; | ||||
|         unsafe { | ||||
|             return match self { | ||||
|                 I32 => LLVMInt32TypeInContext(context.context), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct IRFunction<'a, 'b> { | ||||
|     module: &'b mut IRModule<'a>, | ||||
|     /// The actual function
 | ||||
| @ -132,10 +160,54 @@ impl<'a, 'b, 'c> IRBlock<'a, 'b, 'c> { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn add( | ||||
|         &mut self, | ||||
|         IRValue(lhs_t, lhs_v): IRValue, | ||||
|         IRValue(rhs_t, rhs_v): IRValue, | ||||
|     ) -> Result<IRValue, Error> { | ||||
|         unsafe { | ||||
|             if lhs_t == rhs_t { | ||||
|                 Ok(IRValue( | ||||
|                     lhs_t, | ||||
|                     LLVMBuildAdd( | ||||
|                         self.function.module.context.builder, | ||||
|                         lhs_v, | ||||
|                         rhs_v, | ||||
|                         c"tmpadd".as_ptr(), | ||||
|                     ), | ||||
|                 )) | ||||
|             } else { | ||||
|                 Err(Error::TypeMismatch(lhs_t, rhs_t)) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn mult( | ||||
|         &mut self, | ||||
|         IRValue(lhs_t, lhs_v): IRValue, | ||||
|         IRValue(rhs_t, rhs_v): IRValue, | ||||
|     ) -> Result<IRValue, Error> { | ||||
|         unsafe { | ||||
|             if lhs_t == rhs_t { | ||||
|                 Ok(IRValue( | ||||
|                     lhs_t, | ||||
|                     LLVMBuildMul( | ||||
|                         self.function.module.context.builder, | ||||
|                         lhs_v, | ||||
|                         rhs_v, | ||||
|                         c"tmpadd".as_ptr(), | ||||
|                     ), | ||||
|                 )) | ||||
|             } else { | ||||
|                 Err(Error::TypeMismatch(lhs_t, rhs_t)) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_return(self, value: Option<IRValue>) { | ||||
|         unsafe { | ||||
|             if let Some(value) = value { | ||||
|                 LLVMBuildRet(self.function.module.context.builder, value.ir_value); | ||||
|             if let Some(IRValue(_, value)) = value { | ||||
|                 LLVMBuildRet(self.function.module.context.builder, value); | ||||
|             } else { | ||||
|                 LLVMBuildRetVoid(self.function.module.context.builder); | ||||
|             } | ||||
| @ -150,28 +222,3 @@ impl<'a, 'b, 'c> Drop for IRBlock<'a, 'b, 'c> { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct IRValue { | ||||
|     pub ir_type: IRType, | ||||
|     ir_value: *mut LLVMValue, | ||||
| } | ||||
| 
 | ||||
| impl IRValue { | ||||
|     pub fn from_literal(literal: &ast::Literal, block: &mut IRBlock) -> Self { | ||||
|         use ast::Literal; | ||||
|         match literal { | ||||
|             Literal::I32(v) => { | ||||
|                 let ir_type = IRType::I32; | ||||
|                 unsafe { | ||||
|                     let ir_value = LLVMConstInt( | ||||
|                         ir_type.in_context(block.function.module.context), | ||||
|                         mem::transmute(*v as i64), | ||||
|                         1, | ||||
|                     ); | ||||
|                     return IRValue { ir_type, ir_value }; | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -2,16 +2,16 @@ mod llvm; | ||||
| 
 | ||||
| use std::collections::HashMap; | ||||
| 
 | ||||
| use llvm::{IRBlock, IRContext, IRFunction, IRModule, IRValue}; | ||||
| use llvm::{Error, IRBlock, IRContext, IRFunction, IRModule, IRValue}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     ast::{Block, Expression, ExpressionKind, FunctionDefinition}, | ||||
|     ast::{ | ||||
|         BinaryOperator, Block, BlockLevelStatement, Expression, ExpressionKind, FunctionDefinition, | ||||
|         LetStatement, ReturnType, | ||||
|     }, | ||||
|     TopLevelStatement, | ||||
| }; | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug)] | ||||
| pub enum Error {} | ||||
| 
 | ||||
| pub fn form_context() -> IRContext { | ||||
|     IRContext::new() | ||||
| } | ||||
| @ -49,6 +49,10 @@ impl FunctionDefinition { | ||||
| 
 | ||||
| impl Block { | ||||
|     fn codegen(&self, mut scope: Scope) { | ||||
|         for statement in &self.0 { | ||||
|             statement.codegen(&mut scope); | ||||
|         } | ||||
| 
 | ||||
|         if let Some((_, return_exp)) = &self.1 { | ||||
|             let value = return_exp.codegen(&mut scope); | ||||
|             scope.block.add_return(Some(value)); | ||||
| @ -56,6 +60,23 @@ impl Block { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl BlockLevelStatement { | ||||
|     fn codegen(&self, scope: &mut Scope) { | ||||
|         use BlockLevelStatement::*; | ||||
|         match self { | ||||
|             Expression(exp) | Return(ReturnType::Soft, exp) => { | ||||
|                 exp.codegen(scope); | ||||
|             } | ||||
|             Let(LetStatement(name, exp, _)) => { | ||||
|                 let val = exp.codegen(scope); | ||||
|                 scope.data.insert(name, val); | ||||
|             } | ||||
|             Return(ReturnType::Hard, _) => panic!("hard returns here should not be possible.."), | ||||
|             Import(_) => panic!("block level import not supported"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Expression { | ||||
|     fn codegen(&self, scope: &mut Scope) -> IRValue { | ||||
|         let Expression(kind, _) = self; | ||||
| @ -64,6 +85,16 @@ impl Expression { | ||||
|         match kind { | ||||
|             Literal(lit) => IRValue::from_literal(lit, &mut scope.block), | ||||
|             VariableName(v) => scope.data.fetch(v), | ||||
|             Binop(op, lhs, rhs) => { | ||||
|                 let lhs = lhs.codegen(scope); | ||||
|                 let rhs = rhs.codegen(scope); | ||||
|                 use crate::ast::BinaryOperator::*; | ||||
|                 match op { | ||||
|                     Add => scope.block.add(lhs, rhs).unwrap(), | ||||
|                     Mult => scope.block.mult(lhs, rhs).unwrap(), | ||||
|                     _ => panic!("operator not supported: {:?}", op), | ||||
|                 } | ||||
|             } | ||||
|             _ => panic!("expression type not supported"), | ||||
|         } | ||||
|     } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user