1use crate::allocator::AstArena;
2use crate::ast::{
3 ArgumentName, AstString, Attribute, AttributeKind, BinaryOp, Block, BlockNode, ClassMember,
4 DeclaredExternTypeProperty, Expression, ExpressionInit, ExpressionKind, Function, GenericType,
5 GenericTypePack, IndexNameOp, Local, LocalInit, Statement, StatementAssign, StatementClass,
6 StatementCompoundAssign, StatementDeclareExternType, StatementDeclareFunction,
7 StatementDeclareGlobal, StatementError, StatementExpression, StatementFunctionDeclaration,
8 StatementGenericFor, StatementIf, StatementLocal, StatementLocalFunction, StatementNumericFor,
9 StatementRepeat, StatementReturn, StatementTag, StatementTypeAlias, StatementTypeFunction,
10 StatementUnit, StatementWhile, StringQuoteStyle, TableAccess, TableItem, TableTypeIndexer,
11 TableTypeProp, Type, TypeKind, TypeList, TypeOrPack, TypePack, TypePackKind, UnaryOp,
12};
13use crate::ast_names::{AstName, AstNameDenseHasher, AstNameTable};
14use crate::cst::{
15 CstAttrList, CstAttribute, CstExprCall, CstExprConstantInteger, CstExprConstantNumber,
16 CstExprConstantString, CstExprExplicitTypeInstantiation, CstExprFunction, CstExprGroup,
17 CstExprIfElse, CstExprIndexExpr, CstExprInterpString, CstExprOp, CstExprTable,
18 CstExprTableItem, CstExprTypeAssertion, CstGenericType, CstGenericTypePack, CstNode,
19 CstStatAssign, CstStatCompoundAssign, CstStatDo, CstStatFor, CstStatForIn, CstStatFunction,
20 CstStatLocal, CstStatLocalFunction, CstStatRepeat, CstStatReturn, CstStatTypeAlias,
21 CstStatTypeFunction, CstStringQuoteStyle, CstTypeFunction, CstTypeGroup, CstTypeInstantiation,
22 CstTypeIntersection, CstTypePackExplicit, CstTypePackGeneric, CstTypePackParentheses,
23 CstTypeReference, CstTypeSingletonString, CstTypeTable, CstTypeTableItem, CstTypeTableItemKind,
24 CstTypeTypeof, CstTypeUnion, TableSeparator,
25};
26
27use crate::lexer::{
28 Lexer, ReservedWord as R, Token, TokenKind, fixup_string_bytes, multiline_string_bytes,
29};
30use crate::location::{Location, Position};
31pub(in crate::parser) use luau_common::flags;
32use luau_common::{DenseHashMap, time_trace};
33use std::sync::OnceLock;
34
35mod analysis;
36mod arena;
37mod attributes;
38pub(in crate::parser) use attributes::ParsedAttributes;
39mod binding;
40mod block;
41mod comments;
42mod context;
43mod cst;
44mod cursor;
45mod declaration;
46mod diagnostics;
47mod errors;
48mod expression;
49mod function;
50pub(in crate::parser) use function::{FunctionLocalBinding, FunctionParseContext};
51mod locals;
52mod model;
53mod number;
54mod recovery;
55mod scratch;
56mod session;
57mod state;
58mod statement;
59mod temp_vec;
60mod types;
61
62use analysis::{
63 BinaryPriority, ExpressionAnalysis, ExpressionSliceAnalysis, LuauKeyword, StatementAnalysis,
64 TokenAnalysis,
65};
66pub(in crate::parser) use binding::{Binding, ParsedBindingList};
67use comments::CommentState;
68use model::ParseMetadata;
69pub use model::{
70 Comment, CommentKind, CompileDirective, FragmentParseResumeSettings, HotComment, Mode,
71 ParseError, ParseErrors, ParseMessage, ParseNodeResult, ParseOptions, ParseResult,
72};
73use state::{ContextState, CstState, DiagnosticState, LocalState, RecoveryState};
74use temp_vec::{ScratchVec, TempVector};
75
76type Result<T> = std::result::Result<T, ParseError>;
77
78const BLOCK_FOLLOW: &[&str] = &["else", "elseif", "end", "until"];
79
80pub fn parse<'ast, 'name>(
81 source: &str,
82 arena: &'ast AstArena,
83 names: &mut AstNameTable<'name>,
84 options: ParseOptions,
85) -> std::result::Result<ParseResult<'ast>, ParseErrors>
86where
87 'name: 'ast,
88{
89 parse_bytes(source.as_bytes(), arena, names, options)
90}
91
92pub fn parse_bytes<'ast, 'name>(
93 source: &[u8],
94 arena: &'ast AstArena,
95 names: &mut AstNameTable<'name>,
96 options: ParseOptions,
97) -> std::result::Result<ParseResult<'ast>, ParseErrors>
98where
99 'name: 'ast,
100{
101 Parser::new(source, arena, names, options, None).parse()
102}
103
104pub fn parse_fragment<'ast, 'name>(
105 source: &str,
106 arena: &'ast AstArena,
107 names: &mut AstNameTable<'name>,
108 options: ParseOptions,
109 resume: FragmentParseResumeSettings<'ast>,
110) -> std::result::Result<ParseResult<'ast>, ParseErrors>
111where
112 'name: 'ast,
113{
114 parse_fragment_bytes(source.as_bytes(), arena, names, options, resume)
115}
116
117pub fn parse_fragment_bytes<'ast, 'name>(
118 source: &[u8],
119 arena: &'ast AstArena,
120 names: &mut AstNameTable<'name>,
121 options: ParseOptions,
122 resume: FragmentParseResumeSettings<'ast>,
123) -> std::result::Result<ParseResult<'ast>, ParseErrors>
124where
125 'name: 'ast,
126{
127 Parser::new(source, arena, names, options, Some(&resume)).parse()
128}
129
130pub fn parse_expression<'ast, 'name>(
131 source: &[u8],
132 arena: &'ast AstArena,
133 names: &mut AstNameTable<'name>,
134 options: ParseOptions,
135) -> std::result::Result<ParseNodeResult<'ast, Expression<'ast>>, ParseErrors>
136where
137 'name: 'ast,
138{
139 Parser::new(source, arena, names, options, None).parse_expression_node()
140}
141
142pub fn parse_type<'ast, 'name>(
143 source: &[u8],
144 arena: &'ast AstArena,
145 names: &mut AstNameTable<'name>,
146 options: ParseOptions,
147) -> std::result::Result<ParseNodeResult<'ast, Type<'ast>>, ParseErrors>
148where
149 'name: 'ast,
150{
151 Parser::new(source, arena, names, options, None).parse_type_node()
152}
153
154struct Parser<'source, 'ast, 'name, 'names>
155where
156 'name: 'ast,
157{
158 options: ParseOptions,
159 lexer: Lexer<'source, 'ast, 'name, 'names>,
160 base_position: Position,
161 arena: &'ast AstArena,
162 current: Token<'source, 'ast>,
163 diagnostics: DiagnosticState,
164 comments: CommentState,
165 cst: CstState<'ast>,
166 contexts: ContextState,
167 locals: LocalState<'ast>,
168 recovery: RecoveryState,
169 name_self: AstName<'ast>,
170 name_number: AstName<'ast>,
171 name_error: AstName<'ast>,
172 name_nil: AstName<'ast>,
173 declared_export_bindings: DenseHashMap<AstName<'ast>, Location, AstNameDenseHasher>,
174 has_module_return: bool,
175 scratch_stat: ScratchVec<Statement<'ast>>,
176 scratch_expr: ScratchVec<Expression<'ast>>,
177 scratch_expr_aux: ScratchVec<Expression<'ast>>,
178 scratch_string: ScratchVec<AstString<'ast>>,
179 scratch_string2: ScratchVec<AstString<'ast>>,
180 scratch_attr: ScratchVec<&'ast Attribute<'ast>>,
181 scratch_binding: ScratchVec<Binding<'ast>>,
182 scratch_table_items: ScratchVec<TableItem<'ast>>,
183 scratch_cst_table_items: ScratchVec<CstExprTableItem>,
184 scratch_class_members: ScratchVec<ClassMember<'ast>>,
185 scratch_declared_extern_type_props: ScratchVec<DeclaredExternTypeProperty<'ast>>,
186 scratch_type: ScratchVec<Type<'ast>>,
187 scratch_type_or_pack: ScratchVec<TypeOrPack<'ast>>,
188 scratch_arg_name: ScratchVec<ArgumentName<'ast>>,
189 scratch_opt_arg_name: ScratchVec<Option<ArgumentName<'ast>>>,
190 scratch_generic_types: ScratchVec<&'ast GenericType<'ast>>,
191 scratch_generic_type_packs: ScratchVec<&'ast GenericTypePack<'ast>>,
192 scratch_local: ScratchVec<&'ast Local<'ast>>,
193 scratch_table_type_props: ScratchVec<TableTypeProp<'ast>>,
194 scratch_cst_table_type_items: ScratchVec<CstTypeTableItem<'ast>>,
195 scratch_position: ScratchVec<Position>,
196 scratch_position2: ScratchVec<Option<Position>>,
197}
198
199#[derive(Debug, Clone, Copy)]
200struct BlockContext {
201 opener: &'static str,
202 line: usize,
203 column: usize,
204}
205
206#[derive(Debug, Clone, Copy, Default)]
207struct FunctionContext {
208 loop_depth: usize,
209 vararg: bool,
210}
211
212struct ParsedCallArguments<'ast> {
213 arguments: &'ast [Expression<'ast>],
214 location: Location,
215 end: Position,
216 cst: Option<CstExprCall>,
217}
218
219struct ParsedCallList<'ast> {
220 arguments: &'ast [Expression<'ast>],
221 location: Location,
222 end: Position,
223 cst: CstExprCall,
224}
225
226struct ParsedTableFields<'ast> {
227 items: &'ast [TableItem<'ast>],
228 cst_items: Option<Vec<CstExprTableItem>>,
229}
230
231struct ParsedGenericParameters<'ast> {
232 types: Vec<&'ast GenericType<'ast>>,
233 type_packs: Vec<&'ast GenericTypePack<'ast>>,
234 open: Position,
235 commas: Vec<Position>,
236 close: Position,
237}
238
239struct ParsedTableAccess {
240 access: TableAccess,
241 location: Option<Location>,
242}
243
244struct ParsedStatement<'ast> {
245 statement: Statement<'ast>,
246}
247
248struct ParsedFunctionName<'ast> {
249 expression: Expression<'ast>,
250 has_self: bool,
251 debug_name: AstName<'ast>,
252}
253
254#[derive(Debug, Clone, Copy, PartialEq, Eq)]
255enum MatchRecoveryStop {
256 Equal,
257 RightParen,
258 ReservedEnd,
259 SkinnyArrow,
260}
261
262impl MatchRecoveryStop {
263 const COUNT: usize = 4;
264
265 const fn index(self) -> usize {
266 match self {
267 Self::Equal => 0,
268 Self::RightParen => 1,
269 Self::ReservedEnd => 2,
270 Self::SkinnyArrow => 3,
271 }
272 }
273}
274
275impl Default for ParsedGenericParameters<'_> {
276 fn default() -> Self {
277 Self {
278 types: Vec::new(),
279 type_packs: Vec::new(),
280 open: Position::missing(),
281 commas: Vec::new(),
282 close: Position::missing(),
283 }
284 }
285}