parser: initial expression parsing logic
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
@@ -9,6 +9,7 @@ use crate::lexer::{
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
|
/// entity ::= module | class | fn
|
||||||
pub(super) fn parse_entity(&mut self) -> Option<Entity> {
|
pub(super) fn parse_entity(&mut self) -> Option<Entity> {
|
||||||
use TokenKeyword::*;
|
use TokenKeyword::*;
|
||||||
let token = self.peek_token();
|
let token = self.peek_token();
|
||||||
@@ -17,7 +18,7 @@ impl<'a> Parser<'a> {
|
|||||||
match keyword {
|
match keyword {
|
||||||
Module => Some(Entity::Module(self.parse_module()?)),
|
Module => Some(Entity::Module(self.parse_module()?)),
|
||||||
Class => Some(Entity::Class(self.parse_class()?)),
|
Class => Some(Entity::Class(self.parse_class()?)),
|
||||||
Fn => Some(Entity::Fn(self.parse_function()?)),
|
Fn => Some(Entity::Fn(self.parse_fn()?)),
|
||||||
_ => {
|
_ => {
|
||||||
self.error_expected_peek("entity");
|
self.error_expected_peek("entity");
|
||||||
None
|
None
|
||||||
@@ -29,6 +30,7 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// module ::= "module" ident "{" { module | fn | static | class } "}"
|
||||||
fn parse_module(&mut self) -> Option<Module> {
|
fn parse_module(&mut self) -> Option<Module> {
|
||||||
self.next_token();
|
self.next_token();
|
||||||
|
|
||||||
@@ -46,7 +48,7 @@ impl<'a> Parser<'a> {
|
|||||||
if let TokenKind::Keyword(keyword) = &self.peek_token().kind {
|
if let TokenKind::Keyword(keyword) = &self.peek_token().kind {
|
||||||
children.push(match keyword {
|
children.push(match keyword {
|
||||||
Module => ModuleChildren::Module(self.parse_module()?),
|
Module => ModuleChildren::Module(self.parse_module()?),
|
||||||
Fn => ModuleChildren::Fn(self.parse_function()?),
|
Fn => ModuleChildren::Fn(self.parse_fn()?),
|
||||||
Static => ModuleChildren::Static(self.parse_static()?),
|
Static => ModuleChildren::Static(self.parse_static()?),
|
||||||
Class => ModuleChildren::Class(self.parse_class()?),
|
Class => ModuleChildren::Class(self.parse_class()?),
|
||||||
_ => {
|
_ => {
|
||||||
@@ -65,6 +67,7 @@ impl<'a> Parser<'a> {
|
|||||||
Some(Module { name, children })
|
Some(Module { name, children })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// class ::= "class" ident "{" { fn | static | let } "}"
|
||||||
fn parse_class(&mut self) -> Option<Class> {
|
fn parse_class(&mut self) -> Option<Class> {
|
||||||
self.next_token();
|
self.next_token();
|
||||||
|
|
||||||
@@ -81,7 +84,7 @@ impl<'a> Parser<'a> {
|
|||||||
self.trim_newlines();
|
self.trim_newlines();
|
||||||
if let TokenKind::Keyword(keyword) = &self.peek_token().kind {
|
if let TokenKind::Keyword(keyword) = &self.peek_token().kind {
|
||||||
children.push(match keyword {
|
children.push(match keyword {
|
||||||
Fn => ClassChildren::Fn(self.parse_function()?),
|
Fn => ClassChildren::Fn(self.parse_fn()?),
|
||||||
Static => ClassChildren::Static(self.parse_static()?),
|
Static => ClassChildren::Static(self.parse_static()?),
|
||||||
Let => ClassChildren::Let(self.parse_let()?),
|
Let => ClassChildren::Let(self.parse_let()?),
|
||||||
_ => {
|
_ => {
|
||||||
@@ -100,7 +103,9 @@ impl<'a> Parser<'a> {
|
|||||||
Some(Class { name, children })
|
Some(Class { name, children })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_function(&mut self) -> Option<Fn> {
|
/// fn ::= "fn" ident "(" [ identWithTy { "," identWithTy } ] ")" [ ":" ty ]
|
||||||
|
/// "{" { statement } "}"
|
||||||
|
fn parse_fn(&mut self) -> Option<Fn> {
|
||||||
self.next_token();
|
self.next_token();
|
||||||
|
|
||||||
let name = self.parse_ident()?;
|
let name = self.parse_ident()?;
|
||||||
@@ -115,7 +120,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
if self.peek_token().kind == TokenKind::Identifier {
|
if self.peek_token().kind == TokenKind::Identifier {
|
||||||
params.push(self.parse_ident_with_type()?);
|
params.push(self.parse_ident_with_ty()?);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.skip_token(TokenKind::Symbol(TokenSymbol::Comma)) {
|
if !self.skip_token(TokenKind::Symbol(TokenSymbol::Comma)) {
|
||||||
@@ -164,16 +169,7 @@ fn test_parse_entity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fn02 (): int { }
|
||||||
fn fn02(): int {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -190,7 +186,7 @@ fn test_parse_entity() {
|
|||||||
children: vec![Statement::Static(Let {
|
children: vec![Statement::Static(Let {
|
||||||
name: "let01".into(),
|
name: "let01".into(),
|
||||||
ty: Ty::Int,
|
ty: Ty::Int,
|
||||||
expr: Some(Expr::Int(4))
|
expr: Some(Expr::Literal(Literal::Int(4)))
|
||||||
})]
|
})]
|
||||||
})]
|
})]
|
||||||
}),
|
}),
|
||||||
|
@@ -1,109 +1,356 @@
|
|||||||
use super::Parser;
|
use super::Parser;
|
||||||
use crate::ast::*;
|
use crate::ast::{
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
};
|
||||||
use crate::lexer::{
|
use crate::lexer::{
|
||||||
|
TokenDelimiter,
|
||||||
TokenKeyword,
|
TokenKeyword,
|
||||||
TokenKind,
|
TokenKind,
|
||||||
TokenLiteral,
|
TokenLiteral,
|
||||||
TokenSymbol,
|
TokenSymbol,
|
||||||
};
|
};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
pub(super) fn parse_statement(&mut self) -> Option<Statement> {
|
/// exprIf ::= "if" expr block [ else (block | exprIf ) ]
|
||||||
use TokenKeyword::*;
|
fn parse_expr_if(&mut self) -> Option<If> {
|
||||||
|
// skip "if"
|
||||||
match self.peek_token().kind {
|
|
||||||
TokenKind::Keyword(Static) => Some(Statement::Static(self.parse_static()?)),
|
|
||||||
TokenKind::Keyword(Let) => Some(Statement::Let(self.parse_let()?)),
|
|
||||||
_ => Some(Statement::Expr(self.parse_expr()?)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn parse_let(&mut self) -> Option<Let> {
|
|
||||||
self.next_token();
|
self.next_token();
|
||||||
|
|
||||||
let (name, ty) = self.parse_ident_with_type()?;
|
let cond = Box::new(self.parse_expr()?);
|
||||||
let expr;
|
let then = self.parse_expr_block()?;
|
||||||
|
|
||||||
if self.skip_token(TokenKind::Symbol(TokenSymbol::Eq)) {
|
if !self.skip_token(TokenKind::Keyword(TokenKeyword::Else)) {
|
||||||
expr = Some(self.parse_expr()?);
|
return Some(If {
|
||||||
|
cond,
|
||||||
|
then,
|
||||||
|
or: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.peek_token().kind != TokenKind::Keyword(TokenKeyword::If) {
|
||||||
|
return Some(If {
|
||||||
|
cond,
|
||||||
|
then,
|
||||||
|
or: Some(Box::new(ElseType::Else(self.parse_expr_block()?))),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(If {
|
||||||
|
cond,
|
||||||
|
then,
|
||||||
|
or: Some(Box::new(ElseType::If(self.parse_expr_if()?))),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// exprBlock ::= "{" { statement } "}"
|
||||||
|
fn parse_expr_block(&mut self) -> Option<Vec<Statement>> {
|
||||||
|
let mut statements = vec![];
|
||||||
|
|
||||||
|
// skip {
|
||||||
|
self.next_token();
|
||||||
|
|
||||||
|
loop {
|
||||||
self.trim_newlines();
|
self.trim_newlines();
|
||||||
} else if self.skip_token(TokenKind::Newline) {
|
if self.skip_token(TokenKind::Delimiter(TokenDelimiter::BraceClose)) {
|
||||||
expr = None;
|
break;
|
||||||
} else {
|
}
|
||||||
self.error_expected_peek("= or newline");
|
statements.push(self.parse_statement()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(statements)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// exprLoop ::= "loop" exprBlock
|
||||||
|
fn parse_expr_loop(&mut self) -> Option<Vec<Statement>> {
|
||||||
|
self.next_token();
|
||||||
|
if self.peek_token().kind != TokenKind::Delimiter(TokenDelimiter::BraceOpen) {
|
||||||
|
self.error_expected_peek("{");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Let { name, ty, expr })
|
self.parse_expr_block()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expr(&mut self) -> Option<Expr> {
|
/// exprAtom ::= ( "(" expr ")" ) | ident | int | float | char | exprBlock | exprLoop | exprIf
|
||||||
|
fn parse_expr_atom(&mut self) -> Option<Expr> {
|
||||||
|
use ast::Literal::*;
|
||||||
use TokenKind::*;
|
use TokenKind::*;
|
||||||
|
|
||||||
match self.peek_token().kind {
|
// TODO: check lvalue validity in the analysis phase
|
||||||
Literal(TokenLiteral::Int) => Some(Expr::Int(self.parse_int()?)),
|
Some(match self.peek_token().kind {
|
||||||
Literal(TokenLiteral::Float) => Some(Expr::Float(self.parse_float()?)),
|
Delimiter(TokenDelimiter::ParenOpen) => {
|
||||||
Literal(TokenLiteral::Char) => Some(Expr::Char(self.parse_char()?)),
|
self.next_token(); // skip (
|
||||||
|
|
||||||
|
let expr = self.parse_expr()?;
|
||||||
|
|
||||||
|
if !self.skip_token(TokenKind::Delimiter(TokenDelimiter::ParenClose)) {
|
||||||
|
self.error_expected_peek(")");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr
|
||||||
|
}
|
||||||
|
Identifier => {
|
||||||
|
let token = self.next_token();
|
||||||
|
Expr::Identifier(Rc::clone(&token.val))
|
||||||
|
}
|
||||||
|
Literal(TokenLiteral::Int) => Expr::Literal(Int(self.parse_int()?)),
|
||||||
|
Literal(TokenLiteral::Float) => Expr::Literal(Float(self.parse_float()?)),
|
||||||
|
Literal(TokenLiteral::Char) => Expr::Literal(Char(self.parse_char()?)),
|
||||||
|
Delimiter(TokenDelimiter::BraceOpen) => Expr::Block(self.parse_expr_block()?),
|
||||||
|
Keyword(TokenKeyword::Loop) => Expr::Loop(self.parse_expr_loop()?),
|
||||||
|
Keyword(TokenKeyword::If) => Expr::If(self.parse_expr_if()?),
|
||||||
_ => {
|
_ => {
|
||||||
self.error_expected_peek("expression");
|
self.error_expected_peek("expression");
|
||||||
None
|
return None;
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
/// exprUnary ::= [ unaryOp ] exprAtom
|
||||||
fn test_parse_let() {
|
/// unaryOp ::= "+" | "-" | "~"
|
||||||
let mut parser = Parser::new(
|
fn parse_expr_unary(&mut self) -> Option<Expr> {
|
||||||
r#"static let test01: int = 4
|
use TokenSymbol::*;
|
||||||
let test02: char = '6'
|
Some(match self.peek_token().kind {
|
||||||
static let test03: float
|
TokenKind::Symbol(symbol @ (Minus | Plus | Tilde)) => {
|
||||||
let test04 = 9"#,
|
self.next_token();
|
||||||
);
|
Expr::Op(symbol, Box::new(self.parse_expr_atom()?), None)
|
||||||
assert_eq!(
|
}
|
||||||
parser.parse_static(),
|
_ => self.parse_expr_atom()?,
|
||||||
Some(Let {
|
|
||||||
name: "test01".into(),
|
|
||||||
ty: Ty::Int,
|
|
||||||
expr: Some(Expr::Int(4))
|
|
||||||
})
|
})
|
||||||
);
|
}
|
||||||
assert_eq!(
|
|
||||||
parser.parse_let(),
|
/// exprArithmeticMul ::= exprUnary [ arithmeticMulOp exprArithmeticMul ]
|
||||||
Some(Let {
|
/// arithmeticMulOp ::= "*" | "/" | "%"
|
||||||
name: "test02".into(),
|
fn parse_expr_arithmetic_mul(&mut self) -> Option<Expr> {
|
||||||
ty: Ty::Char,
|
use TokenSymbol::*;
|
||||||
expr: Some(Expr::Char('6'))
|
let lhs = self.parse_expr_unary()?;
|
||||||
|
|
||||||
|
Some(match self.peek_token().kind {
|
||||||
|
TokenKind::Symbol(symbol @ (Star | Slash | Percent)) => {
|
||||||
|
self.next_token();
|
||||||
|
Expr::Op(
|
||||||
|
symbol,
|
||||||
|
Box::new(lhs),
|
||||||
|
Some(Box::new(self.parse_expr_arithmetic_mul()?)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => lhs,
|
||||||
})
|
})
|
||||||
);
|
}
|
||||||
assert_eq!(
|
|
||||||
parser.parse_static(),
|
/// exprArithmeticAdd ::= exprArithmeticMul [ arithmeticAddOp exprArithmeticAdd ]
|
||||||
Some(Let {
|
/// arithmeticAddOp ::= "+" | "-"
|
||||||
name: "test03".into(),
|
fn parse_expr_arithmetic_add(&mut self) -> Option<Expr> {
|
||||||
ty: Ty::Float,
|
use TokenSymbol::*;
|
||||||
expr: None
|
let lhs = self.parse_expr_arithmetic_mul()?;
|
||||||
|
|
||||||
|
Some(match self.peek_token().kind {
|
||||||
|
TokenKind::Symbol(symbol @ (Plus | Minus)) => {
|
||||||
|
self.next_token();
|
||||||
|
Expr::Op(
|
||||||
|
symbol,
|
||||||
|
Box::new(lhs),
|
||||||
|
Some(Box::new(self.parse_expr_arithmetic_add()?)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => lhs,
|
||||||
})
|
})
|
||||||
);
|
}
|
||||||
assert_eq!(parser.parse_let(), None);
|
|
||||||
|
/// exprBitwiseShift ::= exprArithmeticAdd [ bitwiseShiftOp exprBitwiseShift ]
|
||||||
|
/// bitwiseShiftOp ::= "<<" | ">>"
|
||||||
|
fn parse_expr_bitwise_shift(&mut self) -> Option<Expr> {
|
||||||
|
use TokenSymbol::*;
|
||||||
|
let lhs = self.parse_expr_arithmetic_add()?;
|
||||||
|
|
||||||
|
Some(match self.peek_token().kind {
|
||||||
|
TokenKind::Symbol(symbol @ (Shl | Shr)) => {
|
||||||
|
self.next_token();
|
||||||
|
Expr::Op(
|
||||||
|
symbol,
|
||||||
|
Box::new(lhs),
|
||||||
|
Some(Box::new(self.parse_expr_bitwise_shift()?)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => lhs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// exprBitwiseAnd ::= exprBitwiseShift [ "&" exprBitwiseAnd ]
|
||||||
|
fn parse_expr_bitwise_and(&mut self) -> Option<Expr> {
|
||||||
|
let lhs = self.parse_expr_bitwise_shift()?;
|
||||||
|
let symbol = TokenSymbol::And;
|
||||||
|
|
||||||
|
if !self.skip_token(TokenKind::Symbol(symbol)) {
|
||||||
|
return Some(lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Expr::Op(
|
||||||
|
symbol,
|
||||||
|
Box::new(lhs),
|
||||||
|
Some(Box::new(self.parse_expr_bitwise_and()?)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// exprBitwiseXor ::= exprBitwiseAnd [ "^" exprBitwiseXor ]
|
||||||
|
fn parse_expr_bitwise_xor(&mut self) -> Option<Expr> {
|
||||||
|
let lhs = self.parse_expr_bitwise_and()?;
|
||||||
|
let symbol = TokenSymbol::Caret;
|
||||||
|
|
||||||
|
if !self.skip_token(TokenKind::Symbol(symbol)) {
|
||||||
|
return Some(lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Expr::Op(
|
||||||
|
symbol,
|
||||||
|
Box::new(lhs),
|
||||||
|
Some(Box::new(self.parse_expr_bitwise_xor()?)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// exprBiwiseOr ::= exprBitwiseXor [ "|" exprBitwiseOr ]
|
||||||
|
fn parse_expr_bitwise_or(&mut self) -> Option<Expr> {
|
||||||
|
let lhs = self.parse_expr_bitwise_xor()?;
|
||||||
|
let symbol = TokenSymbol::Or;
|
||||||
|
|
||||||
|
if !self.skip_token(TokenKind::Symbol(symbol)) {
|
||||||
|
return Some(lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Expr::Op(
|
||||||
|
symbol,
|
||||||
|
Box::new(lhs),
|
||||||
|
Some(Box::new(self.parse_expr_bitwise_or()?)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// exprAssign ::= exprBitwiseOr [ relationalOp exprRelational ]
|
||||||
|
/// relationalOp ::= ">" | "<" | ">=" | "<=" | "==" | "!="
|
||||||
|
fn parse_expr_relational(&mut self) -> Option<Expr> {
|
||||||
|
use TokenSymbol::*;
|
||||||
|
let lhs = self.parse_expr_bitwise_or()?;
|
||||||
|
|
||||||
|
Some(match self.peek_token().kind {
|
||||||
|
TokenKind::Symbol(symbol @ (Gt | Lt | GtEq | LtEq | EqEq | Ne)) => {
|
||||||
|
self.next_token();
|
||||||
|
Expr::Op(
|
||||||
|
symbol,
|
||||||
|
Box::new(lhs),
|
||||||
|
Some(Box::new(self.parse_expr_relational()?)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => lhs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// exprLogicalAnd ::= exprLogicalRelational [ "&&" exprLogicalAnd ]
|
||||||
|
fn parse_expr_logical_and(&mut self) -> Option<Expr> {
|
||||||
|
let lhs = self.parse_expr_relational()?;
|
||||||
|
let symbol = TokenSymbol::AndAnd;
|
||||||
|
|
||||||
|
if !self.skip_token(TokenKind::Symbol(symbol)) {
|
||||||
|
return Some(lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Expr::Op(
|
||||||
|
symbol,
|
||||||
|
Box::new(lhs),
|
||||||
|
Some(Box::new(self.parse_expr_logical_and()?)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// exprLogicalOr ::= exprLogicalAnd [ "||" exprLogicalOr ]
|
||||||
|
fn parse_expr_logical_or(&mut self) -> Option<Expr> {
|
||||||
|
let lhs = self.parse_expr_logical_and()?;
|
||||||
|
let symbol = TokenSymbol::OrOr;
|
||||||
|
|
||||||
|
if !self.skip_token(TokenKind::Symbol(symbol)) {
|
||||||
|
return Some(lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Expr::Op(
|
||||||
|
symbol,
|
||||||
|
Box::new(lhs),
|
||||||
|
Some(Box::new(self.parse_expr_logical_or()?)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// exprAssign ::= exprLogicalOr [ assignOp exprAssign ]
|
||||||
|
/// assignOp ::= "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | "<<=" | ">>=" | "&=" | "|="
|
||||||
|
fn parse_expr_assign(&mut self) -> Option<Expr> {
|
||||||
|
use TokenSymbol::*;
|
||||||
|
let lhs = self.parse_expr_logical_or()?;
|
||||||
|
|
||||||
|
Some(match self.peek_token().kind {
|
||||||
|
TokenKind::Symbol(
|
||||||
|
symbol @ (Eq | PlusEq | MinusEq | StarEq | SlashEq | PercentEq | CaretEq | ShlEq
|
||||||
|
| ShrEq | AndEq | OrEq),
|
||||||
|
) => {
|
||||||
|
self.next_token();
|
||||||
|
Expr::Op(
|
||||||
|
symbol,
|
||||||
|
Box::new(lhs),
|
||||||
|
Some(Box::new(self.parse_expr_assign()?)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => lhs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// exprControl ::= "continue" | "break" | "return" [ exprControl ] | exprAssign
|
||||||
|
fn parse_expr_control(&mut self) -> Option<Expr> {
|
||||||
|
use TokenKeyword::*;
|
||||||
|
|
||||||
|
Some(match self.peek_token().kind {
|
||||||
|
TokenKind::Keyword(Continue) => {
|
||||||
|
self.next_token();
|
||||||
|
Expr::Continue
|
||||||
|
}
|
||||||
|
TokenKind::Keyword(Break) => {
|
||||||
|
self.next_token();
|
||||||
|
Expr::Break
|
||||||
|
}
|
||||||
|
TokenKind::Keyword(Return) => {
|
||||||
|
self.next_token();
|
||||||
|
Expr::Return(self.parse_expr_control().map(Box::new))
|
||||||
|
}
|
||||||
|
_ => self.parse_expr_assign()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// entrypoint for expression parsing using recursive descent parsing
|
||||||
|
///
|
||||||
|
/// <https://en.wikipedia.org/wiki/Recursive_descent_parser>
|
||||||
|
/// expr ::= exprControl
|
||||||
|
fn parse_expr(&mut self) -> Option<Expr> {
|
||||||
|
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_literals() {
|
||||||
|
use Literal::*;
|
||||||
|
|
||||||
let mut parser = Parser::new("4524 3123.15e4 9e2 9083482.429455 'c' 3331.13.3");
|
let mut parser = Parser::new("4524 3123.15e4 9e2 9083482.429455 'c' 3331.13.3");
|
||||||
assert_eq!(parser.parse_expr(), Some(Expr::Int(4524)));
|
assert_eq!(parser.parse_expr(), Some(Expr::Literal(Int(4524))));
|
||||||
assert_eq!(parser.parse_expr(), Some(Expr::Float(3123.15e4)));
|
assert_eq!(parser.parse_expr(), Some(Expr::Literal(Float(3123.15e4))));
|
||||||
assert_eq!(parser.parse_expr(), Some(Expr::Float(9e2)));
|
assert_eq!(parser.parse_expr(), Some(Expr::Literal(Float(9e2))));
|
||||||
assert_eq!(parser.parse_expr(), Some(Expr::Float(9083482.429455)));
|
assert_eq!(
|
||||||
assert_eq!(parser.parse_expr(), Some(Expr::Char('c')));
|
parser.parse_expr(),
|
||||||
|
Some(Expr::Literal(Float(9083482.429455)))
|
||||||
|
);
|
||||||
|
assert_eq!(parser.parse_expr(), Some(Expr::Literal(Char('c'))));
|
||||||
assert_eq!(parser.parse_expr(), None);
|
assert_eq!(parser.parse_expr(), None);
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
use super::Parser;
|
use super::Parser;
|
||||||
use crate::lexer::{
|
use crate::lexer::{
|
||||||
TokenKind,
|
TokenKind,
|
||||||
|
TokenLiteral,
|
||||||
TokenSymbol,
|
TokenSymbol,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
|
/// int ::= digit { digit }
|
||||||
pub(super) fn parse_int(&mut self) -> Option<i32> {
|
pub(super) fn parse_int(&mut self) -> Option<i32> {
|
||||||
let val = self.next_token().val;
|
let val = self.next_token().val;
|
||||||
let mut integer: i32 = 0;
|
let mut integer: i32 = 0;
|
||||||
@@ -36,10 +38,13 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(integer)
|
Some(integer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// didnt use parse() because i wanted to do this myself for some reason
|
||||||
/// f32 can be NaN and inf as well
|
/// f32 can be NaN and inf as well
|
||||||
|
/// float ::= int [ "." { digit } ] [ "e" { digit } ]
|
||||||
pub(super) fn parse_float(&mut self) -> Option<f32> {
|
pub(super) fn parse_float(&mut self) -> Option<f32> {
|
||||||
let token = self.next_token();
|
let token = self.next_token();
|
||||||
let mut chars = token.val.chars();
|
let mut chars = token.val.chars();
|
||||||
@@ -68,6 +73,10 @@ impl<'a> Parser<'a> {
|
|||||||
_ => s = 1,
|
_ => s = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.peek_token().kind != TokenKind::Literal(TokenLiteral::Int) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
exp = self.parse_int()? * s;
|
exp = self.parse_int()? * s;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -93,6 +102,7 @@ impl<'a> Parser<'a> {
|
|||||||
Some(float)
|
Some(float)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// char ::= "'" letter "'"
|
||||||
pub(super) fn parse_char(&mut self) -> Option<char> {
|
pub(super) fn parse_char(&mut self) -> Option<char> {
|
||||||
// the lexer ensures that the 0th and 2nd characters are both '
|
// the lexer ensures that the 0th and 2nd characters are both '
|
||||||
self.next_token().val.chars().nth(1)
|
self.next_token().val.chars().nth(1)
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
mod entity;
|
mod entity;
|
||||||
mod expr;
|
mod expr;
|
||||||
mod literal;
|
mod literal;
|
||||||
|
mod statement;
|
||||||
|
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
Parent,
|
Parent,
|
||||||
@@ -60,6 +61,7 @@ impl<'a> Parser<'a> {
|
|||||||
return self.lexer.peek_token();
|
return self.lexer.peek_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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();
|
||||||
@@ -75,6 +77,7 @@ impl<'a> Parser<'a> {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ty ::= "int" | "float" | "char"
|
||||||
fn parse_ty(&mut self) -> Option<Ty> {
|
fn parse_ty(&mut self) -> Option<Ty> {
|
||||||
let ty: Ty;
|
let ty: Ty;
|
||||||
|
|
||||||
@@ -96,6 +99,7 @@ impl<'a> Parser<'a> {
|
|||||||
Some(ty)
|
Some(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ident ::= ( letter | "_" ) { letter | digit | "_" }
|
||||||
fn parse_ident(&mut self) -> Option<Rc<str>> {
|
fn parse_ident(&mut self) -> Option<Rc<str>> {
|
||||||
if self.peek_token().kind != TokenKind::Identifier {
|
if self.peek_token().kind != TokenKind::Identifier {
|
||||||
self.error_expected_peek("identifier");
|
self.error_expected_peek("identifier");
|
||||||
@@ -105,7 +109,8 @@ impl<'a> Parser<'a> {
|
|||||||
Some(Rc::clone(&self.next_token().val))
|
Some(Rc::clone(&self.next_token().val))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ident_with_type(&mut self) -> Option<(Rc<str>, Ty)> {
|
/// identWithTy ::= letter ":" ty
|
||||||
|
fn parse_ident_with_ty(&mut self) -> Option<(Rc<str>, Ty)> {
|
||||||
let ident = self.parse_ident()?;
|
let ident = self.parse_ident()?;
|
||||||
|
|
||||||
if !self.skip_token(TokenKind::Symbol(TokenSymbol::Colon)) {
|
if !self.skip_token(TokenKind::Symbol(TokenSymbol::Colon)) {
|
||||||
@@ -118,6 +123,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
/// Returns an [`Entity`] vector after parsing
|
/// Returns an [`Entity`] vector after parsing
|
||||||
///
|
///
|
||||||
|
/// parent ::= { entity }
|
||||||
/// [`Entity`]: crate::ast::Entity
|
/// [`Entity`]: crate::ast::Entity
|
||||||
pub fn parse(&mut self) -> Option<Parent> {
|
pub fn parse(&mut self) -> Option<Parent> {
|
||||||
let mut parent = vec![];
|
let mut parent = vec![];
|
||||||
|
87
src/parser/statement.rs
Normal file
87
src/parser/statement.rs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
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::*;
|
||||||
|
|
||||||
|
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_ln()?),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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_ln()
|
||||||
|
} else if self.skip_token(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.parse_let(),
|
||||||
|
Some(Let {
|
||||||
|
name: "test02".into(),
|
||||||
|
ty: Ty::Char,
|
||||||
|
expr: Some(Expr::Literal(Char('6')))
|
||||||
|
})
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parser.parse_static(),
|
||||||
|
Some(Let {
|
||||||
|
name: "test03".into(),
|
||||||
|
ty: Ty::Float,
|
||||||
|
expr: None
|
||||||
|
})
|
||||||
|
);
|
||||||
|
assert_eq!(parser.parse_let(), None);
|
||||||
|
}
|
Reference in New Issue
Block a user