; YourDSL - Can you evaluate this S-expr?
; ------------------------------
; The Little Lisper 3rd Edition
; Chapter 10
; Exercise 1
; Common Lisp
; http://t...content-available-to-author-only...r.com/thelittlelisper
; http://t...content-available-to-author-only...t.com/2010/06/little-lisper-chapter-10-what-is-value.html
; http://t...content-available-to-author-only...t.com/2010/06/little-lisper.html
; ------------------------------

(defun first_ (l)
  (cond
   ((null l) '())
   (t (car l))))

(defun second_ (l)
  (cond
   ((null l) '())
   (t (car (cdr l)))))


(defun build (a b)
  (cons a (cons b '())))

(setf e4
     '(3 (quote a)(quote b)))

(defun *self-evaluating (e table)
  e)
          
(defun atom-to-action (e)
  (cond
   ((numberp e) '*self-evaluating)
   (t '*identifier)))

(defun list-to-action (e)
  (cond
   ((atom (car e))
    (cond
     ((eq (car e) (quote quote))
      '*quote)
     ((eq (car e) (quote lambda))
      '*lambda)
     ((eq (car e) (quote cond))
      '*cond)
     (t '*application)))
   (t '*application)))
                
(defun expression-to-action (e)
  (cond
   ((atom e) (atom-to-action e))
   (t (list-to-action e))))
          
(defun meaning (e table)
  (funcall (expression-to-action e) e table))
     
(defun value_ (e)
  (meaning e (quote ())))

(defun *quote (e table)
      (text-of-quotation e))

(defun text-of-quotation (l) 
  (second_ l))

(defun *identifier (e table)
  (lookup-in-table
   e table 'initial-table))

(defun initial-table (name)
  (cond
   ((eq name (quote t)) t)
   ((eq name (quote nil)) nil)
  (t (build 
      (quote primitive)
      name))))

(defun lookup-in-table (name table table-f)
  (cond
   ((null table) (funcall table-f name))
   (t (lookup-in-entry
       name
       (car table)
       (lambda (name)
         (lookup-in-table
          name
          (cdr table)
          table-f))))))

(defun lookup-in-entry (name entry entry-f)
  (lookup-in-entry-help
   name
   (first_ entry)
   (second_ entry)
   entry-f))

(defun lookup-in-entry-help (name names values entry-f)
  (cond
   ((null names) (funcall entry-f name))
   ((eq (car names) name)
   (car values))
  (t (lookup-in-entry-help
      name
      (cdr names)
      (cdr values)
      entry-f))))

(defun *application (e table)
  (apply_
   (meaning (function-of e) table)
   (evlis (arguments-of e) table)))

(defun evcon (lines table)
  (cond
   ((meaning
     (question-of (car lines)) table)
    (meaning
     (answer-of (car lines)) table))
   (t (evcon (cdr lines) table))))

(defun question-of (l)
  (first_ l))
    
(defun answer-of (l)
  (second_ l))

(defun *cond (e table)
  (evcon (cond-lines e) table))

(defun cond-lines (l) 
  (cdr l))


(defun apply_ (fun vals)
  (cond
   ((primitive? fun)
    (apply-primitive
     (second_ fun) vals))
   ((non-primitive? fun)
    (apply-closure
     (second_ fun) vals))))

(defun primitive? (l)
  (eq
   (first_ l)
   (quote primitive)))

(defun non-primitive? (l)
  (eq
   (first_ l)
   (quote non-primitive)))

(defun add1 (n)
  (+ 1 n))

(defun apply-primitive (name vals)
  (cond
   ((eq name (quote car))
    (car (first_ vals)))
   ((eq name (quote cdr))
    (cdr (first_ vals)))
   ((eq name (quote cons))
    (cons (first_ vals) (second_ vals)))
   ((eq name (quote eq))
    (eq (first_ vals) (second_ vals)))
   ((eq name (quote atom))
    (atom (first_ vals) ))   
   ((eq name (quote not))
    (not (first_ vals) ))   
   ((eq name (quote null))
    (null (first_ vals) ))   
   ((eq name (quote number))
    (numberp (first_ vals) ))   
   ((eq name (quote zero))
    (zero (first_ vals) ))      
   ((eq name (quote add1))
    (add1 (first_ vals) ) )  
   ((eq name (quote sub1))
    (sub1 (first_ vals) )) ))

(defun function-of (l) 
  (car l))

(defun arguments-of (l) 
  (cdr l))

(defun evlis (args table)
  (cond
   ((null args) (quote ()))
   (t (cons (meaning (car args) table)
            (evlis (cdr args) table)))))

(defun apply-closure (closure vals)
  (meaning (body-of closure)
           (extend-table
            (new-entry
             (formals-of closure) vals)
            (table-of closure))))

(defun body-of (l)
  (third l))

(defun extend-table (a b)
  (cons a b))

(defun new-entry (a b)
  (build a b))

(defun formals-of (l)
  (second_ l))

(defun table-of (l)
  (first_ l))

(defun *lambda (e table)
  (build (quote non-primitive)
         (cons table (cdr e))))
    
; ------------------------------
;truth values
(print (value_ '(eq 1 1)))
; T

(print (value_ '(eq 1 2)))
; NIL false

;truth values
(print (value_ '(cond ((eq 1 2) 'non-normality) (t 'normality))))
; NORMALITY

;numbers
(print (value_ '23))
; 23

;quoted s-expression
(print (value_ '(add1 1)))
; 2
