make deftag/defmacro macros, not special forms

This commit is contained in:
gilch 2017-09-24 11:54:54 -06:00
parent c4b3d7bcda
commit 3707681056
4 changed files with 46 additions and 58 deletions

View File

@ -831,6 +831,7 @@ class HyASTCompiler(object):
@builds("try")
@checkargs(min=2)
def compile_try_expression(self, expr):
expr = copy.deepcopy(expr)
expr.pop(0) # try
# (try something…)
@ -1125,6 +1126,7 @@ class HyASTCompiler(object):
@builds("import")
def compile_import_expression(self, expr):
expr = copy.deepcopy(expr)
def _compile_import(expr, module, names=None, importer=asty.Import):
if not names:
names = [ast.alias(name=ast_str(module), asname=None)]
@ -2054,63 +2056,6 @@ class HyASTCompiler(object):
bases=bases_expr,
body=body.stmts)
def _compile_time_hack(self, expression):
"""Compile-time hack: we want to get our new macro now
We must provide __name__ in the namespace to make the Python
compiler set the __module__ attribute of the macro function."""
hy.importer.hy_eval(copy.deepcopy(expression),
compile_time_ns(self.module_name),
self.module_name)
# We really want to have a `hy` import to get hy.macro in
ret = self.compile(expression)
ret.add_imports('hy', [None])
return ret
@builds("defmacro")
@checkargs(min=1)
def compile_macro(self, expression):
expression.pop(0)
name = expression.pop(0)
if not isinstance(name, HySymbol):
raise HyTypeError(name, ("received a `%s' instead of a symbol "
"for macro name" % type(name).__name__))
name = HyString(name).replace(name)
for kw in ("&kwonly", "&kwargs", "&key"):
if kw in expression[0]:
raise HyTypeError(name, "macros cannot use %s" % kw)
expression[0].insert(0, HySymbol('&name'))
new_expression = HyExpression([
HyExpression([HySymbol("hy.macros.macro"), name]),
HyExpression([HySymbol("fn")] + expression),
]).replace(expression)
ret = self._compile_time_hack(new_expression)
return ret
@builds("deftag")
@checkargs(min=2)
def compile_tag_macro(self, expression):
expression.pop(0)
name = expression.pop(0)
if name == ":" or name == "&":
raise NameError("%s can't be used as a tag macro name" % name)
if not isinstance(name, HySymbol) and not isinstance(name, HyString):
raise HyTypeError(name,
("received a `%s' instead of a symbol "
"for tag macro name" % type(name).__name__))
name = HyString(name).replace(name)
new_expression = HyExpression([
HyExpression([HySymbol("hy.macros.tag"), name]),
HyExpression([HySymbol("fn")] + expression),
]).replace(expression)
ret = self._compile_time_hack(new_expression)
return ret
@builds("dispatch_tag_macro")
@checkargs(exact=2)
def compile_dispatch_tag_macro(self, expression):

View File

@ -6,6 +6,30 @@
;;; These macros are the essential hy macros.
;;; They are automatically required everywhere, even inside hy.core modules.
(eval-and-compile
(import hy)
((hy.macros.macro "defmacro")
(fn [&name macro-name lambda-list &rest body]
"the defmacro macro"
(if* (not (isinstance macro-name hy.models.HySymbol))
(raise
(hy.errors.HyTypeError
macro-name
(% "received a `%s' instead of a symbol for macro name"
(. (type name)
__name__)))))
(for* [kw '[&kwonly &kwargs &key]]
(if* (in kw lambda-list)
(raise (hy.errors.HyTypeError macro-name
(% "macros cannot use %s"
kw)))))
;; this looks familiar...
`(eval-and-compile
(import hy)
((hy.macros.macro ~(str macro-name))
(fn ~(+ `[&name] lambda-list)
~@body))))))
(defmacro if [&rest args]
"if with elif"
(setv n (len args))
@ -16,6 +40,23 @@
~(get args 1)
(if ~@(cut args 2))))))
(defmacro deftag [tag-name lambda-list &rest body]
(if (and (not (isinstance tag-name hy.models.HySymbol))
(not (isinstance tag-name hy.models.HyString)))
(raise (hy.errors.HyTypeError
tag-name
(% "received a `%s' instead of a symbol for tag macro name"
(. (type tag-name) __name__)))))
(if (or (= tag-name ":")
(= tag-name "&"))
(raise (NameError (% "%s can't be used as a tag macro name" tag-name))))
(setv tag-name (.replace (hy.models.HyString tag-name)
tag-name))
`(eval-and-compile
(import hy)
((hy.macros.tag ~tag-name)
(fn ~lambda-list ~@body))))
(defmacro macro-error [location reason]
"error out properly within a macro"
`(raise (hy.errors.HyMacroExpansionError ~location ~reason)))

View File

@ -81,7 +81,7 @@ class HyTypeError(TypeError):
result += colored.yellow("%s: %s\n\n" %
(self.__class__.__name__,
self.message.encode('utf-8')))
self.message))
return result

View File

@ -34,6 +34,7 @@ def macro(name):
"""
def _(fn):
fn.__name__ = '({})'.format(name)
try:
argspec = getargspec(fn)
fn._hy_macro_pass_compiler = argspec.keywords is not None
@ -63,6 +64,7 @@ def tag(name):
"""
def _(fn):
fn.__name__ = '#{}'.format(name)
module_name = fn.__module__
if module_name.startswith("hy.core"):
module_name = None