From 431aae0b0d949b831e59ab9d23e5db20810f4a20 Mon Sep 17 00:00:00 2001 From: sofia Date: Wed, 23 Jul 2025 19:52:46 +0300 Subject: [PATCH 1/7] Add lexing to loops --- examples/loops.reid | 15 +++++++++++++++ reid/src/ast/mod.rs | 2 ++ reid/src/ast/parse.rs | 4 ++-- reid/src/ast/process.rs | 4 ++++ reid/src/lexer.rs | 8 ++++++++ 5 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 examples/loops.reid diff --git a/examples/loops.reid b/examples/loops.reid new file mode 100644 index 0000000..8f776e9 --- /dev/null +++ b/examples/loops.reid @@ -0,0 +1,15 @@ +// Arithmetic, function calls and imports! + + +fn main() -> u32 { + for i in [0, 1, 2, 3, 4, 5, 6, 7, 9, 10] { + print("hello") + } + + let mut num = 0; + while num < 10 { + num = num + 1; + } + + return num; +} diff --git a/reid/src/ast/mod.rs b/reid/src/ast/mod.rs index ff4ab7a..daff3ac 100644 --- a/reid/src/ast/mod.rs +++ b/reid/src/ast/mod.rs @@ -178,6 +178,8 @@ pub enum BlockLevelStatement { }, Expression(Expression), Return(ReturnType, Expression), + ForLoop(String, Expression, Block), + WhileLoop(Expression, Block), } #[derive(Debug, Clone)] diff --git a/reid/src/ast/parse.rs b/reid/src/ast/parse.rs index 4141abc..6e9a3cb 100644 --- a/reid/src/ast/parse.rs +++ b/reid/src/ast/parse.rs @@ -231,10 +231,10 @@ impl Parse for PrimaryExpression { stream.expect(Token::BracketClose)?; Expression(Kind::Array(expressions), stream.get_range().unwrap()) } - _ => Err(stream.expected_err("expression inner")?)?, + _ => Err(stream.expecting_err("expression")?)?, } } else { - Err(stream.expected_err("expression")?)? + Err(stream.expecting_err("expression")?)? }; while let Ok(index) = stream.parse::() { diff --git a/reid/src/ast/process.rs b/reid/src/ast/process.rs index 8ebd252..ad321e8 100644 --- a/reid/src/ast/process.rs +++ b/reid/src/ast/process.rs @@ -148,6 +148,10 @@ impl ast::Block { ast::BlockLevelStatement::Return(_, e) => { (StmtKind::Expression(e.process(module_id)), e.1) } + ast::BlockLevelStatement::ForLoop(expression, expression1, block) => { + todo!() + } + ast::BlockLevelStatement::WhileLoop(expression, block) => todo!(), }; mir_statements.push(mir::Statement(kind, range.as_meta(module_id))); diff --git a/reid/src/lexer.rs b/reid/src/lexer.rs index 4032f4c..e6f19d8 100644 --- a/reid/src/lexer.rs +++ b/reid/src/lexer.rs @@ -42,6 +42,10 @@ pub enum Token { Extern, /// `struct` Struct, + /// `while` + While, + /// `for` + For, // Symbols /// `;` @@ -136,6 +140,8 @@ impl ToString for Token { Token::Extern => String::from("extern"), Token::Struct => String::from("struct"), Token::AsKeyword => String::from("as"), + Token::For => String::from("for"), + Token::While => String::from("while"), Token::Semi => String::from(';'), Token::Equals => String::from('='), Token::Colon => String::from(':'), @@ -322,6 +328,8 @@ pub fn tokenize>(to_tokenize: T) -> Result, Error "pub" => Token::PubKeyword, "struct" => Token::Struct, "as" => Token::AsKeyword, + "for" => Token::For, + "while" => Token::While, _ => Token::Identifier(value), }; variant From ef4964ed867fc8a99c97ed6d9c7e40cc3c50db4b Mon Sep 17 00:00:00 2001 From: sofia Date: Wed, 23 Jul 2025 20:13:58 +0300 Subject: [PATCH 2/7] Add parsing for for/while loops --- examples/loops.reid | 2 +- reid/src/ast/mod.rs | 2 +- reid/src/ast/parse.rs | 36 ++++++++++++++++++++++++++++++++++++ reid/src/ast/process.rs | 2 +- reid/src/lexer.rs | 12 ++++++++++++ reid/src/lib.rs | 3 +++ reid/src/mir/linker.rs | 1 - 7 files changed, 54 insertions(+), 4 deletions(-) diff --git a/examples/loops.reid b/examples/loops.reid index 8f776e9..8d66fe6 100644 --- a/examples/loops.reid +++ b/examples/loops.reid @@ -2,7 +2,7 @@ fn main() -> u32 { - for i in [0, 1, 2, 3, 4, 5, 6, 7, 9, 10] { + for i in 0 to 10 { print("hello") } diff --git a/reid/src/ast/mod.rs b/reid/src/ast/mod.rs index daff3ac..038e4b9 100644 --- a/reid/src/ast/mod.rs +++ b/reid/src/ast/mod.rs @@ -178,7 +178,7 @@ pub enum BlockLevelStatement { }, Expression(Expression), Return(ReturnType, Expression), - ForLoop(String, Expression, Block), + ForLoop(String, Expression, Expression, Block), WhileLoop(Expression, Block), } diff --git a/reid/src/ast/parse.rs b/reid/src/ast/parse.rs index 6e9a3cb..96fe0b6 100644 --- a/reid/src/ast/parse.rs +++ b/reid/src/ast/parse.rs @@ -667,6 +667,14 @@ impl Parse for BlockLevelStatement { stream.expect(Token::Semi)?; Stmt::Return(ReturnType::Hard, exp) } + Some(Token::For) => { + let for_stmt = stream.parse::()?; + Stmt::ForLoop(for_stmt.0, for_stmt.1, for_stmt.2, for_stmt.3) + } + Some(Token::While) => { + let while_stmt = stream.parse::()?; + Stmt::WhileLoop(while_stmt.0, while_stmt.1) + } _ => { if let Ok(SetStatement(ident, expr, range)) = stream.parse() { Stmt::Set(ident, expr, range) @@ -683,6 +691,34 @@ impl Parse for BlockLevelStatement { } } +#[derive(Debug)] +pub struct ForStatement(String, Expression, Expression, Block); + +#[derive(Debug)] +pub struct WhileStatement(Expression, Block); + +impl Parse for ForStatement { + fn parse(mut stream: TokenStream) -> Result { + stream.expect(Token::For)?; + let Some(Token::Identifier(idx)) = stream.next() else { + return Err(stream.expected_err("loop counter")?); + }; + stream.expect(Token::In)?; + let start = stream.parse()?; + stream.expect(Token::To)?; + let end = stream.parse()?; + + Ok(ForStatement(idx, start, end, stream.parse()?)) + } +} + +impl Parse for WhileStatement { + fn parse(mut stream: TokenStream) -> Result { + stream.expect(Token::While)?; + + Ok(WhileStatement(stream.parse()?, stream.parse()?)) + } +} #[derive(Debug)] pub struct SetStatement(Expression, Expression, TokenRange); diff --git a/reid/src/ast/process.rs b/reid/src/ast/process.rs index ad321e8..b9d9317 100644 --- a/reid/src/ast/process.rs +++ b/reid/src/ast/process.rs @@ -148,7 +148,7 @@ impl ast::Block { ast::BlockLevelStatement::Return(_, e) => { (StmtKind::Expression(e.process(module_id)), e.1) } - ast::BlockLevelStatement::ForLoop(expression, expression1, block) => { + ast::BlockLevelStatement::ForLoop(counter, start, end, block) => { todo!() } ast::BlockLevelStatement::WhileLoop(expression, block) => todo!(), diff --git a/reid/src/lexer.rs b/reid/src/lexer.rs index e6f19d8..176ef92 100644 --- a/reid/src/lexer.rs +++ b/reid/src/lexer.rs @@ -46,6 +46,12 @@ pub enum Token { While, /// `for` For, + /// `from` + From, + /// `to` + To, + /// `to` + In, // Symbols /// `;` @@ -141,6 +147,9 @@ impl ToString for Token { Token::Struct => String::from("struct"), Token::AsKeyword => String::from("as"), Token::For => String::from("for"), + Token::From => String::from("from"), + Token::In => String::from("in"), + Token::To => String::from("to"), Token::While => String::from("while"), Token::Semi => String::from(';'), Token::Equals => String::from('='), @@ -330,6 +339,9 @@ pub fn tokenize>(to_tokenize: T) -> Result, Error "as" => Token::AsKeyword, "for" => Token::For, "while" => Token::While, + "in" => Token::In, + "from" => Token::From, + "to" => Token::To, _ => Token::Identifier(value), }; variant diff --git a/reid/src/lib.rs b/reid/src/lib.rs index 58c30ec..81e07fa 100644 --- a/reid/src/lib.rs +++ b/reid/src/lib.rs @@ -112,6 +112,9 @@ pub fn compile_module<'map>( is_main, }; + #[cfg(debug_assertions)] + dbg!(&ast_module); + Ok(ast_module.process(module_id)) } diff --git a/reid/src/mir/linker.rs b/reid/src/mir/linker.rs index 2d9b249..e404c67 100644 --- a/reid/src/mir/linker.rs +++ b/reid/src/mir/linker.rs @@ -188,7 +188,6 @@ impl<'map> Pass for LinkerPass<'map> { .borrow_mut(); 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) else { From 1a5e3ef1d9644bce53191d5b630f2097ce209deb Mon Sep 17 00:00:00 2001 From: sofia Date: Wed, 23 Jul 2025 20:29:13 +0300 Subject: [PATCH 3/7] Add loops ast -> mir --- reid/src/ast/mod.rs | 2 +- reid/src/ast/parse.rs | 7 ++++--- reid/src/ast/process.rs | 30 ++++++++++++++++++++++++------ reid/src/codegen.rs | 2 ++ reid/src/mir/fmt.rs | 25 +++++++++++++++++++++---- reid/src/mir/implement.rs | 5 +++++ reid/src/mir/mod.rs | 18 ++++++++++++++++++ reid/src/mir/pass.rs | 15 +++++++++++++-- reid/src/mir/typecheck.rs | 4 +++- reid/src/mir/typeinference.rs | 2 ++ 10 files changed, 93 insertions(+), 17 deletions(-) diff --git a/reid/src/ast/mod.rs b/reid/src/ast/mod.rs index 038e4b9..3995f95 100644 --- a/reid/src/ast/mod.rs +++ b/reid/src/ast/mod.rs @@ -178,7 +178,7 @@ pub enum BlockLevelStatement { }, Expression(Expression), Return(ReturnType, Expression), - ForLoop(String, Expression, Expression, Block), + ForLoop(String, TokenRange, Expression, Expression, Block), WhileLoop(Expression, Block), } diff --git a/reid/src/ast/parse.rs b/reid/src/ast/parse.rs index 96fe0b6..34edad4 100644 --- a/reid/src/ast/parse.rs +++ b/reid/src/ast/parse.rs @@ -669,7 +669,7 @@ impl Parse for BlockLevelStatement { } Some(Token::For) => { let for_stmt = stream.parse::()?; - Stmt::ForLoop(for_stmt.0, for_stmt.1, for_stmt.2, for_stmt.3) + 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::()?; @@ -692,7 +692,7 @@ impl Parse for BlockLevelStatement { } #[derive(Debug)] -pub struct ForStatement(String, Expression, Expression, Block); +pub struct ForStatement(String, TokenRange, Expression, Expression, Block); #[derive(Debug)] pub struct WhileStatement(Expression, Block); @@ -703,12 +703,13 @@ impl Parse for ForStatement { 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::To)?; let end = stream.parse()?; - Ok(ForStatement(idx, start, end, stream.parse()?)) + Ok(ForStatement(idx, start_range, start, end, stream.parse()?)) } } diff --git a/reid/src/ast/process.rs b/reid/src/ast/process.rs index b9d9317..929a86f 100644 --- a/reid/src/ast/process.rs +++ b/reid/src/ast/process.rs @@ -3,8 +3,8 @@ use std::path::PathBuf; use crate::{ ast::{self}, mir::{ - self, CustomTypeKey, ModuleMap, NamedVariableRef, SourceModuleId, StmtKind, StructField, - StructType, + self, CustomTypeKey, ForStatement, ModuleMap, NamedVariableRef, SourceModuleId, StmtKind, + StructField, StructType, WhileStatement, }, }; @@ -148,10 +148,28 @@ impl ast::Block { ast::BlockLevelStatement::Return(_, e) => { (StmtKind::Expression(e.process(module_id)), e.1) } - ast::BlockLevelStatement::ForLoop(counter, start, end, block) => { - todo!() - } - ast::BlockLevelStatement::WhileLoop(expression, block) => todo!(), + ast::BlockLevelStatement::ForLoop(counter, counter_range, start, end, block) => ( + StmtKind::For(ForStatement { + counter: NamedVariableRef( + mir::TypeKind::Vague(mir::VagueType::Unknown), + counter.clone(), + counter_range.as_meta(module_id), + ), + start: start.process(module_id), + end: end.process(module_id), + block: block.into_mir(module_id), + 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))); diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index 6abc671..2b270ca 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -598,6 +598,8 @@ impl mir::Statement { } mir::StmtKind::Import(_) => todo!(), mir::StmtKind::Expression(expression) => expression.codegen(scope, state), + mir::StmtKind::For(for_statement) => todo!(), + mir::StmtKind::While(while_statement) => todo!(), } } } diff --git a/reid/src/mir/fmt.rs b/reid/src/mir/fmt.rs index 53e5417..4bf9b98 100644 --- a/reid/src/mir/fmt.rs +++ b/reid/src/mir/fmt.rs @@ -147,7 +147,7 @@ impl Display for Statement { impl Display for StmtKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Let(var, mutable, block) => { + StmtKind::Let(var, mutable, block) => { write!( f, "let{} {} = {}", @@ -156,9 +156,26 @@ impl Display for StmtKind { block ) } - Self::Set(var, expr) => write!(f, "{} = {}", var, expr), - Self::Import(n) => write!(f, "import {}", n), - Self::Expression(exp) => Display::fmt(exp, f), + StmtKind::Set(var, expr) => write!(f, "{} = {}", var, expr), + StmtKind::Import(n) => write!(f, "import {}", n), + StmtKind::Expression(exp) => Display::fmt(exp, f), + StmtKind::For(for_statement) => { + write!( + f, + "for {} in {} to {} {}", + for_statement.counter, + for_statement.start, + for_statement.end, + for_statement.block + ) + } + StmtKind::While(while_statement) => { + write!( + f, + "while {} {}", + while_statement.condition, while_statement.block, + ) + } } } } diff --git a/reid/src/mir/implement.rs b/reid/src/mir/implement.rs index 7f36ec3..18ee891 100644 --- a/reid/src/mir/implement.rs +++ b/reid/src/mir/implement.rs @@ -9,6 +9,7 @@ pub enum ReturnTypeOther { NoBlockReturn(Metadata), IndexingNonArray(Metadata), DerefNonBorrow(Metadata), + Loop, } impl TypeKind { @@ -374,6 +375,8 @@ impl Statement { ), Import(_) => todo!(), Expression(expression) => expression.return_type(refs, mod_id), + For(_) => Err(ReturnTypeOther::Loop), + While(_) => Err(ReturnTypeOther::Loop), } } @@ -383,6 +386,8 @@ impl Statement { StmtKind::Set(_, _) => None, StmtKind::Import(_) => None, StmtKind::Expression(expr) => expr.backing_var(), + StmtKind::For(_) => None, + StmtKind::While(_) => None, } } } diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 1372bbd..4229b19 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -338,6 +338,24 @@ pub enum StmtKind { Set(Expression, Expression), Import(Import), Expression(Expression), + For(ForStatement), + While(WhileStatement), +} + +#[derive(Debug)] +pub struct ForStatement { + pub counter: NamedVariableRef, + pub start: Expression, + pub end: Expression, + pub block: Block, + pub meta: Metadata, +} + +#[derive(Debug)] +pub struct WhileStatement { + pub condition: Expression, + pub block: Block, + pub meta: Metadata, } #[derive(Debug, Clone)] diff --git a/reid/src/mir/pass.rs b/reid/src/mir/pass.rs index 5409d80..ac7ee85 100644 --- a/reid/src/mir/pass.rs +++ b/reid/src/mir/pass.rs @@ -390,10 +390,19 @@ impl Statement { StmtKind::Set(_, expression) => { expression.pass(pass, state, scope, mod_id)?; } - StmtKind::Import(_) => {} // Never exists at this stage + StmtKind::Import(_) => {} StmtKind::Expression(expression) => { expression.pass(pass, state, scope, mod_id)?; } + StmtKind::For(for_statement) => { + for_statement.start.pass(pass, state, scope, mod_id); + for_statement.end.pass(pass, state, scope, mod_id); + for_statement.block.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)))?; @@ -412,8 +421,10 @@ impl Statement { .ok(); } StmtKind::Set(_, _) => {} - StmtKind::Import(_) => {} // Never exists at this stage + StmtKind::Import(_) => {} StmtKind::Expression(_) => {} + StmtKind::For(_) => {} + StmtKind::While(_) => {} }; Ok(()) } diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck.rs index 9d8dfc0..f3582c6 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck.rs @@ -323,7 +323,7 @@ impl Block { None } - StmtKind::Import(_) => todo!(), // TODO + StmtKind::Import(_) => todo!(), StmtKind::Expression(expression) => { let res = expression.typecheck(&mut state, &typerefs, None); state.or_else(res, TypeKind::Void, expression.1); @@ -335,6 +335,8 @@ impl Block { None } } + StmtKind::For(for_statement) => todo!(), + StmtKind::While(while_statement) => todo!(), }; if let Some((ReturnKind::Hard, _)) = ret { diff --git a/reid/src/mir/typeinference.rs b/reid/src/mir/typeinference.rs index 35bf42f..22379c9 100644 --- a/reid/src/mir/typeinference.rs +++ b/reid/src/mir/typeinference.rs @@ -126,6 +126,8 @@ impl Block { let expr_res = expr.infer_types(&mut state, &inner_refs); state.ok(expr_res, expr.1); } + StmtKind::For(for_statement) => todo!(), + StmtKind::While(while_statement) => todo!(), }; } From 75a7a435d1944d44e28f547da0f5c95735d36aab Mon Sep 17 00:00:00 2001 From: sofia Date: Wed, 23 Jul 2025 20:41:09 +0300 Subject: [PATCH 4/7] Make for-loops syntax sugar instead --- reid/src/ast/process.rs | 74 ++++++++++++++++++++++++++++------- reid/src/codegen.rs | 3 +- reid/src/mir/fmt.rs | 11 +----- reid/src/mir/implement.rs | 2 - reid/src/mir/mod.rs | 12 +----- reid/src/mir/pass.rs | 6 --- reid/src/mir/typecheck.rs | 1 - reid/src/mir/typeinference.rs | 1 - 8 files changed, 62 insertions(+), 48 deletions(-) diff --git a/reid/src/ast/process.rs b/reid/src/ast/process.rs index 929a86f..4929cad 100644 --- a/reid/src/ast/process.rs +++ b/reid/src/ast/process.rs @@ -3,8 +3,8 @@ use std::path::PathBuf; use crate::{ ast::{self}, mir::{ - self, CustomTypeKey, ForStatement, ModuleMap, NamedVariableRef, SourceModuleId, StmtKind, - StructField, StructType, WhileStatement, + self, CustomTypeKey, ModuleMap, NamedVariableRef, SourceModuleId, StmtKind, StructField, + StructType, WhileStatement, }, }; @@ -148,20 +148,64 @@ impl ast::Block { ast::BlockLevelStatement::Return(_, e) => { (StmtKind::Expression(e.process(module_id)), e.1) } - ast::BlockLevelStatement::ForLoop(counter, counter_range, start, end, block) => ( - StmtKind::For(ForStatement { - counter: NamedVariableRef( - mir::TypeKind::Vague(mir::VagueType::Unknown), - counter.clone(), - counter_range.as_meta(module_id), + 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), + ), ), - start: start.process(module_id), - end: end.process(module_id), - block: block.into_mir(module_id), - meta: self.2.as_meta(module_id), - }), - self.2, - ), + 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), diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index 2b270ca..5fd776b 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -598,8 +598,7 @@ impl mir::Statement { } mir::StmtKind::Import(_) => todo!(), mir::StmtKind::Expression(expression) => expression.codegen(scope, state), - mir::StmtKind::For(for_statement) => todo!(), - mir::StmtKind::While(while_statement) => todo!(), + mir::StmtKind::While(_) => todo!(), } } } diff --git a/reid/src/mir/fmt.rs b/reid/src/mir/fmt.rs index 4bf9b98..1d1037e 100644 --- a/reid/src/mir/fmt.rs +++ b/reid/src/mir/fmt.rs @@ -159,16 +159,7 @@ impl Display for StmtKind { StmtKind::Set(var, expr) => write!(f, "{} = {}", var, expr), StmtKind::Import(n) => write!(f, "import {}", n), StmtKind::Expression(exp) => Display::fmt(exp, f), - StmtKind::For(for_statement) => { - write!( - f, - "for {} in {} to {} {}", - for_statement.counter, - for_statement.start, - for_statement.end, - for_statement.block - ) - } + StmtKind::While(while_statement) => { write!( f, diff --git a/reid/src/mir/implement.rs b/reid/src/mir/implement.rs index 18ee891..e4670c8 100644 --- a/reid/src/mir/implement.rs +++ b/reid/src/mir/implement.rs @@ -375,7 +375,6 @@ impl Statement { ), Import(_) => todo!(), Expression(expression) => expression.return_type(refs, mod_id), - For(_) => Err(ReturnTypeOther::Loop), While(_) => Err(ReturnTypeOther::Loop), } } @@ -386,7 +385,6 @@ impl Statement { StmtKind::Set(_, _) => None, StmtKind::Import(_) => None, StmtKind::Expression(expr) => expr.backing_var(), - StmtKind::For(_) => None, StmtKind::While(_) => None, } } diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 4229b19..d432090 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -241,7 +241,7 @@ pub enum ReturnKind { Soft, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata); #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] @@ -338,19 +338,9 @@ pub enum StmtKind { Set(Expression, Expression), Import(Import), Expression(Expression), - For(ForStatement), While(WhileStatement), } -#[derive(Debug)] -pub struct ForStatement { - pub counter: NamedVariableRef, - pub start: Expression, - pub end: Expression, - pub block: Block, - pub meta: Metadata, -} - #[derive(Debug)] pub struct WhileStatement { pub condition: Expression, diff --git a/reid/src/mir/pass.rs b/reid/src/mir/pass.rs index ac7ee85..3ca659e 100644 --- a/reid/src/mir/pass.rs +++ b/reid/src/mir/pass.rs @@ -394,11 +394,6 @@ impl Statement { StmtKind::Expression(expression) => { expression.pass(pass, state, scope, mod_id)?; } - StmtKind::For(for_statement) => { - for_statement.start.pass(pass, state, scope, mod_id); - for_statement.end.pass(pass, state, scope, mod_id); - for_statement.block.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); @@ -423,7 +418,6 @@ impl Statement { StmtKind::Set(_, _) => {} StmtKind::Import(_) => {} StmtKind::Expression(_) => {} - StmtKind::For(_) => {} StmtKind::While(_) => {} }; Ok(()) diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck.rs index f3582c6..3819ddb 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck.rs @@ -335,7 +335,6 @@ impl Block { None } } - StmtKind::For(for_statement) => todo!(), StmtKind::While(while_statement) => todo!(), }; diff --git a/reid/src/mir/typeinference.rs b/reid/src/mir/typeinference.rs index 22379c9..c7e10f5 100644 --- a/reid/src/mir/typeinference.rs +++ b/reid/src/mir/typeinference.rs @@ -126,7 +126,6 @@ impl Block { let expr_res = expr.infer_types(&mut state, &inner_refs); state.ok(expr_res, expr.1); } - StmtKind::For(for_statement) => todo!(), StmtKind::While(while_statement) => todo!(), }; } From 15ff9c59065c4bb6bd48977d44c997bd6d228b3a Mon Sep 17 00:00:00 2001 From: sofia Date: Wed, 23 Jul 2025 20:44:58 +0300 Subject: [PATCH 5/7] Fix warnings --- reid/src/mir/pass.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reid/src/mir/pass.rs b/reid/src/mir/pass.rs index 3ca659e..f67ad74 100644 --- a/reid/src/mir/pass.rs +++ b/reid/src/mir/pass.rs @@ -395,8 +395,8 @@ impl Statement { 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); + while_statement.condition.pass(pass, state, scope, mod_id)?; + while_statement.block.pass(pass, state, scope, mod_id)?; } } From a251be2715f2f0437cbd1a82c6999db34edd4b40 Mon Sep 17 00:00:00 2001 From: sofia Date: Wed, 23 Jul 2025 20:53:11 +0300 Subject: [PATCH 6/7] Make loops typecheck and type infere --- examples/loops.reid | 7 +++++-- reid-llvm-lib/src/builder.rs | 1 - reid/src/ast/parse.rs | 12 +++++++----- reid/src/codegen.rs | 1 - reid/src/lexer.rs | 10 +--------- reid/src/mir/typecheck.rs | 9 ++++++++- reid/src/mir/typeinference.rs | 8 +++++++- 7 files changed, 28 insertions(+), 20 deletions(-) diff --git a/examples/loops.reid b/examples/loops.reid index 8d66fe6..2c07934 100644 --- a/examples/loops.reid +++ b/examples/loops.reid @@ -1,9 +1,12 @@ // Arithmetic, function calls and imports! +import std::print; +import std::from_str; fn main() -> u32 { - for i in 0 to 10 { - print("hello") + let text = from_str("hello"); + for i in 0 .. 10 { + print(&text) } let mut num = 0; diff --git a/reid-llvm-lib/src/builder.rs b/reid-llvm-lib/src/builder.rs index 949a147..67de72b 100644 --- a/reid-llvm-lib/src/builder.rs +++ b/reid-llvm-lib/src/builder.rs @@ -440,7 +440,6 @@ impl Builder { } Instr::GetStructElemPtr(ptr_val, idx) => { let ptr_ty = ptr_val.get_type(&self)?; - dbg!(&ptr_ty); if let Type::Ptr(ty) = ptr_ty { if let Type::CustomType(val) = *ty { match self.type_data(&val).kind { diff --git a/reid/src/ast/parse.rs b/reid/src/ast/parse.rs index 34edad4..dfc519e 100644 --- a/reid/src/ast/parse.rs +++ b/reid/src/ast/parse.rs @@ -155,11 +155,12 @@ impl Parse for PrimaryExpression { } Token::DecimalValue(v) => { 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 - let Some(Token::DecimalValue(fractional)) = stream.next() else { - return Err(stream.expected_err("fractional part")?); - }; + stream.next(); // Consume fractional + Expression( Kind::Literal(Literal::Decimal( format!("{}.{}", v, fractional) @@ -706,7 +707,8 @@ impl Parse for ForStatement { let start_range = stream.get_range().unwrap(); stream.expect(Token::In)?; let start = stream.parse()?; - stream.expect(Token::To)?; + stream.expect(Token::Dot)?; + stream.expect(Token::Dot)?; let end = stream.parse()?; Ok(ForStatement(idx, start_range, start, end, stream.parse()?)) diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index 5fd776b..ddb69c6 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -1001,7 +1001,6 @@ impl mir::Expression { let TypeKind::CodegenPtr(inner) = &struct_val.1 else { panic!("tried accessing non-pointer"); }; - dbg!(&inner); let TypeKind::CustomType(key) = *inner.clone() else { panic!("tried accessing non-custom-type"); }; diff --git a/reid/src/lexer.rs b/reid/src/lexer.rs index 176ef92..97f1f6f 100644 --- a/reid/src/lexer.rs +++ b/reid/src/lexer.rs @@ -46,11 +46,7 @@ pub enum Token { While, /// `for` For, - /// `from` - From, - /// `to` - To, - /// `to` + /// `In` In, // Symbols @@ -147,9 +143,7 @@ impl ToString for Token { Token::Struct => String::from("struct"), Token::AsKeyword => String::from("as"), Token::For => String::from("for"), - Token::From => String::from("from"), Token::In => String::from("in"), - Token::To => String::from("to"), Token::While => String::from("while"), Token::Semi => String::from(';'), Token::Equals => String::from('='), @@ -340,8 +334,6 @@ pub fn tokenize>(to_tokenize: T) -> Result, Error "for" => Token::For, "while" => Token::While, "in" => Token::In, - "from" => Token::From, - "to" => Token::To, _ => Token::Identifier(value), }; variant diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck.rs index 3819ddb..653b256 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck.rs @@ -335,7 +335,14 @@ impl Block { None } } - StmtKind::While(while_statement) => todo!(), + StmtKind::While(WhileStatement { + condition, block, .. + }) => { + condition.typecheck(&mut state, typerefs, Some(&TypeKind::Bool))?; + block.typecheck(&mut state, typerefs, None)?; + + None + } }; if let Some((ReturnKind::Hard, _)) = ret { diff --git a/reid/src/mir/typeinference.rs b/reid/src/mir/typeinference.rs index c7e10f5..cfb1bcb 100644 --- a/reid/src/mir/typeinference.rs +++ b/reid/src/mir/typeinference.rs @@ -16,6 +16,7 @@ use super::{ IfExpression, Module, ReturnKind, StmtKind, TypeKind::*, VagueType::*, + WhileStatement, }; /// Struct used to implement Type Inference, where an intermediary @@ -126,7 +127,12 @@ impl Block { let expr_res = expr.infer_types(&mut state, &inner_refs); state.ok(expr_res, expr.1); } - StmtKind::While(while_statement) => todo!(), + StmtKind::While(WhileStatement { + condition, block, .. + }) => { + condition.infer_types(&mut state, &inner_refs)?; + block.infer_types(&mut state, &inner_refs)?; + } }; } From c4017715d24c820a165cba6ca207c8abae03ca5a Mon Sep 17 00:00:00 2001 From: sofia Date: Wed, 23 Jul 2025 21:07:12 +0300 Subject: [PATCH 7/7] Codegen for/while loops --- reid/src/ast/parse.rs | 2 +- reid/src/codegen.rs | 50 ++++++++++++++++++++++++++++++++++++++- reid/src/mir/typecheck.rs | 14 +++++++++-- reid/tests/e2e.rs | 4 ++++ 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/reid/src/ast/parse.rs b/reid/src/ast/parse.rs index dfc519e..757cabe 100644 --- a/reid/src/ast/parse.rs +++ b/reid/src/ast/parse.rs @@ -696,7 +696,7 @@ impl Parse for BlockLevelStatement { pub struct ForStatement(String, TokenRange, Expression, Expression, Block); #[derive(Debug)] -pub struct WhileStatement(Expression, Block); +pub struct WhileStatement(pub Expression, pub Block); impl Parse for ForStatement { fn parse(mut stream: TokenStream) -> Result { diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index ddb69c6..421f2ab 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -19,6 +19,7 @@ use crate::{ mir::{ self, implement::TypeCategory, CustomTypeKey, Metadata, NamedVariableRef, SourceModuleId, StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, VagueLiteral, + WhileStatement, }, util::try_all, }; @@ -598,7 +599,54 @@ impl mir::Statement { } mir::StmtKind::Import(_) => todo!(), mir::StmtKind::Expression(expression) => expression.codegen(scope, state), - mir::StmtKind::While(_) => todo!(), + 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) + } } } } diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck.rs index 653b256..8e8f297 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck.rs @@ -336,9 +336,19 @@ impl Block { } } StmtKind::While(WhileStatement { - condition, block, .. + condition, + block, + meta, }) => { - condition.typecheck(&mut state, typerefs, Some(&TypeKind::Bool))?; + 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 diff --git a/reid/tests/e2e.rs b/reid/tests/e2e.rs index abf94ef..5685490 100644 --- a/reid/tests/e2e.rs +++ b/reid/tests/e2e.rs @@ -120,3 +120,7 @@ fn strings_compiles_well() { fn struct_compiles_well() { test(include_str!("../../examples/struct.reid"), "test", 17); } +#[test] +fn loops_compiles_well() { + test(include_str!("../../examples/loops.reid"), "test", 10); +}