use crate::allocator::AstArena;
use crate::ast::{
ArgumentName, AstString, Attribute, AttributeKind, BinaryOp, Block, BlockNode, ClassMember,
DeclaredExternTypeProperty, Expression, ExpressionInit, ExpressionKind, Function, GenericType,
GenericTypePack, IndexNameOp, Local, LocalInit, Statement, StatementAssign, StatementClass,
StatementCompoundAssign, StatementDeclareExternType, StatementDeclareFunction,
StatementDeclareGlobal, StatementError, StatementExpression, StatementFunctionDeclaration,
StatementGenericFor, StatementIf, StatementLocal, StatementLocalFunction, StatementNumericFor,
StatementRepeat, StatementReturn, StatementTag, StatementTypeAlias, StatementTypeFunction,
StatementUnit, StatementWhile, StringQuoteStyle, TableAccess, TableItem, TableTypeIndexer,
TableTypeProp, Type, TypeKind, TypeList, TypeOrPack, TypePack, TypePackKind, UnaryOp,
};
use crate::ast_names::{AstName, AstNameDenseHasher, AstNameTable};
use crate::cst::{
CstAttrList, CstAttribute, CstExprCall, CstExprConstantInteger, CstExprConstantNumber,
CstExprConstantString, CstExprExplicitTypeInstantiation, CstExprFunction, CstExprGroup,
CstExprIfElse, CstExprIndexExpr, CstExprInterpString, CstExprOp, CstExprTable,
CstExprTableItem, CstExprTypeAssertion, CstGenericType, CstGenericTypePack, CstNode,
CstStatAssign, CstStatCompoundAssign, CstStatDo, CstStatFor, CstStatForIn, CstStatFunction,
CstStatLocal, CstStatLocalFunction, CstStatRepeat, CstStatReturn, CstStatTypeAlias,
CstStatTypeFunction, CstStringQuoteStyle, CstTypeFunction, CstTypeGroup, CstTypeInstantiation,
CstTypeIntersection, CstTypePackExplicit, CstTypePackGeneric, CstTypePackParentheses,
CstTypeReference, CstTypeSingletonString, CstTypeTable, CstTypeTableItem, CstTypeTableItemKind,
CstTypeTypeof, CstTypeUnion, TableSeparator,
};
use crate::lexer::{
Lexer, ReservedWord as R, Token, TokenKind, fixup_string_bytes, multiline_string_bytes,
};
use crate::location::{Location, Position};
pub(in crate::parser) use luau_common::flags;
use luau_common::{DenseHashMap, time_trace};
use std::sync::OnceLock;
mod analysis;
mod arena;
mod attributes;
pub(in crate::parser) use attributes::ParsedAttributes;
mod binding;
mod block;
mod comments;
mod context;
mod cst;
mod cursor;
mod declaration;
mod diagnostics;
mod errors;
mod expression;
mod function;
pub(in crate::parser) use function::{FunctionLocalBinding, FunctionParseContext};
mod locals;
mod model;
mod number;
mod recovery;
mod scratch;
mod session;
mod state;
mod statement;
mod temp_vec;
mod types;
use analysis::{
BinaryPriority, ExpressionAnalysis, ExpressionSliceAnalysis, LuauKeyword, StatementAnalysis,
TokenAnalysis,
};
pub(in crate::parser) use binding::{Binding, ParsedBindingList};
use comments::CommentState;
use model::ParseMetadata;
pub use model::{
Comment, CommentKind, CompileDirective, FragmentParseResumeSettings, HotComment, Mode,
ParseError, ParseErrors, ParseMessage, ParseNodeResult, ParseOptions, ParseResult,
};
use state::{ContextState, CstState, DiagnosticState, LocalState, RecoveryState};
use temp_vec::{ScratchVec, TempVector};
type Result<T> = std::result::Result<T, ParseError>;
const BLOCK_FOLLOW: &[&str] = &["else", "elseif", "end", "until"];
pub fn parse<'ast, 'name>(
source: &str,
arena: &'ast AstArena,
names: &mut AstNameTable<'name>,
options: ParseOptions,
) -> std::result::Result<ParseResult<'ast>, ParseErrors>
where
'name: 'ast,
{
parse_bytes(source.as_bytes(), arena, names, options)
}
pub fn parse_bytes<'ast, 'name>(
source: &[u8],
arena: &'ast AstArena,
names: &mut AstNameTable<'name>,
options: ParseOptions,
) -> std::result::Result<ParseResult<'ast>, ParseErrors>
where
'name: 'ast,
{
Parser::new(source, arena, names, options, None).parse()
}
pub fn parse_fragment<'ast, 'name>(
source: &str,
arena: &'ast AstArena,
names: &mut AstNameTable<'name>,
options: ParseOptions,
resume: FragmentParseResumeSettings<'ast>,
) -> std::result::Result<ParseResult<'ast>, ParseErrors>
where
'name: 'ast,
{
parse_fragment_bytes(source.as_bytes(), arena, names, options, resume)
}
pub fn parse_fragment_bytes<'ast, 'name>(
source: &[u8],
arena: &'ast AstArena,
names: &mut AstNameTable<'name>,
options: ParseOptions,
resume: FragmentParseResumeSettings<'ast>,
) -> std::result::Result<ParseResult<'ast>, ParseErrors>
where
'name: 'ast,
{
Parser::new(source, arena, names, options, Some(&resume)).parse()
}
pub fn parse_expression<'ast, 'name>(
source: &[u8],
arena: &'ast AstArena,
names: &mut AstNameTable<'name>,
options: ParseOptions,
) -> std::result::Result<ParseNodeResult<'ast, Expression<'ast>>, ParseErrors>
where
'name: 'ast,
{
Parser::new(source, arena, names, options, None).parse_expression_node()
}
pub fn parse_type<'ast, 'name>(
source: &[u8],
arena: &'ast AstArena,
names: &mut AstNameTable<'name>,
options: ParseOptions,
) -> std::result::Result<ParseNodeResult<'ast, Type<'ast>>, ParseErrors>
where
'name: 'ast,
{
Parser::new(source, arena, names, options, None).parse_type_node()
}
struct Parser<'source, 'ast, 'name, 'names>
where
'name: 'ast,
{
options: ParseOptions,
lexer: Lexer<'source, 'ast, 'name, 'names>,
base_position: Position,
arena: &'ast AstArena,
current: Token<'source, 'ast>,
diagnostics: DiagnosticState,
comments: CommentState,
cst: CstState<'ast>,
contexts: ContextState,
locals: LocalState<'ast>,
recovery: RecoveryState,
name_self: AstName<'ast>,
name_number: AstName<'ast>,
name_error: AstName<'ast>,
name_nil: AstName<'ast>,
declared_export_bindings: DenseHashMap<AstName<'ast>, Location, AstNameDenseHasher>,
has_module_return: bool,
scratch_stat: ScratchVec<Statement<'ast>>,
scratch_expr: ScratchVec<Expression<'ast>>,
scratch_expr_aux: ScratchVec<Expression<'ast>>,
scratch_string: ScratchVec<AstString<'ast>>,
scratch_string2: ScratchVec<AstString<'ast>>,
scratch_attr: ScratchVec<&'ast Attribute<'ast>>,
scratch_binding: ScratchVec<Binding<'ast>>,
scratch_table_items: ScratchVec<TableItem<'ast>>,
scratch_cst_table_items: ScratchVec<CstExprTableItem>,
scratch_class_members: ScratchVec<ClassMember<'ast>>,
scratch_declared_extern_type_props: ScratchVec<DeclaredExternTypeProperty<'ast>>,
scratch_type: ScratchVec<Type<'ast>>,
scratch_type_or_pack: ScratchVec<TypeOrPack<'ast>>,
scratch_arg_name: ScratchVec<ArgumentName<'ast>>,
scratch_opt_arg_name: ScratchVec<Option<ArgumentName<'ast>>>,
scratch_generic_types: ScratchVec<&'ast GenericType<'ast>>,
scratch_generic_type_packs: ScratchVec<&'ast GenericTypePack<'ast>>,
scratch_local: ScratchVec<&'ast Local<'ast>>,
scratch_table_type_props: ScratchVec<TableTypeProp<'ast>>,
scratch_cst_table_type_items: ScratchVec<CstTypeTableItem<'ast>>,
scratch_position: ScratchVec<Position>,
scratch_position2: ScratchVec<Option<Position>>,
}
#[derive(Debug, Clone, Copy)]
struct BlockContext {
opener: &'static str,
line: usize,
column: usize,
}
#[derive(Debug, Clone, Copy, Default)]
struct FunctionContext {
loop_depth: usize,
vararg: bool,
}
struct ParsedCallArguments<'ast> {
arguments: &'ast [Expression<'ast>],
location: Location,
end: Position,
cst: Option<CstExprCall>,
}
struct ParsedCallList<'ast> {
arguments: &'ast [Expression<'ast>],
location: Location,
end: Position,
cst: CstExprCall,
}
struct ParsedTableFields<'ast> {
items: &'ast [TableItem<'ast>],
cst_items: Option<Vec<CstExprTableItem>>,
}
struct ParsedGenericParameters<'ast> {
types: Vec<&'ast GenericType<'ast>>,
type_packs: Vec<&'ast GenericTypePack<'ast>>,
open: Position,
commas: Vec<Position>,
close: Position,
}
struct ParsedTableAccess {
access: TableAccess,
location: Option<Location>,
}
struct ParsedStatement<'ast> {
statement: Statement<'ast>,
}
struct ParsedFunctionName<'ast> {
expression: Expression<'ast>,
has_self: bool,
debug_name: AstName<'ast>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum MatchRecoveryStop {
Equal,
RightParen,
ReservedEnd,
SkinnyArrow,
}
impl MatchRecoveryStop {
const COUNT: usize = 4;
const fn index(self) -> usize {
match self {
Self::Equal => 0,
Self::RightParen => 1,
Self::ReservedEnd => 2,
Self::SkinnyArrow => 3,
}
}
}
impl Default for ParsedGenericParameters<'_> {
fn default() -> Self {
Self {
types: Vec::new(),
type_packs: Vec::new(),
open: Position::missing(),
commas: Vec::new(),
close: Position::missing(),
}
}
}