78 lines
2.9 KiB
Hy
78 lines
2.9 KiB
Hy
;;; Hy bootstrap macros
|
|
;; Copyright 2020 the authors.
|
|
;; This file is part of Hy, which is free software licensed under the Expat
|
|
;; license. See the LICENSE.
|
|
|
|
;;; 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
|
|
(% "received a `%s' instead of a symbol for macro name"
|
|
(. (type name) __name__))
|
|
None --file-- None)))
|
|
(for [kw '[&kwonly &kwargs]]
|
|
(if* (in kw lambda-list)
|
|
(raise (hy.errors.HyTypeError (% "macros cannot use %s"
|
|
kw)
|
|
macro-name --file-- None))))
|
|
;; this looks familiar...
|
|
`(eval-and-compile
|
|
(import hy)
|
|
((hy.macros.macro ~(str macro-name))
|
|
(fn ~(+ `[&name] lambda-list)
|
|
~@body))))))
|
|
|
|
(defmacro if [&rest args]
|
|
"Conditionally evaluate alternating test and then expressions."
|
|
(setv n (len args))
|
|
(if* n
|
|
(if* (= n 1)
|
|
(get args 0)
|
|
`(if* ~(get args 0)
|
|
~(get args 1)
|
|
(if ~@(cut args 2))))))
|
|
|
|
(defmacro deftag [tag-name lambda-list &rest body]
|
|
(import hy.models)
|
|
(if (and (not (isinstance tag-name hy.models.HySymbol))
|
|
(not (isinstance tag-name hy.models.HyString)))
|
|
(raise (hy.errors.HyTypeError
|
|
(% "received a `%s' instead of a symbol for tag macro name"
|
|
(. (type tag-name) --name--))
|
|
tag-name --file-- None)))
|
|
(if (or (= tag-name ":")
|
|
(= tag-name "&"))
|
|
(raise (hy.errors.HyNameError (% "%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 [expression reason &optional [filename '--name--]]
|
|
`(raise (hy.errors.HyMacroExpansionError ~reason ~filename ~expression None)))
|
|
|
|
(defmacro defn [name &rest args]
|
|
"Define `name` as a function with `args` as the signature, annotations, and body."
|
|
(import hy)
|
|
(if (not (= (type name) hy.HySymbol))
|
|
(macro-error name "defn takes a name as first argument"))
|
|
`(setv ~name (fn* ~@args)))
|
|
|
|
(defmacro defn/a [name lambda-list &rest body]
|
|
"Define `name` as a function with `lambda-list` signature and body `body`."
|
|
(import hy)
|
|
(if (not (= (type name) hy.HySymbol))
|
|
(macro-error name "defn/a takes a name as first argument"))
|
|
(if (not (isinstance lambda-list hy.HyList))
|
|
(macro-error name "defn/a takes a parameter list as second argument"))
|
|
`(setv ~name (fn/a ~lambda-list ~@body)))
|