123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- ;;;; (sxml fold) -- transformation of sxml via fold operations
- ;;;;
- ;;;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
- ;;;; Written 2007 by Andy Wingo <wingo at pobox dot com>.
- ;;;;
- ;;;; This library is free software; you can redistribute it and/or
- ;;;; modify it under the terms of the GNU Lesser General Public
- ;;;; License as published by the Free Software Foundation; either
- ;;;; version 3 of the License, or (at your option) any later version.
- ;;;;
- ;;;; This library 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
- ;;;; Lesser General Public License for more details.
- ;;;;
- ;;;; You should have received a copy of the GNU Lesser General Public
- ;;;; License along with this library; if not, write to the Free Software
- ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- ;;;;
- ;;; Commentary:
- ;;
- ;; @code{(sxml fold)} defines a number of variants of the @dfn{fold}
- ;; algorithm for use in transforming SXML trees. Additionally it defines
- ;; the layout operator, @code{fold-layout}, which might be described as
- ;; a context-passing variant of SSAX's @code{pre-post-order}.
- ;;
- ;;; Code:
- (define-module (sxml fold)
- #:use-module (srfi srfi-1)
- #:export (foldt
- foldts
- foldts*
- fold-values
- foldts*-values
- fold-layout))
- (define (atom? x)
- (not (pair? x)))
- (define (foldt fup fhere tree)
- "The standard multithreaded tree fold.
- @var{fup} is of type [a] -> a. @var{fhere} is of type object -> a.
- "
- (if (atom? tree)
- (fhere tree)
- (fup (map (lambda (kid)
- (foldt fup fhere kid))
- tree))))
- (define (foldts fdown fup fhere seed tree)
- "The single-threaded tree fold originally defined in SSAX.
- @xref{sxml ssax,,(sxml ssax)}, for more information."
- (if (atom? tree)
- (fhere seed tree)
- (fup seed
- (fold (lambda (kid kseed)
- (foldts fdown fup fhere kseed kid))
- (fdown seed tree)
- tree)
- tree)))
- (define (foldts* fdown fup fhere seed tree)
- "A variant of @ref{sxml fold foldts,,foldts} that allows pre-order
- tree rewrites. Originally defined in Andy Wingo's 2007 paper,
- @emph{Applications of fold to XML transformation}."
- (if (atom? tree)
- (fhere seed tree)
- (call-with-values
- (lambda () (fdown seed tree))
- (lambda (kseed tree)
- (fup seed
- (fold (lambda (kid kseed)
- (foldts* fdown fup fhere
- kseed kid))
- kseed
- tree)
- tree)))))
- (define (fold-values proc list . seeds)
- "A variant of @ref{SRFI-1 Fold and Map, fold} that allows multi-valued
- seeds. Note that the order of the arguments differs from that of
- @code{fold}."
- (if (null? list)
- (apply values seeds)
- (call-with-values
- (lambda () (apply proc (car list) seeds))
- (lambda seeds
- (apply fold-values proc (cdr list) seeds)))))
- (define (foldts*-values fdown fup fhere tree . seeds)
- "A variant of @ref{sxml fold foldts*,,foldts*} that allows
- multi-valued seeds. Originally defined in Andy Wingo's 2007 paper,
- @emph{Applications of fold to XML transformation}."
- (if (atom? tree)
- (apply fhere tree seeds)
- (call-with-values
- (lambda () (apply fdown tree seeds))
- (lambda (tree . kseeds)
- (call-with-values
- (lambda ()
- (apply fold-values
- (lambda (tree . seeds)
- (apply foldts*-values
- fdown fup fhere tree seeds))
- tree kseeds))
- (lambda kseeds
- (apply fup tree (append seeds kseeds))))))))
- (define (assq-ref alist key default)
- (cond ((assq key alist) => cdr)
- (else default)))
- (define (fold-layout tree bindings params layout stylesheet)
- "A traversal combinator in the spirit of SSAX's @ref{sxml transform
- pre-post-order,,pre-post-order}.
- @code{fold-layout} was originally presented in Andy Wingo's 2007 paper,
- @emph{Applications of fold to XML transformation}.
- @example
- bindings := (<binding>...)
- binding := (<tag> <bandler-pair>...)
- | (*default* . <post-handler>)
- | (*text* . <text-handler>)
- tag := <symbol>
- handler-pair := (pre-layout . <pre-layout-handler>)
- | (post . <post-handler>)
- | (bindings . <bindings>)
- | (pre . <pre-handler>)
- | (macro . <macro-handler>)
- @end example
- @table @var
- @item pre-layout-handler
- A function of three arguments:
- @table @var
- @item kids
- the kids of the current node, before traversal
- @item params
- the params of the current node
- @item layout
- the layout coming into this node
- @end table
- @var{pre-layout-handler} is expected to use this information to return a
- layout to pass to the kids. The default implementation returns the
- layout given in the arguments.
- @item post-handler
- A function of five arguments:
- @table @var
- @item tag
- the current tag being processed
- @item params
- the params of the current node
- @item layout
- the layout coming into the current node, before any kids were processed
- @item klayout
- the layout after processing all of the children
- @item kids
- the already-processed child nodes
- @end table
- @var{post-handler} should return two values, the layout to pass to the
- next node and the final tree.
- @item text-handler
- @var{text-handler} is a function of three arguments:
- @table @var
- @item text
- the string
- @item params
- the current params
- @item layout
- the current layout
- @end table
- @var{text-handler} should return two values, the layout to pass to the
- next node and the value to which the string should transform.
- @end table
- "
- (define (err . args)
- (error "no binding available" args))
- (define (fdown tree bindings pcont params layout ret)
- (define (fdown-helper new-bindings new-layout cont)
- (let ((cont-with-tag (lambda args
- (apply cont (car tree) args)))
- (bindings (if new-bindings
- (append new-bindings bindings)
- bindings))
- (style-params (assq-ref stylesheet (car tree) '())))
- (cond
- ((null? (cdr tree))
- (values
- '() bindings cont-with-tag (cons style-params params) new-layout '()))
- ((and (pair? (cadr tree)) (eq? (caadr tree) '@))
- (let ((params (cons (append (cdadr tree) style-params) params)))
- (values
- (cddr tree) bindings cont-with-tag params new-layout '())))
- (else
- (values
- (cdr tree) bindings cont-with-tag (cons style-params params) new-layout '())))))
- (define (no-bindings)
- (fdown-helper #f layout (assq-ref bindings '*default* err)))
- (define (macro macro-handler)
- (fdown (apply macro-handler tree)
- bindings pcont params layout ret))
- (define (pre pre-handler)
- (values '() bindings
- (lambda (params layout old-layout kids)
- (values layout (reverse kids)))
- params layout (apply pre-handler tree)))
- (define (have-bindings tag-bindings)
- (fdown-helper
- (assq-ref tag-bindings 'bindings #f)
- ((assq-ref tag-bindings 'pre-layout
- (lambda (tag params layout)
- layout))
- tree params layout)
- (assq-ref tag-bindings 'post
- (assq-ref bindings '*default* err))))
- (let ((tag-bindings (assq-ref bindings (car tree) #f)))
- (cond
- ((not tag-bindings) (no-bindings))
- ((assq-ref tag-bindings 'macro #f) => macro)
- ((assq-ref tag-bindings 'pre #f) => pre)
- (else (have-bindings tag-bindings)))))
- (define (fup tree bindings cont params layout ret
- kbindings kcont kparams klayout kret)
- (call-with-values
- (lambda ()
- (kcont kparams layout klayout (reverse kret)))
- (lambda (klayout kret)
- (values bindings cont params klayout (cons kret ret)))))
- (define (fhere tree bindings cont params layout ret)
- (call-with-values
- (lambda ()
- ((assq-ref bindings '*text* err) tree params layout))
- (lambda (tlayout tret)
- (values bindings cont params tlayout (cons tret ret)))))
- (call-with-values
- (lambda ()
- (foldts*-values
- fdown fup fhere tree bindings #f (cons params '()) layout '()))
- (lambda (bindings cont params layout ret)
- (values (car ret) layout))))
|