use crate::{
grammar::parse_comment,
kind::LuaTokenKind,
lexer::{LuaDocLexer, LuaDocLexerState, LuaTokenData},
parser_error::LuaParseError,
text::SourceRange,
};
use super::{LuaParser, MarkEvent, MarkerEventContainer};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LuaDocParserState {
Normal,
Mapped,
Extends,
}
pub struct LuaDocParser<'a, 'b> {
lua_parser: &'a mut LuaParser<'b>,
tokens: &'a [LuaTokenData],
pub lexer: LuaDocLexer<'a>,
current_token: LuaTokenKind,
current_token_range: SourceRange,
origin_token_index: usize,
pub state: LuaDocParserState,
}
impl MarkerEventContainer for LuaDocParser<'_, '_> {
fn get_mark_level(&self) -> usize {
self.lua_parser.get_mark_level()
}
fn incr_mark_level(&mut self) {
self.lua_parser.incr_mark_level()
}
fn decr_mark_level(&mut self) {
self.lua_parser.decr_mark_level()
}
fn get_events(&mut self) -> &mut Vec<MarkEvent> {
self.lua_parser.get_events()
}
}
impl<'b> LuaDocParser<'_, 'b> {
pub fn parse(lua_parser: &mut LuaParser<'_>, tokens: &[LuaTokenData]) {
let lexer = LuaDocLexer::new(lua_parser.origin_text());
let mut parser = LuaDocParser {
lua_parser,
tokens,
lexer,
current_token: LuaTokenKind::None,
current_token_range: SourceRange::EMPTY,
origin_token_index: 0,
state: LuaDocParserState::Normal,
};
parser.init();
parse_comment(&mut parser);
}
fn init(&mut self) {
if self.tokens.is_empty() {
return;
}
self.bump();
}
pub fn bump(&mut self) {
if !is_invalid_kind(self.current_token) {
self.lua_parser.get_events().push(MarkEvent::EatToken {
kind: self.current_token,
range: self.current_token_range,
});
}
self.calc_next_current_token();
}
fn calc_next_current_token(&mut self) {
let token = self.lex_token();
self.current_token = token.kind;
self.current_token_range = token.range;
if self.current_token == LuaTokenKind::TkEof {
return;
}
match self.lexer.state {
LuaDocLexerState::Normal
| LuaDocLexerState::Version
| LuaDocLexerState::Mapped
| LuaDocLexerState::Extends => {
while matches!(
self.current_token,
LuaTokenKind::TkDocContinue
| LuaTokenKind::TkEndOfLine
| LuaTokenKind::TkWhitespace
) {
self.eat_current_and_lex_next();
}
}
LuaDocLexerState::FieldStart
| LuaDocLexerState::See
| LuaDocLexerState::Source
| LuaDocLexerState::AttributeUse => {
while matches!(self.current_token, LuaTokenKind::TkWhitespace) {
self.eat_current_and_lex_next();
}
}
LuaDocLexerState::CastExpr => {
while matches!(self.current_token, LuaTokenKind::TkWhitespace) {
self.eat_current_and_lex_next();
}
}
LuaDocLexerState::Init => {
while matches!(
self.current_token,
LuaTokenKind::TkEndOfLine | LuaTokenKind::TkWhitespace
) {
self.eat_current_and_lex_next();
}
}
_ => {}
}
}
fn eat_current_and_lex_next(&mut self) {
self.lua_parser.get_events().push(MarkEvent::EatToken {
kind: self.current_token,
range: self.current_token_range,
});
let token = self.lex_token();
self.current_token = token.kind;
if !token.range.is_empty() {
self.current_token_range = token.range;
}
}
fn lex_token(&mut self) -> LuaTokenData {
#[allow(unused_assignments)]
let mut kind = LuaTokenKind::TkEof;
loop {
if self.lexer.is_invalid() {
let next_origin_index =
if self.origin_token_index == 0 && self.current_token == LuaTokenKind::None {
0
} else {
self.origin_token_index + 1
};
if next_origin_index >= self.tokens.len() {
return LuaTokenData::new(
LuaTokenKind::TkEof,
SourceRange::new(self.current_token_range.end_offset(), 0),
);
}
let next_origin_token = self.tokens[next_origin_index];
self.origin_token_index = next_origin_index;
if next_origin_token.kind == LuaTokenKind::TkEndOfLine
|| next_origin_token.kind == LuaTokenKind::TkWhitespace
|| next_origin_token.kind == LuaTokenKind::TkShebang
{
return next_origin_token;
}
self.lexer
.reset(next_origin_token.kind, next_origin_token.range);
}
kind = self.lexer.lex();
if kind != LuaTokenKind::TkEof {
break;
}
}
LuaTokenData::new(kind, self.lexer.current_token_range())
}
pub fn current_token(&self) -> LuaTokenKind {
self.current_token
}
pub fn current_token_range(&self) -> SourceRange {
self.current_token_range
}
pub fn current_token_text(&self) -> &'b str {
let range = self.current_token_range;
&self.origin_text()[range.start_offset..range.end_offset()]
}
pub fn origin_text(&self) -> &'b str {
self.lua_parser.origin_text()
}
pub fn set_lexer_state(&mut self, state: LuaDocLexerState) {
match state {
LuaDocLexerState::Description => {
if !matches!(
self.current_token,
LuaTokenKind::TkWhitespace
| LuaTokenKind::TkEndOfLine
| LuaTokenKind::TkEof
| LuaTokenKind::TkDocContinueOr
| LuaTokenKind::TkNormalStart
| LuaTokenKind::TkLongCommentStart
| LuaTokenKind::TkDocStart
| LuaTokenKind::TkDocLongStart
| LuaTokenKind::TkLongCommentEnd
) {
self.re_calc_detail();
}
}
LuaDocLexerState::Trivia => {
if !matches!(
self.current_token,
LuaTokenKind::TkWhitespace
| LuaTokenKind::TkEndOfLine
| LuaTokenKind::TkEof
| LuaTokenKind::TkDocContinueOr
) {
self.current_token = LuaTokenKind::TkDocTrivia;
}
}
LuaDocLexerState::Normal => {
if self.lexer.state == LuaDocLexerState::CastExpr {
self.re_calc_cast_type();
}
}
_ => {}
}
self.lexer.state = state;
}
fn re_calc_detail(&mut self) {
self.current_token = LuaTokenKind::TkDocDetail;
if self.lexer.is_invalid() {
return;
}
self.current_token = LuaTokenKind::None;
let read_range = self.current_token_range;
let origin_token_range = self.tokens[self.origin_token_index].range;
let origin_token_kind = self.tokens[self.origin_token_index].kind;
let new_range = SourceRange {
start_offset: read_range.start_offset,
length: origin_token_range.end_offset() - read_range.start_offset,
};
self.lexer.reset(origin_token_kind, new_range);
self.lexer.state = LuaDocLexerState::Description;
self.bump();
}
fn re_calc_cast_type(&mut self) {
if self.lexer.is_invalid() {
return;
}
let read_range = self.current_token_range;
let origin_token_range = self.tokens[self.origin_token_index].range;
let origin_token_kind = self.tokens[self.origin_token_index].kind;
let new_range = SourceRange {
start_offset: read_range.start_offset,
length: origin_token_range.end_offset() - read_range.start_offset,
};
self.lexer.reset(origin_token_kind, new_range);
self.lexer.state = LuaDocLexerState::Normal;
let token = self.lex_token();
self.current_token = token.kind;
if !token.range.is_empty() {
self.current_token_range = token.range;
}
}
pub fn bump_to_end(&mut self) {
self.set_lexer_state(LuaDocLexerState::Trivia);
self.eat_current_and_lex_next();
self.set_lexer_state(LuaDocLexerState::Init);
self.bump();
}
pub fn push_error(&mut self, error: LuaParseError) {
self.lua_parser.errors.push(error);
}
pub fn set_parser_state(&mut self, state: LuaDocParserState) {
self.state = state;
}
pub fn set_current_token_kind(&mut self, kind: LuaTokenKind) {
self.current_token = kind;
}
}
fn is_invalid_kind(kind: LuaTokenKind) -> bool {
matches!(kind, LuaTokenKind::None | LuaTokenKind::TkEof)
}