use super::*;
pub(in crate::parser) struct ParsedName<'ast> {
pub(in crate::parser) name: AstName<'ast>,
pub(in crate::parser) location: Location,
}
impl<'source, 'ast> Parser<'source, 'ast, '_, '_> {
pub(in crate::parser) fn expect_and_consume(
&mut self,
expected: Token<'source, 'ast>,
context: &'static str,
) -> bool {
let expected_kind = expected.kind();
if self.current.kind() == expected_kind {
self.advance();
true
} else {
self.report_parse_error(self.located(format!(
"Expected {} when parsing {context}, got {}",
expected, self.current
)));
if self.peek().kind() == expected_kind {
self.advance();
self.advance();
}
false
}
}
pub(in crate::parser) fn expect_and_consume_keyword(
&mut self,
expected: R,
context: &'static str,
) -> bool {
self.expect_and_consume(Token::Reserved(expected), context)
}
pub(in crate::parser) fn parse_index_name(
&mut self,
context: Option<&'static str>,
op_position: Position,
) -> Result<ParsedName<'ast>> {
match self.current {
Token::Ident(name) => {
let location = self.current_token_location();
self.advance();
Ok(ParsedName { name, location })
}
Token::Reserved(word) if self.current_position().line == op_position.line => {
self.report_parse_error(self.identifier_error(context));
let location = self.current_token_location();
let name = self.intern_name(word.as_str());
self.advance();
Ok(ParsedName { name, location })
}
_ => {
self.report_parse_error(self.identifier_error(context));
let location = self.current_token_location();
Ok(ParsedName {
name: self.name_error,
location: Location::new(location.begin, location.begin),
})
}
}
}
pub(in crate::parser) fn parse_name(&mut self, context: &'static str) -> ParsedName<'ast> {
match self.current {
Token::Ident(name) => {
let location = self.current_token_location();
self.advance();
ParsedName { name, location }
}
_ => {
let location = self.current_token_location();
self.report_parse_error(self.identifier_error(Some(context)));
ParsedName {
name: self.name_error,
location: Location::new(location.begin, location.begin),
}
}
}
}
#[inline(always)]
pub(in crate::parser) fn advance(&mut self) {
let mut update_previous_location = true;
loop {
self.lexer
.advance_lexeme_with_previous(false, update_previous_location);
update_previous_location = false;
let location = self.lexer.current_location();
let token = self.lexer.current_token();
match token {
Token::Comment(text) => {
self.capture_comment(CommentKind::Line, location);
self.capture_hotcomment(text, location);
}
Token::BlockComment(_) => {
self.capture_comment(CommentKind::Block, location);
}
Token::BrokenComment => {
self.capture_comment(CommentKind::Broken, location);
self.current = token;
return;
}
_ => {
self.current = token;
if self.current.kind() != TokenKind::Eof {
self.finish_hotcomment_header();
}
return;
}
}
}
}
pub(in crate::parser) fn peek(&mut self) -> Token<'source, 'ast> {
self.lexer.lookahead_token(true)
}
pub(in crate::parser) fn peek_nth(&mut self, n: usize) -> Token<'source, 'ast> {
if n == 0 {
return Token::Eof;
}
self.lexer.lookahead_nth_token(n, true)
}
#[inline(always)]
pub(in crate::parser) fn current_location(&self) -> Location {
self.current_token_location()
}
#[inline(always)]
pub(in crate::parser) fn current_position(&self) -> Position {
self.current_token_location().begin
}
#[inline(always)]
pub(in crate::parser) fn current_token_location(&self) -> Location {
self.lexer.current_location()
}
#[inline(always)]
pub(in crate::parser) fn previous_token_end_position(&self) -> Position {
self.previous_token_location().end
}
#[inline(always)]
pub(in crate::parser) fn previous_token_location(&self) -> Location {
self.lexer.previous_location()
}
#[inline(always)]
pub(in crate::parser) fn current_line(&self) -> usize {
self.current_token_location().begin.line as usize + 1
}
#[inline(always)]
pub(in crate::parser) fn current_column(&self) -> usize {
self.current_token_location().begin.column as usize + 1
}
#[inline(always)]
pub(in crate::parser) fn previous_line(&self) -> usize {
self.previous_token_location().begin.line as usize + 1
}
pub(in crate::parser) fn source_line_count(&self) -> usize {
let source = self.lexer.source();
self.current_token_location().end.line as usize
+ usize::from(!source.is_empty() && !source.ends_with(b"\n"))
}
#[inline(always)]
pub(in crate::parser) fn current_source_string(&self) -> AstString<'ast> {
match self.current {
Token::Number(source)
| Token::InterpStringBegin(source)
| Token::InterpStringMid(source)
| Token::InterpStringEnd(source)
| Token::InterpStringSimple(source) => self.ast_string(source),
Token::QuotedString { value, .. } | Token::RawString { value, .. } => {
self.ast_string(value)
}
_ => {
let (start, end) = self.lexer.current_span();
self.ast_string(&self.lexer.source()[start..end])
}
}
}
pub(in crate::parser) fn check_binary_confusables(
&mut self,
limit: u8,
) -> Option<BinaryPriority> {
match self.current {
Token::Ampersand | Token::Pipe | Token::Bang => {}
_ => return None,
}
let adjacent = self.lexer.lookahead_lexeme(true);
if adjacent.start != self.lexer.current_span().1 {
return None;
}
let op_position = self.current_position();
let location = Location::new(self.current_token_location().begin, adjacent.location.end);
match self.current {
Token::Bang if adjacent.token.kind() == TokenKind::Equal && 3 > limit => {
self.advance();
self.report_parse_error(ParseError::new(
location,
"Unexpected '!='; did you mean '~='?",
));
Some(BinaryPriority {
op: BinaryOp::NotEqual,
left: 3,
right: 3,
op_position: Some(op_position),
})
}
Token::Ampersand if adjacent.token.kind() == TokenKind::Ampersand && 2 > limit => {
self.advance();
self.report_parse_error(ParseError::new(
location,
"Unexpected '&&'; did you mean 'and'?",
));
Some(BinaryPriority {
op: BinaryOp::And,
left: 2,
right: 2,
op_position: Some(op_position),
})
}
Token::Pipe if adjacent.token.kind() == TokenKind::Pipe && 1 > limit => {
self.advance();
self.report_parse_error(ParseError::new(
location,
"Unexpected '||'; did you mean 'or'?",
));
Some(BinaryPriority {
op: BinaryOp::Or,
left: 1,
right: 1,
op_position: Some(op_position),
})
}
_ => None,
}
}
pub(in crate::parser) fn parse_interpolated_literal(
&self,
literal: &[u8],
) -> Result<AstString<'ast>> {
fixup_string_bytes(literal)
.map(|bytes| self.ast_string(&bytes))
.ok_or_else(|| self.interpolated_malformed_escape_error())
}
pub(in crate::parser) fn expect_function_left_paren(&mut self) -> Result<()> {
if self.current.kind() == TokenKind::LeftParen {
self.advance();
Ok(())
} else {
self.report_parse_error(self.located(format!(
"Expected '(' when parsing function, got {}",
self.current
)));
if self.peek().kind() == TokenKind::LeftParen {
self.advance();
self.advance();
}
Ok(())
}
}
}