use alloc::collections::BTreeMap;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use proc_macro2::Ident;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum Ns {
Value,
Type,
Lifetime,
Label,
Macro,
}
impl Ns {
pub(crate) fn key(self, name: &str) -> &str {
match self {
Self::Value | Self::Type | Self::Macro => unraw(name),
Self::Lifetime | Self::Label => name,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct BindingId(pub(crate) usize);
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub(crate) enum FreeKey {
Resolved(String),
Unresolved(String),
}
impl FreeKey {
pub(crate) fn text(&self) -> String {
match self {
Self::Resolved(name) => format!("f{name}"),
Self::Unresolved(name) => format!("g{name}"),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum Origin {
Parameter,
Let,
Closure,
Generic,
Lifetime,
Label,
Item,
Use,
TypeAlias,
MacroRule,
SelfTy,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) enum IntWidth {
W8,
W16,
W32,
W64,
W128,
}
impl IntWidth {
pub(crate) fn bits(self) -> u32 {
match self {
Self::W8 => 8,
Self::W16 => 16,
Self::W32 => 32,
Self::W64 => 64,
Self::W128 => 128,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) enum PrimTy {
Int { width: IntWidth, signed: bool },
Bool,
}
impl PrimTy {
pub(crate) fn suffix(self) -> &'static str {
match self {
Self::Int {
width,
signed: true,
} => match width {
IntWidth::W8 => "i8",
IntWidth::W16 => "i16",
IntWidth::W32 => "i32",
IntWidth::W64 => "i64",
IntWidth::W128 => "i128",
},
Self::Int {
width,
signed: false,
} => match width {
IntWidth::W8 => "u8",
IntWidth::W16 => "u16",
IntWidth::W32 => "u32",
IntWidth::W64 => "u64",
IntWidth::W128 => "u128",
},
Self::Bool => "bool",
}
}
}
pub(crate) fn primitive_suffix(name: &str) -> Option<PrimTy> {
match unraw(name) {
"i8" => Some(PrimTy::Int {
width: IntWidth::W8,
signed: true,
}),
"i16" => Some(PrimTy::Int {
width: IntWidth::W16,
signed: true,
}),
"i32" => Some(PrimTy::Int {
width: IntWidth::W32,
signed: true,
}),
"i64" => Some(PrimTy::Int {
width: IntWidth::W64,
signed: true,
}),
"i128" => Some(PrimTy::Int {
width: IntWidth::W128,
signed: true,
}),
"u8" => Some(PrimTy::Int {
width: IntWidth::W8,
signed: false,
}),
"u16" => Some(PrimTy::Int {
width: IntWidth::W16,
signed: false,
}),
"u32" => Some(PrimTy::Int {
width: IntWidth::W32,
signed: false,
}),
"u64" => Some(PrimTy::Int {
width: IntWidth::W64,
signed: false,
}),
"u128" => Some(PrimTy::Int {
width: IntWidth::W128,
signed: false,
}),
"bool" => Some(PrimTy::Bool),
_ => None,
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct HelperId(pub(crate) usize);
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct Binding {
pub(crate) id: BindingId,
pub(crate) canon: String,
pub(crate) origin: Origin,
pub(crate) prim: Option<PrimTy>,
pub(crate) port: usize,
pub(crate) value_port: Option<crate::schedule::Port>,
pub(crate) target: Option<usize>,
pub(crate) raw: bool,
pub(crate) helper: Option<HelperId>,
pub(crate) macro_resolution: Option<crate::macros::MacroResolution>,
}
#[derive(Clone, Default)]
pub(crate) struct Frame {
names: [BTreeMap<String, Binding>; 5],
pub(crate) glob: bool,
pub(crate) observed: bool,
pub(crate) std_rebound: u64,
enums: BTreeMap<BindingId, Vec<String>>,
}
impl Frame {
pub(crate) fn bind(&mut self, ns: Ns, name: &str, mut binding: Binding) {
binding.raw = name.starts_with("r#");
self.names[ns as usize].insert(ns.key(name).to_string(), binding);
}
pub(crate) fn lookup(&self, ns: Ns, name: &str) -> Option<&Binding> {
self.names[ns as usize].get(ns.key(name))
}
pub(crate) fn bindings(&self, ns: Ns) -> &BTreeMap<String, Binding> {
&self.names[ns as usize]
}
pub(crate) fn bindings_mut(&mut self, ns: Ns) -> &mut BTreeMap<String, Binding> {
&mut self.names[ns as usize]
}
pub(crate) fn next_id(&self) -> usize {
self.names
.iter()
.flat_map(BTreeMap::values)
.map(|binding| binding.id.0)
.max()
.map_or(0, |id| id + 1)
}
pub(crate) fn set_helper(&mut self, ns: Ns, name: &str, helper: HelperId) {
self.names[ns as usize]
.get_mut(ns.key(name))
.expect("indexed helper value binding")
.helper = Some(helper);
}
pub(crate) fn set_macro_resolution(
&mut self,
ns: Ns,
name: &str,
standard: Option<crate::macros::MacroResolution>,
) {
self.bindings_mut(ns)
.get_mut(ns.key(name))
.expect("a prebound name")
.macro_resolution = standard;
}
pub(crate) fn set_variants(&mut self, name: &str, item: &syn::ItemEnum) {
let id = self.lookup(Ns::Type, name).expect("a prebound enum").id;
self.enums.insert(
id,
item.variants
.iter()
.map(|variant| ident_name(&variant.ident))
.collect(),
);
}
pub(crate) fn variants(&self, binding: &Binding) -> Option<&[String]> {
self.enums.get(&binding.id).map(Vec::as_slice)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum Domain {
Local,
Inherited,
}
#[derive(Clone, Debug)]
pub(crate) struct TargetSeg {
pub(crate) name: String,
pub(crate) origin: Option<(Domain, BindingId, Ns)>,
}
#[derive(Clone, Debug)]
pub(crate) struct Target {
pub(crate) rooted: bool,
pub(crate) segments: Vec<TargetSeg>,
}
pub(crate) enum FirstSeg<'a> {
Alias(&'a Target),
Module(Domain, BindingId),
Free,
}
pub(crate) struct Inherited<'env> {
pub(crate) frames: &'env [Frame],
pub(crate) mod_frames: &'env BTreeMap<BindingId, Frame>,
pub(crate) targets: &'env [Target],
}
pub(crate) fn unraw(name: &str) -> &str {
name.strip_prefix("r#").unwrap_or(name)
}
pub(crate) fn ident_name(ident: &Ident) -> String {
unraw(&ident.to_string()).to_string()
}