charon_lib/ast/
meta_utils.rsuse crate::meta::*;
use crate::names::{Disambiguator, Name, PathElem};
use itertools::Itertools;
use std::cmp::Ordering;
use std::iter::Iterator;
impl Loc {
fn dummy() -> Self {
Loc { line: 0, col: 0 }
}
fn min(l0: &Loc, l1: &Loc) -> Loc {
match l0.line.cmp(&l1.line) {
Ordering::Equal => Loc {
line: l0.line,
col: std::cmp::min(l0.col, l1.col),
},
Ordering::Less => *l0,
Ordering::Greater => *l1,
}
}
fn max(l0: &Loc, l1: &Loc) -> Loc {
match l0.line.cmp(&l1.line) {
Ordering::Equal => Loc {
line: l0.line,
col: std::cmp::max(l0.col, l1.col),
},
Ordering::Greater => *l0,
Ordering::Less => *l1,
}
}
}
impl RawSpan {
pub fn dummy() -> Self {
RawSpan {
file_id: FileId::from_raw(0),
beg: Loc::dummy(),
end: Loc::dummy(),
#[cfg(feature = "rustc")]
rust_span_data: rustc_span::DUMMY_SP.data(),
}
}
fn sort_key(&self) -> impl Ord {
(self.file_id, self.beg, self.end)
}
}
impl PartialOrd for RawSpan {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RawSpan {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.sort_key().cmp(&other.sort_key())
}
}
impl Span {
pub fn dummy() -> Self {
Span {
span: RawSpan::dummy(),
generated_from_span: None,
}
}
}
pub fn combine_span(m0: &Span, m1: &Span) -> Span {
if m0.span.file_id == m1.span.file_id {
let span = RawSpan {
file_id: m0.span.file_id,
beg: Loc::min(&m0.span.beg, &m1.span.beg),
end: Loc::max(&m0.span.end, &m1.span.end),
#[cfg(feature = "rustc")]
rust_span_data: m0
.span
.rust_span_data
.span()
.to(m1.span.rust_span_data.span())
.data(),
};
Span {
span,
generated_from_span: None,
}
} else {
*m0
}
}
pub fn combine_span_iter<'a, T: Iterator<Item = &'a Span>>(mut ms: T) -> Span {
let mut mc: Span = *ms.next().unwrap();
for m in ms {
mc = combine_span(&mc, m);
}
mc
}
impl Attribute {
pub fn parse_from_raw(raw_attr: RawAttribute) -> Result<Self, String> {
let path = raw_attr.path.split("::").collect_vec();
let attr_name = if let &[path_start, attr_name] = path.as_slice()
&& (path_start == "charon" || path_start == "aeneas")
{
attr_name
} else {
return Ok(Self::Unknown(raw_attr));
};
match Self::parse_special_attr(attr_name, raw_attr.args.as_deref())? {
Some(parsed) => Ok(parsed),
None => Err(format!(
"Unrecognized attribute: `{}`",
raw_attr.to_string()
)),
}
}
fn parse_special_attr(attr_name: &str, args: Option<&str>) -> Result<Option<Self>, String> {
let parsed = match attr_name {
"opaque" if args.is_none() => Self::Opaque,
"rename" if let Some(attr) = args => {
let Some(attr) = attr
.strip_prefix("\"")
.and_then(|attr| attr.strip_suffix("\""))
else {
return Err(format!(
"the new name should be between quotes: `rename(\"{attr}\")`."
));
};
if attr.is_empty() {
return Err(format!("attribute `rename` should not be empty"));
}
let first_char = attr.chars().nth(0).unwrap();
let is_identifier = (first_char.is_alphabetic() || first_char == '_')
&& attr.chars().all(|c| c.is_alphanumeric() || c == '_');
if !is_identifier {
return Err(format!(
"attribute `rename` should contain a valid identifier"
));
}
Self::Rename(attr.to_string())
}
"variants_prefix" if let Some(attr) = args => {
let Some(attr) = attr
.strip_prefix("\"")
.and_then(|attr| attr.strip_suffix("\""))
else {
return Err(format!(
"the name should be between quotes: `variants_prefix(\"{attr}\")`."
));
};
Self::VariantsPrefix(attr.to_string())
}
"variants_suffix" if let Some(attr) = args => {
let Some(attr) = attr
.strip_prefix("\"")
.and_then(|attr| attr.strip_suffix("\""))
else {
return Err(format!(
"the name should be between quotes: `variants_suffix(\"{attr}\")`."
));
};
Self::VariantsSuffix(attr.to_string())
}
_ => return Ok(None),
};
Ok(Some(parsed))
}
}
impl ItemOpacity {
pub fn with_content_visibility(self, contents_are_public: bool) -> Self {
use ItemOpacity::*;
match self {
Invisible => Invisible,
Transparent => Transparent,
Foreign if contents_are_public => Transparent,
Foreign => Opaque,
Opaque => Opaque,
}
}
pub fn with_private_contents(self) -> Self {
self.with_content_visibility(false)
}
}
impl ItemMeta {
pub fn renamed_name(&self) -> Name {
let mut name = self.name.clone();
if let Some(rename) = self.attr_info.rename.clone() {
*name.name.last_mut().unwrap() = PathElem::Ident(rename, Disambiguator::new(0));
}
name
}
}