mod expr;
mod path_trait;
mod stat;
mod test;
use crate::{
LuaCommentOwner, LuaSyntaxNode,
kind::{LuaSyntaxKind, LuaTokenKind},
syntax::traits::{LuaAstChildren, LuaAstNode, LuaAstToken},
};
pub use expr::*;
pub use path_trait::*;
use rowan::TextRange;
pub use stat::*;
use super::{LuaLiteralToken, LuaNameToken, LuaNumberToken, LuaStringToken};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LuaChunk {
syntax: LuaSyntaxNode,
}
impl LuaAstNode for LuaChunk {
fn syntax(&self) -> &LuaSyntaxNode {
&self.syntax
}
fn can_cast(kind: LuaSyntaxKind) -> bool
where
Self: Sized,
{
kind == LuaSyntaxKind::Chunk
}
fn cast(syntax: LuaSyntaxNode) -> Option<Self>
where
Self: Sized,
{
if syntax.kind() == LuaSyntaxKind::Chunk.into() {
Some(Self { syntax })
} else {
None
}
}
}
impl LuaChunk {
pub fn get_block(&self) -> Option<LuaBlock> {
self.child()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LuaBlock {
syntax: LuaSyntaxNode,
}
impl LuaAstNode for LuaBlock {
fn syntax(&self) -> &LuaSyntaxNode {
&self.syntax
}
fn can_cast(kind: LuaSyntaxKind) -> bool
where
Self: Sized,
{
kind == LuaSyntaxKind::Block
}
fn cast(syntax: LuaSyntaxNode) -> Option<Self>
where
Self: Sized,
{
if syntax.kind() == LuaSyntaxKind::Block.into() {
Some(Self { syntax })
} else {
None
}
}
}
impl LuaBlock {
pub fn get_stats(&self) -> LuaAstChildren<LuaStat> {
self.children()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LuaLocalName {
syntax: LuaSyntaxNode,
}
impl LuaAstNode for LuaLocalName {
fn syntax(&self) -> &LuaSyntaxNode {
&self.syntax
}
fn can_cast(kind: LuaSyntaxKind) -> bool
where
Self: Sized,
{
kind == LuaSyntaxKind::LocalName
}
fn cast(syntax: LuaSyntaxNode) -> Option<Self>
where
Self: Sized,
{
if Self::can_cast(syntax.kind().into()) {
Some(Self { syntax })
} else {
None
}
}
}
impl LuaLocalName {
pub fn get_name_token(&self) -> Option<LuaNameToken> {
self.token()
}
pub fn get_attrib(&self) -> Option<LuaLocalAttribute> {
self.child()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LuaCallArgList {
syntax: LuaSyntaxNode,
}
impl LuaAstNode for LuaCallArgList {
fn syntax(&self) -> &LuaSyntaxNode {
&self.syntax
}
fn can_cast(kind: LuaSyntaxKind) -> bool
where
Self: Sized,
{
kind == LuaSyntaxKind::CallArgList
}
fn cast(syntax: LuaSyntaxNode) -> Option<Self>
where
Self: Sized,
{
if Self::can_cast(syntax.kind().into()) {
Some(Self { syntax })
} else {
None
}
}
}
impl LuaCallArgList {
pub fn is_single_arg_no_parens(&self) -> bool {
self.token_by_kind(LuaTokenKind::TkLeftParen).is_none()
}
pub fn get_args(&self) -> LuaAstChildren<LuaExpr> {
self.children()
}
pub fn get_single_arg_expr(&self) -> Option<LuaSingleArgExpr> {
self.child()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LuaLocalAttribute {
syntax: LuaSyntaxNode,
}
impl LuaAstNode for LuaLocalAttribute {
fn syntax(&self) -> &LuaSyntaxNode {
&self.syntax
}
fn can_cast(kind: LuaSyntaxKind) -> bool
where
Self: Sized,
{
kind == LuaSyntaxKind::Attribute
}
fn cast(syntax: LuaSyntaxNode) -> Option<Self>
where
Self: Sized,
{
if Self::can_cast(syntax.kind().into()) {
Some(Self { syntax })
} else {
None
}
}
}
impl LuaLocalAttribute {
pub fn get_name_token(&self) -> Option<LuaNameToken> {
self.token()
}
pub fn is_close(&self) -> bool {
match self.get_name_token() {
None => false,
Some(name_token) => name_token.get_name_text() == "close",
}
}
pub fn is_const(&self) -> bool {
match self.get_name_token() {
None => false,
Some(name_token) => name_token.get_name_text() == "const",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LuaTableField {
syntax: LuaSyntaxNode,
}
impl LuaAstNode for LuaTableField {
fn syntax(&self) -> &LuaSyntaxNode {
&self.syntax
}
fn can_cast(kind: LuaSyntaxKind) -> bool
where
Self: Sized,
{
kind == LuaSyntaxKind::TableFieldAssign || kind == LuaSyntaxKind::TableFieldValue
}
fn cast(syntax: LuaSyntaxNode) -> Option<Self>
where
Self: Sized,
{
if Self::can_cast(syntax.kind().into()) {
Some(Self { syntax })
} else {
None
}
}
}
impl LuaCommentOwner for LuaTableField {}
impl LuaTableField {
pub fn is_assign_field(&self) -> bool {
self.syntax().kind() == LuaSyntaxKind::TableFieldAssign.into()
}
pub fn is_value_field(&self) -> bool {
self.syntax().kind() == LuaSyntaxKind::TableFieldValue.into()
}
pub fn get_field_key(&self) -> Option<LuaIndexKey> {
if !self.is_assign_field() {
let parent_table = self.get_parent::<LuaTableExpr>()?;
let fields = parent_table.get_fields();
let mut idx = 1;
for field in fields {
if field.is_value_field() {
if field.syntax() == self.syntax() {
return Some(LuaIndexKey::Idx(idx));
}
idx += 1;
}
}
return None;
}
let mut meet_left_bracket = false;
for child in self.syntax.children_with_tokens() {
if meet_left_bracket {
match child {
rowan::NodeOrToken::Node(node) => {
if LuaLiteralExpr::can_cast(node.kind().into()) {
let literal_expr = LuaLiteralExpr::cast(node.clone()).unwrap();
if let Some(literal_token) = literal_expr.get_literal() {
match literal_token {
LuaLiteralToken::String(token) => {
return Some(LuaIndexKey::String(token.clone()));
}
LuaLiteralToken::Number(token) => {
return Some(LuaIndexKey::Integer(token.clone()));
}
_ => {}
}
}
}
return Some(LuaIndexKey::Expr(LuaExpr::cast(node).unwrap()));
}
_ => return None,
}
} else if let Some(token) = child.as_token() {
if token.kind() == LuaTokenKind::TkLeftBracket.into() {
meet_left_bracket = true;
} else if token.kind() == LuaTokenKind::TkName.into() {
return Some(LuaIndexKey::Name(
LuaNameToken::cast(token.clone()).unwrap(),
));
}
}
}
None
}
pub fn get_value_expr(&self) -> Option<LuaExpr> {
if self.is_assign_field() {
self.children().last()
} else {
self.child()
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum LuaIndexKey {
Name(LuaNameToken),
String(LuaStringToken),
Integer(LuaNumberToken),
Expr(LuaExpr),
Idx(usize),
}
impl LuaIndexKey {
pub fn is_name(&self) -> bool {
matches!(self, LuaIndexKey::Name(_))
}
pub fn is_string(&self) -> bool {
matches!(self, LuaIndexKey::String(_))
}
pub fn is_integer(&self) -> bool {
matches!(self, LuaIndexKey::Integer(_))
}
pub fn is_expr(&self) -> bool {
matches!(self, LuaIndexKey::Expr(_))
}
pub fn get_name(&self) -> Option<&LuaNameToken> {
match self {
LuaIndexKey::Name(token) => Some(token),
_ => None,
}
}
pub fn get_string(&self) -> Option<&LuaStringToken> {
match self {
LuaIndexKey::String(token) => Some(token),
_ => None,
}
}
pub fn get_integer(&self) -> Option<&LuaNumberToken> {
match self {
LuaIndexKey::Integer(token) => Some(token),
_ => None,
}
}
pub fn get_expr(&self) -> Option<&LuaExpr> {
match self {
LuaIndexKey::Expr(expr) => Some(expr),
_ => None,
}
}
pub fn get_path_part(&self) -> String {
match self {
LuaIndexKey::String(s) => s.get_value(),
LuaIndexKey::Name(name) => name.get_name_text().to_string(),
LuaIndexKey::Integer(i) => {
format!("[{}]", i.get_number_value())
}
LuaIndexKey::Expr(expr) => {
format!("[{}]", expr.syntax().text())
}
LuaIndexKey::Idx(i) => {
format!("[{}]", i)
}
}
}
pub fn get_range(&self) -> Option<TextRange> {
match self {
LuaIndexKey::Name(token) => Some(token.get_range()),
LuaIndexKey::String(token) => Some(token.get_range()),
LuaIndexKey::Integer(token) => Some(token.get_range()),
LuaIndexKey::Expr(expr) => Some(expr.syntax().text_range()),
LuaIndexKey::Idx(_) => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LuaParamName {
syntax: LuaSyntaxNode,
}
impl LuaAstNode for LuaParamName {
fn syntax(&self) -> &LuaSyntaxNode {
&self.syntax
}
fn can_cast(kind: LuaSyntaxKind) -> bool
where
Self: Sized,
{
kind == LuaSyntaxKind::ParamName
}
fn cast(syntax: LuaSyntaxNode) -> Option<Self>
where
Self: Sized,
{
if Self::can_cast(syntax.kind().into()) {
Some(Self { syntax })
} else {
None
}
}
}
impl LuaParamName {
pub fn get_name_token(&self) -> Option<LuaNameToken> {
self.token()
}
pub fn is_dots(&self) -> bool {
self.token_by_kind(LuaTokenKind::TkDots).is_some()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LuaParamList {
syntax: LuaSyntaxNode,
}
impl LuaAstNode for LuaParamList {
fn syntax(&self) -> &LuaSyntaxNode {
&self.syntax
}
fn can_cast(kind: LuaSyntaxKind) -> bool
where
Self: Sized,
{
kind == LuaSyntaxKind::ParamList
}
fn cast(syntax: LuaSyntaxNode) -> Option<Self>
where
Self: Sized,
{
if Self::can_cast(syntax.kind().into()) {
Some(Self { syntax })
} else {
None
}
}
}
impl LuaParamList {
pub fn get_params(&self) -> LuaAstChildren<LuaParamName> {
self.children()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum LuaIndexMemberExpr {
IndexExpr(LuaIndexExpr),
TableField(LuaTableField),
}
impl LuaAstNode for LuaIndexMemberExpr {
fn syntax(&self) -> &LuaSyntaxNode {
match self {
LuaIndexMemberExpr::IndexExpr(expr) => expr.syntax(),
LuaIndexMemberExpr::TableField(field) => field.syntax(),
}
}
fn can_cast(kind: LuaSyntaxKind) -> bool
where
Self: Sized,
{
LuaIndexExpr::can_cast(kind) || LuaTableField::can_cast(kind)
}
fn cast(syntax: LuaSyntaxNode) -> Option<Self>
where
Self: Sized,
{
if LuaIndexExpr::can_cast(syntax.kind().into()) {
Some(Self::IndexExpr(LuaIndexExpr::cast(syntax).unwrap()))
} else if LuaTableField::can_cast(syntax.kind().into()) {
Some(Self::TableField(LuaTableField::cast(syntax).unwrap()))
} else {
None
}
}
}
impl LuaIndexMemberExpr {
pub fn get_index_expr(&self) -> Option<LuaIndexExpr> {
match self {
LuaIndexMemberExpr::IndexExpr(expr) => Some(expr.clone()),
_ => None,
}
}
pub fn get_table_field(&self) -> Option<LuaTableField> {
match self {
LuaIndexMemberExpr::TableField(field) => Some(field.clone()),
_ => None,
}
}
pub fn get_index_key(&self) -> Option<LuaIndexKey> {
match self {
LuaIndexMemberExpr::IndexExpr(expr) => expr.get_index_key(),
LuaIndexMemberExpr::TableField(field) => field.get_field_key(),
}
}
pub fn get_prefix_expr(&self) -> Option<LuaExpr> {
match self {
LuaIndexMemberExpr::IndexExpr(expr) => expr.get_prefix_expr(),
LuaIndexMemberExpr::TableField(field) => field.get_parent(),
}
}
}