Files
tricc/src/parser/statement.rs
Amneesh Singh af30410aab 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>
2023-08-14 00:57:17 +05:30

92 lines
2.4 KiB
Rust

use super::Parser;
use crate::ast::*;
use crate::lexer::{
TokenKeyword,
TokenKind,
TokenSymbol,
};
impl<'a> Parser<'a> {
/// statement ::= static | let | expr
pub(super) fn parse_statement(&mut self) -> Option<Statement> {
use TokenKeyword::*;
println!("STMT");
Some(match self.peek_token().kind {
TokenKind::Keyword(Static) => Statement::Static(self.parse_static()?),
TokenKind::Keyword(Let) => Statement::Let(self.parse_let()?),
_ => Statement::Expr(self.parse_expr()?),
})
}
/// static ::="static" let
pub(super) fn parse_static(&mut self) -> Option<Let> {
self.next_token();
if self.peek_token().kind != TokenKind::Keyword(TokenKeyword::Let) {
self.error_expected_peek("let");
return None;
}
self.parse_let()
}
/// let ::= "let" identWithTy "=" expr
pub(super) fn parse_let(&mut self) -> Option<Let> {
self.next_token();
let (name, ty) = self.parse_ident_with_ty()?;
let expr = if self.skip_token(TokenKind::Symbol(TokenSymbol::Eq)) {
self.parse_expr()
} else if self.peek_token().kind == TokenKind::Newline {
None
} else {
self.error_expected_peek("= or newline");
return None;
};
Some(Let { name, ty, expr })
}
}
#[test]
fn test_parse_let() {
use Literal::*;
let mut parser = Parser::new(
r#"static let test01: int = 4
let test02: char = '6'
static let test03: float
let test04 = 9"#,
);
assert_eq!(
parser.parse_static(),
Some(Let {
name: "test01".into(),
ty: Ty::Int,
expr: Some(Expr::Literal(Int(4)))
})
);
assert_eq!(parser.skip_token(TokenKind::Newline), true);
assert_eq!(
parser.parse_let(),
Some(Let {
name: "test02".into(),
ty: Ty::Char,
expr: Some(Expr::Literal(Char('6')))
})
);
assert_eq!(parser.skip_token(TokenKind::Newline), true);
assert_eq!(
parser.parse_static(),
Some(Let {
name: "test03".into(),
ty: Ty::Float,
expr: None
})
);
assert_eq!(parser.skip_token(TokenKind::Newline), true);
assert_eq!(parser.parse_let(), None);
}