charon_core 0.6.2

A simple concatenative programming language
Documentation
use crate::Token;
use itertools::Itertools;
use lazy_static::lazy_static;
use logos::{Lexer, Logos};
use phf::phf_map;
use regex::{Captures, Regex};

static MACROS: phf::Map<&'static str, &'static str> = phf_map! {
    "TRUE" => "1",
    "FALSE" => "0"
};

pub fn macros(text: String) -> String {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"(\S*)").unwrap();
    }

    RE.replace_all(&text, |caps: &Captures| match MACROS.get(&caps[0]) {
        Some(value) => value.to_string(),
        _ => caps[0].to_string(),
    })
    .to_string()
}

fn string(lex: &mut Lexer<LexerToken>) -> Token {
    let slice = lex.slice();

    Token::Group(
        slice[1..slice.len() - 1]
            .chars()
            .map(Token::Char)
            .collect::<Vec<_>>(),
    )
}

fn container_literal(lex: &mut Lexer<LexerToken>) -> String {
    let mut slice = lex.slice().to_string();
    slice.retain(|c| c != '`');

    slice
}

fn boolean_guard(lex: &mut Lexer<LexerToken>) -> String {
    let slice = lex.slice().trim();

    slice[..slice.len() - 4].to_string()
}

fn guard_option(lex: &mut Lexer<LexerToken>) -> (String, String) {
    let slice = lex.slice().split(" -> ").collect::<Vec<_>>();

    (slice[0][1..].trim().to_string(), slice[1].to_string())
}

fn assignment(lex: &mut Lexer<LexerToken>) -> String {
    let slice = lex.slice().trim();

    slice[..slice.len() - 3].to_string()
}

fn parameter(lex: &mut Lexer<LexerToken>) -> Token {
    let slice = lex.slice()[1..].parse::<usize>().unwrap();
    Token::Parameter(slice)
}

fn range(lex: &mut Lexer<LexerToken>) -> Token {
    let slice = &lex.slice()[1..];

    if let Some((start, end)) = slice
        .split("..")
        .map(|x| x.parse::<usize>().unwrap())
        .collect_tuple()
    {
        Token::Iterator((start..=end).map(|x| Token::Value(x as f64)).collect())
    } else {
        panic!("Invalid tuple found.")
    }
}

#[derive(Logos, Debug, Clone, PartialEq)]
pub enum LexerToken {
    #[regex(r"[a-zA-Z_] <-\|", boolean_guard)]
    BooleanGuard(String),

    #[regex(r"\n  [^\n]*", |default| default.slice()[1..].trim().to_string())]
    GuardDefault(String),

    #[regex(r"\n  [^\n]+ -> [^\n]*", guard_option)]
    GuardOption((String, String)),

    #[regex(r"[a-zA-Z_]+ <- *", assignment)]
    Assignment(String),

    #[regex("\"[^\"]*\"", string)]
    #[regex(r"-?\d+(\.\d+)?", |number| Token::Value(number.slice().parse().unwrap()))]
    #[regex("'.'", |character| Token::Char(character.slice().chars().nth(1).unwrap()))]
    #[regex(r"\$\d+", parameter)]
    #[regex(r"@\d+\.\.\d+", range)]
    #[regex(r":[a-zA-Z\+\-\*/%><\|&_]+", |atom| Token::Atom(atom.slice()[1..].to_string()))]
    #[regex(r"\{|\}|\[|\]", |s| Token::Special(s.slice().to_string()))]
    Token(Token),

    #[regex(r"[a-zA-Z\+\-\*/%><\|&_]+", |func| func.slice().to_string())]
    Function(String),

    #[regex(r"`[a-zA-Z\+\-\*/%><\|&_]+`", container_literal)]
    FunctionLiteral(String),

    #[token(" ")]
    Seperator,

    #[token("\n")]
    Newline,

    #[error]
    Error,
}