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