Merge branch 'pr/829'
This commit is contained in:
commit
144ee3b2f0
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
36
hy/models/set.py
Normal 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]))
|
@ -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
8
tests/models/test_set.py
Normal 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]
|
@ -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])
|
||||
|
Loading…
Reference in New Issue
Block a user