use crate::frontend::ast::{Expr, ExprKind, Literal, MatchArm, Pattern, Span, Type};
use crate::frontend::lexer::Token;
use crate::frontend::parser::{bail, parse_expr_recursive, utils, ParserState, Result};
fn parse_variant_pattern_with_name(
state: &mut ParserState,
variant_name: String,
) -> Result<Pattern> {
state.tokens.expect(&Token::LeftParen)?;
let mut patterns = vec![];
if !matches!(state.tokens.peek(), Some((Token::RightParen, _))) {
patterns.push(parse_single_pattern(state)?);
while matches!(state.tokens.peek(), Some((Token::Comma, _))) {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::RightParen, _))) {
break;
}
patterns.push(parse_single_pattern(state)?);
}
}
state.tokens.expect(&Token::RightParen)?;
create_pattern_for_variant(variant_name, patterns)
}
fn create_pattern_for_variant(variant_name: String, patterns: Vec<Pattern>) -> Result<Pattern> {
if patterns.len() == 1 {
match variant_name.as_str() {
"Some" => {
return Ok(Pattern::Some(Box::new(
patterns
.into_iter()
.next()
.expect("patterns.len() == 1 so next() must return Some"),
)))
}
"Ok" => {
return Ok(Pattern::Ok(Box::new(
patterns
.into_iter()
.next()
.expect("patterns.len() == 1 so next() must return Some"),
)))
}
"Err" => {
return Ok(Pattern::Err(Box::new(
patterns
.into_iter()
.next()
.expect("patterns.len() == 1 so next() must return Some"),
)))
}
_ => {}
}
}
Ok(Pattern::TupleVariant {
path: vec![variant_name],
patterns,
})
}
pub(in crate::frontend::parser) fn parse_let_pattern(
state: &mut ParserState,
is_mutable: bool,
) -> Result<Pattern> {
match state.tokens.peek() {
Some((Token::Some, _)) => {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_variant_pattern_with_name(state, "Some".to_string())
} else {
bail!("Some must be followed by parentheses in patterns: Some(value)")
}
}
Some((Token::Ok, _)) => {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_variant_pattern_with_name(state, "Ok".to_string())
} else {
bail!("Ok must be followed by parentheses in patterns: Ok(value)")
}
}
Some((Token::Err, _)) => {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_variant_pattern_with_name(state, "Err".to_string())
} else {
bail!("Err must be followed by parentheses in patterns: Err(value)")
}
}
Some((Token::None, _)) => {
state.tokens.advance();
Ok(Pattern::None)
}
Some((Token::Identifier(name), _)) => {
let name = name.clone();
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_variant_pattern_with_name(state, name)
}
else if matches!(state.tokens.peek(), Some((Token::LeftBrace, _))) {
parse_struct_pattern_with_name(state, name)
} else {
Ok(Pattern::Identifier(name))
}
}
Some((Token::DataFrame, _)) => {
state.tokens.advance();
Ok(Pattern::Identifier("df".to_string()))
}
Some((Token::Default, _)) => {
state.tokens.advance();
Ok(Pattern::Identifier("default".to_string()))
}
Some((Token::Final, _)) => {
state.tokens.advance();
Ok(Pattern::Identifier("final".to_string()))
}
Some((Token::Underscore, _)) => {
state.tokens.advance();
Ok(Pattern::Identifier("_".to_string()))
}
Some((Token::LeftParen, _)) => {
parse_tuple_pattern(state)
}
Some((Token::LeftBracket, _)) => {
parse_list_pattern(state)
}
Some((Token::LeftBrace, _)) => {
parse_struct_pattern(state)
}
_ => bail!(
"Expected identifier or pattern after 'let{}'",
if is_mutable { " mut" } else { "" }
),
}
}
fn parse_let_type_annotation(state: &mut ParserState) -> Result<Option<Type>> {
if matches!(state.tokens.peek(), Some((Token::Colon, _))) {
state.tokens.advance(); Ok(Some(utils::parse_type(state)?))
} else {
Ok(None)
}
}
fn parse_let_else_clause(state: &mut ParserState) -> Result<Option<Box<Expr>>> {
if matches!(state.tokens.peek(), Some((Token::Else, _))) {
state.tokens.advance(); if !matches!(state.tokens.peek(), Some((Token::LeftBrace, _))) {
bail!("let-else requires a block after 'else'");
}
let block = parse_expr_recursive(state)?;
Ok(Some(Box::new(block)))
} else {
Ok(None)
}
}
fn parse_let_in_clause(state: &mut ParserState, value_span: Span) -> Result<Box<Expr>> {
if matches!(state.tokens.peek(), Some((Token::In, _))) {
state.tokens.advance(); Ok(Box::new(parse_expr_recursive(state)?))
} else {
Ok(Box::new(Expr::new(
ExprKind::Literal(Literal::Unit),
value_span,
)))
}
}
fn create_let_expression(
pattern: Pattern,
type_annotation: Option<Type>,
value: Box<Expr>,
body: Box<Expr>,
is_mutable: bool,
else_block: Option<Box<Expr>>,
start_span: Span,
) -> Result<Expr> {
let end_span = body.span;
match &pattern {
Pattern::Identifier(name) => Ok(Expr::new(
ExprKind::Let {
name: name.clone(),
type_annotation,
value,
body,
is_mutable,
else_block,
},
start_span.merge(end_span),
)),
Pattern::Tuple(_) | Pattern::List(_) => {
Ok(Expr::new(
ExprKind::LetPattern {
pattern,
type_annotation,
value,
body,
is_mutable,
else_block,
},
start_span.merge(end_span),
))
}
Pattern::Wildcard
| Pattern::Literal(_)
| Pattern::QualifiedName(_)
| Pattern::Struct { .. }
| Pattern::TupleVariant { .. }
| Pattern::Range { .. }
| Pattern::Or(_)
| Pattern::Rest
| Pattern::RestNamed(_)
| Pattern::AtBinding { .. }
| Pattern::WithDefault { .. }
| Pattern::Ok(_)
| Pattern::Err(_)
| Pattern::Some(_)
| Pattern::None
| Pattern::Mut(_) => {
Ok(Expr::new(
ExprKind::LetPattern {
pattern,
type_annotation,
value,
body,
is_mutable,
else_block,
},
start_span.merge(end_span),
))
}
}
}
pub(in crate::frontend::parser) fn parse_var_statement(state: &mut ParserState) -> Result<Expr> {
super::variable_declarations::parse_var_statement(state)
}
pub(in crate::frontend::parser) fn parse_var_pattern(state: &mut ParserState) -> Result<Pattern> {
match state.tokens.peek() {
Some((Token::Identifier(name), _)) => {
let name = name.clone();
state.tokens.advance();
Ok(Pattern::Identifier(name))
}
Some((Token::DataFrame, _)) => {
state.tokens.advance();
Ok(Pattern::Identifier("df".to_string()))
}
Some((Token::Underscore, _)) => {
state.tokens.advance();
Ok(Pattern::Identifier("_".to_string()))
}
Some((Token::LeftParen, _)) => parse_tuple_pattern(state),
Some((Token::LeftBracket, _)) => parse_list_pattern(state),
_ => bail!("Expected identifier or pattern after 'var'"),
}
}
fn parse_optional_type_annotation(
state: &mut ParserState,
) -> Result<Option<crate::frontend::ast::Type>> {
if matches!(state.tokens.peek(), Some((Token::Colon, _))) {
state.tokens.advance();
Ok(Some(utils::parse_type(state)?))
} else {
Ok(None)
}
}
fn create_var_expression(
pattern: Pattern,
type_annotation: Option<crate::frontend::ast::Type>,
value: Box<Expr>,
start_span: Span,
) -> Result<Expr> {
let body = Box::new(Expr::new(ExprKind::Literal(Literal::Unit), value.span));
let end_span = value.span;
let is_mutable = true;
match &pattern {
Pattern::Identifier(name) => Ok(Expr::new(
ExprKind::Let {
name: name.clone(),
type_annotation,
value,
body,
is_mutable,
else_block: None, },
start_span.merge(end_span),
)),
_ => Ok(Expr::new(
ExprKind::LetPattern {
pattern,
type_annotation,
value,
body,
is_mutable,
else_block: None, },
start_span.merge(end_span),
)),
}
}
pub(in crate::frontend::parser) fn parse_tuple_pattern(state: &mut ParserState) -> Result<Pattern> {
state.tokens.expect(&Token::LeftParen)?;
let mut patterns = Vec::new();
while !matches!(state.tokens.peek(), Some((Token::RightParen, _))) {
let pattern = parse_single_tuple_pattern_element(state)?;
patterns.push(pattern);
if !handle_pattern_separator(state, Token::RightParen)? {
break;
}
}
state.tokens.expect(&Token::RightParen)?;
Ok(Pattern::Tuple(patterns))
}
fn parse_single_tuple_pattern_element(state: &mut ParserState) -> Result<Pattern> {
let is_mut = if matches!(state.tokens.peek(), Some((Token::Mut, _))) {
state.tokens.advance(); true
} else {
false
};
let pattern = match state.tokens.peek() {
Some((Token::Identifier(name), _)) => {
let name = name.clone();
state.tokens.advance();
Ok(Pattern::Identifier(name))
}
Some((Token::LeftParen, _)) => parse_tuple_pattern(state),
Some((Token::LeftBracket, _)) => parse_list_pattern(state),
Some((Token::LeftBrace, _)) => parse_struct_pattern(state),
Some((Token::Underscore, _)) => {
state.tokens.advance();
Ok(Pattern::Wildcard)
}
_ => bail!("Expected identifier, tuple, list, struct, or wildcard in tuple pattern"),
}?;
if is_mut {
Ok(Pattern::Mut(Box::new(pattern)))
} else {
Ok(pattern)
}
}
pub(in crate::frontend::parser) fn parse_struct_pattern(
state: &mut ParserState,
) -> Result<Pattern> {
state.tokens.advance(); parse_struct_pattern_fields(state, String::new())
}
pub(in crate::frontend::parser) fn parse_struct_pattern_with_name(
state: &mut ParserState,
name: String,
) -> Result<Pattern> {
state.tokens.advance(); parse_struct_pattern_fields(state, name)
}
fn parse_struct_pattern_fields(state: &mut ParserState, name: String) -> Result<Pattern> {
let mut fields = Vec::new();
let mut has_rest = false;
while !matches!(state.tokens.peek(), Some((Token::RightBrace, _))) {
if matches!(state.tokens.peek(), Some((Token::DotDot, _))) {
has_rest = parse_struct_rest_pattern(state)?;
break;
}
fields.push(parse_struct_field_pattern(state)?);
if !handle_struct_field_separator(state)? {
break;
}
}
state.tokens.expect(&Token::RightBrace)?;
Ok(Pattern::Struct {
name,
fields,
has_rest,
})
}
fn parse_struct_rest_pattern(state: &mut ParserState) -> Result<bool> {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::Comma, _))) {
state.tokens.advance();
}
if !matches!(state.tokens.peek(), Some((Token::RightBrace, _))) {
bail!("Rest pattern (..) must be the last field in struct pattern");
}
Ok(true)
}
fn parse_struct_field_pattern(
state: &mut ParserState,
) -> Result<crate::frontend::ast::StructPatternField> {
let field_name = match state.tokens.peek() {
Some((Token::Identifier(name), _)) => name.clone(),
Some((Token::Type, _)) => "type".to_string(),
Some((Token::Use, _)) => "use".to_string(),
Some((Token::Mod, _)) => "mod".to_string(),
Some((Token::Async, _)) => "async".to_string(),
Some((Token::Await, _)) => "await".to_string(),
Some((Token::Self_, _)) => "self".to_string(),
Some((Token::Super, _)) => "super".to_string(),
Some((Token::Crate, _)) => "crate".to_string(),
_ => bail!("Expected identifier or '..' in struct pattern"),
};
state.tokens.advance();
let pattern = if matches!(state.tokens.peek(), Some((Token::Colon, _))) {
state.tokens.advance();
Some(parse_match_pattern(state)?)
} else {
None
};
Ok(crate::frontend::ast::StructPatternField {
name: field_name,
pattern,
})
}
fn handle_struct_field_separator(state: &mut ParserState) -> Result<bool> {
if matches!(state.tokens.peek(), Some((Token::Comma, _))) {
state.tokens.advance();
Ok(!matches!(state.tokens.peek(), Some((Token::RightBrace, _))))
} else if matches!(state.tokens.peek(), Some((Token::RightBrace, _))) {
Ok(false)
} else {
bail!("Expected comma or closing brace after struct pattern field")
}
}
pub(in crate::frontend::parser) fn parse_list_pattern(state: &mut ParserState) -> Result<Pattern> {
state.tokens.expect(&Token::LeftBracket)?;
let mut patterns = Vec::new();
while !matches!(state.tokens.peek(), Some((Token::RightBracket, _))) {
let pattern = parse_single_list_pattern_element(state)?;
patterns.push(pattern);
if !handle_pattern_separator(state, Token::RightBracket)? {
break;
}
}
state.tokens.expect(&Token::RightBracket)?;
Ok(Pattern::List(patterns))
}
fn parse_single_list_pattern_element(state: &mut ParserState) -> Result<Pattern> {
match state.tokens.peek() {
Some((Token::Identifier(name), _)) => {
let name = name.clone();
parse_identifier_pattern_with_default(state, name)
}
Some((Token::DotDot, _)) => parse_list_rest_pattern(state),
Some((Token::DotDotDot, _)) => parse_rest_pattern(state),
Some((Token::LeftParen, _)) => parse_tuple_pattern(state),
Some((Token::LeftBracket, _)) => parse_list_pattern(state),
Some((Token::Underscore, _)) => {
state.tokens.advance();
Ok(Pattern::Wildcard)
}
_ => bail!("Expected identifier, tuple, list, wildcard, or rest pattern in list pattern"),
}
}
fn parse_identifier_pattern_with_default(state: &mut ParserState, name: String) -> Result<Pattern> {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::Equal, _))) {
state.tokens.advance(); let default_expr = parse_expr_recursive(state)?;
Ok(Pattern::WithDefault {
pattern: Box::new(Pattern::Identifier(name)),
default: Box::new(default_expr),
})
} else {
Ok(Pattern::Identifier(name))
}
}
fn parse_rest_pattern(state: &mut ParserState) -> Result<Pattern> {
state.tokens.advance(); if let Some((Token::Identifier(name), _)) = state.tokens.peek() {
let name = name.clone();
state.tokens.advance();
Ok(Pattern::RestNamed(name))
} else {
Ok(Pattern::Rest)
}
}
fn handle_pattern_separator(state: &mut ParserState, end_token: Token) -> Result<bool> {
if matches!(state.tokens.peek(), Some((Token::Comma, _))) {
state.tokens.advance();
if let Some((token, _)) = state.tokens.peek() {
if *token == end_token {
return Ok(false);
}
}
Ok(true)
} else if let Some((token, _)) = state.tokens.peek() {
if *token != end_token {
let expected = match end_token {
Token::RightBracket => "',' or ']'",
Token::RightParen => "',' or ')'",
_ => "',' or closing delimiter",
};
bail!("Expected {expected} in pattern");
}
Ok(false)
} else {
bail!("Unexpected end of input in pattern")
}
}
pub(in crate::frontend::parser) fn parse_if_expression(state: &mut ParserState) -> Result<Expr> {
let start_span = state.tokens.expect(&Token::If)?;
if matches!(state.tokens.peek(), Some((Token::Let, _))) {
parse_if_let_expression(state, start_span)
} else {
parse_regular_if_expression(state, start_span)
}
}
fn parse_if_let_expression(state: &mut ParserState, start_span: Span) -> Result<Expr> {
state.tokens.advance(); let pattern = parse_match_pattern(state)
.map_err(|e| anyhow::anyhow!("Expected pattern after 'if let': {e}"))?;
state
.tokens
.expect(&Token::Equal)
.map_err(|e| anyhow::anyhow!("Expected '=' after pattern in if-let: {e}"))?;
let expr = Box::new(
parse_expr_recursive(state)
.map_err(|e| anyhow::anyhow!("Expected expression after '=' in if-let: {e}"))?,
);
let then_branch = Box::new(parse_expr_recursive(state).map_err(|e| {
anyhow::anyhow!("Expected body after if-let condition, typically {{ ... }}: {e}")
})?);
let else_branch = parse_else_branch(state)?;
Ok(Expr::new(
ExprKind::IfLet {
pattern,
expr,
then_branch,
else_branch,
},
start_span,
))
}
fn parse_regular_if_expression(state: &mut ParserState, start_span: Span) -> Result<Expr> {
let condition = Box::new(
parse_expr_recursive(state)
.map_err(|e| anyhow::anyhow!("Expected condition after 'if': {e}"))?,
);
let then_branch = Box::new(parse_expr_recursive(state).map_err(|e| {
anyhow::anyhow!("Expected body after if condition, typically {{ ... }}: {e}")
})?);
let else_branch = parse_else_branch(state)?;
Ok(Expr::new(
ExprKind::If {
condition,
then_branch,
else_branch,
},
start_span,
))
}
fn parse_else_branch(state: &mut ParserState) -> Result<Option<Box<Expr>>> {
if matches!(state.tokens.peek(), Some((Token::Else, _))) {
state.tokens.advance(); if matches!(state.tokens.peek(), Some((Token::If, _))) {
Ok(Some(Box::new(parse_if_expression(state)?)))
} else {
Ok(Some(Box::new(parse_expr_recursive(state).map_err(
|e| anyhow::anyhow!("Expected body after 'else', typically {{ ... }}: {e}"),
)?)))
}
} else {
Ok(None)
}
}
pub(in crate::frontend::parser) fn parse_match_expression(state: &mut ParserState) -> Result<Expr> {
let start_span = state.tokens.expect(&Token::Match)?;
let expr = Box::new(
parse_expr_recursive(state)
.map_err(|e| anyhow::anyhow!("Expected expression after 'match': {e}"))?,
);
state
.tokens
.expect(&Token::LeftBrace)
.map_err(|_| anyhow::anyhow!("Expected '{{' after match expression"))?;
let arms = parse_match_arms(state)?;
state
.tokens
.expect(&Token::RightBrace)
.map_err(|_| anyhow::anyhow!("Expected '}}' after match arms"))?;
Ok(Expr::new(ExprKind::Match { expr, arms }, start_span))
}
fn parse_match_arms(state: &mut ParserState) -> Result<Vec<MatchArm>> {
let mut arms = Vec::new();
while !matches!(state.tokens.peek(), Some((Token::RightBrace, _)) | None) {
let arm = parse_single_match_arm(state)?;
arms.push(arm);
if matches!(state.tokens.peek(), Some((Token::Comma, _))) {
state.tokens.advance();
}
if matches!(state.tokens.peek(), Some((Token::RightBrace, _))) {
break;
}
}
if arms.is_empty() {
bail!("Match expression must have at least one arm");
}
Ok(arms)
}
fn parse_guard_expression(state: &mut ParserState) -> Result<Expr> {
let old_context = state.in_guard_context;
state.in_guard_context = true;
let expr = parse_expr_recursive(state);
state.in_guard_context = old_context;
let expr = expr?;
if !matches!(
state.tokens.peek(),
Some((Token::FatArrow | Token::Arrow, _))
) {
bail!("Guard expression did not stop at match arm delimiter => or ->");
}
Ok(expr)
}
fn parse_single_match_arm(state: &mut ParserState) -> Result<MatchArm> {
let start_span = state.tokens.peek().map(|(_, s)| *s).unwrap_or_default();
let pattern = parse_match_pattern(state)?;
let guard = if matches!(state.tokens.peek(), Some((Token::If, _))) {
state.tokens.advance(); Some(Box::new(parse_guard_expression(state)?))
} else {
None
};
if !matches!(
state.tokens.peek(),
Some((Token::FatArrow | Token::Arrow, _))
) {
bail!("Expected '=>' or '->' in match arm");
}
state.tokens.advance();
let body = Box::new(parse_expr_recursive(state)?);
let end_span = body.span;
Ok(MatchArm {
pattern,
guard,
body,
span: start_span.merge(end_span),
})
}
pub(in crate::frontend::parser) fn parse_match_pattern(state: &mut ParserState) -> Result<Pattern> {
if state.tokens.peek().is_none() {
bail!("Expected pattern in match arm");
}
let pattern = parse_single_pattern(state)?;
if matches!(state.tokens.peek(), Some((Token::Pipe, _))) {
parse_or_pattern(state, pattern)
} else {
Ok(pattern)
}
}
pub(in crate::frontend::parser) fn parse_single_pattern(
state: &mut ParserState,
) -> Result<Pattern> {
let Some((token, _span)) = state.tokens.peek() else {
bail!("Expected pattern");
};
match token {
Token::Underscore => parse_wildcard_pattern(state),
Token::Integer(_)
| Token::Float(_)
| Token::String(_)
| Token::RawString(_)
| Token::Char(_)
| Token::Bool(_)
| Token::Atom(_) => parse_literal_pattern(state),
Token::Some | Token::None => parse_option_pattern(state),
Token::Ok | Token::Err => parse_result_pattern(state),
Token::Identifier(_) | Token::Result | Token::Var => {
parse_identifier_or_constructor_pattern(state)
}
Token::LeftParen => parse_match_tuple_pattern(state),
Token::LeftBracket => parse_match_list_pattern(state),
Token::LeftBrace => parse_struct_pattern(state),
_ => bail!("Unexpected token in pattern: {token:?}"),
}
}
fn parse_wildcard_pattern(state: &mut ParserState) -> Result<Pattern> {
state.tokens.advance();
Ok(Pattern::Wildcard)
}
fn parse_literal_pattern(state: &mut ParserState) -> Result<Pattern> {
let Some((token, _span)) = state.tokens.peek() else {
bail!("Expected literal pattern");
};
let token = token.clone(); let pattern = match token {
Token::Integer(val) => parse_integer_literal_pattern(state, val)?,
Token::Float(val) => parse_simple_literal_pattern(state, Literal::Float(val))?,
Token::String(s) => parse_simple_literal_pattern(state, Literal::String(s))?,
Token::RawString(s) => parse_simple_literal_pattern(state, Literal::String(s))?,
Token::Char(c) => parse_char_literal_pattern(state, c)?,
Token::Byte(b) => parse_simple_literal_pattern(state, Literal::Byte(b))?,
Token::Bool(b) => parse_simple_literal_pattern(state, Literal::Bool(b))?,
Token::Atom(s) => parse_simple_literal_pattern(state, Literal::Atom(s))?,
_ => bail!("Expected literal pattern, got: {token:?}"),
};
Ok(pattern)
}
fn parse_integer_literal_pattern(state: &mut ParserState, val: String) -> Result<Pattern> {
state.tokens.advance();
let (num_part, type_suffix) = if let Some(pos) = val.find(|c: char| c.is_alphabetic()) {
(&val[..pos], Some(val[pos..].to_string()))
} else {
(val.as_str(), None)
};
let parsed_val = num_part
.parse::<i64>()
.map_err(|_| anyhow::anyhow!("Invalid integer literal: {num_part}"))?;
match state.tokens.peek() {
Some((Token::DotDot, _)) => parse_integer_range_pattern(state, parsed_val, false),
Some((Token::DotDotEqual, _)) => parse_integer_range_pattern(state, parsed_val, true),
_ => Ok(Pattern::Literal(Literal::Integer(parsed_val, type_suffix))),
}
}
fn parse_integer_range_pattern(
state: &mut ParserState,
start_val: i64,
inclusive: bool,
) -> Result<Pattern> {
state.tokens.advance(); if let Some((Token::Integer(end_val_str), _)) = state.tokens.peek() {
let end_val_str = end_val_str.clone();
state.tokens.advance();
let (num_part, _type_suffix) =
if let Some(pos) = end_val_str.find(|c: char| c.is_alphabetic()) {
(&end_val_str[..pos], Some(end_val_str[pos..].to_string()))
} else {
(end_val_str.as_str(), None)
};
let end_val = num_part
.parse::<i64>()
.map_err(|_| anyhow::anyhow!("Invalid integer literal: {num_part}"))?;
Ok(Pattern::Range {
start: Box::new(Pattern::Literal(Literal::Integer(start_val, None))),
end: Box::new(Pattern::Literal(Literal::Integer(end_val, None))),
inclusive,
})
} else {
bail!("Expected integer after range operator");
}
}
fn parse_char_literal_pattern(state: &mut ParserState, val: char) -> Result<Pattern> {
state.tokens.advance();
match state.tokens.peek() {
Some((Token::DotDot, _)) => parse_char_range_pattern(state, val, false),
Some((Token::DotDotEqual, _)) => parse_char_range_pattern(state, val, true),
_ => Ok(Pattern::Literal(Literal::Char(val))),
}
}
fn parse_char_range_pattern(
state: &mut ParserState,
start_val: char,
inclusive: bool,
) -> Result<Pattern> {
state.tokens.advance(); if let Some((Token::Char(end_val), _)) = state.tokens.peek() {
let end_val = *end_val;
state.tokens.advance();
Ok(Pattern::Range {
start: Box::new(Pattern::Literal(Literal::Char(start_val))),
end: Box::new(Pattern::Literal(Literal::Char(end_val))),
inclusive,
})
} else {
bail!("Expected char after range operator");
}
}
fn parse_simple_literal_pattern(state: &mut ParserState, literal: Literal) -> Result<Pattern> {
state.tokens.advance();
Ok(Pattern::Literal(literal))
}
fn parse_option_pattern(state: &mut ParserState) -> Result<Pattern> {
let Some((token, _span)) = state.tokens.peek() else {
bail!("Expected Option pattern");
};
match token {
Token::Some => {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_constructor_pattern(state, "Some".to_string())
} else {
Ok(Pattern::Identifier("Some".to_string()))
}
}
Token::None => {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_constructor_pattern(state, "None".to_string())
} else {
Ok(Pattern::Identifier("None".to_string()))
}
}
_ => bail!("Expected Some or None pattern"),
}
}
fn parse_result_pattern(state: &mut ParserState) -> Result<Pattern> {
let Some((token, _span)) = state.tokens.peek() else {
bail!("Expected Result pattern");
};
match token {
Token::Ok => {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_constructor_pattern(state, "Ok".to_string())
} else {
Ok(Pattern::Identifier("Ok".to_string()))
}
}
Token::Err => {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_constructor_pattern(state, "Err".to_string())
} else {
Ok(Pattern::Identifier("Err".to_string()))
}
}
_ => bail!("Expected Ok or Err pattern"),
}
}
fn parse_identifier_or_constructor_pattern(state: &mut ParserState) -> Result<Pattern> {
let name = match state.tokens.peek() {
Some((Token::Identifier(n), _)) => n.clone(),
Some((Token::Result, _)) => "Result".to_string(),
Some((Token::Var, _)) => "var".to_string(),
_ => bail!("Expected identifier pattern"),
};
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::At, _))) {
state.tokens.advance();
let inner_pattern = parse_single_pattern(state)?;
return Ok(Pattern::AtBinding {
name,
pattern: Box::new(inner_pattern),
});
}
if matches!(state.tokens.peek(), Some((Token::ColonColon, _))) {
let full_path = super::identifiers::parse_module_path_segments(state, name)?;
return if matches!(state.tokens.peek(), Some((Token::LeftBrace, _))) {
parse_struct_pattern_with_name(state, full_path)
} else if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_constructor_pattern(state, full_path)
} else {
let path_segments: Vec<String> =
full_path.split("::").map(ToString::to_string).collect();
Ok(Pattern::QualifiedName(path_segments))
};
}
if matches!(state.tokens.peek(), Some((Token::LeftBrace, _))) {
parse_struct_pattern_with_name(state, name)
}
else if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_constructor_pattern(state, name)
} else {
Ok(Pattern::Identifier(name))
}
}
fn parse_match_tuple_pattern(state: &mut ParserState) -> Result<Pattern> {
state.tokens.expect(&Token::LeftParen)?;
if matches!(state.tokens.peek(), Some((Token::RightParen, _))) {
state.tokens.advance();
return Ok(Pattern::Tuple(vec![]));
}
let mut patterns = vec![parse_match_pattern(state)?];
while matches!(state.tokens.peek(), Some((Token::Comma, _))) {
state.tokens.advance(); if matches!(state.tokens.peek(), Some((Token::RightParen, _))) {
break; }
patterns.push(parse_match_pattern(state)?);
}
state.tokens.expect(&Token::RightParen)?;
Ok(Pattern::Tuple(patterns))
}
fn parse_list_rest_pattern(state: &mut ParserState) -> Result<Pattern> {
state.tokens.advance(); if let Some((Token::Identifier(name), _)) = state.tokens.peek() {
let name = name.clone();
state.tokens.advance();
Ok(Pattern::RestNamed(name))
} else {
Ok(Pattern::Rest)
}
}
fn parse_list_pattern_element(state: &mut ParserState) -> Result<Pattern> {
if matches!(state.tokens.peek(), Some((Token::DotDot, _))) {
parse_list_rest_pattern(state)
} else if matches!(state.tokens.peek(), Some((Token::DotDotDot, _))) {
parse_rest_pattern(state)
} else {
parse_match_pattern(state)
}
}
fn parse_match_list_pattern(state: &mut ParserState) -> Result<Pattern> {
state.tokens.expect(&Token::LeftBracket)?;
if matches!(state.tokens.peek(), Some((Token::RightBracket, _))) {
state.tokens.advance();
return Ok(Pattern::List(vec![]));
}
let mut patterns = vec![];
loop {
patterns.push(parse_list_pattern_element(state)?);
if matches!(state.tokens.peek(), Some((Token::Comma, _))) {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::RightBracket, _))) {
break; }
} else {
break;
}
}
state.tokens.expect(&Token::RightBracket)?;
Ok(Pattern::List(patterns))
}
fn parse_constructor_pattern(state: &mut ParserState, name: String) -> Result<Pattern> {
state.tokens.expect(&Token::LeftParen)?;
let patterns = parse_constructor_arguments(state)?;
state.tokens.expect(&Token::RightParen)?;
create_constructor_pattern(name, patterns)
}
fn parse_constructor_arguments(state: &mut ParserState) -> Result<Vec<Pattern>> {
if matches!(state.tokens.peek(), Some((Token::RightParen, _))) {
return Ok(vec![]);
}
let mut patterns = vec![parse_match_pattern(state)?];
while matches!(state.tokens.peek(), Some((Token::Comma, _))) {
state.tokens.advance(); if matches!(state.tokens.peek(), Some((Token::RightParen, _))) {
break; }
patterns.push(parse_match_pattern(state)?);
}
Ok(patterns)
}
fn create_constructor_pattern(name: String, patterns: Vec<Pattern>) -> Result<Pattern> {
match (name.as_str(), patterns.len()) {
("Ok", 1) => {
Ok(Pattern::Ok(Box::new(patterns.into_iter().next().expect(
"patterns.len() == 1, so next() must return Some",
))))
}
("Err", 1) => {
Ok(Pattern::Err(Box::new(patterns.into_iter().next().expect(
"patterns.len() == 1, so next() must return Some",
))))
}
("Some", 1) => {
Ok(Pattern::Some(Box::new(patterns.into_iter().next().expect(
"patterns.len() == 1, so next() must return Some",
))))
}
("None", 0) => {
Ok(Pattern::None)
}
(name, 0) => {
if name.contains("::") {
let path: Vec<String> = name.split("::").map(ToString::to_string).collect();
Ok(Pattern::QualifiedName(path))
} else {
Ok(Pattern::Identifier(name.to_string()))
}
}
(name, _) => {
let path: Vec<String> = name.split("::").map(ToString::to_string).collect();
Ok(Pattern::TupleVariant { path, patterns })
}
}
}
fn parse_or_pattern(state: &mut ParserState, first: Pattern) -> Result<Pattern> {
let mut patterns = vec![first];
while matches!(state.tokens.peek(), Some((Token::Pipe, _))) {
state.tokens.advance(); let next = parse_single_pattern(state)?;
patterns.push(next);
}
if patterns.len() == 1 {
Ok(patterns
.into_iter()
.next()
.expect("patterns.len() == 1, so next() must return Some"))
} else {
Ok(Pattern::Or(patterns))
}
}
#[cfg(test)]
#[path = "patterns_tests.rs"]
mod tests;
#[cfg(test)]
#[path = "patterns_tests_part2.rs"]
mod tests_part2;