summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPgBiel <9021226+PgBiel@users.noreply.github.com>2024-04-30 09:49:18 -0300
committerGitHub <noreply@github.com>2024-04-30 12:49:18 +0000
commit1247c6d8e102cc40c3ec0d913a28ea904e4e4dec (patch)
tree16882e51a21702fbde207f873ea313926d1f0106
parent44bc51ba4fef66b7778668b3877a65425ac2eedc (diff)
Add `std` module for names in the standard library (#4038)
-rw-r--r--crates/typst/src/foundations/scope.rs24
-rw-r--r--crates/typst/src/lib.rs8
-rw-r--r--tests/ref/std-math.pngbin0 -> 298 bytes
-rw-r--r--tests/suite/foundations/std.typ31
4 files changed, 58 insertions, 5 deletions
diff --git a/crates/typst/src/foundations/scope.rs b/crates/typst/src/foundations/scope.rs
index caa82e13..870fa5b0 100644
--- a/crates/typst/src/foundations/scope.rs
+++ b/crates/typst/src/foundations/scope.rs
@@ -48,8 +48,14 @@ impl<'a> Scopes<'a> {
pub fn get(&self, var: &str) -> HintedStrResult<&Value> {
std::iter::once(&self.top)
.chain(self.scopes.iter().rev())
- .chain(self.base.map(|base| base.global.scope()))
.find_map(|scope| scope.get(var))
+ .or_else(|| {
+ self.base.and_then(|base| match base.global.scope().get(var) {
+ Some(value) => Some(value),
+ None if var == "std" => Some(&base.std),
+ None => None,
+ })
+ })
.ok_or_else(|| unknown_variable(var))
}
@@ -57,8 +63,14 @@ impl<'a> Scopes<'a> {
pub fn get_in_math(&self, var: &str) -> HintedStrResult<&Value> {
std::iter::once(&self.top)
.chain(self.scopes.iter().rev())
- .chain(self.base.map(|base| base.math.scope()))
.find_map(|scope| scope.get(var))
+ .or_else(|| {
+ self.base.and_then(|base| match base.math.scope().get(var) {
+ Some(value) => Some(value),
+ None if var == "std" => Some(&base.std),
+ None => None,
+ })
+ })
.ok_or_else(|| unknown_variable(var))
}
@@ -69,13 +81,19 @@ impl<'a> Scopes<'a> {
.find_map(|scope| scope.get_mut(var))
.ok_or_else(|| {
match self.base.and_then(|base| base.global.scope().get(var)) {
- Some(_) => eco_format!("cannot mutate a constant: {}", var).into(),
+ Some(_) => cannot_mutate_constant(var),
+ _ if var == "std" => cannot_mutate_constant(var),
_ => unknown_variable(var),
}
})?
}
}
+#[cold]
+fn cannot_mutate_constant(var: &str) -> HintedString {
+ eco_format!("cannot mutate a constant: {}", var).into()
+}
+
/// The error message when a variable is not found.
#[cold]
fn unknown_variable(var: &str) -> HintedString {
diff --git a/crates/typst/src/lib.rs b/crates/typst/src/lib.rs
index 35915e2b..f41fb605 100644
--- a/crates/typst/src/lib.rs
+++ b/crates/typst/src/lib.rs
@@ -67,7 +67,7 @@ use crate::diag::{warning, FileResult, SourceDiagnostic, SourceResult};
use crate::engine::{Engine, Route};
use crate::eval::Tracer;
use crate::foundations::{
- Array, Bytes, Content, Datetime, Dict, Module, Scope, StyleChain, Styles,
+ Array, Bytes, Content, Datetime, Dict, Module, Scope, StyleChain, Styles, Value,
};
use crate::introspection::{Introspector, Locator};
use crate::layout::{Alignment, Dir, LayoutRoot};
@@ -297,6 +297,9 @@ pub struct Library {
/// The default style properties (for page size, font selection, and
/// everything else configurable via set and show rules).
pub styles: Styles,
+ /// The standard library as a value.
+ /// Used to provide the `std` variable.
+ pub std: Value,
}
impl Library {
@@ -333,7 +336,8 @@ impl LibraryBuilder {
let math = math::module();
let inputs = self.inputs.unwrap_or_default();
let global = global(math.clone(), inputs);
- Library { global, math, styles: Styles::new() }
+ let std = Value::Module(global.clone());
+ Library { global, math, styles: Styles::new(), std }
}
}
diff --git a/tests/ref/std-math.png b/tests/ref/std-math.png
new file mode 100644
index 00000000..f7cecf47
--- /dev/null
+++ b/tests/ref/std-math.png
Binary files differ
diff --git a/tests/suite/foundations/std.typ b/tests/suite/foundations/std.typ
new file mode 100644
index 00000000..48a69502
--- /dev/null
+++ b/tests/suite/foundations/std.typ
@@ -0,0 +1,31 @@
+// Test 'std', a module with the standard library
+
+--- std-basic-access ---
+#test(std.grid, grid)
+#test(std.calc, calc)
+
+--- std-import ---
+#import std: grid as banana
+#test(grid, banana)
+
+--- std-of-shadowed ---
+#let my-grid = grid[a][b]
+#let grid = "oh no!"
+#test(my-grid.func(), std.grid)
+
+--- std-shadowing ---
+#let std = 5
+// Error: 6-10 cannot access fields on type integer
+#std.grid
+
+--- std-mutation ---
+// Error: 3-6 cannot mutate a constant: std
+#(std = 10)
+
+--- std-shadowed-mutation ---
+#let std = 10
+#(std = 7)
+#test(std, 7)
+
+--- std-math ---
+$ std.rect(x + y = 5) $