whileTruestmt38.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. # Copyright (c) 2022-2023 Rocky Bernstein
  2. # This program is free software: you can redistribute it and/or modify
  3. # it under the terms of the GNU General Public License as published by
  4. # the Free Software Foundation, either version 3 of the License, or
  5. # (at your option) any later version.
  6. #
  7. # This program is distributed in the hope that it will be useful,
  8. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. # GNU General Public License for more details.
  11. #
  12. # You should have received a copy of the GNU General Public License
  13. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. def whileTruestmt38_check(
  15. self, lhs: str, n: int, rule, tree, tokens: list, first: int, last: int
  16. ) -> bool:
  17. # When we are missing a COME_FROM_LOOP, the
  18. # "while" statement is nested inside an if/else
  19. # so after the POP_BLOCK we have a JUMP_FORWARD which forms the "else" portion of the "if"
  20. # Check this.
  21. # print("XXX", first, last, rule)
  22. # for t in range(first, last): print(tokens[t])
  23. # print("="*40)
  24. if not tokens[last].kind.startswith("COME_FROM") and tokens[
  25. last - 1
  26. ].kind.startswith("COME_FROM"):
  27. last -= 1
  28. while tokens[last].kind.startswith("COME_FROM"):
  29. last -= 1
  30. if rule[-1][-1] == "\\e__come_froms":
  31. jump_loop = tree[-2]
  32. else:
  33. # This might not be needed
  34. jump_loop = tokens[last]
  35. if jump_loop == "JUMP_LOOP":
  36. jump_target = jump_loop.attr
  37. if jump_target < tokens[first].off2int(prefer_last=False):
  38. return True
  39. c_stmts = tree[1]
  40. if c_stmts == "c_stmts":
  41. # Distinguish:
  42. # while True:
  43. # if expr:
  44. # from:
  45. # while expr:
  46. #
  47. # We distinguish by checking to see if the "if expr" jumps *outside* of
  48. # the loop bound.
  49. # First, see if we have "ifstmt" as the first statement inside "while True"
  50. c_stmts_offset = c_stmts.first_child().off2int()
  51. first_stmt = c_stmts[0]
  52. while first_stmt in ("_stmts", "stmts"):
  53. first_stmt = first_stmt[0]
  54. if first_stmt == "ifstmt":
  55. # Next check for a testexpr and get the last instruction of that
  56. testexpr = first_stmt[0]
  57. if testexpr == "testexpr":
  58. pop_jump_if = testexpr.last_child()
  59. # Do we have POP_JUMP_IF with a jump outside of the loop?
  60. if (
  61. pop_jump_if.kind.startswith("POP_JUMP_IF")
  62. and pop_jump_if.attr > tokens[last].off2int()
  63. ):
  64. # Fail here, but we expect a "while expr" pattern to succeed elsewhere.
  65. return True
  66. return c_stmts_offset != jump_target
  67. return False