use super::errors::{ParseError, ParseErrorKind, ParseResult};
use crate::compiler::ir::{IrNode, IrSpan, MatchArmExpr};
use crate::compiler::parser::Parser;
use crate::compiler::syntax::SyntaxKind;
impl Parser {
pub(super) fn parse_if_expr(&mut self) -> ParseResult<IrNode> {
let start_byte = self.current_byte_offset();
self.push_context(super::super::Context::template_control_block([
SyntaxKind::BraceColonElseBrace,
SyntaxKind::BraceColonElseIf,
SyntaxKind::BraceSlashIfBrace,
]));
self.consume().ok_or_else(|| {
self.pop_context(); ParseError::unexpected_eof(self.current_byte_offset(), "if-expression opening")
})?;
self.skip_whitespace();
let condition_str = self.collect_rust_until(SyntaxKind::RBrace);
if self.expect(SyntaxKind::RBrace).is_none() {
self.pop_context(); return Err(ParseError::new(
ParseErrorKind::MissingClosingBrace,
self.current_byte_offset(),
)
.with_context("if-expression condition"));
}
let then_expr = self.parse_expr_until_control_continuation()?;
let mut else_if_branches = Vec::new();
while self.at(SyntaxKind::BraceColonElseIf) {
self.consume(); self.skip_whitespace();
let cond_str = self.collect_rust_until(SyntaxKind::RBrace);
self.expect(SyntaxKind::RBrace).ok_or_else(|| {
ParseError::new(
ParseErrorKind::MissingClosingBrace,
self.current_byte_offset(),
)
.with_context("else-if condition")
})?;
let expr = self.parse_expr_until_control_continuation()?;
let cond = Self::str_to_token_stream(&cond_str)
.map_err(|e| e.with_context("else-if condition"))?;
else_if_branches.push((cond, Box::new(expr)));
}
if !self.at(SyntaxKind::BraceColonElseBrace) {
self.pop_context(); return Err(ParseError::new(ParseErrorKind::MissingElseBranch, self.current_byte_offset())
.with_context("if-expression")
.with_help("if-expressions require an {:else} branch to produce a value. Add {:else} expr before {/if}."));
}
self.consume(); let else_expr = self.parse_expr_until_control_continuation()?;
self.skip_whitespace();
self.pop_context();
if !self.at(SyntaxKind::BraceSlashIfBrace) {
return Err(ParseError::new(
ParseErrorKind::UnexpectedToken,
self.current_byte_offset(),
)
.with_expected(&["{/if}"])
.with_context("if-expression"));
}
self.consume();
let condition = Self::str_to_token_stream(&condition_str)
.map_err(|e| e.with_context("if-expression condition"))?;
Ok(IrNode::IfExpr {
span: IrSpan::new(start_byte, self.current_byte_offset()),
condition,
then_expr: Box::new(then_expr),
else_if_branches,
else_expr: Box::new(else_expr),
})
}
pub(super) fn parse_for_expr(&mut self) -> ParseResult<IrNode> {
let start_byte = self.current_byte_offset();
self.push_context(super::super::Context::template_control_block([
SyntaxKind::BraceSlashForBrace,
]));
self.consume().ok_or_else(|| {
self.pop_context(); ParseError::unexpected_eof(self.current_byte_offset(), "for-expression opening")
})?;
self.skip_whitespace();
let mut pattern_str = String::new();
while !self.at_eof() && !self.at(SyntaxKind::InKw) && !self.at(SyntaxKind::RBrace) {
if let Some(token) = self.consume() {
pattern_str.push_str(&token.text);
}
}
if self.expect(SyntaxKind::InKw).is_none() {
self.pop_context(); return Err(ParseError::new(
ParseErrorKind::UnexpectedToken,
self.current_byte_offset(),
)
.with_expected(&["in"])
.with_context("for-expression"));
}
self.skip_whitespace();
let iterator_str = self.collect_rust_until(SyntaxKind::RBrace);
if self.expect(SyntaxKind::RBrace).is_none() {
self.pop_context(); return Err(ParseError::new(
ParseErrorKind::MissingClosingBrace,
self.current_byte_offset(),
)
.with_context("for-expression iterator"));
}
let body_expr = self.parse_expr_until_control_continuation()?;
self.skip_whitespace();
self.pop_context();
if !self.at(SyntaxKind::BraceSlashForBrace) {
return Err(ParseError::new(
ParseErrorKind::UnexpectedToken,
self.current_byte_offset(),
)
.with_expected(&["{/for}"])
.with_context("for-expression"));
}
self.consume();
let pattern = Self::str_to_token_stream(pattern_str.trim())
.map_err(|e| e.with_context("for-expression pattern"))?;
let iterator = Self::str_to_token_stream(&iterator_str)
.map_err(|e| e.with_context("for-expression iterator"))?;
Ok(IrNode::ForExpr {
span: IrSpan::new(start_byte, self.current_byte_offset()),
pattern,
iterator,
body_expr: Box::new(body_expr),
})
}
pub(super) fn parse_while_expr(&mut self) -> ParseResult<IrNode> {
let start_byte = self.current_byte_offset();
self.push_context(super::super::Context::template_control_block([
SyntaxKind::BraceSlashWhileBrace,
]));
self.consume().ok_or_else(|| {
self.pop_context(); ParseError::unexpected_eof(self.current_byte_offset(), "while-expression opening")
})?;
self.skip_whitespace();
let condition_str = self.collect_rust_until(SyntaxKind::RBrace);
if self.expect(SyntaxKind::RBrace).is_none() {
self.pop_context(); return Err(ParseError::new(
ParseErrorKind::MissingClosingBrace,
self.current_byte_offset(),
)
.with_context("while-expression condition"));
}
let body_expr = self.parse_expr_until_control_continuation()?;
self.skip_whitespace();
self.pop_context();
if !self.at(SyntaxKind::BraceSlashWhileBrace) {
return Err(ParseError::new(
ParseErrorKind::UnexpectedToken,
self.current_byte_offset(),
)
.with_expected(&["{/while}"])
.with_context("while-expression"));
}
self.consume();
let condition = Self::str_to_token_stream(&condition_str)
.map_err(|e| e.with_context("while-expression condition"))?;
Ok(IrNode::WhileExpr {
span: IrSpan::new(start_byte, self.current_byte_offset()),
condition,
body_expr: Box::new(body_expr),
})
}
pub(super) fn parse_match_expr(&mut self) -> ParseResult<IrNode> {
let start_byte = self.current_byte_offset();
self.push_context(super::super::Context::template_control_block([
SyntaxKind::BraceSlashMatchBrace,
SyntaxKind::BraceColonCase,
]));
self.consume().ok_or_else(|| {
self.pop_context(); ParseError::unexpected_eof(self.current_byte_offset(), "match-expression opening")
})?;
self.skip_whitespace();
let expr_str = self.collect_rust_until(SyntaxKind::RBrace);
if self.expect(SyntaxKind::RBrace).is_none() {
self.pop_context(); return Err(ParseError::new(
ParseErrorKind::MissingClosingBrace,
self.current_byte_offset(),
)
.with_context("match-expression scrutinee"));
}
let mut arms = Vec::new();
self.skip_whitespace();
while self.at(SyntaxKind::BraceColonCase) {
self.consume(); self.skip_whitespace();
let pattern_str = self.collect_rust_until(SyntaxKind::RBrace);
self.expect(SyntaxKind::RBrace).ok_or_else(|| {
ParseError::new(
ParseErrorKind::MissingClosingBrace,
self.current_byte_offset(),
)
.with_context("match arm pattern")
})?;
let body_expr = self.parse_expr_until_control_continuation()?;
let pattern = Self::str_to_token_stream(&pattern_str)
.map_err(|e| e.with_context("match arm pattern"))?;
arms.push(MatchArmExpr {
span: IrSpan::new(start_byte, self.current_byte_offset()),
pattern,
guard: None, body_expr: Box::new(body_expr),
});
self.skip_whitespace();
}
self.pop_context();
if !self.at(SyntaxKind::BraceSlashMatchBrace) {
return Err(ParseError::new(
ParseErrorKind::UnexpectedToken,
self.current_byte_offset(),
)
.with_expected(&["{/match}"])
.with_context("match-expression"));
}
self.consume();
let expr = Self::str_to_token_stream(&expr_str)
.map_err(|e| e.with_context("match-expression scrutinee"))?;
Ok(IrNode::MatchExpr {
span: IrSpan::new(start_byte, self.current_byte_offset()),
expr,
arms,
})
}
fn parse_expr_until_control_continuation(&mut self) -> ParseResult<IrNode> {
self.skip_whitespace();
let terminators = &[
SyntaxKind::BraceColonElseBrace,
SyntaxKind::BraceColonElseIf,
SyntaxKind::BraceSlashIfBrace,
SyntaxKind::BraceSlashForBrace,
SyntaxKind::BraceSlashWhileBrace,
SyntaxKind::BraceSlashMatchBrace,
SyntaxKind::BraceColonCase,
];
let in_object_literal = self.is_inside_object_literal();
self.parse_expression_until_in_context(terminators, in_object_literal)
}
}
#[cfg(test)]
mod tests {
}