summary refs log tree commit diff
path: root/src/guile
diff options
context:
space:
mode:
authorLudovic Court`es2006-03-01 17:32:20 +0000
committerLudovic Court`es2006-03-01 17:32:20 +0000
commita9b63d91b3d75b65d058dde3bc3f66d8aedf41fb (patch)
treef60911738c370c91a8c931e1e9e26dd25a9271f5 /src/guile
parentfa0b07b863a029896688805f411fc7e361f837f0 (diff)
downloadskribilo-a9b63d91b3d75b65d058dde3bc3f66d8aedf41fb.tar.gz
skribilo-a9b63d91b3d75b65d058dde3bc3f66d8aedf41fb.tar.lz
skribilo-a9b63d91b3d75b65d058dde3bc3f66d8aedf41fb.zip
Significantly optimized lookup of markup writers.
* src/guile/skribilo/engine.scm (<engine>)[writers]: Became a hash table
  (instead of a list).
  [free-writers]: New.
  (engine-add-writer!): Changed accordingly.

* src/guile/skribilo/writer.scm (write-object): Renamed to `write'.
  (lookup-markup-writer): Rewritten according to the above changes.
  (markup-writer-get): Likewise.
  (markup-writer-get*): Likewise.

git-archimport-id: lcourtes@laas.fr--2004-libre/skribilo--devel--1.2--patch-63
Diffstat (limited to 'src/guile')
-rw-r--r--src/guile/skribilo/engine.scm48
-rw-r--r--src/guile/skribilo/writer.scm193
2 files changed, 139 insertions, 102 deletions
diff --git a/src/guile/skribilo/engine.scm b/src/guile/skribilo/engine.scm
index 5800486..fbaf4d2 100644
--- a/src/guile/skribilo/engine.scm
+++ b/src/guile/skribilo/engine.scm
@@ -53,14 +53,43 @@
 ;;; Class definition.
 ;;;
 
+;; Note on writers
+;; ---------------
+;;
+;; `writers' here is an `eq?' hash table where keys are markup names
+;; (symbols) and values are lists of markup writers (most of the time, the
+;; list will only contain one writer).  Each of these writer may define a
+;; predicate or class that may further restrict its applicability.
+;;
+;; `free-writers' is a list of writers that may apply to *any* kind of
+;; markup.  These are typically define by passing `#t' to `markup-writer'
+;; instead of a symbol:
+;;
+;;   (markup-writer #f (find-engine 'xml)
+;;     :before ...
+;;     ...)
+;;
+;; The XML engine contains an example of such free writers.  Again, these
+;; writers may define a predicate or a class restricting their applicability.
+;;
+;; The distinction between these two kinds of writers is mostly performance:
+;; "free writers" are rarely used and markup-specific are the most common
+;; case which we want to be fast.  Therefore, for the latter case, we can't
+;; afford traversing a list of markups, evaluating each and every markup
+;; predicate.
+;;
+;; For more details, see `markup-writer-get' and `lookup-markup-writer' in
+;; `(skribilo writer)'.
+
 (define-class <engine> ()
   (ident		:init-keyword :ident		:init-value '???)
   (format		:init-keyword :format		:init-value "raw")
-  (info		:init-keyword :info		:init-value '())
+  (info		        :init-keyword :info		:init-value '())
   (version		:init-keyword :version
 			:init-value 'unspecified)
   (delegate		:init-keyword :delegate		:init-value #f)
-  (writers		:init-keyword :writers		:init-value '())
+  (writers              :init-thunk make-hash-table)
+  (free-writers         :init-value '())
   (filter		:init-keyword :filter		:init-value #f)
   (customs		:init-keyword :custom		:init-value '())
   (symbol-table	:init-keyword :symbol-table	:init-value '()))
@@ -268,7 +297,13 @@ otherwise the requested engine is returned."
 	(slot-set! e 'customs (cons (list id val) customs)))))
 
 
-(define (engine-add-writer! e ident pred upred opt before action after class valid)
+(define (engine-add-writer! e ident pred upred opt before action
+			    after class valid)
+  ;; Add a writer to engine E.  If IDENT is a symbol, then it should denote
+  ;; a markup name and the writer being added is specific to that markup.  If
+  ;; IDENT is `#t' (for instance), then it is assumed to be a ``free writer''
+  ;; that may apply to any kind of markup for which PRED returns true.
+
   (define (check-procedure name proc arity)
     (cond
       ((not (procedure? proc))
@@ -309,7 +344,12 @@ otherwise the requested engine is returned."
 	     :class class :pred pred :upred upred :options opt
 	     :before before :action action :after after
 	     :validate valid)))
-    (slot-set! e 'writers (cons n (slot-ref e 'writers)))
+    (if (symbol? ident)
+	(let ((writers (slot-ref e 'writers)))
+	  (hashq-set! writers ident
+		      (cons n (hashq-ref writers ident '()))))
+	(slot-set! e 'free-writers
+		   (cons n (slot-ref e 'free-writers))))
     n))
 
 
diff --git a/src/guile/skribilo/writer.scm b/src/guile/skribilo/writer.scm
index fe7781c..62fa8b0 100644
--- a/src/guile/skribilo/writer.scm
+++ b/src/guile/skribilo/writer.scm
@@ -1,29 +1,23 @@
-;;;;
-;;;; writer.stk	-- Skribe Writer Stuff
-;;;;
-;;;; Copyright © 2003-2004 Erick Gallesio - I3S-CNRS/ESSI <eg@essi.fr>
-;;;;
-;;;;
-;;;; 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 2 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, write to the Free Software
-;;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-;;;; USA.
-;;;;
-;;;;           Author: Erick Gallesio [eg@essi.fr]
-;;;;    Creation date: 15-Sep-2003 22:21 (eg)
-;;;; Last file update:  4-Mar-2004 10:48 (eg)
-;;;;
-
+;;; writer.scm  --  Markup writers.
+;;;
+;;; Copyright 2003, 2004  Erick Gallesio - I3S-CNRS/ESSI <eg@essi.fr>
+;;; Copyright 2005, 2006  Ludovic Courtès <ludovic.courtes@laas.fr>
+;;;
+;;;
+;;; 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 2 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, write to the Free Software
+;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+;;; USA.
 
 (define-module (skribilo writer)
   :export (<writer> writer? write-object writer-options writer-ident
@@ -33,6 +27,7 @@
 	   lookup-markup-writer copy-markup-writer)
 
   :use-module (skribilo utils syntax)
+  :autoload (srfi srfi-1)     (find filter)
   :autoload (skribilo engine) (engine? engine-ident? default-engine))
 
 
@@ -69,11 +64,11 @@
 (define (writer? obj)
   (is-a? obj <writer>))
 
-(define-method (write-object (obj <writer>) port)
+(define-method (write (obj <writer>) port)
   (format port "#[~A (~A) ~A]"
 	  (class-name (class-of obj))
 	  (slot-ref obj 'ident)
-	  (address-of obj)))
+	  (object-address obj)))
 
 
 
@@ -92,20 +87,6 @@
 	     (proc node e)))))
 
 
-(define (lookup-markup-writer node e)
-  (let ((writers (slot-ref e 'writers))
-	(delegate (slot-ref e 'delegate)))
-    (let loop ((w* writers))
-      (cond
-	((pair? w*)
-	   (let ((pred (slot-ref (car w*) 'pred)))
-	     (if (pred node e)
-		 (car w*)
-		 (loop (cdr w*)))))
-	((engine? delegate)
-	   (lookup-markup-writer node delegate))
-	(else
-	   #f)))))
 
 (define (make-writer-predicate markup predicate class)
   (let* ((t1 (if (symbol? markup)
@@ -130,27 +111,10 @@
 	       (and (t2 n e) (predicate n e)))))
 	t2)))
 
-;;;; ======================================================================
-;;;;
-;;;;				MARKUP-WRITER
-;;;;
-;;;; ======================================================================
-; (define-macro (lambda** arglist . body)
-;   (let ((parse-arglist (module-ref (resolve-module '(ice-9 optargs))
-; 				   'parse-arglist)))
-;     (parse-arglist
-;      arglist
-;      (lambda (mandatory-args optionals keys aok? rest-arg)
-;        (let ((l**-rest-arg (gensym "L**-rest"))
-; 	     (l**-loop (gensym "L**-loop")))
-; 	 `(lambda (,@mandatory-args . ,l**-rest-arg)
-; 	    `(let ,l**-loop ((,l**-rest-arg ,l**-rest-arg)
-; 			     (,rest-arg '())
-; 			     ,@optionals
-; 			     ,@keys)
-; 		  (if (null? ,l**-rest-arg)
-; 		      (begin
-; 			,@body)
+
+;;;
+;;; `markup-writer'
+;;;
 
 (define* (markup-writer markup ;; #:optional (engine #f)
 			#:key (predicate #f) (class #f) (options '())
@@ -191,53 +155,86 @@
 			     options before ac after class validate))))))
 
 
+
+;;;
+;;; Finding a markup writer.
+;;;
+
+(define (lookup-markup-writer node e)
+  ;; Find the writer that applies best to NODE.  See also `markup-writer-get'
+  ;; and `markup-writer-get*'.
+
+  (define (matching-writer writers)
+    (find (lambda (w)
+	    (let ((pred (slot-ref w 'pred)))
+	      (pred node e)))
+	  writers))
+
+  (let* ((writers (slot-ref e 'writers))
+	 (node-writers (hashq-ref writers (markup-markup node) '()))
+	 (delegate (slot-ref e 'delegate)))
+
+    (or (matching-writer node-writers)
+	(matching-writer (slot-ref e 'free-writers))
+	(and (engine? delegate)
+	     (lookup-markup-writer node delegate)))))
+
+
 (define* (markup-writer-get markup :optional engine :key (class #f) (pred #f))
+  ;; Get a markup writer for MARKUP (a symbol) in ENGINE, with class CLASS
+  ;; and user predicate PRED.  [FIXME: Useless since PRED is a procedure and
+  ;; therefore not comparable?]
+
+  (define (matching-writer writers)
+    (find (lambda (w)
+	    (and (if class (equal? (writer-class w) class) #t)
+		 (or (unspecified? pred)
+		     (eq? (slot-ref w 'upred) pred))))
+	  writers))
+
   (let ((e (or engine (default-engine))))
     (cond
       ((not (symbol? markup))
-	 (skribe-error 'markup-writer-get "Illegal symbol" markup))
+       (skribe-error 'markup-writer-get "illegal symbol" markup))
       ((not (engine? e))
-	 (skribe-error 'markup-writer-get "Illegal engine" e))
+       (skribe-error 'markup-writer-get "illegal engine" e))
       (else
-       (let liip ((e e))
-	 (let loop ((w* (slot-ref e 'writers)))
-	   (cond
-	     ((pair? w*)
-		(if (and (eq? (writer-ident (car w*)) markup)
-			 (equal? (writer-class (car w*)) class)
-			 (or (unspecified? pred)
-			     (eq? (slot-ref (car w*) 'upred) pred)))
-		    (car w*)
-		    (loop (cdr w*))))
-	     ((engine? (slot-ref e 'delegate))
-		(liip (slot-ref e 'delegate)))
-	     (else
-		#f))))))))
-
-
-;; Finds all writers that matches MARKUP with optional CLASS attribute.
+       (let* ((writers (slot-ref e 'writers))
+	      (markup-writers (hashq-ref writers markup '()))
+	      (delegate (slot-ref e 'delegate)))
+
+	 (or (matching-writer markup-writers)
+	     (and (engine? delegate)
+		  (markup-writer-get markup delegate
+				     :class class :pred pred))))))))
+
+
 (define* (markup-writer-get* markup #:optional engine #:key (class #f))
+  ;; Finds all writers, recursively going through the engine hierarchy, that
+  ;; match MARKUP with optional CLASS attribute.
+
+  (define (matching-writers writers)
+    (filter (lambda (w)
+	      (or (not class)
+		  (equal? (writer-class w) class)))
+	    writers))
+
   (let ((e (or engine (default-engine))))
     (cond
       ((not (symbol? markup))
-       (skribe-error 'markup-writer "Illegal symbol" markup))
+       (skribe-error 'markup-writer "illegal symbol" markup))
       ((not (engine? e))
-       (skribe-error 'markup-writer "Illegal engine" e))
+       (skribe-error 'markup-writer "illegal engine" e))
       (else
-       (let liip ((e e)
-		  (res '()))
-	 (let loop ((w* (slot-ref e 'writers))
-		    (res res))
-	   (cond
-	     ((pair? w*)
-	      (if (and (eq? (slot-ref (car w*) 'ident) markup)
-		       (equal? (slot-ref (car w*) 'class) class))
-		  (loop (cdr w*) (cons (car w*) res))
-		  (loop (cdr w*) res)))
-	     ((engine? (slot-ref e 'delegate))
-	      (liip (slot-ref e 'delegate) res))
-	     (else
-	      (reverse! res)))))))))
+       (let* ((writers (slot-ref e 'writers))
+	      (markup-writers (hashq-ref writers markup '()))
+	      (delegate (slot-ref e 'delegate)))
+
+	 (append (matching-writers writers)
+		 (if (engine? delegate)
+		     (markup-writer-get* markup delegate :class class)
+		     '())))))))
+
 
 (define* (copy-markup-writer markup old-engine :optional new-engine
 			      :key (predicate 'unspecified)