Macros actually working

This commit is contained in:
FelixBrendel
2018-10-27 15:57:45 +02:00
parent 65b97fe535
commit 5aa92062c3
15 changed files with 693 additions and 192 deletions
+136 -109
View File
@@ -1,128 +1,155 @@
(define nil ())
(define pe
(macro (expr)
(print expr)
(print " evaluates to -> ")
(print (eval expr))
(print "
")
(define defun
(macro (@name @params :rest @body)
(eval (pair 'define (pair @name (pair (pair 'lambda (pair @params @body)) nil))))))
(define defmacro
(macro (@name @params :rest @body)
(eval (pair 'define (pair @name (pair (pair 'macro (pair @params @body)) nil))))))
(defmacro pe (@expr)
(printf @expr "evaluates to" (eval @expr)))
(defun nil? (x)
"Checks if the argument is nil."
(= x nil))
(defun number? (x)
"Checks if the argument is a number."
(= (type x) :number))
(defun symbol? (x)
"Checks if the argument is a symbol."
(= (type x) :symbol))
(defun keyword? (x)
"Checks if the argument is a keyword."
(= (type x) :keyword))
(defun pair? (x)
"Checks if the argument is a pair."
(= (type x) :pair))
(defun string? (x)
"Checks if the argument is a string."
(= (type x) :string))
(defun dynamic-function? (x)
"Checks if the argument is a function."
(= (type x) :dynamic-function))
(defun dynamic-macro? (x)
"Checks if the argument is a macro."
(= (type x) :dynamic-macro))
(defun built-in-function? (x)
"Checks if the argument is a built-in function."
(= (type x) :built-in-function))
(defun apply (fun seq)
"Applies the funciton to the sequence, as in calls the funciton with
ithe sequence as arguemens."
(eval (pair fun seq)))
(defmacro when (@test :rest @body)
"Executes the code in :rest if test is true"
(if (eval @test)
(eval (pair prog @body))
nil))
(defmacro unless (@test :rest @body)
"Executes the code in :rest if test is false."
(if (eval @test)
nil
(eval (pair prog @body))))
(define apply
(lambda (fun seq)
(eval (pair fun seq))))
(defun end (seq)
"Returns the last pair in the sqeuence."
(if (or (nil? seq) (not (pair? (rest seq))))
seq
(end (rest seq))))
(define defun
(macro (name params :rest body)
(printf "name" params "params" params "body" body)
(define name
(lambda (params) body))))
(defun last (seq)
"Returns the (first) of the last (pair) of the given sequence."
(first (end seq)))
(define when
(macro (test :rest body)
(if (eval test)
(apply prog body)
nil)))
(defun extend (seq elem)
"Extends a list with the given element, by putting it in
the (rest) of the last element of the sequence."
(when (pair? seq)
(define e (end seq))
(mutate e (pair (first e) elem)))
seq)
(define unless
(macro (test :rest body)
(if (eval test)
nil
(apply prog body))))
(defun append (seq elem)
(extend seq (pair elem nil)))
(define nil?
(lambda (x)
"Checks if the argument is nil."
(= x nil)))
(defmacro n-times (@times @action)
(unless (<= (eval @times) 0)
(eval @action)
(macro-define @args (pair (pair - (pair (eval @times) (pair 1 nil))) (pair @action nil)))
;; [o|o] --------------------------> [o|o] -> nil
;; | |
;; V V
;; [o|o] -> [o|o] -> [o|o]-> nil action
;; | | |
;; V V V
;; - times 1
(eval (pair n-times @args))))
(define append
(lambda (seq elem)
(if (nil? seq)
nil
(if (not (= (type (rest seq)) :pair))
;; we are on the last element
(mutate seq (pair (first seq) elem))
(append (rest seq) elem)))))
(defun range (:keys from :defaults-to 0 to)
"Returns a sequence of numbers starting with the number defined
by the key 'from' and ends with the number defined in 'to'."
(if (<= from to)
(pair from (range :from (+ 1 from) :to to))
nil))
(define last
(lambda (seq)
"Returns the last element of the given sequence."
(if (nil? seq)
seq
(if (not (= (type (rest seq)) :pair))
(first seq)
(last (rest seq))))))
(defun map (fun seq)
"Takes a sequence and a function as arguments and returns a new
sequence which contains the results of using the first sequences
elemens as argument to that function."
(if (nil? seq)
seq
(pair (fun (first seq))
(map fun (rest seq)))))
(define n-times
(lambda (times action)
(if (<= times 0)
nil
(prog
(eval action)
(n-times (- 1 times) action)))))
(defun reduce (fun seq)
"Takes a sequence and a function as arguments and applies the
function to the argument sequence. This only works correctly if
the given function accepts a variable amount of parameters. If
your funciton is limited to two arguments, use `reduce-binary'
instead."
(eval (pair fun seq)))
(define range
(lambda (:keys from :defaults-to 0 to)
"Returns a sequence of numbers starting with the number
defined by the key 'from' and ends with the number defined in
'to'."
(if (<= from to)
(pair from (range :from (+ 1 from) :to to))
nil)))
(define map
(lambda (fun seq)
"Takes a sequence and a function as arguments and returns a
new sequence which contains the results of using the first
sequences elemens as argument to that function."
(if (nil? seq)
seq
(pair (fun (first seq))
(map fun (rest seq))))))
(define reduce
(lambda (function sequence)
"Takes a sequence and a function as arguments and applies the
function to the argument sequence. This only works correctly if the
given function accepts a variable amount of parameters. If your
funciton is limited to two arguments, use `reduce-binary' instead."
(apply function sequence)))
(define reduce-binary
(lambda (function sequence)
"Takes a sequence and a function as arguments and applies the
(defun reduce-binary (fun seq)
"Takes a sequence and a function as arguments and applies the
function to the argument sequence. reduce-binary applies the
arguments `pair-wise' which means it works with binary functions
as compared to `reduce'."
(if (nil? (rest sequence))
(first sequence)
(function (first sequence)
(reduce-binary (rest sequence) function)))))
(if (nil? (rest seq))
(first seq)
(fun (first seq)
(reduce-binary fun (rest seq)))))
(define filter
(lambda (function sequence)
(if (nil? sequence)
nil
(if (function (first sequence))
(pair (first sequence)
(filter (rest sequence) function))
(filter (rest sequence) function)))))
(defun filter (fun seq)
(if (nil? seq)
nil
(if (fun (first seq))
(pair (first seq)
(filter fun (rest seq)))
(filter fun (rest seq)))))
(define printf-quoted
(macro (:keys sep :defaults-to " " end :defaults-to "\n" :rest args)
(if (nil? args)
(prog (print (eval end)) nil)
(prog
(print (first args))
(when (not (nil? (rest args))) (print (eval sep)))
(define command-args (list :sep (eval sep) :end (eval end)))
(append command-args (rest args))
(apply printf-quoted command-args)))))
(defmacro printf-quoted (:keys @sep :defaults-to " " @end :defaults-to "\n" :rest @args)
(if (nil? @args)
(prog (print (eval @end)) nil)
(prog
(print (first @args))
(when (not (nil? (rest @args))) (print (eval @sep)))
(eval
(pair printf-quoted
(extend (list :@sep (eval @sep) :@end (eval @end)) (rest @args)))))))
(define printf
(lambda (:keys sep :defaults-to " " end :defaults-to "\n" :rest args)
(define command-args (list :sep (eval sep) :end (eval end)))
(append command-args args)
(apply printf-quoted command-args)))
(defun printf (:keys sep :defaults-to " " end :defaults-to "\n" :rest args)
(define command-args (extend (list :@sep (eval sep) :@end (eval end)) args))
(eval (pair printf-quoted command-args)))