iflaststmt.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. # Copyright (c) 2020, 2022 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 iflaststmt(
  15. self, lhs: str, n: int, rule, tree, tokens: list, first: int, last: int
  16. ) -> bool:
  17. testexpr = tree[0]
  18. # print("XXX", first, last, rule)
  19. # for t in range(first, last): print(tokens[t])
  20. # print("="*40)
  21. if testexpr[0] in ("testtrue", "testfalse"):
  22. test = testexpr[0]
  23. if len(test) > 1 and test[1].kind.startswith("jmp_"):
  24. if last == n:
  25. last -= 1
  26. jmp_target = test[1][0].attr
  27. if tokens[first].off2int() <= jmp_target < tokens[last].off2int():
  28. return True
  29. # jmp_target less than tokens[first] is okay - is to a loop
  30. # jmp_target equal tokens[last] is also okay: normal non-optimized non-loop jump
  31. if (
  32. (last + 1) < n
  33. and tokens[last - 1] != "JUMP_BACK"
  34. and tokens[last + 1] == "COME_FROM_LOOP"
  35. ):
  36. # iflastsmtl is not at the end of a loop, but jumped outside of loop. No good.
  37. # FIXME: check that tokens[last] == "POP_BLOCK"? Or allow for it not to appear?
  38. return True
  39. # If the instruction before "first" is a "POP_JUMP_IF_FALSE" which goes
  40. # to the same target as jmp_target, then this not nested "if .. if .."
  41. # but rather "if ... and ..."
  42. if first > 0 and tokens[first - 1] == "POP_JUMP_IF_FALSE":
  43. return tokens[first - 1].attr == jmp_target
  44. if jmp_target > tokens[last].off2int():
  45. # One more weird case to look out for
  46. # if c1:
  47. # if c2: # Jumps around the *outer* "else"
  48. # ...
  49. # else:
  50. if jmp_target == tokens[last - 1].attr:
  51. return False
  52. if last < n and tokens[last].kind.startswith("JUMP"):
  53. return False
  54. return True
  55. pass
  56. return False