aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/sloth/src/parser/expr.rs2
-rw-r--r--crates/sloth/src/parser/stmt.rs109
-rw-r--r--examples/guessing.sloth20
3 files changed, 110 insertions, 21 deletions
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<Stmt> {
@@ -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::<Expr>::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!");