use crate::lexer::Token;
use crate::{ast::*, ParseError, ParseResult};
use logos::{Logos, Span};
pub fn preprocess_tokens(input: &str) -> Vec<(Token, Span)> {
let mut tokens = Vec::new();
let mut lexer = Token::lexer(input);
let mut indent_stack = vec![0];
let mut at_line_start = true;
let mut current_line_indent;
let mut pending_tokens = Vec::new();
while let Some(result) = lexer.next() {
if let Ok(token) = result {
let span = lexer.span();
pending_tokens.push((token, span));
}
}
let mut i = 0;
let mut paren_depth: usize = 0; let mut in_function_signature = false;
while i < pending_tokens.len() {
let (token, span) = pending_tokens[i].clone();
match &token {
Token::Newline => {
tokens.push((token, span));
at_line_start = true;
i += 1;
}
_ => {
if at_line_start && paren_depth == 0 && !in_function_signature {
let line_start = input[..span.start].rfind('\n').map(|p| p + 1).unwrap_or(0);
let indent_str = &input[line_start..span.start];
current_line_indent = indent_str.chars().filter(|&c| c == ' ').count();
if matches!(token, Token::Newline) {
tokens.push((token, span));
i += 1;
continue;
}
let prev_indent = *indent_stack.last().unwrap();
if current_line_indent > prev_indent {
tokens.push((Token::Indent, span.start..span.start));
indent_stack.push(current_line_indent);
} else if current_line_indent < prev_indent {
while let Some(&stack_indent) = indent_stack.last() {
if stack_indent <= current_line_indent {
break;
}
tokens.push((Token::Dedent, span.start..span.start));
indent_stack.pop();
}
if indent_stack.last() != Some(¤t_line_indent) {
if let Some(&last_indent) = indent_stack.last() {
if current_line_indent > last_indent {
tokens.push((Token::Indent, span.start..span.start));
indent_stack.push(current_line_indent);
}
}
}
}
at_line_start = false;
}
match &token {
Token::LeftParen | Token::LeftBracket | Token::LeftBrace => {
paren_depth += 1;
}
Token::RightParen | Token::RightBracket | Token::RightBrace => {
paren_depth = paren_depth.saturating_sub(1);
}
_ => {}
}
if matches!(token, Token::Def) {
in_function_signature = true;
} else if matches!(token, Token::Colon) && in_function_signature && paren_depth == 0
{
in_function_signature = false;
}
tokens.push((token, span));
i += 1;
}
}
}
while indent_stack.len() > 1 {
tokens.push((Token::Dedent, input.len()..input.len()));
indent_stack.pop();
}
tokens
}
type ParsedArguments = (Vec<Expression>, Vec<(String, Expression)>);
pub struct Parser<'a> {
tokens: Vec<(Token, Span)>,
current: usize,
current_line: usize,
#[allow(dead_code)]
errors: Vec<ParseError>,
#[allow(dead_code)]
error_recovery: bool,
source: &'a str,
}
impl<'a> Parser<'a> {
pub fn new(input: &'a str) -> Self {
let tokens = preprocess_tokens(input);
Self {
tokens,
current: 0,
current_line: 1,
errors: vec![],
error_recovery: true, source: input,
}
}
pub fn parse(&mut self) -> ParseResult<GlyphModule> {
self.skip_whitespace();
let program_decorator = self.parse_program_decorator()?;
self.skip_whitespace();
let mut imports = vec![];
while self.is_at_import() {
imports.push(self.parse_import()?);
self.skip_whitespace();
}
let mut statements = vec![];
while !self.is_at_end() {
self.skip_whitespace();
if self.is_at_end() {
break;
}
statements.push(self.parse_statement()?);
}
Ok(GlyphModule {
program: program_decorator,
imports,
statements,
})
}
fn current_token(&self) -> Option<&Token> {
if self.current < self.tokens.len() {
Some(&self.tokens[self.current].0)
} else {
None
}
}
fn current_span(&self) -> Span {
if self.current < self.tokens.len() {
self.tokens[self.current].1.clone()
} else {
self.source.len()..self.source.len()
}
}
fn peek_token(&self) -> Option<&Token> {
if self.current + 1 < self.tokens.len() {
Some(&self.tokens[self.current + 1].0)
} else {
None
}
}
fn is_at_end(&self) -> bool {
self.current >= self.tokens.len()
}
fn advance(&mut self) {
if !self.is_at_end() {
if let Some(Token::Newline) = self.current_token() {
self.current_line += 1;
}
self.current += 1;
}
}
fn expect(&mut self, expected: Token) -> ParseResult<()> {
if self.current_token() == Some(&expected) {
self.advance();
Ok(())
} else {
Err(ParseError::UnexpectedToken(format!(
"Expected {:?}, found {:?} at line {}",
expected,
self.current_token(),
self.current_line
)))
}
}
fn skip_whitespace(&mut self) {
while matches!(self.current_token(), Some(Token::Newline)) {
self.advance();
}
}
fn is_at_import(&self) -> bool {
matches!(
self.current_token(),
Some(Token::Import) | Some(Token::From)
)
}
fn get_source_text(&self, span: &Span) -> String {
self.source[span.clone()].to_string()
}
fn parse_program_decorator(&mut self) -> ParseResult<ProgramDecorator> {
self.expect(Token::At)?;
if !matches!(self.current_token(), Some(Token::Identifier)) {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected 'program' after @".to_string(),
});
}
let ident_text = self.get_source_text(&self.current_span());
if ident_text != "program" {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: format!("Expected 'program', found '{ident_text}'"),
});
}
self.advance();
self.expect(Token::LeftParen)?;
let mut name = String::new();
let mut version = "0.1.0".to_string();
let mut requires = vec![];
while !matches!(self.current_token(), Some(Token::RightParen)) {
if !matches!(self.current_token(), Some(Token::Identifier)) {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected keyword argument".to_string(),
});
}
let key = self.get_source_text(&self.current_span());
self.advance();
self.expect(Token::Equal)?;
match key.as_str() {
"name" => {
if let Some(Token::String) = &self.current_token() {
name = self.get_source_text(&self.current_span());
name = name
.trim_start_matches('"')
.trim_end_matches('"')
.trim_start_matches('\'')
.trim_end_matches('\'')
.to_string();
self.advance();
} else {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected string for 'name'".to_string(),
});
}
}
"version" => {
if let Some(Token::String) = &self.current_token() {
version = self.get_source_text(&self.current_span());
version = version
.trim_start_matches('"')
.trim_end_matches('"')
.trim_start_matches('\'')
.trim_end_matches('\'')
.to_string();
self.advance();
}
}
"requires" => {
requires = self.parse_string_list()?;
}
_ => {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: format!("Unknown program parameter: {key}"),
});
}
}
if matches!(self.current_token(), Some(Token::Comma)) {
self.advance();
}
}
self.expect(Token::RightParen)?;
self.skip_whitespace();
if name.is_empty() {
return Err(ParseError::MissingProgramField {
field: "name".to_string(),
});
}
Ok(ProgramDecorator {
name,
version,
requires,
})
}
fn parse_string_list(&mut self) -> ParseResult<Vec<String>> {
self.expect(Token::LeftBracket)?;
let mut items = vec![];
while !matches!(self.current_token(), Some(Token::RightBracket)) {
if let Some(Token::String) = &self.current_token() {
let mut item = self.get_source_text(&self.current_span());
item = item
.trim_start_matches('"')
.trim_end_matches('"')
.trim_start_matches('\'')
.trim_end_matches('\'')
.to_string();
items.push(item);
self.advance();
if matches!(self.current_token(), Some(Token::Comma)) {
self.advance();
}
} else {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected string in list".to_string(),
});
}
}
self.expect(Token::RightBracket)?;
Ok(items)
}
fn parse_import(&mut self) -> ParseResult<Import> {
match self.current_token() {
Some(Token::Import) => {
self.advance();
if let Some(Token::Identifier) = &self.current_token() {
let name = self.get_source_text(&self.current_span());
self.advance();
self.skip_whitespace();
Ok(Import::Module { name })
} else {
Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected module name after 'import'".to_string(),
})
}
}
Some(Token::From) => {
self.advance();
if !matches!(self.current_token(), Some(Token::Identifier)) {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected module name after 'from'".to_string(),
});
}
let module = self.get_source_text(&self.current_span());
self.advance();
self.expect(Token::Import)?;
let mut items = vec![];
loop {
if let Some(Token::Identifier) = &self.current_token() {
items.push(self.get_source_text(&self.current_span()));
self.advance();
if matches!(self.current_token(), Some(Token::Comma)) {
self.advance();
} else {
break;
}
} else {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected identifier in import list".to_string(),
});
}
}
self.skip_whitespace();
Ok(Import::FromImport { module, items })
}
_ => Err(ParseError::UnexpectedToken(format!(
"Expected 'import' or 'from', found {:?}",
self.current_token()
))),
}
}
fn parse_statement(&mut self) -> ParseResult<Statement> {
match self.current_token() {
Some(Token::Def) => Ok(Statement::FunctionDef(self.parse_function()?)),
Some(Token::If) => Ok(Statement::If(self.parse_if_statement()?)),
Some(Token::Match) => Ok(Statement::Match(self.parse_match_statement()?)),
Some(Token::While) => self.parse_while_statement(),
Some(Token::For) => self.parse_for_statement(),
Some(Token::Break) => {
self.advance();
self.skip_whitespace();
Ok(Statement::Break)
}
Some(Token::Continue) => {
self.advance();
self.skip_whitespace();
Ok(Statement::Continue)
}
Some(Token::Return) => {
self.advance();
let expr = if matches!(self.current_token(), Some(Token::Newline)) {
None
} else {
Some(self.parse_expression()?)
};
self.skip_whitespace();
Ok(Statement::Return(expr))
}
Some(Token::Let) => {
self.advance();
if !matches!(self.current_token(), Some(Token::Identifier)) {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected identifier after 'let'".to_string(),
});
}
let name = self.get_source_text(&self.current_span());
self.advance();
let type_hint = if matches!(self.current_token(), Some(Token::Colon)) {
self.advance();
Some(self.parse_type()?)
} else {
None
};
self.expect(Token::Equal)?;
let value = self.parse_expression()?;
self.skip_whitespace();
Ok(Statement::Let {
name,
value,
type_hint,
})
}
Some(Token::Pass) => {
self.advance();
self.skip_whitespace();
Ok(Statement::Expression(Expression::Literal(Literal::Unit)))
}
Some(Token::Identifier) => {
let checkpoint = self.current;
let name = self.get_source_text(&self.current_span());
self.advance();
if matches!(self.current_token(), Some(Token::Equal)) {
self.advance();
let value = self.parse_expression()?;
self.skip_whitespace();
Ok(Statement::Assignment {
target: name,
value,
})
} else {
self.current = checkpoint;
let expr = self.parse_expression()?;
self.skip_whitespace();
Ok(Statement::Expression(expr))
}
}
_ => {
let expr = self.parse_expression()?;
self.skip_whitespace();
Ok(Statement::Expression(expr))
}
}
}
fn parse_function(&mut self) -> ParseResult<Function> {
self.expect(Token::Def)?;
if !matches!(self.current_token(), Some(Token::Identifier)) {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected function name".to_string(),
});
}
let name = self.get_source_text(&self.current_span());
self.advance();
self.expect(Token::LeftParen)?;
let mut params = vec![];
while !matches!(self.current_token(), Some(Token::RightParen)) {
while matches!(self.current_token(), Some(Token::Newline)) {
self.advance();
}
if matches!(self.current_token(), Some(Token::RightParen)) {
break;
}
params.push(self.parse_parameter()?);
if matches!(self.current_token(), Some(Token::Comma)) {
self.advance();
while matches!(self.current_token(), Some(Token::Newline)) {
self.advance();
}
}
}
self.expect(Token::RightParen)?;
let return_type = if matches!(self.current_token(), Some(Token::Arrow)) {
self.advance();
Some(self.parse_type()?)
} else {
None
};
self.expect(Token::Colon)?;
if matches!(self.current_token(), Some(Token::Newline)) {
self.advance();
}
self.expect(Token::Indent)?;
let mut body = vec![];
while !matches!(self.current_token(), Some(Token::Dedent)) {
body.push(self.parse_statement()?);
}
self.expect(Token::Dedent)?;
Ok(Function {
name,
params,
return_type,
body,
is_async: false, })
}
fn parse_parameter(&mut self) -> ParseResult<Parameter> {
if !matches!(self.current_token(), Some(Token::Identifier)) {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected parameter name".to_string(),
});
}
let name = self.get_source_text(&self.current_span());
self.advance();
let type_hint = if matches!(self.current_token(), Some(Token::Colon)) {
self.advance();
Some(self.parse_type()?)
} else {
None
};
let default = if matches!(self.current_token(), Some(Token::Equal)) {
self.advance();
Some(self.parse_expression()?)
} else {
None
};
Ok(Parameter {
name,
type_hint,
default,
})
}
fn parse_type(&mut self) -> ParseResult<Type> {
if !matches!(self.current_token(), Some(Token::Identifier)) {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected type name".to_string(),
});
}
let type_name = self.get_source_text(&self.current_span());
self.advance();
match type_name.as_str() {
"list" => {
if matches!(self.current_token(), Some(Token::LeftBracket)) {
self.advance();
let inner = Box::new(self.parse_type()?);
self.expect(Token::RightBracket)?;
Ok(Type::List(inner))
} else {
Ok(Type::Named("list".to_string()))
}
}
"dict" => {
if matches!(self.current_token(), Some(Token::LeftBracket)) {
self.advance();
let key = Box::new(self.parse_type()?);
self.expect(Token::Comma)?;
let value = Box::new(self.parse_type()?);
self.expect(Token::RightBracket)?;
Ok(Type::Dict { key, value })
} else {
Ok(Type::Named("dict".to_string()))
}
}
"optional" => {
self.expect(Token::LeftBracket)?;
let inner = Box::new(self.parse_type()?);
self.expect(Token::RightBracket)?;
Ok(Type::Optional(inner))
}
"promise" => {
self.expect(Token::LeftBracket)?;
let inner = Box::new(self.parse_type()?);
self.expect(Token::RightBracket)?;
Ok(Type::Promise(inner))
}
"result" => {
self.expect(Token::LeftBracket)?;
let ok = Box::new(self.parse_type()?);
self.expect(Token::Comma)?;
let err = Box::new(self.parse_type()?);
self.expect(Token::RightBracket)?;
Ok(Type::Result { ok, err })
}
_ => Ok(Type::Named(type_name)),
}
}
fn parse_if_statement(&mut self) -> ParseResult<IfStatement> {
self.expect(Token::If)?;
let condition = self.parse_expression()?;
self.expect(Token::Colon)?;
if matches!(self.current_token(), Some(Token::Newline)) {
self.advance();
}
self.expect(Token::Indent)?;
let mut then_body = vec![];
while !matches!(self.current_token(), Some(Token::Dedent)) {
then_body.push(self.parse_statement()?);
}
self.expect(Token::Dedent)?;
let mut elif_clauses = vec![];
while matches!(self.current_token(), Some(Token::Elif)) {
self.advance();
let elif_condition = self.parse_expression()?;
self.expect(Token::Colon)?;
if matches!(self.current_token(), Some(Token::Newline)) {
self.advance();
}
self.expect(Token::Indent)?;
let mut elif_body = vec![];
while !matches!(self.current_token(), Some(Token::Dedent)) {
elif_body.push(self.parse_statement()?);
}
self.expect(Token::Dedent)?;
elif_clauses.push(ElifClause {
condition: elif_condition,
body: elif_body,
});
}
let else_body = if matches!(self.current_token(), Some(Token::Else)) {
self.advance();
self.expect(Token::Colon)?;
if matches!(self.current_token(), Some(Token::Newline)) {
self.advance();
}
self.expect(Token::Indent)?;
let mut else_stmts = vec![];
while !matches!(self.current_token(), Some(Token::Dedent)) {
else_stmts.push(self.parse_statement()?);
}
self.expect(Token::Dedent)?;
Some(else_stmts)
} else {
None
};
Ok(IfStatement {
condition,
then_body,
elif_clauses,
else_body,
})
}
fn parse_match_statement(&mut self) -> ParseResult<MatchStatement> {
self.expect(Token::Match)?;
let subject = self.parse_expression()?;
self.expect(Token::Colon)?;
if matches!(self.current_token(), Some(Token::Newline)) {
self.advance();
}
self.expect(Token::Indent)?;
let mut cases = vec![];
while !matches!(self.current_token(), Some(Token::Dedent)) {
cases.push(self.parse_case_clause()?);
}
self.expect(Token::Dedent)?;
Ok(MatchStatement { subject, cases })
}
fn parse_case_clause(&mut self) -> ParseResult<CaseClause> {
self.expect(Token::Case)?;
let pattern = self.parse_pattern()?;
self.expect(Token::Colon)?;
if matches!(self.current_token(), Some(Token::Newline)) {
self.advance();
}
self.expect(Token::Indent)?;
let mut body = vec![];
while !matches!(self.current_token(), Some(Token::Dedent)) {
body.push(self.parse_statement()?);
}
self.expect(Token::Dedent)?;
Ok(CaseClause { pattern, body })
}
fn parse_pattern(&mut self) -> ParseResult<Pattern> {
match self.current_token() {
Some(Token::Identifier) => {
let name = self.get_source_text(&self.current_span());
self.advance();
if name == "_" {
Ok(Pattern::Wildcard)
} else if matches!(self.current_token(), Some(Token::LeftParen)) {
self.advance();
let mut args = vec![];
while !matches!(self.current_token(), Some(Token::RightParen)) {
args.push(self.parse_pattern()?);
if matches!(self.current_token(), Some(Token::Comma)) {
self.advance();
}
}
self.expect(Token::RightParen)?;
Ok(Pattern::Constructor { name, args })
} else {
Ok(Pattern::Variable(name))
}
}
Some(Token::Int) => {
let value = self
.get_source_text(&self.current_span())
.parse::<i64>()
.map_err(|_| ParseError::SyntaxError {
line: self.current_line,
message: "Invalid integer".to_string(),
})?;
self.advance();
Ok(Pattern::Literal(Literal::Int(value)))
}
Some(Token::Float) => {
let value = self
.get_source_text(&self.current_span())
.parse::<f64>()
.map_err(|_| ParseError::SyntaxError {
line: self.current_line,
message: "Invalid float".to_string(),
})?;
self.advance();
Ok(Pattern::Literal(Literal::Float(value)))
}
Some(Token::String) => {
let mut value = self.get_source_text(&self.current_span());
value = value
.trim_start_matches('"')
.trim_end_matches('"')
.trim_start_matches('\'')
.trim_end_matches('\'')
.to_string();
self.advance();
Ok(Pattern::Literal(Literal::String(value)))
}
Some(Token::True) => {
self.advance();
Ok(Pattern::Literal(Literal::Bool(true)))
}
Some(Token::False) => {
self.advance();
Ok(Pattern::Literal(Literal::Bool(false)))
}
Some(Token::None) => {
self.advance();
Ok(Pattern::Literal(Literal::Unit))
}
_ => Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected pattern".to_string(),
}),
}
}
fn parse_while_statement(&mut self) -> ParseResult<Statement> {
self.expect(Token::While)?;
let condition = self.parse_expression()?;
self.expect(Token::Colon)?;
if matches!(self.current_token(), Some(Token::Newline)) {
self.advance();
}
self.expect(Token::Indent)?;
let mut body = vec![];
while !matches!(self.current_token(), Some(Token::Dedent)) {
body.push(self.parse_statement()?);
}
self.expect(Token::Dedent)?;
Ok(Statement::While { condition, body })
}
fn parse_for_statement(&mut self) -> ParseResult<Statement> {
self.expect(Token::For)?;
if !matches!(self.current_token(), Some(Token::Identifier)) {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected identifier after 'for'".to_string(),
});
}
let variable = self.get_source_text(&self.current_span());
self.advance();
self.expect(Token::In)?;
let iterable = self.parse_expression()?;
self.expect(Token::Colon)?;
if matches!(self.current_token(), Some(Token::Newline)) {
self.advance();
}
self.expect(Token::Indent)?;
let mut body = vec![];
while !matches!(self.current_token(), Some(Token::Dedent)) {
body.push(self.parse_statement()?);
}
self.expect(Token::Dedent)?;
Ok(Statement::For {
variable,
iterable,
body,
})
}
fn parse_expression(&mut self) -> ParseResult<Expression> {
self.parse_or_expr()
}
fn parse_or_expr(&mut self) -> ParseResult<Expression> {
let mut left = self.parse_and_expr()?;
while matches!(self.current_token(), Some(Token::Or)) {
self.advance();
let right = self.parse_and_expr()?;
left = Expression::BinaryOp {
left: Box::new(left),
op: BinaryOperator::Or,
right: Box::new(right),
};
}
Ok(left)
}
fn parse_and_expr(&mut self) -> ParseResult<Expression> {
let mut left = self.parse_not_expr()?;
while matches!(self.current_token(), Some(Token::And)) {
self.advance();
let right = self.parse_not_expr()?;
left = Expression::BinaryOp {
left: Box::new(left),
op: BinaryOperator::And,
right: Box::new(right),
};
}
Ok(left)
}
fn parse_not_expr(&mut self) -> ParseResult<Expression> {
if matches!(self.current_token(), Some(Token::Not)) {
self.advance();
let operand = self.parse_not_expr()?;
Ok(Expression::UnaryOp {
op: UnaryOperator::Not,
operand: Box::new(operand),
})
} else {
self.parse_comparison()
}
}
fn parse_comparison(&mut self) -> ParseResult<Expression> {
let mut left = self.parse_additive()?;
loop {
let op = match &self.current_token() {
Some(Token::Less) => BinaryOperator::Less,
Some(Token::Greater) => BinaryOperator::Greater,
Some(Token::LessEqual) => BinaryOperator::LessEqual,
Some(Token::GreaterEqual) => BinaryOperator::GreaterEqual,
Some(Token::EqualEqual) => BinaryOperator::Equal,
Some(Token::NotEqual) => BinaryOperator::NotEqual,
_ => break,
};
self.advance();
let right = self.parse_additive()?;
left = Expression::BinaryOp {
left: Box::new(left),
op,
right: Box::new(right),
};
}
Ok(left)
}
fn parse_additive(&mut self) -> ParseResult<Expression> {
let mut left = self.parse_multiplicative()?;
loop {
let op = match &self.current_token() {
Some(Token::Plus) => BinaryOperator::Add,
Some(Token::Minus) => BinaryOperator::Subtract,
_ => break,
};
self.advance();
let right = self.parse_multiplicative()?;
left = Expression::BinaryOp {
left: Box::new(left),
op,
right: Box::new(right),
};
}
Ok(left)
}
fn parse_multiplicative(&mut self) -> ParseResult<Expression> {
let mut left = self.parse_power()?;
loop {
let op = match &self.current_token() {
Some(Token::Star) => BinaryOperator::Multiply,
Some(Token::Slash) => BinaryOperator::Divide,
Some(Token::Percent) => BinaryOperator::Modulo,
_ => break,
};
self.advance();
let right = self.parse_power()?;
left = Expression::BinaryOp {
left: Box::new(left),
op,
right: Box::new(right),
};
}
Ok(left)
}
fn parse_power(&mut self) -> ParseResult<Expression> {
let mut left = self.parse_unary()?;
if matches!(self.current_token(), Some(Token::StarStar)) {
self.advance();
let right = self.parse_power()?; left = Expression::BinaryOp {
left: Box::new(left),
op: BinaryOperator::Power,
right: Box::new(right),
};
}
Ok(left)
}
fn parse_unary(&mut self) -> ParseResult<Expression> {
match &self.current_token() {
Some(Token::Minus) => {
self.advance();
let operand = self.parse_unary()?;
Ok(Expression::UnaryOp {
op: UnaryOperator::Negate,
operand: Box::new(operand),
})
}
_ => self.parse_postfix(),
}
}
fn parse_postfix(&mut self) -> ParseResult<Expression> {
let mut expr = self.parse_atom()?;
loop {
match self.current_token() {
Some(Token::LeftParen) => {
self.advance();
let (args, kwargs) = self.parse_arguments()?;
self.expect(Token::RightParen)?;
expr = Expression::Call {
func: Box::new(expr),
args,
kwargs,
};
}
Some(Token::Dot) => {
self.advance();
if !matches!(self.current_token(), Some(Token::Identifier)) {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Expected attribute name after '.'".to_string(),
});
}
let attr = self.get_source_text(&self.current_span());
self.advance();
expr = Expression::Attribute {
value: Box::new(expr),
attr,
};
}
Some(Token::LeftBracket) => {
self.advance();
let _index = self.parse_expression()?;
self.expect(Token::RightBracket)?;
}
_ => break,
}
}
if matches!(self.current_token(), Some(Token::Await)) {
self.advance();
expr = Expression::Await(Box::new(expr));
}
Ok(expr)
}
fn parse_atom(&mut self) -> ParseResult<Expression> {
match self.current_token() {
Some(Token::Int) => {
let value = self
.get_source_text(&self.current_span())
.parse::<i64>()
.map_err(|_| ParseError::SyntaxError {
line: self.current_line,
message: "Invalid integer".to_string(),
})?;
self.advance();
Ok(Expression::Literal(Literal::Int(value)))
}
Some(Token::Float) => {
let value = self
.get_source_text(&self.current_span())
.parse::<f64>()
.map_err(|_| ParseError::SyntaxError {
line: self.current_line,
message: "Invalid float".to_string(),
})?;
self.advance();
Ok(Expression::Literal(Literal::Float(value)))
}
Some(Token::String) => {
let mut value = self.get_source_text(&self.current_span());
value = value
.trim_start_matches('"')
.trim_end_matches('"')
.trim_start_matches('\'')
.trim_end_matches('\'')
.to_string();
self.advance();
Ok(Expression::Literal(Literal::String(value)))
}
Some(Token::FString) => {
let mut value = self.get_source_text(&self.current_span());
if value.starts_with("f\"") || value.starts_with("f'") {
value = value[2..value.len() - 1].to_string();
}
self.advance();
Ok(Expression::Literal(Literal::String(value)))
}
Some(Token::True) => {
self.advance();
Ok(Expression::Literal(Literal::Bool(true)))
}
Some(Token::False) => {
self.advance();
Ok(Expression::Literal(Literal::Bool(false)))
}
Some(Token::None) => {
self.advance();
Ok(Expression::Literal(Literal::Unit))
}
Some(Token::Identifier) => {
let name = self.get_source_text(&self.current_span());
self.advance();
Ok(Expression::Identifier(name))
}
Some(Token::LeftParen) => {
self.advance();
let expr = self.parse_expression()?;
self.expect(Token::RightParen)?;
Ok(expr)
}
Some(Token::LeftBracket) => {
self.advance();
let mut elements = vec![];
while !matches!(self.current_token(), Some(Token::RightBracket)) {
elements.push(self.parse_expression()?);
if matches!(self.current_token(), Some(Token::Comma)) {
self.advance();
}
}
self.expect(Token::RightBracket)?;
Ok(Expression::List(elements))
}
Some(Token::LeftBrace) => {
self.advance();
let mut pairs = vec![];
while !matches!(self.current_token(), Some(Token::RightBrace)) {
let key = self.parse_expression()?;
self.expect(Token::Colon)?;
let value = self.parse_expression()?;
pairs.push((key, value));
if matches!(self.current_token(), Some(Token::Comma)) {
self.advance();
}
}
self.expect(Token::RightBrace)?;
Ok(Expression::Dict(pairs))
}
_ => Err(ParseError::UnexpectedToken(format!(
"Expected expression, found {:?}",
self.current_token()
))),
}
}
fn parse_arguments(&mut self) -> ParseResult<ParsedArguments> {
let mut args = vec![];
let mut kwargs = vec![];
let mut parsing_kwargs = false;
while !matches!(self.current_token(), Some(Token::RightParen)) {
if matches!(self.current_token(), Some(Token::Identifier))
&& matches!(self.peek_token(), Some(Token::Equal))
{
parsing_kwargs = true;
let key = self.get_source_text(&self.current_span());
self.advance(); self.advance(); let value = self.parse_expression()?;
kwargs.push((key, value));
} else if parsing_kwargs {
return Err(ParseError::SyntaxError {
line: self.current_line,
message: "Positional argument after keyword argument".to_string(),
});
} else {
args.push(self.parse_expression()?);
}
if matches!(self.current_token(), Some(Token::Comma)) {
self.advance();
}
}
Ok((args, kwargs))
}
}
pub fn parse_glyph(source: &str) -> ParseResult<GlyphModule> {
let mut parser = Parser::new(source);
parser.parse()
}