def __call__(self, source, filename="<input>", symbol="single"): if source == 'pass': # We need to return a no-op to signal that no more input is needed. return (compile(source, filename, symbol), ) * 2 hash_digest = hashlib.sha1(source.encode("utf-8").strip()).hexdigest() name = '{}-{}'.format(filename.strip('<>'), hash_digest) try: hy_ast = hy_parse(source, filename=name) except Exception: # Capture a traceback without the compiler/REPL frames. sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info() self._update_exc_info() raise self._cache(source, name) try: hy_ast = hy_parse(source, filename=filename) root_ast = ast.Interactive if symbol == 'single' else ast.Module # Our compiler doesn't correspond to a real, fixed source file, so # we need to [re]set these. self.hy_compiler.filename = filename self.hy_compiler.source = source exec_ast, eval_ast = hy_compile(hy_ast, self.module, root=root_ast, get_expr=True, compiler=self.hy_compiler, filename=filename, source=source, import_stdlib=False) if self.ast_callback: self.ast_callback(exec_ast, eval_ast) exec_code = super(HyCompile, self).__call__(exec_ast, name, symbol) eval_code = super(HyCompile, self).__call__(eval_ast, name, 'eval') except HyLanguageError: # Hy will raise exceptions during compile-time that Python would # raise during run-time (e.g. import errors for `require`). In # order to work gracefully with the Python world, we convert such # Hy errors to code that purposefully reraises those exceptions in # the places where Python code expects them. sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info() self._update_exc_info() exec_code = super(HyCompile, self).__call__( 'import hy._compat; hy._compat.reraise(' '_hy_last_type, _hy_last_value, _hy_last_traceback)', name, symbol) eval_code = super(HyCompile, self).__call__('None', name, 'eval') return exec_code, eval_code
def __call__(self, source, filename="<input>", symbol="single"): if source == 'pass': # We need to return a no-op to signal that no more input is needed. return (compile(source, filename, symbol),) * 2 hash_digest = hashlib.sha1(source.encode("utf-8").strip()).hexdigest() name = '{}-{}'.format(filename.strip('<>'), hash_digest) try: hy_ast = hy_parse(source, filename=name) except Exception: # Capture a traceback without the compiler/REPL frames. sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info() self._update_exc_info() raise self._cache(source, name) try: hy_ast = hy_parse(source, filename=filename) root_ast = ast.Interactive if symbol == 'single' else ast.Module # Our compiler doesn't correspond to a real, fixed source file, so # we need to [re]set these. self.hy_compiler.filename = filename self.hy_compiler.source = source exec_ast, eval_ast = hy_compile(hy_ast, self.module, root=root_ast, get_expr=True, compiler=self.hy_compiler, filename=filename, source=source) if self.ast_callback: self.ast_callback(exec_ast, eval_ast) exec_code = super(HyCompile, self).__call__(exec_ast, name, symbol) eval_code = super(HyCompile, self).__call__(eval_ast, name, 'eval') except HyLanguageError: # Hy will raise exceptions during compile-time that Python would # raise during run-time (e.g. import errors for `require`). In # order to work gracefully with the Python world, we convert such # Hy errors to code that purposefully reraises those exceptions in # the places where Python code expects them. sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info() self._update_exc_info() exec_code = super(HyCompile, self).__call__( 'import hy._compat; hy._compat.reraise(' '_hy_last_type, _hy_last_value, _hy_last_traceback)', name, symbol) eval_code = super(HyCompile, self).__call__('None', name, 'eval') return exec_code, eval_code
def runsource(self, source, filename='<input>', symbol='single'): global SIMPLE_TRACEBACKS def error_handler(e, use_simple_traceback=False): self.locals[mangle("*e")] = e if use_simple_traceback: print(e, file=sys.stderr) else: self.showtraceback() try: try: do = hy_parse(source) except PrematureEndOfInput: return True except LexException as e: if e.source is None: e.source = source e.filename = filename error_handler(e, use_simple_traceback=True) return False try: def ast_callback(main_ast, expr_ast): if self.spy: # Mush the two AST chunks into a single module for # conversion into Python. new_ast = ast.Module(main_ast.body + [ast.Expr(expr_ast.body)]) print(astor.to_source(new_ast)) value = hy_eval(do, self.locals, ast_callback=ast_callback, compiler=self.hy_compiler) except HyTypeError as e: if e.source is None: e.source = source e.filename = filename error_handler(e, use_simple_traceback=SIMPLE_TRACEBACKS) return False except Exception as e: error_handler(e) return False if value is not None: # Shift exisitng REPL results next_result = value for sym in self._repl_results_symbols: self.locals[sym], next_result = next_result, self.locals[sym] # Print the value. try: output = self.output_fn(value) except Exception as e: error_handler(e) return False print(output) return False
def do_execute_direct(self, code): ''' Execute the code, and return result. ''' self.result = None #### try to parse it: try: filename = "In [%s]" % self.execution_count hy_ast = hy_parse(code, filename=filename) exec_ast, eval_ast = hy_compile(hy_ast, self.module, root=ast.Interactive, get_expr=True, compiler=self.hy_compiler, filename=filename, source=code) exec_code = compile(exec_ast, filename, 'single') eval_code = compile(eval_ast, filename, 'eval') eval(exec_code, self.locals) self.result = eval(eval_code, self.locals) except Exception as e: self.Error(traceback.format_exc()) self.kernel_resp.update({ "status": "error", 'ename' : e.__class__.__name__, # Exception name, as a string 'evalue' : e.__class__.__name__, # Exception value, as a string 'traceback' : [], # traceback frames as strings }) return None return self.result
def _hy_source_to_code(self, data, path, _optimize=-1): if _could_be_hy_src(path): source = data.decode("utf-8") hy_tree = hy_parse(source, filename=path) with loader_module_obj(self) as module: data = hy_compile(hy_tree, module) return _py_source_to_code(self, data, path, _optimize=_optimize)
def cant_compile(expr): with pytest.raises(HyError) as excinfo: hy_compile(hy_parse(expr), __name__) # Anything that can't be compiled should raise a user friendly # error, otherwise it's a compiler bug. assert issubclass(excinfo.type, HyLanguageError) assert excinfo.value.msg return excinfo.value
def hy2py_main(): options = dict(prog="hy2py", usage="%(prog)s [options] [FILE]", formatter_class=argparse.RawDescriptionHelpFormatter) parser = argparse.ArgumentParser(**options) parser.add_argument("FILE", type=str, nargs='?', help="Input Hy code (use STDIN if \"-\" or " "not provided)") parser.add_argument("--with-source", "-s", action="store_true", help="Show the parsed source structure") parser.add_argument("--with-ast", "-a", action="store_true", help="Show the generated AST") parser.add_argument("--without-python", "-np", action="store_true", help=("Do not show the Python code generated " "from the AST")) options = parser.parse_args(sys.argv[1:]) if options.FILE is None or options.FILE == '-': sys.path.insert(0, "") filename = '<stdin>' source = sys.stdin.read() else: filename = options.FILE set_path(filename) with io.open(options.FILE, 'r', encoding='utf-8') as source_file: source = source_file.read() with filtered_hy_exceptions(): hst = hy_parse(source, filename=filename) if options.with_source: _print_for_windows(hst) print() print() with filtered_hy_exceptions(): _ast = hy_compile(hst, '__main__', filename=filename, source=source) if options.with_ast: _print_for_windows(ast.dump(_ast)) print() print() if not options.without_python: _print_for_windows(ast.unparse(_ast)) parser.exit(0)
def cant_compile(expr): with pytest.raises(HyError) as excinfo: hy_compile(hy_parse(expr), __name__) if issubclass(excinfo.type, HyLanguageError): assert excinfo.value.msg return excinfo.value elif issubclass(excinfo.type, HyCompileError): # Anything that can't be compiled should raise a user friendly # error, otherwise it's a compiler bug. return excinfo.value
def run_command(source, filename=None): __main__ = importlib.import_module('__main__') require("hy.cmdline", __main__, assignments="ALL") try: tree = hy_parse(source, filename=filename) except HyLanguageError: hy_exc_handler(*sys.exc_info()) return 1 with filtered_hy_exceptions(): hy_eval(tree, None, __main__, filename=filename, source=source) return 0
def _hy_source_to_code(self, data, path, _optimize=-1): if _could_be_hy_src(path): source = data.decode("utf-8") try: hy_tree = hy_parse(source) with loader_module_obj(self) as module: data = hy_compile(hy_tree, module) except (HyTypeError, LexException) as e: if e.source is None: e.source = source e.filename = path raise return _py_source_to_code(self, data, path, _optimize=_optimize)
def cant_compile(expr): try: hy_compile(hy_parse(expr), "__main__") assert False except HyTypeError as e: # Anything that can't be compiled should raise a user friendly # error, otherwise it's a compiler bug. assert isinstance(e.expression, HyObject) assert e.message return e except HyCompileError as e: # Anything that can't be compiled should raise a user friendly # error, otherwise it's a compiler bug. assert isinstance(e.exception, HyTypeError) assert e.traceback return e
def generate(self, code, lang='py', mode='main'): self.mod_name = mode if mode not in ['main', 'block']: self.namespace = mode self.variables |= {mode: {'type': types.types['module'](mode)}} if lang == 'py': tree = ast.parse(code).body elif lang == 'hy': if not is_hy_supported: raise Exception( "requires hy library\n" "\trun 'python -m pip install kithon[add-langs]' to fix") tree = hy_parse(code)[1:] elif lang == 'coco': if not is_coconut_supported: raise Exception( "requires coconut library\n" "\trun 'python -m pip install kithon[add-langs]' to fix") setup(target='sys') tree = ast.parse(parse(code, 'block')).body for block in map(self.visit, tree): if not block: continue self.strings.extend(block.render().split('\n')) if mode != 'block': code = self.templates['main']['tmp'].render(_body=self.strings, body='\n'.join( self.strings), env=self) if mode == 'main': self.variables = { '__main__': { 'type': types.types['module']('__main__') } } self.temp_var_counts = defaultdict(int) else: code = '\n'.join(self.strings) self.nl = 0 self.namespace = '__main__' self.strings = [] self.used = set([]) return code
def byte_compile_hy(self, fullname=None): fullname = self._fix_name(fullname) if fullname is None: fullname = self.fullname hy_source = self.get_source(fullname) hy_tree = hy_parse(hy_source, filename=self.filename) with loader_module_obj(self) as module: hy_ast = hy_compile(hy_tree, module) code = compile(hy_ast, self.filename, 'exec', hy_ast_compile_flags) if not sys.dont_write_bytecode: try: hyc_compile(code, module=fullname) except IOError: pass return code
def test_import_error_reporting(): "Make sure that (import) reports errors correctly." with pytest.raises(HyLanguageError): hy_compile(hy_parse("(import \"sys\")"), __name__)
def test_stringer(): _ast = hy_compile(hy_parse("(defn square [x] (* x x))"), __name__) assert type(_ast.body[0]) == ast.FunctionDef
def can_eval(expr): return hy_eval(hy_parse(expr))
def can_compile(expr): return hy_compile(hy_parse(expr), __name__)
def can_compile(expr): return hy_compile(hy_parse(expr), "__main__")
def __init__(self, spy=False, output_fn=None, locals=None, filename="<stdin>"): # Create a proper module for this REPL so that we can obtain it easily # (e.g. using `importlib.import_module`). # We let `InteractiveConsole` initialize `self.locals` when it's # `None`. super(HyREPL, self).__init__(locals=locals, filename=filename) module_name = self.locals.get('__name__', '__console__') # Make sure our newly created module is properly introduced to # `sys.modules`, and consistently use its namespace as `self.locals` # from here on. self.module = sys.modules.setdefault(module_name, types.ModuleType(module_name)) self.module.__dict__.update(self.locals) self.locals = self.module.__dict__ if os.environ.get("HYSTARTUP"): try: loader = HyLoader("__hystartup__", os.environ.get("HYSTARTUP")) spec = importlib.util.spec_from_loader(loader.name, loader) mod = importlib.util.module_from_spec(spec) sys.modules.setdefault(mod.__name__, mod) loader.exec_module(mod) imports = mod.__dict__.get('__all__', [ name for name in mod.__dict__ if not name.startswith("_") ]) imports = {name: mod.__dict__[name] for name in imports} spy = spy or imports.get("repl_spy") output_fn = output_fn or imports.get("repl_output_fn") # Load imports and defs self.locals.update(imports) # load module macros require(mod, self.module, assignments='ALL') except Exception as e: print(e) # Load cmdline-specific macros. require('hy.cmdline', self.module, assignments='ALL') self.hy_compiler = HyASTCompiler(self.module) self.cmdline_cache = {} self.compile = HyCommandCompiler(self.module, self.locals, ast_callback=self.ast_callback, hy_compiler=self.hy_compiler, cmdline_cache=self.cmdline_cache) self.spy = spy self.last_value = None self.print_last_value = True if output_fn is None: self.output_fn = hy.repr elif callable(output_fn): self.output_fn = output_fn elif "." in output_fn: parts = [mangle(x) for x in output_fn.split(".")] module, f = '.'.join(parts[:-1]), parts[-1] self.output_fn = getattr(importlib.import_module(module), f) else: self.output_fn = getattr(builtins, mangle(output_fn)) # 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}) # Allow access to the running REPL instance self.locals['_hy_repl'] = self # Compile an empty statement to load the standard prelude exec_ast = hy_compile(hy_parse(''), self.module, compiler=self.hy_compiler, import_stdlib=True) if self.ast_callback: self.ast_callback(exec_ast, None)
def hyc_compile(file_or_code, cfile=None, dfile=None, doraise=False, module=None): """Write a Hy file, or code object, to pyc. This is a patched version of Python 2.7's `py_compile.compile`. Also, it tries its best to write the bytecode file atomically. Parameters ---------- file_or_code : str or instance of `types.CodeType` A filename for a Hy or Python source file or its corresponding code object. cfile : str, optional The filename to use for the bytecode file. If `None`, use the standard bytecode filename determined by `cache_from_source`. dfile : str, optional The filename to use for compile-time errors. doraise : bool, default False If `True` raise compilation exceptions; otherwise, ignore them. module : str or types.ModuleType, optional The module, or module name, in which the Hy tree is expanded. Default is the caller's module. Returns ------- out : str The resulting bytecode file name. Python 3.x returns this, but Python 2.7 doesn't; this function does for convenience. """ if isinstance(file_or_code, types.CodeType): codeobject = file_or_code filename = codeobject.co_filename else: filename = file_or_code with open(filename, 'rb') as f: source_str = f.read().decode('utf-8') try: flags = None if _could_be_hy_src(filename): hy_tree = hy_parse(source_str) if module is None: module = inspect.getmodule(inspect.stack()[1][0]) elif not inspect.ismodule(module): module = importlib.import_module(module) source = hy_compile(hy_tree, module) flags = hy_ast_compile_flags codeobject = compile(source, dfile or filename, 'exec', flags) except Exception as err: if isinstance(err, (HyTypeError, LexException)) and err.source is None: err.source = source_str err.filename = filename py_exc = py_compile.PyCompileError(err.__class__, err, dfile or filename) if doraise: raise py_exc else: traceback.print_exc() return timestamp = long(os.stat(filename).st_mtime) if cfile is None: cfile = cache_from_source(filename) f = tempfile.NamedTemporaryFile('wb', dir=os.path.split(cfile)[0], delete=False) try: f.write('\0\0\0\0') f.write(struct.pack('<I', timestamp)) f.write(marshal.dumps(codeobject)) f.flush() f.seek(0, 0) f.write(imp.get_magic()) # Make sure it's written to disk. f.flush() os.fsync(f.fileno()) f.close() # Rename won't replace an existing dest on Windows. if os.name == 'nt' and os.path.isfile(cfile): os.unlink(cfile) os.rename(f.name, cfile) except OSError: try: os.unlink(f.name) except OSError: pass return cfile
def can_compile(expr, import_stdlib=False): return hy_compile(hy_parse(expr), __name__, import_stdlib=import_stdlib)
def hy2py_main(): import platform options = dict(prog="hy2py", usage="%(prog)s [options] [FILE]", formatter_class=argparse.RawDescriptionHelpFormatter) parser = argparse.ArgumentParser(**options) parser.add_argument("FILE", type=str, nargs='?', help="Input Hy code (use STDIN if \"-\" or " "not provided)") parser.add_argument("--with-source", "-s", action="store_true", help="Show the parsed source structure") parser.add_argument("--with-ast", "-a", action="store_true", help="Show the generated AST") parser.add_argument("--without-python", "-np", action="store_true", help=("Do not show the Python code generated " "from the AST")) options = parser.parse_args(sys.argv[1:]) if options.FILE is None or options.FILE == '-': filename = '<stdin>' source = sys.stdin.read() else: filename = options.FILE with io.open(options.FILE, 'r', encoding='utf-8') as source_file: source = source_file.read() with filtered_hy_exceptions(): hst = hy_parse(source, filename=filename) if options.with_source: # need special printing on Windows in case the # codepage doesn't support utf-8 characters if PY3 and platform.system() == "Windows": for h in hst: try: print(h) except: print(str(h).encode('utf-8')) else: print(hst) print() print() with filtered_hy_exceptions(): _ast = hy_compile(hst, '__main__', filename=filename, source=source) if options.with_ast: if PY3 and platform.system() == "Windows": _print_for_windows(astor.dump_tree(_ast)) else: print(astor.dump_tree(_ast)) print() print() if not options.without_python: if PY3 and platform.system() == "Windows": _print_for_windows(astor.code_gen.to_source(_ast)) else: print(astor.code_gen.to_source(_ast)) parser.exit(0)
def run_command(source): tree = hy_parse(source) require("hy.cmdline", "__main__", assignments="ALL") pretty_error(hy_eval, tree, None, importlib.import_module('__main__')) return 0
def hyc_compile(file_or_code, cfile=None, dfile=None, doraise=False, module=None): """Write a Hy file, or code object, to pyc. This is a patched version of Python 2.7's `py_compile.compile`. Also, it tries its best to write the bytecode file atomically. Parameters ---------- file_or_code : str or instance of `types.CodeType` A filename for a Hy or Python source file or its corresponding code object. cfile : str, optional The filename to use for the bytecode file. If `None`, use the standard bytecode filename determined by `cache_from_source`. dfile : str, optional The filename to use for compile-time errors. doraise : bool, default False If `True` raise compilation exceptions; otherwise, ignore them. module : str or types.ModuleType, optional The module, or module name, in which the Hy tree is expanded. Default is the caller's module. Returns ------- out : str The resulting bytecode file name. Python 3.x returns this, but Python 2.7 doesn't; this function does for convenience. """ if isinstance(file_or_code, types.CodeType): codeobject = file_or_code filename = codeobject.co_filename else: filename = file_or_code with open(filename, 'rb') as f: source_str = f.read().decode('utf-8') try: flags = None if _could_be_hy_src(filename): hy_tree = hy_parse(source_str, filename=filename) if module is None: module = inspect.getmodule(inspect.stack()[1][0]) elif not inspect.ismodule(module): module = importlib.import_module(module) source = hy_compile(hy_tree, module) flags = hy_ast_compile_flags codeobject = compile(source, dfile or filename, 'exec', flags) except Exception as err: py_exc = py_compile.PyCompileError(err.__class__, err, dfile or filename) if doraise: raise py_exc else: traceback.print_exc() return timestamp = long(os.stat(filename).st_mtime) if cfile is None: cfile = cache_from_source(filename) f = None try: f = tempfile.NamedTemporaryFile('wb', dir=os.path.split(cfile)[0], delete=False) f.write('\0\0\0\0') f.write(struct.pack('<I', timestamp)) f.write(marshal.dumps(codeobject)) f.flush() f.seek(0, 0) f.write(imp.get_magic()) # Make sure it's written to disk. f.flush() os.fsync(f.fileno()) f.close() # Rename won't replace an existing dest on Windows. if os.name == 'nt' and os.path.isfile(cfile): os.unlink(cfile) os.rename(f.name, cfile) except OSError: try: if f is not None: os.unlink(f.name) except OSError: pass return cfile
def hy2py_main(): import platform options = dict(prog="hy2py", usage="%(prog)s [options] [FILE]", formatter_class=argparse.RawDescriptionHelpFormatter) parser = argparse.ArgumentParser(**options) parser.add_argument("FILE", type=str, nargs='?', help="Input Hy code (use STDIN if \"-\" or " "not provided)") parser.add_argument("--with-source", "-s", action="store_true", help="Show the parsed source structure") parser.add_argument("--with-ast", "-a", action="store_true", help="Show the generated AST") parser.add_argument("--without-python", "-np", action="store_true", help=("Do not show the Python code generated " "from the AST")) options = parser.parse_args(sys.argv[1:]) if options.FILE is None or options.FILE == '-': filename = '<stdin>' source = sys.stdin.read() else: filename = options.FILE with io.open(options.FILE, 'r', encoding='utf-8') as source_file: source = source_file.read() with filtered_hy_exceptions(): hst = hy_parse(source, filename=filename) if options.with_source: # need special printing on Windows in case the # codepage doesn't support utf-8 characters if platform.system() == "Windows": for h in hst: try: print(h) except: print(str(h).encode('utf-8')) else: print(hst) print() print() with filtered_hy_exceptions(): _ast = hy_compile(hst, '__main__', filename=filename, source=source) if options.with_ast: if platform.system() == "Windows": _print_for_windows(astor.dump_tree(_ast)) else: print(astor.dump_tree(_ast)) print() print() if not options.without_python: if platform.system() == "Windows": _print_for_windows(astor.code_gen.to_source(_ast)) else: print(astor.code_gen.to_source(_ast)) parser.exit(0)
def _import_error_test(): try: _ = hy_compile(hy_parse("(import \"sys\")"), '__main__') except HyTypeError: return "Error reported"