use super::{
bail, parse_expr_recursive, Expr, ExprKind, Literal, ParserState, Pattern, Result, Span, Token,
};
#[path = "expressions_helpers/mod.rs"]
pub(in crate::frontend::parser) mod expressions_helpers;
pub fn parse_prefix(state: &mut ParserState) -> Result<Expr> {
let Some((token, span)) = state.tokens.peek() else {
bail!("Unexpected end of input - expected expression");
};
let token = token.clone();
let span = *span;
dispatch_prefix_token(state, token, span)
}
fn dispatch_prefix_token(state: &mut ParserState, token: Token, span: Span) -> Result<Expr> {
match token {
Token::Integer(_)
| Token::HexInteger(_)
| Token::Float(_)
| Token::String(_)
| Token::RawString(_)
| Token::FString(_)
| Token::Char(_)
| Token::Byte(_)
| Token::Bool(_)
| Token::Atom(_)
| Token::Null
| Token::None
| Token::Some => parse_literal_prefix(state, token, span),
Token::Minus
| Token::Plus
| Token::Bang
| Token::Star
| Token::Ampersand
| Token::Power
| Token::Await
| Token::Tilde
| Token::Spawn => {
expressions_helpers::unary_operators::parse_unary_prefix(state, token, span)
}
Token::DotDot | Token::DotDotEqual => parse_prefix_range(state, token, span),
Token::Identifier(_)
| Token::Underscore
| Token::Self_
| Token::Super
| Token::Default
| Token::Result => parse_identifier_prefix(state, token, span),
Token::Fun
| Token::Fn
| Token::LeftBrace
| Token::Let
| Token::Var
| Token::Mod
| Token::Module
| Token::At => parse_declaration_prefix(state, token, span),
Token::If
| Token::Match
| Token::While
| Token::For
| Token::Try
| Token::Loop
| Token::Lifetime(_)
| Token::Label(_) => parse_control_prefix(state, token, span),
Token::Struct
| Token::Class
| Token::Trait
| Token::Interface
| Token::Impl
| Token::Type
| Token::DataFrame
| Token::Actor
| Token::Effect
| Token::Handle => parse_structure_prefix(state, token, span),
Token::Import
| Token::From
| Token::Use
| Token::Pub
| Token::Const
| Token::Sealed
| Token::Final
| Token::Abstract
| Token::Unsafe
| Token::Break
| Token::Continue
| Token::Return
| Token::Throw
| Token::Export
| Token::Async
| Token::Lazy
| Token::Increment
| Token::Decrement => parse_modifier_prefix(state, token, span),
Token::Pipe
| Token::OrOr
| Token::Backslash
| Token::LeftParen
| Token::LeftBracket
| Token::Enum
| Token::Ok
| Token::Err
| Token::Option => parse_collection_prefix(state, token, span),
_ => bail!("Unexpected token: {token:?}"),
}
}
fn parse_literal_prefix(state: &mut ParserState, token: Token, span: Span) -> Result<Expr> {
match token {
Token::Integer(_)
| Token::HexInteger(_)
| Token::Float(_)
| Token::String(_)
| Token::RawString(_)
| Token::FString(_)
| Token::Char(_)
| Token::Byte(_)
| Token::Bool(_)
| Token::Atom(_) => expressions_helpers::literals::parse_literal_token(state, &token, span),
Token::Null => expressions_helpers::literals::parse_null(state, span),
Token::None => expressions_helpers::literals::parse_none(state, span),
Token::Some => expressions_helpers::literals::parse_some_constructor(state, span),
_ => unreachable!(),
}
}
fn parse_identifier_prefix(state: &mut ParserState, token: Token, span: Span) -> Result<Expr> {
match token {
Token::Identifier(_) | Token::Underscore | Token::Self_ | Token::Super => {
expressions_helpers::identifiers::parse_identifier_token(state, &token, span)
}
Token::Default => {
state.tokens.advance();
Ok(Expr::new(ExprKind::Identifier("default".to_string()), span))
}
Token::Result => {
state.tokens.advance();
Ok(Expr::new(ExprKind::Identifier("Result".to_string()), span))
}
_ => unreachable!(),
}
}
fn parse_declaration_prefix(state: &mut ParserState, token: Token, _span: Span) -> Result<Expr> {
match token {
Token::Fun | Token::Fn | Token::LeftBrace => parse_function_block_token(state, token),
Token::Let | Token::Var => parse_variable_declaration_token(state, token),
Token::Mod | Token::Module => parse_module_declaration(state),
Token::At => parse_decorator_prefix(state),
_ => unreachable!(),
}
}
fn parse_decorator_prefix(state: &mut ParserState) -> Result<Expr> {
let decorators = expressions_helpers::classes::parse_decorators(state)?;
let mut expr = parse_prefix(state)?;
if let ExprKind::Class {
decorators: ref mut class_decorators,
..
} = &mut expr.kind
{
*class_decorators = decorators;
}
Ok(expr)
}
fn parse_control_prefix(state: &mut ParserState, token: Token, _span: Span) -> Result<Expr> {
match token {
Token::If | Token::Match | Token::While | Token::For | Token::Try | Token::Loop => {
parse_control_flow_token(state, token)
}
Token::Lifetime(label_name) => {
state.tokens.advance(); let stripped_label = label_name
.strip_prefix('\'')
.unwrap_or(&label_name)
.to_string();
parse_loop_label(state, stripped_label)
}
Token::Label(label_name) => {
state.tokens.advance(); if matches!(state.tokens.peek(), Some((Token::Colon, _))) {
parse_loop_label(state, label_name)
} else {
parse_label_as_decorator(state, label_name)
}
}
_ => unreachable!(),
}
}
fn parse_label_as_decorator(state: &mut ParserState, label_name: String) -> Result<Expr> {
use crate::frontend::ast::{Attribute, Decorator};
let first_span = state.tokens.peek().map_or(Span::new(0, 0), |(_, s)| *s);
let name = label_name
.strip_prefix('@')
.unwrap_or(&label_name)
.to_string();
let args = if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_decorator_args_inline(state)?
} else {
Vec::new()
};
let mut attributes = vec![Attribute {
name,
args,
span: first_span,
}];
let mut decorators = vec![];
while let Some((Token::Label(next_label), next_span)) = state.tokens.peek() {
let next_label = next_label.clone();
let next_span = *next_span;
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::Colon, _))) {
bail!("Unexpected labeled loop after decorator");
}
let next_name = next_label
.strip_prefix('@')
.unwrap_or(&next_label)
.to_string();
let next_args = if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_decorator_args_inline(state)?
} else {
Vec::new()
};
attributes.push(Attribute {
name: next_name.clone(),
args: next_args.clone(),
span: next_span,
});
decorators.push(Decorator {
name: next_name,
args: next_args,
});
}
while let Some((Token::At, at_span)) = state.tokens.peek() {
let at_span = *at_span;
state.tokens.advance(); let dec_name = match state.tokens.peek() {
Some((Token::Identifier(n), _)) => {
let name = n.clone();
state.tokens.advance();
name
}
_ => bail!("Expected identifier after '@'"),
};
let dec_args = if matches!(state.tokens.peek(), Some((Token::LeftParen, _))) {
parse_decorator_args_inline(state)?
} else {
Vec::new()
};
attributes.push(Attribute {
name: dec_name.clone(),
args: dec_args.clone(),
span: at_span,
});
decorators.push(Decorator {
name: dec_name,
args: dec_args,
});
}
let mut expr = parse_prefix(state)?;
expr.attributes.extend(attributes);
if let ExprKind::Class {
decorators: class_decorators,
..
} = &mut expr.kind
{
let first_dec = Decorator {
name: label_name
.strip_prefix('@')
.unwrap_or(&label_name)
.to_string(),
args: if let Some(attr) = expr.attributes.first() {
attr.args.clone()
} else {
Vec::new()
},
};
let mut all_decorators = vec![first_dec];
all_decorators.extend(decorators);
*class_decorators = all_decorators;
}
Ok(expr)
}
fn parse_decorator_args_inline(state: &mut ParserState) -> Result<Vec<String>> {
state.tokens.advance(); let mut args = Vec::new();
while !matches!(state.tokens.peek(), Some((Token::RightParen, _))) {
match state.tokens.peek() {
Some((Token::String(s), _)) => {
args.push(s.clone());
state.tokens.advance();
}
Some((Token::Identifier(id), _)) => {
args.push(id.clone());
state.tokens.advance();
}
_ => bail!("Expected string or identifier in decorator arguments"),
}
if matches!(state.tokens.peek(), Some((Token::Comma, _))) {
state.tokens.advance();
}
}
state.tokens.expect(&Token::RightParen)?;
Ok(args)
}
fn parse_loop_label(state: &mut ParserState, label_name: String) -> Result<Expr> {
expressions_helpers::loops::parse_loop_label(state, label_name)
}
fn parse_structure_prefix(state: &mut ParserState, token: Token, span: Span) -> Result<Expr> {
match token {
Token::Struct
| Token::Class
| Token::Trait
| Token::Interface
| Token::Impl
| Token::Type => parse_data_structure_token(state, token),
Token::DataFrame | Token::Actor | Token::Effect | Token::Handle => {
parse_special_definition_token(state, token, span)
}
_ => unreachable!(),
}
}
fn parse_modifier_prefix(state: &mut ParserState, token: Token, span: Span) -> Result<Expr> {
match token {
Token::Import | Token::From | Token::Use => parse_import_token(state, token),
_ => parse_control_statement_token(state, token, span),
}
}
fn parse_collection_prefix(state: &mut ParserState, token: Token, span: Span) -> Result<Expr> {
match token {
Token::Pipe | Token::OrOr | Token::Backslash => parse_lambda_token(state, token),
Token::LeftParen => expressions_helpers::tuples::parse_parentheses_token(state, span),
Token::LeftBracket | Token::Enum => parse_collection_enum_token(state, token),
Token::Ok | Token::Err | Token::Result | Token::Option => {
parse_constructor_token(state, token, span)
}
_ => unreachable!(),
}
}
fn parse_constructor_token(state: &mut ParserState, token: Token, span: Span) -> Result<Expr> {
expressions_helpers::increment_decrement::parse_constructor_token(state, token, span)
}
fn parse_control_flow_token(state: &mut ParserState, token: Token) -> Result<Expr> {
match token {
Token::If => parse_if_expression(state),
Token::Match => parse_match_expression(state),
Token::While => parse_while_loop(state),
Token::For => parse_for_loop(state),
Token::Try => parse_try_catch(state),
Token::Loop => parse_loop(state),
_ => bail!("Expected control flow token, got: {token:?}"),
}
}
fn parse_try_catch(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::error_handling::parse_try_catch(state)
}
fn parse_module_declaration(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::modules::parse_module_declaration(state)
}
fn parse_data_structure_token(state: &mut ParserState, token: Token) -> Result<Expr> {
match token {
Token::Struct => parse_struct_definition(state),
Token::Class => parse_struct_definition(state), Token::Trait => parse_trait_definition(state),
Token::Interface => parse_trait_definition(state), Token::Impl => parse_impl_block(state),
Token::Type => parse_type_alias(state),
_ => bail!("Expected data structure token, got: {token:?}"),
}
}
fn parse_import_token(state: &mut ParserState, token: Token) -> Result<Expr> {
match token {
Token::Import => {
state.tokens.advance();
if matches!(state.tokens.peek(), Some((Token::LeftBrace, _))) {
super::imports::parse_js_style_import(state)
} else {
super::imports::parse_import_statement(state)
}
}
Token::From => {
state.tokens.advance();
super::imports::parse_from_import_statement(state)
}
Token::Use => parse_use_statement(state),
_ => bail!("Expected import token, got: {token:?}"),
}
}
fn parse_lambda_token(state: &mut ParserState, token: Token) -> Result<Expr> {
match token {
Token::Pipe => parse_lambda_expression(state),
Token::OrOr => parse_lambda_no_params(state),
Token::Backslash => super::functions::parse_lambda(state),
_ => bail!("Expected lambda token, got: {token:?}"),
}
}
fn parse_function_block_token(state: &mut ParserState, token: Token) -> Result<Expr> {
match token {
Token::Fun | Token::Fn => super::functions::parse_function(state),
Token::LeftBrace => super::collections::parse_block(state),
_ => bail!("Expected function/block token, got: {token:?}"),
}
}
fn parse_variable_declaration_token(state: &mut ParserState, token: Token) -> Result<Expr> {
match token {
Token::Let => parse_let_statement(state),
Token::Var => parse_var_statement(state),
_ => bail!("Expected variable declaration token, got: {token:?}"),
}
}
fn parse_special_definition_token(
state: &mut ParserState,
token: Token,
span: Span,
) -> Result<Expr> {
match token {
Token::DataFrame => expressions_helpers::dataframes::parse_dataframe_token(state, span),
Token::Actor => parse_actor_definition(state),
Token::Effect => parse_effect_definition(state),
Token::Handle => parse_handler_expression(state),
_ => bail!("Expected special definition token, got: {token:?}"),
}
}
fn parse_control_statement_token(
state: &mut ParserState,
token: Token,
span: Span,
) -> Result<Expr> {
match token {
Token::Pub => expressions_helpers::visibility_modifiers::parse_pub_token(state, span),
Token::Const => expressions_helpers::visibility_modifiers::parse_const_token(state, span),
Token::Sealed => expressions_helpers::visibility_modifiers::parse_sealed_token(state, span),
Token::Final => expressions_helpers::visibility_modifiers::parse_final_token(state, span),
Token::Abstract => {
expressions_helpers::visibility_modifiers::parse_abstract_token(state, span)
}
Token::Unsafe => expressions_helpers::visibility_modifiers::parse_unsafe_token(state, span),
Token::Break => expressions_helpers::control_flow::parse_break_token(state, span),
Token::Continue => expressions_helpers::control_flow::parse_continue_token(state, span),
Token::Return => expressions_helpers::control_flow::parse_return_token(state, span),
Token::Throw => expressions_helpers::control_flow::parse_throw_token(state, span),
Token::Export => parse_export_token(state),
Token::Async => parse_async_token(state),
Token::Lazy => parse_lazy_token(state),
Token::Increment => parse_increment_token(state, span),
Token::Decrement => parse_decrement_token(state, span),
_ => bail!("Expected control statement token, got: {token:?}"),
}
}
fn parse_collection_enum_token(state: &mut ParserState, token: Token) -> Result<Expr> {
match token {
Token::LeftBracket => expressions_helpers::arrays::parse_list_literal(state),
Token::Enum => parse_enum_definition(state),
_ => bail!("Expected collection/enum token, got: {token:?}"),
}
}
fn parse_let_statement(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::variable_declarations::parse_let_statement(state)
}
fn parse_let_mutability(state: &mut ParserState) -> bool {
if matches!(state.tokens.peek(), Some((Token::Mut, _))) {
state.tokens.advance();
true
} else {
false
}
}
fn parse_let_pattern(state: &mut ParserState, is_mutable: bool) -> Result<Pattern> {
expressions_helpers::patterns::parse_let_pattern(state, is_mutable)
}
fn parse_var_pattern(state: &mut ParserState) -> Result<Pattern> {
expressions_helpers::patterns::parse_var_pattern(state)
}
pub fn parse_tuple_pattern(state: &mut ParserState) -> Result<Pattern> {
expressions_helpers::patterns::parse_tuple_pattern(state)
}
pub fn parse_struct_pattern(state: &mut ParserState) -> Result<Pattern> {
expressions_helpers::patterns::parse_struct_pattern(state)
}
pub fn parse_list_pattern(state: &mut ParserState) -> Result<Pattern> {
expressions_helpers::patterns::parse_list_pattern(state)
}
fn parse_match_pattern(state: &mut ParserState) -> Result<Pattern> {
expressions_helpers::patterns::parse_match_pattern(state)
}
fn parse_if_expression(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::patterns::parse_if_expression(state)
}
fn parse_match_expression(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::patterns::parse_match_expression(state)
}
fn parse_var_statement(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::patterns::parse_var_statement(state)
}
fn parse_while_loop(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::loops::parse_while_loop(state)
}
fn parse_for_loop(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::loops::parse_for_loop(state)
}
fn parse_loop(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::loops::parse_loop(state)
}
fn parse_lambda_no_params(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::lambdas::parse_lambda_no_params(state)
}
fn parse_lambda_from_expr(state: &mut ParserState, expr: Expr, start_span: Span) -> Result<Expr> {
expressions_helpers::lambdas::parse_lambda_from_expr(state, expr, start_span)
}
fn parse_lambda_expression(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::lambdas::parse_lambda_expression(state)
}
fn parse_type_alias(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::type_aliases::parse_type_alias(state)
}
pub(super) fn parse_optional_generics(state: &mut ParserState) -> Result<Vec<String>> {
expressions_helpers::type_aliases::parse_optional_generics(state)
}
fn parse_struct_definition(state: &mut ParserState) -> Result<Expr> {
let (is_class, start_span) = match state.tokens.peek().map(|(t, s)| (t.clone(), *s)) {
Some((Token::Struct, span)) => {
state.tokens.advance();
(false, span)
}
Some((Token::Class, span)) => {
state.tokens.advance();
(true, span)
}
_ => bail!("Expected 'struct' or 'class' keyword"),
};
let name = expressions_helpers::structs::parse_struct_name(state)?;
let type_params = parse_optional_generics(state)?;
if is_class {
expressions_helpers::classes::parse_class_definition(state, name, type_params, start_span)
} else {
expressions_helpers::structs::parse_struct_variant(state, name, type_params, start_span)
}
}
fn parse_trait_definition(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::traits::parse_trait_definition(state)
}
fn parse_impl_block(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::impls::parse_impl_block(state)
}
fn parse_use_statement(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::use_statements::parse_use_statement(state)
}
pub(super) fn parse_from_import_statement(state: &mut ParserState) -> Result<Expr> {
super::imports::parse_from_import_statement(state)
}
pub(super) fn parse_use_path(
state: &mut ParserState,
start_span: crate::frontend::ast::Span,
) -> Result<Expr> {
expressions_helpers::use_statements::parse_use_path(state, start_span)
}
fn parse_enum_definition(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::enums::parse_enum_definition(state)
}
fn parse_actor_definition(state: &mut ParserState) -> Result<Expr> {
super::actors::parse_actor(state)
}
fn parse_effect_definition(state: &mut ParserState) -> Result<Expr> {
super::effects::parse_effect(state)
}
fn parse_handler_expression(state: &mut ParserState) -> Result<Expr> {
super::effects::parse_handler(state)
}
pub use expressions_helpers::binary_operators::{get_precedence, token_to_binary_op};
fn parse_export_token(state: &mut ParserState) -> Result<Expr> {
super::utils::parse_export(state)
}
fn parse_async_token(state: &mut ParserState) -> Result<Expr> {
expressions_helpers::async_expressions::parse_async_token(state)
}
fn parse_lazy_token(state: &mut ParserState) -> Result<Expr> {
state.tokens.advance();
let expr = parse_expr_recursive(state)?;
let start_span = expr.span;
Ok(Expr::new(
ExprKind::Lazy {
expr: Box::new(expr),
},
start_span,
))
}
fn parse_increment_token(state: &mut ParserState, span: Span) -> Result<Expr> {
expressions_helpers::increment_decrement::parse_increment_token(state, span)
}
fn parse_decrement_token(state: &mut ParserState, span: Span) -> Result<Expr> {
expressions_helpers::increment_decrement::parse_decrement_token(state, span)
}
fn parse_prefix_range(state: &mut ParserState, token: Token, _span: Span) -> Result<Expr> {
let inclusive = matches!(token, Token::DotDotEqual);
state.tokens.advance();
let end = match state.tokens.peek() {
Some((
Token::RightBracket
| Token::Semicolon
| Token::Comma
| Token::RightParen
| Token::RightBrace,
_,
)) => {
Expr::new(ExprKind::Literal(Literal::Unit), Span { start: 0, end: 0 })
}
_ => {
super::parse_expr_with_precedence_recursive(state, 6)? }
};
Ok(Expr {
kind: ExprKind::Range {
start: Box::new(Expr::new(
ExprKind::Literal(Literal::Unit),
Span { start: 0, end: 0 },
)),
end: Box::new(end),
inclusive,
},
span: Span { start: 0, end: 0 },
attributes: Vec::new(),
leading_comments: Vec::new(),
trailing_comment: None,
})
}
#[cfg(test)]
#[path = "expressions_tests.rs"]
mod tests;