use crate::ast_names::AstName;
use crate::lexer::QuoteStyle as LexerQuoteStyle;
use crate::location::Location;
use luau_common::{BStr, ByteSlice};
use std::fmt;
pub struct Local<'ast> {
pub name: AstName<'ast>,
pub location: Location,
pub shadow: Option<&'ast Local<'ast>>,
pub function_depth: usize,
pub loop_depth: usize,
pub annotation: Option<Type<'ast>>,
pub is_const: bool,
pub is_exported: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct LocalInit<'ast> {
pub name: AstName<'ast>,
pub location: Location,
pub shadow: Option<&'ast Local<'ast>>,
pub function_depth: usize,
pub loop_depth: usize,
pub annotation: Option<Type<'ast>>,
pub is_const: bool,
pub is_exported: bool,
}
impl fmt::Debug for Local<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("Local")
.field("name", &self.name)
.field("location", &self.location)
.field("shadow", &self.shadow)
.field("function_depth", &self.function_depth)
.field("loop_depth", &self.loop_depth)
.field("annotation", &self.annotation)
.field("is_const", &self.is_const)
.field("is_exported", &self.is_exported)
.finish()
}
}
impl PartialEq for Local<'_> {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& self.location == other.location
&& self.shadow == other.shadow
&& self.function_depth == other.function_depth
&& self.loop_depth == other.loop_depth
&& self.annotation == other.annotation
&& self.is_const == other.is_const
&& self.is_exported == other.is_exported
}
}
#[derive(Debug, PartialEq)]
pub struct GenericType<'ast> {
pub location: Location,
pub name: AstName<'ast>,
pub default_value: Option<Type<'ast>>,
}
#[derive(Debug, PartialEq)]
pub struct GenericTypePack<'ast> {
pub location: Location,
pub name: AstName<'ast>,
pub default_value: Option<TypePack<'ast>>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ArgumentName<'ast> {
pub name: AstName<'ast>,
pub location: Location,
}
impl<'ast> Local<'ast> {
pub(crate) fn new(init: LocalInit<'ast>) -> Self {
Local {
name: init.name,
location: init.location,
shadow: init.shadow,
function_depth: init.function_depth,
loop_depth: init.loop_depth,
annotation: init.annotation,
is_const: init.is_const,
is_exported: init.is_exported,
}
}
pub fn visit<V: AstVisitor>(&self, visitor: &mut V) {
if let Some(annotation) = &self.annotation {
annotation.visit(visitor);
}
}
}
impl GenericType<'_> {
pub fn visit<V: AstVisitor>(&self, visitor: &mut V) {
if !visitor.visit_generic_type(self) {
return;
}
if let Some(default_value) = &self.default_value {
default_value.visit(visitor);
}
}
}
impl GenericTypePack<'_> {
pub fn visit<V: AstVisitor>(&self, visitor: &mut V) {
if !visitor.visit_generic_type_pack(self) {
return;
}
if let Some(default_value) = &self.default_value {
default_value.visit(visitor);
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AstString<'ast> {
bytes: &'ast BStr,
}
impl<'ast> AstString<'ast> {
pub(crate) fn from_arena_bytes(bytes: &'ast [u8]) -> Self {
Self {
bytes: BStr::new(bytes),
}
}
pub fn as_bytes(&self) -> &[u8] {
self.bytes.as_bytes()
}
pub fn as_bstr(self) -> &'ast BStr {
self.bytes
}
pub fn into_bytes(self) -> &'ast [u8] {
self.bytes.as_bytes()
}
}
impl PartialEq<str> for AstString<'_> {
fn eq(&self, other: &str) -> bool {
self.as_bytes() == other.as_bytes()
}
}
pub trait AstVisitor {
fn visit_node(&mut self, _node: AstNodeRef<'_, '_>) -> bool {
true
}
fn visit_attribute(&mut self, attribute: &Attribute<'_>) -> bool {
self.visit_node(AstNodeRef::Attribute(attribute))
}
fn visit_generic_type(&mut self, generic: &GenericType<'_>) -> bool {
self.visit_node(AstNodeRef::GenericType(generic))
}
fn visit_generic_type_pack(&mut self, generic: &GenericTypePack<'_>) -> bool {
self.visit_node(AstNodeRef::GenericTypePack(generic))
}
fn visit_block(&mut self, block: Block<'_>) -> bool {
self.visit_statement(block.as_statement())
}
fn visit_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_node(AstNodeRef::Statement(statement))
}
fn visit_assign_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_compound_assign_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_break_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_continue_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_class_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_expression_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_numeric_for_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_generic_for_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_function_declaration_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_if_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_local_function_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_local_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_type_alias_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_type_function_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_declare_global_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_declare_function_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_declare_extern_type_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_repeat_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_return_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_while_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_error_statement(&mut self, statement: Statement<'_>) -> bool {
self.visit_statement(statement)
}
fn visit_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_node(AstNodeRef::Expression(expression))
}
fn visit_boolean_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_call_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_function_literal_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_grouped_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_integer_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_nil_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_number_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_string_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_interp_string_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_table_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_if_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_varargs_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_index_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_index_name_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_type_assertion_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_instantiate_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_unary_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_local_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_global_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_binary_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_error_expression(&mut self, expression: Expression<'_>) -> bool {
self.visit_expression(expression)
}
fn visit_type(&mut self, _annotation: Type<'_>) -> bool {
false
}
fn visit_reference_type(&mut self, annotation: Type<'_>) -> bool {
self.visit_type(annotation)
}
fn visit_table_type(&mut self, annotation: Type<'_>) -> bool {
self.visit_type(annotation)
}
fn visit_function_type(&mut self, annotation: Type<'_>) -> bool {
self.visit_type(annotation)
}
fn visit_typeof_type(&mut self, annotation: Type<'_>) -> bool {
self.visit_type(annotation)
}
fn visit_singleton_bool_type(&mut self, annotation: Type<'_>) -> bool {
self.visit_type(annotation)
}
fn visit_singleton_string_type(&mut self, annotation: Type<'_>) -> bool {
self.visit_type(annotation)
}
fn visit_group_type(&mut self, annotation: Type<'_>) -> bool {
self.visit_type(annotation)
}
fn visit_optional_type(&mut self, annotation: Type<'_>) -> bool {
self.visit_type(annotation)
}
fn visit_union_type(&mut self, annotation: Type<'_>) -> bool {
self.visit_type(annotation)
}
fn visit_intersection_type(&mut self, annotation: Type<'_>) -> bool {
self.visit_type(annotation)
}
fn visit_error_type(&mut self, annotation: Type<'_>) -> bool {
self.visit_type(annotation)
}
fn visit_type_pack(&mut self, _annotation: TypePack<'_>) -> bool {
false
}
fn visit_explicit_type_pack(&mut self, annotation: TypePack<'_>) -> bool {
self.visit_type_pack(annotation)
}
fn visit_variadic_type_pack(&mut self, annotation: TypePack<'_>) -> bool {
self.visit_type_pack(annotation)
}
fn visit_generic_type_pack_type(&mut self, annotation: TypePack<'_>) -> bool {
self.visit_type_pack(annotation)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AstNodeRef<'a, 'ast> {
Attribute(&'a Attribute<'ast>),
GenericType(&'a GenericType<'ast>),
GenericTypePack(&'a GenericTypePack<'ast>),
Statement(Statement<'ast>),
Expression(Expression<'ast>),
Type(Type<'ast>),
TypePack(TypePack<'ast>),
}
mod expression;
mod statement;
mod types;
pub(crate) use self::statement::{BlockNode, StatementUnit};
pub use self::{
expression::{
BinaryOp, ConstantNumberParseResult, Expression, ExpressionInit, ExpressionKind, Function,
IndexNameOp, StringQuoteStyle, TableItem, UnaryOp,
},
statement::{
Block, ClassMember, Statement, StatementAssign, StatementClass, StatementCompoundAssign,
StatementDeclareExternType, StatementDeclareFunction, StatementDeclareGlobal,
StatementError, StatementExpression, StatementFunctionDeclaration, StatementGenericFor,
StatementIf, StatementLocal, StatementLocalFunction, StatementNumericFor, StatementRepeat,
StatementReturn, StatementTag, StatementTypeAlias, StatementTypeFunction, StatementWhile,
},
types::{
Attribute, AttributeKind, DeclaredExternTypeProperty, DeprecatedInfo, TableAccess,
TableTypeIndexer, TableTypeProp, Type, TypeKind, TypeList, TypeOrPack, TypePack,
TypePackKind,
},
};
pub(super) fn find_attribute<'ast>(
attributes: &[&'ast Attribute<'ast>],
kind: AttributeKind,
) -> Option<&'ast Attribute<'ast>> {
attributes
.iter()
.copied()
.find(|attribute| attribute.kind == kind)
}
pub(super) fn visit_statements<V: AstVisitor>(statements: &[Statement<'_>], visitor: &mut V) {
for &statement in statements {
statement.visit(visitor);
}
}
pub(super) fn visit_expressions<V: AstVisitor>(expressions: &[Expression<'_>], visitor: &mut V) {
for &expression in expressions {
expression.visit(visitor);
}
}