From ee2133a13d61b3b3fb8fcf88f9c9781debd77d9e Mon Sep 17 00:00:00 2001 From: Cody Date: Thu, 29 Jun 2023 03:23:35 -0500 Subject: [PATCH] For loops --- examples/hello.sloth | 18 ++------ sloth/src/analysis/setup.rs | 28 +++++++++--- sloth/src/codegen/mod.rs | 85 ++++++++++++++++++++++++++++--------- sloth/src/lexer.rs | 6 ++- sloth/src/parser/stmt.rs | 1 + 5 files changed, 97 insertions(+), 41 deletions(-) diff --git a/examples/hello.sloth b/examples/hello.sloth index 8f42051..5aa54e9 100644 --- a/examples/hello.sloth +++ b/examples/hello.sloth @@ -1,19 +1,7 @@ fn main() Int { - var x: [Int] = [5]; - vpopi(x); - var i: Int = 0; - while i < 100 { - vpushi(x, randGen(0, 100)); - i = i + 1; + var i: Int = 10; + for j in 0..i { + print(istr(j)); } - - var y: Int = vgeti(x, 42); - var y: Int = vgeti(x, 45); - var y: Int = vgeti(x, 41); - var y: Int = vgeti(x, 49); - println(istr(y)); - - - print("Hello World\n"); return 0; } diff --git a/sloth/src/analysis/setup.rs b/sloth/src/analysis/setup.rs index f124663..274ec4a 100644 --- a/sloth/src/analysis/setup.rs +++ b/sloth/src/analysis/setup.rs @@ -54,6 +54,19 @@ impl Populator { } } } + StmtKind::ForStmt { + identifier, body, .. + } => { + // When a for statement exists we must bind the identifier + // to the value of the iterator. + let mut body_table = body.symtable.clone(); + let symbol = Symbol::Value(ValueSymbol { + typ: Type::Integer, + id: self.reserve_id(), + }); + + body_table.insert(identifier.to_owned(), symbol); + } _ => (), } } @@ -134,11 +147,7 @@ pub(super) fn propagate_types_stmt(node: &mut Stmt) -> Result<(), AnalysisError> propagate_types(condition)?; propagate_types_stmt(body)?; } - StmtKind::ForStmt { - iterator, - identifier, - body, - } => { + StmtKind::ForStmt { iterator, body, .. } => { propagate_types(iterator)?; propagate_types_stmt(body)?; } @@ -223,10 +232,17 @@ pub(super) fn propagate_types(node: &mut Expr) -> Result<(), AnalysisError> { | BinaryOp::GtEq | BinaryOp::EqEq | BinaryOp::NotEq => Type::Boolean, - BinaryOp::LogicalAnd | BinaryOp::LogicalOr | BinaryOp::Range => lhs + BinaryOp::LogicalAnd | BinaryOp::LogicalOr => lhs .typ .clone() .ok_or(AnalysisError::Unknown(node.line, "owo?? choco???"))?, + BinaryOp::Range => Type::Iterator { + typ: Box::new( + lhs.typ + .clone() + .ok_or(AnalysisError::Unknown(node.line, "skill issue"))?, + ), + }, } } ExprKind::UnaryOp { value, .. } => { diff --git a/sloth/src/codegen/mod.rs b/sloth/src/codegen/mod.rs index fbf3d5f..65277e7 100644 --- a/sloth/src/codegen/mod.rs +++ b/sloth/src/codegen/mod.rs @@ -164,17 +164,58 @@ impl<'ctx> Codegen<'ctx> { let body_bb = self.context.append_basic_block(func, "loop body"); let after_bb = self.context.append_basic_block(func, "after loop"); + // Before the loop + let i32_type = self.context.i32_type(); + let range_type = self + .context + .struct_type(&[i32_type.into(), i32_type.into()], false); + + let range = self.codegen_expr(iterator).unwrap().into_struct_value(); + let range_ptr = self.codegen_alloca(range_type.as_basic_type_enum(), "range"); + self.builder.build_store(range_ptr, range); + + let current_ptr = self + .builder + .build_struct_gep(range_type, range_ptr, 0, "current") + .expect("Butter corn salt!"); + + let table = body.symtable.clone(); + let symbol = table.get_value(identifier).unwrap(); + self.references.insert(symbol.id, current_ptr); + + let end_ptr = self + .builder + .build_struct_gep(range_type, range_ptr, 1, "end") + .expect("❌🧢"); + self.builder.build_unconditional_branch(loop_bb); // Building the blocks for the head of the loop self.builder.position_at_end(loop_bb); - let iterator = self.codegen_expr(iterator).unwrap().into_int_value(); + let current = self.builder.build_load(i32_type, current_ptr, ""); + let end = self.builder.build_load(i32_type, end_ptr, ""); + let condition = self.builder.build_int_compare( + IntPredicate::SLT, + current.into_int_value(), + end.into_int_value(), + "", + ); + self.builder - .build_conditional_branch(iterator, body_bb, after_bb); + .build_conditional_branch(condition, body_bb, after_bb); // Building the blocks for the body of the loop self.builder.position_at_end(body_bb); self.codegen_stmt(body); + + let current = self.builder.build_load(i32_type, current_ptr, ""); + let updated_current = self.builder.build_int_add( + current.into_int_value(), + i32_type.const_int(1, true), + "", + ); + self.builder.build_store(current_ptr, updated_current); + self.builder.build_unconditional_branch(loop_bb); // Position the builder at the end of the loop @@ -330,26 +371,32 @@ impl<'ctx> Codegen<'ctx> { let r = self.codegen_expr(rhs).unwrap().into_int_value(); match op { - BinaryOp::Add => self.builder.build_int_add(l, r, "add"), - BinaryOp::Sub => self.builder.build_int_sub(l, r, "sub"), - BinaryOp::Mul => self.builder.build_int_mul(l, r, "mul"), - BinaryOp::Div => self.builder.build_int_signed_div(l, r, "div"), - BinaryOp::Mod => self.builder.build_int_signed_rem(l, r, "mod"), - - BinaryOp::Gt => self.builder.build_int_compare(SGT, l, r, "gt"), - BinaryOp::GtEq => self.builder.build_int_compare(SGE, l, r, ""), - BinaryOp::Lt => self.builder.build_int_compare(SLT, l, r, "lt"), - BinaryOp::LtEq => self.builder.build_int_compare(SLE, l, r, ""), - - BinaryOp::EqEq => self.builder.build_int_compare(EQ, l, r, ""), - BinaryOp::NotEq => self.builder.build_int_compare(NE, l, r, ""), - - BinaryOp::LogicalAnd => self.builder.build_and(l, r, "logand"), - BinaryOp::LogicalOr => self.builder.build_or(l, r, "logor"), + BinaryOp::Add => self.builder.build_int_add(l, r, "add").into(), + BinaryOp::Sub => self.builder.build_int_sub(l, r, "sub").into(), + BinaryOp::Mul => self.builder.build_int_mul(l, r, "mul").into(), + BinaryOp::Div => self.builder.build_int_signed_div(l, r, "div").into(), + BinaryOp::Mod => self.builder.build_int_signed_rem(l, r, "mod").into(), + + BinaryOp::Gt => self.builder.build_int_compare(SGT, l, r, "gt").into(), + BinaryOp::GtEq => self.builder.build_int_compare(SGE, l, r, "").into(), + BinaryOp::Lt => self.builder.build_int_compare(SLT, l, r, "lt").into(), + BinaryOp::LtEq => self.builder.build_int_compare(SLE, l, r, "").into(), + + BinaryOp::EqEq => self.builder.build_int_compare(EQ, l, r, "").into(), + BinaryOp::NotEq => self.builder.build_int_compare(NE, l, r, "").into(), + + BinaryOp::LogicalAnd => self.builder.build_and(l, r, "logand").into(), + BinaryOp::LogicalOr => self.builder.build_or(l, r, "logor").into(), + + BinaryOp::Range => { + // FIXME: Change Range type to Iterator type + self.context + .const_struct(&[l.into(), r.into()], false) + .into() + } _ => panic!("{op:?}"), } - .into() } Some(Type::Float) => { use FloatPredicate::*; diff --git a/sloth/src/lexer.rs b/sloth/src/lexer.rs index 01eeb46..0b2399f 100644 --- a/sloth/src/lexer.rs +++ b/sloth/src/lexer.rs @@ -277,6 +277,10 @@ impl<'a> Lexer<'a> { self.window[0] } + fn peek2(&self) -> char { + self.window[1] + } + fn eof(&self) -> bool { self.peek() == '\0' } @@ -323,7 +327,7 @@ impl<'a> Lexer<'a> { value.push(self.advance()); } - if self.peek() == '.' { + if self.peek() == '.' && self.peek2() != '.' { value.push(self.advance()); while self.peek().is_ascii_digit() { diff --git a/sloth/src/parser/stmt.rs b/sloth/src/parser/stmt.rs index c326a0c..8bfbda5 100644 --- a/sloth/src/parser/stmt.rs +++ b/sloth/src/parser/stmt.rs @@ -11,6 +11,7 @@ impl<'a> AstParser<'a> { TokenType::If => self.if_stmt(), TokenType::While => self.while_stmt(), + TokenType::For => self.for_stmt(), TokenType::Var => self.define_variable(), TokenType::Fn => self.define_function(false), TokenType::Return => self.return_stmt(),