Use model patterns for defclass

This commit is contained in:
Kodi Arfer 2018-04-19 11:19:40 -07:00
parent 9368e4bc4e
commit 3ebff987e0

View File

@ -6,7 +6,7 @@
from hy.models import (HyObject, HyExpression, HyKeyword, HyInteger, HyComplex,
HyString, HyBytes, HySymbol, HyFloat, HyList, HySet,
HyDict, HySequence, wrap_value)
from hy.model_patterns import FORM, SYM, sym, brackets, whole, notpexpr, dolike, pexpr
from hy.model_patterns import FORM, SYM, STR, sym, brackets, whole, notpexpr, dolike, pexpr
from funcparserlib.parser import many, oneplus, maybe, NoParseError
from hy.errors import HyCompileError, HyTypeError
@ -1812,79 +1812,61 @@ class HyASTCompiler(object):
ret += self.compile(expr[1])
return ret + asty.Return(expr, value=ret.force_expr)
@builds("defclass")
@checkargs(min=1)
def compile_class_expression(self, expressions):
def rewire_init(expr):
new_args = []
if (isinstance(expr, HyExpression)
and len(expr) > 1
and isinstance(expr[0], HySymbol)
and expr[0] == HySymbol("setv")):
pairs = expr[1:]
while len(pairs) > 0:
k, v = (pairs.pop(0), pairs.pop(0))
if ast_str(k) == "__init__":
v.append(HySymbol("None"))
new_args.append(k)
new_args.append(v)
expr = HyExpression([
HySymbol("setv")
] + new_args).replace(expr)
@special("defclass", [
SYM,
maybe(brackets(many(FORM)) + maybe(STR) +
maybe(brackets(many(SYM + FORM))) + many(FORM))])
def compile_class_expression(self, expr, root, name, rest):
base_list, docstring, attrs, body = rest or ([[]], None, None, [])
return expr
bases_expr, bases, keywords = (
self._compile_collect(base_list[0], with_kwargs=PY3))
expressions.pop(0) # class
bodyr = Result()
class_name = expressions.pop(0)
if not isinstance(class_name, HySymbol):
raise HyTypeError(class_name, "Class name must be a symbol.")
bases_expr = []
bases = Result()
keywords = []
if expressions:
base_list = expressions.pop(0)
if not isinstance(base_list, HyList):
raise HyTypeError(base_list, "Base classes must be a list.")
bases_expr, bases, keywords = self._compile_collect(base_list, with_kwargs=PY3)
body = Result()
# grab the doc string, if there is one
docstring = None
if expressions and isinstance(expressions[0], HyString):
docstring = expressions.pop(0)
if docstring is not None:
if not PY37:
body += self.compile(docstring).expr_as_stmt()
bodyr += self.compile(docstring).expr_as_stmt()
docstring = None
if expressions and isinstance(expressions[0], HyList) \
and not isinstance(expressions[0], HyExpression):
expr = expressions.pop(0)
expr = HyExpression([
HySymbol("setv")
] + expr).replace(expr)
body += self.compile(rewire_init(expr))
if attrs is not None:
bodyr += self.compile(self._rewire_init(HyExpression(
[HySymbol("setv")] +
[x for pair in attrs[0] for x in pair]).replace(attrs)))
for expression in expressions:
e = self.compile(rewire_init(macroexpand(expression, self)))
body += e + e.expr_as_stmt()
if not body.stmts:
body += asty.Pass(expressions)
for e in body:
e = self.compile(self._rewire_init(macroexpand(e, self)))
bodyr += e + e.expr_as_stmt()
return bases + asty.ClassDef(
expressions,
expr,
decorator_list=[],
name=ast_str(class_name),
name=ast_str(name),
keywords=keywords,
starargs=None,
kwargs=None,
bases=bases_expr,
body=body.stmts,
body=bodyr.stmts or [asty.Pass(expr)],
docstring=(None if docstring is None else str_type(docstring)))
def _rewire_init(self, expr):
"Given a (setv …) form, append None to definitions of __init__."
if not (isinstance(expr, HyExpression)
and len(expr) > 1
and isinstance(expr[0], HySymbol)
and expr[0] == HySymbol("setv")):
return expr
new_args = []
pairs = list(expr[1:])
while pairs:
k, v = (pairs.pop(0), pairs.pop(0))
if ast_str(k) == "__init__" and isinstance(v, HyExpression):
v += HyExpression([HySymbol("None")])
new_args.extend([k, v])
return HyExpression([HySymbol("setv")] + new_args).replace(expr)
@builds("dispatch-tag-macro")
@checkargs(exact=2)
def compile_dispatch_tag_macro(self, expression):