luaparse 0.2.0

A Lua 5.3 parser
Documentation
//! Tokens.

use std::borrow::Cow;
use std::fmt::{self, Display};

use crate::span::{HasSpan, Span};

pub use crate::symbol::{Symbol, SymbolGroup};

/// A token.
#[derive(Clone, Debug, PartialEq)]
pub struct Token<'a> {
    pub span: Span,
    pub value: TokenValue<'a>,
}

impl HasSpan for Token<'_> {
    fn span(&self) -> Span {
        self.span
    }
}

/// The value of the token.
#[derive(Clone, Debug, PartialEq)]
pub enum TokenValue<'a> {
    /// A symbol token.
    Symbol(Symbol),
    /// A number literal.
    Number(NumberLiteral),
    /// A string literal.
    String {
        /// The string value. All escapes are decoded by the lexer.
        value: Cow<'a, [u8]>,
        /// The literal type.
        kind: StringLiteralKind,
    },
    /// A comment.
    Comment {
        /// The comment body.
        value: &'a str,
        /// The comment type.
        kind: CommentKind,
    },
    /// A whitespace sequence (spaces and newlines).
    Whitespace(&'a str),
    /// An identifier or a keyword.
    Ident(&'a str),
    /// The end of the file.
    Eof,
}

/// A number literal.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum NumberLiteral {
    Float(f64),
    Integer(i64),
}

/// The type of an string literal.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum StringLiteralKind {
    /// A long string, enclosed in long brackets (`[==[ ... ]==]`).
    Bracketed { level: usize },
    /// A short string (`'...'`).
    SingleQuoted,
    /// A short stirng (`"..."`).
    DoubleQuoted,
}

/// The type of a comment.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum CommentKind {
    /// A long comment, enclosed in long brackets (`--[==[...]==]`).
    Bracketed { level: usize },
    /// A short comment that stretches to the end of line (`-- ...`).
    Unbracketed,
}

/// A token kind.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum TokenKind {
    /// A symbol.
    Symbol(Symbol),
    /// A number literal.
    Number,
    /// A string literal.
    String,
    /// A comment.
    Comment,
    /// A whitespace sequence.
    Whitespace,
    /// An identifier.
    Ident,
    /// The end of the file.
    Eof,
}

impl Token<'_> {
    /// Returns the token kind.
    pub fn kind(&self) -> TokenKind {
        self.value.kind()
    }
}

impl TokenValue<'_> {
    /// Returns the token kind.
    pub fn kind(&self) -> TokenKind {
        match self {
            TokenValue::Symbol(s) => TokenKind::Symbol(*s),
            TokenValue::Number(_) => TokenKind::Number,
            TokenValue::String { .. } => TokenKind::String,
            TokenValue::Comment { .. } => TokenKind::Comment,
            TokenValue::Whitespace(_) => TokenKind::Whitespace,
            TokenValue::Ident(_) => TokenKind::Ident,
            TokenValue::Eof => TokenKind::Eof,
        }
    }
}

impl TokenKind {
    /// Returns `true` for insignificant tokens: whitespace and comments.
    pub fn is_trivia(self) -> bool {
        matches!(self, TokenKind::Whitespace | TokenKind::Comment)
    }
}

impl From<Symbol> for TokenKind {
    fn from(s: Symbol) -> TokenKind {
        TokenKind::Symbol(s)
    }
}

impl Display for TokenKind {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Symbol(s) => write!(formatter, "{}", s),
            Self::Number => write!(formatter, "a number"),
            Self::String => write!(formatter, "a string"),
            Self::Comment => write!(formatter, "a comment"),
            Self::Whitespace => write!(formatter, "whitespace"),
            Self::Ident => write!(formatter, "an identifier"),
            Self::Eof => write!(formatter, "end of file"),
        }
    }
}