From a875d1626dd74a6dee31ef056f3ffe874256a8e2 Mon Sep 17 00:00:00 2001 From: nic-gaffney Date: Tue, 11 Apr 2023 20:30:43 -0500 Subject: Fixed if statements and while loops --- examples/guessing.sloth | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/guessing.sloth b/examples/guessing.sloth index 1938269..01f0796 100644 --- a/examples/guessing.sloth +++ b/examples/guessing.sloth @@ -9,7 +9,7 @@ while !correct { if human == computer { println("You guessed the same number as me!"); - correct = true; + var correct = true; } if human > computer { @@ -20,7 +20,7 @@ while !correct { println("Your guess was too low."); } - tries = tries + 1; + var tries = tries + 1; } println("\nIt took you ", tries, " tries to guess correctly!"); -- cgit v1.2.3 From 81c56242feb2951cece9b4876edb2e298548a5c1 Mon Sep 17 00:00:00 2001 From: nic-gaffney Date: Tue, 11 Apr 2023 22:34:24 -0500 Subject: Mutability should work now (very jank) --- crates/sloth/src/parser/expr.rs | 2 +- crates/sloth/src/parser/stmt.rs | 109 ++++++++++++++++++++++++++++++++++++++-- examples/guessing.sloth | 20 ++------ 3 files changed, 110 insertions(+), 21 deletions(-) (limited to 'examples') diff --git a/crates/sloth/src/parser/expr.rs b/crates/sloth/src/parser/expr.rs index 4095f98..866663a 100644 --- a/crates/sloth/src/parser/expr.rs +++ b/crates/sloth/src/parser/expr.rs @@ -21,7 +21,7 @@ impl<'a> AstParser<'a> { TokenType::Bang => UnaryOp::Not, TokenType::Tilde => UnaryOp::BWComp, TokenType::Minus => UnaryOp::Neg, - _ => panic!(), // TODO: Idk how to not have this shit + _ => panic!(), }; let rhs = self.unary(); diff --git a/crates/sloth/src/parser/stmt.rs b/crates/sloth/src/parser/stmt.rs index c35c4e3..94ddec0 100644 --- a/crates/sloth/src/parser/stmt.rs +++ b/crates/sloth/src/parser/stmt.rs @@ -1,6 +1,7 @@ -use super::ast::{FuncArgs, Stmt}; +use super::ast::{Expr, FuncArgs, Stmt}; use super::AstParser; use crate::lexer::TokenType; +use crate::parser::ast::Literal; impl<'a> AstParser<'a> { pub fn parse(&mut self) -> Vec { @@ -42,13 +43,56 @@ impl<'a> AstParser<'a> { return self.return_statement(); } + self.mut_statement() + // If we couldn't parse a statement return an expression statement + // self.expression_statement() + } + + fn mut_statement(&mut self) -> Stmt { + let TokenType::Identifier(ident) = self.peek().tt.clone() else { + panic!("uh oh {:?}", self.peek()); + }; + + self.advance(); + let next = self.advance().unwrap().tt.clone(); + if next == TokenType::Eq { + let value = self.expression(); + self.consume(TokenType::SemiColon, "No semi colon for me i guess"); + return Stmt::DefineVariable { + name: (ident), + value: (value), + typ: (None), + }; + } else if next == TokenType::OpeningParen { + let mut arguments = Vec::::new(); + + if self.peek().tt != TokenType::ClosingParen { + loop { + arguments.push(self.expression()); + if !self.advance_if_eq(&TokenType::Comma) { + break; + } + } + } + + self.consume( + TokenType::ClosingParen, + "Expected ')' to close off function call", + ); + + self.consume(TokenType::SemiColon, "No semi colon for me i guess"); + return Stmt::ExprStmt(Expr::Call { + ident: (Box::new(Expr::Literal(Literal::String(ident)))), + args: (arguments), + }); + } self.expression_statement() } fn var_statement(&mut self) -> Stmt { let TokenType::Identifier(ident) = self.peek().tt.clone() else { - panic!("Identifier expected after 'var'"); + panic!("Identifier expected after 'var', not {:?}", self.peek()); }; self.advance(); // Advancing from the identifier TODO: Check for type @@ -346,9 +390,12 @@ mod tests { } #[test] fn basic_statement_e() { - let lexer = Lexer::new("if a+5 > 10 {\nprint(a);\n}\nif a+5 < 10 {\nprint(10);\n}"); + let lexer = Lexer::new( + "if a+5 > 10 {\nprint(a);\n}\nif a+5 < 10 {\nprintln(10);\n}\nif a+5 == 10 \ + {\nprint(toString(10));\na = true;\n}", + ); let tokens = lexer.collect_vec(); - println!("{tokens:?}"); + // println!("{tokens:?}"); let expected_ast = vec![ Stmt::If { @@ -379,12 +426,40 @@ mod tests { rhs: (Box::new(Expr::Literal(Literal::Integer(10)))), }), body: (vec![Stmt::ExprStmt(Expr::Call { - ident: (Box::new(Expr::Literal(Literal::String("print".to_string())))), + ident: (Box::new(Expr::Literal(Literal::String("println".to_string())))), args: (vec![Expr::Literal(Literal::Integer(10))]), })]), else_if: (Vec::new()), els: (None), }, + Stmt::If { + expr: (Expr::BinaryOp { + op: (BinaryOp::EqEq), + lhs: (Box::new(Expr::BinaryOp { + op: (BinaryOp::Add), + lhs: (Box::new(Expr::Variable("a".to_string()))), + rhs: (Box::new(Expr::Literal(Literal::Integer(5)))), + })), + rhs: (Box::new(Expr::Literal(Literal::Integer(10)))), + }), + body: (vec![ + Stmt::ExprStmt(Expr::Call { + ident: (Box::new(Expr::Literal(Literal::String("print".to_string())))), + args: (vec![Expr::Call { + ident: Box::new(Expr::Literal(Literal::String("toString".to_string()))), + args: vec![Expr::Literal(Literal::Integer(10))], + }]), + }), + Stmt::DefineVariable { + name: ("a".to_string()), + value: (Expr::Literal(Literal::Bool(true))), + typ: (None), + }, + ]), + + else_if: (Vec::new()), + els: (None), + }, ]; let mut parser = AstParser::new(tokens); @@ -395,4 +470,28 @@ mod tests { assert_eq!(expected_ast, generated_ast); } + + #[test] + fn basic_statement_f() { + let lexer = Lexer::new("test_a = 5 + 3;"); + let tokens = lexer.collect_vec(); + + let expected_ast = Stmt::DefineVariable { + name: ("test_a".to_string()), + value: (Expr::BinaryOp { + op: (BinaryOp::Add), + lhs: (Box::new(Expr::Literal(Literal::Integer(5)))), + rhs: (Box::new(Expr::Literal(Literal::Integer(3)))), + }), + typ: (None), + }; + + let mut parser = AstParser::new(tokens); + let generated_ast = parser.statement(); + + println!("Expected AST:\n{expected_ast:#?}\n\n"); + println!("Generated AST:\n{generated_ast:#?}\n\n"); + + assert_eq!(expected_ast, generated_ast); + } } diff --git a/examples/guessing.sloth b/examples/guessing.sloth index 01f0796..830519b 100644 --- a/examples/guessing.sloth +++ b/examples/guessing.sloth @@ -1,26 +1,16 @@ val computer = random(1, 10); - var tries = 0; var correct = false; - while !correct { print("\nPick a number between 1 and 10: "); val human = parse_int(readln()); - - if human == computer { - println("You guessed the same number as me!"); - var correct = true; - } - - if human > computer { - println("Your guess was too high."); - } - - if human < computer { - println("Your guess was too low."); + if human == computer {println("You guessed the same number as me!"); + correct = true; } + if human > computer {println("Your guess was too high.");} + if human < computer {println("Your guess was too low.");} - var tries = tries + 1; + tries = tries + 1; } println("\nIt took you ", tries, " tries to guess correctly!"); -- cgit v1.2.3 From a6dc77aa4db8aec2593743f058d91d4fe572ab60 Mon Sep 17 00:00:00 2001 From: nic-gaffney Date: Tue, 11 Apr 2023 22:35:37 -0500 Subject: Reformatted guessing.sloth --- examples/guessing.sloth | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/guessing.sloth b/examples/guessing.sloth index 830519b..1938269 100644 --- a/examples/guessing.sloth +++ b/examples/guessing.sloth @@ -1,14 +1,24 @@ val computer = random(1, 10); + var tries = 0; var correct = false; + while !correct { print("\nPick a number between 1 and 10: "); val human = parse_int(readln()); - if human == computer {println("You guessed the same number as me!"); - correct = true; + + if human == computer { + println("You guessed the same number as me!"); + correct = true; + } + + if human > computer { + println("Your guess was too high."); + } + + if human < computer { + println("Your guess was too low."); } - if human > computer {println("Your guess was too high.");} - if human < computer {println("Your guess was too low.");} tries = tries + 1; } -- cgit v1.2.3 From 93b2afeda3a0f413ec7df2b411a53973f2d7a8a6 Mon Sep 17 00:00:00 2001 From: nic-gaffney Date: Wed, 12 Apr 2023 21:17:18 -0500 Subject: Guessing game has explicit types now --- examples/guessing.sloth | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/guessing.sloth b/examples/guessing.sloth index 1938269..05c25db 100644 --- a/examples/guessing.sloth +++ b/examples/guessing.sloth @@ -1,11 +1,11 @@ -val computer = random(1, 10); +val computer: int = random(1, 10); -var tries = 0; -var correct = false; +var tries: int = 0; +var correct: bool = false; while !correct { print("\nPick a number between 1 and 10: "); - val human = parse_int(readln()); + val human: int = parse_int(readln()); if human == computer { println("You guessed the same number as me!"); -- cgit v1.2.3 From a97d9f4a7f8c1e8c1e9d2921b40b34aad3643481 Mon Sep 17 00:00:00 2001 From: nic-gaffney Date: Thu, 13 Apr 2023 23:47:25 -0500 Subject: Fixed for loops --- crates/sloth/src/lexer.rs | 6 ++++-- crates/sloth/src/parser/ast.rs | 4 ++-- crates/sloth/src/parser/expr.rs | 2 +- crates/sloth/src/parser/stmt.rs | 3 ++- examples/hello.sloth | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/crates/sloth/src/lexer.rs b/crates/sloth/src/lexer.rs index cc17b3d..0afaf1c 100644 --- a/crates/sloth/src/lexer.rs +++ b/crates/sloth/src/lexer.rs @@ -293,12 +293,14 @@ impl<'a> Iterator for Lexer<'a> { let tt = match self.window { ['#', '#', ..] => { self.advance_while(|it| it[0] != '\n'); - TokenType::DocComment + // TODO: TokenType::DocComment + return self.next(); } ['#', ..] => { self.advance_while(|it| it[0] != '\n'); - TokenType::Comment + // TODO: okenType::Comment + return self.next(); } // Blocks diff --git a/crates/sloth/src/parser/ast.rs b/crates/sloth/src/parser/ast.rs index 99bbf52..3c8cdeb 100644 --- a/crates/sloth/src/parser/ast.rs +++ b/crates/sloth/src/parser/ast.rs @@ -39,7 +39,7 @@ pub enum Literal { Char(char), String(String), Regex(String), - List(Vec), // TODO: holy shit we forgor listys + List(Vec), } #[derive(Debug, PartialEq)] pub enum Expr { @@ -59,7 +59,7 @@ pub enum Expr { }, Variable(String), Literal(Literal), - Lambda, // TODO: Lambda bitch + Lambda, // TODO: Lambda } #[derive(PartialEq, Debug)] pub struct FuncArgs { diff --git a/crates/sloth/src/parser/expr.rs b/crates/sloth/src/parser/expr.rs index 0cc3a93..ad35d20 100644 --- a/crates/sloth/src/parser/expr.rs +++ b/crates/sloth/src/parser/expr.rs @@ -134,7 +134,7 @@ macro_rules! binary_expr { TokenType::BangEq => BinaryOp::NotEq, TokenType::AmpAmp => BinaryOp::LogAnd, TokenType::PipePipe => BinaryOp::LogOr, - _ => panic!("uh oh spagghetio"), // TODO: Idk how to not have this shit + _ => panic!("uh oh spagghetio"), }; let rhs = self.$parent(); diff --git a/crates/sloth/src/parser/stmt.rs b/crates/sloth/src/parser/stmt.rs index 0d28131..2c48da8 100644 --- a/crates/sloth/src/parser/stmt.rs +++ b/crates/sloth/src/parser/stmt.rs @@ -51,7 +51,7 @@ impl<'a> AstParser<'a> { fn mut_statement(&mut self) -> Stmt { let TokenType::Identifier(ident) = self.peek().tt.clone() else { - panic!("uh oh {:?}", self.peek()); + panic!("Identifier error {:?}", self.peek()); }; self.advance(); @@ -195,6 +195,7 @@ impl<'a> AstParser<'a> { while !self.eof() && self.peek().tt != TokenType::ClosingBrace { body.push(self.statement()); } + self.advance(); Stmt::For { name: (binding), diff --git a/examples/hello.sloth b/examples/hello.sloth index 3dbc685..8201dae 100644 --- a/examples/hello.sloth +++ b/examples/hello.sloth @@ -1,6 +1,6 @@ print("Hello World!"); -## A basic for loop greeting the user in multiple languages +# Comment for greeting in ["Hello", "Hola", "你好"] { print(greeting + " World!"); } -- cgit v1.2.3