use crate::ast::{
ArrayLiteral, AssignmentExpr, BinaryExpr, CallExpr, ComputedExpr, Expr, FunctionExpr,
MemberExpr, NewExpr, Parameter, PrefixExpr, RangeExpr, Stmt, Type,
};
use crate::error::RelixError;
use crate::lexer::TokenKind;
use crate::lookups::{BindingPower, Lookups};
use crate::parser::Parser;
use crate::stmts::parse_block_stmt;
use crate::types::parse_type;
type FnParamsAndBody = (Vec<Parameter>, Option<Type>, Vec<Stmt>);
pub fn parse_expr(p: &mut Parser, lu: &Lookups, bp: BindingPower) -> Result<Expr, RelixError> {
let token_kind = p.current_token_kind();
let nud_fn = lu.nud.get(&token_kind).ok_or_else(|| {
RelixError::new(format!("NUD Handler expected for token {}\n", token_kind))
})?;
let mut left = nud_fn(p, lu)?;
while lu.bp.get(&p.current_token_kind()).copied().unwrap_or(BindingPower::Default) > bp {
let token_kind = p.current_token_kind();
let led_fn = lu.led.get(&token_kind).ok_or_else(|| {
RelixError::new(format!("LED Handler expected for token {}\n", token_kind))
})?;
left = led_fn(p, lu, left, bp)?;
}
Ok(left)
}
pub fn parse_prefix_expr(p: &mut Parser, lu: &Lookups) -> Result<Expr, RelixError> {
let operator = p.advance();
let right = parse_expr(p, lu, BindingPower::Unary)?;
Ok(Expr::Prefix(PrefixExpr {
operator,
right: Box::new(right),
}))
}
pub fn parse_assignment_expr(
p: &mut Parser,
lu: &Lookups,
left: Expr,
bp: BindingPower,
) -> Result<Expr, RelixError> {
p.advance();
let rhs = parse_expr(p, lu, bp)?;
Ok(Expr::Assignment(AssignmentExpr {
assignee: Box::new(left),
assigned_value: Box::new(rhs),
}))
}
pub fn parse_range_expr(
p: &mut Parser,
lu: &Lookups,
left: Expr,
bp: BindingPower,
) -> Result<Expr, RelixError> {
p.advance();
Ok(Expr::Range(RangeExpr {
lower: Box::new(left),
upper: Box::new(parse_expr(p, lu, bp)?),
}))
}
pub fn parse_binary_expr(
p: &mut Parser,
lu: &Lookups,
left: Expr,
_bp: BindingPower,
) -> Result<Expr, RelixError> {
let operator = p.advance();
let right = parse_expr(p, lu, BindingPower::Default)?;
Ok(Expr::Binary(BinaryExpr {
left: Box::new(left),
operator,
right: Box::new(right),
}))
}
pub fn parse_primary_expr(p: &mut Parser, _lu: &Lookups) -> Result<Expr, RelixError> {
match p.current_token_kind() {
TokenKind::Number => {
let token = p.advance();
let value: f64 = token.value.parse().map_err(|_| {
RelixError::new(format!("Invalid number literal: {}", token.value))
})?;
Ok(Expr::Number(crate::ast::NumberExpr { value }))
}
TokenKind::String => Ok(Expr::String(crate::ast::StringExpr {
value: p.advance().value,
})),
TokenKind::Identifier => Ok(Expr::Symbol(crate::ast::SymbolExpr {
value: p.advance().value,
})),
other => Err(RelixError::new(format!(
"Cannot create primary_expr from {}\n",
other
))),
}
}
pub fn parse_member_expr(
p: &mut Parser,
lu: &Lookups,
left: Expr,
bp: BindingPower,
) -> Result<Expr, RelixError> {
let is_computed = p.advance().kind == TokenKind::OpenBracket;
if is_computed {
let rhs = parse_expr(p, lu, bp)?;
p.expect(TokenKind::CloseBracket)?;
Ok(Expr::Computed(ComputedExpr {
member: Box::new(left),
property: Box::new(rhs),
}))
} else {
Ok(Expr::Member(MemberExpr {
member: Box::new(left),
property: p.expect(TokenKind::Identifier)?.value,
}))
}
}
pub fn parse_array_literal_expr(p: &mut Parser, lu: &Lookups) -> Result<Expr, RelixError> {
p.expect(TokenKind::OpenBracket)?;
let mut contents: Vec<Expr> = Vec::new();
while p.has_tokens() && p.current_token_kind() != TokenKind::CloseBracket {
contents.push(parse_expr(p, lu, BindingPower::Logical)?);
if !p.current_token().is_one_of_many(&[TokenKind::Eof, TokenKind::CloseBracket]) {
p.expect(TokenKind::Comma)?;
}
}
p.expect(TokenKind::CloseBracket)?;
Ok(Expr::Array(ArrayLiteral { contents }))
}
pub fn parse_grouping_expr(p: &mut Parser, lu: &Lookups) -> Result<Expr, RelixError> {
p.expect(TokenKind::OpenParen)?;
let expr = parse_expr(p, lu, BindingPower::Default)?;
p.expect(TokenKind::CloseParen)?;
Ok(expr)
}
pub fn parse_call_expr(
p: &mut Parser,
lu: &Lookups,
left: Expr,
_bp: BindingPower,
) -> Result<Expr, RelixError> {
p.advance();
let mut arguments: Vec<Expr> = Vec::new();
while p.has_tokens() && p.current_token_kind() != TokenKind::CloseParen {
arguments.push(parse_expr(p, lu, BindingPower::Assignment)?);
if !p.current_token().is_one_of_many(&[TokenKind::Eof, TokenKind::CloseParen]) {
p.expect(TokenKind::Comma)?;
}
}
p.expect(TokenKind::CloseParen)?;
Ok(Expr::Call(CallExpr {
method: Box::new(left),
arguments,
}))
}
pub fn parse_fn_expr(p: &mut Parser, lu: &Lookups) -> Result<Expr, RelixError> {
p.expect(TokenKind::Fn)?;
let (parameters, return_type, body) = parse_fn_params_and_body(p, lu)?;
Ok(Expr::Function(FunctionExpr {
parameters,
return_type,
body,
}))
}
pub fn parse_new_expr(p: &mut Parser, lu: &Lookups) -> Result<Expr, RelixError> {
p.advance();
let instantiation = parse_expr(p, lu, BindingPower::Default)?;
let call = match instantiation {
Expr::Call(c) => c,
_ => return Err(RelixError::new("Expected call expression after `new`")),
};
Ok(Expr::New(NewExpr {
instantiation: call,
}))
}
pub fn parse_fn_params_and_body(
p: &mut Parser,
lu: &Lookups,
) -> Result<FnParamsAndBody, RelixError> {
let mut params: Vec<Parameter> = Vec::new();
p.expect(TokenKind::OpenParen)?;
while p.has_tokens() && p.current_token_kind() != TokenKind::CloseParen {
let param_name = p.expect(TokenKind::Identifier)?.value;
p.expect(TokenKind::Colon)?;
let param_type = parse_type(p, lu, BindingPower::Default)?;
params.push(Parameter {
name: param_name,
ty: param_type,
});
if !p.current_token().is_one_of_many(&[TokenKind::CloseParen, TokenKind::Eof]) {
p.expect(TokenKind::Comma)?;
}
}
p.expect(TokenKind::CloseParen)?;
let return_type = if p.current_token_kind() == TokenKind::Colon {
p.advance();
Some(parse_type(p, lu, BindingPower::Default)?)
} else {
None
};
let body = match parse_block_stmt(p, lu)? {
crate::ast::Stmt::Block(b) => b.body,
_ => return Err(RelixError::new("Expected block statement for function body")),
};
Ok((params, return_type, body))
}