use std::collections::HashMap;
use proc_macro2::Ident;
use quote::format_ident;
use crate::codegen::CodeGen;
fn binding_ident(index: usize, name: &str) -> Ident {
let sanitized: String = name
.chars()
.map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
.collect();
format_ident!("rel_{}_{}", index, sanitized)
}
impl CodeGen {
pub(super) fn make_global_ident_map(&mut self) {
self.global_fp_to_ident = self
.program
.relations()
.iter()
.enumerate()
.map(|(index, rel)| (rel.fingerprint(), binding_ident(index, rel.name())))
.collect();
}
pub(super) fn find_global_ident(&self, fp: u64) -> Ident {
self.global_fp_to_ident
.get(&fp)
.cloned()
.unwrap_or_else(|| format_ident!("t_{}", fp))
}
pub(super) fn display_name(&self, fp: u64) -> String {
self.program
.relation_by_fingerprint(fp)
.map(|rel| rel.raw_name().to_string())
.unwrap_or_else(|| self.find_global_ident(fp).to_string())
}
}
pub(crate) fn find_local_ident(local_fp_to_ident: &HashMap<u64, Ident>, fp: u64) -> Ident {
local_fp_to_ident
.get(&fp)
.cloned()
.unwrap_or_else(|| format_ident!("t_{}", fp))
}
#[cfg(test)]
mod binding_ident_tests {
use super::binding_ident;
use quote::quote;
#[test]
fn keyword_names_are_harmless() {
for (i, kw) in ["type", "match", "crate", "self", "Self", "super"]
.iter()
.enumerate()
{
let id = binding_ident(i, kw);
let ts = quote! { { let #id = 1; let _ = #id; } };
syn::parse2::<syn::Block>(ts).unwrap_or_else(|e| {
panic!("keyword {kw:?} -> `{id}` is not a usable binding: {e}")
});
}
assert_eq!(binding_ident(0, "type").to_string(), "rel_0_type");
}
#[test]
fn identical_names_distinct_by_index() {
assert_ne!(
binding_ident(3, "edge").to_string(),
binding_ident(4, "edge").to_string()
);
assert_eq!(binding_ident(1, "crate_").to_string(), "rel_1_crate_");
}
#[test]
fn inliner_separator_is_sanitized() {
assert_eq!(binding_ident(2, "c·holdsat").to_string(), "rel_2_c_holdsat");
}
}