Merge pull request #1224 from Kodiologist/refactor-models

Refactor hy.models
This commit is contained in:
Kodi Arfer 2017-02-17 07:42:40 -08:00 committed by GitHub
commit 92d5d6b42c
35 changed files with 483 additions and 811 deletions

View File

@ -44,7 +44,7 @@ Hy parser.
HyList HyList
~~~~~~ ~~~~~~
``hy.models.list.HyList`` is the base class of "iterable" Hy models. Its ``hy.models.HyList`` is the base class of "iterable" Hy models. Its
basic use is to represent bracketed ``[]`` lists, which, when used as a basic use is to represent bracketed ``[]`` lists, which, when used as a
top-level expression, translate to Python list literals in the top-level expression, translate to Python list literals in the
compilation phase. compilation phase.
@ -58,7 +58,7 @@ objects in a macro, for instance.
HyExpression HyExpression
~~~~~~~~~~~~ ~~~~~~~~~~~~
``hy.models.expression.HyExpression`` inherits :ref:`HyList` for ``hy.models.HyExpression`` inherits :ref:`HyList` 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
@ -69,7 +69,7 @@ macros, and regular Python function calls.
HyDict HyDict
~~~~~~ ~~~~~~
``hy.models.dict.HyDict`` inherits :ref:`HyList` for curly-bracketed ``{}`` ``hy.models.HyDict`` inherits :ref:`HyList` 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
@ -101,7 +101,7 @@ the following order:
HyString HyString
~~~~~~~~ ~~~~~~~~
``hy.models.string.HyString`` is the base class of string-equivalent Hy ``hy.models.HyString`` is the base class of string-equivalent Hy
models. It also represents double-quoted string literals, ``""``, which models. It also represents double-quoted string literals, ``""``, which
compile down to unicode string literals in Python. ``HyStrings`` inherit compile down to unicode string literals in Python. ``HyStrings`` inherit
unicode objects in Python 2, and string objects in Python 3 (and are unicode objects in Python 2, and string objects in Python 3 (and are
@ -118,12 +118,12 @@ strings.
Numeric Models Numeric Models
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
``hy.models.integer.HyInteger`` represents integer literals (using the ``hy.models.HyInteger`` represents integer literals (using the
``long`` type on Python 2, and ``int`` on Python 3). ``long`` type on Python 2, and ``int`` on Python 3).
``hy.models.float.HyFloat`` represents floating-point literals. ``hy.models.HyFloat`` represents floating-point literals.
``hy.models.complex.HyComplex`` represents complex literals. ``hy.models.HyComplex`` represents complex literals.
Numeric models are parsed using the corresponding Python routine, and Numeric models are parsed using the corresponding Python routine, and
valid numeric python literals will be turned into their Hy counterpart. valid numeric python literals will be turned into their Hy counterpart.
@ -133,7 +133,7 @@ valid numeric python literals will be turned into their Hy counterpart.
HySymbol HySymbol
~~~~~~~~ ~~~~~~~~
``hy.models.symbol.HySymbol`` is the model used to represent symbols ``hy.models.HySymbol`` is the model used to represent symbols
in the Hy language. It inherits :ref:`HyString`. in the Hy language. It inherits :ref:`HyString`.
``HySymbol`` objects are mangled in the parsing phase, to help Python ``HySymbol`` objects are mangled in the parsing phase, to help Python
@ -153,7 +153,7 @@ source code. Such a mechanism is used by :ref:`gensym` to generate
HyKeyword HyKeyword
~~~~~~~~~ ~~~~~~~~~
``hy.models.keyword.HyKeyword`` represents keywords in Hy. Keywords are ``hy.models.HyKeyword`` represents keywords in Hy. Keywords are
symbols starting with a ``:``. The class inherits :ref:`HyString`. symbols starting with a ``:``. The class inherits :ref:`HyString`.
To distinguish :ref:`HyKeywords <HyKeyword>` from :ref:`HySymbols To distinguish :ref:`HyKeywords <HyKeyword>` from :ref:`HySymbols
@ -166,7 +166,7 @@ literal before storage.
Cons Cells Cons Cells
========== ==========
``hy.models.cons.HyCons`` is a representation of Python-friendly `cons ``hy.models.HyCons`` is a representation of Python-friendly `cons
cells`_. Cons cells are especially useful to mimic features of "usual" cells`_. Cons cells are especially useful to mimic features of "usual"
LISP variants such as Scheme or Common Lisp. LISP variants such as Scheme or Common Lisp.

View File

@ -26,17 +26,7 @@ except ImportError:
__version__ = 'unknown' __version__ = 'unknown'
from hy.models.expression import HyExpression # NOQA from hy.models import HyExpression, HyInteger, HyKeyword, HyComplex, HyString, HySymbol, HyFloat, HyDict, HyList, HySet, HyCons # NOQA
from hy.models.integer import HyInteger # NOQA
from hy.models.keyword import HyKeyword # NOQA
from hy.models.complex import HyComplex # NOQA
from hy.models.string import HyString # NOQA
from hy.models.symbol import HySymbol # NOQA
from hy.models.float import HyFloat # NOQA
from hy.models.dict import HyDict # NOQA
from hy.models.list import HyList # NOQA
from hy.models.set import HySet # NOQA
from hy.models.cons import HyCons # NOQA
import hy.importer # NOQA import hy.importer # NOQA

View File

@ -48,9 +48,7 @@ from hy.completer import Completer
from hy.errors import HyIOError from hy.errors import HyIOError
from hy.macros import macro, require from hy.macros import macro, require
from hy.models.expression import HyExpression from hy.models import HyExpression, HyString, HySymbol
from hy.models.string import HyString
from hy.models.symbol import HySymbol
from hy._compat import builtins, PY3 from hy._compat import builtins, PY3

View File

@ -24,18 +24,8 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE. # DEALINGS IN THE SOFTWARE.
from hy.models.expression import HyExpression from hy.models import (HyExpression, HyKeyword, HyInteger, HyComplex, HyString,
from hy.models.keyword import HyKeyword HySymbol, HyFloat, HyList, HySet, HyDict, HyCons)
from hy.models.integer import HyInteger
from hy.models.complex import HyComplex
from hy.models.string import HyString
from hy.models.symbol import HySymbol
from hy.models.float import HyFloat
from hy.models.list import HyList
from hy.models.set import HySet
from hy.models.dict import HyDict
from hy.models.cons import HyCons
from hy.errors import HyCompileError, HyTypeError from hy.errors import HyCompileError, HyTypeError
from hy.lex.parser import hy_symbol_mangle from hy.lex.parser import hy_symbol_mangle

View File

@ -21,9 +21,7 @@
;; DEALINGS IN THE SOFTWARE. ;; DEALINGS IN THE SOFTWARE.
(import [collections [defaultdict]] (import [collections [defaultdict]]
[hy.models.expression [HyExpression]] [hy [HyExpression HyList HyString]])
[hy.models.list [HyList]]
[hy.models.string [HyString]])
(defclass MultiDispatch [object] [ (defclass MultiDispatch [object] [

View File

@ -33,9 +33,7 @@
(import [StringIO [StringIO]]) (import [StringIO [StringIO]])
(import [io [StringIO]])) (import [io [StringIO]]))
(import [hy._compat [long-type]]) ; long for python2, int for python3 (import [hy._compat [long-type]]) ; long for python2, int for python3
(import [hy.models.cons [HyCons]] (import [hy.models [HyCons HySymbol HyKeyword]])
[hy.models.symbol [HySymbol]]
[hy.models.keyword [HyKeyword *keyword-prefix*]])
(import [hy.lex [LexException PrematureEndOfInput tokenize]]) (import [hy.lex [LexException PrematureEndOfInput tokenize]])
(import [hy.compiler [HyASTCompiler]]) (import [hy.compiler [HyASTCompiler]])
@ -458,7 +456,7 @@
(defn keyword [value] (defn keyword [value]
"Create a keyword from the given value. Strings numbers and even objects "Create a keyword from the given value. Strings numbers and even objects
with the __name__ magic will work" with the __name__ magic will work"
(if (and (string? value) (value.startswith *keyword-prefix*)) (if (and (string? value) (value.startswith HyKeyword.PREFIX))
(hyify value) (hyify value)
(if (string? value) (if (string? value)
(HyKeyword (+ ":" (hyify value))) (HyKeyword (+ ":" (hyify value)))
@ -469,7 +467,7 @@
(defn name [value] (defn name [value]
"Convert the given value to a string. Keyword special character will be stripped. "Convert the given value to a string. Keyword special character will be stripped.
String will be used as is. Even objects with the __name__ magic will work" String will be used as is. Even objects with the __name__ magic will work"
(if (and (string? value) (value.startswith *keyword-prefix*)) (if (and (string? value) (value.startswith HyKeyword.PREFIX))
(hyify (cut value 2)) (hyify (cut value 2))
(if (string? value) (if (string? value)
(hyify value) (hyify value)

View File

@ -26,8 +26,7 @@
;;; They are automatically required in every module, except inside hy.core ;;; They are automatically required in every module, except inside hy.core
(import [hy.models.list [HyList]] (import [hy.models [HyList HySymbol]]
[hy.models.symbol [HySymbol]]
[hy._compat [PY33 PY34]]) [hy._compat [PY33 PY34]])
(defmacro as-> [head name &rest rest] (defmacro as-> [head name &rest rest]

View File

@ -23,18 +23,8 @@ from functools import wraps
from rply import ParserGenerator from rply import ParserGenerator
from hy.models.complex import HyComplex from hy.models import (HyComplex, HyCons, HyDict, HyExpression, HyFloat,
from hy.models.cons import HyCons HyInteger, HyKeyword, HyList, HySet, HyString, HySymbol)
from hy.models.dict import HyDict
from hy.models.expression import HyExpression
from hy.models.float import HyFloat
from hy.models.integer import HyInteger
from hy.models.keyword import HyKeyword
from hy.models.list import HyList
from hy.models.set import HySet
from hy.models.string import HyString
from hy.models.symbol import HySymbol
from .lexer import lexer from .lexer import lexer
from .exceptions import LexException, PrematureEndOfInput from .exceptions import LexException, PrematureEndOfInput

View File

@ -19,9 +19,7 @@
# DEALINGS IN THE SOFTWARE. # DEALINGS IN THE SOFTWARE.
from inspect import getargspec, formatargspec from inspect import getargspec, formatargspec
from hy.models import replace_hy_obj, wrap_value from hy.models import replace_hy_obj, wrap_value, HyExpression, HyString
from hy.models.expression import HyExpression
from hy.models.string import HyString
from hy.errors import HyTypeError, HyMacroExpansionError from hy.errors import HyTypeError, HyMacroExpansionError

332
hy/models.py Normal file
View File

@ -0,0 +1,332 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from __future__ import unicode_literals
from hy._compat import PY3, str_type, long_type, string_types
class HyObject(object):
"""
Generic Hy Object model. This is helpful to inject things into all the
Hy lexing Objects at once.
"""
def replace(self, other):
if isinstance(other, HyObject):
for attr in ["start_line", "end_line",
"start_column", "end_column"]:
if not hasattr(self, attr) and hasattr(other, attr):
setattr(self, attr, getattr(other, attr))
else:
raise TypeError("Can't replace a non Hy object with a Hy object")
return self
_wrappers = {}
def wrap_value(x):
"""Wrap `x` into the corresponding Hy type.
This allows replace_hy_obj to convert a non Hy object to a Hy object.
This also allows a macro to return an unquoted expression transparently.
"""
wrapper = _wrappers.get(type(x))
if wrapper is None:
return x
else:
return wrapper(x)
def replace_hy_obj(obj, other):
if isinstance(obj, HyObject):
return obj.replace(other)
wrapped_obj = wrap_value(obj)
if isinstance(wrapped_obj, HyObject):
return wrapped_obj.replace(other)
else:
raise TypeError("Don't know how to wrap a %s object to a HyObject"
% type(obj))
class HyString(HyObject, str_type):
"""
Generic Hy String object. Helpful to store string literals from Hy
scripts. It's either a ``str`` or a ``unicode``, depending on the
Python version.
"""
pass
_wrappers[str_type] = HyString
class HySymbol(HyString):
"""
Hy Symbol. Basically a String.
"""
def __init__(self, string):
self += string
_wrappers[bool] = lambda x: HySymbol("True") if x else HySymbol("False")
_wrappers[type(None)] = lambda foo: HySymbol("None")
class HyKeyword(HyObject, str_type):
"""Generic Hy Keyword object. It's either a ``str`` or a ``unicode``,
depending on the Python version.
"""
PREFIX = "\uFDD0"
def __new__(cls, value):
if not value.startswith(cls.PREFIX):
value = cls.PREFIX + value
obj = str_type.__new__(cls, value)
return obj
def strip_digit_separators(number):
return (number.replace("_", "").replace(",", "")
if isinstance(number, string_types)
else number)
class HyInteger(HyObject, long_type):
"""
Internal representation of a Hy Integer. May raise a ValueError as if
int(foo) was called, given HyInteger(foo). On python 2.x long will
be used instead
"""
def __new__(cls, number, *args, **kwargs):
if isinstance(number, string_types):
number = strip_digit_separators(number)
bases = {"0x": 16, "0o": 8, "0b": 2}
for leader, base in bases.items():
if number.startswith(leader):
# We've got a string, known leader, set base.
number = long_type(number, base=base)
break
else:
# We've got a string, no known leader; base 10.
number = long_type(number, base=10)
else:
# We've got a non-string; convert straight.
number = long_type(number)
return super(HyInteger, cls).__new__(cls, number)
_wrappers[int] = HyInteger
if not PY3: # do not add long on python3
_wrappers[long_type] = HyInteger
class HyFloat(HyObject, float):
"""
Internal representation of a Hy Float. May raise a ValueError as if
float(foo) was called, given HyFloat(foo).
"""
def __new__(cls, number, *args, **kwargs):
number = float(strip_digit_separators(number))
return super(HyFloat, cls).__new__(cls, number)
_wrappers[float] = HyFloat
class HyComplex(HyObject, complex):
"""
Internal representation of a Hy Complex. May raise a ValueError as if
complex(foo) was called, given HyComplex(foo).
"""
def __new__(cls, number, *args, **kwargs):
number = complex(strip_digit_separators(number))
return super(HyComplex, cls).__new__(cls, number)
_wrappers[complex] = HyComplex
class HyList(HyObject, list):
"""
Hy List. Basically just a list.
"""
def replace(self, other):
for x in self:
replace_hy_obj(x, other)
HyObject.replace(self, other)
return self
def __add__(self, other):
return self.__class__(super(HyList, self).__add__(other))
def __getslice__(self, start, end):
return self.__class__(super(HyList, self).__getslice__(start, end))
def __getitem__(self, item):
ret = super(HyList, self).__getitem__(item)
if isinstance(item, slice):
return self.__class__(ret)
return ret
def __repr__(self):
return "[%s]" % (" ".join([repr(x) for x in self]))
_wrappers[list] = lambda l: HyList(wrap_value(x) for x in l)
_wrappers[tuple] = lambda t: HyList(wrap_value(x) for x in t)
class HyDict(HyList):
"""
HyDict (just a representation of a dict)
"""
def __repr__(self):
return "{%s}" % (" ".join([repr(x) for x in self]))
def keys(self):
return self[0::2]
def values(self):
return self[1::2]
def items(self):
return list(zip(self.keys(), self.values()))
_wrappers[dict] = lambda d: HyDict(wrap_value(x) for x in sum(d.items(), ()))
class HyExpression(HyList):
"""
Hy S-Expression. Basically just a list.
"""
def __repr__(self):
return "(%s)" % (" ".join([repr(x) for x in self]))
_wrappers[HyExpression] = lambda e: HyExpression(wrap_value(x) for x in e)
class HySet(HyList):
"""
Hy set (just a representation of a set)
"""
def __repr__(self):
return "#{%s}" % (" ".join([repr(x) for x in self]))
_wrappers[set] = lambda s: HySet(wrap_value(x) for x in s)
class HyCons(HyObject):
"""
HyCons: a cons object.
Building a HyCons of something and a HyList really builds a HyList
"""
__slots__ = ["car", "cdr"]
def __new__(cls, car, cdr):
if isinstance(cdr, list):
# Keep unquotes in the cdr of conses
if type(cdr) == HyExpression:
if len(cdr) > 0 and type(cdr[0]) == HySymbol:
if cdr[0] in ("unquote", "unquote_splice"):
return super(HyCons, cls).__new__(cls)
return cdr.__class__([wrap_value(car)] + cdr)
elif cdr is None:
return HyExpression([wrap_value(car)])
else:
return super(HyCons, cls).__new__(cls)
def __init__(self, car, cdr):
self.car = wrap_value(car)
self.cdr = wrap_value(cdr)
def __getitem__(self, n):
if n == 0:
return self.car
if n == slice(1, None):
return self.cdr
raise IndexError(
"Can only get the car ([0]) or the cdr ([1:]) of a HyCons")
def __setitem__(self, n, new):
if n == 0:
self.car = new
return
if n == slice(1, None):
self.cdr = new
return
raise IndexError(
"Can only set the car ([0]) or the cdr ([1:]) of a HyCons")
def __iter__(self):
yield self.car
try:
iterator = (i for i in self.cdr)
except TypeError:
if self.cdr is not None:
yield self.cdr
raise TypeError("Iteration on malformed cons")
else:
for i in iterator:
yield i
def replace(self, other):
if self.car is not None:
replace_hy_obj(self.car, other)
if self.cdr is not None:
replace_hy_obj(self.cdr, other)
HyObject.replace(self, other)
def __repr__(self):
if isinstance(self.cdr, self.__class__):
return "(%s %s)" % (repr(self.car), repr(self.cdr)[1:-1])
else:
return "(%s . %s)" % (repr(self.car), repr(self.cdr))
def __eq__(self, other):
return (
isinstance(other, self.__class__) and
self.car == other.car and
self.cdr == other.cdr
)

View File

@ -1,69 +0,0 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
class HyObject(object):
"""
Generic Hy Object model. This is helpful to inject things into all the
Hy lexing Objects at once.
"""
def replace(self, other):
if isinstance(other, HyObject):
for attr in ["start_line", "end_line",
"start_column", "end_column"]:
if not hasattr(self, attr) and hasattr(other, attr):
setattr(self, attr, getattr(other, attr))
else:
raise TypeError("Can't replace a non Hy object with a Hy object")
return self
_wrappers = {}
def wrap_value(x):
"""Wrap `x` into the corresponding Hy type.
This allows replace_hy_obj to convert a non Hy object to a Hy object.
This also allows a macro to return an unquoted expression transparently.
"""
wrapper = _wrappers.get(type(x))
if wrapper is None:
return x
else:
return wrapper(x)
def replace_hy_obj(obj, other):
if isinstance(obj, HyObject):
return obj.replace(other)
wrapped_obj = wrap_value(obj)
if isinstance(wrapped_obj, HyObject):
return wrapped_obj.replace(other)
else:
raise TypeError("Don't know how to wrap a %s object to a HyObject"
% type(obj))

View File

@ -1,37 +0,0 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models import HyObject, _wrappers
from hy._compat import string_types
class HyComplex(HyObject, complex):
"""
Internal representation of a Hy Complex. May raise a ValueError as if
complex(foo) was called, given HyComplex(foo).
"""
def __new__(cls, number, *args, **kwargs):
if isinstance(number, string_types):
number = number.replace("_", "").replace(",", "")
number = complex(number)
return super(HyComplex, cls).__new__(cls, number)
_wrappers[complex] = HyComplex

View File

@ -1,107 +0,0 @@
# Copyright (c) 2013 Nicolas Dandrimont <nicolas.dandrimont@crans.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models import HyObject, replace_hy_obj, wrap_value
from hy.models.expression import HyExpression
from hy.models.symbol import HySymbol
class HyCons(HyObject):
"""
HyCons: a cons object.
Building a HyCons of something and a HyList really builds a HyList
"""
__slots__ = ["car", "cdr"]
def __new__(cls, car, cdr):
if isinstance(cdr, list):
# Keep unquotes in the cdr of conses
if type(cdr) == HyExpression:
if len(cdr) > 0 and type(cdr[0]) == HySymbol:
if cdr[0] in ("unquote", "unquote_splice"):
return super(HyCons, cls).__new__(cls)
return cdr.__class__([wrap_value(car)] + cdr)
elif cdr is None:
return HyExpression([wrap_value(car)])
else:
return super(HyCons, cls).__new__(cls)
def __init__(self, car, cdr):
self.car = wrap_value(car)
self.cdr = wrap_value(cdr)
def __getitem__(self, n):
if n == 0:
return self.car
if n == slice(1, None):
return self.cdr
raise IndexError(
"Can only get the car ([0]) or the cdr ([1:]) of a HyCons")
def __setitem__(self, n, new):
if n == 0:
self.car = new
return
if n == slice(1, None):
self.cdr = new
return
raise IndexError(
"Can only set the car ([0]) or the cdr ([1:]) of a HyCons")
def __iter__(self):
yield self.car
try:
iterator = (i for i in self.cdr)
except TypeError:
if self.cdr is not None:
yield self.cdr
raise TypeError("Iteration on malformed cons")
else:
for i in iterator:
yield i
def replace(self, other):
if self.car is not None:
replace_hy_obj(self.car, other)
if self.cdr is not None:
replace_hy_obj(self.cdr, other)
HyObject.replace(self, other)
def __repr__(self):
if isinstance(self.cdr, self.__class__):
return "(%s %s)" % (repr(self.car), repr(self.cdr)[1:-1])
else:
return "(%s . %s)" % (repr(self.car), repr(self.cdr))
def __eq__(self, other):
return (
isinstance(other, self.__class__) and
self.car == other.car and
self.cdr == other.cdr
)

View File

@ -1,42 +0,0 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models import _wrappers, wrap_value
from hy.models.list import HyList
class HyDict(HyList):
"""
HyDict (just a representation of a dict)
"""
def __repr__(self):
return "{%s}" % (" ".join([repr(x) for x in self]))
def keys(self):
return self[0::2]
def values(self):
return self[1::2]
def items(self):
return list(zip(self.keys(), self.values()))
_wrappers[dict] = lambda d: HyDict(wrap_value(x) for x in sum(d.items(), ()))

View File

@ -1,33 +0,0 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models import _wrappers, wrap_value
from hy.models.list import HyList
class HyExpression(HyList):
"""
Hy S-Expression. Basically just a list.
"""
def __repr__(self):
return "(%s)" % (" ".join([repr(x) for x in self]))
_wrappers[HyExpression] = lambda e: HyExpression(wrap_value(x) for x in e)

View File

@ -1,37 +0,0 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models import HyObject, _wrappers
from hy._compat import string_types
class HyFloat(HyObject, float):
"""
Internal representation of a Hy Float. May raise a ValueError as if
float(foo) was called, given HyFloat(foo).
"""
def __new__(cls, number, *args, **kwargs):
if isinstance(number, string_types):
number = number.replace("_", "").replace(",", "")
number = float(number)
return super(HyFloat, cls).__new__(cls, number)
_wrappers[float] = HyFloat

View File

@ -1,55 +0,0 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models import HyObject, _wrappers
from hy._compat import long_type, string_types
import sys
class HyInteger(HyObject, long_type):
"""
Internal representation of a Hy Integer. May raise a ValueError as if
int(foo) was called, given HyInteger(foo). On python 2.x long will
be used instead
"""
def __new__(cls, number, *args, **kwargs):
if isinstance(number, string_types):
number = number.replace("_", "").replace(",", "")
bases = {"0x": 16, "0o": 8, "0b": 2}
for leader, base in bases.items():
if number.startswith(leader):
# We've got a string, known leader, set base.
number = long_type(number, base=base)
break
else:
# We've got a string, no known leader; base 10.
number = long_type(number, base=10)
else:
# We've got a non-string; convert straight.
number = long_type(number)
return super(HyInteger, cls).__new__(cls, number)
_wrappers[int] = HyInteger
if sys.version_info[0] < 3: # do not add long on python3
_wrappers[long_type] = HyInteger

View File

@ -1,39 +0,0 @@
# Copyright (c) 2013 Gergely Nagy <algernon@madhouse-project.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from __future__ import unicode_literals
from hy.models import HyObject
from hy._compat import str_type
KEYWORD_PREFIX = "\uFDD0"
class HyKeyword(HyObject, str_type):
"""Generic Hy Keyword object. It's either a ``str`` or a ``unicode``,
depending on the Python version.
"""
def __new__(cls, value):
if not value.startswith(KEYWORD_PREFIX):
value = KEYWORD_PREFIX + value
obj = str_type.__new__(cls, value)
return obj

View File

@ -1,54 +0,0 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models import HyObject, replace_hy_obj, _wrappers, wrap_value
class HyList(HyObject, list):
"""
Hy List. Basically just a list.
"""
def replace(self, other):
for x in self:
replace_hy_obj(x, other)
HyObject.replace(self, other)
return self
def __add__(self, other):
return self.__class__(super(HyList, self).__add__(other))
def __getslice__(self, start, end):
return self.__class__(super(HyList, self).__getslice__(start, end))
def __getitem__(self, item):
ret = super(HyList, self).__getitem__(item)
if isinstance(item, slice):
return self.__class__(ret)
return ret
def __repr__(self):
return "[%s]" % (" ".join([repr(x) for x in self]))
_wrappers[list] = lambda l: HyList(wrap_value(x) for x in l)
_wrappers[tuple] = lambda t: HyList(wrap_value(x) for x in t)

View File

@ -1,33 +0,0 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models import _wrappers, wrap_value
from hy.models.list import HyList
class HySet(HyList):
"""
Hy set (just a representation of a set)
"""
def __repr__(self):
return "#{%s}" % (" ".join([repr(x) for x in self]))
_wrappers[set] = lambda s: HySet(wrap_value(x) for x in s)

View File

@ -1,33 +0,0 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models import HyObject, _wrappers
from hy._compat import str_type
class HyString(HyObject, str_type):
"""
Generic Hy String object. Helpful to store string literals from Hy
scripts. It's either a ``str`` or a ``unicode``, depending on the
Python version.
"""
pass
_wrappers[str_type] = HyString

View File

@ -1,34 +0,0 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models import _wrappers
from hy.models.string import HyString
class HySymbol(HyString):
"""
Hy Symbol. Basically a String.
"""
def __init__(self, string):
self += string
_wrappers[bool] = lambda x: HySymbol("True") if x else HySymbol("False")
_wrappers[type(None)] = lambda foo: HySymbol("None")

View File

@ -23,10 +23,7 @@ import ast
import sys import sys
from hy import compiler from hy import compiler
from hy.models.expression import HyExpression from hy.models import HyExpression, HyList, HySymbol, HyInteger
from hy.models.list import HyList
from hy.models.symbol import HySymbol
from hy.models.integer import HyInteger
from hy._compat import PY33 from hy._compat import PY33
if sys.version_info[0] <= 2 and sys.version_info[1] <= 6: if sys.version_info[0] <= 2 and sys.version_info[1] <= 6:

View File

@ -19,17 +19,8 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE. # DEALINGS IN THE SOFTWARE.
from hy.models.expression import HyExpression from hy.models import (HyExpression, HyInteger, HyFloat, HyComplex, HySymbol,
from hy.models.integer import HyInteger HyString, HyDict, HyList, HySet, HyCons)
from hy.models.float import HyFloat
from hy.models.complex import HyComplex
from hy.models.symbol import HySymbol
from hy.models.string import HyString
from hy.models.dict import HyDict
from hy.models.list import HyList
from hy.models.set import HySet
from hy.models.cons import HyCons
from hy.lex import LexException, PrematureEndOfInput, tokenize from hy.lex import LexException, PrematureEndOfInput, tokenize

View File

@ -2,10 +2,7 @@
from hy.macros import macro, macroexpand from hy.macros import macro, macroexpand
from hy.lex import tokenize from hy.lex import tokenize
from hy.models.string import HyString from hy.models import HyString, HyList, HySymbol, HyExpression
from hy.models.list import HyList
from hy.models.symbol import HySymbol
from hy.models.expression import HyExpression
from hy.errors import HyMacroExpansionError from hy.errors import HyMacroExpansionError
from hy.compiler import HyASTCompiler from hy.compiler import HyASTCompiler

View File

@ -1,56 +0,0 @@
# Copyright (c) 2013 Nicolas Dandrimont <nicolas.dandrimont@crans.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models.cons import HyCons
def test_cons_slicing():
"""Check that cons slicing works as expected"""
cons = HyCons("car", "cdr")
assert cons[0] == "car"
assert cons[1:] == "cdr"
try:
cons[:]
assert True is False
except IndexError:
pass
try:
cons[1]
assert True is False
except IndexError:
pass
def test_cons_replacing():
"""Check that assigning to a cons works as expected"""
cons = HyCons("foo", "bar")
cons[0] = "car"
assert cons == HyCons("car", "bar")
cons[1:] = "cdr"
assert cons == HyCons("car", "cdr")
try:
cons[:] = "foo"
assert True is False
except IndexError:
pass

View File

@ -1,16 +0,0 @@
from hy.models.dict import HyDict
hydict = HyDict(["a", 1, "b", 2, "c", 3])
def test_dict_items():
assert hydict.items() == [("a", 1), ("b", 2), ("c", 3)]
def test_dict_keys():
assert hydict.keys() == ["a", "b", "c"]
def test_dict_values():
assert hydict.values() == [1, 2, 3]

View File

@ -1,22 +0,0 @@
from hy.models.list import HyList
def test_list_add():
"""Check that adding two HyLists generates a HyList"""
a = HyList([1, 2, 3])
b = HyList([3, 4, 5])
c = a + b
assert c == [1, 2, 3, 3, 4, 5]
assert c.__class__ == HyList
def test_list_slice():
"""Check that slicing a HyList produces a HyList"""
a = HyList([1, 2, 3, 4])
sl1 = a[1:]
sl5 = a[5:]
assert type(sl1) == HyList
assert sl1 == HyList([2, 3, 4])
assert type(sl5) == HyList
assert sl5 == HyList([])

View File

@ -1,26 +0,0 @@
from hy._compat import long_type, str_type
from hy.models.string import HyString
from hy.models.integer import HyInteger
from hy.models.list import HyList
from hy.models import replace_hy_obj
def test_replace_long_type():
""" Test replacing integers."""
replaced = replace_hy_obj(long_type(0), HyInteger(13))
assert replaced == HyInteger(0)
def test_replace_string_type():
"""Test replacing python string"""
replaced = replace_hy_obj(str_type("foo"), HyString("bar"))
assert replaced == HyString("foo")
def test_replace_tuple():
""" Test replacing tuples."""
replaced = replace_hy_obj((long_type(0), ), HyInteger(13))
assert type(replaced) == HyList
assert type(replaced[0]) == HyInteger
assert replaced == HyList([HyInteger(0)])

View File

@ -1,8 +0,0 @@
from hy.models.set import HySet
hyset = HySet([3, 1, 2, 2])
def test_set():
assert hyset == [3, 1, 2, 2]

View File

@ -1,28 +0,0 @@
from hy._compat import long_type
from hy.models.integer import HyInteger
from hy.models.list import HyList
from hy.models.expression import HyExpression
from hy.models import wrap_value
def test_wrap_long_type():
""" Test conversion of integers."""
wrapped = wrap_value(long_type(0))
assert type(wrapped) == HyInteger
def test_wrap_tuple():
""" Test conversion of tuples."""
wrapped = wrap_value((HyInteger(0),))
assert type(wrapped) == HyList
assert type(wrapped[0]) == HyInteger
assert wrapped == HyList([HyInteger(0)])
def test_wrap_nested_expr():
""" Test conversion of HyExpressions with embedded non-HyObjects."""
wrapped = wrap_value(HyExpression([long_type(0)]))
assert type(wrapped) == HyExpression
assert type(wrapped[0]) == HyInteger
assert wrapped == HyExpression([HyInteger(0)])

View File

@ -241,7 +241,7 @@
(defn test-gensym [] (defn test-gensym []
"NATIVE: testing the gensym function" "NATIVE: testing the gensym function"
(import [hy.models.symbol [HySymbol]]) (import [hy.models [HySymbol]])
(setv s1 (gensym)) (setv s1 (gensym))
(assert (isinstance s1 HySymbol)) (assert (isinstance s1 HySymbol))
(assert (= 0 (.find s1 ":G_"))) (assert (= 0 (.find s1 ":G_")))

View File

@ -1363,7 +1363,7 @@
(if-python2 (if-python2
(import [StringIO [StringIO]]) (import [StringIO [StringIO]])
(import [io [StringIO]])) (import [io [StringIO]]))
(import [hy.models.expression [HyExpression]]) (import [hy.models [HyExpression]])
(def stdin-buffer (StringIO "(+ 2 2)\n(- 2 2)")) (def stdin-buffer (StringIO "(+ 2 2)\n(- 2 2)"))
(assert (= (eval (read stdin-buffer)) 4)) (assert (= (eval (read stdin-buffer)) 4))

123
tests/test_models.py Normal file
View File

@ -0,0 +1,123 @@
from hy._compat import long_type, str_type
from hy.models import (wrap_value, replace_hy_obj, HyString, HyInteger, HyList,
HyDict, HySet, HyExpression, HyCons)
def test_wrap_long_type():
""" Test conversion of integers."""
wrapped = wrap_value(long_type(0))
assert type(wrapped) == HyInteger
def test_wrap_tuple():
""" Test conversion of tuples."""
wrapped = wrap_value((HyInteger(0),))
assert type(wrapped) == HyList
assert type(wrapped[0]) == HyInteger
assert wrapped == HyList([HyInteger(0)])
def test_wrap_nested_expr():
""" Test conversion of HyExpressions with embedded non-HyObjects."""
wrapped = wrap_value(HyExpression([long_type(0)]))
assert type(wrapped) == HyExpression
assert type(wrapped[0]) == HyInteger
assert wrapped == HyExpression([HyInteger(0)])
def test_replace_long_type():
""" Test replacing integers."""
replaced = replace_hy_obj(long_type(0), HyInteger(13))
assert replaced == HyInteger(0)
def test_replace_string_type():
"""Test replacing python string"""
replaced = replace_hy_obj(str_type("foo"), HyString("bar"))
assert replaced == HyString("foo")
def test_replace_tuple():
""" Test replacing tuples."""
replaced = replace_hy_obj((long_type(0), ), HyInteger(13))
assert type(replaced) == HyList
assert type(replaced[0]) == HyInteger
assert replaced == HyList([HyInteger(0)])
def test_list_add():
"""Check that adding two HyLists generates a HyList"""
a = HyList([1, 2, 3])
b = HyList([3, 4, 5])
c = a + b
assert c == [1, 2, 3, 3, 4, 5]
assert c.__class__ == HyList
def test_list_slice():
"""Check that slicing a HyList produces a HyList"""
a = HyList([1, 2, 3, 4])
sl1 = a[1:]
sl5 = a[5:]
assert type(sl1) == HyList
assert sl1 == HyList([2, 3, 4])
assert type(sl5) == HyList
assert sl5 == HyList([])
hydict = HyDict(["a", 1, "b", 2, "c", 3])
def test_dict_items():
assert hydict.items() == [("a", 1), ("b", 2), ("c", 3)]
def test_dict_keys():
assert hydict.keys() == ["a", "b", "c"]
def test_dict_values():
assert hydict.values() == [1, 2, 3]
hyset = HySet([3, 1, 2, 2])
def test_set():
assert hyset == [3, 1, 2, 2]
def test_cons_slicing():
"""Check that cons slicing works as expected"""
cons = HyCons("car", "cdr")
assert cons[0] == "car"
assert cons[1:] == "cdr"
try:
cons[:]
assert True is False
except IndexError:
pass
try:
cons[1]
assert True is False
except IndexError:
pass
def test_cons_replacing():
"""Check that assigning to a cons works as expected"""
cons = HyCons("foo", "bar")
cons[0] = "car"
assert cons == HyCons("car", "bar")
cons[1:] = "cdr"
assert cons == HyCons("car", "cdr")
try:
cons[:] = "foo"
assert True is False
except IndexError:
pass