Expressions as JSON values, and the symbol table
The math grammars are stated over the JSON value at an expression position
(spec §4.1), not over Esm.Ast, which drops fields. An expression is
- a number (
Json.num), in the canonical form of CONFORMANCE §5.5.3.1; - a name (
Json.str): dot-separated identifier segments (§4.6 scoped references); - a node (
Json.obj):op,argsand any other fields.
isE
is the well-formedness check. It asks for the canonical form only where the
round trip needs it: object keys strictly increasing (the sorted-key canonical
serialization), canonical numbers, every args entry an expression, and an op that
is neither removed (§4.2 “Removed ops”) nor deprecated (neg, pow: the printer
never writes them). Every other field may hold any well-formed JSON value. The
redundant spellings of Notation.spellingRules (an explicit reduce: "+", a
unitless scalar const, a D without wrt) are NOT excluded: they print in the
generic escape form and round-trip exactly, so the theorem covers them too.
The symbol table Sym
is what a document declares: the declared names and the
parameter lists of the templates in scope. The printer and the parser both consult
it, and the round-trip theorem holds for every table.
Characters
Names
def nameOK (s : String) : Bool
A name: dot-separated identifier segments (every name in the corpus has this shape).
def greek : List String
The Greek letter names that are a command in LaTeX (\lambda) and a symbol in
Typst (lambda): the lowercase letters but omicron, and the eleven uppercase letters
LaTeX has.
def isSingle (s : List Char) : Bool
One letter, or a Greek letter name: the single name shape.
def elements : List String
The element symbols a chemical-formula name is built from.
def digRun : List Char → List Char × List Char
The maximal run of digits at the front.
def letRun : List Char → List Char × List Char
The maximal run of letters at the front.
def pieces (s : List Char) : List (List Char × List Char)
Split a formula-shaped name into pieces: a run of letters and the run of digits
after it (possibly empty). CH2O is [("CH", "2"), ("O", "")].
def elemToks : List Char → Option (List String)
The element-symbol tokens of a letter run: an uppercase letter, then an optional lowercase one, greedily.
def isFormula (s : List Char) : Bool
A chemical-formula name (decision 2): letters and digits only, read as element
symbols and counts, starting with an element, with at least two tokens. NO2,
CH2O, O3, NO.
def subParts (s : List Char) : Option (List Char × List Char)
The subscripted shape b_r: a single letter or Greek name, _, then a nonempty
rest. Returns the base and the rest.
Numbers and JSON well-formedness, as checks
Operators
def deprecatedOps : List String
Deprecated: read in the call form and rewritten, never printed.
def opOK (s : String) : Bool
The op pattern of the schema: [A-Za-z_][A-Za-z0-9_.]* or [-+*/^<>=!]+.
Expressions
def opFieldOK (kvs : List (String × Json)) : Bool
The op field is present and names an operator that is neither removed nor
deprecated.