Make hy.compiler.builds more flexible
I removed the "Hypster" error message and the test for it because it can only catch compiler bugs that should themselves be caught by Hy's tests.
This commit is contained in:
parent
e30abcd20f
commit
cf7ff802c9
109
hy/compiler.py
109
hy/compiler.py
@ -91,28 +91,20 @@ def ast_str(foobar):
|
|||||||
return "hy_%s" % (str(foobar).replace("-", "_"))
|
return "hy_%s" % (str(foobar).replace("-", "_"))
|
||||||
|
|
||||||
|
|
||||||
def builds(_type):
|
def builds(*types, **kwargs):
|
||||||
|
# A decorator that adds the decorated method to _compile_table for
|
||||||
unpythonic_chars = ["-"]
|
# compiling `types`, but only if kwargs['iff'] (if provided) is
|
||||||
really_ok = ["-"]
|
# true.
|
||||||
if any(x in unpythonic_chars for x in str_type(_type)):
|
if not kwargs.get('iff', True):
|
||||||
if _type not in really_ok:
|
return lambda fn: fn
|
||||||
raise TypeError("Dear Hypster: `build' needs to be *post* "
|
|
||||||
"translated strings... `%s' sucks." % (_type))
|
|
||||||
|
|
||||||
def _dec(fn):
|
def _dec(fn):
|
||||||
_compile_table[_type] = fn
|
for t in types:
|
||||||
|
_compile_table[t] = fn
|
||||||
return fn
|
return fn
|
||||||
return _dec
|
return _dec
|
||||||
|
|
||||||
|
|
||||||
def builds_if(_type, condition):
|
|
||||||
if condition:
|
|
||||||
return builds(_type)
|
|
||||||
else:
|
|
||||||
return lambda fn: fn
|
|
||||||
|
|
||||||
|
|
||||||
def spoof_positions(obj):
|
def spoof_positions(obj):
|
||||||
if not isinstance(obj, HyObject) or isinstance(obj, HyCons):
|
if not isinstance(obj, HyObject) or isinstance(obj, HyCons):
|
||||||
return
|
return
|
||||||
@ -762,8 +754,7 @@ class HyASTCompiler(object):
|
|||||||
return imports, HyExpression([HySymbol(name),
|
return imports, HyExpression([HySymbol(name),
|
||||||
form]).replace(form), False
|
form]).replace(form), False
|
||||||
|
|
||||||
@builds("quote")
|
@builds("quote", "quasiquote")
|
||||||
@builds("quasiquote")
|
|
||||||
@checkargs(exact=1)
|
@checkargs(exact=1)
|
||||||
def compile_quote(self, entries):
|
def compile_quote(self, entries):
|
||||||
if entries[0] == "quote":
|
if entries[0] == "quote":
|
||||||
@ -776,8 +767,7 @@ class HyASTCompiler(object):
|
|||||||
ret.add_imports("hy", imports)
|
ret.add_imports("hy", imports)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@builds("unquote")
|
@builds("unquote", "unquote_splicing")
|
||||||
@builds("unquote_splicing")
|
|
||||||
def compile_unquote(self, expr):
|
def compile_unquote(self, expr):
|
||||||
raise HyTypeError(expr,
|
raise HyTypeError(expr,
|
||||||
"`%s' can't be used at the top-level" % expr[0])
|
"`%s' can't be used at the top-level" % expr[0])
|
||||||
@ -796,7 +786,7 @@ class HyASTCompiler(object):
|
|||||||
def compile_unpack_mapping(self, expr):
|
def compile_unpack_mapping(self, expr):
|
||||||
raise HyTypeError(expr, "`unpack-mapping` isn't allowed here")
|
raise HyTypeError(expr, "`unpack-mapping` isn't allowed here")
|
||||||
|
|
||||||
@builds_if("exec*", not PY3)
|
@builds("exec*", iff=(not PY3))
|
||||||
# Under Python 3, `exec` is a function rather than a statement type, so Hy
|
# Under Python 3, `exec` is a function rather than a statement type, so Hy
|
||||||
# doesn't need a special form for it.
|
# doesn't need a special form for it.
|
||||||
@checkargs(min=1, max=3)
|
@checkargs(min=1, max=3)
|
||||||
@ -1106,13 +1096,10 @@ class HyASTCompiler(object):
|
|||||||
return ret + asty.Assert(expr, test=e, msg=msg)
|
return ret + asty.Assert(expr, test=e, msg=msg)
|
||||||
|
|
||||||
@builds("global")
|
@builds("global")
|
||||||
@builds("nonlocal")
|
@builds("nonlocal", iff=PY3)
|
||||||
@checkargs(min=1)
|
@checkargs(min=1)
|
||||||
def compile_global_or_nonlocal(self, expr):
|
def compile_global_or_nonlocal(self, expr):
|
||||||
form = expr.pop(0)
|
form = expr.pop(0)
|
||||||
if form == "nonlocal" and not PY3:
|
|
||||||
raise HyCompileError(
|
|
||||||
"nonlocal only supported in python 3!")
|
|
||||||
names = []
|
names = []
|
||||||
while len(expr) > 0:
|
while len(expr) > 0:
|
||||||
identifier = expr.pop(0)
|
identifier = expr.pop(0)
|
||||||
@ -1126,7 +1113,7 @@ class HyASTCompiler(object):
|
|||||||
return node(expr, names=names)
|
return node(expr, names=names)
|
||||||
|
|
||||||
@builds("yield")
|
@builds("yield")
|
||||||
@builds_if("yield_from", PY3)
|
@builds("yield_from", iff=PY3)
|
||||||
@checkargs(max=1)
|
@checkargs(max=1)
|
||||||
def compile_yield_expression(self, expr):
|
def compile_yield_expression(self, expr):
|
||||||
ret = Result(contains_yield=(not PY3))
|
ret = Result(contains_yield=(not PY3))
|
||||||
@ -1377,9 +1364,7 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
return gen_res + cond, gen
|
return gen_res + cond, gen
|
||||||
|
|
||||||
@builds("list_comp")
|
@builds("list_comp", "set_comp", "genexpr")
|
||||||
@builds("set_comp")
|
|
||||||
@builds("genexpr")
|
|
||||||
@checkargs(min=2, max=3)
|
@checkargs(min=2, max=3)
|
||||||
def compile_comprehension(self, expr):
|
def compile_comprehension(self, expr):
|
||||||
# (list-comp expr (target iter) cond?)
|
# (list-comp expr (target iter) cond?)
|
||||||
@ -1418,8 +1403,7 @@ class HyASTCompiler(object):
|
|||||||
value=value.force_expr,
|
value=value.force_expr,
|
||||||
generators=gen)
|
generators=gen)
|
||||||
|
|
||||||
@builds("not")
|
@builds("not", "~")
|
||||||
@builds("~")
|
|
||||||
@checkargs(1)
|
@checkargs(1)
|
||||||
def compile_unary_operator(self, expression):
|
def compile_unary_operator(self, expression):
|
||||||
ops = {"not": ast.Not,
|
ops = {"not": ast.Not,
|
||||||
@ -1480,8 +1464,7 @@ class HyASTCompiler(object):
|
|||||||
raise HyTypeError(entry, "unrecognized (require) syntax")
|
raise HyTypeError(entry, "unrecognized (require) syntax")
|
||||||
return Result()
|
return Result()
|
||||||
|
|
||||||
@builds("and")
|
@builds("and", "or")
|
||||||
@builds("or")
|
|
||||||
def compile_logical_or_and_and_operator(self, expression):
|
def compile_logical_or_and_and_operator(self, expression):
|
||||||
ops = {"and": (ast.And, "True"),
|
ops = {"and": (ast.And, "True"),
|
||||||
"or": (ast.Or, "None")}
|
"or": (ast.Or, "None")}
|
||||||
@ -1548,26 +1531,19 @@ class HyASTCompiler(object):
|
|||||||
return ret + asty.Compare(
|
return ret + asty.Compare(
|
||||||
e, left=exprs[0], ops=ops, comparators=exprs[1:])
|
e, left=exprs[0], ops=ops, comparators=exprs[1:])
|
||||||
|
|
||||||
@builds("=")
|
@builds("=", "is", "<", "<=", ">", ">=")
|
||||||
@builds("is")
|
|
||||||
@builds("<")
|
|
||||||
@builds("<=")
|
|
||||||
@builds(">")
|
|
||||||
@builds(">=")
|
|
||||||
@checkargs(min=1)
|
@checkargs(min=1)
|
||||||
def compile_compare_op_expression(self, expression):
|
def compile_compare_op_expression(self, expression):
|
||||||
if len(expression) == 2:
|
if len(expression) == 2:
|
||||||
return asty.Name(expression, id="True", ctx=ast.Load())
|
return asty.Name(expression, id="True", ctx=ast.Load())
|
||||||
return self._compile_compare_op_expression(expression)
|
return self._compile_compare_op_expression(expression)
|
||||||
|
|
||||||
@builds("!=")
|
@builds("!=", "is_not")
|
||||||
@builds("is_not")
|
|
||||||
@checkargs(min=2)
|
@checkargs(min=2)
|
||||||
def compile_compare_op_expression_coll(self, expression):
|
def compile_compare_op_expression_coll(self, expression):
|
||||||
return self._compile_compare_op_expression(expression)
|
return self._compile_compare_op_expression(expression)
|
||||||
|
|
||||||
@builds("in")
|
@builds("in", "not_in")
|
||||||
@builds("not_in")
|
|
||||||
@checkargs(2)
|
@checkargs(2)
|
||||||
def compile_compare_op_expression_binary(self, expression):
|
def compile_compare_op_expression_binary(self, expression):
|
||||||
return self._compile_compare_op_expression(expression)
|
return self._compile_compare_op_expression(expression)
|
||||||
@ -1602,23 +1578,17 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@builds("**")
|
@builds("**", "//", "<<", ">>", "&")
|
||||||
@builds("//")
|
|
||||||
@builds("<<")
|
|
||||||
@builds(">>")
|
|
||||||
@builds("&")
|
|
||||||
@checkargs(min=2)
|
@checkargs(min=2)
|
||||||
def compile_maths_expression_2_or_more(self, expression):
|
def compile_maths_expression_2_or_more(self, expression):
|
||||||
return self._compile_maths_expression(expression)
|
return self._compile_maths_expression(expression)
|
||||||
|
|
||||||
@builds("%")
|
@builds("%", "^")
|
||||||
@builds("^")
|
|
||||||
@checkargs(2)
|
@checkargs(2)
|
||||||
def compile_maths_expression_exactly_2(self, expression):
|
def compile_maths_expression_exactly_2(self, expression):
|
||||||
return self._compile_maths_expression(expression)
|
return self._compile_maths_expression(expression)
|
||||||
|
|
||||||
@builds("*")
|
@builds("*", "|")
|
||||||
@builds("|")
|
|
||||||
def compile_maths_expression_mul(self, expression):
|
def compile_maths_expression_mul(self, expression):
|
||||||
id_elem = {"*": 1, "|": 0}[expression[0]]
|
id_elem = {"*": 1, "|": 0}[expression[0]]
|
||||||
if len(expression) == 1:
|
if len(expression) == 1:
|
||||||
@ -1647,7 +1617,7 @@ class HyASTCompiler(object):
|
|||||||
expression, op=op, operand=ret.force_expr)
|
expression, op=op, operand=ret.force_expr)
|
||||||
|
|
||||||
@builds("&")
|
@builds("&")
|
||||||
@builds_if("@", PY35)
|
@builds("@", iff=PY35)
|
||||||
@checkargs(min=1)
|
@checkargs(min=1)
|
||||||
def compile_maths_expression_unary_idempotent(self, expression):
|
def compile_maths_expression_unary_idempotent(self, expression):
|
||||||
if len(expression) == 2:
|
if len(expression) == 2:
|
||||||
@ -1670,19 +1640,9 @@ class HyASTCompiler(object):
|
|||||||
def compile_maths_expression_sub(self, expression):
|
def compile_maths_expression_sub(self, expression):
|
||||||
return self._compile_maths_expression_additive(expression)
|
return self._compile_maths_expression_additive(expression)
|
||||||
|
|
||||||
@builds("+=")
|
@builds("+=", "/=", "//=", "*=", "_=", "%=", "**=", "<<=", ">>=", "|=",
|
||||||
@builds("/=")
|
"^=", "&=")
|
||||||
@builds("//=")
|
@builds("@=", iff=PY35)
|
||||||
@builds("*=")
|
|
||||||
@builds("_=")
|
|
||||||
@builds("%=")
|
|
||||||
@builds("**=")
|
|
||||||
@builds("<<=")
|
|
||||||
@builds(">>=")
|
|
||||||
@builds("|=")
|
|
||||||
@builds("^=")
|
|
||||||
@builds("&=")
|
|
||||||
@builds_if("@=", PY35)
|
|
||||||
@checkargs(2)
|
@checkargs(2)
|
||||||
def compile_augassign_expression(self, expression):
|
def compile_augassign_expression(self, expression):
|
||||||
ops = {"+=": ast.Add,
|
ops = {"+=": ast.Add,
|
||||||
@ -1793,8 +1753,7 @@ class HyASTCompiler(object):
|
|||||||
expression, func=func.expr, args=args, keywords=keywords,
|
expression, func=func.expr, args=args, keywords=keywords,
|
||||||
starargs=oldpy_star, kwargs=oldpy_kw)
|
starargs=oldpy_star, kwargs=oldpy_kw)
|
||||||
|
|
||||||
@builds("def")
|
@builds("def", "setv")
|
||||||
@builds("setv")
|
|
||||||
def compile_def_expression(self, expression):
|
def compile_def_expression(self, expression):
|
||||||
root = expression.pop(0)
|
root = expression.pop(0)
|
||||||
if not expression:
|
if not expression:
|
||||||
@ -1908,8 +1867,7 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@builds("fn")
|
@builds("fn", "fn*")
|
||||||
@builds("fn*")
|
|
||||||
# The starred version is for internal use (particularly, in the
|
# The starred version is for internal use (particularly, in the
|
||||||
# definition of `defn`). It ensures that a FunctionDef is
|
# definition of `defn`). It ensures that a FunctionDef is
|
||||||
# produced rather than a Lambda.
|
# produced rather than a Lambda.
|
||||||
@ -2174,9 +2132,7 @@ class HyASTCompiler(object):
|
|||||||
def compile_cons(self, cons):
|
def compile_cons(self, cons):
|
||||||
raise HyTypeError(cons, "Can't compile a top-level cons cell")
|
raise HyTypeError(cons, "Can't compile a top-level cons cell")
|
||||||
|
|
||||||
@builds(HyInteger)
|
@builds(HyInteger, HyFloat, HyComplex)
|
||||||
@builds(HyFloat)
|
|
||||||
@builds(HyComplex)
|
|
||||||
def compile_numeric_literal(self, number, building):
|
def compile_numeric_literal(self, number, building):
|
||||||
f = {HyInteger: long_type,
|
f = {HyInteger: long_type,
|
||||||
HyFloat: float,
|
HyFloat: float,
|
||||||
@ -2214,16 +2170,13 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
return asty.Name(symbol, id=ast_str(symbol), ctx=ast.Load())
|
return asty.Name(symbol, id=ast_str(symbol), ctx=ast.Load())
|
||||||
|
|
||||||
@builds(HyString)
|
@builds(HyString, HyKeyword, HyBytes)
|
||||||
@builds(HyKeyword)
|
|
||||||
@builds(HyBytes)
|
|
||||||
def compile_string(self, string, building):
|
def compile_string(self, string, building):
|
||||||
node = asty.Bytes if PY3 and building is HyBytes else asty.Str
|
node = asty.Bytes if PY3 and building is HyBytes else asty.Str
|
||||||
f = bytes_type if building is HyBytes else str_type
|
f = bytes_type if building is HyBytes else str_type
|
||||||
return node(string, s=f(string))
|
return node(string, s=f(string))
|
||||||
|
|
||||||
@builds(HyList)
|
@builds(HyList, HySet)
|
||||||
@builds(HySet)
|
|
||||||
def compile_list(self, expression, building):
|
def compile_list(self, expression, building):
|
||||||
elts, ret, _ = self._compile_collect(expression)
|
elts, ret, _ = self._compile_collect(expression)
|
||||||
node = {HyList: asty.List, HySet: asty.Set}[building]
|
node = {HyList: asty.List, HySet: asty.Set}[building]
|
||||||
|
@ -9,18 +9,6 @@ from hy.models import HyExpression, HyList, HySymbol, HyInteger
|
|||||||
from hy._compat import PY3
|
from hy._compat import PY3
|
||||||
|
|
||||||
|
|
||||||
def test_builds_with_dash():
|
|
||||||
assert callable(compiler.builds("foobar"))
|
|
||||||
assert callable(compiler.builds("foo_bar"))
|
|
||||||
assert callable(compiler.builds("-"))
|
|
||||||
try:
|
|
||||||
compiler.builds("foobar-with-dash-")
|
|
||||||
except TypeError as e:
|
|
||||||
assert "*post* translated strings" in str(e)
|
|
||||||
else:
|
|
||||||
assert False
|
|
||||||
|
|
||||||
|
|
||||||
def make_expression(*args):
|
def make_expression(*args):
|
||||||
h = HyExpression(args)
|
h = HyExpression(args)
|
||||||
h.start_line = 1
|
h.start_line = 1
|
||||||
|
Loading…
Reference in New Issue
Block a user