make deftag/defmacro macros, not special forms
This commit is contained in:
parent
c4b3d7bcda
commit
3707681056
@ -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):
|
||||
|
@ -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)))
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user