forked from natto1784/tricc
		
	parser: fix newline checks after statements
since there is no EOL delimiter like ';', we have to check for newline to avoid something like `a = 4 + 4 b = a` also added tests for expr parsing Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
		@@ -12,7 +12,7 @@ pub enum Entity {
 | 
				
			|||||||
    Fn(Fn),
 | 
					    Fn(Fn),
 | 
				
			||||||
    Class(Class),
 | 
					    Class(Class),
 | 
				
			||||||
    Module(Module),
 | 
					    Module(Module),
 | 
				
			||||||
    Static(Let)
 | 
					    Static(Let),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A module just provides an additional scope
 | 
					/// A module just provides an additional scope
 | 
				
			||||||
@@ -106,7 +106,7 @@ pub enum ElseType {
 | 
				
			|||||||
    Else(Vec<Statement>),
 | 
					    Else(Vec<Statement>),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Op = crate::lexer::TokenSymbol;
 | 
					pub(crate) type Op = crate::lexer::TokenSymbol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, PartialEq)]
 | 
					#[derive(Debug, PartialEq)]
 | 
				
			||||||
pub enum Literal {
 | 
					pub enum Literal {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ use std::str;
 | 
				
			|||||||
/// All token literals
 | 
					/// All token literals
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// TODO: Add string
 | 
					/// TODO: Add string
 | 
				
			||||||
#[derive(Debug, PartialEq)]
 | 
					#[derive(Debug, PartialEq, Clone, Copy)]
 | 
				
			||||||
pub enum TokenLiteral {
 | 
					pub enum TokenLiteral {
 | 
				
			||||||
    Int,
 | 
					    Int,
 | 
				
			||||||
    Float,
 | 
					    Float,
 | 
				
			||||||
@@ -65,7 +65,7 @@ pub enum TokenSymbol {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// All token keywod
 | 
					/// All token keywod
 | 
				
			||||||
#[derive(Debug, PartialEq)]
 | 
					#[derive(Debug, PartialEq, Clone, Copy)]
 | 
				
			||||||
pub enum TokenKeyword {
 | 
					pub enum TokenKeyword {
 | 
				
			||||||
    // parents
 | 
					    // parents
 | 
				
			||||||
    Fn,
 | 
					    Fn,
 | 
				
			||||||
@@ -97,7 +97,7 @@ pub enum TokenKeyword {
 | 
				
			|||||||
/// All token delimiters
 | 
					/// All token delimiters
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// TODO: Maybe add \[ and \]
 | 
					/// TODO: Maybe add \[ and \]
 | 
				
			||||||
#[derive(Debug, PartialEq)]
 | 
					#[derive(Debug, PartialEq, Clone, Copy)]
 | 
				
			||||||
pub enum TokenDelimiter {
 | 
					pub enum TokenDelimiter {
 | 
				
			||||||
    BraceOpen,
 | 
					    BraceOpen,
 | 
				
			||||||
    BraceClose,
 | 
					    BraceClose,
 | 
				
			||||||
@@ -106,7 +106,7 @@ pub enum TokenDelimiter {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// All tokens
 | 
					/// All tokens
 | 
				
			||||||
#[derive(Debug, PartialEq)]
 | 
					#[derive(Debug, PartialEq, Clone, Copy)]
 | 
				
			||||||
pub enum TokenKind {
 | 
					pub enum TokenKind {
 | 
				
			||||||
    Newline,
 | 
					    Newline,
 | 
				
			||||||
    Eof,
 | 
					    Eof,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,6 +57,10 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
                        return None;
 | 
					                        return None;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					                if !self.check_newline_or_tok(TokenKind::Delimiter(TokenDelimiter::BraceClose)) {
 | 
				
			||||||
 | 
					                    self.error_expected_peek("newline or }");
 | 
				
			||||||
 | 
					                    return None;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            } else if !self.skip_token(TokenKind::Delimiter(TokenDelimiter::BraceClose)) {
 | 
					            } else if !self.skip_token(TokenKind::Delimiter(TokenDelimiter::BraceClose)) {
 | 
				
			||||||
                self.error_expected_peek("}");
 | 
					                self.error_expected_peek("}");
 | 
				
			||||||
                return None;
 | 
					                return None;
 | 
				
			||||||
@@ -93,6 +97,10 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
                        return None;
 | 
					                        return None;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					                if !self.check_newline_or_tok(TokenKind::Delimiter(TokenDelimiter::BraceClose)) {
 | 
				
			||||||
 | 
					                    self.error_expected_peek("newline or }");
 | 
				
			||||||
 | 
					                    return None;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            } else if !self.skip_token(TokenKind::Delimiter(TokenDelimiter::BraceClose)) {
 | 
					            } else if !self.skip_token(TokenKind::Delimiter(TokenDelimiter::BraceClose)) {
 | 
				
			||||||
                self.error_expected_peek("}");
 | 
					                self.error_expected_peek("}");
 | 
				
			||||||
                return None;
 | 
					                return None;
 | 
				
			||||||
@@ -148,7 +156,11 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
            if self.skip_token(TokenKind::Delimiter(TokenDelimiter::BraceClose)) {
 | 
					            if self.skip_token(TokenKind::Delimiter(TokenDelimiter::BraceClose)) {
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            children.push(self.parse_statement()?)
 | 
					            children.push(self.parse_statement()?);
 | 
				
			||||||
 | 
					            if !self.check_newline_or_tok(TokenKind::Delimiter(TokenDelimiter::BraceClose)) {
 | 
				
			||||||
 | 
					                self.error_expected_peek("newline or }");
 | 
				
			||||||
 | 
					                return None;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Some(Fn {
 | 
					        Some(Fn {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,6 +57,10 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            statements.push(self.parse_statement()?);
 | 
					            statements.push(self.parse_statement()?);
 | 
				
			||||||
 | 
					            if !self.check_newline_or_tok(TokenKind::Delimiter(TokenDelimiter::BraceClose)) {
 | 
				
			||||||
 | 
					                self.error_expected_peek("newline or }");
 | 
				
			||||||
 | 
					                return None;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Some(statements)
 | 
					        Some(statements)
 | 
				
			||||||
@@ -325,32 +329,107 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// <https://en.wikipedia.org/wiki/Recursive_descent_parser>
 | 
					    /// <https://en.wikipedia.org/wiki/Recursive_descent_parser>
 | 
				
			||||||
    /// expr ::= exprControl
 | 
					    /// expr ::= exprControl
 | 
				
			||||||
    fn parse_expr(&mut self) -> Option<Expr> {
 | 
					    pub(super) fn parse_expr(&mut self) -> Option<Expr> {
 | 
				
			||||||
        self.parse_expr_control()
 | 
					        self.parse_expr_control()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub(super) fn parse_expr_ln(&mut self) -> Option<Expr> {
 | 
					 | 
				
			||||||
        let expr = self.parse_expr();
 | 
					 | 
				
			||||||
        if !self.skip_token(TokenKind::Newline) {
 | 
					 | 
				
			||||||
            self.error_expected_peek("newline");
 | 
					 | 
				
			||||||
            return None;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        expr
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn test_parse_expr_literals() {
 | 
					fn test_parse_expr() {
 | 
				
			||||||
    use Literal::*;
 | 
					    use Literal::*;
 | 
				
			||||||
 | 
					    use TokenSymbol::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    macro_rules! b {
 | 
				
			||||||
 | 
					        ($expr:expr) => {
 | 
				
			||||||
 | 
					            Box::new($expr)
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut parser = Parser::new(
 | 
				
			||||||
 | 
					        r#"if if 1 { 1 } else { 0 } + 9 {
 | 
				
			||||||
 | 
					             a = 4
 | 
				
			||||||
 | 
					           } else if 1 {
 | 
				
			||||||
 | 
					             a = 5
 | 
				
			||||||
 | 
					           } else {
 | 
				
			||||||
 | 
					           }
 | 
				
			||||||
 | 
					          amul ^= (4 + 93 * (1 << 3) / 1.44) ^ bhatura
 | 
				
			||||||
 | 
					          stove = { 44 } + amul"#,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut parser = Parser::new("4524 3123.15e4 9e2 9083482.429455 'c' 3331.13.3");
 | 
					 | 
				
			||||||
    assert_eq!(parser.parse_expr(), Some(Expr::Literal(Int(4524))));
 | 
					 | 
				
			||||||
    assert_eq!(parser.parse_expr(), Some(Expr::Literal(Float(3123.15e4))));
 | 
					 | 
				
			||||||
    assert_eq!(parser.parse_expr(), Some(Expr::Literal(Float(9e2))));
 | 
					 | 
				
			||||||
    assert_eq!(
 | 
					    assert_eq!(
 | 
				
			||||||
        parser.parse_expr(),
 | 
					        parser.parse_expr(),
 | 
				
			||||||
        Some(Expr::Literal(Float(9083482.429455)))
 | 
					        Some(Expr::If(If {
 | 
				
			||||||
 | 
					            cond: b!(Expr::Op(
 | 
				
			||||||
 | 
					                Plus,
 | 
				
			||||||
 | 
					                b!(Expr::If(If {
 | 
				
			||||||
 | 
					                    cond: b!(Expr::Literal(Int(1))),
 | 
				
			||||||
 | 
					                    then: vec![Statement::Expr(Expr::Literal(Int(1)))],
 | 
				
			||||||
 | 
					                    or: Some(b!(ElseType::Else(vec![Statement::Expr(Expr::Literal(
 | 
				
			||||||
 | 
					                        Int(0)
 | 
				
			||||||
 | 
					                    ))])))
 | 
				
			||||||
 | 
					                })),
 | 
				
			||||||
 | 
					                Some(b!(Expr::Literal(Int(9))))
 | 
				
			||||||
 | 
					            )),
 | 
				
			||||||
 | 
					            then: vec![Statement::Expr(Expr::Op(
 | 
				
			||||||
 | 
					                Eq,
 | 
				
			||||||
 | 
					                b!(Expr::Identifier("a".into())),
 | 
				
			||||||
 | 
					                Some(b!(Expr::Literal(Int(4))))
 | 
				
			||||||
 | 
					            ))],
 | 
				
			||||||
 | 
					            or: Some(b!(ElseType::If(If {
 | 
				
			||||||
 | 
					                cond: b!(Expr::Literal(Int(1))),
 | 
				
			||||||
 | 
					                then: vec![Statement::Expr(Expr::Op(
 | 
				
			||||||
 | 
					                    Eq,
 | 
				
			||||||
 | 
					                    b!(Expr::Identifier("a".into())),
 | 
				
			||||||
 | 
					                    Some(b!(Expr::Literal(Int(5))))
 | 
				
			||||||
 | 
					                ))],
 | 
				
			||||||
 | 
					                or: Some(b!(ElseType::Else(vec![])))
 | 
				
			||||||
 | 
					            })))
 | 
				
			||||||
 | 
					        }))
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(parser.skip_token(TokenKind::Newline), true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(
 | 
				
			||||||
 | 
					        parser.parse_expr(),
 | 
				
			||||||
 | 
					        Some(Expr::Op(
 | 
				
			||||||
 | 
					            CaretEq,
 | 
				
			||||||
 | 
					            b!(Expr::Identifier("amul".into())),
 | 
				
			||||||
 | 
					            Some(b!(Expr::Op(
 | 
				
			||||||
 | 
					                Caret,
 | 
				
			||||||
 | 
					                b!(Expr::Op(
 | 
				
			||||||
 | 
					                    Plus,
 | 
				
			||||||
 | 
					                    b!(Expr::Literal(Int(4))),
 | 
				
			||||||
 | 
					                    Some(b!(Expr::Op(
 | 
				
			||||||
 | 
					                        Star,
 | 
				
			||||||
 | 
					                        b!(Expr::Literal(Int(93))),
 | 
				
			||||||
 | 
					                        Some(b!(Expr::Op(
 | 
				
			||||||
 | 
					                            Slash,
 | 
				
			||||||
 | 
					                            b!(Expr::Op(
 | 
				
			||||||
 | 
					                                Shl,
 | 
				
			||||||
 | 
					                                b!(Expr::Literal(Int(1))),
 | 
				
			||||||
 | 
					                                Some(b!(Expr::Literal(Int(3))))
 | 
				
			||||||
 | 
					                            )),
 | 
				
			||||||
 | 
					                            Some(b!(Expr::Literal(Float(1.44))))
 | 
				
			||||||
 | 
					                        )))
 | 
				
			||||||
 | 
					                    )))
 | 
				
			||||||
 | 
					                )),
 | 
				
			||||||
 | 
					                Some(b!(Expr::Identifier("bhatura".into())))
 | 
				
			||||||
 | 
					            )))
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(parser.skip_token(TokenKind::Newline), true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_eq!(
 | 
				
			||||||
 | 
					        parser.parse_expr(),
 | 
				
			||||||
 | 
					        Some(Expr::Op(
 | 
				
			||||||
 | 
					            Eq,
 | 
				
			||||||
 | 
					            b!(Expr::Identifier("stove".into())),
 | 
				
			||||||
 | 
					            Some(b!(Expr::Op(
 | 
				
			||||||
 | 
					                Plus,
 | 
				
			||||||
 | 
					                b!(Expr::Block(vec![Statement::Expr(Expr::Literal(Int(44)))])),
 | 
				
			||||||
 | 
					                Some(b!(Expr::Identifier("amul".into())))
 | 
				
			||||||
 | 
					            )))
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    assert_eq!(parser.parse_expr(), Some(Expr::Literal(Char('c'))));
 | 
					 | 
				
			||||||
    assert_eq!(parser.parse_expr(), None);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,3 +108,14 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
        self.next_token().val.chars().nth(1)
 | 
					        self.next_token().val.chars().nth(1)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn test_parse_literals() {
 | 
				
			||||||
 | 
					    let mut parser = Parser::new("4524 3123.15e4 9e2 9083482.429455 'c' 3331.13.1");
 | 
				
			||||||
 | 
					    assert_eq!(parser.parse_int(), Some(4524));
 | 
				
			||||||
 | 
					    assert_eq!(parser.parse_float(), Some(3123.15e4));
 | 
				
			||||||
 | 
					    assert_eq!(parser.parse_float(), Some(9e2));
 | 
				
			||||||
 | 
					    assert_eq!(parser.parse_float(), Some(9083482.429455));
 | 
				
			||||||
 | 
					    assert_eq!(parser.parse_char(), Some('c'));
 | 
				
			||||||
 | 
					    assert_eq!(parser.next_token().kind, TokenKind::Invalid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,7 +53,9 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    fn next_token(&mut self) -> Token {
 | 
					    fn next_token(&mut self) -> Token {
 | 
				
			||||||
        self.lexer.next_token()
 | 
					        let t = self.lexer.next_token();
 | 
				
			||||||
 | 
					        println!("{:?}", t);
 | 
				
			||||||
 | 
					        t
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
@@ -61,7 +63,7 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
        return self.lexer.peek_token();
 | 
					        return self.lexer.peek_token();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// newline ::= "\n"
 | 
					    /// newline ::= "}\n"
 | 
				
			||||||
    fn trim_newlines(&mut self) {
 | 
					    fn trim_newlines(&mut self) {
 | 
				
			||||||
        while self.peek_token().kind == TokenKind::Newline {
 | 
					        while self.peek_token().kind == TokenKind::Newline {
 | 
				
			||||||
            self.next_token();
 | 
					            self.next_token();
 | 
				
			||||||
@@ -77,6 +79,14 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
        false
 | 
					        false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn check_newline_or_tok(&mut self, token: TokenKind) -> bool {
 | 
				
			||||||
 | 
					        match self.peek_token().kind {
 | 
				
			||||||
 | 
					            TokenKind::Newline => true,
 | 
				
			||||||
 | 
					            d if d == token => true,
 | 
				
			||||||
 | 
					            _ => false,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// ty ::= "int" | "float" | "char"
 | 
					    /// ty ::= "int" | "float" | "char"
 | 
				
			||||||
    fn parse_ty(&mut self) -> Option<Ty> {
 | 
					    fn parse_ty(&mut self) -> Option<Ty> {
 | 
				
			||||||
        let ty: Ty;
 | 
					        let ty: Ty;
 | 
				
			||||||
@@ -134,6 +144,10 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
                TokenKind::Eof => break,
 | 
					                TokenKind::Eof => break,
 | 
				
			||||||
                _ => {
 | 
					                _ => {
 | 
				
			||||||
                    parent.push(self.parse_entity()?);
 | 
					                    parent.push(self.parse_entity()?);
 | 
				
			||||||
 | 
					                    if !self.check_newline_or_tok(TokenKind::Eof) {
 | 
				
			||||||
 | 
					                        self.error_expected_peek("newline or end of file");
 | 
				
			||||||
 | 
					                        return None;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,11 +10,12 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
    /// statement ::= static | let | expr
 | 
					    /// statement ::= static | let | expr
 | 
				
			||||||
    pub(super) fn parse_statement(&mut self) -> Option<Statement> {
 | 
					    pub(super) fn parse_statement(&mut self) -> Option<Statement> {
 | 
				
			||||||
        use TokenKeyword::*;
 | 
					        use TokenKeyword::*;
 | 
				
			||||||
 | 
					        println!("STMT");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Some(match self.peek_token().kind {
 | 
					        Some(match self.peek_token().kind {
 | 
				
			||||||
            TokenKind::Keyword(Static) => Statement::Static(self.parse_static()?),
 | 
					            TokenKind::Keyword(Static) => Statement::Static(self.parse_static()?),
 | 
				
			||||||
            TokenKind::Keyword(Let) => Statement::Let(self.parse_let()?),
 | 
					            TokenKind::Keyword(Let) => Statement::Let(self.parse_let()?),
 | 
				
			||||||
            _ => Statement::Expr(self.parse_expr_ln()?),
 | 
					            _ => Statement::Expr(self.parse_expr()?),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -37,8 +38,8 @@ impl<'a> Parser<'a> {
 | 
				
			|||||||
        let (name, ty) = self.parse_ident_with_ty()?;
 | 
					        let (name, ty) = self.parse_ident_with_ty()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let expr = if self.skip_token(TokenKind::Symbol(TokenSymbol::Eq)) {
 | 
					        let expr = if self.skip_token(TokenKind::Symbol(TokenSymbol::Eq)) {
 | 
				
			||||||
            self.parse_expr_ln()
 | 
					            self.parse_expr()
 | 
				
			||||||
        } else if self.skip_token(TokenKind::Newline) {
 | 
					        } else if self.peek_token().kind == TokenKind::Newline {
 | 
				
			||||||
            None
 | 
					            None
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            self.error_expected_peek("= or newline");
 | 
					            self.error_expected_peek("= or newline");
 | 
				
			||||||
@@ -67,6 +68,7 @@ fn test_parse_let() {
 | 
				
			|||||||
            expr: Some(Expr::Literal(Int(4)))
 | 
					            expr: Some(Expr::Literal(Int(4)))
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    assert_eq!(parser.skip_token(TokenKind::Newline), true);
 | 
				
			||||||
    assert_eq!(
 | 
					    assert_eq!(
 | 
				
			||||||
        parser.parse_let(),
 | 
					        parser.parse_let(),
 | 
				
			||||||
        Some(Let {
 | 
					        Some(Let {
 | 
				
			||||||
@@ -75,6 +77,7 @@ fn test_parse_let() {
 | 
				
			|||||||
            expr: Some(Expr::Literal(Char('6')))
 | 
					            expr: Some(Expr::Literal(Char('6')))
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    assert_eq!(parser.skip_token(TokenKind::Newline), true);
 | 
				
			||||||
    assert_eq!(
 | 
					    assert_eq!(
 | 
				
			||||||
        parser.parse_static(),
 | 
					        parser.parse_static(),
 | 
				
			||||||
        Some(Let {
 | 
					        Some(Let {
 | 
				
			||||||
@@ -83,5 +86,6 @@ fn test_parse_let() {
 | 
				
			|||||||
            expr: None
 | 
					            expr: None
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    assert_eq!(parser.skip_token(TokenKind::Newline), true);
 | 
				
			||||||
    assert_eq!(parser.parse_let(), None);
 | 
					    assert_eq!(parser.parse_let(), None);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user