use std::{borrow::Cow, str::FromStr};
use log::debug;
use num_bigint::BigInt;
use num_traits::Num;
use rue_ast::AstLiteralExpr;
use rue_hir::{Hir, Value};
use rue_lir::bigint_atom;
use rue_parser::{SyntaxKind, T};
use rue_types::{Atom, AtomRestriction, AtomSemantic, Type};
use crate::Compiler;
pub fn compile_literal_expr(ctx: &mut Compiler, expr: &AstLiteralExpr) -> Value {
let Some(value) = expr.value() else {
debug!("Unresolved literal expr");
return ctx.builtins().unresolved.clone();
};
match value.kind() {
SyntaxKind::String => {
let mut text = value.text();
if let Some(stripped) = text.strip_prefix('"') {
text = stripped;
}
if let Some(stripped) = text.strip_suffix('"') {
text = stripped;
}
let hir = ctx.alloc_hir(Hir::String(text.to_string()));
let ty = ctx.alloc_type(Type::Atom(Atom::new(
AtomSemantic::String,
Some(AtomRestriction::Value(Cow::Owned(text.as_bytes().to_vec()))),
)));
Value::new(hir, ty)
}
SyntaxKind::Hex => {
let mut text = value.text();
if let Some(stripped) = text.strip_prefix("0x") {
text = stripped;
}
let mut text = text.replace('_', "");
if text.len() % 2 == 1 {
text.insert(0, '0');
}
let bytes = hex::decode(text).unwrap();
let ty = ctx.alloc_type(Type::Atom(if bytes.is_empty() {
Atom::NIL
} else {
Atom::new(
if bytes.len() == 48 {
AtomSemantic::PublicKey
} else if bytes.len() == 96 {
AtomSemantic::Signature
} else {
AtomSemantic::Bytes
},
Some(AtomRestriction::Value(Cow::Owned(bytes.clone()))),
)
}));
Value::new(ctx.alloc_hir(Hir::Bytes(bytes)), ty)
}
SyntaxKind::Binary => {
let mut text = value.text();
if let Some(stripped) = text.strip_prefix("0b") {
text = stripped;
}
let text = text.replace('_', "");
let bigint = if text.is_empty() {
BigInt::ZERO
} else {
BigInt::from_str_radix(&text, 2).expect("invalid binary literal")
};
let ty = ctx.alloc_type(Type::Atom(Atom::new(
AtomSemantic::Int,
Some(AtomRestriction::Value(Cow::Owned(bigint_atom(
bigint.clone(),
)))),
)));
Value::new(ctx.alloc_hir(Hir::Int(bigint)), ty)
}
SyntaxKind::Octal => {
let mut text = value.text();
if let Some(stripped) = text.strip_prefix("0o") {
text = stripped;
}
let text = text.replace('_', "");
let bigint = if text.is_empty() {
BigInt::ZERO
} else {
BigInt::from_str_radix(&text, 8).expect("invalid octal literal")
};
let ty = ctx.alloc_type(Type::Atom(Atom::new(
AtomSemantic::Int,
Some(AtomRestriction::Value(Cow::Owned(bigint_atom(
bigint.clone(),
)))),
)));
Value::new(ctx.alloc_hir(Hir::Int(bigint)), ty)
}
SyntaxKind::Integer => {
let text = value.text().replace('_', "");
let num = BigInt::from_str(&text).unwrap();
let ty = ctx.alloc_type(Type::Atom(Atom::new(
AtomSemantic::Int,
Some(AtomRestriction::Value(Cow::Owned(bigint_atom(num.clone())))),
)));
Value::new(ctx.alloc_hir(Hir::Int(num)), ty)
}
T![nil] => ctx.builtins().nil.clone(),
T![true] => ctx.builtins().true_value.clone(),
T![false] => ctx.builtins().false_value.clone(),
_ => unreachable!(),
}
}