calyx_frontend/
lib_sig.rs1use crate::Primitive;
2use calyx_utils::Id;
3use itertools::Itertools;
4use linked_hash_map::LinkedHashMap;
5use std::path::PathBuf;
6
7#[derive(Debug)]
8pub enum PrimitiveInfo {
10 Extern {
12 path: PathBuf,
13 primitives: LinkedHashMap<Id, Primitive>,
14 is_source: bool,
15 },
16 Inline {
18 primitive: Primitive,
19 is_source: bool,
20 },
21}
22impl PrimitiveInfo {
23 pub fn ext(
24 path: PathBuf,
25 primitives: LinkedHashMap<Id, Primitive>,
26 ) -> Self {
27 PrimitiveInfo::Extern {
28 path,
29 primitives,
30 is_source: false,
31 }
32 }
33
34 pub fn inline(primitive: Primitive) -> Self {
35 PrimitiveInfo::Inline {
36 primitive,
37 is_source: false,
38 }
39 }
40
41 pub fn is_source(&self) -> bool {
43 match self {
44 PrimitiveInfo::Extern { is_source, .. } => *is_source,
45 PrimitiveInfo::Inline { is_source, .. } => *is_source,
46 }
47 }
48
49 pub fn set_source(&mut self) {
51 match self {
52 PrimitiveInfo::Extern {
53 ref mut is_source, ..
54 } => *is_source = true,
55 PrimitiveInfo::Inline {
56 ref mut is_source, ..
57 } => *is_source = true,
58 }
59 }
60}
61
62#[derive(Debug, Default)]
65pub struct LibrarySignatures {
66 prims: Vec<PrimitiveInfo>,
68}
69
70impl LibrarySignatures {
71 pub fn add_inline_primitive(
74 &mut self,
75 primitive: Primitive,
76 ) -> &mut PrimitiveInfo {
77 assert!(
78 primitive.body.is_some(),
79 "inline primitive must have a body"
80 );
81 let name = primitive.name;
82 if self.find_primitive(name).is_some() {
83 panic!("Primitive `{}` is already defined in the context.", name);
84 }
85 let prim = PrimitiveInfo::inline(primitive);
86 self.prims.push(prim);
87 self.prims.last_mut().unwrap()
88 }
89
90 pub fn add_extern_primitive(
94 &mut self,
95 file: PathBuf,
96 primitive: Primitive,
97 ) {
98 assert!(
99 primitive.body.is_none(),
100 "non-inline primitive must not have a body"
101 );
102 let name = primitive.name;
103 if self.find_primitive(name).is_some() {
104 panic!("Primitive `{}` is already defined in the context.", name);
105 }
106 let definined_ext = self.prims.iter_mut().find(|prim| match prim {
107 PrimitiveInfo::Extern { path, .. } => path == &file,
108 _ => false,
109 });
110 if let Some(PrimitiveInfo::Extern { primitives, .. }) = definined_ext {
111 primitives.insert(name, primitive);
112 } else {
113 let mut primitives = LinkedHashMap::new();
114 primitives.insert(name, primitive);
115 self.prims.push(PrimitiveInfo::ext(file, primitives));
116 }
117 }
118
119 pub(crate) fn add_extern(
120 &mut self,
121 file: PathBuf,
122 prims: Vec<Primitive>,
123 ) -> &mut PrimitiveInfo {
124 let definined_ext = self.prims.iter().any(|prim| match prim {
125 PrimitiveInfo::Extern { path, .. } => path == &file,
126 _ => false,
127 });
128 if definined_ext {
129 panic!(
130 "Extern block with file `{}` is already defined in the context",
131 file.display()
132 );
133 }
134
135 let ext = PrimitiveInfo::ext(
136 file,
137 prims.into_iter().map(|p| (p.name, p)).collect(),
138 );
139 self.prims.push(ext);
140 self.prims.last_mut().unwrap()
141 }
142
143 pub fn find_primitive<S>(&self, name: S) -> Option<&Primitive>
145 where
146 S: Into<Id>,
147 {
148 let key = name.into();
149 self.prims.iter().find_map(|prim| match prim {
150 PrimitiveInfo::Extern { primitives, .. } => primitives.get(&key),
151 PrimitiveInfo::Inline { primitive, .. } => {
152 if primitive.name == key {
153 Some(primitive)
154 } else {
155 None
156 }
157 }
158 })
159 }
160
161 pub fn get_primitive<S>(&self, name: S) -> &Primitive
163 where
164 S: Into<Id>,
165 {
166 let key = name.into();
167 self.find_primitive(key).unwrap_or_else(|| {
168 panic!("Primitive `{}` is not defined in the context.", key)
169 })
170 }
171
172 pub fn mark_inline_source(&mut self, name: Id) {
176 let Some(inlined) = self.prims.iter_mut().find(|prim| match prim {
177 PrimitiveInfo::Inline { primitive, .. } => primitive.name == name,
178 PrimitiveInfo::Extern { .. } => false,
179 }) else {
180 panic!("Primitive `{}` is not defined in the context.", name);
181 };
182 inlined.set_source()
183 }
184
185 pub fn mark_extern_source(&mut self, path: PathBuf) {
189 let Some(ext_def) = self.prims.iter_mut().find(|prim| match prim {
190 PrimitiveInfo::Extern { path: p, .. } => p == &path,
191 PrimitiveInfo::Inline { .. } => false,
192 }) else {
193 panic!(
194 "extern file `{}` is not defined in the context",
195 path.to_string_lossy()
196 );
197 };
198 ext_def.set_source()
199 }
200
201 pub fn signatures(&self) -> impl Iterator<Item = &Primitive> + '_ {
203 self.prims.iter().flat_map(|prim| match prim {
204 PrimitiveInfo::Extern { primitives, .. } => {
205 primitives.values().collect_vec()
206 }
207 PrimitiveInfo::Inline { primitive, .. } => vec![primitive],
208 })
209 }
210
211 pub fn prim_infos(&self) -> &Vec<PrimitiveInfo> {
214 &self.prims
215 }
216
217 pub fn prim_inlines(
219 &self,
220 ) -> impl Iterator<Item = (&Primitive, bool)> + '_ {
221 self.prims.iter().flat_map(|prim| match prim {
222 PrimitiveInfo::Extern { .. } => None,
223 PrimitiveInfo::Inline {
224 primitive,
225 is_source,
226 } => Some((primitive, *is_source)),
227 })
228 }
229
230 pub fn extern_paths(&self) -> Vec<&PathBuf> {
232 self.prims
233 .iter()
234 .filter_map(|p| match p {
235 PrimitiveInfo::Extern { path, .. } => Some(path),
236 PrimitiveInfo::Inline { .. } => None,
237 })
238 .collect_vec()
239 }
240}