Merge branch 'pr/829'

This commit is contained in:
Berker Peksag 2015-07-15 00:00:01 +03:00
commit 144ee3b2f0
9 changed files with 112 additions and 2 deletions

View File

@ -198,6 +198,8 @@ Hy. Let's experiment with this in the hy interpreter::
{'dog': 'bark', 'cat': 'meow'}
=> (, 1 2 3)
(1, 2, 3)
=> #{3 1 2}
{1, 2, 3}
If you are familiar with other Lisps, you may be interested that Hy
supports the Common Lisp method of quoting:

View File

@ -31,6 +31,7 @@ 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

View File

@ -32,6 +32,7 @@ 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
@ -628,7 +629,7 @@ class HyASTCompiler(object):
name = form.__class__.__name__
imports = set([name])
if isinstance(form, (HyList, HyDict)):
if isinstance(form, (HyList, HyDict, HySet)):
if not form:
contents = HyList()
else:
@ -1974,6 +1975,31 @@ class HyASTCompiler(object):
col_offset=expression.start_column)
return ret
@builds(HySet)
def compile_set(self, expression):
elts, ret, _ = self._compile_collect(expression)
if PY27:
ret += ast.Set(elts=elts,
ctx=ast.Load(),
lineno=expression.start_line,
col_offset=expression.start_column)
else:
ret += ast.Call(func=ast.Name(id='set',
ctx=ast.Load(),
lineno=expression.start_line,
col_offset=expression.start_column),
args=[
ast.List(elts=elts,
ctx=ast.Load(),
lineno=expression.start_line,
col_offset=expression.start_column)],
keywords=[],
starargs=None,
kwargs=None,
lineno=expression.start_line,
col_offset=expression.start_column)
return ret
@builds("lambda")
@builds("fn")
@checkargs(min=1)

View File

@ -35,12 +35,13 @@ lg.add('LBRACKET', r'\[')
lg.add('RBRACKET', r'\]')
lg.add('LCURLY', r'\{')
lg.add('RCURLY', r'\}')
lg.add('HLCURLY', r'#\{')
lg.add('QUOTE', r'\'%s' % end_quote)
lg.add('QUASIQUOTE', r'`%s' % end_quote)
lg.add('UNQUOTESPLICE', r'~@%s' % end_quote)
lg.add('UNQUOTE', r'~%s' % end_quote)
lg.add('HASHBANG', r'#!.*[^\r\n]')
lg.add('HASHREADER', r'#.')
lg.add('HASHREADER', r'#[^{]')
# A regexp which matches incomplete strings, used to support
# multi-line strings in the interpreter

View File

@ -31,6 +31,7 @@ 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
@ -152,6 +153,7 @@ def list_contents_single(p):
@pg.production("term : paren")
@pg.production("term : dict")
@pg.production("term : list")
@pg.production("term : set")
@pg.production("term : string")
def term(p):
return p[0]
@ -190,6 +192,18 @@ def hash_reader(p):
return HyExpression([HySymbol("dispatch_reader_macro"), str_object, expr])
@pg.production("set : HLCURLY list_contents RCURLY")
@set_boundaries
def t_set(p):
return HySet(p[1])
@pg.production("set : HLCURLY RCURLY")
@set_boundaries
def empty_set(p):
return HySet([])
@pg.production("dict : LCURLY list_contents RCURLY")
@set_boundaries
def t_dict(p):

36
hy/models/set.py Normal file
View File

@ -0,0 +1,36 @@
# 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.list import HyList
from functools import reduce
class HySet(HyList):
"""
Hy set (actually a list that pretends to be a set)
"""
def __init__(self, items):
items = sorted(items)
items = list(reduce(lambda r, v: v in r and r or r+[v], items, []))
super(HySet, self).__init__(items)
def __repr__(self):
return "#{%s}" % (" ".join([repr(x) for x in self]))

View File

@ -27,6 +27,7 @@ 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
@ -202,6 +203,21 @@ def test_dicts():
])]
def test_sets():
""" Ensure that we can tokenize a set. """
objs = tokenize("#{1 2}")
assert objs == [HySet([HyInteger(1), HyInteger(2)])]
objs = tokenize("(bar #{foo bar baz})")
assert objs == [HyExpression([HySymbol("bar"),
HySet(["foo", "bar", "baz"])])]
objs = tokenize("#{(foo bar) (baz quux)}")
assert objs == [HySet([
HyExpression([HySymbol("foo"), HySymbol("bar")]),
HyExpression([HySymbol("baz"), HySymbol("quux")])
])]
def test_nospace():
""" Ensure we can tokenize without spaces if we have to """
entry = tokenize("(foo(one two))")[0]

8
tests/models/test_set.py Normal file
View File

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

View File

@ -23,6 +23,12 @@
(assert (= {1 2 3 4} {1 (+ 1 1) 3 (+ 2 2)})))
(defn test-sets []
"NATIVE: test sets work right"
(assert (= #{1 2 3 4} (| #{1 2} #{3 4})))
(assert (= #{} (set))))
(defn test-setv-get []
"NATIVE: test setv works on a get expression"
(setv foo [0 1 2])