(in-package "XLISP")
(export '(compile compile-file *compile-verbose* *compile-print*))
(defpackage "XLSCMP"
(:use "XLISP")
(:import-from "XLISP" "*CMP-SETF*" "*CMP-STRUCTS*" "*CMP-GLOBAL-MACROS*"
"*CMP-MACROS*" "*CMP-SPECIALS*" #+xlisp-stat "ADD-METHOD"))
(in-package "XLSCMP")
#|
put in package stuff
move macros to cmpmacr.lsp
move cps stuff to convert.lsp
|#
(require "backquot")
(require "cmpmacro")
(require "convert")
(require "cells")
(require "simplify")
(require "lift")
(require "gencode")
(require "peephole")
(require "assemble")
#|
Macros currently defined (**** need to be checked over ***):
DEFSETF PUSH PUSHNEW STEP WITH-INPUT-FROM-STRING WITH-OPEN-FILE
WITH-OUTPUT-TO-STRING
Macros needed (check which are really needed):
assert call-method ccase check-type ctypecase decf declaim defclass
defgeneric define-compiler-macro define-condition define-declaration
define-method-combination define-modify-macro define-setf-method
defmethod defpackage deftype destructuring-bind do-all-symbols
do-external-symbols do-symbols ecase encapsulated etypecase formatter
gathering generic-function handler-bind handler-case ignore-errors
in-package incf iterate loop-finish mapping multiple-value-bind
multiple-value-list multiple-value-setq next-in nth-value pop
pprint-exit-if-exhausted pprint-logical-block pprint-pop
print-unreadable-object producing psetf remf restart-bind restart-case
rotatef shiftf terminate-producing typecase with-accessors
with-compilation-unit with-condition-restarts with-hash-table-iterator
with-open-stream with-package-iterator with-simple-restarts with-slots
with-standard-io-syntax
|#
(defun pscvt (e)
(progv '(*cmp-env* *cmp-fenv* *cmp-denv* *cmp-tenv* *cmp-specials*
*cmp-gvars* *cmp-gfuns* *cmp-consts*
*cmp-specials* *cmp-macros* *cmp-setf* *cmp-structs*)
'(nil nil nil nil nil nil nil nil nil nil nil nil)
(let ((n (if (and (consp e) (eq (first e) 'lambda))
(convert-lambda e)
(convert-lambda `(lambda () ,e)))))
(pp-cps (merge-tests (simplify-tree (insert-cells n)))))))
;;;;
;;;; Simple compiler front end
;;;;
(defun cmp (e &optional name)
(progv '(*cmp-env* *cmp-denv* *cmp-tenv*
*cmp-gvars* *cmp-gfuns* *cmp-consts*)
'(nil nil nil nil nil nil)
(let ((n (if (and (consp e) (eq (first e) 'lambda))
(if name
(convert-named-lambda (cons name (rest e)))
(convert-lambda e))
(convert-lambda `(lambda () ,e)))))
(insert-cells n)
(substitute-all-variables n)
(collapse-null-lambda-calls n)
(simplify-tree n)
(merge-tests n)
(let ((pieces (lift-lambdas n)))
(dolist (p pieces)
(let ((c (second p)))
(extract-constants c)
(remove-unused-cells c)
;;(mapcar #'pp-cps p)
))
(generate-code pieces)))))
(defun pcmp (e) (pprint (cmp e)))
(defun cmp-reset ()
(mapcar #'set
'(*cmp-env* *cmp-fenv* *cmp-denv* *cmp-tenv*
*cmp-specials* *cmp-macros* *cmp-setf* *cmp-structs*
*cmp-gvars* *cmp-gfuns* *cmp-consts*)
'(nil nil nil nil nil nil nil nil nil nil nil)))
(defparameter *cmp-files*
'("backquot" "cmpmacro" "convert" "cells" "simplify"
"lift" "gencode" "peephole" "assemble" "cmpfront"))
(defun compile-file-list (list &optional load)
(progv '(*features*)
#+unix '((WINDOWS DIALOGS COLOR UNIX X11 XLISP))
#+macintosh '((WINDOWS DIALOGS MACINTOSH XLISP))
(dolist (f list)
(format t "~%Compiling file ~s ... ~%" f)
(compile-file f)
(format t "finished compiling file ~s~%~%" f)
(if load (load f)))))
(defun compile-cmp () (compile-file-list *cmp-files* t))
;;;;;
;;;;;
;;;;; New File Compiler
;;;;;
;;;;;
(defun print-compiled-form (form stream sp)
(let ((*print-readably* t)
(*print-symbol-package* sp))
(format stream "~s~%" form)))
(defun accumulate-compiled-form (form outstuff)
(rplacd (last outstuff) (list form)))
;;**** change default later?
(defvar *compile-verbose* t)
(defvar *compile-print* t)
(defvar *compile-print-symbol-package* nil)
(defvar *compile-warn-specials* nil)
(defvar *cmp-specials* nil)
(defvar *cmp-macros* nil)
(defvar *cmp-setf* nil)
(defvar *cmp-structs* nil)
#|
(defun file-name-needs-extension (fname)
(not (eql #\.
(find-if-not #'(lambda (x) (or (digit-char-p x) (alpha-char-p x)))
fname
:from-end t))))
(defun lsp-file-name (f)
(if (file-name-needs-extension f)
(concatenate 'string f ".lsp")
f))
(defun fsl-file-name (f)
(let ((n (length f)))
(unless (and (<= 4 (length f)) (string= (subseq f (- n 4) n) ".lsp"))
(error "not a valid lisp file name -- ~s" f))
(concatenate 'string (subseq f 0 (- n 4)) ".fsl")))
|#
(defun cmp-print-start-message (form)
(when *compile-print*
(let ((*print-level* 2)
(*print-length* 3))
(format t "~&; compiling ~s ... " form)
(force-output))))
(defun cmp-print-end-message ()
(when *compile-print*
(format t "done~%")
(force-output)))
(defun expand-one (e)
(if (consp e)
(loop
(if (member (first e) '(progn macrolet eval-when)) (return e))
(multiple-value-bind (ee flag) (cmp-macroexpand-1 e)
(if flag
(setq e ee)
(return e))))))
;;**** %set-cmp-macro???
(defun compile-one (e compile-time-too stream)
(handler-case
(progn
(setq e (expand-one e))
(case (first e)
(progn (dolist (e (rest e)) (compile-one e compile-time-too stream)))
(macrolet
(let ((macs (second e))
(env (list nil *cmp-fenv* *cmp-macros* *cmp-global-macros*))
(frame nil)
(body (rest (rest e)))
(*cmp-fenv* *cmp-fenv*))
(dolist (m macs)
(push
(cons (first m)
(coerce-to-macro
(parse-macro (first m) (second m) (rest (rest m)) env)))
frame))
(dolist (x frame) (push x *cmp-fenv*))
(compile-one `(progn ,@body) compile-time-too stream)))
(eval-when
(let* ((sits (second e))
(body `(progn ,@(rest (rest e))))
(lt (or (member 'load sits) (member :load-toplevel sits)))
(ct (or (member 'compile sits) (member :compile-toplevel sits)))
(ex (or (member 'eval sits) (member :execute sits))))
(cond
((or (and lt ct)
(and lt (not ct) ex compile-time-too))
(compile-one body t stream))
((or (and lt (not ct) (not compile-time-too))
(and lt (not ct) (not ex)))
(compile-one body nil stream))
((or (and (not lt) ct)
(and (not lt) (not ct) ex compile-time-too))
(eval body)))))
(t (if compile-time-too (eval e))
(compile-form e stream))))
(error (c)
(format *error-output* "~&Compiler error: ~a~%" c)
;;****(format stream "~&;;**** Error compiling exression:~%")
(compile-form `(eval ',e) stream))))
;;**** could ignore top level atoms, (function ...) expressions
(defun compile-form (e outstuff)
(labels ((cmparg (e)
(cond
((and (consp e)
(eq (first e) 'function)
(consp (second e))
(eq (first (second e)) 'lambda))
;;**** should be put in quote?
`(byte-code-close (quote ,(assemble (cmp (second e))))))
((consp e) (rcmp e))
(t e)))
(rcmp (e)
(if (consp e)
(let ((f (first e)))
(if (and (symbolp f)
(not (assoc f *cmp-fenv*))
(not (assoc f *cmp-macros*))
(not (assoc f *cmp-global-macros*))
(fboundp f)
(functionp (symbol-function f)))
`(,(first e) ,@(mapcar #'cmparg (rest e)))
e))
e)))
(handler-case
(let ((ce (rcmp e)))
;;**** don't need the test -- top level (function ...) 's are not done
(accumulate-compiled-form
(if (typep ce 'byte-code) ce (assemble (cmp ce)))
;(if (typep ce 'byte-code) ce (assemble (cmp `(eval ',ce))))
outstuff))
(error (c)
(format *error-output* "~&Compiler error: ~a~%" c)
(accumulate-compiled-form (assemble (cmp `(eval ',e)))
outstuff)))))
#|
(defun compile-form (e outstuff)
(accumulate-compiled-form (assemble (cmp e)) outstuff))
|#
(defun print-fsl-version-check (out sp)
(let ((major xlisp::*fsl-major-version*)
(minor xlisp::*fsl-minor-version*))
(print-compiled-form `(xlisp::check-fsl-version ,major ,minor) out sp)))
;;**** need to avoid creating bad .fsl file
(defun compile-file (file &key
(output-file (merge-pathnames ".fsl" file))
(temporary-file (merge-pathnames "cmptmp.fsl" file))
(load nil)
((:print *compile-print*) *compile-print*)
((:verbose *compile-verbose*) *compile-verbose*)
((:print-symbol-package sp) ;;**** do this cleaner
*compile-print-symbol-package*))
(let* ((*package* *package*)
(*readtable* *readtable*)
(*cmp-specials* nil)
(*cmp-macros* nil)
(*cmp-setf* nil)
(*cmp-structs* nil)
(iname (merge-pathnames ".lsp" file)))
(with-open-file (in iname)
(with-open-file (out temporary-file :direction :output)
(when *compile-verbose*
(format t "~&; compiling file ~s~%" iname)
(force-output))
(print-fsl-version-check out sp)
(let ((eof (list 'eof)))
(do ((e (read in nil eof) (read in nil eof)))
((eq e eof))
(let ((outstuff (list 'progn)))
(cmp-print-start-message e)
(let ((*cmp-fenv* nil))
(compile-one e nil outstuff))
(cmp-print-end-message)
;; this insures that a single expression is printed for
;; each expression read -- so common literals can be
;; handled by circle printing/reading.
(case (length outstuff)
(1 nil)
(2 (print-compiled-form (second outstuff) out sp))
(t (print-compiled-form (assemble (cmp `(eval ',outstuff)))
out
sp))))))))
(rename-file temporary-file output-file)
(if load (load output-file))))
;;**** this doesn't currently work for compiling macros
(defun compile-lambda-expression (fun name env macrop)
(when env (error "COMPILE can only compile top level definitions"))
(let ((*cmp-specials* nil)
(*cmp-macros* nil)
(*cmp-fenv* nil)
(*cmp-setf* nil)
(*cmp-structs* nil))
(let* ((fun (if macrop (cons 'lambda (rest fun)) fun))
(cfun (byte-code-close (assemble (cmp fun name)))))
(if macrop (coerce-to-macro cfun) cfun))))
(defun compile-return (f cfun)
(if f
(xlisp::install-function f cfun)
cfun))
(defun compile (f &optional (fun (symbol-function f)))
(cond
((or (typep fun 'subr) (typep fun 'fsubr) (compiled-function-p fun))
(compile-return f fun))
((typep fun 'closure)
(multiple-value-bind (flam top fname) (function-lambda-expression fun)
(let ((name (if f f fname))
(macrop (eq (first flam) 'macro)))
(compile-return f (compile-lambda-expression flam name top macrop)))))
((and (consp fun) (eq (first fun) 'lambda))
(compile-return f (compile-lambda-expression fun f nil nil)))
(t (error "bad argument type -- ~s" fun))))
(provide "cmpload")
syntax highlighted by Code2HTML, v. 0.9.1