summaryrefslogtreecommitdiff
path: root/src/eval/module.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-03-01 16:30:58 +0100
committerLaurenz <laurmaedje@gmail.com>2023-03-01 16:33:28 +0100
commit6ab7760822ccd24b4ef126d4737d41f1be15fe19 (patch)
tree49905f91d292ceefe4f9878ead43f117c4b1fec0 /src/eval/module.rs
parentab841188e3d2687ee8f436336e6fde337985a83e (diff)
Split up `model` module
Diffstat (limited to 'src/eval/module.rs')
-rw-r--r--src/eval/module.rs87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/eval/module.rs b/src/eval/module.rs
new file mode 100644
index 00000000..e911d859
--- /dev/null
+++ b/src/eval/module.rs
@@ -0,0 +1,87 @@
+use std::fmt::{self, Debug, Formatter};
+use std::sync::Arc;
+
+use ecow::{eco_format, EcoString};
+
+use super::{Content, Scope, Value};
+use crate::diag::StrResult;
+
+/// An evaluated module, ready for importing or typesetting.
+#[derive(Clone, Hash)]
+pub struct Module(Arc<Repr>);
+
+/// The internal representation.
+#[derive(Clone, Hash)]
+struct Repr {
+ /// The module's name.
+ name: EcoString,
+ /// The top-level definitions that were bound in this module.
+ scope: Scope,
+ /// The module's layoutable contents.
+ content: Content,
+}
+
+impl Module {
+ /// Create a new module.
+ pub fn new(name: impl Into<EcoString>) -> Self {
+ Self(Arc::new(Repr {
+ name: name.into(),
+ scope: Scope::new(),
+ content: Content::empty(),
+ }))
+ }
+
+ /// Update the module's scope.
+ pub fn with_scope(mut self, scope: Scope) -> Self {
+ Arc::make_mut(&mut self.0).scope = scope;
+ self
+ }
+
+ /// Update the module's content.
+ pub fn with_content(mut self, content: Content) -> Self {
+ Arc::make_mut(&mut self.0).content = content;
+ self
+ }
+
+ /// Get the module's name.
+ pub fn name(&self) -> &EcoString {
+ &self.0.name
+ }
+
+ /// Access the module's scope.
+ pub fn scope(&self) -> &Scope {
+ &self.0.scope
+ }
+
+ /// Access the module's scope, mutably.
+ pub fn scope_mut(&mut self) -> &mut Scope {
+ &mut Arc::make_mut(&mut self.0).scope
+ }
+
+ /// Try to access a definition in the module.
+ pub fn get(&self, name: &str) -> StrResult<&Value> {
+ self.scope().get(&name).ok_or_else(|| {
+ eco_format!("module `{}` does not contain `{name}`", self.name())
+ })
+ }
+
+ /// Extract the module's content.
+ pub fn content(self) -> Content {
+ match Arc::try_unwrap(self.0) {
+ Ok(repr) => repr.content,
+ Err(arc) => arc.content.clone(),
+ }
+ }
+}
+
+impl Debug for Module {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ write!(f, "<module {}>", self.name())
+ }
+}
+
+impl PartialEq for Module {
+ fn eq(&self, other: &Self) -> bool {
+ Arc::ptr_eq(&self.0, &other.0)
+ }
+}