From 098cd2a6d3edc1725d4ce47d491e049ae729aef5 Mon Sep 17 00:00:00 2001 From: Ronald Tse Date: Thu, 1 Oct 2026 06:12:32 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20normalize=20capture-free=20blocks=20to?= =?UTF-8?q?=20empty=20arrays=20=E2=80=94=20the=20gate=20hits=20289/289?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The grammar consumes comments as whitespace, so a comment-only or empty parallel/sequence body matches zero rule lines and .as folds the capture-free block to a raw slice. The artifact's empty capture is an array; the Normalizer now folds raw block values the same way. Differential tree gate: 289/289 corpus maps byte-identical through the .parg artifact (un-mar included via the bare-\\U accommodation). --- lib/interscript/isc/normalizer.rb | 16 +++++++++++++++- spec/interscript/isc/node_adapter_spec.rb | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/lib/interscript/isc/normalizer.rb b/lib/interscript/isc/normalizer.rb index 8fe2dc71..a79bef04 100644 --- a/lib/interscript/isc/normalizer.rb +++ b/lib/interscript/isc/normalizer.rb @@ -64,7 +64,7 @@ def normalize_block(block) elsif block.key?(:tests) {tests: merge_tests(Array(block[:tests]))} elsif block.key?(:stage) - {stage_name: scalar(block[:stage_name]), stage: block[:stage]} + {stage_name: scalar(block[:stage_name]), stage: normalize_stage_items(block[:stage])} elsif block.key?(:target) {target: scalar(block[:target]), alias: scalar(block[:alias])}.compact else @@ -72,6 +72,20 @@ def normalize_block(block) end end + # A capture-free block (empty or comment-only body — comments are + # consumed as whitespace) folds to a raw slice under .as; the .parg + # artifact's empty capture is an array. Match it. + def normalize_stage_items(items) + Array(items).map do |item| + if item.is_a?(Hash) + %i[parallel sequence].each do |k| + item = {k => []} if item.key?(k) && !item[k].is_a?(Array) + end + end + item + end + end + # {field_name: {identifier: "authority"}, field_value: {string: [...]}} # becomes {authority: "BGN-PCGN"}. def normalize_meta_field(field) diff --git a/spec/interscript/isc/node_adapter_spec.rb b/spec/interscript/isc/node_adapter_spec.rb index bbc16731..c5886a60 100644 --- a/spec/interscript/isc/node_adapter_spec.rb +++ b/spec/interscript/isc/node_adapter_spec.rb @@ -421,3 +421,24 @@ def parse_and_adapt(src) expect(interp.call("чч")).to eq("ч") end end + +RSpec.describe "comment-only blocks" do + it "normalize to an empty block, matching the artifact tree" do + src = <<~ISC + system "t:a-b:C-D:1" { + metadata { name "T" } + stage main { + parallel { + # This is a comment + } + } + } + ISC + tree = Interscript::Isc::Parser.parse(src) + stage = tree[:system][:body].find { |b| b.is_a?(Hash) && b[:stage] }[:stage] + # The grammar consumes comments as whitespace; a capture-free block + # folds to a raw slice that must normalize to an empty array like + # the .parg artifact's empty capture. + expect(stage).to eq([{parallel: []}]) + end +end