use lsp_types::Range;
use luau_lexer::prelude::{Error, Lexer, Symbol, Token, TokenType};
use std::cell::Cell;
use crate::{
safe_unwrap,
types::{
Bracketed, BracketedList, Expression, FunctionArguments, GetRange, GetRangeError, Parse,
ParseWithArgs, Pointer, Print, Table, TableAccessKey, TableField, TableFieldValue,
TableKey, TryParse, TryParseWithArgs, TypeValue,
},
};
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
struct ParseArgs {
is_type: bool,
inferred_keys: Cell<u32>,
}
impl ParseArgs {
#[inline]
const fn new(is_type: bool, inferred_keys: u32) -> Self {
Self {
is_type,
inferred_keys: Cell::new(inferred_keys),
}
}
}
impl TableKey {
#[inline]
fn undefined_number(parse_args: &ParseArgs) -> Self {
Self::UndefinedNumber(
parse_args
.inferred_keys
.replace(parse_args.inferred_keys.get() + 1),
)
}
#[inline]
fn undefined_string() -> Self {
Self::UndefinedString("number".into())
}
}
impl ParseWithArgs<bool> for TableKey {
fn parse_with(
token: Token,
lexer: &mut Lexer,
errors: &mut Vec<Error>,
is_type: bool,
) -> Option<Self> {
match token.token_type {
TokenType::Identifier(_) | TokenType::PartialKeyword(_) => Some(Self::Simple(token)),
TokenType::Symbol(Symbol::OpeningBrackets) => {
if is_type {
Bracketed::<_>::parse_with(
token,
lexer,
errors,
("Expected <type>", Symbol::ClosingBrackets),
)
.map(Self::Type)
} else {
Bracketed::<_>::parse_with(
token,
lexer,
errors,
("Expected <expr>", Symbol::ClosingBrackets),
)
.map(Self::Expression)
}
}
_ => None,
}
}
}
impl ParseWithArgs<&ParseArgs> for TableField {
fn parse_with(
token: Token,
lexer: &mut Lexer,
errors: &mut Vec<Error>,
parse_args: &ParseArgs,
) -> Option<Self> {
if token == TokenType::Symbol(Symbol::ClosingCurlyBrackets) {
return None;
}
let state = lexer.save_state();
let (key, equal_or_colon) =
TableKey::parse_with(token.clone(), lexer, errors, parse_args.is_type).map_or(
(None, None),
|key| {
#[allow(clippy::branches_sharing_code)]
let equal_or_colon = if parse_args.is_type {
maybe_next_token!(lexer, temp, TokenType::Symbol(Symbol::Colon));
temp
} else {
maybe_next_token!(lexer, temp, TokenType::Symbol(Symbol::Equal));
temp
};
(Some(Pointer::new(key)), equal_or_colon)
},
);
if key.is_none() || equal_or_colon.is_none() {
lexer.set_state(state);
return Some(Self {
key: if parse_args.is_type {
Pointer::new(TableKey::undefined_string())
} else {
Pointer::new(TableKey::undefined_number(parse_args))
},
equal_or_colon: None,
value: safe_unwrap!(
lexer,
errors,
"Expected <type>",
TableFieldValue::parse_with(token, lexer, errors, parse_args.is_type)
.map(Pointer::new)
),
});
}
#[allow(clippy::unwrap_used)]
let key = key.unwrap();
let value = Pointer::new(TableFieldValue::try_parse_with(
lexer,
errors,
parse_args.is_type,
)?);
Some(Self {
key,
equal_or_colon,
value,
})
}
}
impl ParseWithArgs<bool> for TableFieldValue {
#[inline]
fn parse_with(
token: Token,
lexer: &mut Lexer,
errors: &mut Vec<Error>,
is_type: bool,
) -> Option<Self> {
if is_type {
TypeValue::parse(token, lexer, errors).map(Self::Type)
} else if token == TokenType::Symbol(Symbol::Ellipses) {
Some(Self::VariadicValues(token))
} else {
Expression::parse(token, lexer, errors).map(Self::Expression)
}
}
}
impl ParseWithArgs<bool> for Table {
fn parse_with(
token: Token,
lexer: &mut Lexer,
errors: &mut Vec<Error>,
is_type: bool,
) -> Option<Self> {
if !matches!(
token.token_type,
TokenType::Symbol(Symbol::OpeningCurlyBrackets)
) {
return None;
}
BracketedList::<TableField>::parse_with(
token,
lexer,
errors,
(
"Expected <table-field>",
Symbol::ClosingCurlyBrackets,
&ParseArgs::new(is_type, 1),
),
)
.map(Self)
}
}
impl Parse<FunctionArguments> for Table {
#[inline]
fn parse(
token: Token,
lexer: &mut Lexer,
errors: &mut Vec<Error>,
) -> Option<FunctionArguments> {
Self::parse_with(token, lexer, errors, false).map(FunctionArguments::Table)
}
}
impl TryParse<FunctionArguments> for Table {}
impl Parse<TableAccessKey> for TableKey {
#[inline]
fn parse(token: Token, lexer: &mut Lexer, errors: &mut Vec<Error>) -> Option<TableAccessKey> {
Self::parse_with(token, lexer, errors, false)
.map(Pointer::new)
.map(TableAccessKey::Expression)
}
}
impl TryParse<TableAccessKey> for TableKey {}
impl GetRange for TableKey {
#[inline]
fn get_range(&self) -> Result<Range, GetRangeError> {
match self {
Self::ERROR => Err(GetRangeError::ErrorVariant),
Self::UndefinedNumber(_) | Self::UndefinedString(_) => {
Err(GetRangeError::UndefinedKey)
}
Self::Simple(token) => token.get_range(),
Self::Expression(bracketed) => bracketed.get_range(),
Self::Type(bracketed) => bracketed.get_range(),
}
}
}
impl GetRange for TableField {
#[inline]
fn get_range(&self) -> Result<Range, GetRangeError> {
let value_range = self.value.get_range();
if let Ok(key_range) = self.key.get_range() {
Ok(Range::new(key_range.start, value_range?.end))
} else {
value_range
}
}
}
impl Print for TableKey {
#[inline]
fn print(&self) -> String {
match self {
Self::Simple(token) => token.print(),
Self::Expression(bracketed) => bracketed.print(),
Self::Type(bracketed) => bracketed.print(),
_ => "".to_string(),
}
}
#[inline]
fn print_final_trivia(&self) -> String {
match self {
Self::Simple(token) => token.print_final_trivia(),
Self::Expression(bracketed) => bracketed.print_final_trivia(),
Self::Type(bracketed) => bracketed.print_final_trivia(),
_ => "".to_string(),
}
}
#[inline]
fn print_without_final_trivia(&self) -> String {
match self {
Self::Simple(token) => token.print_without_final_trivia(),
Self::Expression(bracketed) => bracketed.print_without_final_trivia(),
Self::Type(bracketed) => bracketed.print_without_final_trivia(),
_ => "".to_string(),
}
}
}
impl Print for TableField {
#[inline]
fn print_without_final_trivia(&self) -> String {
self.key.print_without_final_trivia()
+ &self.equal_or_colon.print_without_final_trivia()
+ &self.value.print_without_final_trivia()
}
#[inline]
fn print_final_trivia(&self) -> String {
self.value.print_final_trivia()
}
}