# Source lineage and compatibility decisions ## What was supplied, and what was not `original/PROVENANCE.md` describes the preserved handoff text and its extraction. The historical sources supplied were `original/script.cpp` and `original/vanilla1.cpp`; the original `script.h`, `vstdlib.h`, Windows DLLs, and CGI `Webio` implementation were **not** supplied. Historical buildability, intended header layouts, and behavior of missing external components cannot be independently established from those two files. The restoration was grounded directly in both C++ sources. It is a source-informed reimplementation, not a binary-compatible port or an exact execution oracle for undefined behavior. `original/` is not compiled and was not edited. ## Recognizable model retained - `vScript`: source loading, function registry, command dispatch, execution-wide state. - `vFunc`: function name, declared argument count, ordered code lines. - `CodeLine`: token sequence, now also source location and validated control-flow links. - `variable`: named local values, now owned strings/arrays rather than manual character buffers. - `Load` and `Run`, `function ...` / `kill ...`, and the old command vocabulary remain recognizable. `restored/script.h` is a **newly reconstructed interface**, explicitly labeled as such. It consolidates the required declarations. No fictitious recovered `vstdlib.h` is claimed: helper declarations are now in `script.h`, implementations are in `script.cpp`/`math.cpp`, and DLL-only historical helpers/types are not recreated. The Linux `main` is rewritten in `restored/vanilla1.cpp`. ## Evidence vs decisions Line references below refer to the untouched supplied text, including its blank lines. “Observed” means visible in that source, not proven behavior of a working historical binary. | Area | Observed historical source | Restoration / inference or correction | |---|---|---| | CLI | `vanilla1.cpp:15–43` has `void main`, `run`, then `Load`/`Run`; no-argument path attempts `Webio` and `PATH_TRANSLATED`. | Standard `int main`, checked arguments, help/version/limits. CGI explicitly unavailable; no-argument invocation is a usage error. | | Functions | `script.cpp:472–495` reads `function name argc` until `kill name`; `Run` starts `main` at 504–514. | Same syntax and entry name. Main arity zero, exact call arity, duplicate/reserved names, nesting, and missing kill are now validated. | | Locals | `script.cpp:542–546` creates invocation-local variable vectors. | Per-invocation local map; no global or block-local variable scope. | | Variables | `script_var` at 1084–1090 passes bare declaration names; `setvar` searches names at 161–174. | `var x`, destination `$x`; declaring twice preserves existing value. This idempotent rule is chosen, rather than reproducing duplicate entries or accidental first-match behavior. Undefined variables are errors, not the historical `"(0)"` fallback at 157. | | Set/print | `script_set:1118–1160` concatenates values; `script_print:1306–1365` emits without automatic separators/newlines. | Same concatenation; bounded owned strings. Escape handling is consistently lexical, not only a print-time special case. | | Arguments | `SetArgVales:252–257` uses `atoi(tmp)+1`, while `script_print:1330–1336` uses `atoi(tmp)`; dispatch order/copies complicate substitution. | The inconsistent historical indexing is **not emulated**. `%1` always means first argument, including math and nested/direct calls; `%0` is invalid. This is an explicit normalization, not a claim about missing headers. | | If/loop/do | `Run:635–747` handles `if`, `end if`, pre-test `loop`/`end loop`, and `do`/`while`. | Same readable block syntax; prelinked matching blocks and lexical loop owners replace unbounded scans and unsafe stacks. `else`, `for`, `break`, `continue` are new. | | Labels | `Run:615–633` records `point` when reached and looks it up for `goto`. | Only already visited points, per invocation; repeated points overwrite safely. Same-block restriction is a new safety rule. | | Return/exit | `Run:608–609` returns from function or exits process. | Preserve return-vs-global-exit distinction; scalar return values and `call $dest` are new. | | Includes | `Load:465–468` recursively calls `Load` for includes; `Load:453` also contains a self-call on `vanilla1.v`. | Explicit relative-to-including-file semantics are chosen; canonical-path cycle detection, depth/size limits, checked regular files. The self-recursion bug is not preserved. Includes remain top-level. | | Environment | `script_env:1254–1290` attempts `getenv`/`putenv`, with temporary string lifetime and substitution problems. | Get inherited values safely; set a script-wide bounded overlay. This standard-library-only choice differs from modifying the process environment. Missing keys become empty. | | DLLs | Loader/free/Windows callbacks at 320–328, 380–440, 1168–1252, 1560–1645. | No Windows loader or speculative replacement ABI. `dll`/`dllimport` explicitly fail as unavailable. | | Parser | `ReadLine:771–858` uses fixed buffers, quote counters, and unchecked neighbor indexing. | Entire lexer rewritten, with owned tokens, exact escapes, consistent literal quoting, bounded line/token counts, and errors for malformed input. Quoted reference tokens are now literal. | | Extensions | No supplied code establishes the newly requested APIs. | String/array/file/time/random functions and captured returns are deliberately new; exact syntax is specified in `LANGUAGE.md`, not attributed to history. | ## Math is deliberately corrected The old `mathemu` (`script.cpp:1647–1976`) splits into parallel number/operator vectors and mutates intermediate formulas. Its power pass at 1830–1836 casts to `long`, then repeatedly multiplies; this does not implement general real powers, handles zero/negative exponents incorrectly, and can overflow signed integers. The multiplication/division pass uses changing parallel offsets. Bracket replacement and unary-negative rewriting use fragile buffers and underscore sentinels. Division by zero returns 0 at 1882–1885; integer modulo at 1897 has no zero guard. None of those unsafe/erroneous behaviors are compatibility targets. The new `math.cpp` uses bounded precedence parsing and explicit numeric operands: - `2+3*4` is 14; `24/3*2/4` is 4 (left-associative products). - `2^3^2` is 512 (right-associative power), `7^0` is 1, and `9^0.5` is 3. - Unary minus is lower precedence than power: `-2^2` is -4; negative exponents work. - Binary `%` is defined as floating remainder, not unchecked integer truncation. - Zero division/remainder, nonfinite results, domain errors, malformed expressions, and excessive expression nesting are diagnosed. - Output is no longer the old `%f` six-decimal rendering with trailing-zero stripping; binary64 values are rendered with 17 significant digits for round-tripping. The old condition classifier (`script.cpp:1445–1449`) recognizes only digits and dots, so a leading minus marks a number as a string and can make negative comparisons lexicographic. It also accepts malformed digit/dot patterns. The restoration uses complete finite decimal parsing, including signs and scientific notation: **`-10 < -2` now evaluates true numerically**. If either operand is not a complete finite number, string comparison is still available. ## Ownership and safety components rewritten The supplied text contains raw `new[]`/scalar `delete` mismatches, unchecked buffer sizes, unchecked indices, mutable C-string conversions, leaked operator results, and error paths that exit successfully. Reusing those components would not be a responsible restoration. New components: RAII strings/vectors/maps; bounded lexer and source loader; canonical include-cycle tracking; block linker; safe per-call state; precedence parser; bounded conversions; checked array/string expansion; structured exceptions; CLI validation; test harness and all extensions. Error exit status is now nonzero. See `SAFETY.md` for concrete limits and remaining trust boundaries.