Merge branch 'loops'
This commit is contained in:
		
						commit
						a9abb55287
					
				
							
								
								
									
										18
									
								
								examples/loops.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								examples/loops.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | // Arithmetic, function calls and imports! | ||||||
|  | 
 | ||||||
|  | import std::print; | ||||||
|  | import std::from_str; | ||||||
|  | 
 | ||||||
|  | fn main() -> u32 { | ||||||
|  |   let text = from_str("hello"); | ||||||
|  |   for i in 0 .. 10 { | ||||||
|  |     print(&text) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   let mut num = 0; | ||||||
|  |   while num < 10 { | ||||||
|  |     num = num + 1; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return num; | ||||||
|  | } | ||||||
| @ -440,7 +440,6 @@ impl Builder { | |||||||
|                 } |                 } | ||||||
|                 Instr::GetStructElemPtr(ptr_val, idx) => { |                 Instr::GetStructElemPtr(ptr_val, idx) => { | ||||||
|                     let ptr_ty = ptr_val.get_type(&self)?; |                     let ptr_ty = ptr_val.get_type(&self)?; | ||||||
|                     dbg!(&ptr_ty); |  | ||||||
|                     if let Type::Ptr(ty) = ptr_ty { |                     if let Type::Ptr(ty) = ptr_ty { | ||||||
|                         if let Type::CustomType(val) = *ty { |                         if let Type::CustomType(val) = *ty { | ||||||
|                             match self.type_data(&val).kind { |                             match self.type_data(&val).kind { | ||||||
|  | |||||||
| @ -178,6 +178,8 @@ pub enum BlockLevelStatement { | |||||||
|     }, |     }, | ||||||
|     Expression(Expression), |     Expression(Expression), | ||||||
|     Return(ReturnType, Expression), |     Return(ReturnType, Expression), | ||||||
|  |     ForLoop(String, TokenRange, Expression, Expression, Block), | ||||||
|  |     WhileLoop(Expression, Block), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
|  | |||||||
| @ -155,11 +155,12 @@ impl Parse for PrimaryExpression { | |||||||
|                 } |                 } | ||||||
|                 Token::DecimalValue(v) => { |                 Token::DecimalValue(v) => { | ||||||
|                     stream.next(); // Consume decimal
 |                     stream.next(); // Consume decimal
 | ||||||
|                     if let Some(Token::Dot) = stream.peek() { |                     if let (Some(Token::Dot), Some(Token::DecimalValue(fractional))) = | ||||||
|  |                         (stream.peek(), stream.peek2()) | ||||||
|  |                     { | ||||||
|                         stream.next(); // Consume dot
 |                         stream.next(); // Consume dot
 | ||||||
|                         let Some(Token::DecimalValue(fractional)) = stream.next() else { |                         stream.next(); // Consume fractional
 | ||||||
|                             return Err(stream.expected_err("fractional part")?); | 
 | ||||||
|                         }; |  | ||||||
|                         Expression( |                         Expression( | ||||||
|                             Kind::Literal(Literal::Decimal( |                             Kind::Literal(Literal::Decimal( | ||||||
|                                 format!("{}.{}", v, fractional) |                                 format!("{}.{}", v, fractional) | ||||||
| @ -231,10 +232,10 @@ impl Parse for PrimaryExpression { | |||||||
|                     stream.expect(Token::BracketClose)?; |                     stream.expect(Token::BracketClose)?; | ||||||
|                     Expression(Kind::Array(expressions), stream.get_range().unwrap()) |                     Expression(Kind::Array(expressions), stream.get_range().unwrap()) | ||||||
|                 } |                 } | ||||||
|                 _ => Err(stream.expected_err("expression inner")?)?, |                 _ => Err(stream.expecting_err("expression")?)?, | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             Err(stream.expected_err("expression")?)? |             Err(stream.expecting_err("expression")?)? | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         while let Ok(index) = stream.parse::<ValueIndex>() { |         while let Ok(index) = stream.parse::<ValueIndex>() { | ||||||
| @ -667,6 +668,14 @@ impl Parse for BlockLevelStatement { | |||||||
|                 stream.expect(Token::Semi)?; |                 stream.expect(Token::Semi)?; | ||||||
|                 Stmt::Return(ReturnType::Hard, exp) |                 Stmt::Return(ReturnType::Hard, exp) | ||||||
|             } |             } | ||||||
|  |             Some(Token::For) => { | ||||||
|  |                 let for_stmt = stream.parse::<ForStatement>()?; | ||||||
|  |                 Stmt::ForLoop(for_stmt.0, for_stmt.1, for_stmt.2, for_stmt.3, for_stmt.4) | ||||||
|  |             } | ||||||
|  |             Some(Token::While) => { | ||||||
|  |                 let while_stmt = stream.parse::<WhileStatement>()?; | ||||||
|  |                 Stmt::WhileLoop(while_stmt.0, while_stmt.1) | ||||||
|  |             } | ||||||
|             _ => { |             _ => { | ||||||
|                 if let Ok(SetStatement(ident, expr, range)) = stream.parse() { |                 if let Ok(SetStatement(ident, expr, range)) = stream.parse() { | ||||||
|                     Stmt::Set(ident, expr, range) |                     Stmt::Set(ident, expr, range) | ||||||
| @ -683,6 +692,36 @@ impl Parse for BlockLevelStatement { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct ForStatement(String, TokenRange, Expression, Expression, Block); | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct WhileStatement(pub Expression, pub Block); | ||||||
|  | 
 | ||||||
|  | impl Parse for ForStatement { | ||||||
|  |     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||||
|  |         stream.expect(Token::For)?; | ||||||
|  |         let Some(Token::Identifier(idx)) = stream.next() else { | ||||||
|  |             return Err(stream.expected_err("loop counter")?); | ||||||
|  |         }; | ||||||
|  |         let start_range = stream.get_range().unwrap(); | ||||||
|  |         stream.expect(Token::In)?; | ||||||
|  |         let start = stream.parse()?; | ||||||
|  |         stream.expect(Token::Dot)?; | ||||||
|  |         stream.expect(Token::Dot)?; | ||||||
|  |         let end = stream.parse()?; | ||||||
|  | 
 | ||||||
|  |         Ok(ForStatement(idx, start_range, start, end, stream.parse()?)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Parse for WhileStatement { | ||||||
|  |     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||||
|  |         stream.expect(Token::While)?; | ||||||
|  | 
 | ||||||
|  |         Ok(WhileStatement(stream.parse()?, stream.parse()?)) | ||||||
|  |     } | ||||||
|  | } | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct SetStatement(Expression, Expression, TokenRange); | pub struct SetStatement(Expression, Expression, TokenRange); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ use crate::{ | |||||||
|     ast::{self}, |     ast::{self}, | ||||||
|     mir::{ |     mir::{ | ||||||
|         self, CustomTypeKey, ModuleMap, NamedVariableRef, SourceModuleId, StmtKind, StructField, |         self, CustomTypeKey, ModuleMap, NamedVariableRef, SourceModuleId, StmtKind, StructField, | ||||||
|         StructType, |         StructType, WhileStatement, | ||||||
|     }, |     }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -148,6 +148,72 @@ impl ast::Block { | |||||||
|                 ast::BlockLevelStatement::Return(_, e) => { |                 ast::BlockLevelStatement::Return(_, e) => { | ||||||
|                     (StmtKind::Expression(e.process(module_id)), e.1) |                     (StmtKind::Expression(e.process(module_id)), e.1) | ||||||
|                 } |                 } | ||||||
|  |                 ast::BlockLevelStatement::ForLoop(counter, counter_range, start, end, block) => { | ||||||
|  |                     let counter_var = NamedVariableRef( | ||||||
|  |                         mir::TypeKind::Vague(mir::VagueType::Unknown), | ||||||
|  |                         counter.clone(), | ||||||
|  |                         counter_range.as_meta(module_id), | ||||||
|  |                     ); | ||||||
|  |                     let let_statement = mir::Statement( | ||||||
|  |                         StmtKind::Let(counter_var.clone(), true, start.process(module_id)), | ||||||
|  |                         counter_range.as_meta(module_id), | ||||||
|  |                     ); | ||||||
|  |                     mir_statements.push(let_statement); | ||||||
|  | 
 | ||||||
|  |                     let set_new = mir::Statement( | ||||||
|  |                         StmtKind::Set( | ||||||
|  |                             mir::Expression( | ||||||
|  |                                 mir::ExprKind::Variable(counter_var.clone()), | ||||||
|  |                                 counter_range.as_meta(module_id), | ||||||
|  |                             ), | ||||||
|  |                             mir::Expression( | ||||||
|  |                                 mir::ExprKind::BinOp( | ||||||
|  |                                     mir::BinaryOperator::Add, | ||||||
|  |                                     Box::new(mir::Expression( | ||||||
|  |                                         mir::ExprKind::Variable(counter_var.clone()), | ||||||
|  |                                         counter_range.as_meta(module_id), | ||||||
|  |                                     )), | ||||||
|  |                                     Box::new(mir::Expression( | ||||||
|  |                                         mir::ExprKind::Literal(mir::Literal::Vague( | ||||||
|  |                                             mir::VagueLiteral::Number(1), | ||||||
|  |                                         )), | ||||||
|  |                                         counter_range.as_meta(module_id), | ||||||
|  |                                     )), | ||||||
|  |                                 ), | ||||||
|  |                                 counter_range.as_meta(module_id), | ||||||
|  |                             ), | ||||||
|  |                         ), | ||||||
|  |                         counter_range.as_meta(module_id), | ||||||
|  |                     ); | ||||||
|  |                     let mut block = block.into_mir(module_id); | ||||||
|  |                     block.statements.insert(0, set_new); | ||||||
|  |                     ( | ||||||
|  |                         StmtKind::While(WhileStatement { | ||||||
|  |                             condition: mir::Expression( | ||||||
|  |                                 mir::ExprKind::BinOp( | ||||||
|  |                                     mir::BinaryOperator::Cmp(mir::CmpOperator::LT), | ||||||
|  |                                     Box::new(mir::Expression( | ||||||
|  |                                         mir::ExprKind::Variable(counter_var), | ||||||
|  |                                         counter_range.as_meta(module_id), | ||||||
|  |                                     )), | ||||||
|  |                                     Box::new(end.process(module_id)), | ||||||
|  |                                 ), | ||||||
|  |                                 counter_range.as_meta(module_id), | ||||||
|  |                             ), | ||||||
|  |                             block, | ||||||
|  |                             meta: self.2.as_meta(module_id), | ||||||
|  |                         }), | ||||||
|  |                         self.2, | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  |                 ast::BlockLevelStatement::WhileLoop(expression, block) => ( | ||||||
|  |                     StmtKind::While(WhileStatement { | ||||||
|  |                         condition: expression.process(module_id), | ||||||
|  |                         block: block.into_mir(module_id), | ||||||
|  |                         meta: self.2.as_meta(module_id), | ||||||
|  |                     }), | ||||||
|  |                     self.2, | ||||||
|  |                 ), | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             mir_statements.push(mir::Statement(kind, range.as_meta(module_id))); |             mir_statements.push(mir::Statement(kind, range.as_meta(module_id))); | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ use crate::{ | |||||||
|     mir::{ |     mir::{ | ||||||
|         self, implement::TypeCategory, CustomTypeKey, Metadata, NamedVariableRef, SourceModuleId, |         self, implement::TypeCategory, CustomTypeKey, Metadata, NamedVariableRef, SourceModuleId, | ||||||
|         StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, VagueLiteral, |         StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, VagueLiteral, | ||||||
|  |         WhileStatement, | ||||||
|     }, |     }, | ||||||
|     util::try_all, |     util::try_all, | ||||||
| }; | }; | ||||||
| @ -598,6 +599,54 @@ impl mir::Statement { | |||||||
|             } |             } | ||||||
|             mir::StmtKind::Import(_) => todo!(), |             mir::StmtKind::Import(_) => todo!(), | ||||||
|             mir::StmtKind::Expression(expression) => expression.codegen(scope, state), |             mir::StmtKind::Expression(expression) => expression.codegen(scope, state), | ||||||
|  |             mir::StmtKind::While(WhileStatement { | ||||||
|  |                 condition, block, .. | ||||||
|  |             }) => { | ||||||
|  |                 let condition_block = scope.function.ir.block("condition_block"); | ||||||
|  |                 let condition_true_block = scope.function.ir.block("condition_true"); | ||||||
|  |                 let condition_failed_block = scope.function.ir.block("condition_failed"); | ||||||
|  | 
 | ||||||
|  |                 scope | ||||||
|  |                     .block | ||||||
|  |                     .terminate(Term::Br(condition_block.value())) | ||||||
|  |                     .unwrap(); | ||||||
|  |                 let mut condition_scope = scope.with_block(condition_block); | ||||||
|  |                 let condition_res = condition.codegen(&mut condition_scope, state)?.unwrap(); | ||||||
|  |                 let true_instr = condition_scope | ||||||
|  |                     .block | ||||||
|  |                     .build(Instr::Constant(ConstValue::Bool(true))) | ||||||
|  |                     .unwrap(); | ||||||
|  |                 let check = condition_scope | ||||||
|  |                     .block | ||||||
|  |                     .build(Instr::ICmp( | ||||||
|  |                         CmpPredicate::EQ, | ||||||
|  |                         condition_res.instr(), | ||||||
|  |                         true_instr, | ||||||
|  |                     )) | ||||||
|  |                     .unwrap(); | ||||||
|  | 
 | ||||||
|  |                 condition_scope | ||||||
|  |                     .block | ||||||
|  |                     .terminate(Term::CondBr( | ||||||
|  |                         check, | ||||||
|  |                         condition_true_block.value(), | ||||||
|  |                         condition_failed_block.value(), | ||||||
|  |                     )) | ||||||
|  |                     .unwrap(); | ||||||
|  | 
 | ||||||
|  |                 let mut condition_true_scope = scope.with_block(condition_true_block); | ||||||
|  |                 block.codegen(&mut condition_true_scope, state)?; | ||||||
|  | 
 | ||||||
|  |                 condition_true_scope | ||||||
|  |                     .block | ||||||
|  |                     .terminate(Term::Br(condition_scope.block.value())) | ||||||
|  |                     // Can hard return inside the condition_true_scope
 | ||||||
|  |                     .ok(); | ||||||
|  | 
 | ||||||
|  |                 scope.swap_block(condition_failed_block); | ||||||
|  | 
 | ||||||
|  |                 Ok(None) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1000,7 +1049,6 @@ impl mir::Expression { | |||||||
|                 let TypeKind::CodegenPtr(inner) = &struct_val.1 else { |                 let TypeKind::CodegenPtr(inner) = &struct_val.1 else { | ||||||
|                     panic!("tried accessing non-pointer"); |                     panic!("tried accessing non-pointer"); | ||||||
|                 }; |                 }; | ||||||
|                 dbg!(&inner); |  | ||||||
|                 let TypeKind::CustomType(key) = *inner.clone() else { |                 let TypeKind::CustomType(key) = *inner.clone() else { | ||||||
|                     panic!("tried accessing non-custom-type"); |                     panic!("tried accessing non-custom-type"); | ||||||
|                 }; |                 }; | ||||||
|  | |||||||
| @ -42,6 +42,12 @@ pub enum Token { | |||||||
|     Extern, |     Extern, | ||||||
|     /// `struct`
 |     /// `struct`
 | ||||||
|     Struct, |     Struct, | ||||||
|  |     /// `while`
 | ||||||
|  |     While, | ||||||
|  |     /// `for`
 | ||||||
|  |     For, | ||||||
|  |     /// `In`
 | ||||||
|  |     In, | ||||||
| 
 | 
 | ||||||
|     // Symbols
 |     // Symbols
 | ||||||
|     /// `;`
 |     /// `;`
 | ||||||
| @ -136,6 +142,9 @@ impl ToString for Token { | |||||||
|             Token::Extern => String::from("extern"), |             Token::Extern => String::from("extern"), | ||||||
|             Token::Struct => String::from("struct"), |             Token::Struct => String::from("struct"), | ||||||
|             Token::AsKeyword => String::from("as"), |             Token::AsKeyword => String::from("as"), | ||||||
|  |             Token::For => String::from("for"), | ||||||
|  |             Token::In => String::from("in"), | ||||||
|  |             Token::While => String::from("while"), | ||||||
|             Token::Semi => String::from(';'), |             Token::Semi => String::from(';'), | ||||||
|             Token::Equals => String::from('='), |             Token::Equals => String::from('='), | ||||||
|             Token::Colon => String::from(':'), |             Token::Colon => String::from(':'), | ||||||
| @ -322,6 +331,9 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error | |||||||
|                     "pub" => Token::PubKeyword, |                     "pub" => Token::PubKeyword, | ||||||
|                     "struct" => Token::Struct, |                     "struct" => Token::Struct, | ||||||
|                     "as" => Token::AsKeyword, |                     "as" => Token::AsKeyword, | ||||||
|  |                     "for" => Token::For, | ||||||
|  |                     "while" => Token::While, | ||||||
|  |                     "in" => Token::In, | ||||||
|                     _ => Token::Identifier(value), |                     _ => Token::Identifier(value), | ||||||
|                 }; |                 }; | ||||||
|                 variant |                 variant | ||||||
|  | |||||||
| @ -112,6 +112,9 @@ pub fn compile_module<'map>( | |||||||
|         is_main, |         is_main, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     #[cfg(debug_assertions)] | ||||||
|  |     dbg!(&ast_module); | ||||||
|  | 
 | ||||||
|     Ok(ast_module.process(module_id)) |     Ok(ast_module.process(module_id)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -147,7 +147,7 @@ impl Display for Statement { | |||||||
| impl Display for StmtKind { | impl Display for StmtKind { | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|         match self { |         match self { | ||||||
|             Self::Let(var, mutable, block) => { |             StmtKind::Let(var, mutable, block) => { | ||||||
|                 write!( |                 write!( | ||||||
|                     f, |                     f, | ||||||
|                     "let{} {} = {}", |                     "let{} {} = {}", | ||||||
| @ -156,9 +156,17 @@ impl Display for StmtKind { | |||||||
|                     block |                     block | ||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
|             Self::Set(var, expr) => write!(f, "{} = {}", var, expr), |             StmtKind::Set(var, expr) => write!(f, "{} = {}", var, expr), | ||||||
|             Self::Import(n) => write!(f, "import {}", n), |             StmtKind::Import(n) => write!(f, "import {}", n), | ||||||
|             Self::Expression(exp) => Display::fmt(exp, f), |             StmtKind::Expression(exp) => Display::fmt(exp, f), | ||||||
|  | 
 | ||||||
|  |             StmtKind::While(while_statement) => { | ||||||
|  |                 write!( | ||||||
|  |                     f, | ||||||
|  |                     "while {} {}", | ||||||
|  |                     while_statement.condition, while_statement.block, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ pub enum ReturnTypeOther { | |||||||
|     NoBlockReturn(Metadata), |     NoBlockReturn(Metadata), | ||||||
|     IndexingNonArray(Metadata), |     IndexingNonArray(Metadata), | ||||||
|     DerefNonBorrow(Metadata), |     DerefNonBorrow(Metadata), | ||||||
|  |     Loop, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl TypeKind { | impl TypeKind { | ||||||
| @ -374,6 +375,7 @@ impl Statement { | |||||||
|             ), |             ), | ||||||
|             Import(_) => todo!(), |             Import(_) => todo!(), | ||||||
|             Expression(expression) => expression.return_type(refs, mod_id), |             Expression(expression) => expression.return_type(refs, mod_id), | ||||||
|  |             While(_) => Err(ReturnTypeOther::Loop), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -383,6 +385,7 @@ impl Statement { | |||||||
|             StmtKind::Set(_, _) => None, |             StmtKind::Set(_, _) => None, | ||||||
|             StmtKind::Import(_) => None, |             StmtKind::Import(_) => None, | ||||||
|             StmtKind::Expression(expr) => expr.backing_var(), |             StmtKind::Expression(expr) => expr.backing_var(), | ||||||
|  |             StmtKind::While(_) => None, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -188,7 +188,6 @@ impl<'map> Pass for LinkerPass<'map> { | |||||||
|                 .borrow_mut(); |                 .borrow_mut(); | ||||||
| 
 | 
 | ||||||
|                 let func_name = unsafe { path.get_unchecked(1) }; |                 let func_name = unsafe { path.get_unchecked(1) }; | ||||||
|                 let imported_mod_name = imported.name.clone(); |  | ||||||
| 
 | 
 | ||||||
|                 let Some(func) = imported.functions.iter_mut().find(|f| f.name == *func_name) |                 let Some(func) = imported.functions.iter_mut().find(|f| f.name == *func_name) | ||||||
|                 else { |                 else { | ||||||
|  | |||||||
| @ -241,7 +241,7 @@ pub enum ReturnKind { | |||||||
|     Soft, |     Soft, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug, Clone)] | ||||||
| pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata); | pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata); | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||||
| @ -338,6 +338,14 @@ pub enum StmtKind { | |||||||
|     Set(Expression, Expression), |     Set(Expression, Expression), | ||||||
|     Import(Import), |     Import(Import), | ||||||
|     Expression(Expression), |     Expression(Expression), | ||||||
|  |     While(WhileStatement), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct WhileStatement { | ||||||
|  |     pub condition: Expression, | ||||||
|  |     pub block: Block, | ||||||
|  |     pub meta: Metadata, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
|  | |||||||
| @ -390,10 +390,14 @@ impl Statement { | |||||||
|             StmtKind::Set(_, expression) => { |             StmtKind::Set(_, expression) => { | ||||||
|                 expression.pass(pass, state, scope, mod_id)?; |                 expression.pass(pass, state, scope, mod_id)?; | ||||||
|             } |             } | ||||||
|             StmtKind::Import(_) => {} // Never exists at this stage
 |             StmtKind::Import(_) => {} | ||||||
|             StmtKind::Expression(expression) => { |             StmtKind::Expression(expression) => { | ||||||
|                 expression.pass(pass, state, scope, mod_id)?; |                 expression.pass(pass, state, scope, mod_id)?; | ||||||
|             } |             } | ||||||
|  |             StmtKind::While(while_statement) => { | ||||||
|  |                 while_statement.condition.pass(pass, state, scope, mod_id)?; | ||||||
|  |                 while_statement.block.pass(pass, state, scope, mod_id)?; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         pass.stmt(self, PassState::from(state, scope, Some(mod_id)))?; |         pass.stmt(self, PassState::from(state, scope, Some(mod_id)))?; | ||||||
| @ -412,8 +416,9 @@ impl Statement { | |||||||
|                     .ok(); |                     .ok(); | ||||||
|             } |             } | ||||||
|             StmtKind::Set(_, _) => {} |             StmtKind::Set(_, _) => {} | ||||||
|             StmtKind::Import(_) => {} // Never exists at this stage
 |             StmtKind::Import(_) => {} | ||||||
|             StmtKind::Expression(_) => {} |             StmtKind::Expression(_) => {} | ||||||
|  |             StmtKind::While(_) => {} | ||||||
|         }; |         }; | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -323,7 +323,7 @@ impl Block { | |||||||
| 
 | 
 | ||||||
|                     None |                     None | ||||||
|                 } |                 } | ||||||
|                 StmtKind::Import(_) => todo!(), // TODO
 |                 StmtKind::Import(_) => todo!(), | ||||||
|                 StmtKind::Expression(expression) => { |                 StmtKind::Expression(expression) => { | ||||||
|                     let res = expression.typecheck(&mut state, &typerefs, None); |                     let res = expression.typecheck(&mut state, &typerefs, None); | ||||||
|                     state.or_else(res, TypeKind::Void, expression.1); |                     state.or_else(res, TypeKind::Void, expression.1); | ||||||
| @ -335,6 +335,24 @@ impl Block { | |||||||
|                         None |                         None | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |                 StmtKind::While(WhileStatement { | ||||||
|  |                     condition, | ||||||
|  |                     block, | ||||||
|  |                     meta, | ||||||
|  |                 }) => { | ||||||
|  |                     let condition_ty = | ||||||
|  |                         condition.typecheck(&mut state, typerefs, Some(&TypeKind::Bool))?; | ||||||
|  |                     if condition_ty.assert_known(typerefs, &state)? != TypeKind::Bool { | ||||||
|  |                         state.note_errors( | ||||||
|  |                             &vec![ErrorKind::TypesIncompatible(condition_ty, TypeKind::Bool)], | ||||||
|  |                             *meta, | ||||||
|  |                         ); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     block.typecheck(&mut state, typerefs, None)?; | ||||||
|  | 
 | ||||||
|  |                     None | ||||||
|  |                 } | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             if let Some((ReturnKind::Hard, _)) = ret { |             if let Some((ReturnKind::Hard, _)) = ret { | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ use super::{ | |||||||
|     IfExpression, Module, ReturnKind, StmtKind, |     IfExpression, Module, ReturnKind, StmtKind, | ||||||
|     TypeKind::*, |     TypeKind::*, | ||||||
|     VagueType::*, |     VagueType::*, | ||||||
|  |     WhileStatement, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Struct used to implement Type Inference, where an intermediary
 | /// Struct used to implement Type Inference, where an intermediary
 | ||||||
| @ -126,6 +127,12 @@ impl Block { | |||||||
|                     let expr_res = expr.infer_types(&mut state, &inner_refs); |                     let expr_res = expr.infer_types(&mut state, &inner_refs); | ||||||
|                     state.ok(expr_res, expr.1); |                     state.ok(expr_res, expr.1); | ||||||
|                 } |                 } | ||||||
|  |                 StmtKind::While(WhileStatement { | ||||||
|  |                     condition, block, .. | ||||||
|  |                 }) => { | ||||||
|  |                     condition.infer_types(&mut state, &inner_refs)?; | ||||||
|  |                     block.infer_types(&mut state, &inner_refs)?; | ||||||
|  |                 } | ||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -120,3 +120,7 @@ fn strings_compiles_well() { | |||||||
| fn struct_compiles_well() { | fn struct_compiles_well() { | ||||||
|     test(include_str!("../../examples/struct.reid"), "test", 17); |     test(include_str!("../../examples/struct.reid"), "test", 17); | ||||||
| } | } | ||||||
|  | #[test] | ||||||
|  | fn loops_compiles_well() { | ||||||
|  |     test(include_str!("../../examples/loops.reid"), "test", 10); | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user