Skip to content

Commit 23971b6

Browse files
committed
test(WO80/A4): rulings batch 4 — funcall, item algebra, boundary, embedded tests
Empirically pinned against the interpreter, normative as IS-1 v2 sections: - run <stdlib-name> dispatches Stdlib::Functions; run takes NO kwargs (kwargs belong to declared funcall directives — rababa); parse error otherwise - stage-level case directives execute at their rule position on the whole string (downcase-then-sub ordering pinned) - item algebra: any(<chars>) set, any(lo..hi) inclusive range, capture+ref source substitution - boundary is a zero-width word edge (string edges match, mid-word never) - embedded tests are normative data — never executed by transliterate; the verification layer runs them - HAZARD pinned: stray identifiers (incl. unknown run targets) are consumed as parse no-ops — a typo'd map is silently wrong. Ruled tolerable for the legacy corpus; stricter parsing is an IS-1 v2 follow-up gated on a clean 293-map parse across all three compilers
1 parent 7a5e425 commit 23971b6

1 file changed

Lines changed: 132 additions & 0 deletions

File tree

‎spec/isc/semantics_spec.rb‎

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,135 @@ def with_map(name, body)
208208
end
209209
end
210210
end
211+
212+
RSpec.describe "ISC semantics — funcall and stdlib" do
213+
def with_map(name, body)
214+
dir = Dir.mktmpdir
215+
File.write(File.join(dir, name), body)
216+
Interscript.load_path.unshift(dir)
217+
yield
218+
ensure
219+
Interscript.load_path.delete(dir) if dir
220+
end
221+
222+
def system_map(id, body)
223+
<<~ISC
224+
system "TST:xx-Latn:Latn:#{id}" {
225+
metadata { authority_id tst; id #{id}; language iso-639-2:xx; source_script Latn; destination_script Latn }
226+
#{body}
227+
}
228+
ISC
229+
end
230+
231+
it "rules: run <stdlib-name> dispatches the stdlib function" do
232+
with_map("tst-fn-1.isc", system_map(51, "stage main { run downcase }")) do
233+
expect(Interscript.transliterate("tst-fn-1", "AbC")).to eq("abc")
234+
end
235+
end
236+
237+
it "rules: stage-level case directives run at their position, on the whole string" do
238+
with_map("tst-fn-2.isc", system_map(52,
239+
"stage main { downcase parallel { sub { from \"b\" to \"B\" } } }")) do
240+
# downcase applies before the sub (rule order), so b -> B still fires
241+
expect(Interscript.transliterate("tst-fn-2", "AB")).to eq("aB")
242+
end
243+
end
244+
245+
it "rules: run accepts no kwargs — kwargs belong to declared funcall directives (rababa)" do
246+
with_map("tst-fn-3.isc", system_map(53, "stage main { run separate separator: \"-\" }")) do
247+
expect { Interscript.transliterate("tst-fn-3", "abc") }
248+
.to raise_error(Interscript::Isc::ParseError)
249+
end
250+
end
251+
252+
it "rules: stray identifiers are consumed as no-ops — pinned as a hazard" do
253+
# HAZARD (A4 follow-up): `run nosuchfunction` drops BOTH identifiers
254+
# at parse time and the stage becomes empty — a typo'd map is
255+
# silently wrong. Ruled normative-for-now (legacy .imp corpus
256+
# tolerance, grammar/concerns/stages.rb comment_item); the stricter
257+
# parse is an open item tracked in the IS-1 v2 text, gated on a
258+
# clean parse of the full 293-map corpus across all three compilers.
259+
with_map("tst-fn-4.isc", system_map(54, "stage main { run nosuchfunction parallel { sub { from \"a\" to \"b\" } } }")) do
260+
expect(Interscript.transliterate("tst-fn-4", "a")).to eq("b")
261+
end
262+
end
263+
end
264+
265+
RSpec.describe "ISC semantics — item algebra and boundary" do
266+
def with_map(name, body)
267+
dir = Dir.mktmpdir
268+
File.write(File.join(dir, name), body)
269+
Interscript.load_path.unshift(dir)
270+
yield
271+
ensure
272+
Interscript.load_path.delete(dir) if dir
273+
end
274+
275+
def system_map(id, body)
276+
<<~ISC
277+
system "TST:xx-Latn:Latn:#{id}" {
278+
metadata { authority_id tst; id #{id}; language iso-639-2:xx; source_script Latn; destination_script Latn }
279+
#{body}
280+
}
281+
ISC
282+
end
283+
284+
it "rules: any(<chars>) is a character set of length 1" do
285+
with_map("tst-item-1.isc", system_map(61,
286+
"stage main { parallel { sub { from any(\"bc\") to \"X\" } } }")) do
287+
expect(Interscript.transliterate("tst-item-1", "abcd")).to eq("aXXd")
288+
end
289+
end
290+
291+
it "rules: any(<lo>..<hi>) is an inclusive codepoint range" do
292+
with_map("tst-item-2.isc", system_map(62,
293+
"stage main { parallel { sub { from any(\"0\"..\"9\") to \"N\" } } }")) do
294+
expect(Interscript.transliterate("tst-item-2", "a7b")).to eq("aNb")
295+
end
296+
end
297+
298+
it "rules: capture + ref substitutes the captured source text" do
299+
with_map("tst-item-3.isc", system_map(63,
300+
"stage main { sequence { sub { from capture(\"a\") + \"b\" to ref(1) + \"Y\" } } }")) do
301+
expect(Interscript.transliterate("tst-item-3", "ab")).to eq("aY")
302+
end
303+
end
304+
305+
it "rules: boundary is a zero-width word-edge, not string-edge-only" do
306+
with_map("tst-item-4.isc", system_map(64,
307+
"stage main { parallel { sub { from \"a\" to \"X\" after boundary } } }")) do
308+
# string end IS a word edge
309+
expect(Interscript.transliterate("tst-item-4", "xa")).to eq("xX")
310+
# mid-word: no edge after a
311+
expect(Interscript.transliterate("tst-item-4", "ab")).to eq("ab")
312+
end
313+
end
314+
end
315+
316+
RSpec.describe "ISC semantics — metadata contract and embedded tests" do
317+
def with_map(name, body)
318+
dir = Dir.mktmpdir
319+
File.write(File.join(dir, name), body)
320+
Interscript.load_path.unshift(dir)
321+
yield
322+
ensure
323+
Interscript.load_path.delete(dir) if dir
324+
end
325+
326+
it "rules: embedded tests are normative data — never executed by transliterate" do
327+
dir = Dir.mktmpdir
328+
File.write(File.join(dir, "tst-test-1.isc"), <<~ISC)
329+
system "TST:xx-Latn:Latn:71" {
330+
metadata { authority_id tst; id 71; language iso-639-2:xx; source_script Latn; destination_script Latn }
331+
stage main { parallel { sub { from "a" to "b" } } }
332+
tests { "zzz" -> "wrong" }
333+
}
334+
ISC
335+
Interscript.load_path.unshift(dir)
336+
# a deliberately wrong expectation does not fire; the verification
337+
# layer (conformance runner / artifact build) executes tests
338+
expect(Interscript.transliterate("tst-test-1", "a")).to eq("b")
339+
ensure
340+
Interscript.load_path.delete(dir) if dir
341+
end
342+
end

0 commit comments

Comments
 (0)