resolve function call ambiguity

This commit is contained in:
minish 2025-07-01 20:26:03 -04:00
parent c9a404a5f9
commit 29b8d9644f
Signed by: min
SSH Key Fingerprint: SHA256:h4k7JNrfe1dzv1WE3oGVeAY9DPSZXIu3/j89+6DtHWE
2 changed files with 40 additions and 6 deletions

View File

@ -45,6 +45,7 @@ pub enum Token {
ParenClose, ParenClose,
Comma, Comma,
Eol,
Return, Return,
@ -176,7 +177,7 @@ where
fn lex_whitespace(&mut self) -> Option<char> { fn lex_whitespace(&mut self) -> Option<char> {
loop { loop {
match self.peek()? { match self.peek()? {
' ' | '\t' | '\n' | '\r' => self.eat(), ' ' | '\t' | '\r' => self.eat(),
_ => break self.peek(), _ => break self.peek(),
} }
} }
@ -322,6 +323,9 @@ where
continue; continue;
} }
// ;, \n eol
'\n' | ';' => self.eat_to(Token::Eol),
// unexpected character // unexpected character
c => Some(Err(LexError::UnexpectedCharacter(c))), c => Some(Err(LexError::UnexpectedCharacter(c))),
}; };

View File

@ -65,6 +65,7 @@ pub type Result<T> = std::result::Result<T, ParseError>;
pub struct Parser<I: Iterator<Item = Token>> { pub struct Parser<I: Iterator<Item = Token>> {
tokens: Peekable<I>, tokens: Peekable<I>,
is_next_eol: bool,
} }
impl<I> Parser<I> impl<I> Parser<I>
where where
@ -72,7 +73,10 @@ where
{ {
pub fn new(tokens: I) -> Self { pub fn new(tokens: I) -> Self {
let tokens = tokens.peekable(); let tokens = tokens.peekable();
Self { tokens } Self {
tokens,
is_next_eol: false,
}
} }
fn eat(&mut self) { fn eat(&mut self) {
@ -81,10 +85,26 @@ where
fn next_unwrap(&mut self) -> Token { fn next_unwrap(&mut self) -> Token {
self.try_next().unwrap() self.try_next().unwrap()
} }
fn skip_eol(&mut self) -> bool {
let mut did_skip = false;
while matches!(self.tokens.peek(), Some(Token::Eol)) {
self.tokens.next();
did_skip = true;
}
return did_skip;
}
fn try_peek(&mut self) -> Result<&Token> { fn try_peek(&mut self) -> Result<&Token> {
// Peek doesn't advance the token stream, so
// don't allow it to unset the EOL flag
if self.skip_eol() {
self.is_next_eol = true;
}
self.tokens.peek().ok_or(ParseError::UnexpectedEnd) self.tokens.peek().ok_or(ParseError::UnexpectedEnd)
} }
fn try_next(&mut self) -> Result<Token> { fn try_next(&mut self) -> Result<Token> {
self.is_next_eol = self.skip_eol();
self.tokens.next().ok_or(ParseError::UnexpectedEnd) self.tokens.next().ok_or(ParseError::UnexpectedEnd)
} }
@ -92,6 +112,7 @@ where
let mut lhs = match self.try_next()? { let mut lhs = match self.try_next()? {
// literal // literal
Token::Literal(lit) => Box::new(Expr::Literal(lit)), Token::Literal(lit) => Box::new(Expr::Literal(lit)),
// start of group // start of group
Token::ParenOpen => { Token::ParenOpen => {
// begin a new expr parse (group mode) // begin a new expr parse (group mode)
@ -107,6 +128,7 @@ where
self.eat(); self.eat();
Box::new(Expr::Block(b)) Box::new(Expr::Block(b))
} }
// unary ops!! (prefix) // unary ops!! (prefix)
t if t.prefix_precedence().is_some() => { t if t.prefix_precedence().is_some() => {
let prec = t.prefix_precedence().unwrap(); let prec = t.prefix_precedence().unwrap();
@ -118,6 +140,7 @@ where
_ => unreachable!(), _ => unreachable!(),
}) })
} }
// unexpected token // unexpected token
t => return Err(ParseError::UnexpectedToken(t)), t => return Err(ParseError::UnexpectedToken(t)),
}; };
@ -128,8 +151,18 @@ where
Ok(Token::ParenClose) if in_group => break, Ok(Token::ParenClose) if in_group => break,
// end (stream) // end (stream)
Err(_) if !in_group => break, Err(_) if !in_group => break,
// unexpected end
Err(err) => return Err(err),
// operator
Ok(t) if t.infix_precedence().is_some() => t,
// function call // function call
Ok(Token::ParenOpen) => { Ok(Token::ParenOpen) => {
if self.is_next_eol {
break;
}
// eat opening paren // eat opening paren
self.eat(); self.eat();
@ -151,12 +184,9 @@ where
lhs = Box::new(Expr::Call(lhs, exprs)); lhs = Box::new(Expr::Call(lhs, exprs));
continue; continue;
} }
// operator
Ok(t) if t.infix_precedence().is_some() => t,
// unexpected token (stop trying to parse) // unexpected token (stop trying to parse)
Ok(_) => break, Ok(_) => break,
// unexpected end
Err(err) => return Err(err),
}; };
let (prec, assoc) = op.infix_precedence().unwrap(); let (prec, assoc) = op.infix_precedence().unwrap();