Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gitgalaxy/tools/cobol_to_java/det/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class Item:
conditions: list = field(default_factory=list) # its 88s
parent: Item | None = None
line: int = 0
storage_alias: str | None = None # #4767: the storage name of a repeated 01 FILLER (nothing can name it)
# computed
offset: int = 0 # within its 01 record
size: int = 0 # one occurrence
Expand Down
9 changes: 8 additions & 1 deletion gitgalaxy/tools/cobol_to_java/det/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -812,11 +812,18 @@ def callee_types(cls: str) -> list[str]:
# fields (after the paragraphs: gen.ids is complete from the start; the constants come from the statements)
storages: list[tuple[str, str]] = []
seen = set()
fillers = 0
for rec in records:
r = roots[id(rec)]
if id(r) in seen or id(r) in gen.lifted: # a lifted item is a typed field, not storage
continue
seen.add(id(r))
if r.name.upper() == "FILLER" and r.section != "FILE":
# #4767 (zECS ZECS001 declares `01 FILLER.` four times): no reference can name a FILLER, so unlike a repeated
# real name nothing is ambiguous -- each group's named children are reached through their own storage
fillers += 1
if fillers > 1:
r.storage_alias = f"FILLER_{r.line}"
img = L.image(r) if r.section != "FILE" else b" " * sizes[id(r)]
img = img.ljust(sizes[id(r)], b"\x00" if r.section != "FILE" else b" ")
name = _storage_name(r)
Expand Down Expand Up @@ -1303,7 +1310,7 @@ def sync_code(gen: G.Gen, records: list, roots: dict) -> list[str]:


def _storage_name(rec: L.Item) -> str:
return "s_" + G.jname(rec.name)
return "s_" + G.jname(rec.storage_alias or rec.name)


def _cics_parts(gen: G.Gen, records: list, roots: dict, proc: S.Procedure,
Expand Down
31 changes: 31 additions & 0 deletions tests/cobol_mainframe/test_det_programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1926,3 +1926,34 @@ def translate(data: list[str]) -> str:
assert java.count("Storage s_D ") == 1, java
with pytest.raises(ValueError, match="second 01 group named D"):
translate(["01 X PIC X(3) VALUE 'abc'.", "01 D PIC 9.", "01 D.", " 05 D1 PIC 9."])


def test_repeated_01_filler_groups_each_get_their_own_storage(tmp_path):
"""#4767: zECS ZECS001 declares `01 FILLER.` four times, each with named children. Nothing can name a FILLER, so no
reference is ambiguous (unlike a repeated real name): each group keeps its own storage and its children bind to it.
The first keeps `s_FILLER` (ports of programs with one `01 FILLER` do not move)."""
pytest.importorskip("tree_sitter_language_pack")
from gitgalaxy.tools.cobol_to_java.det import program as P

src = tmp_path / "t"
src.mkdir()
(src / "FILX.cbl").write_text(
program(
"FILX",
[
"01 FILLER.",
" 05 A PIC X(3) VALUE 'abc'.",
"01 FILLER.",
" 05 B PIC X(3) VALUE 'xyz'.",
"01 FILLER.",
" 05 C PIC 9(2) VALUE 7.",
],
["DISPLAY A B C"],
) # fmt: skip
)
(src / "project").mkdir()
java = P.translate(src / "FILX.cbl", [], "public class FilxService {\n}\n", PKG, None, src / "project").java
assert java.count("Storage s_FILLER ") == 1, java
assert java.count("Storage s_FILLER_") == 2, java
if _java() is not None: # the port compiles and each group's children read their own bytes
assert _java_run("FILX", (src / "FILX.cbl").read_text(), tmp_path) == "abcxyz07\n"
Loading