This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

82 lines
2.0 KiB

  1. """
  2. Compile Python to Bytecode
  3. ==========================
  4. A toy example that compiles Python directly to bytecode, without generating an AST.
  5. It currently only works for very very simple Python code.
  6. It requires the 'bytecode' library. You can get it using
  7. ::
  8. $ pip install bytecode
  9. """
  10. from lark import Lark, Transformer, v_args
  11. from lark.indenter import Indenter
  12. from bytecode import Instr, Bytecode
  13. class PythonIndenter(Indenter):
  14. NL_type = '_NEWLINE'
  15. OPEN_PAREN_types = ['LPAR', 'LSQB', 'LBRACE']
  16. CLOSE_PAREN_types = ['RPAR', 'RSQB', 'RBRACE']
  17. INDENT_type = '_INDENT'
  18. DEDENT_type = '_DEDENT'
  19. tab_len = 8
  20. @v_args(inline=True)
  21. class Compile(Transformer):
  22. def number(self, n):
  23. return [Instr('LOAD_CONST', int(n))]
  24. def string(self, s):
  25. return [Instr('LOAD_CONST', s[1:-1])]
  26. def var(self, n):
  27. return [Instr('LOAD_NAME', n)]
  28. def arith_expr(self, a, op, b):
  29. # TODO support chain arithmetic
  30. assert op == '+'
  31. return a + b + [Instr('BINARY_ADD')]
  32. def arguments(self, args):
  33. return args
  34. def funccall(self, name, args):
  35. return name + args + [Instr('CALL_FUNCTION', 1)]
  36. @v_args(inline=False)
  37. def file_input(self, stmts):
  38. return sum(stmts, []) + [Instr("RETURN_VALUE")]
  39. def expr_stmt(self, lval, rval):
  40. # TODO more complicated than that
  41. name ,= lval
  42. assert name.name == 'LOAD_NAME' # XXX avoid with another layer of abstraction
  43. return rval + [Instr("STORE_NAME", name.arg)]
  44. def __default__(self, *args):
  45. assert False, args
  46. python_parser3 = Lark.open('python3.lark', rel_to=__file__, start='file_input',
  47. parser='lalr', postlex=PythonIndenter(),
  48. transformer=Compile(), propagate_positions=False)
  49. def compile_python(s):
  50. insts = python_parser3.parse(s+"\n")
  51. return Bytecode(insts).to_code()
  52. code = compile_python("""
  53. a = 3
  54. b = 5
  55. print("Hello World!")
  56. print(a+(b+2))
  57. print((a+b)+2)
  58. """)
  59. exec(code)
  60. # -- Output --
  61. # Hello World!
  62. # 10
  63. # 10