From 034cd8f2fcec1c2557a83e0380a39aa6921680a5 Mon Sep 17 00:00:00 2001 From: Ronald Tse Date: Tue, 27 Oct 2026 06:51:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(A4):=20adopt=20the=20strict=20parse=20?= =?UTF-8?q?=E2=80=94=20stray=20identifiers=20are=20a=20parse=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The batch-4 hazard (stray identifiers silently no-op — a typo'd map is silently wrong) is closed: the corpus gate passed (295/295 strict-clean after maps#207's stray-'s' fix), so comment_item no longer consumes bare identifiers. The batch-4/5 vectors flip accordingly: - stray identifiers now raise Isc::ParseError (was: silent no-op) - is likewise rejected — the strict parse revealed it only ever executed by accident (noop + the case directive). The sanctioned spelling is the bare stage directive, which the vector now pins. Also fixes the run_rule documentation gap: stdlib functions are stage directives, never run targets. --- .../isc/grammar/concerns/stages.rb | 7 ++--- spec/isc/semantics_spec.rb | 26 ++++++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/lib/interscript/isc/grammar/concerns/stages.rb b/lib/interscript/isc/grammar/concerns/stages.rb index 70844407..32a90a3f 100644 --- a/lib/interscript/isc/grammar/concerns/stages.rb +++ b/lib/interscript/isc/grammar/concerns/stages.rb @@ -25,10 +25,11 @@ module Stages whitespace? end - # Comments and stray identifiers are silently consumed. + # Comments are consumed; stray identifiers are a parse error + # (WO87/A4 strict-parse ruling: the corpus is 295/295 strict-clean, + # so a typo'd map can no longer silently no-op). rule(:comment_item) do - (str("#") >> (str("\n").absent? >> any).repeat).as(:comment) | - identifier.as(:noop) + (str("#") >> (str("\n").absent? >> any).repeat).as(:comment) end # Bare rule directly in a stage body (not wrapped in sequence/parallel). diff --git a/spec/isc/semantics_spec.rb b/spec/isc/semantics_spec.rb index 613e8e5c..2c1bc4fa 100644 --- a/spec/isc/semantics_spec.rb +++ b/spec/isc/semantics_spec.rb @@ -228,10 +228,17 @@ def system_map(id, body) ISC end - it "rules: run dispatches the stdlib function" do - with_map("tst-fn-1.isc", system_map(51, "stage main { run downcase }")) do + it "rules: stdlib string functions are stage DIRECTIVES (downcase), not run targets" do + # The strict parse revealed `run downcase` only ever worked by + # accident (noop + case-directive). The sanctioned spelling is the + # bare directive. + with_map("tst-fn-1.isc", system_map(51, "stage main { downcase }")) do expect(Interscript.transliterate("tst-fn-1", "AbC")).to eq("abc") end + with_map("tst-fn-1b.isc", system_map(51, "stage main { run downcase }")) do + expect { Interscript.transliterate("tst-fn-1b", "AbC") } + .to raise_error(Interscript::Isc::ParseError) + end end it "rules: stage-level case directives run at their position, on the whole string" do @@ -249,15 +256,14 @@ def system_map(id, body) end end - it "rules: stray identifiers are consumed as no-ops — pinned as a hazard" do - # HAZARD (A4 follow-up): `run nosuchfunction` drops BOTH identifiers - # at parse time and the stage becomes empty — a typo'd map is - # silently wrong. Ruled normative-for-now (legacy .imp corpus - # tolerance, grammar/concerns/stages.rb comment_item); the stricter - # parse is an open item tracked in the IS-1 v2 text, gated on a - # clean parse of the full 293-map corpus across all three compilers. + it "rules: stray identifiers are a PARSE ERROR (the strict-parse ruling, A4 adopted)" do + # The batch-4 hazard (silent no-op) is CLOSED: the corpus gate + # passed (295/295 strict-clean after the odni-prs stray-'s' fix, + # maps#207), so the grammar rejects stray identifiers — a typo'd + # map fails loudly instead of being silently wrong. with_map("tst-fn-4.isc", system_map(54, "stage main { run nosuchfunction parallel { sub { from \"a\" to \"b\" } } }")) do - expect(Interscript.transliterate("tst-fn-4", "a")).to eq("b") + expect { Interscript.transliterate("tst-fn-4", "a") } + .to raise_error(Interscript::Isc::ParseError) end end end