+;;; lispstrack.lisp ---
+
+;; Copyright (C) 2012 David Vazquez
+;; Copyright (C) 2012 Raimon Grau
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; This code is executed when lispstrack compiles this file
+;;; itself. The compiler provides compilation of some special forms,
+;;; as well as funcalls and macroexpansion, but no functions. So, we
+;;; define the Lisp world from scratch. This code has to define enough
+;;; language to the compiler to be able to run.
+#+lispstrack
+(progn
+ (eval-when-compile
+ (%compile-defmacro 'defmacro
+ '(lambda (name args &rest body)
+ `(eval-when-compile
+ (%compile-defmacro ',name '(lambda ,args ,@body))))))
+
+ (defmacro %defvar (name value)
+ `(progn
+ (eval-when-compile
+ (%compile-defvar ',name))
+ (setq ,name ,value)))
+
+ (defmacro defvar (name &optional value)
+ `(%defvar ,name ,value))
+
+ (defmacro %defun (name args &rest body)
+ `(progn
+ (eval-when-compile
+ (%compile-defun ',name))
+ (fsetq ,name (lambda ,args ,@body))))
+
+ (defmacro defun (name args &rest body)
+ `(%defun ,name ,args ,@body))
+
+ (defvar *package* (new))
+
+ (defvar nil (make-symbol "NIL"))
+ (set *package* "NIL" nil)
+
+ (defvar t (make-symbol "T"))
+ (set *package* "T" t)
+
+ (defun internp (name)
+ (in name *package*))
+
+ (defun intern (name)
+ (if (internp name)
+ (get *package* name)
+ (set *package* name (make-symbol name))))
+
+ (defun find-symbol (name)
+ (get *package* name))
+
+ ;; Basic functions
+ (defun = (x y) (= x y))
+ (defun + (x y) (+ x y))
+ (defun - (x y) (- x y))
+ (defun * (x y) (* x y))
+ (defun / (x y) (/ x y))
+ (defun 1+ (x) (+ x 1))
+ (defun 1- (x) (- x 1))
+ (defun zerop (x) (= x 0))
+ (defun truncate (x y) (floor (/ x y)))
+
+ (defun eql (x y) (eq x y))
+
+ (defun not (x) (if x nil t))
+
+ (defun cons (x y ) (cons x y))
+ (defun consp (x) (consp x))
+ (defun car (x) (car x))
+ (defun cdr (x) (cdr x))
+ (defun caar (x) (car (car x)))
+ (defun cadr (x) (car (cdr x)))
+ (defun cdar (x) (cdr (car x)))
+ (defun cddr (x) (cdr (cdr x)))
+ (defun caddr (x) (car (cdr (cdr x))))
+ (defun cdddr (x) (cdr (cdr (cdr x))))
+ (defun cadddr (x) (car (cdr (cdr (cdr x)))))
+ (defun first (x) (car x))
+ (defun second (x) (cadr x))
+ (defun third (x) (caddr x))
+ (defun fourth (x) (cadddr x))
+
+ (defun list (&rest args) args)
+ (defun atom (x)
+ (not (consp x)))
+
+ ;; Basic macros
+
+ (defmacro incf (x &optional (delta 1))
+ `(setq ,x (+ ,x ,delta)))
+
+ (defmacro decf (x &optional (delta 1))
+ `(setq ,x (- ,x ,delta)))
+
+ (defmacro push (x place)
+ `(setq ,place (cons ,x ,place)))
+
+ (defmacro when (condition &rest body)
+ `(if ,condition (progn ,@body) nil))
+
+ (defmacro unless (condition &rest body)
+ `(if ,condition nil (progn ,@body)))
+
+ (defmacro dolist (iter &rest body)
+ (let ((var (first iter))
+ (g!list (make-symbol "LIST")))
+ `(let ((,g!list ,(second iter))
+ (,var nil))
+ (while ,g!list
+ (setq ,var (car ,g!list))
+ ,@body
+ (setq ,g!list (cdr ,g!list))))))
+
+ (defmacro cond (&rest clausules)
+ (if (null clausules)
+ nil
+ (if (eq (caar clausules) t)
+ `(progn ,@(cdar clausules))
+ `(if ,(caar clausules)
+ (progn ,@(cdar clausules))
+ (cond ,@(cdr clausules))))))
+
+ (defmacro case (form &rest clausules)
+ (let ((!form (make-symbol "FORM")))
+ `(let ((,!form ,form))
+ (cond
+ ,@(mapcar (lambda (clausule)
+ (if (eq (car clausule) t)
+ clausule
+ `((eql ,!form ,(car clausule))
+ ,@(cdr clausule))))
+ clausules)))))
+
+ (defmacro ecase (form &rest clausules)
+ `(case ,form
+ ,@(append
+ clausules
+ `((t
+ (error "ECASE expression failed."))))))
+
+ (defmacro and (&rest forms)
+ (cond
+ ((null forms)
+ t)
+ ((null (cdr forms))
+ (car forms))
+ (t
+ `(if ,(car forms)
+ (and ,@(cdr forms))
+ nil))))
+
+ (defmacro or (&rest forms)
+ (cond
+ ((null forms)
+ nil)
+ ((null (cdr forms))
+ (car forms))
+ (t
+ (let ((g (make-symbol "VAR")))
+ `(let ((,g ,(car forms)))
+ (if ,g ,g (or ,@(cdr forms))))))))
+
+ (defmacro prog1 (form &rest body)
+ (let ((value (make-symbol "VALUE")))
+ `(let ((,value ,form))
+ ,@body
+ ,value))))
+
+;;; This couple of helper functions will be defined in both Common
+;;; Lisp and in Lispstrack.
+(defun ensure-list (x)
+ (if (listp x)
+ x
+ (list x)))
+
+(defun !reduce (func list initial)
+ (if (null list)
+ initial
+ (!reduce func
+ (cdr list)
+ (funcall func initial (car list)))))
+
+;;; Go on growing the Lisp language in Lispstrack, with more high
+;;; level utilities as well as correct versions of other
+;;; constructions.
+#+lispstrack
+(progn
+ (defmacro defun (name args &rest body)
+ `(progn
+ (%defun ,name ,args ,@body)
+ ',name))
+
+ (defmacro defvar (name &optional value)
+ `(progn
+ (%defvar ,name ,value)
+ ',name))
+
+ (defun append-two (list1 list2)
+ (if (null list1)
+ list2
+ (cons (car list1)
+ (append (cdr list1) list2))))
+
+ (defun append (&rest lists)
+ (!reduce #'append-two lists '()))
+
+ (defun reverse-aux (list acc)
+ (if (null list)
+ acc
+ (reverse-aux (cdr list) (cons (car list) acc))))
+
+ (defun reverse (list)
+ (reverse-aux list '()))
+
+ (defun list-length (list)
+ (let ((l 0))
+ (while (not (null list))
+ (incf l)
+ (setq list (cdr list)))
+ l))
+
+ (defun length (seq)
+ (if (stringp seq)
+ (string-length seq)
+ (list-length seq)))
+
+ (defun concat-two (s1 s2)
+ (concat-two s1 s2))
+
+ (defun mapcar (func list)
+ (if (null list)
+ '()
+ (cons (funcall func (car list))
+ (mapcar func (cdr list)))))
+
+ (defun code-char (x) x)
+ (defun char-code (x) x)
+ (defun char= (x y) (= x y))
+
+ (defun <= (x y) (or (< x y) (= x y)))
+ (defun >= (x y) (not (< x y)))
+
+ (defun integerp (x)
+ (and (numberp x) (= (floor x) x)))
+
+ (defun plusp (x) (< 0 x))
+ (defun minusp (x) (< x 0))
+
+ (defun listp (x)
+ (or (consp x) (null x)))
+
+ (defun nth (n list)
+ (cond
+ ((null list) list)
+ ((zerop n) (car list))
+ (t (nth (1- n) (cdr list)))))
+
+ (defun last (x)
+ (if (null (cdr x))
+ x
+ (last (cdr x))))
+
+ (defun butlast (x)
+ (if (null (cdr x))
+ nil
+ (cons (car x) (butlast (cdr x)))))
+
+ (defun member (x list)
+ (cond
+ ((null list)
+ nil)
+ ((eql x (car list))
+ list)
+ (t
+ (member x (cdr list)))))
+
+ (defun remove (x list)
+ (cond
+ ((null list)
+ nil)
+ ((eql x (car list))
+ (remove x (cdr list)))
+ (t
+ (cons (car list) (remove x (cdr list))))))
+
+ (defun remove-if (func list)
+ (cond
+ ((null list)
+ nil)
+ ((funcall func (car list))
+ (remove-if func (cdr list)))
+ (t
+ (cons (car list) (remove-if func (cdr list))))))
+
+ (defun remove-if-not (func list)
+ (cond
+ ((null list)
+ nil)
+ ((funcall func (car list))
+ (cons (car list) (remove-if-not func (cdr list))))
+ (t
+ (remove-if-not func (cdr list)))))
+
+ (defun digit-char-p (x)
+ (if (and (<= #\0 x) (<= x #\9))
+ (- x #\0)
+ nil))
+
+ (defun parse-integer (string)
+ (let ((value 0)
+ (index 0)
+ (size (length string)))
+ (while (< index size)
+ (setq value (+ (* value 10) (digit-char-p (char string index))))
+ (incf index))
+ value))
+
+ (defun every (function seq)
+ ;; string
+ (let ((ret t)
+ (index 0)
+ (size (length seq)))
+ (while (and ret (< index size))
+ (unless (funcall function (char seq index))
+ (setq ret nil))
+ (incf index))
+ ret))
+
+ (defun assoc (x alist)
+ (cond
+ ((null alist)
+ nil)
+ ((eql x (caar alist))
+ (car alist))
+ (t
+ (assoc x (cdr alist)))))
+
+ (defun string= (s1 s2)
+ (equal s1 s2)))
+
+
+;;; The compiler offers some primitives and special forms which are
+;;; not found in Common Lisp, for instance, while. So, we grow Common
+;;; Lisp a bit to it can execute the rest of the file.
+#+common-lisp
+(progn
+ (defmacro while (condition &body body)
+ `(do ()
+ ((not ,condition))
+ ,@body))
+
+ (defmacro eval-when-compile (&body body)
+ `(eval-when (:compile-toplevel :load-toplevel :execute)
+ ,@body))
+
+ (defun concat-two (s1 s2)
+ (concatenate 'string s1 s2))