diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index acf2e197ac1..798a7972225 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -1052,15 +1052,15 @@ class EsphomeCore: # Split main_statements at ComponentMarker sentinels into a prefix # (statements emitted before any component) plus per-component groups. - # Each group's first entry is its marker comment, kept separate so - # it can bracket the IIFE rather than be buried inside it. + # Each group carries its component name so cpp_main_section can emit + # begin/end marker comments bracketing the IIFE. prefix: list[str] = [] components: list[tuple[str, list[str]]] = [] current = prefix for exp in self.main_statements: if isinstance(exp, ComponentMarker): body: list[str] = [] - components.append((str(exp).rstrip(), body)) + components.append((exp.name, body)) current = body continue current.append(str(statement(exp)).rstrip()) @@ -1072,16 +1072,18 @@ class EsphomeCore: # Each component's block is wrapped in IIFE lambdas so its stack # frame is released on return, bounding peak stack during setup(). # Large blocks are sub-split to cap single heavy components (e.g. - # sensor platforms with many filter registrations). The marker - # comment brackets the IIFE on both sides so the generated - # main.cpp is easy to scan by component. + # sensor platforms with many filter registrations). "begin X" and + # "end X" marker comments bracket the IIFE so the generated + # main.cpp is easy to scan by component; a comment-only component + # gets a single "begin X" marker (no IIFE, no end marker). pieces = list(prefix) - for marker, body in components: + for name, body in components: wrapped = _wrap_in_iifes(body, max_statements=50) - pieces.append(marker) + has_iife = any("[]()" in line for line in wrapped) + pieces.append(f"// === begin {name} ===") pieces.extend(wrapped) - if any("[]()" in line for line in wrapped): - pieces.append(marker) + if has_iife: + pieces.append(f"// === end {name} ===") return "\n".join(pieces) + "\n\n" @property diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index d7205d1d8fb..608f55aa0c0 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -436,9 +436,8 @@ class LineComment(Statement): class ComponentMarker(Statement): """Sentinel marker recorded in main_statements when a component's - to_code begins emitting code. Used by cpp_main_section to split - setup() output into per-component chunks, so each component's - stack frame is released on return.""" + to_code begins emitting code. ``cpp_main_section`` consumes these + to bracket each component's IIFE with begin/end comment markers.""" __slots__ = ("name",) @@ -446,7 +445,7 @@ class ComponentMarker(Statement): self.name = name def __str__(self): - return f"// === {self.name} ===" + return f"// === begin {self.name} ===" class ProgmemAssignmentExpression(AssignmentExpression): diff --git a/tests/unit_tests/test_core.py b/tests/unit_tests/test_core.py index dc16d4cfe9c..f23955672de 100644 --- a/tests/unit_tests/test_core.py +++ b/tests/unit_tests/test_core.py @@ -937,7 +937,7 @@ def test_wrap_in_iifes_unbalanced_braces_fall_through() -> None: def test_wrap_in_iifes_skips_comment_only_chunks() -> None: # Components that emit only a ComponentMarker + config dump (no C++ # statements) should not be wrapped in an empty IIFE. - lines = ["// === sha256 ===", "// sha256:", "// {}"] + lines = ["// === begin sha256 ===", "// sha256:", "// {}"] assert core._wrap_in_iifes(lines, max_statements=50) == lines @@ -961,14 +961,16 @@ def test_cpp_main_section_component_marker_wraps_in_iife() -> None: out = target.cpp_main_section assert out.count("[]() {") == 2 assert out.count("}();") == 2 - # Each component's marker brackets its IIFE (once before, once after). - assert out.count("// === logger ===") == 2 - assert out.count("// === wifi ===") == 2 + # Each component's IIFE is bracketed by a begin/end marker pair. + assert "// === begin logger ===" in out + assert "// === end logger ===" in out + assert "// === begin wifi ===" in out + assert "// === end wifi ===" in out def test_cpp_main_section_comment_only_component_emits_single_marker() -> None: # A component that emits no C++ statements (only a ComponentMarker) - # should not grow a useless trailing duplicate marker. + # gets only a begin marker — no IIFE, so no end marker. target = core.EsphomeCore() target.main_statements = [ ComponentMarker("sha256"), @@ -976,8 +978,10 @@ def test_cpp_main_section_comment_only_component_emits_single_marker() -> None: RawStatement("new_wifi();"), ] out = target.cpp_main_section - assert out.count("// === sha256 ===") == 1 - assert out.count("// === wifi ===") == 2 # wifi has an IIFE + assert "// === begin sha256 ===" in out + assert "// === end sha256 ===" not in out + assert "// === begin wifi ===" in out + assert "// === end wifi ===" in out def test_cpp_main_section_prefix_statements_stay_outside_iife() -> None: