def runsource(self, source, filename='<input>', symbol='single'): global SIMPLE_TRACEBACKS try: tokens = tokenize(source) except PrematureEndOfInput: return True except LexException as e: if e.source is None: e.source = source e.filename = filename sys.stderr.write(str_type(e)) return False try: _ast = hy_compile(tokens, "__console__", root=ast.Interactive) if self.spy: print_python_code(_ast) code = ast_compile(_ast, filename, symbol) except HyTypeError as e: if e.source is None: e.source = source e.filename = filename if SIMPLE_TRACEBACKS: sys.stderr.write(str_type(e)) else: self.showtraceback() return False except Exception: self.showtraceback() return False self.runcode(code) return False
def mangle(s): """Stringify the argument and convert it to a valid Python identifier according to Hy's mangling rules.""" assert s s = str_type(s) s = s.replace("-", "_") s2 = s.lstrip('_') leading_underscores = '_' * (len(s) - len(s2)) s = s2 if s.endswith("?"): s = 'is_' + s[:-1] if not isidentifier(leading_underscores + s): # Replace illegal characters with their Unicode character # names, or hexadecimal if they don't have one. s = 'hyx_' + ''.join( c if c != mangle_delim and isidentifier('S' + c) # We prepend the "S" because some characters aren't # allowed at the start of an identifier. else '{0}{1}{0}'.format(mangle_delim, unicodedata.name(c, '').lower().replace('-', 'H').replace(' ', '_') or 'U{:x}'.format(ord(c))) for c in s) s = leading_underscores + s assert isidentifier(s) return s
def macroexpand_1(tree, module_name): """Expand the toplevel macro from `tree` once, in the context of `module_name`.""" if isinstance(tree, HyExpression): if tree == []: return tree fn = tree[0] if fn in ("quote", "quasiquote"): return tree ntree = HyExpression(tree[:]) ntree.replace(tree) if isinstance(fn, HyString): m = _hy_macros[module_name].get(fn) if m is None: m = _hy_macros[None].get(fn) if m is not None: try: obj = _wrap_value(m(*ntree[1:])) except HyTypeError as e: if e.expression is None: e.expression = tree raise except Exception as e: msg = "expanding `" + str_type(tree[0]) + "': " + repr(e) raise HyMacroExpansionError(tree, msg) obj.replace(tree) return obj return ntree return tree
def mangle(s): """Stringify the argument and convert it to a valid Python identifier according to Hy's mangling rules.""" def unicode_char_to_hex(uchr): # Covert a unicode char to hex string, without prefix return uchr.encode('unicode-escape').decode('utf-8').lstrip( '\\U').lstrip('\\u').lstrip('0') assert s s = str_type(s) s = s.replace("-", "_") s2 = s.lstrip('_') leading_underscores = '_' * (len(s) - len(s2)) s = s2 if s.endswith("?"): s = 'is_' + s[:-1] if not isidentifier(leading_underscores + s): # Replace illegal characters with their Unicode character # names, or hexadecimal if they don't have one. s = 'hyx_' + ''.join( c if c != mangle_delim and isidentifier('S' + c) # We prepend the "S" because some characters aren't # allowed at the start of an identifier. else '{0}{1}{0}'.format( mangle_delim, unicodedata.name(c, '').lower().replace('-', 'H'). replace(' ', '_') or 'U{}'.format(unicode_char_to_hex(c))) for c in unicode_to_ucs4iter(s)) s = leading_underscores + s assert isidentifier(s) return s
def require(source_module, target_module, assignments, prefix=""): """Load macros from `source_module` in the namespace of `target_module`. `assignments` maps old names to new names, or should be the string "ALL". If `prefix` is nonempty, it is prepended to the name of each imported macro. (This means you get macros named things like "mymacromodule.mymacro", which looks like an attribute of a module, although it's actually just a symbol with a period in its name.) This function is called from the `require` special form in the compiler. """ seen_names = set() if prefix: prefix += "." if assignments != "ALL": assignments = {mangle(str_type(k)): v for k, v in assignments} for d in _hy_macros, _hy_tag: for name, macro in d[source_module].items(): seen_names.add(name) if assignments == "ALL": d[target_module][mangle(prefix + name)] = macro elif name in assignments: d[target_module][mangle(prefix + assignments[name])] = macro if assignments != "ALL": unseen = frozenset(assignments.keys()).difference(seen_names) if unseen: raise ImportError("cannot require names: " + repr(list(unseen)))
def __str__(self): if isinstance(self.exception, HyTypeError): return str_type(self.exception) if self.traceback: tb = "".join(traceback.format_tb(self.traceback)).strip() else: tb = "No traceback available. 😟" return("Internal Compiler Bug 😱\n⤷ %s: %s\nCompilation traceback:\n%s" % (self.exception.__class__.__name__, self.exception, tb))
def test_unicode_exception_messages(): """Ensure we can generate error messages containing unicode.""" try: hy_compile(tokenize("(defmacro ❤ () (throw Exception)) (❤)"), "__main__") assert False except HyMacroExpansionError as e: assert isinstance(e.expression, HyObject) message = str_type(e) assert '❤' in message assert "Exception()" in message
def run_file(filename): from hy.importer import import_file_to_module try: import_file_to_module("__main__", filename) except (HyTypeError, LexException) as e: if SIMPLE_TRACEBACKS: sys.stderr.write(str_type(e)) return 1 raise except Exception: raise return 0
def run_command(source): try: if not PY3: # TODO: Encoding type should depend on locale. source = source.decode('utf-8') import_buffer_to_module("__main__", source) except (HyTypeError, LexException) as e: if SIMPLE_TRACEBACKS: sys.stderr.write(str_type(e)) return 1 raise except Exception: raise return 0
def macroexpand_1(tree, compiler): """Expand the toplevel macro from `tree` once, in the context of `module_name`.""" if isinstance(tree, HyExpression): if tree == []: return tree fn = tree[0] if fn in ("quote", "quasiquote"): return tree ntree = HyExpression(tree[:]) ntree.replace(tree) opts = {} if isinstance(fn, HySymbol): fn = mangle(str_type(fn)) m = _hy_macros[compiler.module_name].get(fn) if m is None: m = _hy_macros[None].get(fn) if m is not None: if m._hy_macro_pass_compiler: opts['compiler'] = compiler try: m_copy = make_empty_fn_copy(m) m_copy(compiler.module_name, *ntree[1:], **opts) except TypeError as e: msg = "expanding `" + str(tree[0]) + "': " msg += str(e).replace("<lambda>()", "", 1).strip() raise HyMacroExpansionError(tree, msg) try: obj = m(compiler.module_name, *ntree[1:], **opts) except HyTypeError as e: if e.expression is None: e.expression = tree raise except Exception as e: msg = "expanding `" + str(tree[0]) + "': " + repr(e) raise HyMacroExpansionError(tree, msg) replace_hy_obj(obj, tree) return obj return ntree return tree
def __str__(self): line = self.expression.start_line start = self.expression.start_column end = self.expression.end_column source = [] if self.source is not None: source = self.source.split("\n")[line-1:self.expression.end_line] if line == self.expression.end_line: length = end - start else: length = len(source[0]) - start result = "" result += ' File "%s", line %d, column %d\n\n' % (self.filename, line, start) if len(source) == 1: result += ' %s\n' % colored.red(source[0]) result += ' %s%s\n' % (' '*(start-1), colored.green('^' + '-'*(length-1) + '^')) if len(source) > 1: result += ' %s\n' % colored.red(source[0]) result += ' %s%s\n' % (' '*(start-1), colored.green('^' + '-'*length)) if len(source) > 2: # write the middle lines for line in source[1:-1]: result += ' %s\n' % colored.red("".join(line)) result += ' %s\n' % colored.green("-"*len(line)) # write the last line result += ' %s\n' % colored.red("".join(source[-1])) result += ' %s\n' % colored.green('-'*(end-1) + '^') result += str_type(colored.yellow("%s: %s\n\n" % (self.__class__.__name__, self.message))) return result
def hy_symbol_unmangle(p): # hy_symbol_mangle is one-way, so this can't be perfect. # But it can be useful till we have a way to get the original # symbol (https://github.com/hylang/hy/issues/360). p = str_type(p) if p.endswith("_bang") and p != "_bang": p = p[:-len("_bang")] + "!" if p.startswith("is_") and p != "is_": p = p[len("is_"):] + "?" if "_" in p and p != "_": p = p.replace("_", "-") if (all([c.isalpha() and c.isupper() or c == '_' for c in p]) and any([c.isalpha() for c in p])): p = '*' + p.lower() + '*' return p
def unmangle(s): """Stringify the argument and try to convert it to a pretty unmangled form. This may not round-trip, because different Hy symbol names can mangle to the same Python identifier.""" s = str_type(s) s2 = s.lstrip('_') leading_underscores = len(s) - len(s2) s = s2 if s.startswith('hyx_'): s = re.sub( '{0}(U)?([_a-z0-9H]+?){0}'.format(mangle_delim), lambda mo: chr(int(mo.group(2), base=16)) if mo.group(1) else unicodedata.lookup( mo.group(2).replace('_', ' ').replace('H', '-').upper()), s[len('hyx_'):]) if s.startswith('is_'): s = s[len("is_"):] + "?" s = s.replace('_', '-') return '-' * leading_underscores + s
def mangle(s): """Stringify the argument and convert it to a valid Python identifier according to Hy's mangling rules.""" def unicode_char_to_hex(uchr): # Covert a unicode char to hex string, without prefix if len(uchr) == 1 and ord(uchr) < 128: return format(ord(uchr), 'x') return (uchr.encode('unicode-escape').decode('utf-8') .lstrip('\\U').lstrip('\\u').lstrip('\\x').lstrip('0')) assert s s = str_type(s) s = s.replace("-", "_") s2 = s.lstrip('_') leading_underscores = '_' * (len(s) - len(s2)) s = s2 if s.endswith("?"): s = 'is_' + s[:-1] if not isidentifier(leading_underscores + s): # Replace illegal characters with their Unicode character # names, or hexadecimal if they don't have one. s = 'hyx_' + ''.join( c if c != mangle_delim and isidentifier('S' + c) # We prepend the "S" because some characters aren't # allowed at the start of an identifier. else '{0}{1}{0}'.format(mangle_delim, unicodedata.name(c, '').lower().replace('-', 'H').replace(' ', '_') or 'U{}'.format(unicode_char_to_hex(c))) for c in unicode_to_ucs4iter(s)) s = leading_underscores + s assert isidentifier(s) return s
def unmangle(s): """Stringify the argument and try to convert it to a pretty unmangled form. This may not round-trip, because different Hy symbol names can mangle to the same Python identifier.""" s = str_type(s) s2 = s.lstrip('_') leading_underscores = len(s) - len(s2) s = s2 if s.startswith('hyx_'): s = re.sub('{0}(U)?([_a-z0-9H]+?){0}'.format(mangle_delim), lambda mo: chr(int(mo.group(2), base=16)) if mo.group(1) else unicodedata.lookup( mo.group(2).replace('_', ' ').replace('H', '-').upper()), s[len('hyx_'):]) if s.startswith('is_'): s = s[len("is_"):] + "?" s = s.replace('_', '-') return '-' * leading_underscores + s
def read_str(input): return read(StringIO(str_type(input)))
def test_replace_string_type(): """Test replacing python string""" replaced = replace_hy_obj(str_type("foo"), HyString("bar")) assert replaced == HyString("foo")