Map sorting and usecode

This commit is contained in:
MaddoScientisto 2026-03-26 23:12:38 +01:00
commit af5b77ea13
7 changed files with 1497 additions and 39 deletions

View file

@ -2544,6 +2544,110 @@ def render_selector_chain(
return rendered, label_to_index[join_label]
def render_loop_construct(
blocks: list[tuple[str, list[str]]],
label_to_index: dict[str, int],
index: int,
end_index: int,
return_labels: set[str],
active_regions: set[tuple[int, int, tuple[str, ...]]] | None = None,
render_cache: dict[tuple[int, int, tuple[str, ...]], tuple[list[str], bool] | None] | None = None,
) -> tuple[list[str], int] | None:
_, statements = blocks[index]
if not statements:
return None
terminal = parse_terminal_statement(statements[-1])
if terminal is None or terminal.kind != "if":
return None
target_label = terminal.target or ""
target_index = label_to_index.get(target_label)
if target_index is None or target_index <= index or target_index > end_index:
return None
loop_tail_index = last_nonempty_block_index(blocks, index + 1, target_index)
if loop_tail_index is None:
return None
loop_tail_terminal = parse_terminal_statement(blocks[loop_tail_index][1][-1])
if loop_tail_terminal is None or loop_tail_terminal.kind != "goto" or loop_tail_terminal.target != blocks[index][0]:
return None
loop_body = render_structured_region(
blocks,
label_to_index,
index + 1,
target_index,
return_labels,
{blocks[index][0]},
active_regions,
render_cache,
)
if loop_body is None:
return None
loop_lines, _ = loop_body
loop_selector = None
if index > 0 and is_loop_selector_only_block(blocks[index - 1][1]):
loop_selector = parse_loop_selector_statement(blocks[index - 1][1][0])
rendered: list[str] = []
if loop_selector is not None:
rendered.append(f"for {loop_selector} {{")
else:
rendered.append(f"while ({invert_condition_text(terminal.condition or 'condition')}) {{")
rendered.extend(indent_lines(loop_lines))
rendered.append("}")
return rendered, target_index
def render_infinite_loop_construct(
blocks: list[tuple[str, list[str]]],
label_to_index: dict[str, int],
index: int,
end_index: int,
return_labels: set[str],
active_regions: set[tuple[int, int, tuple[str, ...]]] | None = None,
render_cache: dict[tuple[int, int, tuple[str, ...]], tuple[list[str], bool] | None] | None = None,
) -> tuple[list[str], int] | None:
if index + 1 >= end_index:
return None
loop_label = blocks[index][0]
loop_tail_index: int | None = None
for candidate in range(end_index - 1, index, -1):
statements = blocks[candidate][1]
if not statements:
continue
terminal = parse_terminal_statement(statements[-1])
if terminal is not None and terminal.kind == "goto" and terminal.target == loop_label:
loop_tail_index = candidate
break
if loop_tail_index is None:
return None
loop_body = render_structured_region(
blocks,
label_to_index,
index,
loop_tail_index + 1,
return_labels,
{loop_label},
active_regions,
render_cache,
)
if loop_body is None:
return None
loop_lines, _ = loop_body
rendered = ["while (true) {"]
rendered.extend(indent_lines(loop_lines))
rendered.append("}")
return rendered, loop_tail_index + 1
def render_structured_region(
blocks: list[tuple[str, list[str]]],
label_to_index: dict[str, int],
@ -2635,34 +2739,20 @@ def render_structured_region(
index = selector_join_index
continue
if target_index <= end_index:
loop_tail_index = last_nonempty_block_index(blocks, index + 1, target_index)
if loop_tail_index is not None:
loop_tail_terminal = parse_terminal_statement(blocks[loop_tail_index][1][-1])
if loop_tail_terminal is not None and loop_tail_terminal.kind == "goto" and loop_tail_terminal.target == blocks[index][0]:
loop_body = render_structured_region(
blocks,
label_to_index,
index + 1,
target_index,
return_labels,
{blocks[index][0]},
active_regions,
render_cache,
)
if loop_body is not None:
loop_lines, _ = loop_body
loop_selector = None
if index > start_index:
loop_selector = parse_loop_selector_statement(blocks[index - 1][1][0]) if is_loop_selector_only_block(blocks[index - 1][1]) else None
if loop_selector is not None:
lines.append(f"for {loop_selector} {{")
else:
lines.append(f"while ({invert_condition_text(terminal.condition or 'condition')}) {{")
lines.extend(indent_lines(loop_lines))
lines.append("}")
index = target_index
continue
loop_construct = render_loop_construct(
blocks,
label_to_index,
index,
end_index,
return_labels,
active_regions,
render_cache,
)
if loop_construct is not None:
loop_lines, loop_join_index = loop_construct
lines.extend(loop_lines)
index = loop_join_index
continue
true_tail_index = last_nonempty_block_index(blocks, index + 1, target_index)
if true_tail_index is not None:
@ -2817,6 +2907,38 @@ def render_partially_structured_blocks(blocks: list[tuple[str, list[str]]]) -> l
index = selector_join_index
continue
loop_construct = render_loop_construct(
blocks,
label_to_index,
index,
len(blocks),
return_labels,
)
if loop_construct is not None:
loop_lines, loop_join_index = loop_construct
lines.append(f" {label}:")
for statement in loop_lines:
lines.append(f" {statement}" if statement else "")
lines.append("")
index = loop_join_index
continue
infinite_loop_construct = render_infinite_loop_construct(
blocks,
label_to_index,
index,
len(blocks),
return_labels,
)
if infinite_loop_construct is not None:
loop_lines, loop_join_index = infinite_loop_construct
lines.append(f" {label}:")
for statement in loop_lines:
lines.append(f" {statement}" if statement else "")
lines.append("")
index = loop_join_index
continue
lines.append(f" {label}:")
for statement in statements:
lines.append(f" {statement}")
@ -2855,6 +2977,47 @@ def render_pseudocode(ir: dict[str, Any], shape_catalog: ShapeCatalog | None = N
return apply_shape_catalog_to_pseudocode("\n".join(lines) + "\n", shape_catalog)
def validate_pseudocode_text(text: str) -> list[str]:
errors: list[str] = []
label_lines: dict[str, int] = {}
goto_targets: list[tuple[str, int]] = []
brace_depth = 0
for line_number, raw_line in enumerate(text.splitlines(), start=1):
stripped = raw_line.strip()
if not stripped:
continue
if stripped.endswith("{"):
brace_depth += 1
if stripped == "}":
brace_depth -= 1
if brace_depth < 0:
errors.append(f"line {line_number}: unexpected closing brace")
brace_depth = 0
label_match = re.fullmatch(r"([A-Za-z_][A-Za-z0-9_]*):", stripped)
if label_match is not None:
label = label_match.group(1)
previous_line = label_lines.get(label)
if previous_line is not None:
errors.append(f"line {line_number}: duplicate label {label} (first at line {previous_line})")
else:
label_lines[label] = line_number
for match in re.finditer(r"\bgoto ([A-Za-z_][A-Za-z0-9_]*)\s*;", stripped):
goto_targets.append((match.group(1), line_number))
if brace_depth != 0:
errors.append(f"unbalanced braces: final depth {brace_depth}")
for target, line_number in goto_targets:
if target not in label_lines:
errors.append(f"line {line_number}: goto target {target} has no label")
return errors
def render_text(ir: dict[str, Any]) -> str:
labels = build_listing_labels(ir)