;;;;;;;;;;;;;;;;;;;;;;
;;                  ;;
;;  Macros de base  ;;
;;                  ;;
;;;;;;;;;;;;;;;;;;;;;;

(defvar list (lambda x x))

(defvar defun (macro (nom args . body)
                     (list 'defvar nom
                           (cons 'lambda
                                 (cons args body)))))

(defvar defun (macro (nom args . body)
                      (list 'defvar nom
                            (cons 'lambda
                                  (cons args body)))))

(defvar defmacro (macro (nom args . body)
                        (list 'defvar nom
                              (cons 'macro
                                    (cons args body)))))

(defmacro exemples body ''exemples)

(defun macro->lambda (liste)
  (cons 'lambda (cdr liste)))

(defmacro expand-macro (liste)
  (cons 'apply
        (cons (list 'macro->lambda (car liste))
              (list (list 'quote
                          (map (lambda (x) (cons 'quote (list x))) (cdr liste)))))))


(exemples

 (macro->lambda defun)

 (expand-macro
  (exemples a b c))

 (expand-macro
  (defun fonction (a b c)
    ligne1
    ligne2
    lign3))

 (expand-macro
  (expand-macro
   (defun fonction (a b c)
     ligne1
     ligne2
     ligne3)))

 nil)





;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                      ;;
;;  Fonctions de bases sur les listes   ;;
;;                                      ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun map (f l)
  (if l
      (cons (f (car l))
            (map f (cdr l)))
    nil))

(defun append (liste1 liste2)
  (if liste1
      (cons (car liste1)
            (append (cdr liste1) liste2))
    liste2))

(defun zip (liste1 liste2)
  (if liste1
      (cons (cons (car liste1) (car liste2))
            (zip  (cdr liste1) (cdr liste2)))
    nil))

(defun cadr (x)
  (car (cdr x)))

(exemples

 (map (lambda (x) (* 10 x))
      (list 1 2 3))

 (append (list 1 2 3)
         (list 4 5 6))

 (zip (list :a :b :c)
      (list 11 22 33))

 (car (list :un :deux :trois))
 (cadr (list :un :deux :trois))

 nil)





;;;;;;;;;;;;;;
;;          ;;
;;  Macro   ;;
;;          ;;
;;;;;;;;;;;;;;


(defmacro let (bindings . body)
  (cons (cons 'lambda
              (cons (map car bindings) body))
        (map cadr bindings)))


(exemple

 (let ((a 1)
       (b 20)
       (c 300))
   (+ a (+ b c)))

 nil)


(defun list* liste
  (let ((list*-aux (lambda (liste)
                     (if (cdr liste) ;; si la liste contient au moins un élément
                         (cons (car liste)
                               (list*-aux (cdr liste)))
                       (car liste)))))
  (list*-aux liste)))

(defmacro progn body
  (if (cdr body)
      (list (list* 'lambda nil body))
   (car body)))

(defmacro when (test . body)
  (list 'if test
        (cons 'progn body)
        nil))

(defmacro unless (test . body)
  (list 'if test
        nil
        (cons 'progn body)))

(defmacro cond liste
  (when liste
    (let ((test (car (car liste)))
          (body (cdr (car liste))))
      (if (= test t)
          (cons 'progn body)
        (list 'if test
              (cons 'progn body)
              (cons 'cond (cdr liste)))))))

(defmacro and liste
  (if liste
      (list 'if (car liste)
            (cons 'and (cdr liste))
            nil)
    t))

(defmacro let* (bindings . body)
  (let ((variables (map car  bindings))
        (valeurs   (map cadr bindings))
        (déclarer (lambda (x) (list x nil)) )
        (affecter (lambda (couple) (list 'setq (car couple) (cdr couple)))))

    (list* 'let
           (map déclarer variables)
           (append (map affecter (zip variables valeurs))
                   body))))



(exemples

 (let* ((a 1)
        (b (* 10 (+ 1 a)))
        (c (* 10 (+ 10 b))))
   (list a b c))

 nil)


@save:stdlib

