Don't let HyExpression etc. inherit from HyList
This means the compiler no longer allows e.g. `(fn (x) ...)` in place of `(fn [x] ...)`.
This commit is contained in:
parent
032247e380
commit
87aced2370
4
NEWS.rst
4
NEWS.rst
@ -12,6 +12,10 @@ Removals
|
|||||||
|
|
||||||
Other Breaking Changes
|
Other Breaking Changes
|
||||||
------------------------------
|
------------------------------
|
||||||
|
* `HyExpression`, `HyDict`, and `HySet` no longer inherit from `HyList`.
|
||||||
|
This means you can no longer use alternative punctuation in place of
|
||||||
|
square brackets in special forms (e.g. `(fn (x) ...)` instead of
|
||||||
|
the standard `(fn [x] ...)`).
|
||||||
* Mangling rules have been overhauled, such that mangled names
|
* Mangling rules have been overhauled, such that mangled names
|
||||||
are always legal Python identifiers
|
are always legal Python identifiers
|
||||||
* `_` and `-` are now equivalent even as single-character names
|
* `_` and `-` are now equivalent even as single-character names
|
||||||
|
@ -48,26 +48,35 @@ Hy also attempts to color pretty reprs using ``clint.textui.colored``.
|
|||||||
This module has a flag to disable coloring,
|
This module has a flag to disable coloring,
|
||||||
and a method ``clean`` to strip colored strings of their color tags.
|
and a method ``clean`` to strip colored strings of their color tags.
|
||||||
|
|
||||||
|
.. _hysequence:
|
||||||
|
|
||||||
|
HySequence
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
``hy.models.HySequence`` is the abstract base class of "iterable" Hy
|
||||||
|
models, such as HyExpression and HyList.
|
||||||
|
|
||||||
|
Adding a HySequence to another iterable object reuses the class of the
|
||||||
|
left-hand-side object, a useful behavior when you want to concatenate Hy
|
||||||
|
objects in a macro, for instance.
|
||||||
|
|
||||||
|
|
||||||
.. _hylist:
|
.. _hylist:
|
||||||
|
|
||||||
HyList
|
HyList
|
||||||
~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
``hy.models.HyList`` is the base class of "iterable" Hy models. Its
|
``hy.models.HyExpression`` is a :ref:`HySequence` for bracketed ``[]``
|
||||||
basic use is to represent bracketed ``[]`` lists, which, when used as a
|
lists, which, when used as a top-level expression, translate to Python
|
||||||
top-level expression, translate to Python list literals in the
|
list literals in the compilation phase.
|
||||||
compilation phase.
|
|
||||||
|
|
||||||
Adding a HyList to another iterable object reuses the class of the
|
|
||||||
left-hand-side object, a useful behavior when you want to concatenate Hy
|
|
||||||
objects in a macro, for instance.
|
|
||||||
|
|
||||||
.. _hyexpression:
|
.. _hyexpression:
|
||||||
|
|
||||||
HyExpression
|
HyExpression
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
``hy.models.HyExpression`` inherits :ref:`HyList` for
|
``hy.models.HyExpression`` inherits :ref:`HySequence` for
|
||||||
parenthesized ``()`` expressions. The compilation result of those
|
parenthesized ``()`` expressions. The compilation result of those
|
||||||
expressions depends on the first element of the list: the compiler
|
expressions depends on the first element of the list: the compiler
|
||||||
dispatches expressions between compiler special-forms, user-defined
|
dispatches expressions between compiler special-forms, user-defined
|
||||||
@ -78,8 +87,8 @@ macros, and regular Python function calls.
|
|||||||
HyDict
|
HyDict
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
||||||
``hy.models.HyDict`` inherits :ref:`HyList` for curly-bracketed ``{}``
|
``hy.models.HyDict`` inherits :ref:`HySequence` for curly-bracketed
|
||||||
expressions, which compile down to a Python dictionary literal.
|
``{}`` expressions, which compile down to a Python dictionary literal.
|
||||||
|
|
||||||
The decision of using a list instead of a dict as the base class for
|
The decision of using a list instead of a dict as the base class for
|
||||||
``HyDict`` allows easier manipulation of dicts in macros, with the added
|
``HyDict`` allows easier manipulation of dicts in macros, with the added
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
from hy.models import (HyObject, HyExpression, HyKeyword, HyInteger, HyComplex,
|
from hy.models import (HyObject, HyExpression, HyKeyword, HyInteger, HyComplex,
|
||||||
HyString, HyBytes, HySymbol, HyFloat, HyList, HySet,
|
HyString, HyBytes, HySymbol, HyFloat, HyList, HySet,
|
||||||
HyDict, wrap_value)
|
HyDict, HySequence, wrap_value)
|
||||||
from hy.errors import HyCompileError, HyTypeError
|
from hy.errors import HyCompileError, HyTypeError
|
||||||
|
|
||||||
from hy.lex.parser import mangle
|
from hy.lex.parser import mangle
|
||||||
@ -670,7 +670,7 @@ class HyASTCompiler(object):
|
|||||||
name = form.__class__.__name__
|
name = form.__class__.__name__
|
||||||
imports = set([name])
|
imports = set([name])
|
||||||
|
|
||||||
if isinstance(form, (HyList, HyDict, HySet)):
|
if isinstance(form, HySequence):
|
||||||
if not form:
|
if not form:
|
||||||
contents = HyList()
|
contents = HyList()
|
||||||
else:
|
else:
|
||||||
|
24
hy/models.py
24
hy/models.py
@ -233,9 +233,9 @@ class HyComplex(HyObject, complex):
|
|||||||
_wrappers[complex] = HyComplex
|
_wrappers[complex] = HyComplex
|
||||||
|
|
||||||
|
|
||||||
class HyList(HyObject, list):
|
class HySequence(HyObject, list):
|
||||||
"""
|
"""
|
||||||
Hy List. Basically just a list.
|
An abstract type for sequence-like models to inherit from.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def replace(self, other):
|
def replace(self, other):
|
||||||
@ -246,23 +246,23 @@ class HyList(HyObject, list):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
return self.__class__(super(HyList, self).__add__(other))
|
return self.__class__(super(HySequence, self).__add__(other))
|
||||||
|
|
||||||
def __getslice__(self, start, end):
|
def __getslice__(self, start, end):
|
||||||
return self.__class__(super(HyList, self).__getslice__(start, end))
|
return self.__class__(super(HySequence, self).__getslice__(start, end))
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
ret = super(HyList, self).__getitem__(item)
|
ret = super(HySequence, self).__getitem__(item)
|
||||||
|
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
return self.__class__(ret)
|
return self.__class__(ret)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
color = staticmethod(colored.cyan)
|
color = None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return str(self) if PRETTY else super(HyList, self).__repr__()
|
return str(self) if PRETTY else super(HySequence, self).__repr__()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
with pretty():
|
with pretty():
|
||||||
@ -276,11 +276,15 @@ class HyList(HyObject, list):
|
|||||||
else:
|
else:
|
||||||
return '' + c(self.__class__.__name__ + "()")
|
return '' + c(self.__class__.__name__ + "()")
|
||||||
|
|
||||||
|
|
||||||
|
class HyList(HySequence):
|
||||||
|
color = staticmethod(colored.cyan)
|
||||||
|
|
||||||
_wrappers[list] = lambda l: HyList(wrap_value(x) for x in l)
|
_wrappers[list] = lambda l: HyList(wrap_value(x) for x in l)
|
||||||
_wrappers[tuple] = lambda t: HyList(wrap_value(x) for x in t)
|
_wrappers[tuple] = lambda t: HyList(wrap_value(x) for x in t)
|
||||||
|
|
||||||
|
|
||||||
class HyDict(HyList):
|
class HyDict(HySequence):
|
||||||
"""
|
"""
|
||||||
HyDict (just a representation of a dict)
|
HyDict (just a representation of a dict)
|
||||||
"""
|
"""
|
||||||
@ -316,7 +320,7 @@ class HyDict(HyList):
|
|||||||
_wrappers[dict] = lambda d: HyDict(wrap_value(x) for x in sum(d.items(), ()))
|
_wrappers[dict] = lambda d: HyDict(wrap_value(x) for x in sum(d.items(), ()))
|
||||||
|
|
||||||
|
|
||||||
class HyExpression(HyList):
|
class HyExpression(HySequence):
|
||||||
"""
|
"""
|
||||||
Hy S-Expression. Basically just a list.
|
Hy S-Expression. Basically just a list.
|
||||||
"""
|
"""
|
||||||
@ -327,7 +331,7 @@ _wrappers[Fraction] = lambda e: HyExpression(
|
|||||||
[HySymbol("fraction"), wrap_value(e.numerator), wrap_value(e.denominator)])
|
[HySymbol("fraction"), wrap_value(e.numerator), wrap_value(e.denominator)])
|
||||||
|
|
||||||
|
|
||||||
class HySet(HyList):
|
class HySet(HySequence):
|
||||||
"""
|
"""
|
||||||
Hy set (just a representation of a set)
|
Hy set (just a representation of a set)
|
||||||
"""
|
"""
|
||||||
|
@ -241,6 +241,9 @@ def test_ast_good_lambda():
|
|||||||
def test_ast_bad_lambda():
|
def test_ast_bad_lambda():
|
||||||
"Make sure AST can't compile invalid lambda"
|
"Make sure AST can't compile invalid lambda"
|
||||||
cant_compile("(fn)")
|
cant_compile("(fn)")
|
||||||
|
cant_compile("(fn ())")
|
||||||
|
cant_compile("(fn () 1)")
|
||||||
|
cant_compile("(fn (x) 1)")
|
||||||
|
|
||||||
|
|
||||||
def test_ast_good_yield():
|
def test_ast_good_yield():
|
||||||
@ -381,11 +384,11 @@ def test_ast_expression_basics():
|
|||||||
|
|
||||||
def test_ast_anon_fns_basics():
|
def test_ast_anon_fns_basics():
|
||||||
""" Ensure anon fns work. """
|
""" Ensure anon fns work. """
|
||||||
code = can_compile("(fn (x) (* x x))").body[0].value
|
code = can_compile("(fn [x] (* x x))").body[0].value
|
||||||
assert type(code) == ast.Lambda
|
assert type(code) == ast.Lambda
|
||||||
code = can_compile("(fn (x) (print \"multiform\") (* x x))").body[0]
|
code = can_compile("(fn [x] (print \"multiform\") (* x x))").body[0]
|
||||||
assert type(code) == ast.FunctionDef
|
assert type(code) == ast.FunctionDef
|
||||||
can_compile("(fn (x))")
|
can_compile("(fn [x])")
|
||||||
cant_compile("(fn)")
|
cant_compile("(fn)")
|
||||||
|
|
||||||
|
|
||||||
@ -420,16 +423,16 @@ def test_argument_destructuring():
|
|||||||
|
|
||||||
def test_lambda_list_keywords_rest():
|
def test_lambda_list_keywords_rest():
|
||||||
""" Ensure we can compile functions with lambda list keywords."""
|
""" Ensure we can compile functions with lambda list keywords."""
|
||||||
can_compile("(fn (x &rest xs) (print xs))")
|
can_compile("(fn [x &rest xs] (print xs))")
|
||||||
cant_compile("(fn (x &rest xs &rest ys) (print xs))")
|
cant_compile("(fn [x &rest xs &rest ys] (print xs))")
|
||||||
can_compile("(fn (&optional a &rest xs) (print xs))")
|
can_compile("(fn [&optional a &rest xs] (print xs))")
|
||||||
|
|
||||||
|
|
||||||
def test_lambda_list_keywords_kwargs():
|
def test_lambda_list_keywords_kwargs():
|
||||||
""" Ensure we can compile functions with &kwargs."""
|
""" Ensure we can compile functions with &kwargs."""
|
||||||
can_compile("(fn (x &kwargs kw) (list x kw))")
|
can_compile("(fn [x &kwargs kw] (list x kw))")
|
||||||
cant_compile("(fn (x &kwargs xs &kwargs ys) (list x xs ys))")
|
cant_compile("(fn [x &kwargs xs &kwargs ys] (list x xs ys))")
|
||||||
can_compile("(fn (&optional x &kwargs kw) (list x kw))")
|
can_compile("(fn [&optional x &kwargs kw] (list x kw))")
|
||||||
|
|
||||||
|
|
||||||
def test_lambda_list_keywords_kwonly():
|
def test_lambda_list_keywords_kwonly():
|
||||||
@ -452,8 +455,8 @@ def test_lambda_list_keywords_kwonly():
|
|||||||
|
|
||||||
def test_lambda_list_keywords_mixed():
|
def test_lambda_list_keywords_mixed():
|
||||||
""" Ensure we can mix them up."""
|
""" Ensure we can mix them up."""
|
||||||
can_compile("(fn (x &rest xs &kwargs kw) (list x xs kw))")
|
can_compile("(fn [x &rest xs &kwargs kw] (list x xs kw))")
|
||||||
cant_compile("(fn (x &rest xs &fasfkey {bar \"baz\"}))")
|
cant_compile("(fn [x &rest xs &fasfkey {bar \"baz\"}])")
|
||||||
if PY3:
|
if PY3:
|
||||||
can_compile("(fn [x &rest xs &kwargs kwxs &kwonly kwoxs]"
|
can_compile("(fn [x &rest xs &kwargs kwxs &kwonly kwoxs]"
|
||||||
" (list x xs kwxs kwoxs))")
|
" (list x xs kwxs kwoxs))")
|
||||||
|
@ -84,5 +84,5 @@ def test_eval():
|
|||||||
assert eval_str('(.strip " fooooo ")') == 'fooooo'
|
assert eval_str('(.strip " fooooo ")') == 'fooooo'
|
||||||
assert eval_str(
|
assert eval_str(
|
||||||
'(if True "this is if true" "this is if false")') == "this is if true"
|
'(if True "this is if true" "this is if false")') == "this is if true"
|
||||||
assert eval_str('(list-comp (pow num 2) (num (range 100)) (= (% num 2) 1))') == [
|
assert eval_str('(list-comp (pow num 2) [num (range 100)] (= (% num 2) 1))') == [
|
||||||
pow(num, 2) for num in range(100) if num % 2 == 1]
|
pow(num, 2) for num in range(100) if num % 2 == 1]
|
||||||
|
@ -920,48 +920,48 @@
|
|||||||
|
|
||||||
(defn test-list-comprehensions []
|
(defn test-list-comprehensions []
|
||||||
"NATIVE: test list comprehensions"
|
"NATIVE: test list comprehensions"
|
||||||
(assert (= (list-comp (* x 2) (x (range 2))) [0 2]))
|
(assert (= (list-comp (* x 2) [x (range 2)]) [0 2]))
|
||||||
(assert (= (list-comp (* x 2) (x (range 4)) (% x 2)) [2 6]))
|
(assert (= (list-comp (* x 2) [x (range 4)] (% x 2)) [2 6]))
|
||||||
(assert (= (sorted (list-comp (* y 2) ((, x y) (.items {"1" 1 "2" 2}))))
|
(assert (= (sorted (list-comp (* y 2) [(, x y) (.items {"1" 1 "2" 2})]))
|
||||||
[2 4]))
|
[2 4]))
|
||||||
(assert (= (list-comp (, x y) (x (range 2) y (range 2)))
|
(assert (= (list-comp (, x y) [x (range 2) y (range 2)])
|
||||||
[(, 0 0) (, 0 1) (, 1 0) (, 1 1)]))
|
[(, 0 0) (, 0 1) (, 1 0) (, 1 1)]))
|
||||||
(assert (= (list-comp j (j [1 2])) [1 2])))
|
(assert (= (list-comp j [j [1 2]]) [1 2])))
|
||||||
|
|
||||||
|
|
||||||
(defn test-set-comprehensions []
|
(defn test-set-comprehensions []
|
||||||
"NATIVE: test set comprehensions"
|
"NATIVE: test set comprehensions"
|
||||||
(assert (instance? set (set-comp x [x (range 2)])))
|
(assert (instance? set (set-comp x [x (range 2)])))
|
||||||
(assert (= (set-comp (* x 2) (x (range 2))) (set [0 2])))
|
(assert (= (set-comp (* x 2) [x (range 2)]) (set [0 2])))
|
||||||
(assert (= (set-comp (* x 2) (x (range 4)) (% x 2)) (set [2 6])))
|
(assert (= (set-comp (* x 2) [x (range 4)] (% x 2)) (set [2 6])))
|
||||||
(assert (= (set-comp (* y 2) ((, x y) (.items {"1" 1 "2" 2})))
|
(assert (= (set-comp (* y 2) [(, x y) (.items {"1" 1 "2" 2})])
|
||||||
(set [2 4])))
|
(set [2 4])))
|
||||||
(assert (= (set-comp (, x y) (x (range 2) y (range 2)))
|
(assert (= (set-comp (, x y) [x (range 2) y (range 2)])
|
||||||
(set [(, 0 0) (, 0 1) (, 1 0) (, 1 1)])))
|
(set [(, 0 0) (, 0 1) (, 1 0) (, 1 1)])))
|
||||||
(assert (= (set-comp j (j [1 2])) (set [1 2]))))
|
(assert (= (set-comp j [j [1 2]]) (set [1 2]))))
|
||||||
|
|
||||||
|
|
||||||
(defn test-dict-comprehensions []
|
(defn test-dict-comprehensions []
|
||||||
"NATIVE: test dict comprehensions"
|
"NATIVE: test dict comprehensions"
|
||||||
(assert (instance? dict (dict-comp x x [x (range 2)])))
|
(assert (instance? dict (dict-comp x x [x (range 2)])))
|
||||||
(assert (= (dict-comp x (* x 2) (x (range 2))) {1 2 0 0}))
|
(assert (= (dict-comp x (* x 2) [x (range 2)]) {1 2 0 0}))
|
||||||
(assert (= (dict-comp x (* x 2) (x (range 4)) (% x 2)) {3 6 1 2}))
|
(assert (= (dict-comp x (* x 2) [x (range 4)] (% x 2)) {3 6 1 2}))
|
||||||
(assert (= (dict-comp x (* y 2) ((, x y) (.items {"1" 1 "2" 2})))
|
(assert (= (dict-comp x (* y 2) [(, x y) (.items {"1" 1 "2" 2})])
|
||||||
{"2" 4 "1" 2}))
|
{"2" 4 "1" 2}))
|
||||||
(assert (= (dict-comp (, x y) (+ x y) (x (range 2) y (range 2)))
|
(assert (= (dict-comp (, x y) (+ x y) [x (range 2) y (range 2)])
|
||||||
{(, 0 0) 0 (, 1 0) 1 (, 0 1) 1 (, 1 1) 2})))
|
{(, 0 0) 0 (, 1 0) 1 (, 0 1) 1 (, 1 1) 2})))
|
||||||
|
|
||||||
|
|
||||||
(defn test-generator-expressions []
|
(defn test-generator-expressions []
|
||||||
"NATIVE: test generator expressions"
|
"NATIVE: test generator expressions"
|
||||||
(assert (not (instance? list (genexpr x [x (range 2)]))))
|
(assert (not (instance? list (genexpr x [x (range 2)]))))
|
||||||
(assert (= (list (genexpr (* x 2) (x (range 2)))) [0 2]))
|
(assert (= (list (genexpr (* x 2) [x (range 2)])) [0 2]))
|
||||||
(assert (= (list (genexpr (* x 2) (x (range 4)) (% x 2))) [2 6]))
|
(assert (= (list (genexpr (* x 2) [x (range 4)] (% x 2))) [2 6]))
|
||||||
(assert (= (list (sorted (genexpr (* y 2) ((, x y) (.items {"1" 1 "2" 2})))))
|
(assert (= (list (sorted (genexpr (* y 2) [(, x y) (.items {"1" 1 "2" 2})])))
|
||||||
[2 4]))
|
[2 4]))
|
||||||
(assert (= (list (genexpr (, x y) (x (range 2) y (range 2))))
|
(assert (= (list (genexpr (, x y) [x (range 2) y (range 2)]))
|
||||||
[(, 0 0) (, 0 1) (, 1 0) (, 1 1)]))
|
[(, 0 0) (, 0 1) (, 1 0) (, 1 1)]))
|
||||||
(assert (= (list (genexpr j (j [1 2]))) [1 2])))
|
(assert (= (list (genexpr j [j [1 2]])) [1 2])))
|
||||||
|
|
||||||
|
|
||||||
(defn test-defn-order []
|
(defn test-defn-order []
|
||||||
@ -1370,7 +1370,7 @@
|
|||||||
|
|
||||||
(defn test-lambda-keyword-lists []
|
(defn test-lambda-keyword-lists []
|
||||||
"NATIVE: test lambda keyword lists"
|
"NATIVE: test lambda keyword lists"
|
||||||
(defn foo (x &rest xs &kwargs kw) [x xs kw])
|
(defn foo [x &rest xs &kwargs kw] [x xs kw])
|
||||||
(assert (= (foo 10 20 30) [10 (, 20 30) {}])))
|
(assert (= (foo 10 20 30) [10 (, 20 30) {}])))
|
||||||
|
|
||||||
|
|
||||||
@ -1721,7 +1721,7 @@ macros()
|
|||||||
(defmacro identify-keywords [&rest elts]
|
(defmacro identify-keywords [&rest elts]
|
||||||
`(list
|
`(list
|
||||||
(map
|
(map
|
||||||
(fn (x) (if (is-keyword x) "keyword" "other"))
|
(fn [x] (if (is-keyword x) "keyword" "other"))
|
||||||
~elts)))
|
~elts)))
|
||||||
|
|
||||||
(defn test-keywords-and-macros []
|
(defn test-keywords-and-macros []
|
||||||
|
Loading…
Reference in New Issue
Block a user