use crate::ast::{
AstString, Attribute, Block, Expression, Function, GenericType, GenericTypePack, Statement,
Type, TypePack,
};
use crate::lexer::QuoteStyle as LexerQuoteStyle;
use crate::location::Position;
use luau_common::{DenseHashHasher, DenseHashMap};
#[derive(Debug, Clone)]
pub struct CstNodeMap<'ast> {
nodes: DenseHashMap<AstNodeKey, Option<CstNode<'ast>>, AstNodeKeyHasher>,
}
impl Default for CstNodeMap<'_> {
fn default() -> Self {
Self {
nodes: DenseHashMap::new(AstNodeKey::empty()),
}
}
}
impl PartialEq for CstNodeMap<'_> {
fn eq(&self, other: &Self) -> bool {
self.nodes.len() == other.nodes.len()
&& self
.nodes
.iter()
.all(|(key, value)| other.nodes.get(key) == Some(value))
}
}
impl<'ast> CstNodeMap<'ast> {
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub(crate) fn insert(&mut self, node: impl AstNodeKeySource, cst: CstNode<'ast>) {
self.nodes.insert(node.key(), Some(cst));
}
pub(crate) fn get(&self, node: impl AstNodeKeySource) -> Option<&CstNode<'ast>> {
self.nodes.get(&node.key()).and_then(Option::as_ref)
}
pub fn get_block(&self, block: Block) -> Option<&CstNode<'ast>> {
self.get(block.as_statement())
}
pub fn get_statement(&self, statement: Statement) -> Option<&CstNode<'ast>> {
self.get(statement)
}
pub fn get_expression(&self, expression: Expression) -> Option<&CstNode<'ast>> {
self.get(expression)
}
pub fn get_function(&self, function: &Function) -> Option<&CstNode<'ast>> {
self.get(function)
}
pub fn get_attribute(&self, attribute: &Attribute) -> Option<&CstNode<'ast>> {
self.get(attribute)
}
pub fn get_type(&self, annotation: Type) -> Option<&CstNode<'ast>> {
self.get(annotation)
}
pub fn get_type_pack(&self, annotation: TypePack) -> Option<&CstNode<'ast>> {
self.get(annotation)
}
pub fn get_generic_type(&self, generic: &GenericType) -> Option<&CstNode<'ast>> {
self.get(generic)
}
pub fn get_generic_type_pack(&self, generic: &GenericTypePack) -> Option<&CstNode<'ast>> {
self.get(generic)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct AstNodeKey(usize);
impl AstNodeKey {
fn empty() -> Self {
Self(0)
}
fn from_ref<T>(node: &T) -> Self {
Self((node as *const T).cast::<()>() as usize)
}
fn from_ptr(ptr: *const ()) -> Self {
Self(ptr as usize)
}
}
pub(crate) trait AstNodeKeySource {
fn key(self) -> AstNodeKey;
}
impl AstNodeKeySource for Expression<'_> {
fn key(self) -> AstNodeKey {
AstNodeKey::from_ptr(self.as_ptr())
}
}
impl AstNodeKeySource for Statement<'_> {
fn key(self) -> AstNodeKey {
AstNodeKey::from_ptr(self.as_ptr())
}
}
impl AstNodeKeySource for Block<'_> {
fn key(self) -> AstNodeKey {
self.as_statement().key()
}
}
impl AstNodeKeySource for Type<'_> {
fn key(self) -> AstNodeKey {
AstNodeKey::from_ptr(self.as_ptr())
}
}
impl AstNodeKeySource for TypePack<'_> {
fn key(self) -> AstNodeKey {
AstNodeKey::from_ptr(self.as_ptr())
}
}
impl<T> AstNodeKeySource for &T {
fn key(self) -> AstNodeKey {
AstNodeKey::from_ref(self)
}
}
#[derive(Debug, Clone, Copy)]
struct AstNodeKeyHasher;
impl DenseHashHasher<AstNodeKey> for AstNodeKeyHasher {
fn hash(key: &AstNodeKey) -> u64 {
let key = key.0;
((key >> 4) ^ (key >> 9)) as u64
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum CstNode<'ast> {
ExprConstantNumber(CstExprConstantNumber<'ast>),
ExprConstantInteger(CstExprConstantInteger<'ast>),
ExprConstantString(CstExprConstantString<'ast>),
ExprCall(CstExprCall),
ExprGroup(CstExprGroup),
ExprIndexExpr(CstExprIndexExpr),
ExprFunction(CstExprFunction<'ast>),
Attribute(CstAttribute),
ExprTable(CstExprTable),
ExprOp(CstExprOp),
ExprTypeAssertion(CstExprTypeAssertion),
ExprIfElse(CstExprIfElse),
ExprInterpString(CstExprInterpString<'ast>),
ExprExplicitTypeInstantiation(CstExprExplicitTypeInstantiation),
StatDo(CstStatDo),
StatRepeat(CstStatRepeat),
StatReturn(CstStatReturn),
StatLocal(CstStatLocal<'ast>),
StatFor(CstStatFor),
StatForIn(CstStatForIn<'ast>),
StatAssign(CstStatAssign<'ast>),
StatCompoundAssign(CstStatCompoundAssign),
StatFunction(CstStatFunction),
StatLocalFunction(CstStatLocalFunction),
GenericType(CstGenericType),
GenericTypePack(CstGenericTypePack),
StatTypeAlias(CstStatTypeAlias),
StatTypeFunction(CstStatTypeFunction),
TypeReference(CstTypeReference),
TypeGroup(CstTypeGroup),
TypeTable(CstTypeTable<'ast>),
TypeFunction(CstTypeFunction),
TypeTypeof(CstTypeTypeof),
TypeUnion(CstTypeUnion),
TypeIntersection(CstTypeIntersection),
TypeSingletonString(CstTypeSingletonString<'ast>),
TypePackExplicit(CstTypePackExplicit),
TypePackGeneric(CstTypePackGeneric),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CstExprConstantNumber<'ast> {
pub value: AstString<'ast>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CstExprConstantInteger<'ast> {
pub value: AstString<'ast>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CstExprConstantString<'ast> {
pub source_string: AstString<'ast>,
pub quote_style: CstStringQuoteStyle,
pub block_depth: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CstStringQuoteStyle {
QuotedSingle,
QuotedDouble,
QuotedRaw,
QuotedInterp,
}
impl From<LexerQuoteStyle> for CstStringQuoteStyle {
fn from(quote_style: LexerQuoteStyle) -> Self {
match quote_style {
LexerQuoteStyle::Single => Self::QuotedSingle,
LexerQuoteStyle::Double => Self::QuotedDouble,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstTypeInstantiation {
pub left_arrow_1: Position,
pub left_arrow_2: Position,
pub comma_positions: Vec<Position>,
pub right_arrow_1: Position,
pub right_arrow_2: Position,
}
impl Default for CstTypeInstantiation {
fn default() -> Self {
Self {
left_arrow_1: Position::missing(),
left_arrow_2: Position::missing(),
comma_positions: Vec::new(),
right_arrow_1: Position::missing(),
right_arrow_2: Position::missing(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstExprCall {
pub open_parens: Option<Position>,
pub close_parens: Option<Position>,
pub comma_positions: Vec<Position>,
pub explicit_types: Option<CstTypeInstantiation>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstExprGroup {
pub close_position: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstExprIndexExpr {
pub open_bracket: Position,
pub close_bracket: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstExprFunction<'ast> {
pub attr_lists: Vec<CstAttrList>,
pub function_keyword: Position,
pub open_generics: Position,
pub generics_commas: &'ast [Position],
pub close_generics: Position,
pub argument_annotation_colons: &'ast [Position],
pub argument_commas: &'ast [Position],
pub vararg_annotation_colon: Position,
pub return_specifier: Position,
}
impl Default for CstExprFunction<'_> {
fn default() -> Self {
Self {
attr_lists: Vec::new(),
function_keyword: Position::missing(),
open_generics: Position::missing(),
generics_commas: &[],
close_generics: Position::missing(),
argument_annotation_colons: &[],
argument_commas: &[],
vararg_annotation_colon: Position::missing(),
return_specifier: Position::missing(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CstAttrList {
pub at_bracket_position: Position,
pub close_bracket_position: Position,
pub comma_positions: Vec<Position>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CstAttribute {
Simple {
has_at: bool,
},
Parametrized {
open_paren_position: Option<Position>,
close_paren_position: Option<Position>,
argument_commas: Vec<Position>,
},
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstExprTable {
pub items: Vec<CstExprTableItem>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstExprTableItem {
pub indexer_open: Option<Position>,
pub indexer_close: Option<Position>,
pub equals: Option<Position>,
pub separator: Option<TableSeparator>,
pub separator_position: Option<Position>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TableSeparator {
Comma,
Semicolon,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstExprOp {
pub op: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstExprTypeAssertion {
pub op: Position,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CstExprIfElse {
pub then_position: Position,
pub else_position: Position,
pub is_else_if: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstExprInterpString<'ast> {
pub source_strings: Vec<AstString<'ast>>,
pub string_positions: Vec<Position>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstExprExplicitTypeInstantiation {
pub instantiation: CstTypeInstantiation,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatDo {
pub stats_start: Position,
pub end: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatRepeat {
pub until: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatReturn {
pub comma_positions: Vec<Position>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatLocal<'ast> {
pub declaration_keyword_position: Position,
pub variable_annotation_colons: &'ast [Position],
pub variable_commas: &'ast [Position],
pub value_commas: &'ast [Position],
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatFor {
pub annotation_colon: Position,
pub equals: Position,
pub end_comma: Position,
pub step_comma: Option<Position>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatForIn<'ast> {
pub variable_annotation_colons: &'ast [Position],
pub variable_commas: &'ast [Position],
pub value_commas: &'ast [Position],
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatAssign<'ast> {
pub variable_commas: &'ast [Position],
pub equals: Position,
pub value_commas: &'ast [Position],
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatCompoundAssign {
pub op: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatFunction {
pub attr_lists: Vec<CstAttrList>,
pub function_keyword: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatLocalFunction {
pub attr_lists: Vec<CstAttrList>,
pub local_keyword: Position,
pub function_keyword: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstGenericType {
pub default_equals: Option<Position>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstGenericTypePack {
pub ellipsis: Position,
pub default_equals: Option<Position>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatTypeAlias {
pub type_keyword: Position,
pub generics_open: Position,
pub generics_commas: Vec<Position>,
pub generics_close: Position,
pub equals: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstStatTypeFunction {
pub type_keyword: Position,
pub function_keyword: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstTypeReference {
pub prefix_dot: Option<Position>,
pub open_parameters: Position,
pub parameter_commas: Vec<Position>,
pub close_parameters: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstTypeGroup {
pub close_position: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstTypeTable<'ast> {
pub items: Vec<CstTypeTableItem<'ast>>,
pub is_array: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstTypeTableItem<'ast> {
pub kind: CstTypeTableItemKind,
pub indexer_open: Position,
pub indexer_close: Position,
pub colon: Position,
pub separator: Option<TableSeparator>,
pub separator_position: Option<Position>,
pub string_info: Option<CstExprConstantString<'ast>>,
pub string_position: Position,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CstTypeTableItemKind {
Indexer,
Property,
StringProperty,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstTypeFunction {
pub open_generics: Position,
pub generics_commas: Vec<Position>,
pub close_generics: Position,
pub open_arguments: Position,
pub argument_name_colons: Vec<Option<Position>>,
pub argument_commas: Vec<Position>,
pub close_arguments: Position,
pub return_arrow: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstTypeTypeof {
pub open: Position,
pub close: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstTypeUnion {
pub leading: Option<Position>,
pub separators: Vec<Position>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstTypeIntersection {
pub leading: Option<Position>,
pub separators: Vec<Position>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CstTypeSingletonString<'ast> {
pub source_string: AstString<'ast>,
pub quote_style: CstStringQuoteStyle,
pub block_depth: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstTypePackExplicit {
pub parentheses: Option<CstTypePackParentheses>,
pub comma_positions: Vec<Position>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CstTypePackParentheses {
pub open: Position,
pub close: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CstTypePackGeneric {
pub ellipsis: Position,
}