Ports the parser, tokenizer and control-flow part of the Octoscript
makepad-script patch set (PATCHES.md, grammar v0.2) onto the September
`work` revision, by hand, area by area.
Decisions per PATCHES.md item:
1. Logical/comparison precedence, streaming, `!`: ADAPT. Upstream already
patches a pending ShortCircuitEnd during auto-close but forgot the
operator: ShortCircuitEnd now retains `what_op` so a tighter logical
operator keeps a looser left jump open (`a || b && c`), the checkpoint
restores the original TEST opcodes on continuation, comparisons (14)
bind tighter than equality (15), and NOT always negates truth
conversion instead of doing a bitwise NOT on f64-stored numbers.
Upstream's `last_jump_target` bookkeeping is kept at every patch site.
2. Canonical `try protected catch fallback`: PORT. `catch` is a one-shot
contextual separator carried in TryErrBlockOrExpr checkpoint state
(allow_catch/canonical_catch/protected_was_block); block branches keep
their tail value by removing the inherited pop-to-me marker before
recomputing the jump; TRY_ERR now uses its encoded relative distance
and the parser adds the extra TRY_OK skip only when legacy `ok`
follows. Legacy catch-less `try a b [ok c]` still parses (the checker
in Octoscript's own crates restricts it to the compatibility entry).
3. Cross-call unwinding: PORT. handle_errors searches all call frames
(call_stack_has_try), pops younger script calls restoring slot_base
and the return ip's body, then applies the try-frame cleanup/jump.
Hard bails stay on ScriptTrapOn::Bail.
4. Loop back-edges: ADAPT onto upstream's reset_iteration_scope fast
path: truncate_loop_iteration_bases discards iteration-local tries,
operand values and mes before the scope reset; plain loop/while keep
their iteration scope and free nested ones. Hard time-budget bails
drain their diagnostic; OK_END with no try frame bails.
5. Field-assignment reverse-pair walk: PORT (stop at a 1-opcode chunk).
6. Prototype-field `:` rewrite: PORT (chain must begin with an id,
paired insert through insert_code_with_source keeps opcode/source-map
lockstep); unavailable rust-value index is a parse error.
7. Numeric-boundary tokenizer: PORT (`_` stays in the pending number
instead of moving to Whitespace with stale text) plus the char-count
token length so a multibyte identifier cannot underflow `pos`.
Tests: inline parser/tokenizer/vm regressions and tests/try_catch.rs
(legacy syntax, block/expression branches, nested and cross-function
recovery, contextual `catch`, checkpoint restoration, loop cleanup,
streaming appends, precedence and effects, tokenizer boundaries).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgSir4cQyaakzPju4h6smw
(cherry picked from commit 8231a13906cfb339b496ff78b687e43a48e4e11b)
(cherry picked from commit a1f7afb543c8a737f9c56936bfcba605097f88df)