Merge branch 'master' into pr/185

Conflicts:
	hy/macros.py
	tests/compilers/test_compiler.py

Hoodoggy!
This commit is contained in:
Paul Tagliamonte 2013-05-17 11:17:51 -04:00
commit 9c28e0292d
9 changed files with 98 additions and 54 deletions

View File

@ -99,7 +99,7 @@ def builds(_type):
unpythonic_chars = ["-"]
really_ok = ["-"]
if True in (x in str_type(_type) for x in unpythonic_chars):
if any(x in unpythonic_chars for x in str_type(_type)):
if _type not in really_ok:
raise TypeError("`build' needs to be *post* translated strings, "
"Mr. / Mrs. Hypser. -- `%s' sucks." % (_type))
@ -422,22 +422,24 @@ class HyASTCompiler(object):
if isinstance(expr, HyLambdaListKeyword):
if expr not in expr._valid_types:
raise HyCompileError("{0} is not a valid "
"lambda-keyword.".format(repr(expr)))
raise HyTypeError(expr, "{0} is not a valid "
"lambda-keyword.".format(repr(expr)))
if expr == "&rest" and lambda_keyword is None:
lambda_keyword = expr
elif expr == "&optional":
if len(defaults) > 0:
raise HyCompileError("There can only be &optional "
"arguments or one &key argument")
raise HyTypeError(expr,
"There can only be &optional "
"arguments or one &key argument")
lambda_keyword = expr
elif expr == "&key":
lambda_keyword = expr
elif expr == "&kwargs":
lambda_keyword = expr
else:
raise HyCompileError("{0} is in an invalid "
"position.".format(repr(expr)))
raise HyTypeError(expr,
"{0} is in an invalid "
"position.".format(repr(expr)))
# we don't actually care about this token, so we set
# our state and continue to the next token...
continue
@ -446,28 +448,33 @@ class HyASTCompiler(object):
args.append(expr)
elif lambda_keyword == "&rest":
if varargs:
raise HyCompileError("There can only be one "
"&rest argument")
raise HyTypeError(expr,
"There can only be one "
"&rest argument")
varargs = str(expr)
elif lambda_keyword == "&key":
if type(expr) != HyDict:
raise TypeError("There can only be one &key "
"argument")
raise HyTypeError(expr,
"There can only be one &key "
"argument")
else:
if len(defaults) > 0:
raise HyCompileError("There can only be &optional "
"arguments or one &key argument")
raise HyTypeError(expr,
"There can only be &optional "
"arguments or one &key argument")
# As you can see, Python has a funny way of
# defining keyword arguments.
for k, v in expr.items():
it = iter(expr)
for k, v in zip(it, it):
args.append(k)
ret += self.compile(v)
defaults.append(ret.force_expr)
elif lambda_keyword == "&optional":
if isinstance(expr, HyList):
if not len(expr) == 2:
raise TypeError("optional args should be bare names "
"or 2-item lists")
raise HyTypeError(expr,
"optional args should be bare names "
"or 2-item lists")
k, v = expr
else:
k = expr
@ -477,8 +484,9 @@ class HyASTCompiler(object):
defaults.append(ret.force_expr)
elif lambda_keyword == "&kwargs":
if kwargs:
raise HyCompileError("There can only be one "
"&kwargs argument")
raise HyTypeError(expr,
"There can only be one "
"&kwargs argument")
kwargs = str(expr)
return ret, args, defaults, varargs, kwargs
@ -546,7 +554,7 @@ class HyASTCompiler(object):
name = form.__class__.__name__
imports = set([name])
if isinstance(form, HyList):
if isinstance(form, (HyList, HyDict)):
if not form:
contents = HyList()
else:
@ -764,7 +772,8 @@ class HyASTCompiler(object):
@builds("except")
@builds("catch")
def magic_internal_form(self, expr):
raise TypeError("Error: `%s' can't be used like that." % (expr[0]))
raise HyTypeError(expr,
"Error: `%s' can't be used like that." % (expr[0]))
def _compile_catch_expression(self, expr, var):
catch = expr.pop(0) # catch
@ -796,6 +805,11 @@ class HyASTCompiler(object):
# let's pop variable and use it as name
if len(exceptions) == 2:
name = exceptions.pop(0)
if not isinstance(name, HySymbol):
raise HyTypeError(
exceptions,
"Exception storage target name must be a symbol.")
if sys.version_info[0] >= 3:
# Python3 features a change where the Exception handler
# moved the name from a Name() to a pure Python String type.
@ -1694,7 +1708,7 @@ class HyASTCompiler(object):
@builds(HyDict)
def compile_dict(self, m):
keyvalues, ret = self._compile_collect(sum(m.items(), ()))
keyvalues, ret = self._compile_collect(m)
ret += ast.Dict(lineno=m.start_line,
col_offset=m.start_column,

View File

@ -228,9 +228,7 @@ class Dict(ListeyThing):
def exit(self):
self.commit()
it = iter(self.nodes)
result = dict(zip(it, it))
self.result = HyDict(result)
self.result = HyDict(self.nodes)
end_char = "}"

View File

@ -20,7 +20,6 @@
from hy.models.expression import HyExpression
from hy.models.string import HyString
from hy.models.dict import HyDict
from hy.models.list import HyList
from collections import defaultdict
@ -65,15 +64,8 @@ def process(tree, module_name):
ntree.replace(tree)
return ntree
if isinstance(tree, HyDict):
obj = HyDict(dict((process(x, module_name),
process(tree[x], module_name))
for x in tree))
obj.replace(tree)
return obj
if isinstance(tree, HyList):
obj = HyList([process(x, module_name) for x in tree]) # NOQA
obj = tree.__class__([process(x, module_name) for x in tree]) # NOQA
# flake8 thinks we're redefining from 52.
obj.replace(tree)
return obj

View File

@ -18,17 +18,13 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models import HyObject
from hy.models.list import HyList
class HyDict(HyObject, dict):
class HyDict(HyList):
"""
HyDict (just a dict)
HyDict (just a representation of a dict)
"""
def replace(self, other):
for x in self:
self[x].replace(other)
x.replace(other)
HyObject.replace(self, other)
def __repr__(self):
return "{%s}" % (" ".join([repr(x) for x in self]))

View File

@ -22,7 +22,7 @@
from __future__ import unicode_literals
from hy import HyString
from hy.compiler import hy_compile, HyCompileError
from hy.compiler import hy_compile, HyCompileError, HyTypeError
from hy.lex import tokenize
import ast
@ -47,8 +47,11 @@ def cant_compile(expr):
try:
hy_compile(expr, "__main__")
assert False
except HyCompileError:
pass
except HyCompileError as e:
# Anything that can't be compiled should raise a user friendly
# error, otherwise it's a compiler bug.
assert isinstance(e.exception, HyTypeError)
assert e.traceback
def test_ast_bad_type():

View File

@ -27,11 +27,21 @@ if sys.version_info[0] <= 2 and sys.version_info[1] <= 6:
else:
import unittest
from hy import compiler
from hy.models.expression import HyExpression
from hy.models.list import HyList
from hy.models.symbol import HySymbol
from hy.compiler import HyASTCompiler
class CompilerTest(unittest.TestCase):
def test_builds_with_dash(self):
self.assert_(callable(compiler.builds("foobar")))
self.assert_(callable(compiler.builds("foo_bar")))
self.assert_(callable(compiler.builds("-")))
self.assertRaisesRegexp(TypeError,
"\*post\* translated strings",
compiler.builds, "foobar-with-dash-")
class HyASTCompilerTest(unittest.TestCase):
@ -46,7 +56,7 @@ class HyASTCompilerTest(unittest.TestCase):
return h
def setUp(self):
self.c = HyASTCompiler('')
self.c = compiler.HyASTCompiler('test')
def test_fn_compiler_empty_function(self):
ret = self.c.compile_function_def(

View File

@ -185,15 +185,18 @@ def test_lex_line_counting_multi_inner():
def test_dicts():
""" Ensure that we can tokenize a dict. """
objs = tokenize("{foo bar bar baz}")
assert objs == [HyDict({
"foo": "bar",
"bar": "baz"
})]
assert objs == [HyDict(["foo", "bar", "bar", "baz"])]
objs = tokenize("(bar {foo bar bar baz})")
assert objs == [HyExpression([HySymbol("bar"),
HyDict({"foo": "bar",
"bar": "baz"})])]
HyDict(["foo", "bar",
"bar", "baz"])])]
objs = tokenize("{(foo bar) (baz quux)}")
assert objs == [HyDict([
HyExpression([HySymbol("foo"), HySymbol("bar")]),
HyExpression([HySymbol("baz"), HySymbol("quux")])
])]
def test_nospace():

View File

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

View File

@ -1,3 +1,6 @@
(import hy)
(defn test-quote []
"NATIVE: test for quoting functionality"
(setf q (quote (a b c)))
@ -21,6 +24,25 @@
(assert (= (cdr q1) (quote (a b c)))))
(defn test-quote-dicts []
"NATIVE: test quoting dicts"
(setf q (quote {foo bar baz quux}))
(assert (= (len q) 4))
(assert (= (get q 0) (quote foo)))
(assert (= (get q 1) (quote bar)))
(assert (= (get q 2) (quote baz)))
(assert (= (get q 3) (quote quux)))
(assert (= (type q) hy.HyDict)))
(defn test-quote-expr-in-dict []
"NATIVE: test quoting nested exprs in dict"
(setf q (quote {(foo bar) 0}))
(assert (= (len q) 2))
(setf qq (get q 0))
(assert (= qq (quote (foo bar)))))
(defn test-quasiquote []
"NATIVE: test that quasiquote and quote are equivalent for simple cases"
(setf q (quote (a b c)))