Add `mangle` and `unmangle` as core functions

This commit is contained in:
Kodi Arfer 2018-03-04 14:20:46 -08:00
parent ebc9bda7ee
commit 85968e70dd
10 changed files with 43 additions and 28 deletions

View File

@ -12,5 +12,5 @@ import hy.importer # NOQA
# we import for side-effects.
from hy.core.language import read, read_str # NOQA
from hy.core.language import read, read_str, mangle, unmangle # NOQA
from hy.importer import hy_eval as eval # NOQA

View File

@ -16,7 +16,7 @@ import astor.code_gen
import hy
from hy.lex import LexException, PrematureEndOfInput
from hy.lex.parser import hy_symbol_mangle
from hy.lex.parser import mangle
from hy.compiler import HyTypeError
from hy.importer import (hy_eval, import_buffer_to_module,
import_file_to_ast, import_file_to_hst,
@ -64,11 +64,11 @@ class HyREPL(code.InteractiveConsole):
self.output_fn = output_fn
else:
if "." in output_fn:
parts = [hy_symbol_mangle(x) for x in output_fn.split(".")]
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 = __builtins__[hy_symbol_mangle(output_fn)]
self.output_fn = __builtins__[mangle(output_fn)]
code.InteractiveConsole.__init__(self, locals=locals,
filename=filename)

View File

@ -8,7 +8,7 @@ from hy.models import (HyObject, HyExpression, HyKeyword, HyInteger, HyComplex,
HyDict, HyCons, wrap_value)
from hy.errors import HyCompileError, HyTypeError
from hy.lex.parser import hy_symbol_mangle
from hy.lex.parser import mangle
import hy.macros
from hy._compat import (
@ -70,7 +70,7 @@ if PY35:
def ast_str(x, piecewise=False):
if piecewise:
return ".".join(ast_str(s) if s else "" for s in x.split("."))
x = hy_symbol_mangle(str_type(x))
x = mangle(x)
return x if PY3 else x.encode('UTF8')
@ -2109,7 +2109,7 @@ class HyASTCompiler(object):
"Trying to expand a tag macro using `{0}' instead "
"of string".format(type(tag).__name__),
)
tag = HyString(hy_symbol_mangle(str(tag))).replace(tag)
tag = HyString(mangle(tag)).replace(tag)
expr = tag_macroexpand(tag, expression.pop(0), self)
return self.compile(expr)

View File

@ -7,7 +7,6 @@
[functools [partial]]
[collections [OrderedDict]]
[hy.macros [macroexpand :as mexpand]]
[hy.lex.parser [hy-symbol-mangle]]
[hy.compiler [HyASTCompiler]])
(defn walk [inner outer form]
@ -258,7 +257,7 @@ Arguments without a header are under None.
(= head 'defclass) (self.handle-defclass)
(= head 'quasiquote) (self.+quote)
;; must be checked last!
(in (hy-symbol-mangle (string head)) special-forms) (self.handle-special-form)
(in (mangle head) special-forms) (self.handle-special-form)
;; Not a special form. Traverse it like a coll
(self.handle-coll)))

View File

@ -18,6 +18,7 @@
(import [hy._compat [long-type]]) ; long for python2, int for python3
(import [hy.models [HyCons HySymbol HyKeyword]])
(import [hy.lex [LexException PrematureEndOfInput tokenize]])
(import [hy.lex.parser [mangle unmangle]])
(import [hy.compiler [HyASTCompiler spoof-positions]])
(import [hy.importer [hy-eval :as eval]])
@ -495,7 +496,7 @@ Even objects with the __name__ magic will work."
filter flatten float? fraction gensym group-by identity inc input instance?
integer integer? integer-char? interleave interpose islice iterable?
iterate iterator? juxt keyword keyword? last list* macroexpand
macroexpand-1 map merge-with multicombinations name neg? none? nth
macroexpand-1 mangle map merge-with multicombinations name neg? none? nth
numeric? odd? partition permutations pos? product range read read-str
remove repeat repeatedly rest reduce second some string string? symbol?
take take-nth take-while xor tee zero? zip zip-longest])
take take-nth take-while unmangle xor tee zero? zip zip-longest])

View File

@ -13,7 +13,6 @@
The result of the first call is cached."
(global _cache)
(if (is _cache None) (do
(setv unmangle (. sys.modules ["hy.lex.parser"] hy_symbol_unmangle))
(setv _cache (frozenset (map unmangle (+
hy.core.language.EXPORTS
hy.core.shadow.EXPORTS

View File

@ -25,9 +25,14 @@ pg = ParserGenerator(
mangle_delim = 'Δ' if PY3 else 'X'
def hy_symbol_mangle(s):
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))
@ -53,8 +58,11 @@ def hy_symbol_mangle(s):
return s
def hy_symbol_unmangle(s):
# hy_symbol_mangle is one-way, so this won't round-trip.
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('_')

View File

@ -5,7 +5,7 @@
from hy._compat import PY3
import hy.inspect
from hy.models import replace_hy_obj, HyExpression, HySymbol
from hy.lex.parser import hy_symbol_mangle
from hy.lex.parser import mangle
from hy._compat import str_type
from hy.errors import HyTypeError, HyMacroExpansionError
@ -36,7 +36,7 @@ def macro(name):
This function is called from the `defmacro` special form in the compiler.
"""
name = hy_symbol_mangle(name)
name = mangle(name)
def _(fn):
fn.__name__ = '({})'.format(name)
try:
@ -67,14 +67,14 @@ def tag(name):
"""
def _(fn):
_name = hy_symbol_mangle('#{}'.format(name))
_name = mangle('#{}'.format(name))
if not PY3:
_name = _name.encode('UTF-8')
fn.__name__ = _name
module_name = fn.__module__
if module_name.startswith("hy.core"):
module_name = None
_hy_tag[module_name][hy_symbol_mangle(name)] = fn
_hy_tag[module_name][mangle(name)] = fn
return fn
return _
@ -97,15 +97,15 @@ def require(source_module, target_module,
seen_names = set()
if prefix:
prefix += "."
assignments = {hy_symbol_mangle(str_type(k)): v for k, v in assignments.items()}
assignments = {mangle(str_type(k)): v for k, v in assignments.items()}
for d in _hy_macros, _hy_tag:
for name, macro in d[source_module].items():
seen_names.add(name)
if all_macros:
d[target_module][hy_symbol_mangle(prefix + name)] = macro
d[target_module][mangle(prefix + name)] = macro
elif name in assignments:
d[target_module][hy_symbol_mangle(prefix + assignments[name])] = macro
d[target_module][mangle(prefix + assignments[name])] = macro
if not all_macros:
unseen = frozenset(assignments.keys()).difference(seen_names)
@ -187,7 +187,7 @@ def macroexpand_1(tree, compiler):
opts = {}
if isinstance(fn, HySymbol):
fn = hy_symbol_mangle(str_type(fn))
fn = mangle(str_type(fn))
m = _hy_macros[compiler.module_name].get(fn)
if m is None:
m = _hy_macros[None].get(fn)

View File

@ -178,3 +178,12 @@
(setv ~sym 10)
[foo? is_foo])))
(assert (= out [10 10])))
(defn test-functions []
(for [[a b] [
["---ab-cd?" "___is_ab_cd"]
["if" "hyx_if"]
["⚘-⚘" (if PY3 "hyx_ΔflowerΔ_ΔflowerΔ" "hyx_XflowerX_XflowerX")]]]
(assert (= (mangle a) b))
(assert (= (unmangle b) a))))

View File

@ -3,7 +3,6 @@
;; license. See the LICENSE.
(import [hy.errors [HyTypeError]])
(import [hy.lex.parser [hy-symbol-mangle]])
(defmacro rev [&rest body]
"Execute the `body` statements in reverse"
@ -164,8 +163,8 @@
(setv s1 (to_source _ast1))
(setv s2 (to_source _ast2))
;; and make sure there is something new that starts with _;G|
(assert (in (hy-symbol-mangle "_;G|") s1))
(assert (in (hy-symbol-mangle "_;G|") s2))
(assert (in (mangle "_;G|") s1))
(assert (in (mangle "_;G|") s2))
;; but make sure the two don't match each other
(assert (not (= s1 s2))))
@ -189,8 +188,8 @@
(setv _ast2 (import_buffer_to_ast macro1 "foo"))
(setv s1 (to_source _ast1))
(setv s2 (to_source _ast2))
(assert (in (hy-symbol-mangle "_;a|") s1))
(assert (in (hy-symbol-mangle "_;a|") s2))
(assert (in (mangle "_;a|") s1))
(assert (in (mangle "_;a|") s2))
(assert (not (= s1 s2))))
(defn test-defmacro-g! []