use std::collections::HashMap;
use crate::ast::{Declaration, ExternalDecl, Initializer, StorageClass};
use crate::intern::{InternedStr, StringInterner};
use crate::source::SourceLocation;
use crate::type_repr::TypeRepr;
#[derive(Debug, Clone)]
pub struct GlobalConstDecl {
pub name: InternedStr,
pub element_type: TypeRepr,
pub array_size: Option<usize>,
pub initializer: Initializer,
pub loc: SourceLocation,
}
#[derive(Debug, Default)]
pub struct GlobalConstDict {
decls: HashMap<InternedStr, GlobalConstDecl>,
}
impl GlobalConstDict {
pub fn new() -> Self {
Self::default()
}
pub fn try_collect(
&mut self,
decl: &ExternalDecl,
is_target: bool,
interner: &StringInterner,
) {
if !is_target {
return;
}
let d = match decl {
ExternalDecl::Declaration(d) => d,
_ => return,
};
if d.specs.storage != Some(StorageClass::Static) {
return;
}
if !d.specs.qualifiers.is_const {
return;
}
for init_decl in &d.declarators {
let name = match init_decl.declarator.name {
Some(n) => n,
None => continue,
};
let init = match &init_decl.init {
Some(i) => i.clone(),
None => continue,
};
let mut array_size: Option<usize> = None;
let mut is_array = false;
for d in &init_decl.declarator.derived {
if let crate::ast::DerivedDecl::Array(arr) = d {
is_array = true;
if let Some(sz_expr) = &arr.size {
if let crate::ast::ExprKind::IntLit(n) = &sz_expr.kind {
array_size = Some(*n as usize);
}
}
}
}
if !is_array {
continue; }
let element_type = build_element_type(d, init_decl, interner);
let entry = GlobalConstDecl {
name,
element_type,
array_size,
initializer: init,
loc: d.loc().clone(),
};
self.decls.entry(name).or_insert(entry);
}
}
pub fn get(&self, name: InternedStr) -> Option<&GlobalConstDecl> {
self.decls.get(&name)
}
pub fn iter(&self) -> impl Iterator<Item = (&InternedStr, &GlobalConstDecl)> {
self.decls.iter()
}
pub fn len(&self) -> usize {
self.decls.len()
}
pub fn is_empty(&self) -> bool {
self.decls.is_empty()
}
}
fn build_element_type(
decl: &Declaration,
init_decl: &crate::ast::InitDeclarator,
interner: &StringInterner,
) -> TypeRepr {
use crate::type_repr::CDerivedType;
let dropped_derived: Vec<crate::ast::DerivedDecl> = init_decl.declarator.derived
.iter()
.filter(|d| !matches!(d, crate::ast::DerivedDecl::Array(_)))
.cloned()
.collect();
let synthetic_decl = crate::ast::Declarator {
name: init_decl.declarator.name,
derived: dropped_derived,
loc: init_decl.declarator.loc.clone(),
};
let mut ty = TypeRepr::from_decl(&decl.specs, &synthetic_decl, interner);
if let TypeRepr::CType { derived, .. } = &mut ty {
derived.retain(|d| !matches!(d, CDerivedType::Array { .. }));
}
ty
}