skullbrain-lexer 0.1.0

Lexer for the skullbrain programming language, responsible for tokenizing source code.
Documentation
#![allow(missing_docs)]

/// A single token in the stream, consisting of its kind and span.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct Token {
    kind: TokenKind,
    len: u16,
}

/// Different types of tokens in the language.
#[derive(Debug, Clone, PartialEq, Eq, Hash, variantly::Variantly)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum TokenKind {
    /// Represents whitespace characters in `SkullScript`.
    /// - Any space, tab, or newline.
    Whitespace,

    /// `yo fam`
    SingleLineComment,

    /// `chat ... thats real`
    MultiLineComment {
        /// Do i need to explain this?
        is_terminated: bool,
    },

    /// Characters that do not fit any other cateor
    Unknown,

    /*/// Represents type keywords in `SkullScript`.
    /// - `aura` for signed integers.
    /// - `cringe` for unsigned integers.
    /// - `gigachad` for strings.
    /// - `chad` for characters.
    /// - `clutch` for booleans.
    /// - `vibing` for floating-point numbers.
    Type,*/
    /// Represents an identifier in `SkullScript`.
    /// - Any valid identifier, including emojis.
    Ident,

    /// Represents literals such as numbers, strings, and booleans in `SkullScript`.
    /// - Numeric literals: `42`, `3.14`.
    /// - Boolean literals: `W` (true), `L` (false).
    /// - String literals: `"..."`.
    Literial(LiteralKind),

    /// Represents control flow constructs in `SkullScript`.
    ControlFlow(ControlFlowKind),

    Punctuation(PunctuationKind),

    /// Represents modifiers in `SkullScript`.
    Modifier(ModifierKind),

    Operator(OperatorKind),

    Declaration(DeclarationKind),
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, variantly::Variantly)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum ModifierKind {

    /// - `mew` for public visibility.
    VisibilityPublic,

    /// Represents that a function is non-static in an enum or class
    InstanceAccess,
}

// https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_lexer/lib.rs.html

/// Represents different types of literal values.
#[derive(Debug, Clone, PartialEq, Eq, Hash, variantly::Variantly)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum LiteralKind {
    /// Integer literals, such as `42`, `0b1010`, `0o755`, or `0x1F`
    Int {
        /// The base of the integer literal (binary, octal, decimal, or hexadecimal).
        base: Base,
        /// Whether the integer literal is empty (invalid or uninitialized).
        is_empty: bool,
    },
    /// Floating-point literals, such as `3.14` or `2e10`
    Double {
        /// The base of the floating-point literal.
        base: Base,
        /// Whether the exponent part of the floating-point literal is missing.
        empty_exponent: bool,
    },
    /// String literals, such as `"hello"`
    Str { is_terminated: bool },
    /// Boolean literals, such as `true` or `false`
    Boolean(bool),
}

// https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_lexer/lib.rs.html
/// Base of numeric literal encoding according to its prefix.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, variantly::Variantly)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum Base {
    /// Literal starts with "0b".
    Binary = 2,
    /// Literal starts with "0o".
    Octal = 8,
    /// Literal doesn't contain a prefix.
    Decimal = 10,
    /// Literal starts with "0x".
    Hexadecimal = 16,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, variantly::Variantly)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum PunctuationKind {
    /// `uwu`
    OpenParen,

    /// `owo`
    CloseParen,

    /// `bussin`
    OpenBrace,

    /// `no cap`
    CloseBrace,

    /// `.` (acts like a semicolon)
    Dot,

    /// `n`
    Comma,

    /// `is`
    Colon,

    /// bustin
    Arrow,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, variantly::Variantly)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum OperatorKind {
    /// `skibidi`
    Assignment,

    /// `valid`

    #[variantly(rename = "equal")]
    Eq,

    /// `cap`

    #[variantly(rename = "notequal")]
    NotEq,

    /// `lowkey`
    Lt,

    /// `flex`
    Gt,

    /// `lowkey valid`
    LtEq,

    /// `flex valid`
    GtEq,

    /// `cut`
    Minus,

    /// `frfr`
    And,

    /// `|`
    Or,

    /// `nah`
    Not,

    /// `boost`
    Plus,

    /// `drift`
    Mul,

    /// `dab`
    Divide,

    /// `skrrt`
    Mod,

    MethodChaining,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, variantly::Variantly)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum DeclarationKind {
    /// Represents a variable declaration in `SkullScript`.
    VariableDeclaration {
        /// - `gyatt` for mutable variables.
        /// - `facts` for immutable (constant) variables.
        is_mutable: bool,
    },

    /// Represents function declarations in `SkullScript`.
    /// - `bop` for defining a function.
    Function,

    /// Represents class (struct) declarations and related constructs in `SkullScript`.
    /// - `deadass` for defining a struct/class.
    Class,

    /// Represents trait declarations in `SkullScript`.
    /// - `vibe` for defining a trait.
    Trait,

    /// Represents trait implementations in `SkullScript`.
    /// - `trippin` for implementing a trait.
    TraitImpl,

    Enum,

    EnumVariant,

    /// Represents an alias declaration in `SkullScript`.
    /// - `like` for type aliasing.
    Alias,

    /// Represents an import statement in `SkullScript`.
    /// - `glizzy` for importing modules.
    Import,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum ControlFlowKind {
    /// Represents control flow constructs in `SkullScript`.
    /// - `edgin check` for `if` statements.
    If,

    /// Represents control flow constructs in `SkullScript`.
    /// - `only in ohio` for `else` statements.
    Else,

    /// Represents control flow constructs in `SkullScript`.
    /// - `goon` for `while` loops.
    While,

    ForLoopOpen,

    ForLoopClose,

    Match,
    MatchArmDefault,
    MatchArmCondition,

    /// `bruh` - Breaks out of the current loop
    Break,

    /// `grind` - Continues to the next iteration of the loop
    Continue,

    /// Your return keyword (not sure of the actual keyword from what you provided)
    Return,

    /// `yeet` - Throws an error
    Throw,

    /// chill check
    Try,

    /// that l
    Catch,
}

impl Token {
    /// Creates a new `Token`.
    pub const fn new(kind: TokenKind, len: u16) -> Self {
        Token { kind, len }
    }

    /// Returns the kind of the token.
    pub const fn kind(&self) -> &TokenKind {
        &self.kind
    }

    /// Returns the kind of the token.
    pub const fn into_kind(self) -> TokenKind {
        self.kind
    }

    /// Returns the byte length of the source code token represented by this variant.
    pub const fn len_repr(&self) -> u16 {
        self.len
    }
}

impl TokenKind {
    pub fn is(&self, other: &Self) -> bool {
        match (self, other) {
            (TokenKind::Literial(a), TokenKind::Literial(b)) => {
                std::mem::discriminant(a) == std::mem::discriminant(b)
            }
            (TokenKind::ControlFlow(a), TokenKind::ControlFlow(b)) => {
                std::mem::discriminant(a) == std::mem::discriminant(b)
            }
            (TokenKind::Punctuation(a), TokenKind::Punctuation(b)) => {
                std::mem::discriminant(a) == std::mem::discriminant(b)
            }
            (TokenKind::Modifier(a), TokenKind::Modifier(b)) => {
                std::mem::discriminant(a) == std::mem::discriminant(b)
            }
            (TokenKind::Operator(a), TokenKind::Operator(b)) => {
                std::mem::discriminant(a) == std::mem::discriminant(b)
            }
            (TokenKind::Declaration(a), TokenKind::Declaration(b)) => {
                std::mem::discriminant(a) == std::mem::discriminant(b)
            }
            _ => std::mem::discriminant(self) == std::mem::discriminant(other),
        }
    }
}