luau-syntax 0.732.0

Luau lexer, parser, AST, CST, and source utilities
Documentation
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(),
        }
    }
}