code wiki / _hdl_build / nx_tex.nx
nx_tex.nx
buildroot/runtime/_hdl_build/nx_tex.nx
about
nx_tex.nx -- SOVEREIGN LaTeX-math -> presentation MathML renderer (IMS Thrust D, rung 1).
The core of the "arXiv PDF->HTML / LaTeX" capability: turn a real, useful subset of LaTeX math
into WELL-FORMED presentation MathML (<math>...</math>, every open tag closed) with a tokenizer
+ a small recursive-descent parser. PURE + DETERMINISTIC (no clock, no network) so it is trivially
gateable by exact-MathML KATs. Scratch memory via sys_mmap only.
SUBSET COVERED (rung 1):
* digits / decimal numbers -> <mn>123</mn> / <mn>1.5</mn>
* letters / multi-letter identifiers -> <mi>x</mi> (one <mi> per letter, MathML-standard)
* operators + - = < > -> <mo>+</mo> ... ; '*' -> ∗ ; '/' -> <mo>/</mo>
* superscript a^b -> <msup>base sup</msup>
* subscript a_b -> <msub>base sub</msub>
* both a_b^c (or a^b_c) on a base -> <msubsup>base sub sup</msubsup>
* \frac{a}{b} -> <mfrac>a b</mfrac>
* \sqrt{x} -> <msqrt> x </msqrt>
* big operators with optional _lower ^upper limits (either order):
\sum -> munderover(∑, lower, upper) (sum-style, limits under/over)
\prod -> munderover(∏, lower, upper)
\int -> msubsup(∫, lower, upper) (integral-style, limits as sub/sup)
(one limit -> munder/mover or msub/msup ; no limits -> bare <mo>)
* greek \alpha..\omega and \Gamma..\Omega -> the Unicode glyph in <mi>
* \cdot \times \div \pm \le \ge \neq \approx \equiv \to \cdots \ldots -> proper <mo>
* \infty \partial \nabla -> proper <mi>
* grouping { ... } -> <mrow>...</mrow> (transparent)
* \left( ... \right) with ( ) [ ] | and \{ \} -> <mrow><mo>(</mo>...<mo>)</mo></mrow>
Anything UNSUPPORTED (unknown \command) degrades GRACEFULLY: emitted as an html-escaped
<merror><mtext>\name</mtext></merror> and parsing CONTINUES -- never a crash, never malformed
output. tx_render writes the full <math ...>...</math>, NUL-terminates, and returns byte length.
VERIFICATION DOCTRINE: MathML is a STANDARD (non-novel) format -> the implementation is 100%
sovereign here; nx_tex_gate proves the output against hand-verified expected-MathML KATs + a
balanced-tag well-formedness check, plus a 3rd-party structural cross-check WHEN a reference
(latexml/node) is runnable (otherwise flagged PENDING). No overclaiming.
Sovereign: imports only nx_syscalls (sys_mmap). license_tier: ORIGINAL
dependencies 1 imports · 2 importers
imports: nx_syscalls.nx
imported by: nx_math_render_page.nxnx_tex_gate.nx
structs
| 85 | struct Tx |
consts
| 39 | const TX_OK: i64 = 0 |
| 40 | const TX_BAD_INPUT: i64 = 2840 |
| 41 | const TX_TOO_BIG: i64 = 2841 |
| 44 | const TX_OUT_CAP: i64 = 65536 // max MathML bytes for one expression (>> any real formula) |
| 45 | const TX_IN_CAP: i64 = 8192 // max LaTeX source length accepted |
| 46 | const TX_MAX_DEPTH: i64 = 64 // recursion guard (deep nesting degrades, never loops) |
| 47 | const TX_NAME_CAP: i64 = 64 |
| 48 | const TX_LIMB_CAP: i64 = 16384 // per-limit side buffer for big operators |
| 51 | const TX_NUL: i64 = 0 |
| 52 | const TX_SP: i64 = 32 |
| 53 | const TX_DQUOTE: i64 = 34 |
| 54 | const TX_AMP: i64 = 38 |
| 55 | const TX_STAR: i64 = 42 |
| 56 | const TX_PLUS: i64 = 43 |
| 57 | const TX_MINUS: i64 = 45 |
| 58 | const TX_DOT: i64 = 46 |
| 59 | const TX_SLASH: i64 = 47 |
| 60 | const TX_0: i64 = 48 |
| 61 | const TX_9: i64 = 57 |
| 62 | const TX_LT: i64 = 60 |
| 63 | const TX_EQ: i64 = 61 |
| 64 | const TX_GT: i64 = 62 |
| 65 | const TX_UA: i64 = 65 |
| 66 | const TX_UZ: i64 = 90 |
| 67 | const TX_BSLASH: i64 = 92 |
| 68 | const TX_CARET: i64 = 94 |
| 69 | const TX_USCORE: i64 = 95 |
| 70 | const TX_LA: i64 = 97 |
| 71 | const TX_LZ: i64 = 122 |
| 72 | const TX_LBRACE: i64 = 123 |
| 73 | const TX_BAR: i64 = 124 |
| 74 | const TX_RBRACE: i64 = 125 |
| 75 | const TX_LPAREN: i64 = 40 |
| 76 | const TX_RPAREN: i64 = 41 |
| 77 | const TX_LBRACK: i64 = 91 |
| 78 | const TX_RBRACK: i64 = 93 |
functions
| 96 | func tx_emit(t: *Tx, s: *u8) -> i64 |
| 104 | func tx_emit_byte(t: *Tx, b: i64) -> i64 |
| 110 | func tx_is_digit(c: i64) -> i64 { if c >= TX_0 { if c <= TX_9 { return 1 } } return 0 } called by 1: tx_atom |
| 111 | func tx_is_lower(c: i64) -> i64 { if c >= TX_LA { if c <= TX_LZ { return 1 } } return 0 } called by 1: tx_is_alpha |
| 112 | func tx_is_upper(c: i64) -> i64 { if c >= TX_UA { if c <= TX_UZ { return 1 } } return 0 } called by 1: tx_is_alpha |
| 113 | func tx_is_alpha(c: i64) -> i64 |
| 120 | func tx_peek(t: *Tx) -> i64 { if t.pos >= t.n { return 0 } return t.src[t.pos] as i64 } |
| 121 | func tx_adv(t: *Tx) -> i64 { t.pos = t.pos + 1; return 0 } |
| 122 | func tx_skip_sp(t: *Tx) -> i64 |
| 129 | func tx_streq(a: *u8, b: *u8) -> i64 |
| 139 | func tx_setz(dst: *u8, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[i] = s[i]; i = i + 1 } dst[i] = 0 as u8; return 0 } called by 1: tx_op_glyph |
| 142 | func tx_emit_escaped(t: *Tx, c: i64) -> i64 |
| 151 | func tx_merror(t: *Tx, label: *u8) -> i64 |
| 163 | func tx_read_cmd(t: *Tx, buf: *u8, cap: i64) -> i64 |
| 182 | func tx_emit_named(t: *Tx, name: *u8) -> i64 |
| 241 | func tx_op_glyph(name: *u8, b: *u8) -> i64 |
| 256 | func tx_count_top_elems(s: *u8) -> i64 called by 1: tx_group |
| 288 | func tx_group(t: *Tx) -> i64 called by 3: tx_render_group_sidetx_commandtx_atom calls 8: sys_mmaptx_skip_sptx_peektx_atomtx_advtx_expr+2 |
| 320 | func tx_render_group_side(t: *Tx, side: *u8) -> *u8 |
| 340 | func tx_command(t: *Tx) -> i64 |
| 445 | func tx_emit_fence(t: *Tx) -> i64 |
| 471 | func tx_factor(t: *Tx) -> i64 called by 2: tx_exprtx_expr_until_right calls 7: sys_mmaptx_atomtx_skip_sptx_peektx_advtx_render_group_side+1 |
| 523 | func tx_atom(t: *Tx) -> i64 |
| 590 | func tx_expr(t: *Tx) -> i64 |
| 608 | func tx_expr_until_right(t: *Tx) -> i64 |
| 648 | func tx_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } called by 1: tx_render |
| 650 | func tx_render(latex: *u8, out: *u8) -> i64 |
| 670 | func tx_render_inline(latex: *u8, out: *u8) -> i64 |
| 691 | func main() -> i64 |