Add parsing for if-statements
This commit is contained in:
		
							parent
							
								
									4c8417cbee
								
							
						
					
					
						commit
						5084f21ff9
					
				| @ -4,7 +4,7 @@ import std::print; | ||||
| 
 | ||||
| fn main() { | ||||
|     let hello = 32 + { | ||||
|         2 + 2 | ||||
|         2 + 3 | ||||
|     }; | ||||
|     let beep = hello + fibonacci(15); | ||||
|     return beep; | ||||
|  | ||||
							
								
								
									
										95
									
								
								src/ast.rs
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								src/ast.rs
									
									
									
									
									
								
							| @ -33,12 +33,6 @@ pub enum Literal { | ||||
|     I32(i32), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum BinaryOperator { | ||||
|     Add, | ||||
|     Mult, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum Expression { | ||||
|     VariableName(String), | ||||
| @ -46,12 +40,13 @@ pub enum Expression { | ||||
|     Binop(BinaryOperator, Box<Expression>, Box<Expression>), | ||||
|     FunctionCall(Box<FunctionCallExpression>), | ||||
|     BlockExpr(Box<Block>), | ||||
|     IfExpr(Box<IfExpression>), | ||||
| } | ||||
| 
 | ||||
| impl Parse for Expression { | ||||
|     fn parse(mut stream: TokenStream) -> Result<Expression, Error> { | ||||
|         let lhs = parse_primary_expression(&mut stream)?; | ||||
|         parse_binop_rhs(&mut stream, lhs, 0) | ||||
|         parse_binop_rhs(&mut stream, lhs, None) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -60,6 +55,8 @@ fn parse_primary_expression(stream: &mut TokenStream) -> Result<Expression, Erro | ||||
|         Ok(Expression::FunctionCall(Box::new(exp))) | ||||
|     } else if let Ok(block) = stream.parse() { | ||||
|         Ok(Expression::BlockExpr(Box::new(block))) | ||||
|     } else if let Ok(ifexpr) = stream.parse() { | ||||
|         Ok(Expression::IfExpr(Box::new(ifexpr))) | ||||
|     } else if let Some(token) = stream.next() { | ||||
|         Ok(match &token { | ||||
|             Token::Identifier(v) => Expression::VariableName(v.clone()), | ||||
| @ -84,40 +81,79 @@ fn parse_primary_expression(stream: &mut TokenStream) -> Result<Expression, Erro | ||||
| fn parse_binop_rhs( | ||||
|     stream: &mut TokenStream, | ||||
|     mut lhs: Expression, | ||||
|     expr_prec: i8, | ||||
|     mut operator: Option<BinaryOperator>, | ||||
| ) -> Result<Expression, Error> { | ||||
|     while let Some(token) = stream.peek() { | ||||
|         let curr_token_prec = token.get_token_prec(); | ||||
|     let expr_prec = if let Some(op) = operator { | ||||
|         op.get_precedence() + 1 | ||||
|     } else { | ||||
|         0 | ||||
|     }; | ||||
| 
 | ||||
|     while let Some(op) = operator.take().as_ref().or(stream.parse().as_ref().ok()) { | ||||
|         let curr_token_prec = op.get_precedence(); | ||||
| 
 | ||||
|         if curr_token_prec < expr_prec { | ||||
|             break; // Just return lhs
 | ||||
|         } else { | ||||
|             // token has to be an operator
 | ||||
|             stream.next(); // Eat token
 | ||||
| 
 | ||||
|             let mut rhs = parse_primary_expression(stream)?; | ||||
|             if let Some(next_op) = stream.peek() { | ||||
|                 let next_prec = next_op.get_token_prec(); | ||||
|             if let Ok(next_op) = stream.parse::<BinaryOperator>() { | ||||
|                 let next_prec = next_op.get_precedence(); | ||||
|                 if curr_token_prec < next_prec { | ||||
|                     // Operator on the right of rhs has more precedence, turn
 | ||||
|                     // rhs into lhs for new binop
 | ||||
|                     rhs = parse_binop_rhs(stream, rhs, curr_token_prec + 1)?; | ||||
|                     rhs = parse_binop_rhs(stream, rhs, Some(next_op))?; | ||||
|                 } else { | ||||
|                     let _ = operator.insert(next_op); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             use BinaryOperator::*; | ||||
| 
 | ||||
|             lhs = match &token { | ||||
|                 Token::Plus => Expression::Binop(Add, Box::new(lhs), Box::new(rhs)), | ||||
|                 Token::Times => Expression::Binop(Mult, Box::new(lhs), Box::new(rhs)), | ||||
|                 _ => Err(stream.expected_err("+ or *")?)?, | ||||
|             }; | ||||
|             lhs = Expression::Binop(*op, Box::new(lhs), Box::new(rhs)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Ok(lhs) | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| pub enum BinaryOperator { | ||||
|     Add, | ||||
|     Minus, | ||||
|     Mult, | ||||
| 
 | ||||
|     And, | ||||
|     LessThan, | ||||
| } | ||||
| 
 | ||||
| impl Parse for BinaryOperator { | ||||
|     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||
|         Ok(match (stream.next(), stream.peek()) { | ||||
|             (Some(Token::Et), Some(Token::Et)) => { | ||||
|                 stream.next(); | ||||
|                 BinaryOperator::And | ||||
|             } | ||||
|             (Some(Token::LessThan), _) => BinaryOperator::LessThan, | ||||
| 
 | ||||
|             (Some(Token::Plus), _) => BinaryOperator::Add, | ||||
|             (Some(Token::Minus), _) => BinaryOperator::Minus, | ||||
|             (Some(Token::Times), _) => BinaryOperator::Mult, | ||||
|             (_, _) => Err(stream.expected_err("expected operator")?)?, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl BinaryOperator { | ||||
|     pub fn get_precedence(&self) -> i8 { | ||||
|         use BinaryOperator::*; | ||||
|         match &self { | ||||
|             Add => 10, | ||||
|             Minus => 10, | ||||
|             Mult => 20, | ||||
|             And => 100, | ||||
|             LessThan => 100, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct FunctionCallExpression(pub String, pub Vec<Expression>); | ||||
| 
 | ||||
| @ -145,6 +181,16 @@ impl Parse for FunctionCallExpression { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct IfExpression(Expression, pub Block); | ||||
| 
 | ||||
| impl Parse for IfExpression { | ||||
|     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||
|         stream.expect(Token::If)?; | ||||
|         Ok(IfExpression(stream.parse()?, stream.parse()?)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct LetStatement(pub String, pub Expression); | ||||
| 
 | ||||
| @ -260,7 +306,8 @@ impl Parse for Block { | ||||
|         while !matches!(stream.peek(), Some(Token::BraceClose)) { | ||||
|             if let Some((r_type, e)) = return_stmt.take() { | ||||
|                 println!("Oh no, does this statement lack ;"); | ||||
|                 dbg!(r_type, e); | ||||
|                 dbg!(r_type, &e); | ||||
|                 statements.push(BlockLevelStatement::Expression(e)); | ||||
|             } | ||||
|             let statement = stream.parse()?; | ||||
|             if let BlockLevelStatement::Return((r_type, e)) = &statement { | ||||
|  | ||||
| @ -173,6 +173,7 @@ impl Expression { | ||||
|                     let rhs = rhs.codegen(scope)?; | ||||
|                     Ok(scope.block.mul(lhs, rhs)?) | ||||
|                 } | ||||
|                 _ => panic!("Other binary operators not supported yet!"), | ||||
|             }, | ||||
|             BlockExpr(block) => { | ||||
|                 let mut inner = scope.inner(); | ||||
| @ -201,6 +202,7 @@ impl Expression { | ||||
|                 .cloned() | ||||
|                 .ok_or(Error::UndefinedVariable(name.clone())), | ||||
|             Literal(lit) => Ok(scope.block.get_const(lit)), | ||||
|             IfExpr(_) => panic!("if expressions not yet supported"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -20,6 +20,8 @@ pub enum Token { | ||||
|     FnKeyword, | ||||
|     /// `->`
 | ||||
|     Arrow, | ||||
|     /// `if`
 | ||||
|     If, | ||||
| 
 | ||||
|     // Symbols
 | ||||
|     /// `;`
 | ||||
| @ -34,10 +36,14 @@ pub enum Token { | ||||
|     Times, | ||||
|     /// `-`
 | ||||
|     Minus, | ||||
| 
 | ||||
|     /// `>`
 | ||||
|     GreaterThan, | ||||
|     /// `<`
 | ||||
|     LessThan, | ||||
|     /// `&`
 | ||||
|     Et, | ||||
| 
 | ||||
|     /// `(`
 | ||||
|     ParenOpen, | ||||
|     /// `)`
 | ||||
| @ -153,6 +159,7 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error | ||||
|                     "import" => Token::ImportKeyword, | ||||
|                     "return" => Token::ReturnKeyword, | ||||
|                     "fn" => Token::FnKeyword, | ||||
|                     "if" => Token::If, | ||||
|                     _ => Token::Identifier(value), | ||||
|                 }; | ||||
|                 variant | ||||
| @ -182,6 +189,7 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error | ||||
|             '-' => Token::Minus, | ||||
|             '>' => Token::GreaterThan, | ||||
|             '<' => Token::LessThan, | ||||
|             '&' => Token::Et, | ||||
|             '(' => Token::ParenOpen, | ||||
|             ')' => Token::ParenClose, | ||||
|             '{' => Token::BraceOpen, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user