1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-02 19:32:19 +01:00

codegen: Lambda improvements (#1476)

* Use #line directives in generated C++ code for lambdas

The #line directive in gcc is meant specifically for pieces of imported
code included in generated code, exactly what happens with lambdas in
the yaml files: https://gcc.gnu.org/onlinedocs/cpp/Line-Control.html

With this change, if I add the following at line 165 of kithen.yaml:
    - lambda: undefined_var == 5;

then "$ esphome kitchen.yaml compile" shows the following:

INFO Reading configuration kitchen.yaml...
INFO Generating C++ source...
INFO Compiling app...
INFO Running:  platformio run -d kitchen
<...>
Compiling .pioenvs/kitchen/src/main.cpp.o
kitchen.yaml: In lambda function:
kitchen.yaml:165:7: error: 'undefined_var' was not declared in this scope
*** [.pioenvs/kitchen/src/main.cpp.o] Error 1
== [FAILED] Took 2.37 seconds ==

* Silence gcc warning on multiline macros in lambdas

When the \ is used at the end of the C++ source in a lambda (line
continuation, often used in preprocessor macros), esphome will copy that
into main.cpp once as code and once as a // commment.  gcc will complain
about the multiline commment:

Compiling .pioenvs/kitchen/src/main.cpp.o
kitchen.yaml:640:3: warning: multi-line comment [-Wcomment]

Try to replace the \ with a "<cont>" for lack of a better idea.
This commit is contained in:
Andrew Zaborowski
2021-01-24 00:17:15 +01:00
committed by GitHub
parent 52c67d715b
commit c7c71089ce
4 changed files with 48 additions and 10 deletions

View File

@@ -1,6 +1,7 @@
import abc
import inspect
import math
import re
# pylint: disable=unused-import, wrong-import-order
from typing import Any, Generator, List, Optional, Tuple, Type, Union, Sequence
@@ -188,13 +189,14 @@ class ParameterListExpression(Expression):
class LambdaExpression(Expression):
__slots__ = ("parts", "parameters", "capture", "return_type")
__slots__ = ("parts", "parameters", "capture", "return_type", "source")
def __init__(self, parts, parameters, capture: str = '=', return_type=None):
def __init__(self, parts, parameters, capture: str = '=', return_type=None, source=None):
self.parts = parts
if not isinstance(parameters, ParameterListExpression):
parameters = ParameterListExpression(*parameters)
self.parameters = parameters
self.source = source
self.capture = capture
self.return_type = safe_exp(return_type) if return_type is not None else None
@@ -202,7 +204,10 @@ class LambdaExpression(Expression):
cpp = f'[{self.capture}]({self.parameters})'
if self.return_type is not None:
cpp += f' -> {self.return_type}'
cpp += f' {{\n{self.content}\n}}'
cpp += ' {\n'
if self.source is not None:
cpp += f'{self.source.as_line_directive}\n'
cpp += f'{self.content}\n}}'
return indent_all_but_first_and_last(cpp)
@property
@@ -360,7 +365,7 @@ class LineComment(Statement):
self.value = value
def __str__(self):
parts = self.value.split('\n')
parts = re.sub(r'\\\s*\n', r'<cont>\n', self.value, re.MULTILINE).split('\n')
parts = [f'// {x}' for x in parts]
return '\n'.join(parts)
@@ -555,7 +560,7 @@ def process_lambda(
else:
parts[i * 3 + 1] = var
parts[i * 3 + 2] = ''
yield LambdaExpression(parts, parameters, capture, return_type)
yield LambdaExpression(parts, parameters, capture, return_type, value.source_location)
def is_template(value):