hy/hy/core/bootstrap.hy

79 lines
2.7 KiB
Hy

;;; Hy bootstrap macros
;; Copyright 2017 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
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))
(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]
(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)))
(defmacro defn [name lambda-list &rest body]
"define a function `name` with signature `lambda-list` and body `body`"
(import hy)
(if (not (= (type name) hy.HySymbol))
(macro-error name "defn takes a name as first argument"))
(if (not (isinstance lambda-list hy.HyList))
(macro-error name "defn takes a parameter list as second argument"))
`(setv ~name (fn* ~lambda-list ~@body)))
(defmacro if-python2 [python2-form python3-form]
"If running on python2, execute python2-form, else, execute python3-form"
(import sys)
(if (< (get sys.version_info 0) 3)
python2-form
python3-form))