Status commit; split to avoid absolute dependency on cxml and closure-html
templates.lisp
Wed Nov 18 10:23:05 UTC 2009 pix@kepibu.org
* Status commit; split to avoid absolute dependency on cxml and closure-html
--- old-Oh, Ducks!/templates.lisp 1970-01-01 00:00:00.000000000 +0000
+++ new-Oh, Ducks!/templates.lisp 2014-03-07 10:50:28.000000000 +0000
@@ -0,0 +1,68 @@
+(in-package #:oh-ducks)
+
+(defclass css-selector-template (unify::expression-template)
+ ((parser :initarg :parser :initform nil) ;; subtype generally determines parser
+ (specifiers :reader specifiers) ;; list of (specifier . variable) and (specifier . template)
+ ))
+
+(defclass xml-template (css-selector-template) ()) ;; parses xml
+
+(defclass html-template (css-selector-template) ()) ;; parses html
+
+
+(defvar *default-parser* nil "Determines the default parser when none is specified.")
+
+(defgeneric document-parser (template)
+ (:documentation "Returns a function which, given an unparsed document, parses that document into some sort of structure."))
+
+(defmethod document-parser ((template css-selector-template))
+ (slot-value template 'parser))
+
+(defgeneric make-template-for-parser (parser spec)
+ (:documentation "Returns a template of the appropriate type for a given parser.")
+ (:method ((parser t) spec)
+ (make-instance 'css-selector-template :parser parser :spec spec))
+ (:method ((parser null) spec)
+ (error "No parser specified.")))
+
+(defun %spec-includes-opts (spec)
+ (keywordp (first (second spec))))
+
+(defmethod make-template ((kind (eql 'html)) (spec cons))
+ (destructuring-bind (&key parser)
+ (if (%spec-includes-opts spec)
+ (second spec)
+ (list :parser *default-parser*))
+ (make-template-for-parser parser spec)))
+
+(defun combine-selectors (selector parent)
+ (let ((combinator (car (last selector))))
+ (cond
+ ((null parent)
+ selector)
+ ((combinator-p combinator)
+ (setf (slot-value combinator 'matcher) parent)
+ selector)
+ (t
+ (nconc selector (list (make-instance 'descendant-combinator :matcher parent)))))))
+
+(defun parse-specifiers (specs template parent)
+ (loop :for (css-specifier . rest) :in specs
+ :for selector = (combine-selectors (parse-selector css-specifier) parent)
+ :collect (cons selector
+ (cond
+ ((unify::template-p rest) rest)
+ ((unify::variablep rest) rest)
+ ((consp rest)
+ (make-instance (class-of template)
+ :spec (list* (first (template-spec template)) rest)
+ :css-specifiers rest
+ :parent selector))))))
+
+(defmethod initialize-instance :after ((template css-selector-template) &key css-specifiers parent &allow-other-keys)
+ (let* ((spec (template-spec template))
+ (specifiers-and-vars (or css-specifiers (if (%spec-includes-opts spec)
+ (cddr spec)
+ (rest spec)))))
+ (setf (slot-value template 'specifiers)
+ (parse-specifiers specifiers-and-vars template parent))))