luau_parser/impl/value/
table.rs

1//! All `impl` blocks for table-related types:
2//!
3//! * [`TableKey`]
4//! * [`TableField`]
5//! * [`TableFieldValue`]
6//! * [`Table`]
7
8use lsp_types::Range;
9use luau_lexer::prelude::{Error, Lexer, Symbol, Token, TokenType};
10use std::cell::Cell;
11
12use crate::{
13    safe_unwrap,
14    types::{
15        Bracketed, BracketedList, Expression, FunctionArguments, GetRange, GetRangeError, Parse,
16        ParseWithArgs, Pointer, Print, Table, TableAccessKey, TableField, TableFieldValue,
17        TableKey, TryParse, TryParseWithArgs, TypeValue,
18    },
19};
20
21/// A simple struct holding arguments needed for parsing tables.
22#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
23struct ParseArgs {
24    /// Whether or not it's currently parsing a type.
25    is_type: bool,
26
27    /// The number of keys it inferred. Only for expressions.
28    inferred_keys: Cell<u32>,
29}
30impl ParseArgs {
31    /// Create new [`ParseArgs`].
32    #[inline]
33    const fn new(is_type: bool, inferred_keys: u32) -> Self {
34        Self {
35            is_type,
36            inferred_keys: Cell::new(inferred_keys),
37        }
38    }
39}
40
41impl TableKey {
42    /// Crate a new [`TableKey::UndefinedNumber`] from the passed [`ParseArgs`].
43    #[inline]
44    fn undefined_number(parse_args: &ParseArgs) -> Self {
45        Self::UndefinedNumber(
46            parse_args
47                .inferred_keys
48                .replace(parse_args.inferred_keys.get() + 1),
49        )
50    }
51
52    /// Crate a new [`TableKey::UndefinedString`] from the passed [`ParseArgs`].
53    #[inline]
54    fn undefined_string() -> Self {
55        Self::UndefinedString("number".into())
56    }
57}
58
59impl ParseWithArgs<bool> for TableKey {
60    fn parse_with(
61        token: Token,
62        lexer: &mut Lexer,
63        errors: &mut Vec<Error>,
64        is_type: bool,
65    ) -> Option<Self> {
66        match token.token_type {
67            TokenType::Identifier(_) | TokenType::PartialKeyword(_) => Some(Self::Simple(token)),
68            TokenType::Symbol(Symbol::OpeningBrackets) => {
69                if is_type {
70                    Bracketed::<_>::parse_with(
71                        token,
72                        lexer,
73                        errors,
74                        ("Expected <type>", Symbol::ClosingBrackets),
75                    )
76                    .map(Self::Type)
77                } else {
78                    Bracketed::<_>::parse_with(
79                        token,
80                        lexer,
81                        errors,
82                        ("Expected <expr>", Symbol::ClosingBrackets),
83                    )
84                    .map(Self::Expression)
85                }
86            }
87            _ => None,
88        }
89    }
90}
91
92impl ParseWithArgs<&ParseArgs> for TableField {
93    fn parse_with(
94        token: Token,
95        lexer: &mut Lexer,
96        errors: &mut Vec<Error>,
97        parse_args: &ParseArgs,
98    ) -> Option<Self> {
99        if token == TokenType::Symbol(Symbol::ClosingCurlyBrackets) {
100            // Sometimes causes issues when the last item in the table is trailing
101            // this just ensures it never happens.
102            return None;
103        }
104
105        let state = lexer.save_state();
106
107        let (key, equal_or_colon) =
108            TableKey::parse_with(token.clone(), lexer, errors, parse_args.is_type).map_or(
109                (None, None),
110                |key| {
111                    // False warning
112                    // https://github.com/rust-lang/rust-clippy/issues/14873
113                    #[allow(clippy::branches_sharing_code)]
114                    let equal_or_colon = if parse_args.is_type {
115                        maybe_next_token!(lexer, temp, TokenType::Symbol(Symbol::Colon));
116
117                        temp
118                    } else {
119                        maybe_next_token!(lexer, temp, TokenType::Symbol(Symbol::Equal));
120
121                        temp
122                    };
123
124                    (Some(Pointer::new(key)), equal_or_colon)
125                },
126            );
127
128        if key.is_none() || equal_or_colon.is_none() {
129            lexer.set_state(state);
130
131            return Some(Self {
132                key: if parse_args.is_type {
133                    Pointer::new(TableKey::undefined_string())
134                } else {
135                    Pointer::new(TableKey::undefined_number(parse_args))
136                },
137                equal_or_colon: None,
138                value: safe_unwrap!(
139                    lexer,
140                    errors,
141                    "Expected <type>",
142                    TableFieldValue::parse_with(token, lexer, errors, parse_args.is_type)
143                        .map(Pointer::new)
144                ),
145            });
146        }
147
148        // SAFETY: We just checked it above.
149        #[allow(clippy::unwrap_used)]
150        let key = key.unwrap();
151
152        let value = Pointer::new(TableFieldValue::try_parse_with(
153            lexer,
154            errors,
155            parse_args.is_type,
156        )?);
157
158        Some(Self {
159            key,
160            equal_or_colon,
161            value,
162        })
163    }
164}
165
166impl ParseWithArgs<bool> for TableFieldValue {
167    #[inline]
168    fn parse_with(
169        token: Token,
170        lexer: &mut Lexer,
171        errors: &mut Vec<Error>,
172        is_type: bool,
173    ) -> Option<Self> {
174        if is_type {
175            TypeValue::parse(token, lexer, errors).map(Self::Type)
176        } else if token == TokenType::Symbol(Symbol::Ellipses) {
177            Some(Self::VariadicValues(token))
178        } else {
179            Expression::parse(token, lexer, errors).map(Self::Expression)
180        }
181    }
182}
183
184impl ParseWithArgs<bool> for Table {
185    fn parse_with(
186        token: Token,
187        lexer: &mut Lexer,
188        errors: &mut Vec<Error>,
189        is_type: bool,
190    ) -> Option<Self> {
191        if !matches!(
192            token.token_type,
193            TokenType::Symbol(Symbol::OpeningCurlyBrackets)
194        ) {
195            return None;
196        }
197
198        BracketedList::<TableField>::parse_with(
199            token,
200            lexer,
201            errors,
202            (
203                "Expected <table-field>",
204                Symbol::ClosingCurlyBrackets,
205                &ParseArgs::new(is_type, 1),
206            ),
207        )
208        .map(Self)
209    }
210}
211
212impl Parse<FunctionArguments> for Table {
213    #[inline]
214    fn parse(
215        token: Token,
216        lexer: &mut Lexer,
217        errors: &mut Vec<Error>,
218    ) -> Option<FunctionArguments> {
219        Self::parse_with(token, lexer, errors, false).map(FunctionArguments::Table)
220    }
221}
222impl TryParse<FunctionArguments> for Table {}
223
224impl Parse<TableAccessKey> for TableKey {
225    #[inline]
226    fn parse(token: Token, lexer: &mut Lexer, errors: &mut Vec<Error>) -> Option<TableAccessKey> {
227        Self::parse_with(token, lexer, errors, false)
228            .map(Pointer::new)
229            .map(TableAccessKey::Expression)
230    }
231}
232impl TryParse<TableAccessKey> for TableKey {}
233
234impl GetRange for TableKey {
235    #[inline]
236    fn get_range(&self) -> Result<Range, GetRangeError> {
237        match self {
238            Self::ERROR => Err(GetRangeError::ErrorVariant),
239            Self::UndefinedNumber(_) | Self::UndefinedString(_) => {
240                Err(GetRangeError::UndefinedKey)
241            }
242            Self::Simple(token) => token.get_range(),
243            Self::Expression(bracketed) => bracketed.get_range(),
244            Self::Type(bracketed) => bracketed.get_range(),
245        }
246    }
247}
248
249impl GetRange for TableField {
250    #[inline]
251    fn get_range(&self) -> Result<Range, GetRangeError> {
252        let value_range = self.value.get_range();
253
254        if let Ok(key_range) = self.key.get_range() {
255            Ok(Range::new(key_range.start, value_range?.end))
256        } else {
257            value_range
258        }
259    }
260}
261
262impl Print for TableKey {
263    #[inline]
264    fn print(&self) -> String {
265        match self {
266            Self::Simple(token) => token.print(),
267            Self::Expression(bracketed) => bracketed.print(),
268            Self::Type(bracketed) => bracketed.print(),
269            _ => "".to_string(),
270        }
271    }
272
273    #[inline]
274    fn print_final_trivia(&self) -> String {
275        match self {
276            Self::Simple(token) => token.print_final_trivia(),
277            Self::Expression(bracketed) => bracketed.print_final_trivia(),
278            Self::Type(bracketed) => bracketed.print_final_trivia(),
279            _ => "".to_string(),
280        }
281    }
282
283    #[inline]
284    fn print_without_final_trivia(&self) -> String {
285        match self {
286            Self::Simple(token) => token.print_without_final_trivia(),
287            Self::Expression(bracketed) => bracketed.print_without_final_trivia(),
288            Self::Type(bracketed) => bracketed.print_without_final_trivia(),
289            _ => "".to_string(),
290        }
291    }
292}
293
294impl Print for TableField {
295    #[inline]
296    fn print_without_final_trivia(&self) -> String {
297        self.key.print_without_final_trivia()
298            + &self.equal_or_colon.print_without_final_trivia()
299            + &self.value.print_without_final_trivia()
300    }
301
302    #[inline]
303    fn print_final_trivia(&self) -> String {
304        self.value.print_final_trivia()
305    }
306}