Skip to content

Commit 27b2393

Browse files
committed
Eliminate redundant closures, merge consequtive writes in pretty printer
1 parent 7033768 commit 27b2393

5 files changed

Lines changed: 2540 additions & 3785 deletions

File tree

meta/src/meta/codegen_base.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,18 @@ def gen_builtin_call(
473473
return spec.generator(args, lines, indent)
474474
return None
475475

476+
# --- Beta reduction hooks ---
477+
478+
def _enter_beta_body(self, lam: Lambda) -> None:
479+
"""Called before evaluating a beta-reduced lambda body.
480+
481+
Subclasses can override to set up type context (e.g., Go's
482+
lambda return type stack for IfElse type hints).
483+
"""
484+
485+
def _exit_beta_body(self, lam: Lambda) -> None:
486+
"""Called after evaluating a beta-reduced lambda body."""
487+
476488
# --- Type-based expression classification ---
477489

478490
@staticmethod
@@ -585,6 +597,24 @@ def _generate_Call(self, expr: Call, lines: list[str], indent: str) -> str | Non
585597
return None
586598
return result.value
587599

600+
# Beta reduction: inline lambda calls instead of emitting closures.
601+
# Call(Lambda([p1, ...], body), [a1, ...]) => assign args to params, eval body.
602+
if isinstance(expr.func, Lambda) and len(expr.func.params) == len(expr.args):
603+
for param, arg in zip(expr.func.params, expr.args):
604+
arg_code = self.generate_lines(arg, lines, indent)
605+
assert arg_code is not None, (
606+
"Function argument should not contain a return"
607+
)
608+
param_name = self.escape_identifier(param.name)
609+
lines.append(
610+
f"{indent}{self.gen_assignment(param_name, arg_code, is_declaration=True)}"
611+
)
612+
self._enter_beta_body(expr.func)
613+
try:
614+
return self.generate_lines(expr.func.body, lines, indent)
615+
finally:
616+
self._exit_beta_body(expr.func)
617+
588618
# Regular call
589619
f = self.generate_lines(expr.func, lines, indent)
590620
assert f is not None, "Function expression should not contain a return"
@@ -886,17 +916,56 @@ def _generate_nil_else_branch(
886916
lines.append(f"{body_indent}{self.gen_assignment(tmp, else_code)}")
887917
return else_code
888918

919+
@staticmethod
920+
def _extract_write_io_literal(expr: TargetExpr) -> str | None:
921+
"""If expr is Call(Builtin("write_io"), [Lit(s)]), return s."""
922+
if (
923+
isinstance(expr, Call)
924+
and isinstance(expr.func, Builtin)
925+
and expr.func.name == "write_io"
926+
and len(expr.args) == 1
927+
and isinstance(expr.args[0], Lit)
928+
and isinstance(expr.args[0].value, str)
929+
):
930+
return expr.args[0].value
931+
return None
932+
933+
def _flush_write_io_literals(
934+
self, strings: list[str], lines: list[str], indent: str
935+
) -> None:
936+
"""Emit a single write_io call for a run of string literals."""
937+
merged = "".join(strings)
938+
merged_str = self.gen_string(merged)
939+
result = self.gen_builtin_call("write_io", [merged_str], lines, indent)
940+
if result is not None:
941+
for stmt in result.statements:
942+
lines.append(f"{indent}{stmt}")
943+
889944
def _generate_Seq(self, expr: Seq, lines: list[str], indent: str) -> str | None:
890945
"""Generate code for a sequence of expressions.
891946
892947
If any expression returns None (indicating a return statement was executed),
893948
stop processing and propagate None (subsequent expressions are unreachable).
949+
950+
Consecutive write_io calls with string literal arguments are merged into
951+
a single call with the concatenated string.
894952
"""
895953
result: str | None = self.gen_none()
954+
pending_writes: list[str] = []
896955
for e in expr.exprs:
956+
write_str = self._extract_write_io_literal(e)
957+
if write_str is not None:
958+
pending_writes.append(write_str)
959+
result = self.gen_none()
960+
continue
961+
if pending_writes:
962+
self._flush_write_io_literals(pending_writes, lines, indent)
963+
pending_writes.clear()
897964
result = self.generate_lines(e, lines, indent)
898965
if result is None:
899966
break
967+
if pending_writes:
968+
self._flush_write_io_literals(pending_writes, lines, indent)
900969
return result
901970

902971
def _generate_While(self, expr: While, lines: list[str], indent: str) -> str:

meta/src/meta/codegen_go.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -392,23 +392,31 @@ def gen_func_def_header(
392392
def gen_func_def_end(self) -> str:
393393
return "}"
394394

395-
def _generate_Lambda(self, expr, lines: list[str], indent: str) -> str:
396-
"""Track lambda return type for IfElse type hint inference."""
395+
def _lambda_ret_type_str(self, expr) -> str | None:
397396
from .target import Lambda
398397

399398
assert isinstance(expr, Lambda)
400-
ret_type = (
399+
return (
401400
self.gen_type(expr.return_type)
402401
if expr.return_type and not self._is_void_type(expr.return_type)
403402
else None
404403
)
405-
self._lambda_return_type_stack.append(ret_type)
404+
405+
def _generate_Lambda(self, expr, lines: list[str], indent: str) -> str:
406+
"""Track lambda return type for IfElse type hint inference."""
407+
self._lambda_return_type_stack.append(self._lambda_ret_type_str(expr))
406408
try:
407409
result = super()._generate_Lambda(expr, lines, indent)
408410
finally:
409411
self._lambda_return_type_stack.pop()
410412
return result
411413

414+
def _enter_beta_body(self, lam) -> None:
415+
self._lambda_return_type_stack.append(self._lambda_ret_type_str(lam))
416+
417+
def _exit_beta_body(self, lam) -> None:
418+
self._lambda_return_type_stack.pop()
419+
412420
def _ifelse_type_hint(self, expr) -> str | None:
413421
"""Improve IfElse type hint when the overall type resolves to interface{}.
414422

0 commit comments

Comments
 (0)