Commit graph

1 commit

Author SHA1 Message Date
ymote
2f9565e08a script: port Octoscript parser/tokenizer/control-flow VM patches (ws2)
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)
2026-09-23 22:34:43 +02:00