Repository navigation
Syntax and Formats
How notatio — the interface — reads input and renders output, across the notebook, the
REPL, the command line, and the host. The text syntax is Epsil, compute-engine's own;
enumeratio's symbols are declared into it. Component attributes and cells take an
expression — MathJSON, written in Epsil — never statements or effects; a cell may add
one := binding on top of that (below). In the reference data the retypeable text form is
keyed epsil, and notatio keys the component (vdom) serialisation
(Examples as Data §2). Split out of the compute-host doc so the surface-syntax
decisions live in one place. Some of this is implemented; the rest is direction.
The default input syntax is Epsil — compute-engine's own surface syntax:
( for calls, ^ / / for powers and fractions, capitalized heads (Binomial,
Sqrt, Sin), list literals […]. It is also rendered back as Epsil (via
InputForm, see below), so what you type is what you get back.
-
LaTeX goes in
$…$islands inside an Epsil line (Binomial(10,3) + $\frac{1}{2}$), or behind the:latexpragma for a whole line. Bare LaTeX is not accepted — a line starting with\is an Epsil error. This is deliberate: Epsil is the default, and LaTeX is the escape hatch, not the other way round. -
AsciiMath and MathML read whole lines behind
:asciimath/:mathml(-i asciimath,-i mathmlon the command line) and import through the registry. They are notation, not a program: they reach an expression through TeX (AsciiMath, by asciimath2tex) or boxes (MathML,parseMathML) and compute-engine's LaTeX parser, until MakeExpression reads boxes directly (see Roadmap). - We lean on Epsil, not a fork — the goal is compute-engine's syntax as-is. Restricting an attribute or cell to one expression is a gate over it, not a new grammar.
We do not auto-detect syntax from the input shape any more (a leading [ used to
mean MathJSON, Head[…] Wolfram). Everything is Epsil unless a pragma says otherwise —
one rule, no surprises when an Epsil list literal starts with [.
A leading : is a pragma namespace. :latex / :wolfram / :mathjson / :epsil
select the syntax for one line; :in <syntax> sets the session default. That framing
should hold across environments:
-
REPL / TUI:
:is the pragma. Because it's a TUI we can do better than typing it — a mode dropdown (like the docs terminal's example picker) that sets the input syntax, with the active mode shown in the prompt. -
LaTeX affordance: a leading
\could mean "this line is LaTeX" (Lean-style), since\unambiguously starts a LaTeX command — a shorthand for:latex, complementing$…$islands. -
Command line: flags (
-i wolfram); unambiguous prefixes resolve (-i w). -
Host: a
syntaxfield on/eval; the same resolver.
Names are spelled out (:wolfram, not :wl). Short aliases and unique prefixes
still resolve for convenience but are not the documented form. One shared resolver
(resolveForm / resolveSyntax) backs the CLI flags, the REPL pragmas, and the host,
so behaviour is identical everywhere. (Implemented.)
A component attribute or a cell takes an expression — Epsil restricted to
a single expression with no statements or effects: no assignment (:= / =),
no declarations (type / protocol), no control flow (if / match / while),
no pragmas (#…), no ; sequences. It is the language of the web-component
attributes (<notatio-plot value>, <notatio-manipulate> slots) and the default
display form. parseExpression / serializeExpression (in @enumeratio/formats,
also on the /expression subpath for the browser elements) wrap parseEpsil /
serializeEpsil and add the single-expression gate — a parse error or a forbidden
head is a diagnostic, never a throw. Output always round-trips as itself (a result
prints as Epsil and re-reads as the same value).
$…$ LaTeX islands are allowed — Epsil's own feature (parsed through the engine's
LaTeX parser, threaded in as a parseLatex hook); without an engine the islands are
inert. A product of two symbols needs an explicit * in the Epsil text
(A * Sin(x)) — juxtaposition (A Sin(x)) is only legal inside an island.
A notebook or worksheet cell is that same expression plus one binding. Its seed
is read by parseExpression with allow: ["Assign"], so s := 2 is accepted there
and nowhere else — a cell is where a reader names something, and that is the only
statement it needs. Everything a cell binds is still evaluated by enumeratio.
The two names split by what they govern, not by layer. enumeratio is what an
expression means — the heads, their definitions, evaluation — and its language is
full Epsil, statements included, because a definition needs :=, type, control
flow. notatio is how a person writes and sees one: InputForm printing it back,
the *Form heads, the components. Rule of thumb for prose: "a head", "defined as" →
enumeratio; "written as", "typed", "prints as" → notatio.
Parameterized attributes use compute-engine's own pattern notation: a named
wildcard _name is a slot, filled from the control/parameter name (via CE's
.subs), then re-serialized. This replaced an earlier ${…} JS-template syntax,
which collided with Epsil's $ islands and {} set literals and evaluated as
JavaScript rather than as an expression. The _ prefix is the "this attribute is
a template" marker, so it is uniform across a plot's value (Sin(_a * x)) and any
other attribute (n="_n * 20"); <notatio-manipulate> treats a descendant
attribute as a template iff it parses as an expression and carries a matching
wildcard. In a plot, the wildcards are the bound parameters and the remaining bare
symbol is the plot axis.
A form is a way of writing an expression; each one makes a different promise about reading it back. Wolfram's names, with our meaning pinned down:
| Form | What it is | Reads back? | Where |
|---|---|---|---|
| FullForm | Every head in prefix: MathJSON, or Epsil with no operators (Add(Power(x, 2), 1)) |
exactly |
:fullform, the mathjson form, oracle traffic |
| InputForm |
Epsil, one expression, in printable ASCII (a string's contents aside): infix operators where Epsil has them (x^2 + 1, a <= b, n!), calls as Name(args), lists as […], one canonical spelling |
exactly: printer and reader round-trip, tested | the default text everywhere; text/plain on copy; the epsil column of the reference data |
| StandardForm | The default display: makeBoxes notation, typeset (KaTeX). Unambiguous: a head without notation stays Head(args)
|
yes: copy carries InputForm and a LaTeX compute-engine (and MathLive) reads back | reference cells, notebooks, <Head> tags in prose |
| TraditionalForm | Textbook notation (₂F₁(a, b; c; z), implied products, conventional names). May be ambiguous |
best effort, through its TeX | asked for explicitly; TeXForm is its TeX |
| OutputForm | StandardForm as one line of Unicode text (x² ≤ π), boxes' toText
|
no | terminals, outlines, titles, logs, search |
| DisplayForm | Boxes shown as themselves | n/a | a result that is already boxes |
Epsil is our InputForm. It already has what Wolfram's InputForm has over FullForm: infix,
prefix and postfix operators and one linear, retypeable spelling. It is not AsciiMath: every
head must be spellable exactly, and AsciiMath has no spelling for most of them. A $…$
island is LaTeX inside Epsil, written by hand; the printer never emits one.
AsciiMath is a format, not a form: the ASCII text of StandardForm's notation
(x^2 <= pi, sqrt(x), x in RR, sum_(n = 1)^oo n^(-2)), boxes' toAscii. It exports what
it can spell and imports through asciimath2tex; which expressions survive the trip is pinned
in packages/formats/tests/asciimath.golden.json (a binomial doesn't: AsciiMath has none).
MathML is the same notation as markup: out through makeBoxes → toMathML, in through
parseMathML → boxes → an expression.
Every output form is a registered format (:formats lists them, with MIME type
and import/export capability). Forms: inputform, tex, mathjson, wolfram,
epsil, asciimath, mathml, numpy, glsl, wgsl, js. The code forms are real
compute-engine compilation targets. :mime <type> is Wolfram's MIMETypeToFormatList.
The InputForm and Epsil registry formats share the serializeEpsil serializer;
they differ on import — InputForm enforces the single-expression restriction,
Epsil accepts full Epsil. TeX, MathML and AsciiMath read and write; the code forms
only write.
The default being Epsil means most command-line input needs no backslashes:
notatio "Binomial(10, 3)", notatio -f numpy "Sqrt(x^2 + 1)". For LaTeX, use
-i latex or a $…$ island, and either single-quote the expression or pipe a
quoted heredoc (<<'EOF'), which is literal so the backslashes reach notatio
intact. Documented in /docs/cli/command-line.