Support if statements AND expressions (pogchamp)

This commit is contained in:
mars 2022-03-02 13:20:27 -07:00
parent 0604818b0e
commit 2beb493aad
1 changed files with 106 additions and 38 deletions

View File

@ -283,31 +283,49 @@ impl<'a> BranchBody<'a> {
pub fn build(lexer: &mut Lexer<'a>) -> Self { pub fn build(lexer: &mut Lexer<'a>) -> Self {
let mut statements = Vec::new(); let mut statements = Vec::new();
let mut tail_expr = None; let mut next = None;
loop { let tail_expr = loop {
let tok = lexer.next().unwrap(); let tok = if let Some(tok) = next {
next = None;
tok
} else {
lexer.next().unwrap()
};
match tok { match tok {
Token::Let => { Token::Let => {
let (statement, next) = Statement::build_let(lexer); let (statement, next) = Statement::build_let(lexer);
statements.push(statement); statements.push(statement);
match next { match next {
Token::Semicolon => {} Token::Semicolon => {}
Token::BraceClose => break, Token::BraceClose => break None,
_ => lexer.panic_message("Unexpected token"), _ => lexer.panic_message("Unexpected token"),
} }
} }
Token::BraceClose => break, Token::If => {
let (stmt, tail) = IfStmt::build(lexer);
if tail == Token::BraceClose {
if let Some(_) = stmt.else_body {
let expr = stmt.to_expr();
break Some(Expr::If(expr));
} else {
statements.push(Statement::If(stmt));
break None;
}
} else {
statements.push(Statement::If(stmt));
next = Some(tail);
}
}
Token::BraceClose => break None,
_ => match Expr::build_start(tok, lexer) { _ => match Expr::build_start(tok, lexer) {
(None, Token::Semicolon | Token::BraceClose) => {} (None, Token::Semicolon | Token::BraceClose) => {}
(Some(expr), Token::Semicolon) => statements.push(Statement::Expr(expr)), (Some(expr), Token::Semicolon) => statements.push(Statement::Expr(expr)),
(Some(expr), Token::BraceClose) => { (Some(expr), Token::BraceClose) => break Some(expr),
tail_expr = Some(expr);
break;
}
_ => lexer.panic_message("Unexpected token"), _ => lexer.panic_message("Unexpected token"),
}, },
} }
} };
Self { Self {
statements, statements,
@ -327,11 +345,7 @@ pub enum Expr<'a> {
SelfMember(&'a str), SelfMember(&'a str),
Group(Box<Expr<'a>>), Group(Box<Expr<'a>>),
FnCall(Box<Expr<'a>>, Vec<Expr<'a>>), FnCall(Box<Expr<'a>>, Vec<Expr<'a>>),
If { If(IfExpr<'a>),
test_expr: Box<Expr<'a>>,
then_body: BranchBody<'a>,
else_body: BranchBody<'a>,
},
} }
impl<'a> Expr<'a> { impl<'a> Expr<'a> {
@ -346,24 +360,7 @@ impl<'a> Expr<'a> {
} }
Self::Group(Box::new(inner.unwrap())) Self::Group(Box::new(inner.unwrap()))
} }
Token::If => { Token::If => Self::If(IfExpr::build(lexer)),
let test_expr = match Self::build(lexer) {
(Some(test_expr), Token::BraceOpen) => Box::new(test_expr),
(None, Token::BraceOpen) => lexer.panic_message("Expected test expression"),
_ => lexer.panic_message("Expected opening brace"),
};
let then_body = BranchBody::build(lexer);
lexer.eat_expect(Token::Else);
lexer.eat_expect(Token::BraceOpen);
let else_body = BranchBody::build(lexer);
Self::If {
test_expr,
then_body,
else_body,
}
}
Token::BinaryInteger => Self::Literal(Literal::BinaryInteger(lexer.slice())), Token::BinaryInteger => Self::Literal(Literal::BinaryInteger(lexer.slice())),
Token::OctalInteger => Self::Literal(Literal::OctalInteger(lexer.slice())), Token::OctalInteger => Self::Literal(Literal::OctalInteger(lexer.slice())),
Token::HexInteger => Self::Literal(Literal::HexInteger(lexer.slice())), Token::HexInteger => Self::Literal(Literal::HexInteger(lexer.slice())),
@ -485,16 +482,12 @@ pub enum Literal<'a> {
#[derive(Debug)] #[derive(Debug)]
pub enum Statement<'a> { pub enum Statement<'a> {
Expr(Expr<'a>), Expr(Expr<'a>),
If(IfStmt<'a>),
Let { Let {
var: &'a str, var: &'a str,
mutable: bool, mutable: bool,
expr: Expr<'a>, expr: Expr<'a>,
}, },
If {
test_expr: Expr<'a>,
then_body: BranchBody<'a>,
else_body: Option<BranchBody<'a>>,
},
} }
impl<'a> Statement<'a> { impl<'a> Statement<'a> {
@ -520,6 +513,81 @@ impl<'a> Statement<'a> {
} }
} }
#[derive(Debug)]
pub struct IfExpr<'a> {
pub test_expr: Box<Expr<'a>>,
pub then_body: BranchBody<'a>,
pub else_body: BranchBody<'a>,
}
impl<'a> IfExpr<'a> {
pub fn build(lexer: &mut Lexer<'a>) -> Self {
let test_expr = Box::new(Self::eat_test_expr(lexer));
let then_body = BranchBody::build(lexer);
lexer.eat_expect(Token::Else);
lexer.eat_expect(Token::BraceOpen);
let else_body = BranchBody::build(lexer);
Self {
test_expr,
then_body,
else_body,
}
}
pub fn eat_test_expr(lexer: &mut Lexer<'a>) -> Expr<'a> {
match Expr::build(lexer) {
(Some(test_expr), Token::BraceOpen) => test_expr,
(Some(_), _) => lexer.panic_message("Expected opening brace"),
_ => lexer.panic_message("Expected test expression"),
}
}
}
#[derive(Debug)]
pub struct IfStmt<'a> {
pub test_expr: Expr<'a>,
pub then_body: BranchBody<'a>,
pub else_body: Option<BranchBody<'a>>,
}
impl<'a> IfStmt<'a> {
pub fn build(lexer: &mut Lexer<'a>) -> (Self, Token) {
let test_expr = IfExpr::eat_test_expr(lexer);
let then_body = BranchBody::build(lexer);
let (else_body, tail) = match lexer.next().unwrap() {
Token::Else => {
lexer.eat_expect(Token::BraceOpen);
(Some(BranchBody::build(lexer)), lexer.next().unwrap())
}
next => (None, next),
};
(
Self {
test_expr,
then_body,
else_body,
},
tail,
)
}
pub fn to_expr(self) -> IfExpr<'a> {
let Self {
test_expr,
then_body,
else_body,
} = self;
IfExpr {
test_expr: Box::new(test_expr),
then_body,
else_body: else_body.unwrap(),
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;