finx 0.1.0

A fast, lightweight embeddable scripting language
Documentation
use logos::Logos;

#[derive(Default, Debug, PartialEq, Clone)]
pub enum LexingError {
    #[default]
    UnexpectedToken,
    InvalidInteger(String),
}

impl From<std::num::ParseIntError> for LexingError {
    fn from(err: std::num::ParseIntError) -> Self {
        use std::num::IntErrorKind::*;

        match err.kind() {
            PosOverflow | NegOverflow => {
                LexingError::InvalidInteger("Integer overflow".to_string())
            }
            _ => LexingError::InvalidInteger("Other error".to_string()),
        }
    }
}

#[derive(Logos, Debug, PartialEq, Clone)]
#[logos(error = LexingError)]
#[logos(skip r"[ \t\n\f\r]+")]
pub enum Token {
    // Comments
    #[regex("//[^\n]*|/\\*([^*]|\\*[^/])*\\*/", logos::skip)]
    Comment,

    #[token("/*", logos::skip)]
    MultiLineCommentStart,
    #[token("*/", logos::skip)]
    MultiLineCommentEnd,

    // Keywords
    #[token("let")]
    Let,
    #[token("fn")]
    Fn,
    #[token("if")]
    If,
    #[token("else")]
    Else,
    #[token("while")]
    While,
    #[token("for")]
    For,
    #[token("true")]
    True,
    #[token("false")]
    False,
    #[token("null")]
    Null,
    #[token("return")]
    Return,

    // Operators
    #[token("==")]
    EqEq,
    #[token("!=")]
    BangEq,
    #[token(">")]
    Gt,
    #[token("<")]
    Lt,
    #[token(">=")]
    GtEq,
    #[token("<=")]
    LtEq,
    #[token("=")]
    Assign,

    // Arithmetic operators
    #[token("+")]
    Plus,
    #[token("-")]
    Minus,
    #[token("*")]
    Star,
    #[token("/")]
    Slash,
    #[token("%")]
    Percent,
    #[token("..")]
    Range,

    // Delimiters
    #[token("(")]
    LParen,
    #[token(")")]
    RParen,
    #[token("{")]
    LBrace,
    #[token("}")]
    RBrace,
    #[token(",")]
    Comma,
    #[token(";")]
    Semicolon, // For statement termination

    // Literals
    #[regex("[a-zA-Z_][a-zA-Z0-9_]*", |lex| lex.slice().to_string())]
    Identifier(String),
    #[regex(r#""([^"\\]|\\.)*"|'([^'\\]|\\.)*'"#, |lex| {
        let s = lex.slice();
        s[1..s.len()-1].to_string()
    })]
    StringLiteral(String),
    #[regex(r"[0-9][0-9_]*(\.[0-9_]+)?", |lex| {
        let s = lex.slice().replace('_', "");
        s.parse::<f64>().unwrap()
    })]
    NumberLiteral(f64),

    // Special tokens
    #[allow(dead_code)]
    Error, // Represents a lexing error
}