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")
|
@builds("try")
|
||||||
@checkargs(min=2)
|
@checkargs(min=2)
|
||||||
def compile_try_expression(self, expr):
|
def compile_try_expression(self, expr):
|
||||||
|
expr = copy.deepcopy(expr)
|
||||||
expr.pop(0) # try
|
expr.pop(0) # try
|
||||||
|
|
||||||
# (try something…)
|
# (try something…)
|
||||||
@ -1125,6 +1126,7 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
@builds("import")
|
@builds("import")
|
||||||
def compile_import_expression(self, expr):
|
def compile_import_expression(self, expr):
|
||||||
|
expr = copy.deepcopy(expr)
|
||||||
def _compile_import(expr, module, names=None, importer=asty.Import):
|
def _compile_import(expr, module, names=None, importer=asty.Import):
|
||||||
if not names:
|
if not names:
|
||||||
names = [ast.alias(name=ast_str(module), asname=None)]
|
names = [ast.alias(name=ast_str(module), asname=None)]
|
||||||
@ -2054,63 +2056,6 @@ class HyASTCompiler(object):
|
|||||||
bases=bases_expr,
|
bases=bases_expr,
|
||||||
body=body.stmts)
|
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")
|
@builds("dispatch_tag_macro")
|
||||||
@checkargs(exact=2)
|
@checkargs(exact=2)
|
||||||
def compile_dispatch_tag_macro(self, expression):
|
def compile_dispatch_tag_macro(self, expression):
|
||||||
|
@ -6,6 +6,30 @@
|
|||||||
;;; These macros are the essential hy macros.
|
;;; These macros are the essential hy macros.
|
||||||
;;; They are automatically required everywhere, even inside hy.core modules.
|
;;; 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]
|
(defmacro if [&rest args]
|
||||||
"if with elif"
|
"if with elif"
|
||||||
(setv n (len args))
|
(setv n (len args))
|
||||||
@ -16,6 +40,23 @@
|
|||||||
~(get args 1)
|
~(get args 1)
|
||||||
(if ~@(cut args 2))))))
|
(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]
|
(defmacro macro-error [location reason]
|
||||||
"error out properly within a macro"
|
"error out properly within a macro"
|
||||||
`(raise (hy.errors.HyMacroExpansionError ~location ~reason)))
|
`(raise (hy.errors.HyMacroExpansionError ~location ~reason)))
|
||||||
|
@ -81,7 +81,7 @@ class HyTypeError(TypeError):
|
|||||||
|
|
||||||
result += colored.yellow("%s: %s\n\n" %
|
result += colored.yellow("%s: %s\n\n" %
|
||||||
(self.__class__.__name__,
|
(self.__class__.__name__,
|
||||||
self.message.encode('utf-8')))
|
self.message))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ def macro(name):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
def _(fn):
|
def _(fn):
|
||||||
|
fn.__name__ = '({})'.format(name)
|
||||||
try:
|
try:
|
||||||
argspec = getargspec(fn)
|
argspec = getargspec(fn)
|
||||||
fn._hy_macro_pass_compiler = argspec.keywords is not None
|
fn._hy_macro_pass_compiler = argspec.keywords is not None
|
||||||
@ -63,6 +64,7 @@ def tag(name):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
def _(fn):
|
def _(fn):
|
||||||
|
fn.__name__ = '#{}'.format(name)
|
||||||
module_name = fn.__module__
|
module_name = fn.__module__
|
||||||
if module_name.startswith("hy.core"):
|
if module_name.startswith("hy.core"):
|
||||||
module_name = None
|
module_name = None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user