use crate::lst_parser::syntax_kind::SyntaxKind::*;
use crate::SyntaxNode;
use rowan::Language;

// Heavily modified version of https://github.com/rust-analyzer/rowan/blob/e2d2e93e16c5104b136d0bc738a0d48346922200/examples/s_expressions.rs#L250-L266
macro_rules! ast_nodes {
    ($($ast:ident, $kind:ident);+) => {
        $(
            #[derive(Debug, Clone, PartialEq, Eq, Hash)]
            #[repr(transparent)]
            pub struct $ast(SyntaxNode);
            impl rowan::ast::AstNode for $ast {
                type Language = crate::Lang;

                fn can_cast(kind: <Self::Language as Language>::Kind) -> bool {
                    kind == $kind
                }

                fn cast(node: SyntaxNode) -> Option<Self> {
                    if node.kind() == $kind {
                        Some(Self(node))
                    } else {
                        None
                    }
                }

                fn syntax(&self) -> &SyntaxNode {
                    &self.0
                }
            }
        )+
    };
}

ast_nodes!(
    Def, DEF;
    DefName, DEF_NAME;
    DefBody, DEF_BODY;

    Mod, MODULE;
    ModName, MODULE_NAME;
    ModBody, MODULE_BODY;

    Use, USE;
    UsePat, USE_PAT;
    PatItem, PAT_ITEM;
    PatGlob, PAT_GLOB;
    PatGroup, PAT_GROUP;

    Literal, LITERAL;
    IntLit, INT_NUM;
    FloatLit, FLOAT_NUM;
    StringLit, STRING;

    Matrix, MATRIX;
    MatrixRow, MAT_ROW;
    Vector, VEC;
    List, LIST;
    CollectionItem, COLLECTION_ITEM;

    ParenthesizedExpr, PARENTHESIZED_EXPR;
    Expression, EXPR;

    Pipeline, PIPELINE;

    Instruction, INSTR;
    InstructionName, INSTR_NAME;
    InstructionParams, INSTR_PARAMS;

    AttributeSet, ATTR_SET;
    Attribute, ATTR;
    AttributeName, ATTR_NAME;
    AttributeValue, ATTR_VALUE;

    ParseError, PARSE_ERR;
    LexError, LEX_ERR;

    Root, ROOT;
    Eof, EOF
);
