From 1247c6d8e102cc40c3ec0d913a28ea904e4e4dec Mon Sep 17 00:00:00 2001 From: PgBiel <9021226+PgBiel@users.noreply.github.com> Date: Tue, 30 Apr 2024 09:49:18 -0300 Subject: [PATCH] Add `std` module for names in the standard library (#4038) --- crates/typst/src/foundations/scope.rs | 24 +++++++++++++++++--- crates/typst/src/lib.rs | 8 +++++-- tests/ref/std-math.png | Bin 0 -> 298 bytes tests/suite/foundations/std.typ | 31 ++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 tests/ref/std-math.png create mode 100644 tests/suite/foundations/std.typ diff --git a/crates/typst/src/foundations/scope.rs b/crates/typst/src/foundations/scope.rs index caa82e136..870fa5b0f 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 35915e2b1..f41fb6050 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 0000000000000000000000000000000000000000..f7cecf477e6f26ab62e573d7dcac45fbe203d206 GIT binary patch literal 298 zcmV+_0oDGAP)WpVTrJMdO?plKmI zUBB)vRek(#O82+!RZx*O2=#EniXXlE(Nxblbb-1-{n`Ca=RZ`7|4*O&e*%bp-VFvX zLF{FJ8c$F+sBfzM0n-!O+T7aO4uhCqou3{-Q~dej|1EjcwRrKOhW}_j{-0C!AI-pr*w?YpXsxOhLE!;v@{!t5@W_qgkrn2ch1a+xh`h`9Ip{<0sAgM@ufMS{&;T wLI$u;pxEMftH}Z%MjLyh7LQsyYB9|K08)XM)l~a3761SM07*qoM6N<$g4CUeCjbBd literal 0 HcmV?d00001 diff --git a/tests/suite/foundations/std.typ b/tests/suite/foundations/std.typ new file mode 100644 index 000000000..48a695022 --- /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) $