Skip to content

Commit

Permalink
Produce Python AST for require statements
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonwillard committed Sep 25, 2018
1 parent d2319dc commit dde28d7
Show file tree
Hide file tree
Showing 15 changed files with 498 additions and 303 deletions.
1 change: 1 addition & 0 deletions hy/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import __builtin__ as builtins
except ImportError:
import builtins # NOQA

import sys, keyword

PY3 = sys.version_info[0] >= 3
Expand Down
57 changes: 35 additions & 22 deletions hy/cmdline.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Copyright 2018 the authors.
# This file is part of Hy, which is free software licensed under the Expat
# license. See the LICENSE.

from __future__ import print_function
from __future__ import absolute_import, print_function

import argparse
import code
Expand All @@ -13,6 +12,7 @@
import importlib
import py_compile
import runpy
import types

import astor.code_gen

Expand Down Expand Up @@ -47,10 +47,12 @@ def __call__(self, code=None):
builtins.exit = HyQuitter('exit')


class HyREPL(code.InteractiveConsole):
class HyREPL(code.InteractiveConsole, object):
def __init__(self, spy=False, output_fn=None, locals=None,
filename="<input>"):

super(HyREPL, self).__init__(locals=locals, filename=filename)

self.spy = spy

if output_fn is None:
Expand All @@ -65,13 +67,24 @@ def __init__(self, spy=False, output_fn=None, locals=None,
else:
self.output_fn = __builtins__[mangle(output_fn)]

code.InteractiveConsole.__init__(self, locals=locals,
filename=filename)

# Pre-mangle symbols for repl recent results: *1, *2, *3
self._repl_results_symbols = [mangle("*{}".format(i + 1)) for i in range(3)]
self.locals.update({sym: None for sym in self._repl_results_symbols})

# Create a proper module for this REPL so that we can obtain it easily
# (e.g. using `importlib.import_module`), have it be distinct from
# `__main__`, and use it with `hy_compile`.
module_name = self.locals['__name__']
self.module = types.ModuleType(module_name)
self.module.__dict__.update(self.locals)

self.locals = self.module.__dict__

sys.modules[module_name] = self.module

# Load cmdline-specific macros.
require('hy.cmdline', '__console__', assignments='ALL')

def runsource(self, source, filename='<input>', symbol='single'):
global SIMPLE_TRACEBACKS

Expand Down Expand Up @@ -102,8 +115,7 @@ def ast_callback(main_ast, expr_ast):
new_ast = ast.Module(main_ast.body +
[ast.Expr(expr_ast.body)])
print(astor.to_source(new_ast))
value = hy_eval(do, self.locals, "__console__",
ast_callback)
value = hy_eval(do, self.locals, self.module, ast_callback)
except HyTypeError as e:
if e.source is None:
e.source = source
Expand Down Expand Up @@ -181,7 +193,7 @@ def ideas_macro(ETname):
""")])

require("hy.cmdline", "__console__", assignments="ALL")

require("hy.cmdline", "__main__", assignments="ALL")

SIMPLE_TRACEBACKS = True
Expand All @@ -199,7 +211,8 @@ def pretty_error(func, *args, **kw):

def run_command(source):
tree = hy_parse(source)
pretty_error(hy_eval, tree, module_name="__main__")
module = importlib.import_module('__main__')
pretty_error(hy_eval, tree, None, module)
return 0


Expand All @@ -208,12 +221,12 @@ def run_repl(hr=None, **kwargs):
sys.ps1 = "=> "
sys.ps2 = "... "

namespace = {'__name__': '__console__', '__doc__': ''}
if not hr:
hr = HyREPL(**kwargs)

with completion(Completer(namespace)):
namespace = hr.locals

if not hr:
hr = HyREPL(locals=namespace, **kwargs)
with completion(Completer(namespace)):

hr.interact("{appname} {version} using "
"{py}({build}) {pyversion} on {os}".format(
Expand Down Expand Up @@ -363,8 +376,8 @@ def cmdline_handler(scriptname, argv):
return run_repl(spy=options.spy, output_fn=options.repl_output_fn)


# entry point for cmd line script "hy"
def hy_main():
"""Entry point for cmd line script `hy`"""
sys.path.insert(0, "")
sys.exit(cmdline_handler("hy", sys.argv))

Expand Down Expand Up @@ -406,10 +419,9 @@ def hyc_main():
return rv


# entry point for cmd line script "hy2py"
def hy2py_main():
"""Entry point for cmd line script `hy2py`"""
import platform
module_name = "<STDIN>"

options = dict(prog="hy2py", usage="%(prog)s [options] [FILE]",
formatter_class=argparse.RawDescriptionHelpFormatter)
Expand Down Expand Up @@ -448,7 +460,7 @@ def hy2py_main():
print()
print()

_ast = pretty_error(hy_compile, hst, module_name)
_ast = pretty_error(hy_compile, hst, '__main__')
if options.with_ast:
if PY3 and platform.system() == "Windows":
_print_for_windows(astor.dump_tree(_ast))
Expand All @@ -466,18 +478,19 @@ def hy2py_main():
parser.exit(0)


# need special printing on Windows in case the
# codepage doesn't support utf-8 characters
def _print_for_windows(src):
"""Special printing on Windows needed in case the codepage doesn't support
UTF-8 characters.
"""
for line in src.split("\n"):
try:
print(line)
except:
print(line.encode('utf-8'))

# remove PYTHON* environment variables,
# such as "PYTHONPATH"

def _remove_python_envs():
"""Remove Python environment variables, such as `PYTHONPATH`"""
for key in list(os.environ.keys()):
if key.startswith("PYTHON"):
os.environ.pop(key)
Loading

0 comments on commit dde28d7

Please sign in to comment.