X-Git-Url: http://git.kpe.io/?a=blobdiff_plain;f=base.lisp;h=17281522660cfb75e834706ce90ac2e4e4fd9573;hb=2eab8c677bfe8183f3e1e5bef25d30376873e18c;hp=85a59117fc1b81e94cf59e178e1a86de1011a5da;hpb=9c9a88110167cb4727f04677192fd7afd4c8b00f;p=lml.git
diff --git a/base.lisp b/base.lisp
index 85a5911..1728152 100644
--- a/base.lisp
+++ b/base.lisp
@@ -1,13 +1,13 @@
-;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
+;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
-;;;; Name: lml.cl
+;;;; Name: base.lisp
;;;; Purpose: Lisp Markup Language functions
;;;; Programmer: Kevin M. Rosenberg
;;;; Date Started: Aug 2002
;;;;
-;;;; $Id: base.lisp,v 1.1 2002/12/29 09:10:41 kevin Exp $
+;;;; $Id$
;;;;
;;;; This file, part of LML, is Copyright (c) 2002 by Kevin M. Rosenberg
;;;;
@@ -16,8 +16,7 @@
;;;; (http://www.gnu.org/licenses/gpl.html)
;;;; *************************************************************************
-(declaim (optimize (debug 3) (speed 3) (safety 3) (compilation-speed 0)))
-(in-package :lml)
+(in-package #:lml)
(defun html4-prologue-string ()
"")
@@ -26,139 +25,198 @@
"")
(defun xhtml-prologue-string ()
- "")
+ "")
(defvar *print-spaces* nil)
(defvar *indent* 0)
(defun reset-indent ()
(setq *indent* 0))
-(defun lml-print (str &rest args)
+(defun lml-format (str &rest args)
(when (streamp *html-output*)
(when *print-spaces* (indent-spaces *indent* *html-output*))
(if args
- (apply #'format *html-output* str args)
- (princ str *html-output*))
- (when *print-spaces* (format *html-output* "~%"))
- (values)))
+ (apply #'format *html-output* str args)
+ (write-string str *html-output*))
+ (when *print-spaces* (write-char #\newline *html-output*))))
-(defmacro lml-line (str &rest args)
- `(lml-print ,str ,@args))
+(defun lml-princ (s)
+ (princ s *html-output*))
+
+(defun lml-print (s)
+ (format *html-output* "~A~%" s))
+
+(defun lml-write-char (char)
+ (write-char char *html-output*))
+
+(defun lml-write-string (str)
+ (write-string str *html-output*))
(defun lml-print-date (date)
- (lml-print (date-string date)))
+ (lml-write-string (date-string date)))
(defmacro lml-exec-body (&body forms)
`(progn
,@(mapcar
#'(lambda (form)
- (etypecase form
- (string
- `(lml-print ,form))
- (number
- `(lml-print "~D" ,form))
- (symbol
- (when form
- `(lml-print (string-downcase (symbol-name ,form)))))
- (cons
- form)))
+ (etypecase form
+ (string
+ `(lml-princ ,form))
+ (number
+ `(lml-format "~D" ,form))
+ (symbol
+ (when form
+ `(lml-princ ,form)))
+ (cons
+ form)))
forms)))
(defmacro with-attr-string (tag attr-string &body body)
(let ((attr (gensym)))
`(let ((,attr ,attr-string))
- (lml-print "<~(~A~)~A>" ',tag
- (if (and (stringp ,attr) (plusp (length ,attr)))
- (format nil "~A" ,attr)
- ""))
+ (lml-format "<~(~A~)~A>" ',tag
+ (if (and (stringp ,attr) (plusp (length ,attr)))
+ (format nil " ~A" ,attr)
+ ""))
(incf *indent*)
(lml-exec-body ,@body)
(decf *indent*)
- (lml-print "~(~A~)>" ',tag))))
+ (lml-format "~(~A~)>" ',tag))))
+
+(defmacro with-no-endtag-attr-string (tag attr-string)
+ (let ((attr (gensym)))
+ `(let ((,attr ,attr-string))
+ (lml-format "<~(~A~)~A />" ',tag
+ (if (and (stringp ,attr) (plusp (length ,attr)))
+ (format nil " ~A" ,attr)
+ "")))))
(defun one-keyarg-string (key value)
"Return attribute string for keys"
(format nil "~(~A~)=\"~A\"" key
- (typecase value
- (symbol
- (string-downcase (symbol-name value)))
- (string
- value)
- (t
- (eval value)))))
+ (typecase value
+ (symbol
+ (string-downcase (symbol-name value)))
+ (string
+ value)
+ (t
+ (eval value)))))
(defmacro with-keyargs (tag keyargs &body body)
(let ((attr (gensym))
- (kv (gensym)))
+ (kv (gensym)))
`(progn
(let ((,attr '()))
- (dolist (,kv ',keyargs)
- (awhen (cadr ,kv)
- (push (one-keyarg-string (car ,kv) it) ,attr)))
+ (dolist (,kv ,keyargs)
+ (awhen (cdr ,kv)
+ (push (one-keyarg-string (car ,kv) it) ,attr)))
(with-attr-string ,tag (list-to-spaced-string (nreverse ,attr)) ,@body)))))
+(defmacro with-no-endtag-keyargs (tag keyargs)
+ (let ((attr (gensym))
+ (kv (gensym)))
+ `(progn
+ (let ((,attr '()))
+ (dolist (,kv ,keyargs)
+ (awhen (cdr ,kv)
+ (push (one-keyarg-string (car ,kv) it) ,attr)))
+ (with-no-endtag-attr-string ,tag (list-to-spaced-string (nreverse ,attr)))))))
+
+(defmacro bind-one-keyarg (keyarg)
+ `(list ,(car keyarg) ,(cdr keyarg)))
+
+(defmacro bind-all-keyargs (keyargs)
+ "Convert a list of keyarg pairs and convert eval/bind arguments"
+ (let* ((npairs (length keyargs))
+ (syms (make-array npairs))
+ (ipair 0)
+ (ipair2 0))
+ (declare (dynamic-extent syms))
+ (dotimes (i npairs)
+ (setf (aref syms i) (gensym)))
+ `(let ,(mapcar #'(lambda (ka)
+ (prog1
+ (list (aref syms ipair) (cdr ka))
+ (incf ipair)))
+ keyargs)
+ (list ,@(mapcar #'(lambda (ka)
+ (prog1
+ `(cons ,(car ka) ,(aref syms ipair2))
+ (incf ipair2)))
+ keyargs)))))
+
(defmacro with (tag &rest args)
+ "Return a list of keyargs and also the body of LML form"
(let ((body '())
- (keyargs '())
- (n (length args)))
- (do ((i 0 (1+ i)))
- ((> i (1- n)))
- (let ((arg (nth i args))
- (value (when (< (1+ i) n)
- (nth (1+ i) args))))
- (if (keyword-symbol? arg)
- (progn
- (push (list arg value) keyargs)
- (incf i))
- (push arg body))))
- `(with-keyargs ,tag ,keyargs ,@(nreverse body))))
-
-
-(defmacro keyargs-string (&rest args)
- "Returns a string of attributes and values. Result contains a leading space."
- (let ((keyarg-list '()))
- (loop for ( name val ) on args by #'cddr
- do
- (when val
- (push (one-keyarg-string name val) keyarg-list)))
- (list-to-spaced-string (nreverse keyarg-list))))
-
+ (keyargs '())
+ (bound-keyargs (gensym)))
+ (do* ((n (length args))
+ (i 0 (+ 2 i))
+ (arg (nth i args) (nth i args))
+ (value (when (< (1+ i) n)
+ (nth (1+ i) args))
+ (when (< (1+ i) n)
+ (nth (1+ i) args))))
+ ((or (not (keyword-symbol? arg))
+ (>= i n))
+ (dotimes (j (- n i))
+ (push (nth (+ i j) args) body)))
+ (push (cons arg value) keyargs))
+ (setq keyargs (nreverse keyargs))
+ (setq body (nreverse body))
+ `(let ((,bound-keyargs ,(macroexpand `(bind-all-keyargs ,keyargs))))
+ ,(macroexpand `(with-keyargs ,tag ,bound-keyargs ,@body)))))
+
+(defmacro with-no-endtag (tag &rest args)
+ "Return a list of keyargs body of LML form"
+ (let ((keyargs '())
+ (bound-keyargs (gensym)))
+ (do* ((n (length args))
+ (i 0 (+ 2 i))
+ (arg (nth i args) (nth i args))
+ (value (when (< (1+ i) n)
+ (nth (1+ i) args))
+ (when (< (1+ i) n)
+ (nth (1+ i) args))))
+ ((or (not (keyword-symbol? arg))
+ (>= i n)))
+ (push (cons arg value) keyargs))
+ (setq keyargs (nreverse keyargs))
+ `(let ((,bound-keyargs ,(macroexpand `(bind-all-keyargs ,keyargs))))
+ ,(macroexpand `(with-no-endtag-keyargs ,tag ,bound-keyargs)))))
+
+(defmacro jscript (&body body)
+ `(with script :language "JavaScript" :type "text/javascript"
+ ,@body))
(defmacro xhtml-prologue ()
`(progn
- (lml-print "~A~%" (xml-prologue-string))
- (lml-print "~A~%" (xhtml-prologue-string))))
+ (lml-format "~A~%" (xml-prologue-string))
+ (lml-format "~A~%" (xhtml-prologue-string))))
-(defmacro link (dest &body body)
+(defmacro alink (dest &body body)
`(with a :href ,dest ,@body))
-(defmacro link-c (class dest &body body)
- `(with a :href ,dest :class ,class ,@body))
+(defmacro alink-c (class dest &body body)
+ `(with a :href ,dest :class (quote ,class) ,@body))
-(defmacro img (dest &key class id alt style width height align)
- (let ((attr
- (eval `(keyargs-string :class ,class :id ,id :alt ,alt :style ,style
- :width ,width :height ,height :align ,align))))
- `(lml-print ,(format nil "" dest attr))))
+(defmacro img (dest &rest args)
+ `(with-no-endtag img :src ,dest ,@args))
-(defmacro input (&key name class id type style size maxlength value checked)
- (let ((attr
- (eval `(keyargs-string :name ,name :class ,class :id ,id :style ,style
- :size ,size :maxlength ,maxlength :value ,value
- :type ,type :checked ,checked))))
- `(lml-print ,(format nil "" attr))))
+(defmacro input (&rest args)
+ `(with-no-endtag input ,@args))
-(defmacro meta (name content)
- `(with meta :name ,name :content ,content))
+(defmacro link (&rest args)
+ `(with-no-endtag link ,@args))
-(defmacro meta-key (&key name content http-equiv)
- `(with meta :name ,name :content ,content :http-equiv ,http-equiv))
+(defmacro meta (&rest args)
+ `(with-no-endtag meta ,@args))
-(defmacro br ()
- `(lml-print "
"))
+(defmacro br (&rest args)
+ `(with-no-endtag br ,@args))
-(defmacro hr ()
- `(lml-print "