use logos::Logos;
#[derive(Debug, PartialEq, PartialOrd, Logos, Clone)]
#[logos(error = LexingError)]
#[logos(skip r"[\t]+")]
pub enum PklToken<'a> {
#[token("_", priority = 3)]
BlankIdentifier,
#[token(" ")]
Space,
#[token("\n")]
NewLine,
#[token("=")]
EqualSign,
#[token("true", |_| true)]
#[token("false", |_| false)]
Bool(bool),
#[token("{")]
OpenBrace,
#[token("}")]
CloseBrace,
#[token("(")]
OpenParen,
#[token(")")]
CloseParen,
#[token(",")]
Comma,
#[token("new")]
New,
#[regex(r"-?\d+(?:_?\d)*", |lex| {
let raw = lex.slice();
// Remove underscores for parsing
let clean_raw: String = raw.chars().filter(|&c| c != '_').collect();
clean_raw.parse::<i64>()
}, priority = 3)]
Int(i64),
#[regex(r"-?0x[0-9a-fA-F]+(?:_?[0-9a-fA-F])*", |lex| {
let raw = lex.slice();
// Check for the optional minus sign
let (is_negative, hex_str) = if raw.starts_with('-') {
(true, &raw[3..]) } else {
(false, &raw[2..]) };
let clean_hex: String = hex_str.chars().filter(|&c| c != '_').collect();
let value = i64::from_str_radix(&clean_hex, 16);
if is_negative {
value.map(|v| -v)
} else {
value
}
})]
HexInt(i64),
#[regex(r"-?0b[01]+(?:_?[01])*", |lex| {
let raw = lex.slice();
// Check for the optional minus sign
let (is_negative, hex_str) = if raw.starts_with('-') {
(true, &raw[3..]) } else {
(false, &raw[2..]) };
let clean_hex: String = hex_str.chars().filter(|&c| c != '_').collect();
let value = i64::from_str_radix(&clean_hex, 2);
if is_negative {
value.map(|v| -v)
} else {
value
}
})]
BinaryInt(i64),
#[regex(r"-?0o[0-7]+(?:_?[0-7])*", |lex| {
let raw = lex.slice();
// Check for the optional minus sign
let (is_negative, hex_str) = if raw.starts_with('-') {
(true, &raw[3..]) } else {
(false, &raw[2..]) };
let clean_hex: String = hex_str.chars().filter(|&c| c != '_').collect();
let value = i64::from_str_radix(&clean_hex, 8);
if is_negative {
value.map(|v| -v)
} else {
value
}
})]
OctalInt(i64),
#[token("NaN", |_| std::f64::NAN)]
#[token("Infinity", |_| std::f64::INFINITY)]
#[token("-Infinity", |_| std::f64::NEG_INFINITY)]
#[regex(r"-?(?:0|[1-9]+(?:_?\d)*)?(?:\.\d+(?:_?\d)*)(?:[eE][+-]?\d+(?:_?\d)*)?", |lex| {
let raw = lex.slice();
let clean_raw: String = raw.chars().filter(|&c| c != '_').collect();
clean_raw.parse::<f64>()
}, priority = 2)]
Float(f64),
#[regex(r#"(_|\$)[a-zA-Z0-9_]+"#, |lex| lex.slice())]
#[regex(r#"[a-zA-Z][a-zA-Z0-9_]*"#, |lex| lex.slice())]
Identifier(&'a str),
#[regex(r#"`([^`\\]|\\[`\\bnfrt]|\\u\{[a-fA-F0-9]+})*`"#, |lex| {let raw=lex.slice();&raw[1..raw.len()-1]})]
IllegalIdentifier(&'a str),
#[regex(r#"//[^\n\\]*"#, |lex| let raw=lex.slice();&raw[2..raw.len()-1])]
LineComment(&'a str),
#[regex(r#"///[^\n\\]*"#, |lex| let raw=lex.slice();&raw[3..raw.len()-1])]
DocComment(&'a str),
#[regex(r#"/\*[^*]*\*+(?:[^/*][^*]*\*+)*/"#, |lex| let raw=lex.slice();&raw[2..raw.len()-2])]
MultilineComment(&'a str),
#[regex(r#""([^"\\]|\\["\\bnfrt]|\\u\{[a-fA-F0-9]+})*""#, |lex| let raw=lex.slice();&raw[1..raw.len()-1])]
String(&'a str),
#[regex(r#""""([^"\\]|\\["\\bnfrt]|u[a-fA-F0-9]{4})*""""#, |lex| {
let raw=lex.slice();
if raw[3..=3] != *"\n" {
return Err(LexingError::ExpectedNewLineAfterMultilineStringStart)
}
// return err if raw[raw.len()-4..=raw.len()-4] != "\n"
if raw[raw.len()-4..=raw.len()-4] != *"\n" {
return Err(LexingError::ExpectedNewLineBeforeMultilineStringEnd)
}
Ok(&raw[4..raw.len()-4])
})]
MultiLineString(&'a str),
}
#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LexingError {
InvalidInteger(String),
InvalidFloat(String),
ExpectedNewLineBeforeMultilineStringEnd,
ExpectedNewLineAfterMultilineStringStart,
#[default]
DefaultLexingError,
}
use std::{
fmt,
num::{ParseFloatError, ParseIntError},
};
impl From<ParseIntError> for LexingError {
fn from(err: ParseIntError) -> Self {
LexingError::InvalidInteger(err.to_string())
}
}
impl From<ParseFloatError> for LexingError {
fn from(err: ParseFloatError) -> Self {
LexingError::InvalidFloat(err.to_string())
}
}
impl fmt::Display for LexingError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LexingError::InvalidInteger(s) => write!(f, "Invalid integer: {}", s),
LexingError::InvalidFloat(s) => write!(f, "Invalid float: {}", s),
LexingError::ExpectedNewLineBeforeMultilineStringEnd => {
write!(
f,
"Expected a newline before the end of the multiline string"
)
}
LexingError::ExpectedNewLineAfterMultilineStringStart => write!(
f,
"Expected a newline after the start of the multiline string"
),
LexingError::DefaultLexingError => write!(f, "An unspecified lexing error occurred"),
}
}
}