lf-lang / lingua-franca

Intuitive concurrent programming in any language
https://www.lf-lang.org
Other
240 stars 63 forks source link

Indentation in Python can cause unfriendly errors #2055

Open edwardalee opened 1 year ago

edwardalee commented 1 year ago

It may not be worth much effort to fix this, but the following program generates Python that will not execute:

target Python
main reactor {
  reaction(startup) {=
    # comment
        print("Hello world");
  =}
}

The problem is that the comment is indented less than the code in the reaction body, which is apparently allowed in Python, but the code generator appends a return 0 statement to the generated reaction body, which looks like this:

    def reaction_function_0(self):

        # comment
            print("Hello world");
        return 0

It's not clear to me why a return value is needed for reactions in the Python target. This seems problematic anyway. The following code works correctly without any return value having been specified:

target Python
main reactor {
  state s = 0
  timer t(0, 1s)
  reaction(t) {=
    self.s += 1
    if (self.s % 2 == 0):
      print("odd")
      return
    print("even")
  =}
}

Maybe the return statement is not needed? If this is the case, it could just be removed from generatePythonFunction in PythonReactionGenerator.java.

edwardalee commented 1 year ago

It seems the reason for this generated return statement is that Python does not tolerate empty reaction bodies. The generatePythonFunction method in PythonReactionGenerator.java could be changed to read something like this:

  public static String generatePythonFunction(
      String pythonFunctionName,
      String inits,
      String reactionBody,
      List<String> reactionParameters) {
    String params =
        reactionParameters.size() > 0 ? ", " + String.join(", ", reactionParameters) : "";
    CodeBuilder code = new CodeBuilder();
    code.pr("def " + pythonFunctionName + "(self" + params + "):");
    code.indent();
    code.pr(inits);
    code.pr(reactionBody);
    if (isEmptyOrCommentsOnly(initia) && isEmptyOrCommentsOnly(reactionBody)) {
      // Python does not tolerate an empty reaction body nor one with just comments.
      code.pr("return");
    }
    return code.toString();
  }

However, the isEmptyOrCommentsOnly method would have to be written and tests would need to be added.