-
-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathCargo.toml
More file actions
340 lines (321 loc) · 14.6 KB
/
Copy pathCargo.toml
File metadata and controls
340 lines (321 loc) · 14.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
[workspace]
members = [".", "woxi-studio", "woxi-py"]
# Unscoped commands at the root (`cargo build`, `make test`, CI) build only
# the interpreter; woxi-studio (iced → wgpu/winit, 100+ extra crates) is
# built explicitly via `-p woxi-studio` / `make install-macos-app`.
default-members = ["."]
resolver = "3"
# The cargo-fuzz crate is its own workspace: it needs nightly + libFuzzer
# and must not affect the root Cargo.lock or default builds.
exclude = ["fuzz"]
[package]
name = "woxi"
description = "Interpreter for a subset of the Wolfram Language"
keywords = ["wolfram", "wolfram-language", "mathematica", "cas", "math"]
version = "0.3.0"
edition = "2024"
# Point at the lowercase file explicitly; otherwise cargo auto-detects it
# via a case-insensitive search for README.md and synthesizes a duplicate
# uppercase entry in the packaged crate.
readme = "readme.md"
license = "AGPL-3.0-or-later"
repository = "https://github.com/ad-si/Woxi"
# `cargo run -- eval '…'` should run the interpreter CLI, not the
# woxi-diff-fuzz helper binary.
default-run = "woxi"
# Keep packages built from this crate (crates.io and the PyPI sdist,
# which vendors this crate via maturin) down to what's needed to
# compile it. tests/SUMMARY.md, functions.csv, and resources/ are
# embedded via include_str!/include_bytes! and must stay, as must
# benches/interpreter.rs (an explicitly declared [[bench]] target).
exclude = [
"/tests/*/",
"/tests/woxi",
"/tests/zensical.toml",
"/images",
"/files",
"/datasets",
"/examples",
"/entity_types",
"/jupyterlite-woxi-kernel",
"/kernelspec",
"/scripts",
"/woxi-studio",
"/woxi-py",
"/npm",
"/fuzz",
"/.claude",
"/.vscode",
"/.github",
"/.sprite",
"/Dockerfile",
"/flake.nix",
"/flake.lock",
]
# Differential fuzzer comparing woxi against wolframscript
# (see fuzz/README.md and `make fuzz-diff`). Gated behind the non-default
# `diff-fuzz` feature so the default build (and `cargo install`) produces
# only the `woxi` CLI, not this dev-only helper. Build/run it with
# `--features diff-fuzz`.
[[bin]]
name = "woxi-diff-fuzz"
path = "src/bin/diff_fuzz.rs"
required-features = ["diff-fuzz"]
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["cli"]
cli = [
"dep:clap",
"dep:dirs",
"dep:env_logger",
"dep:jupyter-protocol",
"dep:log",
"dep:runtimelib",
"dep:rustyline",
"dep:tokio",
"dep:uuid",
"dep:zeromq",
]
wasm = ["dep:wasm-bindgen", "dep:getrandom", "dep:console_error_panic_hook", "dep:js-sys"]
# Compiles in the tests that are excluded from the normal test run: the
# heavy RosettaCode script snapshots (`slow_script_test!`) and the tests
# that query the live wikidata.org API. Without this feature they don't
# exist in the test binaries at all, so `make test` doesn't report them as
# skipped. They run nightly via `make test-slow`.
slow-tests = []
# The dev-only differential fuzzer (`src/bin/diff_fuzz.rs`, spawns
# `wolframscript`). Non-default so `cargo install` ships only the `woxi`
# CLI; implies `cli` since the fuzzer drives the CLI binary.
diff-fuzz = ["cli"]
# `pub` items rustc can't see from outside the crate escape the dead_code
# lint; warning on them keeps dead code detectable via plain `cargo check`.
[lints.rust]
unreachable_pub = "warn"
# CI gates on `cargo clippy -- -W clippy::pedantic -D warnings` (`make lint`).
# The lints below are allowed crate-wide because following them would make
# this code worse, not better; every other clippy lint must stay clean.
[lints.clippy]
# The pedantic group is enabled as a whole; `priority = -1` makes the
# individual `allow`s below outrank it.
pedantic = { level = "warn", priority = -1 }
# Numeric kernels (matrix decompositions, quadrature, image convolutions)
# index several parallel arrays inside one loop, where `for i in 0..n` is
# both the conventional notation and clearer than zipped iterators.
needless_range_loop = "allow"
# The thread_local evaluator state (definitions, option contexts) is a
# tuple-of-vectors by design; naming each shape adds indirection without
# making the storage easier to follow.
type_complexity = "allow"
# Evaluator entry points thread the full call context (args, head,
# attributes, options, precision, …) explicitly rather than through a
# struct, so the argument counts are deliberate.
too_many_arguments = "allow"
# --- pedantic lints this codebase deliberately does not follow ---
# Doc comments name Wolfram Language symbols (Plus, TagSetDelayed, HoldFirst)
# as prose, not as Rust items. Backticking every occurrence would make the
# documentation harder to read, and the names do not resolve as doc links.
doc_markdown = "allow"
# The interpreter converts constantly between the numeric tower's `i64`,
# `usize`, `f64` and `BigInt` at boundaries where the range is already
# established by the surrounding logic (list indices, pixel coordinates,
# precision counts). Annotating each of those with a `try_into().unwrap()`
# would add panics, not safety.
cast_sign_loss = "allow"
cast_possible_truncation = "allow"
cast_possible_wrap = "allow"
cast_precision_loss = "allow"
cast_lossless = "allow"
# Tables of mathematical constants, colour values and named-character code
# points are transcribed from their sources digit for digit; inserting `_`
# separators would obscure that correspondence.
unreadable_literal = "allow"
# Errors and panics are documented where they are not obvious. Requiring an
# `# Errors` section on every `-> Result` function would add ~1500 comments
# restating the return type.
missing_errors_doc = "allow"
missing_panics_doc = "allow"
# The evaluator's builtin dispatch is a flat match over hundreds of Wolfram
# symbols. Splitting those on line count alone would scatter related cases.
too_many_lines = "allow"
# `#[must_use]` on every getter would be noise in a crate whose public API is
# the interpreter entry points, not the internal expression helpers.
must_use_candidate = "allow"
# Mathematical code uses the notation of its domain: `n`, `x`, `y`, `z` for
# coordinates, `p`/`q` for rational parts, `a`/`b`/`c` for coefficients.
many_single_char_names = "allow"
similar_names = "allow"
# The interpreter must reproduce Wolfram's results bit for bit, so machine
# reals are compared exactly on purpose (round-trip checks, integrality
# tests, cache lookups). An epsilon comparison would change the semantics.
float_cmp = "allow"
# Numeric code dispatches on the sign of a value with the notation of its
# domain — `if x < 0 … else if x > 0 … else …`. Rewriting those chains as
# `match x.cmp(&0)` would obscure the arithmetic for no behavioural gain,
# the same reason `needless_range_loop` is allowed above.
comparison_chain = "allow"
# Doc comments quote Wolfram calls such as `assoc["a", "b"]` and
# `Quantity["Hertz"]`, which clippy reads as a malformed intra-doc link.
# They are sample input, not links.
doc_link_with_quotes = "allow"
# `Option<Option<T>>` is a documented tri-state where both levels carry
# meaning — e.g. `None` = not an infinity, `Some(None)` = ComplexInfinity
# (direction unknown), `Some(Some(d))` = explicit direction. Naming an enum
# per site would not make the three cases clearer than the comment does.
option_option = "allow"
# Wolfram snippets in the test suite are uniformly written as `r#"…"#`.
# Dropping the hashes from just those that happen to contain no `"` would
# make the tables inconsistent for no gain.
needless_raw_string_hashes = "allow"
# Symbol dispatch is written as one `match` arm per Wolfram symbol (see
# `evaluator/dispatch/arg_count.rs`), and character tables as one arm per
# code point. The arms are alphabetical and individually commented; merging
# the ones that currently share a body into `|` chains would destroy both
# properties and churn every time a single symbol's behaviour diverges.
match_same_arms = "allow"
# SVG, notebook and box-form emitters build their output with
# `s.push_str(&format!(…))`. `write!` would return a `fmt::Error` that a
# `String` sink can never produce, so every call site would grow an
# `unwrap()` — a panic path where there is currently none.
format_push_string = "allow"
# Helper `fn`s and `const` tables are declared next to the statements that
# use them rather than hoisted to the top of the enclosing function, which
# keeps a long evaluator branch readable in one pass.
items_after_statements = "allow"
# Every `evaluator` and `functions` submodule opens with `use super::*` to
# pick up the shared prelude (Expr, InterpreterError, the arg helpers). The
# glob is the module layout, not an oversight; enumerating it per file would
# add hundreds of import lines that need editing on every prelude change.
wildcard_imports = "allow"
[dependencies]
anyhow = "1.0.98"
clap = { version = "4.3", features = ["derive"], optional = true }
dirs = { version = "6.0.0", optional = true }
env_logger = { version = "0.11", optional = true }
getrandom = { version = "0.2", features = ["js"], optional = true }
log = { version = "0.4", optional = true }
jupyter-protocol = { version = "1.2", optional = true }
# The git rev carries a wasm32 word-size overflow fix that is not in any
# crates.io release yet. The version is only used for the published crate
# (cargo strips the git spec), where the bug is irrelevant: the wasm build
# is always made from this repo and keeps the pinned rev.
astro-float = { version = "0.9.5", git = "https://github.com/stencillogic/astro-float", rev = "f92380e025deb8e1743ed93c6d5bf0783ac28717" }
base64 = "0.22"
flate2 = "1.0"
# Pure-Rust OpenType parser (wasm-compatible), used to extract Leland (SMuFL)
# music-glyph outlines as self-contained SVG paths. Matches the version resvg
# already pulls in so no duplicate copy is linked.
ttf-parser = "0.25"
geographiclib-rs = "0.2"
# Pure-Rust math for domain coloring and the astronomy ephemerides: the
# transcendentals of the platform libm differ by ULPs between macOS, glibc
# and MSVC, which flips 8-bit color rounding at .5 boundaries and moves the
# last digit of a position, so the snapshots break across platforms.
libm = "0.2"
num-bigint = "0.4.6"
num-prime = "0.5"
plotters = { version = "0.3", default-features = false, features = ["svg_backend", "line_series", "area_series"] }
num-traits = "0.2.19"
pest = "2.5"
pest_derive = "2.5"
petgraph = "0.8.3"
rand = "0.8"
runtimelib = { version = "1.3", features = ["tokio-runtime"], optional = true }
rustyline = { version = "15", optional = true }
serde_json = { version = "1.0", features = ["preserve_order"] }
snailquote = "0.3.1"
thiserror = "1.0.63"
tokio = { version = "1.45.0", features = ["full"], optional = true }
uuid = { version = "1.16.0", features = ["v4"], optional = true }
console_error_panic_hook = { version = "0.1", optional = true }
js-sys = { version = "0.3", optional = true }
wasm-bindgen = { version = "0.2", optional = true }
zeromq = { version = "0.5.0-pre", features = ["tokio-runtime"], default-features = false, optional = true }
regex = "1.12.3"
unicode-normalization = "0.1"
# Drop-in replacement for std::time::{Instant, SystemTime} that works on
# wasm32-unknown-unknown (uses Performance.now()/Date.now()) instead of
# panicking. Re-exports std on native targets.
web-time = "1.1"
sha2 = "0.10"
md-5 = "0.10"
sha1 = "0.10"
rand_distr = "0.4"
rand_chacha = "0.3"
stacker = "0.1"
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "gif", "bmp", "tiff"] }
# Persistent / structurally-shared vector for the Prepend hot path.
# Most lists stay backed by Vec<Expr> (cheap, contiguous slices). Lists
# that hit `push_front` upgrade to imbl::Vector for O(log N) prepends.
imbl = "5"
# LZ4 block decompression for CERN ROOT (.root) file imports. Pure Rust and
# wasm-compatible; `safe-decode` keeps the decoder free of unsafe code since
# the input is untrusted file data.
lz4_flex = { version = "0.11", default-features = false, features = ["std", "safe-decode"] }
# Country / subdivision gazetteer (names, translations, geo coordinates) used
# to resolve geographic Entity[…] specifications to positions.
# `search-translations` is deliberately NOT enabled: its single auto-generated
# ~34k-entry HashMap literal adds ~20s to every clean compile. We rebuild that
# name→country lookup ourselves at runtime from `translations` (see
# `country_name_index` in src/functions/geographics.rs), which is identical.
keshvar = { version = "0.7", features = ["subdivisions", "geo", "translations"] }
sha3 = "0.10"
ripemd = "0.1"
md4 = "0.10"
# Kept on the same resvg minor as svg2pdf 0.13 and iced 0.14 (woxi-studio),
# so only ONE copy of the resvg/usvg/tiny-skia stack is compiled and linked
# across the workspace. Bump only in lockstep with those two.
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.resvg]
version = "0.45"
default-features = false
features = ["text", "raster-images"]
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.svg2pdf]
version = "0.13"
default-features = false
features = ["text"]
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
libc = "0.2"
calamine = "0.34"
rust_xlsxwriter = { version = "0.94", default-features = false }
# All chrono call sites are `#[cfg(not(target_arch = "wasm32"))]`, not
# cli-gated, so chrono must be available whenever the library itself is
# built for a native target (e.g. the woxi-py Python extension, which
# uses `default-features = false`).
chrono = "0.4"
chrono-tz = "0.10"
[dev-dependencies]
base64 = "0.22"
num-bigint = "0.4.6"
insta = { version = "1", features = ["glob"] }
proptest = "1"
image = { version = "0.25", default-features = false, features = ["png", "gif"] }
criterion = { version = "0.5", default-features = false, features = ["html_reports"] }
[[bench]]
name = "interpreter"
harness = false
# Dev/test builds keep file:line info for panics and backtraces but skip
# local-variable debug info — faster codegen and much faster linking for a
# ~400k-line crate. `split-debuginfo = "unpacked"` additionally skips the
# slow dsymutil packaging step on macOS.
[profile.dev]
opt-level = 1
debug = "line-tables-only"
split-debuginfo = "unpacked"
[profile.release]
codegen-units = 1
lto = true
# Surface integer-overflow bugs as loud panics in shipped builds instead of
# silently wrapping to wrong results. For a CAS, numeric correctness matters
# more than the small runtime cost of the checks (see issue #180).
overflow-checks = true
# Profile for shipping Woxi Studio (see `make install-macos-app`). The GUI
# doesn't need the interpreter's fat-LTO/single-CGU treatment, and applying
# it to the iced/wgpu dependency tree makes release builds take far longer
# than necessary. Thin LTO + parallel codegen builds several times faster
# at near-identical runtime performance.
[profile.studio]
inherits = "release"
lto = "thin"
codegen-units = 16
[patch.crates-io]
astro-float-num = { git = "https://github.com/stencillogic/astro-float", rev = "f92380e025deb8e1743ed93c6d5bf0783ac28717" }