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> {
47 let kind = ExportKind::named(ExportKind::CLASS);
48 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
49 return Err(Error::DuplicateExport {
50 kind: "class",
51 symbol,
52 });
53 }
54 let id = self.try_fresh_class_id()?;
55 self.register_runtime_value(symbol, value, kind, RuntimeId::Class(id))?;
56 Ok(id)
57 }
58
59 pub fn register_function_value(&mut self, symbol: Symbol, value: Value) -> Result<FunctionId> {
62 let kind = ExportKind::named(ExportKind::FUNCTION);
63 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
64 return Err(Error::DuplicateExport {
65 kind: "function",
66 symbol,
67 });
68 }
69 let id = self.try_fresh_function_id()?;
70 self.register_runtime_value(symbol, value, kind, RuntimeId::Function(id))?;
71 Ok(id)
72 }
73
74 pub fn register_macro_value(&mut self, symbol: Symbol, value: Value) -> Result<MacroId> {
77 let kind = ExportKind::named(ExportKind::MACRO);
78 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
79 return Err(Error::DuplicateExport {
80 kind: "macro",
81 symbol,
82 });
83 }
84 let id = self.try_fresh_macro_id()?;
85 self.register_runtime_value(symbol, value, kind, RuntimeId::Macro(id))?;
86 Ok(id)
87 }
88
89 pub fn register_shape_value(&mut self, symbol: Symbol, value: Value) -> Result<ShapeId> {
92 let kind = ExportKind::named(ExportKind::SHAPE);
93 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
94 return Err(Error::DuplicateExport {
95 kind: "shape",
96 symbol,
97 });
98 }
99 let id = self.try_fresh_shape_id()?;
100 self.register_runtime_value(symbol, value, kind, RuntimeId::Shape(id))?;
101 Ok(id)
102 }
103
104 pub fn register_codec_value(&mut self, symbol: Symbol, value: Value) -> Result<CodecId> {
107 let kind = ExportKind::named(ExportKind::CODEC);
108 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
109 return Err(Error::DuplicateExport {
110 kind: "codec",
111 symbol,
112 });
113 }
114 let id = self.try_fresh_codec_id()?;
115 self.register_runtime_value(symbol, value, kind, RuntimeId::Codec(id))?;
116 Ok(id)
117 }
118
119 pub fn register_number_domain_value(
122 &mut self,
123 symbol: Symbol,
124 value: Value,
125 ) -> Result<NumberDomainId> {
126 let kind = ExportKind::named(ExportKind::NUMBER_DOMAIN);
127 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
128 return Err(Error::DuplicateExport {
129 kind: "number-domain",
130 symbol,
131 });
132 }
133 let id = self.try_fresh_number_domain_id()?;
134 self.register_runtime_value(symbol, value, kind, RuntimeId::NumberDomain(id))?;
135 Ok(id)
136 }
137
138 pub fn register_site_value(&mut self, symbol: Symbol, value: Value) -> Result<RuntimeId> {
141 let kind = ExportKind::named(ExportKind::SITE);
142 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
143 return Err(Error::DuplicateExport {
144 kind: "site",
145 symbol,
146 });
147 }
148 let id = self.try_fresh_site_id()?;
149 let runtime_id = RuntimeId::Site(id);
150 self.register_runtime_value(symbol, value, kind, runtime_id)?;
151 Ok(runtime_id)
152 }
153
154 pub fn sorted_number_domains(&mut self) -> Vec<(Symbol, Value)> {
157 if self.number_domain_order.is_none() {
158 self.rebuild_number_domain_order();
159 }
160
161 self.number_domain_order
162 .as_ref()
163 .into_iter()
164 .flatten()
165 .filter_map(|id| {
166 let symbol = self
167 .number_domain_symbol_cache
168 .iter()
169 .find_map(|(symbol, candidate)| (*candidate == *id).then(|| symbol.clone()))?;
170 let value = self.number_domain_value_cache.get(id)?.clone();
171 Some((symbol, value))
172 })
173 .collect()
174 }
175
176 pub fn register_test(
179 &mut self,
180 symbol: Symbol,
181 lib: Symbol,
182 test: std::sync::Arc<dyn Test>,
183 subjects: Vec<Symbol>,
184 ) -> Result<()> {
185 if self.catalog_test_by_symbol(&symbol).is_some() {
186 return Err(Error::DuplicateExport {
187 kind: "test",
188 symbol,
189 });
190 }
191 self.commit_direct_test_registration(
192 symbol.clone(),
193 lib.clone(),
194 test.clone(),
195 subjects.clone(),
196 )?;
197 self.tests.insert(
198 symbol.clone(),
199 RegisteredTest {
200 symbol: symbol.clone(),
201 lib: lib.clone(),
202 test,
203 subjects,
204 },
205 );
206 self.tests_by_lib
207 .entry(lib)
208 .or_default()
209 .push(symbol.clone());
210 Ok(())
211 }
212
213 pub fn register_value(&mut self, symbol: Symbol, value: Value) -> Result<()> {
216 let kind = ExportKind::named(ExportKind::VALUE);
217 if self.export_row_by_kind_symbol(&kind, &symbol).is_some() {
218 return Err(Error::DuplicateExport {
219 kind: "value",
220 symbol,
221 });
222 }
223 self.register_runtime_value(symbol, value, kind, RuntimeId::Value)?;
224 Ok(())
225 }
226
227 pub fn register_value_for_lib(
229 &mut self,
230 lib: &Symbol,
231 symbol: Symbol,
232 value: Value,
233 ) -> Result<()> {
234 self.register_value(symbol.clone(), value)?;
235 self.append_export_record(
236 lib,
237 ExportRecord {
238 kind: ExportKind::named(ExportKind::VALUE),
239 symbol,
240 state: ExportState::Resolved {
241 id: RuntimeId::Value,
242 },
243 },
244 )
245 }
246
247 pub fn append_export_record(&mut self, lib: &Symbol, record: ExportRecord) -> Result<()> {
251 let kind = record.kind.clone();
252 let symbol = record.symbol.clone();
253 let runtime_id = match &record.state {
254 ExportState::Resolved { id } => Some(*id),
255 _ => None,
256 };
257
258 let Some(loaded) = self.lib_mut(lib) else {
259 return Err(Error::Lib(format!("unknown lib {lib}")));
260 };
261 if loaded
262 .exports
263 .iter()
264 .any(|existing| existing.kind == kind && existing.symbol == symbol)
265 {
266 return Err(Error::DuplicateExport {
267 kind: kind.duplicate_error_kind(),
268 symbol,
269 });
270 }
271 loaded.exports.push(record);
272 if let Some(runtime_id) = runtime_id {
273 self.insert_runtime_export(kind, symbol, runtime_id);
274 }
275 Ok(())
276 }
277
278 pub fn register_number_binary_op(&mut self, op: NumberBinaryOp) {
280 self.number_binary_ops.push(op);
281 }
282
283 pub fn register_value_number_binary_op(&mut self, op: ValueNumberBinaryOp) {
285 self.value_number_binary_ops.push(op);
286 }
287
288 pub fn register_number_unary_op(&mut self, op: NumberUnaryOp) {
290 self.number_unary_ops.push(op);
291 }
292
293 pub fn register_value_number_unary_op(&mut self, op: ValueNumberUnaryOp) {
295 self.value_number_unary_ops.push(op);
296 }
297
298 pub fn register_number_reduction_op(&mut self, op: NumberReductionOp) {
300 self.number_reduction_ops.push(op);
301 }
302
303 pub fn register_value_number_reduction_op(&mut self, op: ValueNumberReductionOp) {
305 self.value_number_reduction_ops.push(op);
306 }
307
308 pub fn register_promotion_rule(&mut self, rule: crate::number_domain::PromotionRule) {
310 self.promotion_rules.push(rule);
311 }
312
313 pub fn register_value_promotion_rule(&mut self, rule: ValuePromotionRule) {
315 self.value_promotion_rules.push(rule);
316 }
317
318 pub fn promotion_rule(
321 &self,
322 from_domain: &Symbol,
323 to_domain: &Symbol,
324 ) -> Option<&crate::number_domain::PromotionRule> {
325 self.promotion_rules
326 .iter()
327 .filter(|rule| &rule.from_domain == from_domain && &rule.to_domain == to_domain)
328 .min_by_key(|rule| rule.cost)
329 }
330
331 pub fn promotion_rules(&self) -> &[crate::number_domain::PromotionRule] {
333 &self.promotion_rules
334 }
335
336 pub fn value_promotion_rules(&self) -> &[ValuePromotionRule] {
338 &self.value_promotion_rules
339 }
340
341 pub fn number_binary_ops(&self) -> &[NumberBinaryOp] {
343 &self.number_binary_ops
344 }
345
346 pub fn value_number_binary_ops(&self) -> &[ValueNumberBinaryOp] {
348 &self.value_number_binary_ops
349 }
350
351 pub fn number_unary_ops(&self) -> &[NumberUnaryOp] {
353 &self.number_unary_ops
354 }
355
356 pub fn value_number_unary_ops(&self) -> &[ValueNumberUnaryOp] {
358 &self.value_number_unary_ops
359 }
360
361 pub fn number_reduction_ops(&self) -> &[NumberReductionOp] {
363 &self.number_reduction_ops
364 }
365
366 pub fn value_number_reduction_ops(&self) -> &[ValueNumberReductionOp] {
368 &self.value_number_reduction_ops
369 }
370
371 pub fn number_binary_op(
374 &self,
375 operator: &Symbol,
376 left_domain: &Symbol,
377 right_domain: &Symbol,
378 ) -> Option<&NumberBinaryOp> {
379 self.number_binary_ops
380 .iter()
381 .filter(|op| {
382 &op.operator == operator
383 && &op.left_domain == left_domain
384 && &op.right_domain == right_domain
385 })
386 .min_by_key(|op| op.cost)
387 }
388
389 pub fn fresh_lib_id(&mut self) -> LibId {
391 LibId(self.reserve_catalog_sequence_id(catalog::SEQ_LIB))
392 }
393
394 pub fn try_fresh_lib_id(&mut self) -> Result<LibId> {
396 self.try_reserve_catalog_sequence_id(catalog::SEQ_LIB)
397 .map(LibId)
398 }
399
400 pub fn fresh_class_id(&mut self) -> ClassId {
402 ClassId(self.reserve_catalog_sequence_id(catalog::SEQ_CLASS))
403 }
404
405 pub fn try_fresh_class_id(&mut self) -> Result<ClassId> {
407 self.try_reserve_catalog_sequence_id(catalog::SEQ_CLASS)
408 .map(ClassId)
409 }
410
411 pub(crate) fn reserve_class_id(&mut self, id: ClassId) -> Result<()> {
412 self.try_reserve_catalog_sequence_at_least(catalog::SEQ_CLASS, id.0)
413 }
414
415 pub fn fresh_function_id(&mut self) -> FunctionId {
417 FunctionId(self.reserve_catalog_sequence_id(catalog::SEQ_FUNCTION))
418 }
419
420 pub fn try_fresh_function_id(&mut self) -> Result<FunctionId> {
422 self.try_reserve_catalog_sequence_id(catalog::SEQ_FUNCTION)
423 .map(FunctionId)
424 }
425
426 pub(crate) fn reserve_function_id(&mut self, id: FunctionId) -> Result<()> {
427 self.try_reserve_catalog_sequence_at_least(catalog::SEQ_FUNCTION, id.0)
428 }
429
430 pub fn fresh_macro_id(&mut self) -> MacroId {
432 MacroId(self.reserve_catalog_sequence_id(catalog::SEQ_MACRO))
433 }
434
435 pub fn try_fresh_macro_id(&mut self) -> Result<MacroId> {
437 self.try_reserve_catalog_sequence_id(catalog::SEQ_MACRO)
438 .map(MacroId)
439 }
440
441 pub(crate) fn reserve_macro_id(&mut self, id: MacroId) -> Result<()> {
442 self.try_reserve_catalog_sequence_at_least(catalog::SEQ_MACRO, id.0)
443 }
444
445 pub fn fresh_case_id(&mut self) -> CaseId {
447 CaseId(self.reserve_catalog_sequence_id(catalog::SEQ_CASE))
448 }
449
450 pub fn try_fresh_case_id(&mut self) -> Result<CaseId> {
452 self.try_reserve_catalog_sequence_id(catalog::SEQ_CASE)
453 .map(CaseId)
454 }
455
456 pub fn fresh_shape_id(&mut self) -> ShapeId {
458 ShapeId(self.reserve_catalog_sequence_id(catalog::SEQ_SHAPE))
459 }
460
461 pub fn try_fresh_shape_id(&mut self) -> Result<ShapeId> {
463 self.try_reserve_catalog_sequence_id(catalog::SEQ_SHAPE)
464 .map(ShapeId)
465 }
466
467 pub(crate) fn reserve_shape_id(&mut self, id: ShapeId) -> Result<()> {
468 self.try_reserve_catalog_sequence_at_least(catalog::SEQ_SHAPE, id.0)
469 }
470
471 pub fn fresh_codec_id(&mut self) -> CodecId {
473 CodecId(self.reserve_catalog_sequence_id(catalog::SEQ_CODEC))
474 }
475
476 pub fn try_fresh_codec_id(&mut self) -> Result<CodecId> {
478 self.try_reserve_catalog_sequence_id(catalog::SEQ_CODEC)
479 .map(CodecId)
480 }
481
482 pub(crate) fn reserve_codec_id(&mut self, id: CodecId) -> Result<()> {
483 self.try_reserve_catalog_sequence_at_least(catalog::SEQ_CODEC, id.0)
484 }
485
486 pub fn fresh_number_domain_id(&mut self) -> NumberDomainId {
488 NumberDomainId(self.reserve_catalog_sequence_id(catalog::SEQ_NUMBER_DOMAIN))
489 }
490
491 pub fn try_fresh_number_domain_id(&mut self) -> Result<NumberDomainId> {
494 self.try_reserve_catalog_sequence_id(catalog::SEQ_NUMBER_DOMAIN)
495 .map(NumberDomainId)
496 }
497
498 pub(crate) fn reserve_number_domain_id(&mut self, id: NumberDomainId) -> Result<()> {
499 self.try_reserve_catalog_sequence_at_least(catalog::SEQ_NUMBER_DOMAIN, id.0)
500 }
501
502 pub fn fresh_site_id(&mut self) -> SiteId {
504 SiteId(self.reserve_catalog_sequence_id(catalog::SEQ_SITE))
505 }
506
507 pub fn try_fresh_site_id(&mut self) -> Result<SiteId> {
509 self.try_reserve_catalog_sequence_id(catalog::SEQ_SITE)
510 .map(SiteId)
511 }
512
513 pub(crate) fn reserve_site_id(&mut self, id: SiteId) -> Result<()> {
514 self.try_reserve_catalog_sequence_at_least(catalog::SEQ_SITE, id.0)
515 }
516
517 pub(crate) fn insert_runtime_export(
518 &mut self,
519 kind: ExportKind,
520 symbol: Symbol,
521 id: RuntimeId,
522 ) {
523 self.export_symbols
524 .entry(kind)
525 .or_default()
526 .insert(symbol, id);
527 }
528
529 fn register_runtime_value(
530 &mut self,
531 symbol: Symbol,
532 value: Value,
533 kind: ExportKind,
534 runtime_id: RuntimeId,
535 ) -> Result<()> {
536 self.commit_direct_runtime_registration(
537 kind.clone(),
538 symbol.clone(),
539 runtime_id,
540 value.clone(),
541 )?;
542 match runtime_id {
543 RuntimeId::Class(id) => {
544 self.class_symbol_cache.insert(symbol.clone(), id);
545 self.class_value_cache.insert(id, value);
546 }
547 RuntimeId::Function(id) => {
548 self.function_symbol_cache.insert(symbol.clone(), id);
549 self.function_value_cache.insert(id, value);
550 }
551 RuntimeId::Macro(id) => {
552 self.macro_symbol_cache.insert(symbol.clone(), id);
553 self.macro_value_cache.insert(id, value);
554 }
555 RuntimeId::Shape(id) => {
556 self.shape_symbol_cache.insert(symbol.clone(), id);
557 self.shape_value_cache.insert(id, value);
558 }
559 RuntimeId::Codec(id) => {
560 self.codec_symbol_cache.insert(symbol.clone(), id);
561 self.codec_value_cache.insert(id, value);
562 }
563 RuntimeId::NumberDomain(id) => {
564 self.insert_number_domain_value(symbol.clone(), id, value);
565 }
566 RuntimeId::Site(id) => {
567 self.site_symbol_cache.insert(symbol.clone(), id);
568 self.site_value_cache.insert(id, value);
569 }
570 RuntimeId::Value => {
571 self.plain_value_cache.insert(symbol.clone(), value);
572 }
573 }
574 self.insert_runtime_export(kind.clone(), symbol.clone(), runtime_id);
575 Ok(())
576 }
577
578 pub(crate) fn insert_number_domain_value(
579 &mut self,
580 symbol: Symbol,
581 id: NumberDomainId,
582 value: Value,
583 ) {
584 self.number_domain_symbol_cache.insert(symbol, id);
585 self.number_domain_value_cache.insert(id, value);
586 self.number_domain_order = None;
587 }
588
589 pub(crate) fn rebuild_number_domain_order(&mut self) {
590 let mut order = self
591 .number_domain_symbol_cache
592 .iter()
593 .filter_map(|(symbol, id)| {
594 let value = self.number_domain_value_cache.get(id)?;
595 let priority = value
596 .object()
597 .as_number_domain()
598 .map(|domain| domain.parse_priority())
599 .unwrap_or(0);
600 Some((priority, symbol.clone(), *id))
601 })
602 .collect::<Vec<_>>();
603 order.sort_by(
604 |(left_priority, left_symbol, _), (right_priority, right_symbol, _)| {
605 right_priority
606 .cmp(left_priority)
607 .then_with(|| left_symbol.cmp(right_symbol))
608 },
609 );
610 self.number_domain_order = Some(order.into_iter().map(|(_, _, id)| id).collect());
611 }
612}