123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- ;;;; (texinfo serialize) -- rendering stexinfo as texinfo
- ;;;;
- ;;;; Copyright (C) 2009 Free Software Foundation, Inc.
- ;;;; Copyright (C) 2003,2004,2009 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:
- ;;
- ;;Serialization of @code{stexi} to plain texinfo.
- ;;
- ;;; Code:
- (define-module (texinfo serialize)
- #:use-module (texinfo)
- #:use-module (texinfo string-utils)
- #:use-module (sxml transform)
- #:use-module (srfi srfi-1)
- #:use-module (srfi srfi-13)
- #:export (stexi->texi))
- (define (list-intersperse src-l elem)
- (if (null? src-l) src-l
- (let loop ((l (cdr src-l)) (dest (cons (car src-l) '())))
- (if (null? l) (reverse dest)
- (loop (cdr l) (cons (car l) (cons elem dest)))))))
- ;; converts improper lists to proper lists.
- (define (filter* pred l)
- (let lp ((in l) (out '()))
- (cond ((null? in)
- (reverse! out))
- ((pair? in)
- (lp (cdr in) (if (pred (car in)) (cons (car in) out) out)))
- (else
- (lp '() (if (pred in) (cons in out) out))))))
- ;; (list* 'a '(b c) 'd '(e f g)) => '(a b c d e f g)
- (define (list* . args)
- (let* ((args (reverse args))
- (tail (car args)))
- (let lp ((in (cdr args)) (out tail))
- (cond ((null? in) out)
- ((pair? (car in)) (lp (cdr in) (append (car in) out)))
- ((null? (car in)) (lp (cdr in) out))
- (else (lp (cdr in) (cons (car in) out)))))))
- ;; Why? Well, because syntax-case defines `include', and carps about its
- ;; wrong usage below...
- (eval-when (eval load compile)
- (define (include exp lp command type formals args accum)
- (list* "\n"
- (list-intersperse
- args
- " ")
- " " command "@" accum)))
- (define (empty-command exp lp command type formals args accum)
- (list* " " command "@" accum))
- (define (inline-text exp lp command type formals args accum)
- (if (not (string=? command "*braces*")) ;; fixme :(
- (list* "}"
- (append-map (lambda (x) (lp x '())) (reverse (cdr exp)))
- "{" command "@" accum)
- (list* "@}"
- (append-map (lambda (x) (lp x '())) (reverse (cdr exp)))
- "@{" accum)))
- (define (inline-args exp lp command type formals args accum)
- (list* "}"
- (if (not args) ""
- (list-intersperse
- (map
- (lambda (x)
- (cond ((not x) "")
- ((pair? x)
- (if (pair? (cdr x))
- (warn "Strange inline-args!" args))
- (car x))
- (else (error "Invalid inline-args" args))))
- (drop-while not
- (map (lambda (x) (assq-ref args x))
- (reverse formals))))
- ","))
- "{" command "@" accum))
- (define (serialize-text-args lp formals args)
- (apply
- append
- (list-intersperse
- (map (lambda (arg) (append-map (lambda (x) (lp x '())) arg))
- (map
- reverse
- (drop-while
- not (map (lambda (x) (assq-ref args x))
- (reverse formals)))))
- '(" "))))
- (define (eol-text-args exp lp command type formals args accum)
- (list* "\n"
- (serialize-text-args lp formals args)
- " " command "@" accum))
- (define (eol-text exp lp command type formals args accum)
- (list* "\n"
- (append-map (lambda (x) (lp x '()))
- (reverse (if args (cddr exp) (cdr exp))))
- " " command "@" accum))
- (define (eol-args exp lp command type formals args accum)
- (list* "\n"
- (list-intersperse
- (apply append
- (drop-while not
- (map (lambda (x) (assq-ref args x))
- (reverse formals))))
- ", ")
- " " command "@" accum))
- (define (environ exp lp command type formals args accum)
- (case (car exp)
- ((texinfo)
- (list* "@bye\n"
- (append-map (lambda (x) (lp x '())) (reverse (cddr exp)))
- "\n@c %**end of header\n\n"
- (reverse (assq-ref args 'title)) "@settitle "
- (or (and=> (assq-ref args 'filename)
- (lambda (filename)
- (cons "\n" (reverse (cons "@setfilename " filename)))))
- "")
- "\\input texinfo @c -*-texinfo-*-\n@c %**start of header\n"
- accum))
- (else
- (list* "\n\n" command "@end "
- (let ((body (append-map (lambda (x) (lp x '()))
- (reverse (if args (cddr exp) (cdr exp))))))
- (if (or (null? body)
- (eqv? (string-ref (car body)
- (1- (string-length (car body))))
- #\newline))
- body
- (cons "\n" body)))
- "\n"
- (serialize-text-args lp formals args)
- " " command "@" accum))))
- (define (table-environ exp lp command type formals args accum)
- (list* "\n\n" command "@end "
- (append-map (lambda (x) (lp x '()))
- (reverse (if args (cddr exp) (cdr exp))))
- "\n"
- (let* ((arg (if args (cadar args) ""))) ;; zero or one args
- (if (pair? arg)
- (list (symbol->string (car arg)) "@")
- arg))
- " " command "@" accum))
- (define (wrap strings)
- (fill-string (string-concatenate strings)
- #:line-width 72))
- (define (paragraph exp lp command type formals args accum)
- (list* "\n\n"
- (wrap
- (reverse
- (append-map (lambda (x) (lp x '())) (reverse (cdr exp)))))
- accum))
- (define (item exp lp command type formals args accum)
- (list* (append-map (lambda (x) (lp x '())) (reverse (cdr exp)))
- "@item\n"
- accum))
- (define (entry exp lp command type formals args accum)
- (list* (append-map (lambda (x) (lp x '())) (reverse (cddr exp)))
- "\n"
- (append-map (lambda (x) (lp x '())) (reverse (cdar args)))
- "@item "
- accum))
- (define (fragment exp lp command type formals args accum)
- (list* "\n@c %end of fragment\n"
- (append-map (lambda (x) (lp x '())) (reverse (cdr exp)))
- "\n@c %start of fragment\n\n"
- accum))
- (define serializers
- `((EMPTY-COMMAND . ,empty-command)
- (INLINE-TEXT . ,inline-text)
- (INLINE-ARGS . ,inline-args)
- (EOL-TEXT . ,eol-text)
- (EOL-TEXT-ARGS . ,eol-text-args)
- (INDEX . ,eol-text-args)
- (EOL-ARGS . ,eol-args)
- (ENVIRON . ,environ)
- (TABLE-ENVIRON . ,table-environ)
- (ENTRY . ,entry)
- (ITEM . ,item)
- (PARAGRAPH . ,paragraph)
- (FRAGMENT . ,fragment)
- (#f . ,include))) ; support writing include statements
- (define (serialize exp lp command type formals args accum)
- ((or (assq-ref serializers type)
- (error "Unknown command type" exp type))
- exp lp command type formals args accum))
- (define escaped-chars '(#\} #\{ #\@))
- (define (escape str)
- "Escapes any illegal texinfo characters (currently @{, @}, and @@)."
- (let loop ((in (string->list str)) (out '()))
- (if (null? in)
- (apply string (reverse out))
- (if (memq (car in) escaped-chars)
- (loop (cdr in) (cons* (car in) #\@ out))
- (loop (cdr in) (cons (car in) out))))))
- (define (stexi->texi tree)
- "Serialize the stexi @var{tree} into plain texinfo."
- (string-concatenate-reverse
- (let lp ((in tree) (out '()))
- (cond
- ((or (not in) (null? in)) out)
- ((string? in) (cons (escape in) out))
- ((pair? in)
- (let ((command-spec (assq (car in) texi-command-specs)))
- (if (not command-spec)
- (begin
- (warn "Unknown stexi command, not rendering" in)
- out)
- (serialize in
- lp
- (symbol->string (car in))
- (cadr command-spec)
- (filter* symbol? (cddr command-spec))
- (cond
- ((and (pair? (cdr in)) (pair? (cadr in))
- (eq? (caadr in) '%))
- (cdadr in))
- ((not (cadr command-spec))
- ;; include
- (cdr in))
- (else
- #f))
- out))))
- (else
- (error "Invalid stexi" in))))))
- ;;; arch-tag: d3fa16ea-0bf7-4ec5-ab9f-3f08490f77f5
|