application/octet-stream
•
3.54 KB
•
89 lines
;;; Nujel - Copyright (C) 2020-2021 - Benjamin Vincent Schulenburg
;;; This project uses the MIT license, a copy should be included under /LICENSE
;;;
;;; Mostly macros implementing different control flow constructs
(defmacro if-not (pred then else)
`(if ~pred ~else ~then))
(defmacro when-not (pred . body)
"Evalutes to BODY if PRED is false"
`(if ~pred #nil (do ~@body)))
(defmacro when (pred . body)
"Evalutes to BODY if PRED is true"
`(if ~pred (do ~@body) #nil))
(def case (let*
(defn case/clauses/multiple (key-sym cases)
:internal
(when cases
(cons (list '= key-sym (car cases))
(case/clauses/multiple key-sym (cdr cases)))))
(defn case/clauses (key-sym clauses)
:internal
(when clauses
(if (= (caar clauses) 'otherwise)
(cons 'do (cdar clauses))
(list 'if
(if (pair? (caar clauses))
(if (and (= (car (caar clauses)) 'quote)
(last? (cdr (caar clauses)))
(symbol? (cadr (caar clauses))))
(list '= key-sym (caar clauses))
(cons 'or (case/clauses/multiple key-sym (caar clauses))))
(list '= key-sym (caar clauses)))
(cons 'do (cdar clauses))
(case/clauses key-sym (cdr clauses))))))
(defmacro case (key-form . clauses)
(def key-sym (gensym))
(list 'let*
(list 'def key-sym key-form)
(case/clauses key-sym clauses)))))
(defn cond/fn (body)
:internal
(when (and body (caar body))
(list 'if
(caar body)
(cons 'do (cdar body))
(cond/fn (cdr body)))))
(defmacro cond body
"Contains multiple cond clauses"
(cond/fn body))
(defmacro dotimes (binding . body)
"binding => (name n result-form)"
"Repeatedly executes body with name bound to integers from 0 through n-1. Returns result-form or #nil."
(def sym (car binding))
(typecheck/only sym :symbol)
(def times (cadr binding))
(def result-form (caddr binding))
`(do (def ~sym 0)
(while (< ~sym ~times)
~@body
(set! ~sym (inc/int ~sym)))
~result-form))
(defmacro doseq (for-loop . body)
"(doseq (l (list 1 2 3 4) result-form) (println l))"
(def symbol-name (gensym))
`(let ((~symbol-name ~(cadr for-loop)))
(while ~symbol-name
(def ~(car for-loop) (car ~symbol-name))
~@body
(cdr! ~symbol-name))
~(caddr for-loop)))
(def -> (let*
(defn thread/-> (init fun)
:internal
(if-not fun init
(if (pair? (car fun))
`(~(caar fun) ~(thread/-> init (cdr fun)) ~@(cdar fun))
(list (car fun) (thread/-> init (cdr fun))))))
(defmacro -> (init . fun)
"Thread init as the first argument through every function in fun"
(thread/-> init (reverse fun)))))