check_ast.py 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. # Copyright (c) 2019 Rocky Bernstein
  2. #
  3. # This program is free software: you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation, either version 3 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. """
  16. Python parse tree checker.
  17. Our rules sometimes give erroneous results. Until we have perfect rules,
  18. This checker will catch mistakes in decompilation we've made.
  19. FIXME idea: extend parsing system to do same kinds of checks or nonterminal
  20. before reduction and don't reduce when there is a problem.
  21. """
  22. def checker(ast, in_loop: bool, errors) -> None:
  23. if ast is None:
  24. return
  25. in_loop = (
  26. in_loop
  27. or ast.kind.startswith("while")
  28. or ast.kind.startswith("async_for")
  29. or ast.kind.startswith("for")
  30. )
  31. if ast.kind in ("aug_assign1", "aug_assign2") and ast[0][0] == "and":
  32. text = str(ast)
  33. error_text = (
  34. "\n# improper augmented assignment (e.g. +=, *=, ...):\n#\t"
  35. + "\n# ".join(text.split("\n"))
  36. + "\n"
  37. )
  38. errors.append(error_text)
  39. for node in ast:
  40. if not in_loop and node.kind in ("continue", "break"):
  41. text = str(node)
  42. error_text = "\n# not in loop:\n#\t" + "\n# ".join(text.split("\n"))
  43. errors.append(error_text)
  44. if hasattr(node, "__repr1__"):
  45. checker(node, in_loop, errors)