rantlr-core 0.1.0

Rantlr core: .gr lexer, parser, linter, and in-process runtime
Documentation
use serde::Serialize;

use crate::span::Span;

/// Reserved words in the `.gr` surface language.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Keyword {
    Grammar,
    Rule,
    Token,
    Match,
    Repeat,
    Optional,
    Example,
    Input,
    Expect,
    Skip,
    Import,
    Fragment,
}

impl Keyword {
    pub fn as_str(self) -> &'static str {
        match self {
            Self::Grammar => "grammar",
            Self::Rule => "rule",
            Self::Token => "token",
            Self::Match => "match",
            Self::Repeat => "repeat",
            Self::Optional => "optional",
            Self::Example => "example",
            Self::Input => "input",
            Self::Expect => "expect",
            Self::Skip => "skip",
            Self::Import => "import",
            Self::Fragment => "fragment",
        }
    }

    pub fn from_ident(ident: &str) -> Option<Self> {
        Some(match ident {
            "grammar" => Self::Grammar,
            "rule" => Self::Rule,
            "token" => Self::Token,
            "match" => Self::Match,
            "repeat" => Self::Repeat,
            "optional" => Self::Optional,
            "example" => Self::Example,
            "input" => Self::Input,
            "expect" => Self::Expect,
            "skip" => Self::Skip,
            "import" => Self::Import,
            "fragment" => Self::Fragment,
            _ => return None,
        })
    }
}

/// Built-in lexical types available in `token Name = <Builtin>;`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
#[serde(rename_all = "PascalCase")]
pub enum BuiltinType {
    Email,
    Url,
    DateTime,
    QuotedString,
    Number,
}

impl BuiltinType {
    pub fn as_str(self) -> &'static str {
        match self {
            Self::Email => "Email",
            Self::Url => "Url",
            Self::DateTime => "DateTime",
            Self::QuotedString => "QuotedString",
            Self::Number => "Number",
        }
    }

    pub fn from_ident(ident: &str) -> Option<Self> {
        Some(match ident {
            "Email" => Self::Email,
            "Url" => Self::Url,
            "DateTime" => Self::DateTime,
            "QuotedString" => Self::QuotedString,
            "Number" => Self::Number,
            _ => return None,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TokenKind {
    /// End of input sentinel.
    Eof,

    Keyword(Keyword),
    Builtin(BuiltinType),

    /// Rule / token / grammar names (`expr`, `JsonMini`, …).
    Ident(String),

    /// Double-quoted string with escapes (`"import"`, `"{"`).
    String(String),
    /// Backtick raw string for example inputs (`` `{"a":1}` ``).
    RawString(String),

    /// Integer literal (e.g. range bounds in `repeat(0..)`).
    Integer(u64),

    // Punctuation / operators
    LBrace,   // {
    RBrace,   // }
    LParen,   // (
    RParen,   // )
    LBracket, // [
    RBracket, // ]
    Pipe,     // |
    Comma,    // ,
    Semi,     // ;
    Colon,    // :
    Eq,       // =
    DotDot,   // ..
    Arrow,    // ->
}

impl TokenKind {
    pub fn is_eof(&self) -> bool {
        matches!(self, Self::Eof)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Token {
    pub kind: TokenKind,
    pub span: Span,
}

impl Token {
    pub fn new(kind: TokenKind, span: Span) -> Self {
        Self { kind, span }
    }
}