use super::stream::TokenStream;
use crate::core::*;
use crate::lexer::TokenType;
use crate::trace;
use anyhow::{anyhow, Result};
pub fn parse_statement(s: &mut TokenStream) -> Result<Statement> {
trace!(
"parse_statement: starting at position {} ({})",
s.position(),
s.current_token_info()
);
if let Some(stmt) = s.try_parse(parse_macro)? {
trace!("parse_statement: success - parsed macro");
return Ok(stmt);
}
if let Some(stmt) = s.try_parse(parse_var_declaration)? {
trace!("parse_statement: success - parsed var declaration");
return Ok(stmt);
}
if let Some(stmt) = s.try_parse(parse_function_declaration)? {
trace!("parse_statement: success - parsed function declaration");
return Ok(stmt);
}
if let Some(stmt) = s.try_parse(parse_class_declaration)? {
trace!("parse_statement: success - parsed class declaration");
return Ok(stmt);
}
if let Some(stmt) = s.try_parse(parse_import_statement)? {
trace!("parse_statement: success - parsed import statement");
return Ok(stmt);
}
if let Some(stmt) = s.try_parse(parse_return_statement)? {
trace!("parse_statement: success - parsed return statement");
return Ok(stmt);
}
if let Some(stmt) = s.try_parse(parse_break_statement)? {
trace!("parse_statement: success - parsed break statement");
return Ok(stmt);
}
if let Some(stmt) = s.try_parse(parse_continue_statement)? {
trace!("parse_statement: success - parsed continue statement");
return Ok(stmt);
}
if let Some(stmt) = s.try_parse(parse_assignment)? {
trace!("parse_statement: success - parsed assignment");
return Ok(stmt);
}
if let Some(stmt) = s.try_parse(parse_block_like_expression_statement)? {
trace!("parse_statement: success - parsed block-like expression statement");
return Ok(stmt);
}
if s.accept_type(TokenType::Semicolon)?.is_some() {
trace!("parse_statement: success - parsed empty statement");
return Ok(Statement::Empty);
}
trace!("parse_statement: falling back to expression statement");
let result = parse_expression_statement(s);
if result.is_err() {
trace!(
"parse_statement: failed - {}",
result.as_ref().err().unwrap()
);
}
result
}
fn parse_expression_statement(s: &mut TokenStream) -> Result<Statement> {
let expr = parse_expression(s)?;
s.expect_type(TokenType::Semicolon)?;
Ok(Statement::Expression(expr))
}
fn parse_macro(s: &mut TokenStream) -> Result<Option<Statement>> {
if s.accept_type(TokenType::Hash)?.is_none() {
return Ok(None);
}
s.expect_type(TokenType::LeftBracket)?;
let name = if let Some(token) = s.accept_type(TokenType::Ident)? {
token
.text
.ok_or_else(|| anyhow!("Identifier token missing text"))?
} else if s.accept_type(TokenType::Macro)?.is_some() {
"macro".to_string()
} else {
return Err(anyhow!("Expected macro name: identifier or 'macro'"));
};
let mut args = Vec::new();
if s.accept_type(TokenType::LeftParen)?.is_some() {
loop {
if s.is_at_end() {
return Err(anyhow!("Unexpected EOF in macro arguments"));
}
if s.accept_type(TokenType::RightParen)?.is_some() {
break;
}
if let Some(arg) = s.try_parse(parse_macro_arg)? {
args.push(arg);
}
if s.accept_type(TokenType::Comma)?.is_none() {
s.expect_type(TokenType::RightParen)?;
break;
}
}
}
s.expect_type(TokenType::RightBracket)?;
let statement = Box::new(parse_statement(s)?);
let result = Statement::Macro {
name,
args,
statement,
};
Ok(Some(result))
}
fn parse_macro_arg(s: &mut TokenStream) -> Result<Option<MacroArg>> {
if let Some((name, value)) = s.try_parse(|s| {
let name_token = match s.accept_type(TokenType::Ident)? {
Some(token) => token,
None => return Ok(None),
};
let name = name_token
.text
.ok_or_else(|| anyhow!("Identifier token missing text"))?;
if s.accept_type(TokenType::Colon)?.is_none() {
return Ok(None);
}
let value = parse_literal_value(s)?;
Ok(Some((name, value)))
})? {
Ok(Some(MacroArg::Named(name, value)))
} else {
let value = parse_literal_value(s)?;
Ok(Some(MacroArg::Positional(value)))
}
}
fn parse_var_declaration(s: &mut TokenStream) -> Result<Option<Statement>> {
if s.accept_type(TokenType::Var)?.is_none() {
return Ok(None);
}
let pattern = parse_pattern(s)?;
let value = if s.accept_type(TokenType::Equal)?.is_some() {
Some(parse_expression(s)?)
} else {
None
};
s.expect_type(TokenType::Semicolon)?;
Ok(Some(Statement::VarDecl { pattern, value }))
}
fn parse_function_declaration(s: &mut TokenStream) -> Result<Option<Statement>> {
let is_pub = s.accept_type(TokenType::Pub)?.is_some();
if s.accept_type(TokenType::Fn)?.is_none() {
return Ok(None);
}
let name_token = s.expect_type(TokenType::Ident)?;
let name = name_token
.text
.ok_or_else(|| anyhow!("Function name token missing text"))?;
s.expect_type(TokenType::LeftParen)?;
let mut params = Vec::new();
loop {
if s.is_at_end() {
return Err(anyhow!("Unexpected EOF in function parameters"));
}
if s.accept_type(TokenType::RightParen)?.is_some() {
break;
}
params.push(parse_parameter(s)?);
if s.accept_type(TokenType::Comma)?.is_none() {
s.expect_type(TokenType::RightParen)?;
break;
}
}
s.expect_type(TokenType::LeftBrace)?;
let body_expr = super::expression::parse_block_expression(s)?;
let body = match body_expr {
Expression::Block(block) => block,
_ => unreachable!("parse_block_expression should return a Block"),
};
Ok(Some(Statement::FnDecl {
name,
params,
body,
is_pub,
}))
}
fn parse_parameter(s: &mut TokenStream) -> Result<Parameter> {
let kind = if s.accept_type(TokenType::Star)?.is_some() {
if s.accept_type(TokenType::Star)?.is_some() {
ParameterKind::Keyword
} else {
ParameterKind::Rest
}
} else {
ParameterKind::Regular
};
let name_token = s.expect_type(TokenType::Ident)?;
let name = name_token
.text
.ok_or_else(|| anyhow!("Parameter name token missing text"))?;
let default = if s.accept_type(TokenType::Equal)?.is_some() {
Some(parse_literal_value(s)?)
} else {
None
};
Ok(Parameter {
name,
default,
kind,
})
}
fn parse_class_declaration(s: &mut TokenStream) -> Result<Option<Statement>> {
let is_pub = s.accept_type(TokenType::Pub)?.is_some();
if s.accept_type(TokenType::Class)?.is_none() {
return Ok(None);
}
let name_token = s.expect_type(TokenType::Ident)?;
let name = name_token
.text
.ok_or_else(|| anyhow!("Class name token missing text"))?;
if s.accept_type(TokenType::LeftParen)?.is_some() {
while s.peek_type() != TokenType::RightParen && !s.is_at_end() {
s.accept_type(s.peek_type())?;
}
s.expect_type(TokenType::RightParen)?;
}
s.expect_type(TokenType::LeftBrace)?;
let mut members = Vec::new();
while s.peek_type() != TokenType::RightBrace && !s.is_at_end() {
if let Some(member) = s.try_parse(parse_class_member)? {
members.push(member);
} else {
break;
}
}
s.expect_type(TokenType::RightBrace)?;
Ok(Some(Statement::ClassDecl {
name,
members,
is_pub,
}))
}
fn parse_class_member(s: &mut TokenStream) -> Result<Option<ClassMember>> {
if s.accept_type(TokenType::Static)?.is_some() {
s.expect_type(TokenType::Fn)?;
let name_token = s.expect_type(TokenType::Ident)?;
let name = name_token
.text
.ok_or_else(|| anyhow!("Method name token missing text"))?;
s.expect_type(TokenType::LeftParen)?;
let mut params = Vec::new();
while s.peek_type() != TokenType::RightParen && !s.is_at_end() {
params.push(parse_parameter(s)?);
if s.accept_type(TokenType::Comma)?.is_none() {
break;
}
}
s.expect_type(TokenType::RightParen)?;
s.expect_type(TokenType::LeftBrace)?;
let body_expr = super::expression::parse_block_expression(s)?;
let body = match body_expr {
Expression::Block(block) => block,
_ => unreachable!("parse_block_expression should return a Block"),
};
return Ok(Some(ClassMember {
name,
kind: ClassMemberKind::StaticMethod { params, body },
}));
}
if s.accept_type(TokenType::Fn)?.is_some() {
let name_token = s.expect_type(TokenType::Ident)?;
let name = name_token
.text
.ok_or_else(|| anyhow!("Method name token missing text"))?;
s.expect_type(TokenType::LeftParen)?;
let mut params = Vec::new();
while s.peek_type() != TokenType::RightParen && !s.is_at_end() {
params.push(parse_parameter(s)?);
if s.accept_type(TokenType::Comma)?.is_none() {
break;
}
}
s.expect_type(TokenType::RightParen)?;
s.expect_type(TokenType::LeftBrace)?;
let body_expr = super::expression::parse_block_expression(s)?;
let body = match body_expr {
Expression::Block(block) => block,
_ => unreachable!("parse_block_expression should return a Block"),
};
return Ok(Some(ClassMember {
name,
kind: ClassMemberKind::Method { params, body },
}));
}
if s.accept_type(TokenType::Var)?.is_some() {
let name_token = s.expect_type(TokenType::Ident)?;
let name = name_token
.text
.ok_or_else(|| anyhow!("Field name token missing text"))?;
let initializer = if s.accept_type(TokenType::Equal)?.is_some() {
Some(parse_expression(s)?)
} else {
None
};
s.expect_type(TokenType::Semicolon)?;
return Ok(Some(ClassMember {
name,
kind: ClassMemberKind::Field(initializer),
}));
}
Ok(None)
}
fn parse_import_statement(s: &mut TokenStream) -> Result<Option<Statement>> {
if s.accept_type(TokenType::Use)?.is_none() {
return Ok(None);
}
let mut module_parts = Vec::new();
let first_part = s.expect_type(TokenType::Ident)?;
module_parts.push(
first_part
.text
.ok_or_else(|| anyhow!("Module name token missing text"))?,
);
while s.accept_type(TokenType::DoubleColon)?.is_some() {
if s.peek_type() == TokenType::Star
|| s.peek_type() == TokenType::LeftBrace
|| s.peek_type() == TokenType::Ident
{
break;
} else {
let part = s.expect_type(TokenType::Ident)?;
module_parts.push(
part.text
.ok_or_else(|| anyhow!("Module name token missing text"))?,
);
}
}
let module = module_parts.join("::");
let items = if s.accept_type(TokenType::Star)?.is_some() {
ImportItems::All
} else if s.accept_type(TokenType::LeftBrace)?.is_some() {
let mut import_items = Vec::new();
loop {
if s.peek_type() == TokenType::RightBrace {
break;
}
let name_token = s.expect_type(TokenType::Ident)?;
let name = name_token
.text
.ok_or_else(|| anyhow!("Import item name token missing text"))?;
let alias = if s.accept_type(TokenType::As)?.is_some() {
let alias_token = s.expect_type(TokenType::Ident)?;
Some(
alias_token
.text
.ok_or_else(|| anyhow!("Alias token missing text"))?,
)
} else {
None
};
import_items.push(ImportItem { name, alias });
if s.accept_type(TokenType::Comma)?.is_none() {
break;
}
}
s.expect_type(TokenType::RightBrace)?;
ImportItems::Specific(import_items)
} else {
let name_token = s.expect_type(TokenType::Ident)?;
let name = name_token
.text
.ok_or_else(|| anyhow!("Import item name token missing text"))?;
let alias = if s.accept_type(TokenType::As)?.is_some() {
let alias_token = s.expect_type(TokenType::Ident)?;
Some(
alias_token
.text
.ok_or_else(|| anyhow!("Alias token missing text"))?,
)
} else {
None
};
ImportItems::Specific(vec![ImportItem { name, alias }])
};
s.expect_type(TokenType::Semicolon)?;
Ok(Some(Statement::Import(ImportSpec { module, items })))
}
fn parse_return_statement(s: &mut TokenStream) -> Result<Option<Statement>> {
if s.accept_type(TokenType::Return)?.is_none() {
return Ok(None);
}
let expr = if let Some(_token) = s.accept_type(TokenType::Semicolon)? {
None
} else {
Some(parse_expression(s)?)
};
s.expect_type(TokenType::Semicolon)?;
Ok(Some(Statement::Return(expr)))
}
fn parse_break_statement(s: &mut TokenStream) -> Result<Option<Statement>> {
if s.accept_type(TokenType::Break)?.is_none() {
return Ok(None);
}
let expr = if (s.accept_type(TokenType::Semicolon)?).is_some() {
None
} else {
let expr = Some(parse_expression(s)?);
s.expect_type(TokenType::Semicolon)?;
expr
};
Ok(Some(Statement::Break(expr)))
}
fn parse_continue_statement(s: &mut TokenStream) -> Result<Option<Statement>> {
if s.accept_type(TokenType::Continue)?.is_none() {
return Ok(None);
}
s.expect_type(TokenType::Semicolon)?;
Ok(Some(Statement::Continue))
}
fn parse_assignment(s: &mut TokenStream) -> Result<Option<Statement>> {
let target = match parse_lvalue(s)? {
Some(lval) => lval,
None => return Ok(None),
};
let op = if s.accept_type(TokenType::Equal)?.is_some() {
AssignOp::Assign
} else if s.accept_type(TokenType::PlusEqual)?.is_some() {
AssignOp::AddAssign
} else if s.accept_type(TokenType::MinusEqual)?.is_some() {
AssignOp::SubAssign
} else if s.accept_type(TokenType::StarEqual)?.is_some() {
AssignOp::MulAssign
} else if s.accept_type(TokenType::SlashEqual)?.is_some() {
AssignOp::DivAssign
} else if s.accept_type(TokenType::PercentEqual)?.is_some() {
AssignOp::ModAssign
} else {
return Ok(None);
};
let value = parse_expression(s)?;
s.expect_type(TokenType::Semicolon)?;
Ok(Some(Statement::Assignment { target, op, value }))
}
fn parse_lvalue(s: &mut TokenStream) -> Result<Option<LValue>> {
let name_token = match s.accept_type(TokenType::Ident)? {
Some(token) => token,
None => return Ok(None),
};
let name = name_token
.text
.ok_or_else(|| anyhow!("Identifier token missing text"))?;
let mut expr = LValue::Identifier(name);
loop {
if s.accept_type(TokenType::Dot)?.is_some() {
let property_token = s.expect_type(TokenType::Ident)?;
let property = property_token
.text
.ok_or_else(|| anyhow!("Identifier token missing text"))?;
let base_expr = match expr {
LValue::Identifier(name) => Expression::Identifier(name),
LValue::GetAttr(obj, field) => Expression::GetAttr(obj, field),
LValue::GetItem(obj, key) => Expression::GetItem(obj, key),
};
expr = LValue::GetAttr(Box::new(base_expr), property);
} else if s.accept_type(TokenType::LeftBracket)?.is_some() {
let index = parse_expression(s)?;
s.expect_type(TokenType::RightBracket)?;
let base_expr = match expr {
LValue::Identifier(name) => Expression::Identifier(name),
LValue::GetAttr(obj, field) => Expression::GetAttr(obj, field),
LValue::GetItem(obj, key) => Expression::GetItem(obj, key),
};
expr = LValue::GetItem(Box::new(base_expr), Box::new(index));
} else {
break;
}
}
Ok(Some(expr))
}
fn parse_block_like_expression_statement(s: &mut TokenStream) -> Result<Option<Statement>> {
if matches!(
s.peek_type(),
TokenType::If
| TokenType::Loop
| TokenType::While
| TokenType::For
| TokenType::Match
| TokenType::Try
| TokenType::With
) {
let expr = parse_expression(s)?;
return Ok(Some(Statement::Expression(expr)));
}
if s.peek_type() == TokenType::LeftBrace {
if let Some(expr) = s.try_parse(|s| {
let expr = match parse_expression(s) {
Ok(expr) => expr,
Err(_) => return Ok(None),
};
if matches!(expr, Expression::Block(_)) {
Ok(Some(expr))
} else {
Ok(None)
}
})? {
return Ok(Some(Statement::Expression(expr)));
}
}
Ok(None)
}
pub fn parse_pattern(s: &mut TokenStream) -> Result<Pattern> {
match s.peek_type() {
TokenType::Ident => {
let name_token = s.expect_type(TokenType::Ident)?;
let name = name_token
.text
.ok_or_else(|| anyhow!("Identifier token missing text"))?;
if name == "_" {
Ok(Pattern::Wildcard)
} else {
Ok(Pattern::Variable(name))
}
}
TokenType::Int
| TokenType::Float
| TokenType::String
| TokenType::True
| TokenType::False
| TokenType::Null => {
if let Some(range_pattern) = s.try_parse(|s| {
let first_literal = match parse_literal_value(s) {
Ok(literal) => literal,
Err(_) => return Ok(None),
};
if s.accept_type(TokenType::DotDot)?.is_some()
|| s.accept_type(TokenType::DotDotEqual)?.is_some()
{
let second_literal = match parse_literal_value(s) {
Ok(literal) => literal,
Err(_) => return Ok(None),
};
Ok(Some(Pattern::Range(
Box::new(Pattern::Literal(first_literal)),
Box::new(Pattern::Literal(second_literal)),
)))
} else {
Ok(None)
}
})? {
Ok(range_pattern)
} else {
let literal = parse_literal_value(s)?;
Ok(Pattern::Literal(literal))
}
}
TokenType::LeftBracket => parse_list_pattern(s),
TokenType::LeftBrace => parse_dict_pattern(s),
_ => Err(anyhow!("Unsupported pattern type: {:?}", s.peek_type())),
}
}
fn parse_list_pattern(s: &mut TokenStream) -> Result<Pattern> {
s.expect_type(TokenType::LeftBracket)?;
let mut patterns = Vec::new();
let mut rest_var = None;
if s.accept_type(TokenType::RightBracket)?.is_some() {
return Ok(Pattern::List(patterns));
}
loop {
if s.accept_type(TokenType::Star)?.is_some() {
let rest_token = s.expect_type(TokenType::Ident)?;
let rest_name = rest_token
.text
.ok_or_else(|| anyhow!("Identifier token missing text"))?;
rest_var = Some(rest_name);
if s.accept_type(TokenType::Comma)?.is_some() {
if s.peek_type() != TokenType::RightBracket {
return Err(anyhow!("Rest pattern must be the last element"));
}
}
break;
}
patterns.push(parse_pattern(s)?);
if s.accept_type(TokenType::Comma)?.is_some() {
if s.peek_type() == TokenType::RightBracket {
break;
}
continue;
} else {
break;
}
}
s.expect_type(TokenType::RightBracket)?;
if rest_var.is_some() {
Ok(Pattern::ListRest(patterns, rest_var))
} else {
Ok(Pattern::List(patterns))
}
}
fn parse_dict_pattern(s: &mut TokenStream) -> Result<Pattern> {
s.expect_type(TokenType::LeftBrace)?;
let mut dict_patterns = Vec::new();
if s.accept_type(TokenType::RightBrace)?.is_some() {
return Ok(Pattern::Dict(dict_patterns));
}
loop {
let key_token = s.expect_type(TokenType::Ident)?;
let key = key_token
.text
.ok_or_else(|| anyhow!("Identifier token missing text"))?;
let alias = if s.accept_type(TokenType::Colon)?.is_some() {
let alias_token = s.expect_type(TokenType::Ident)?;
Some(
alias_token
.text
.ok_or_else(|| anyhow!("Alias token missing text"))?,
)
} else {
None
};
dict_patterns.push(DictPattern { key, alias });
if s.accept_type(TokenType::Comma)?.is_some() {
if s.peek_type() == TokenType::RightBrace {
break;
}
continue;
} else {
break;
}
}
s.expect_type(TokenType::RightBrace)?;
Ok(Pattern::Dict(dict_patterns))
}
fn parse_expression(s: &mut TokenStream) -> Result<Expression> {
super::expression::parse_expression(s)
}
pub fn parse_literal_value(s: &mut TokenStream) -> Result<LiteralValue> {
if s.accept_type(TokenType::True)?.is_some() {
Ok(LiteralValue::Bool(true))
} else if s.accept_type(TokenType::False)?.is_some() {
Ok(LiteralValue::Bool(false))
} else if s.accept_type(TokenType::Null)?.is_some() {
Ok(LiteralValue::Null)
} else if let Some(token) = s.accept_type(TokenType::Int)? {
let text = token
.text
.ok_or_else(|| anyhow!("Int token missing text"))?;
let n = text
.parse::<i64>()
.map_err(|e| anyhow!("Failed to parse integer '{}': {}", text, e))?;
Ok(LiteralValue::Int(n))
} else if let Some(token) = s.accept_type(TokenType::Float)? {
let text = token
.text
.ok_or_else(|| anyhow!("Float token missing text"))?;
let f = text
.parse::<f64>()
.map_err(|e| anyhow!("Failed to parse float '{}': {}", text, e))?;
Ok(LiteralValue::Float(f))
} else if let Some(token) = s.accept_type(TokenType::String)? {
let text = token
.text
.ok_or_else(|| anyhow!("String token missing text"))?;
Ok(LiteralValue::String(text))
} else if let Some(token) = s.accept_type(TokenType::RawString)? {
let text = token
.text
.ok_or_else(|| anyhow!("RawString token missing text"))?;
Ok(LiteralValue::String(text))
} else {
Err(anyhow!("Expected literal value"))
}
}
#[allow(dead_code)]
pub fn parse_block(s: &mut TokenStream) -> Result<Vec<Statement>> {
let mut statements = Vec::new();
while !s.is_at_end() && s.peek_type() != TokenType::RightBrace {
statements.push(parse_statement(s)?);
}
s.expect_type(TokenType::RightBrace)?;
Ok(statements)
}