use crate::{
error::Result,
id::{
ClassId, CodecId, FunctionId, LibId, MacroId, NumberDomainId, RuntimeId, ShapeId, SiteId,
Symbol,
},
library::{Export, ExportKind, ExportRecord, ExportState, Registry},
number_domain::{
NumberBinaryOp, NumberReductionOp, NumberUnaryOp, ValueNumberBinaryOp,
ValueNumberReductionOp, ValueNumberUnaryOp, ValuePromotionRule,
},
value::Value,
};
#[derive(Default)]
pub(crate) struct PendingExports {
pub(crate) exports: Vec<Export>,
pub(crate) export_records: Vec<ExportRecord>,
pub(crate) class_value_cache: Vec<(ClassId, Value)>,
pub(crate) function_value_cache: Vec<(FunctionId, Value)>,
pub(crate) macro_value_cache: Vec<(MacroId, Value)>,
pub(crate) shape_value_cache: Vec<(ShapeId, Value)>,
pub(crate) codec_value_cache: Vec<(CodecId, Value)>,
pub(crate) number_domain_value_cache: Vec<(NumberDomainId, Value)>,
pub(crate) site_value_cache: Vec<(SiteId, Value)>,
pub(crate) values: Vec<(Symbol, Value)>,
pub(crate) promotion_rules: Vec<crate::number_domain::PromotionRule>,
pub(crate) value_promotion_rules: Vec<ValuePromotionRule>,
pub(crate) number_unary_ops: Vec<NumberUnaryOp>,
pub(crate) number_reduction_ops: Vec<NumberReductionOp>,
pub(crate) number_binary_ops: Vec<NumberBinaryOp>,
pub(crate) value_number_unary_ops: Vec<ValueNumberUnaryOp>,
pub(crate) value_number_reduction_ops: Vec<ValueNumberReductionOp>,
pub(crate) value_number_binary_ops: Vec<ValueNumberBinaryOp>,
}
pub struct LoadTransaction {
pub(crate) lib_id: LibId,
pub(crate) manifest: crate::library::LibManifest,
pub(crate) trusted: bool,
pub(crate) registry: Registry,
pub(crate) pending: PendingExports,
}
pub struct Linker<'a> {
registry: &'a mut Registry,
lib: LibId,
pending: &'a mut PendingExports,
}
impl<'a> Linker<'a> {
pub(crate) fn new(
registry: &'a mut Registry,
lib: LibId,
pending: &'a mut PendingExports,
) -> Self {
Self {
registry,
lib,
pending,
}
}
pub fn lib_id(&self) -> LibId {
self.lib
}
pub fn registry(&self) -> &Registry {
self.registry
}
pub fn class(&mut self, symbol: Symbol) -> Result<ClassId> {
let id = self.registry.fresh_class_id();
self.pending.exports.push(Export::Class {
symbol,
class_id: Some(id),
});
Ok(id)
}
pub fn class_with_id(&mut self, symbol: Symbol, id: ClassId) -> Result<ClassId> {
self.registry.reserve_class_id(id);
self.pending.exports.push(Export::Class {
symbol,
class_id: Some(id),
});
Ok(id)
}
pub fn class_value(&mut self, symbol: Symbol, value: Value) -> Result<ClassId> {
let id = self.class(symbol)?;
self.bind_class_value(id, value)?;
Ok(id)
}
pub fn bind_class_value(&mut self, id: ClassId, value: Value) -> Result<()> {
self.pending.class_value_cache.push((id, value));
Ok(())
}
pub fn function(&mut self, symbol: Symbol) -> Result<FunctionId> {
let id = self.registry.fresh_function_id();
self.pending.exports.push(Export::Function {
symbol,
function_id: Some(id),
});
Ok(id)
}
pub fn function_value(&mut self, symbol: Symbol, value: Value) -> Result<FunctionId> {
let id = self.function(symbol)?;
self.bind_function_value(id, value)?;
Ok(id)
}
pub fn bind_function_value(&mut self, id: FunctionId, value: Value) -> Result<()> {
self.pending.function_value_cache.push((id, value));
Ok(())
}
pub fn macro_export(&mut self, symbol: Symbol) -> Result<MacroId> {
let id = self.registry.fresh_macro_id();
self.pending.exports.push(Export::Macro {
symbol,
macro_id: Some(id),
});
Ok(id)
}
pub fn macro_value(&mut self, symbol: Symbol, value: Value) -> Result<MacroId> {
let id = self.macro_export(symbol)?;
self.pending.macro_value_cache.push((id, value));
Ok(id)
}
pub fn shape(&mut self, symbol: Symbol) -> Result<ShapeId> {
let id = self.registry.fresh_shape_id();
self.pending.exports.push(Export::Shape {
symbol,
shape_id: Some(id),
});
Ok(id)
}
pub fn shape_value(&mut self, symbol: Symbol, value: Value) -> Result<ShapeId> {
let id = self.shape(symbol)?;
self.pending.shape_value_cache.push((id, value));
Ok(id)
}
pub fn codec(&mut self, symbol: Symbol) -> Result<CodecId> {
let id = self.registry.fresh_codec_id();
self.pending.exports.push(Export::Codec {
symbol,
codec_id: Some(id),
});
Ok(id)
}
pub fn codec_value(&mut self, symbol: Symbol, value: Value) -> Result<CodecId> {
let id = self.codec(symbol)?;
self.pending.codec_value_cache.push((id, value));
Ok(id)
}
pub fn number_domain(&mut self, symbol: Symbol) -> Result<NumberDomainId> {
let id = self.registry.fresh_number_domain_id();
self.pending.exports.push(Export::NumberDomain {
symbol,
number_domain_id: Some(id),
});
Ok(id)
}
pub fn number_domain_value(&mut self, symbol: Symbol, value: Value) -> Result<NumberDomainId> {
let id = self.number_domain(symbol)?;
self.pending.number_domain_value_cache.push((id, value));
Ok(id)
}
pub fn site_value(&mut self, symbol: Symbol, value: Value) -> Result<RuntimeId> {
let site_id = self.registry.fresh_site_id();
let runtime_id = RuntimeId::Site(site_id);
self.pending.exports.push(Export::Site {
symbol,
runtime_id: Some(runtime_id),
});
self.pending.site_value_cache.push((site_id, value));
Ok(runtime_id)
}
pub fn value_export(&mut self, symbol: Symbol) -> Result<()> {
self.pending.exports.push(Export::Value { symbol });
Ok(())
}
pub fn declare_export(&mut self, kind: ExportKind, symbol: Symbol) -> Result<()> {
self.pending.export_records.push(ExportRecord {
kind,
symbol,
state: ExportState::Declared,
});
Ok(())
}
pub fn unsupported_export(
&mut self,
kind: ExportKind,
symbol: Symbol,
reason: impl Into<String>,
) -> Result<()> {
self.pending.export_records.push(ExportRecord {
kind,
symbol,
state: ExportState::Unsupported {
reason: reason.into(),
},
});
Ok(())
}
pub fn value(&mut self, symbol: Symbol, value: Value) -> Result<()> {
self.value_export(symbol.clone())?;
self.pending.values.push((symbol, value));
Ok(())
}
pub fn number_binary_op(&mut self, op: NumberBinaryOp) {
self.pending.number_binary_ops.push(op);
}
pub fn value_number_binary_op(&mut self, op: ValueNumberBinaryOp) {
self.pending.value_number_binary_ops.push(op);
}
pub fn number_unary_op(&mut self, op: NumberUnaryOp) {
self.pending.number_unary_ops.push(op);
}
pub fn value_number_unary_op(&mut self, op: ValueNumberUnaryOp) {
self.pending.value_number_unary_ops.push(op);
}
pub fn number_reduction_op(&mut self, op: NumberReductionOp) {
self.pending.number_reduction_ops.push(op);
}
pub fn value_number_reduction_op(&mut self, op: ValueNumberReductionOp) {
self.pending.value_number_reduction_ops.push(op);
}
pub fn promotion_rule(&mut self, rule: crate::number_domain::PromotionRule) {
self.pending.promotion_rules.push(rule);
}
pub fn value_promotion_rule(&mut self, rule: ValuePromotionRule) {
self.pending.value_promotion_rules.push(rule);
}
}
impl LoadTransaction {
pub fn linker(&mut self) -> Linker<'_> {
Linker::new(&mut self.registry, self.lib_id, &mut self.pending)
}
}