microsoft/qdk
Publicmirrored from https://github.com/microsoft/qdkAvailable
compiler/qsc_hir/src/global.rs
172lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | use crate::{ |
| 5 | hir::{Item, ItemId, ItemKind, ItemStatus, Package, PackageId, SpecBody, SpecGen, Visibility}, |
| 6 | ty::Scheme, |
| 7 | }; |
| 8 | use qsc_data_structures::index_map; |
| 9 | use rustc_hash::FxHashMap; |
| 10 | use std::rc::Rc; |
| 11 | |
| 12 | pub struct Global { |
| 13 | pub namespace: Rc<str>, |
| 14 | pub name: Rc<str>, |
| 15 | pub visibility: Visibility, |
| 16 | pub status: ItemStatus, |
| 17 | pub kind: Kind, |
| 18 | } |
| 19 | |
| 20 | pub enum Kind { |
| 21 | Namespace, |
| 22 | Ty(Ty), |
| 23 | Term(Term), |
| 24 | } |
| 25 | |
| 26 | pub struct Ty { |
| 27 | pub id: ItemId, |
| 28 | } |
| 29 | |
| 30 | pub struct Term { |
| 31 | pub id: ItemId, |
| 32 | pub scheme: Scheme, |
| 33 | pub intrinsic: bool, |
| 34 | } |
| 35 | |
| 36 | #[derive(Default)] |
| 37 | pub struct Table { |
| 38 | tys: FxHashMap<Rc<str>, FxHashMap<Rc<str>, Ty>>, |
| 39 | terms: FxHashMap<Rc<str>, FxHashMap<Rc<str>, Term>>, |
| 40 | } |
| 41 | |
| 42 | impl Table { |
| 43 | #[must_use] |
| 44 | pub fn resolve_ty(&self, namespace: &str, name: &str) -> Option<&Ty> { |
| 45 | self.tys.get(namespace).and_then(|terms| terms.get(name)) |
| 46 | } |
| 47 | |
| 48 | #[must_use] |
| 49 | pub fn resolve_term(&self, namespace: &str, name: &str) -> Option<&Term> { |
| 50 | self.terms.get(namespace).and_then(|terms| terms.get(name)) |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | impl FromIterator<Global> for Table { |
| 55 | fn from_iter<T: IntoIterator<Item = Global>>(iter: T) -> Self { |
| 56 | let mut tys: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); |
| 57 | let mut terms: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); |
| 58 | for global in iter { |
| 59 | match global.kind { |
| 60 | Kind::Ty(ty) => { |
| 61 | tys.entry(global.namespace) |
| 62 | .or_default() |
| 63 | .insert(global.name, ty); |
| 64 | } |
| 65 | Kind::Term(term) => { |
| 66 | terms |
| 67 | .entry(global.namespace) |
| 68 | .or_default() |
| 69 | .insert(global.name, term); |
| 70 | } |
| 71 | Kind::Namespace => {} |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | Self { tys, terms } |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | pub struct PackageIter<'a> { |
| 80 | id: Option<PackageId>, |
| 81 | package: &'a Package, |
| 82 | items: index_map::Values<'a, Item>, |
| 83 | next: Option<Global>, |
| 84 | } |
| 85 | |
| 86 | impl PackageIter<'_> { |
| 87 | fn global_item(&mut self, item: &Item) -> Option<Global> { |
| 88 | let parent = item.parent.map(|parent| { |
| 89 | &self |
| 90 | .package |
| 91 | .items |
| 92 | .get(parent) |
| 93 | .expect("parent should exist") |
| 94 | .kind |
| 95 | }); |
| 96 | let id = ItemId { |
| 97 | package: self.id, |
| 98 | item: item.id, |
| 99 | }; |
| 100 | let status = ItemStatus::from_attrs(item.attrs.as_ref()); |
| 101 | |
| 102 | match (&item.kind, &parent) { |
| 103 | (ItemKind::Callable(decl), Some(ItemKind::Namespace(namespace, _))) => Some(Global { |
| 104 | namespace: Rc::clone(&namespace.name), |
| 105 | name: Rc::clone(&decl.name.name), |
| 106 | visibility: item.visibility, |
| 107 | status, |
| 108 | kind: Kind::Term(Term { |
| 109 | id, |
| 110 | scheme: decl.scheme(), |
| 111 | intrinsic: decl.body.body == SpecBody::Gen(SpecGen::Intrinsic), |
| 112 | }), |
| 113 | }), |
| 114 | (ItemKind::Ty(name, def), Some(ItemKind::Namespace(namespace, _))) => { |
| 115 | self.next = Some(Global { |
| 116 | namespace: Rc::clone(&namespace.name), |
| 117 | name: Rc::clone(&name.name), |
| 118 | visibility: item.visibility, |
| 119 | status, |
| 120 | kind: Kind::Term(Term { |
| 121 | id, |
| 122 | scheme: def.cons_scheme(id), |
| 123 | intrinsic: false, |
| 124 | }), |
| 125 | }); |
| 126 | |
| 127 | Some(Global { |
| 128 | namespace: Rc::clone(&namespace.name), |
| 129 | name: Rc::clone(&name.name), |
| 130 | visibility: item.visibility, |
| 131 | status, |
| 132 | kind: Kind::Ty(Ty { id }), |
| 133 | }) |
| 134 | } |
| 135 | (ItemKind::Namespace(ident, _), None) => Some(Global { |
| 136 | namespace: "".into(), |
| 137 | name: Rc::clone(&ident.name), |
| 138 | visibility: Visibility::Public, |
| 139 | status, |
| 140 | kind: Kind::Namespace, |
| 141 | }), |
| 142 | _ => None, |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | impl<'a> Iterator for PackageIter<'a> { |
| 148 | type Item = Global; |
| 149 | |
| 150 | fn next(&mut self) -> Option<Self::Item> { |
| 151 | if let Some(global) = self.next.take() { |
| 152 | Some(global) |
| 153 | } else { |
| 154 | loop { |
| 155 | let item = self.items.next()?; |
| 156 | if let Some(global) = self.global_item(item) { |
| 157 | break Some(global); |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | #[must_use] |
| 165 | pub fn iter_package(id: Option<PackageId>, package: &Package) -> PackageIter { |
| 166 | PackageIter { |
| 167 | id, |
| 168 | package, |
| 169 | items: package.items.values(), |
| 170 | next: None, |
| 171 | } |
| 172 | } |
| 173 | |