1use crate::{
2 error::{Error, Result},
3 id::{
4 CaseId, ClassId, CodecId, FunctionId, LibId, MacroId, NumberDomainId, RuntimeId, ShapeId,
5 SiteId, Symbol,
6 },
7 number_domain::{
8 NumberBinaryOp, NumberReductionOp, NumberUnaryOp, ValueNumberBinaryOp,
9 ValueNumberReductionOp, ValueNumberUnaryOp, ValuePromotionRule,
10 },
11 value::Value,
12};
13
14use super::{Registry, catalog};
15use crate::library::{ExportKind, ExportRecord, ExportState, RegisteredTest, Test};
16
17impl Registry {
18 pub fn register_class_value(&mut self, symbol: Symbol, value: Value) -> Result<ClassId> {
43 let kind = ExportKind::named(ExportKind::CLASS);
44 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
45 return Err(Error::DuplicateExport {
46 kind: "class",
47 symbol,
48 });
49 }
50 let id = self.fresh_class_id();
51 self.register_runtime_value(symbol, value, kind, RuntimeId::Class(id))?;
52 Ok(id)
53 }
54
55 pub fn register_function_value(&mut self, symbol: Symbol, value: Value) -> Result<FunctionId> {
58 let kind = ExportKind::named(ExportKind::FUNCTION);
59 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
60 return Err(Error::DuplicateExport {
61 kind: "function",
62 symbol,
63 });
64 }
65 let id = self.fresh_function_id();
66 self.register_runtime_value(symbol, value, kind, RuntimeId::Function(id))?;
67 Ok(id)
68 }
69
70 pub fn register_macro_value(&mut self, symbol: Symbol, value: Value) -> Result<MacroId> {
73 let kind = ExportKind::named(ExportKind::MACRO);
74 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
75 return Err(Error::DuplicateExport {
76 kind: "macro",
77 symbol,
78 });
79 }
80 let id = self.fresh_macro_id();
81 self.register_runtime_value(symbol, value, kind, RuntimeId::Macro(id))?;
82 Ok(id)
83 }
84
85 pub fn register_shape_value(&mut self, symbol: Symbol, value: Value) -> Result<ShapeId> {
88 let kind = ExportKind::named(ExportKind::SHAPE);
89 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
90 return Err(Error::DuplicateExport {
91 kind: "shape",
92 symbol,
93 });
94 }
95 let id = self.fresh_shape_id();
96 self.register_runtime_value(symbol, value, kind, RuntimeId::Shape(id))?;
97 Ok(id)
98 }
99
100 pub fn register_codec_value(&mut self, symbol: Symbol, value: Value) -> Result<CodecId> {
103 let kind = ExportKind::named(ExportKind::CODEC);
104 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
105 return Err(Error::DuplicateExport {
106 kind: "codec",
107 symbol,
108 });
109 }
110 let id = self.fresh_codec_id();
111 self.register_runtime_value(symbol, value, kind, RuntimeId::Codec(id))?;
112 Ok(id)
113 }
114
115 pub fn register_number_domain_value(
118 &mut self,
119 symbol: Symbol,
120 value: Value,
121 ) -> Result<NumberDomainId> {
122 let kind = ExportKind::named(ExportKind::NUMBER_DOMAIN);
123 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
124 return Err(Error::DuplicateExport {
125 kind: "number-domain",
126 symbol,
127 });
128 }
129 let id = self.fresh_number_domain_id();
130 self.register_runtime_value(symbol, value, kind, RuntimeId::NumberDomain(id))?;
131 Ok(id)
132 }
133
134 pub fn register_site_value(&mut self, symbol: Symbol, value: Value) -> Result<RuntimeId> {
137 let kind = ExportKind::named(ExportKind::SITE);
138 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
139 return Err(Error::DuplicateExport {
140 kind: "site",
141 symbol,
142 });
143 }
144 let id = self.fresh_site_id();
145 let runtime_id = RuntimeId::Site(id);
146 self.register_runtime_value(symbol, value, kind, runtime_id)?;
147 Ok(runtime_id)
148 }
149
150 pub fn sorted_number_domains(&mut self) -> Vec<(Symbol, Value)> {
153 if self.number_domain_order.is_none() {
154 self.rebuild_number_domain_order();
155 }
156
157 self.number_domain_order
158 .as_ref()
159 .into_iter()
160 .flatten()
161 .filter_map(|id| {
162 let symbol = self
163 .number_domain_symbol_cache
164 .iter()
165 .find_map(|(symbol, candidate)| (*candidate == *id).then(|| symbol.clone()))?;
166 let value = self.number_domain_value_cache.get(id)?.clone();
167 Some((symbol, value))
168 })
169 .collect()
170 }
171
172 pub fn register_test(
175 &mut self,
176 symbol: Symbol,
177 lib: Symbol,
178 test: std::sync::Arc<dyn Test>,
179 subjects: Vec<Symbol>,
180 ) -> Result<()> {
181 if self.catalog_test_by_symbol(&symbol).is_some() {
182 return Err(Error::DuplicateExport {
183 kind: "test",
184 symbol,
185 });
186 }
187 self.commit_direct_test_registration(
188 symbol.clone(),
189 lib.clone(),
190 test.clone(),
191 subjects.clone(),
192 )?;
193 self.tests.insert(
194 symbol.clone(),
195 RegisteredTest {
196 symbol: symbol.clone(),
197 lib: lib.clone(),
198 test,
199 subjects,
200 },
201 );
202 self.tests_by_lib
203 .entry(lib)
204 .or_default()
205 .push(symbol.clone());
206 Ok(())
207 }
208
209 pub fn register_value(&mut self, symbol: Symbol, value: Value) -> Result<()> {
212 let kind = ExportKind::named(ExportKind::VALUE);
213 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
214 return Err(Error::DuplicateExport {
215 kind: "value",
216 symbol,
217 });
218 }
219 self.register_runtime_value(symbol, value, kind, RuntimeId::Value)?;
220 Ok(())
221 }
222
223 pub fn register_value_for_lib(
225 &mut self,
226 lib: &Symbol,
227 symbol: Symbol,
228 value: Value,
229 ) -> Result<()> {
230 self.register_value(symbol.clone(), value)?;
231 self.append_export_record(
232 lib,
233 ExportRecord {
234 kind: ExportKind::named(ExportKind::VALUE),
235 symbol,
236 state: ExportState::Resolved {
237 id: RuntimeId::Value,
238 },
239 },
240 )
241 }
242
243 pub fn append_export_record(&mut self, lib: &Symbol, record: ExportRecord) -> Result<()> {
247 let kind = record.kind.clone();
248 let symbol = record.symbol.clone();
249 let runtime_id = match &record.state {
250 ExportState::Resolved { id } => Some(*id),
251 _ => None,
252 };
253
254 let Some(loaded) = self.lib_mut(lib) else {
255 return Err(Error::Lib(format!("unknown lib {lib}")));
256 };
257 if loaded
258 .exports
259 .iter()
260 .any(|existing| existing.kind == kind && existing.symbol == symbol)
261 {
262 return Err(Error::DuplicateExport {
263 kind: kind.duplicate_error_kind(),
264 symbol,
265 });
266 }
267 loaded.exports.push(record);
268 if let Some(runtime_id) = runtime_id {
269 self.insert_runtime_export(kind, symbol, runtime_id);
270 }
271 Ok(())
272 }
273
274 pub fn register_number_binary_op(&mut self, op: NumberBinaryOp) {
276 self.number_binary_ops.push(op);
277 }
278
279 pub fn register_value_number_binary_op(&mut self, op: ValueNumberBinaryOp) {
281 self.value_number_binary_ops.push(op);
282 }
283
284 pub fn register_number_unary_op(&mut self, op: NumberUnaryOp) {
286 self.number_unary_ops.push(op);
287 }
288
289 pub fn register_value_number_unary_op(&mut self, op: ValueNumberUnaryOp) {
291 self.value_number_unary_ops.push(op);
292 }
293
294 pub fn register_number_reduction_op(&mut self, op: NumberReductionOp) {
296 self.number_reduction_ops.push(op);
297 }
298
299 pub fn register_value_number_reduction_op(&mut self, op: ValueNumberReductionOp) {
301 self.value_number_reduction_ops.push(op);
302 }
303
304 pub fn register_promotion_rule(&mut self, rule: crate::number_domain::PromotionRule) {
306 self.promotion_rules.push(rule);
307 }
308
309 pub fn register_value_promotion_rule(&mut self, rule: ValuePromotionRule) {
311 self.value_promotion_rules.push(rule);
312 }
313
314 pub fn promotion_rule(
317 &self,
318 from_domain: &Symbol,
319 to_domain: &Symbol,
320 ) -> Option<&crate::number_domain::PromotionRule> {
321 self.promotion_rules
322 .iter()
323 .filter(|rule| &rule.from_domain == from_domain && &rule.to_domain == to_domain)
324 .min_by_key(|rule| rule.cost)
325 }
326
327 pub fn promotion_rules(&self) -> &[crate::number_domain::PromotionRule] {
329 &self.promotion_rules
330 }
331
332 pub fn value_promotion_rules(&self) -> &[ValuePromotionRule] {
334 &self.value_promotion_rules
335 }
336
337 pub fn number_binary_ops(&self) -> &[NumberBinaryOp] {
339 &self.number_binary_ops
340 }
341
342 pub fn value_number_binary_ops(&self) -> &[ValueNumberBinaryOp] {
344 &self.value_number_binary_ops
345 }
346
347 pub fn number_unary_ops(&self) -> &[NumberUnaryOp] {
349 &self.number_unary_ops
350 }
351
352 pub fn value_number_unary_ops(&self) -> &[ValueNumberUnaryOp] {
354 &self.value_number_unary_ops
355 }
356
357 pub fn number_reduction_ops(&self) -> &[NumberReductionOp] {
359 &self.number_reduction_ops
360 }
361
362 pub fn value_number_reduction_ops(&self) -> &[ValueNumberReductionOp] {
364 &self.value_number_reduction_ops
365 }
366
367 pub fn number_binary_op(
370 &self,
371 operator: &Symbol,
372 left_domain: &Symbol,
373 right_domain: &Symbol,
374 ) -> Option<&NumberBinaryOp> {
375 self.number_binary_ops
376 .iter()
377 .filter(|op| {
378 &op.operator == operator
379 && &op.left_domain == left_domain
380 && &op.right_domain == right_domain
381 })
382 .min_by_key(|op| op.cost)
383 }
384
385 pub fn fresh_lib_id(&mut self) -> LibId {
387 LibId(self.reserve_catalog_sequence_id(catalog::SEQ_LIB))
388 }
389
390 pub fn fresh_class_id(&mut self) -> ClassId {
392 ClassId(self.reserve_catalog_sequence_id(catalog::SEQ_CLASS))
393 }
394
395 pub(crate) fn reserve_class_id(&mut self, id: ClassId) {
396 self.reserve_catalog_sequence_at_least(catalog::SEQ_CLASS, id.0);
397 }
398
399 pub fn fresh_function_id(&mut self) -> FunctionId {
401 FunctionId(self.reserve_catalog_sequence_id(catalog::SEQ_FUNCTION))
402 }
403
404 pub fn fresh_macro_id(&mut self) -> MacroId {
406 MacroId(self.reserve_catalog_sequence_id(catalog::SEQ_MACRO))
407 }
408
409 pub fn fresh_case_id(&mut self) -> CaseId {
411 CaseId(self.reserve_catalog_sequence_id(catalog::SEQ_CASE))
412 }
413
414 pub fn fresh_shape_id(&mut self) -> ShapeId {
416 ShapeId(self.reserve_catalog_sequence_id(catalog::SEQ_SHAPE))
417 }
418
419 pub fn fresh_codec_id(&mut self) -> CodecId {
421 CodecId(self.reserve_catalog_sequence_id(catalog::SEQ_CODEC))
422 }
423
424 pub fn fresh_number_domain_id(&mut self) -> NumberDomainId {
426 NumberDomainId(self.reserve_catalog_sequence_id(catalog::SEQ_NUMBER_DOMAIN))
427 }
428
429 pub fn fresh_site_id(&mut self) -> SiteId {
431 SiteId(self.reserve_catalog_sequence_id(catalog::SEQ_SITE))
432 }
433
434 pub(crate) fn insert_runtime_export(
435 &mut self,
436 kind: ExportKind,
437 symbol: Symbol,
438 id: RuntimeId,
439 ) {
440 self.export_symbols
441 .entry(kind)
442 .or_default()
443 .insert(symbol, id);
444 }
445
446 fn register_runtime_value(
447 &mut self,
448 symbol: Symbol,
449 value: Value,
450 kind: ExportKind,
451 runtime_id: RuntimeId,
452 ) -> Result<()> {
453 self.commit_direct_runtime_registration(
454 kind.clone(),
455 symbol.clone(),
456 runtime_id,
457 value.clone(),
458 )?;
459 match runtime_id {
460 RuntimeId::Class(id) => {
461 self.class_symbol_cache.insert(symbol.clone(), id);
462 self.class_value_cache.insert(id, value);
463 }
464 RuntimeId::Function(id) => {
465 self.function_symbol_cache.insert(symbol.clone(), id);
466 self.function_value_cache.insert(id, value);
467 }
468 RuntimeId::Macro(id) => {
469 self.macro_symbol_cache.insert(symbol.clone(), id);
470 self.macro_value_cache.insert(id, value);
471 }
472 RuntimeId::Shape(id) => {
473 self.shape_symbol_cache.insert(symbol.clone(), id);
474 self.shape_value_cache.insert(id, value);
475 }
476 RuntimeId::Codec(id) => {
477 self.codec_symbol_cache.insert(symbol.clone(), id);
478 self.codec_value_cache.insert(id, value);
479 }
480 RuntimeId::NumberDomain(id) => {
481 self.insert_number_domain_value(symbol.clone(), id, value);
482 }
483 RuntimeId::Site(id) => {
484 self.site_symbol_cache.insert(symbol.clone(), id);
485 self.site_value_cache.insert(id, value);
486 }
487 RuntimeId::Value => {
488 self.plain_value_cache.insert(symbol.clone(), value);
489 }
490 }
491 self.insert_runtime_export(kind.clone(), symbol.clone(), runtime_id);
492 Ok(())
493 }
494
495 pub(crate) fn insert_number_domain_value(
496 &mut self,
497 symbol: Symbol,
498 id: NumberDomainId,
499 value: Value,
500 ) {
501 self.number_domain_symbol_cache.insert(symbol, id);
502 self.number_domain_value_cache.insert(id, value);
503 self.number_domain_order = None;
504 }
505
506 pub(crate) fn rebuild_number_domain_order(&mut self) {
507 let mut order = self
508 .number_domain_symbol_cache
509 .iter()
510 .filter_map(|(symbol, id)| {
511 let value = self.number_domain_value_cache.get(id)?;
512 let priority = value
513 .object()
514 .as_number_domain()
515 .map(|domain| domain.parse_priority())
516 .unwrap_or(0);
517 Some((priority, symbol.clone(), *id))
518 })
519 .collect::<Vec<_>>();
520 order.sort_by(
521 |(left_priority, left_symbol, _), (right_priority, right_symbol, _)| {
522 right_priority
523 .cmp(left_priority)
524 .then_with(|| left_symbol.cmp(right_symbol))
525 },
526 );
527 self.number_domain_order = Some(order.into_iter().map(|(_, _, id)| id).collect());
528 }
529}