Merge branch 'master' into pr/182

This commit is contained in:
Paul Tagliamonte 2013-05-17 11:09:37 -04:00
commit c0fd41620f
3 changed files with 50 additions and 24 deletions

View File

@ -97,7 +97,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))
@ -419,22 +419,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
@ -443,17 +445,20 @@ 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.
it = iter(expr) it = iter(expr)
@ -464,8 +469,9 @@ class HyASTCompiler(object):
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
@ -475,8 +481,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
@ -761,7 +768,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
@ -793,6 +801,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.

View File

@ -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
@ -43,8 +43,11 @@ def cant_compile(expr):
try: try:
hy_compile(expr) hy_compile(expr)
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():

View File

@ -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()
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(