use std::borrow::Cow;
use smartstring::alias::CompactString;
#[derive(Clone, PartialEq)]
#[repr(u8)]
pub enum Literal {
Nil,
Bool(bool),
Int(i64),
Dec(f64),
Uid(uuid::Uuid),
Str(CompactString),
Byt(Box<Byt>),
RefRes,
RefCtx,
RefVar(CompactString),
ObjIdx(usize),
ObjUid(uuid::Uuid),
ObjKey(CompactString)
}
#[derive(Clone, PartialEq)]
pub struct Byt {
pub kind: CompactString,
pub data: Vec<u8>
}
impl Literal {
pub const fn get_type_str(&self) -> &str {
match self {
Literal::Nil => "nil",
Literal::Bool(_) => "boolean",
Literal::Int(_) => "integer-number",
Literal::Dec(_) => "decimal-number",
Literal::Uid(_) => "unique-identifier",
Literal::Str(_) => "char-string",
Literal::Byt(_) => "byte-string",
Literal::RefRes => "ref-res",
Literal::RefCtx => "ref-ctx",
Literal::RefVar(_) => "ref-var",
Literal::ObjIdx(_) => "obj-idx",
Literal::ObjUid(_) => "obj-uid",
Literal::ObjKey(_) => "obj-key",
}
}
}
impl std::fmt::Debug for Literal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Literal::Nil => write!(f, "null"),
Literal::Bool(true) => write!(f, "true"),
Literal::Bool(false) => write!(f, "false"),
Literal::Int(v) => write!(f, "{v}i"),
Literal::Dec(v) => write!(f, "{v}f"),
Literal::Uid(v) => write!(f, "U{v}"),
Literal::Str(v) => write!(f, "{}", bareword_format(v)),
Literal::Byt(v) => {
write!(f, "0x[")?;
let mut tail = false;
for byte in &v.data {
if tail {
write!(f, " ")?;
}
write!(f, "{byte:02X}")?;
tail = true;
}
write!(f, "]")
},
Literal::RefRes => write!(f, "$"),
Literal::RefCtx => write!(f, "$$"),
Literal::RefVar(v) => write!(f, "${v}"),
Literal::ObjIdx(v) => write!(f, "@{v}"),
Literal::ObjUid(v) => write!(f, "@{v}"),
Literal::ObjKey(v) => write!(f, "@{}", bareword_format(v)),
}
}
}
pub fn bareword_format(input: &str) -> Cow<str> {
for (i, ch) in input.char_indices() {
if i == 0 {
if is_bareword_start(ch) {
continue;
}
} else if is_bareword_part(ch) {
continue;
}
let mut escaped = String::with_capacity(input.len()+3);
escaped.push('"');
escaped.push_str(&input[..i]);
for ch in input[i..].chars() {
if ch == '"' {
escaped.push_str("\\\"");
} else {
escaped.push(ch);
}
}
escaped.push('"');
return Cow::Owned(escaped);
};
Cow::Borrowed(input)
}
pub fn is_bareword(input: &str) -> bool {
for (i, ch) in input.char_indices() {
if i == 0 {
if is_bareword_start(ch) {
continue;
}
} else if is_bareword_part(ch) {
continue;
}
return false
}
true
}
pub fn is_bareword_start(ch: char) -> bool {
ch.is_alphabetic() || ch == '_'
}
pub fn is_bareword_part(ch: char) -> bool {
ch.is_alphanumeric() || ch == '_' || ch == '-'
}