Merge branch 'master' into pr/185
Conflicts: hy/macros.py tests/compilers/test_compiler.py Hoodoggy!
This commit is contained in:
commit
9c28e0292d
@ -99,7 +99,7 @@ def builds(_type):
|
|||||||
|
|
||||||
unpythonic_chars = ["-"]
|
unpythonic_chars = ["-"]
|
||||||
really_ok = ["-"]
|
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:
|
if _type not in really_ok:
|
||||||
raise TypeError("`build' needs to be *post* translated strings, "
|
raise TypeError("`build' needs to be *post* translated strings, "
|
||||||
"Mr. / Mrs. Hypser. -- `%s' sucks." % (_type))
|
"Mr. / Mrs. Hypser. -- `%s' sucks." % (_type))
|
||||||
@ -422,22 +422,24 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
if isinstance(expr, HyLambdaListKeyword):
|
if isinstance(expr, HyLambdaListKeyword):
|
||||||
if expr not in expr._valid_types:
|
if expr not in expr._valid_types:
|
||||||
raise HyCompileError("{0} is not a valid "
|
raise HyTypeError(expr, "{0} is not a valid "
|
||||||
"lambda-keyword.".format(repr(expr)))
|
"lambda-keyword.".format(repr(expr)))
|
||||||
if expr == "&rest" and lambda_keyword is None:
|
if expr == "&rest" and lambda_keyword is None:
|
||||||
lambda_keyword = expr
|
lambda_keyword = expr
|
||||||
elif expr == "&optional":
|
elif expr == "&optional":
|
||||||
if len(defaults) > 0:
|
if len(defaults) > 0:
|
||||||
raise HyCompileError("There can only be &optional "
|
raise HyTypeError(expr,
|
||||||
"arguments or one &key argument")
|
"There can only be &optional "
|
||||||
|
"arguments or one &key argument")
|
||||||
lambda_keyword = expr
|
lambda_keyword = expr
|
||||||
elif expr == "&key":
|
elif expr == "&key":
|
||||||
lambda_keyword = expr
|
lambda_keyword = expr
|
||||||
elif expr == "&kwargs":
|
elif expr == "&kwargs":
|
||||||
lambda_keyword = expr
|
lambda_keyword = expr
|
||||||
else:
|
else:
|
||||||
raise HyCompileError("{0} is in an invalid "
|
raise HyTypeError(expr,
|
||||||
"position.".format(repr(expr)))
|
"{0} is in an invalid "
|
||||||
|
"position.".format(repr(expr)))
|
||||||
# we don't actually care about this token, so we set
|
# we don't actually care about this token, so we set
|
||||||
# our state and continue to the next token...
|
# our state and continue to the next token...
|
||||||
continue
|
continue
|
||||||
@ -446,28 +448,33 @@ class HyASTCompiler(object):
|
|||||||
args.append(expr)
|
args.append(expr)
|
||||||
elif lambda_keyword == "&rest":
|
elif lambda_keyword == "&rest":
|
||||||
if varargs:
|
if varargs:
|
||||||
raise HyCompileError("There can only be one "
|
raise HyTypeError(expr,
|
||||||
"&rest argument")
|
"There can only be one "
|
||||||
|
"&rest argument")
|
||||||
varargs = str(expr)
|
varargs = str(expr)
|
||||||
elif lambda_keyword == "&key":
|
elif lambda_keyword == "&key":
|
||||||
if type(expr) != HyDict:
|
if type(expr) != HyDict:
|
||||||
raise TypeError("There can only be one &key "
|
raise HyTypeError(expr,
|
||||||
"argument")
|
"There can only be one &key "
|
||||||
|
"argument")
|
||||||
else:
|
else:
|
||||||
if len(defaults) > 0:
|
if len(defaults) > 0:
|
||||||
raise HyCompileError("There can only be &optional "
|
raise HyTypeError(expr,
|
||||||
"arguments or one &key argument")
|
"There can only be &optional "
|
||||||
|
"arguments or one &key argument")
|
||||||
# As you can see, Python has a funny way of
|
# As you can see, Python has a funny way of
|
||||||
# defining keyword arguments.
|
# defining keyword arguments.
|
||||||
for k, v in expr.items():
|
it = iter(expr)
|
||||||
|
for k, v in zip(it, it):
|
||||||
args.append(k)
|
args.append(k)
|
||||||
ret += self.compile(v)
|
ret += self.compile(v)
|
||||||
defaults.append(ret.force_expr)
|
defaults.append(ret.force_expr)
|
||||||
elif lambda_keyword == "&optional":
|
elif lambda_keyword == "&optional":
|
||||||
if isinstance(expr, HyList):
|
if isinstance(expr, HyList):
|
||||||
if not len(expr) == 2:
|
if not len(expr) == 2:
|
||||||
raise TypeError("optional args should be bare names "
|
raise HyTypeError(expr,
|
||||||
"or 2-item lists")
|
"optional args should be bare names "
|
||||||
|
"or 2-item lists")
|
||||||
k, v = expr
|
k, v = expr
|
||||||
else:
|
else:
|
||||||
k = expr
|
k = expr
|
||||||
@ -477,8 +484,9 @@ class HyASTCompiler(object):
|
|||||||
defaults.append(ret.force_expr)
|
defaults.append(ret.force_expr)
|
||||||
elif lambda_keyword == "&kwargs":
|
elif lambda_keyword == "&kwargs":
|
||||||
if kwargs:
|
if kwargs:
|
||||||
raise HyCompileError("There can only be one "
|
raise HyTypeError(expr,
|
||||||
"&kwargs argument")
|
"There can only be one "
|
||||||
|
"&kwargs argument")
|
||||||
kwargs = str(expr)
|
kwargs = str(expr)
|
||||||
|
|
||||||
return ret, args, defaults, varargs, kwargs
|
return ret, args, defaults, varargs, kwargs
|
||||||
@ -546,7 +554,7 @@ class HyASTCompiler(object):
|
|||||||
name = form.__class__.__name__
|
name = form.__class__.__name__
|
||||||
imports = set([name])
|
imports = set([name])
|
||||||
|
|
||||||
if isinstance(form, HyList):
|
if isinstance(form, (HyList, HyDict)):
|
||||||
if not form:
|
if not form:
|
||||||
contents = HyList()
|
contents = HyList()
|
||||||
else:
|
else:
|
||||||
@ -764,7 +772,8 @@ class HyASTCompiler(object):
|
|||||||
@builds("except")
|
@builds("except")
|
||||||
@builds("catch")
|
@builds("catch")
|
||||||
def magic_internal_form(self, expr):
|
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):
|
def _compile_catch_expression(self, expr, var):
|
||||||
catch = expr.pop(0) # catch
|
catch = expr.pop(0) # catch
|
||||||
@ -796,6 +805,11 @@ class HyASTCompiler(object):
|
|||||||
# let's pop variable and use it as name
|
# let's pop variable and use it as name
|
||||||
if len(exceptions) == 2:
|
if len(exceptions) == 2:
|
||||||
name = exceptions.pop(0)
|
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:
|
if sys.version_info[0] >= 3:
|
||||||
# Python3 features a change where the Exception handler
|
# Python3 features a change where the Exception handler
|
||||||
# moved the name from a Name() to a pure Python String type.
|
# moved the name from a Name() to a pure Python String type.
|
||||||
@ -1694,7 +1708,7 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
@builds(HyDict)
|
@builds(HyDict)
|
||||||
def compile_dict(self, m):
|
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,
|
ret += ast.Dict(lineno=m.start_line,
|
||||||
col_offset=m.start_column,
|
col_offset=m.start_column,
|
||||||
|
@ -228,9 +228,7 @@ class Dict(ListeyThing):
|
|||||||
|
|
||||||
def exit(self):
|
def exit(self):
|
||||||
self.commit()
|
self.commit()
|
||||||
it = iter(self.nodes)
|
self.result = HyDict(self.nodes)
|
||||||
result = dict(zip(it, it))
|
|
||||||
self.result = HyDict(result)
|
|
||||||
|
|
||||||
end_char = "}"
|
end_char = "}"
|
||||||
|
|
||||||
|
10
hy/macros.py
10
hy/macros.py
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
from hy.models.expression import HyExpression
|
from hy.models.expression import HyExpression
|
||||||
from hy.models.string import HyString
|
from hy.models.string import HyString
|
||||||
from hy.models.dict import HyDict
|
|
||||||
from hy.models.list import HyList
|
from hy.models.list import HyList
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
@ -65,15 +64,8 @@ def process(tree, module_name):
|
|||||||
ntree.replace(tree)
|
ntree.replace(tree)
|
||||||
return ntree
|
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):
|
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.
|
# flake8 thinks we're redefining from 52.
|
||||||
obj.replace(tree)
|
obj.replace(tree)
|
||||||
return obj
|
return obj
|
||||||
|
@ -18,17 +18,13 @@
|
|||||||
# 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 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):
|
def __repr__(self):
|
||||||
for x in self:
|
return "{%s}" % (" ".join([repr(x) for x in self]))
|
||||||
self[x].replace(other)
|
|
||||||
x.replace(other)
|
|
||||||
|
|
||||||
HyObject.replace(self, other)
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from hy import HyString
|
from hy import HyString
|
||||||
from hy.compiler import hy_compile, HyCompileError
|
from hy.compiler import hy_compile, HyCompileError, HyTypeError
|
||||||
from hy.lex import tokenize
|
from hy.lex import tokenize
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
@ -47,8 +47,11 @@ def cant_compile(expr):
|
|||||||
try:
|
try:
|
||||||
hy_compile(expr, "__main__")
|
hy_compile(expr, "__main__")
|
||||||
assert False
|
assert False
|
||||||
except HyCompileError:
|
except HyCompileError as e:
|
||||||
pass
|
# 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():
|
def test_ast_bad_type():
|
||||||
|
@ -27,11 +27,21 @@ if sys.version_info[0] <= 2 and sys.version_info[1] <= 6:
|
|||||||
else:
|
else:
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from hy import compiler
|
||||||
from hy.models.expression import HyExpression
|
from hy.models.expression import HyExpression
|
||||||
from hy.models.list import HyList
|
from hy.models.list import HyList
|
||||||
from hy.models.symbol import HySymbol
|
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):
|
class HyASTCompilerTest(unittest.TestCase):
|
||||||
@ -46,7 +56,7 @@ class HyASTCompilerTest(unittest.TestCase):
|
|||||||
return h
|
return h
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.c = HyASTCompiler('')
|
self.c = compiler.HyASTCompiler('test')
|
||||||
|
|
||||||
def test_fn_compiler_empty_function(self):
|
def test_fn_compiler_empty_function(self):
|
||||||
ret = self.c.compile_function_def(
|
ret = self.c.compile_function_def(
|
||||||
|
@ -185,15 +185,18 @@ def test_lex_line_counting_multi_inner():
|
|||||||
def test_dicts():
|
def test_dicts():
|
||||||
""" Ensure that we can tokenize a dict. """
|
""" Ensure that we can tokenize a dict. """
|
||||||
objs = tokenize("{foo bar bar baz}")
|
objs = tokenize("{foo bar bar baz}")
|
||||||
assert objs == [HyDict({
|
assert objs == [HyDict(["foo", "bar", "bar", "baz"])]
|
||||||
"foo": "bar",
|
|
||||||
"bar": "baz"
|
|
||||||
})]
|
|
||||||
|
|
||||||
objs = tokenize("(bar {foo bar bar baz})")
|
objs = tokenize("(bar {foo bar bar baz})")
|
||||||
assert objs == [HyExpression([HySymbol("bar"),
|
assert objs == [HyExpression([HySymbol("bar"),
|
||||||
HyDict({"foo": "bar",
|
HyDict(["foo", "bar",
|
||||||
"bar": "baz"})])]
|
"bar", "baz"])])]
|
||||||
|
|
||||||
|
objs = tokenize("{(foo bar) (baz quux)}")
|
||||||
|
assert objs == [HyDict([
|
||||||
|
HyExpression([HySymbol("foo"), HySymbol("bar")]),
|
||||||
|
HyExpression([HySymbol("baz"), HySymbol("quux")])
|
||||||
|
])]
|
||||||
|
|
||||||
|
|
||||||
def test_nospace():
|
def test_nospace():
|
||||||
|
@ -15,6 +15,12 @@
|
|||||||
(assert (= [1 2 3 4] (+ [1 2] [3 4]))))
|
(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 []
|
(defn test-setv-get []
|
||||||
"NATIVE: test setv works on a get expression"
|
"NATIVE: test setv works on a get expression"
|
||||||
(setv foo [0 1 2])
|
(setv foo [0 1 2])
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
(import hy)
|
||||||
|
|
||||||
|
|
||||||
(defn test-quote []
|
(defn test-quote []
|
||||||
"NATIVE: test for quoting functionality"
|
"NATIVE: test for quoting functionality"
|
||||||
(setf q (quote (a b c)))
|
(setf q (quote (a b c)))
|
||||||
@ -21,6 +24,25 @@
|
|||||||
(assert (= (cdr q1) (quote (a b c)))))
|
(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 []
|
(defn test-quasiquote []
|
||||||
"NATIVE: test that quasiquote and quote are equivalent for simple cases"
|
"NATIVE: test that quasiquote and quote are equivalent for simple cases"
|
||||||
(setf q (quote (a b c)))
|
(setf q (quote (a b c)))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user