1 ;;; -*- show-trailing-whitespace: t; indent-tabs: nil -*-
3 ;;; Copyright (c) 2007 David Lichteblau. All rights reserved.
5 ;;; Redistribution and use in source and binary forms, with or without
6 ;;; modification, are permitted provided that the following conditions
9 ;;; * Redistributions of source code must retain the above copyright
10 ;;; notice, this list of conditions and the following disclaimer.
12 ;;; * Redistributions in binary form must reproduce the above
13 ;;; copyright notice, this list of conditions and the following
14 ;;; disclaimer in the documentation and/or other materials
15 ;;; provided with the distribution.
17 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
18 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 (in-package :cxml-rng
)
33 (declaim (optimize (debug 2)))
35 (defparameter *keywords
*
36 '("attribute" "default" "datatypes" "div" "element" "empty" "external"
37 "grammar" "include" "inherit" "list" "mixed" "namespace" "notAllowed"
38 "parent" "start" "string" "text" "token"))
41 `((lambda (x) (return (values x x
))) ,x
))
44 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
45 ;;;; Escape interpretation
46 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
48 (defclass hex-stream
(trivial-gray-streams:fundamental-character-input-stream
)
49 ((source :initarg
:source
:accessor stream-source
)
50 (buffer :initform
(make-array 1 :adjustable t
:fill-pointer
0)
51 :accessor stream-buffer
)
52 (pos :initform
0 :accessor stream-pos
)))
54 (defmethod trivial-gray-streams:stream-file-position
((s hex-stream
))
55 (file-position (stream-source s
)))
57 ;; zzz geht das nicht besser?
58 (defmethod trivial-gray-streams:stream-read-char
((s hex-stream
))
59 (with-slots (source buffer pos
) s
61 ((< pos
(length buffer
))
66 (setf (fill-pointer buffer
) 0)
69 (let ((c (read-char source nil
)))
70 (vector-push-extend c buffer
)
72 (macrolet ((with-expectation (frob &body body
)
73 (when (characterp frob
)
74 (setf frob
`(eql (slurp) ,frob
)))
75 `(let ((result ,frob
))
78 ,@(or body
(list 'result
)))
89 for d
= (peek-char nil source
)
93 (return (eql (slurp) #\
{)))
96 for result
= 0 then
(+ (* result
16) i
)
97 for d
= (peek-char nil source nil
)
98 for i
= (digit-char-p d
16)
104 (when (eql (slurp) #\
})
105 (setf (fill-pointer buffer
) 0)
107 (code-char result
))))))))))))))
110 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
112 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
118 (or (range #x0041
#x005A
) (range #x0061
#x007A
)
119 ;; just allow the rest of unicode, because clex can't deal with the
120 ;; complete definition of name-char:
121 (range #x00c0
#xd7ff
)
122 (range #xe000
#xfffd
)
123 (range #x10000
#x10ffff
)))
124 (digit (range #x0030
#x0039
)) ;ditto
125 (name-start-char (or letter
+extras
#\_
))
126 (name-char (or letter
+extras digit
#\.
#\-
#\_
#\
:))
132 (range #xe000
#xfffd
)
133 (range #x10000
#x10ffff
)))
138 (range #xe000
#xfffd
)
139 (range #x10000
#x10ffff
)))
141 (or 35 init-comment-char
))
148 (range #xe000
#xfffd
)
149 (range #x10000
#x10ffff
)))
150 (space (or 9 10 13 32))
151 (newline (or 10 13)))
155 ((and "##") (clex:begin
'documentation-line
))
157 ((clex::in documentation-line newline
) (clex:begin
'clex
:initial
))
158 ((clex::in documentation-line comment-char
)
159 (return (values 'documentation-line clex
:bag
)))
161 ((and #\
# init-comment-char
) (clex:begin
'comment
))
163 ((clex::in comment newline
) (clex:begin
'clex
:initial
))
164 ((clex::in comment comment-char
))
166 ((and "'''" (* (or string-char
#\' #\")) "'''")
168 (values 'literal-segment
(subseq clex
:bag
3 (- (length clex
:bag
) 3)))))
170 ((and #\' (* (or string-char
#\")) #\')
171 (when (or (find (code-char 13) clex
:bag
)
172 (find (code-char 10) clex
:bag
))
173 (rng-error nil
"disallowed newline in string literal"))
175 (values 'literal-segment
(subseq clex
:bag
1 (- (length clex
:bag
) 1)))))
177 ((and #\" #\" #\" (* (or string-char
#\' #\")) #\" #\" #\")
179 (values 'literal-segment
(subseq clex
:bag
3 (- (length clex
:bag
) 3)))))
181 ((and #\" (* (or string-char
#\')) #\")
182 (when (or (find (code-char 13) clex
:bag
)
183 (find (code-char 10) clex
:bag
))
184 (rng-error nil
"disallowed newline in string literal"))
186 (values 'literal-segment
(subseq clex
:bag
1 (- (length clex
:bag
) 1)))))
188 ((and name-start-char
(* name-char
))
191 ((find clex
:bag
*keywords
* :test
#'equal
)
192 (let ((sym (intern (string-upcase clex
:bag
) :keyword
)))
195 (let* ((pos (position #\
: clex
:bag
))
196 (prefix (subseq clex
:bag
0 pos
))
197 (lname (subseq clex
:bag
(1+ pos
))))
198 (when (find #\
: lname
)
199 (rng-error "too many colons"))
200 (unless (and (cxml-types::nc-name-p prefix
))
201 (rng-error nil
"not an ncname: ~A" prefix
))
202 (let ((ch (clex::getch
)))
204 ((and (equal lname
"") (eql ch
#\
*))
205 (values 'nsname prefix
))
208 (unless (and (cxml-types::nc-name-p lname
))
209 (rng-error nil
"not an ncname: ~A" lname
))
210 (values 'cname
(cons prefix lname
)))))))
212 (unless (cxml-types::nc-name-p clex
:bag
)
213 (rng-error nil
"not an ncname: ~A" clex
:bag
))
214 (values 'identifier clex
:bag
)))))
216 ((and #\\ name-start-char
(* name-char
))
217 (let ((str (subseq clex
:bag
1)))
218 (unless (cxml-types::nc-name-p str
)
219 (rng-error nil
"not an ncname: ~A" clex
:bag
))
220 (return (values 'identifier str
))))
235 ((and "|=") (double '|\|
=|
))
236 ((and "&=") (double '&=))
237 ((and ">>") (double '>>))
242 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
243 ;;;; Parsing into S-Expressions
244 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
246 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
248 (defmacro lambda
* ((&rest args
) &body body
)
249 (setf args
(mapcar (lambda (arg) (or arg
(gensym))) args
))
251 (declare (ignorable ,@args
))
254 (defmacro lambda
* ((&rest args
) &body body
)
255 (setf args
(mapcar (lambda (arg) (or arg
(gensym))) args
))
256 `(lambda (&rest .args.
)
257 (unless (equal (length .args.
) ,(length args
))
258 (error "expected ~A, got ~A" ',args .args.
))
259 (destructuring-bind (,@args
) .args.
260 (declare (ignorable ,@args
))
263 (defun wrap-decls (decls content
)
266 ,(wrap-decls (cadr decls
) content
))
269 (yacc:define-parser
*compact-parser
*
270 (:start-symbol top-level
)
271 (:terminals
(:attribute
:default
:datatypes
:div
:element
:empty
272 :external
:grammar
:include
:inherit
:list
273 :mixed
:namespace
:notAllowed
:parent
:start
275 = { } |
,|
& |\|| ?
* + |
(| |
)| |\|
=|
&= ~ -
277 identifier literal-segment cname nsname
279 #+debug
(:print-first-terminals t
)
280 #+debug
(:print-states t
)
281 #+debug
(:print-lookaheads t
)
282 #+debug
(:print-goto-graph t
)
283 (:muffle-conflicts
(50 0)) ;hrmpf
285 (top-level (decl* pattern
#'wrap-decls
)
286 (decl* grammar-content
*
287 (lambda (a b
) (wrap-decls a
`(with-grammar () ,@b
)))))
289 (decl* () (decl decl
*))
291 (decl (:namespace identifier-or-keyword
= namespace-uri-literal
292 (lambda* (nil name nil uri
)
293 `(with-namespace (:uri
,uri
:name
,name
))))
294 (:default
:namespace
= namespace-uri-literal
295 (lambda* (nil nil nil uri
)
296 `(with-namespace (:uri
,uri
:default t
))))
297 (:default
:namespace identifier-or-keyword
= namespace-uri-literal
298 (lambda* (nil nil name nil uri
)
299 `(with-namespace (:uri
,uri
:name
,name
:default t
))))
300 (:datatypes identifier-or-keyword
= literal
301 (lambda* (nil name nil uri
)
302 `(with-data-type (:name
,name
:uri
,uri
)))))
304 (pattern (inner-pattern
305 (lambda* (p) `(without-annotations ,p
))))
307 (particle (inner-particle
308 (lambda* (p) `(without-annotations ,p
))))
310 (inner-pattern inner-particle
311 (particle-choice (lambda* (p) `(%with-annotations
,p
)))
312 (particle-group (lambda* (p) `(%with-annotations
,p
)))
313 (particle-interleave (lambda* (p) `(%with-annotations
,p
)))
314 (data-except (lambda* (p) `(%with-annotations-group
,p
))))
316 (primary (:element name-class
{ pattern
}
317 (lambda* (nil name nil pattern nil
)
318 `(with-element (:name
,name
) ,pattern
)))
319 (:attribute name-class
{ pattern
}
320 (lambda* (nil name nil pattern nil
)
321 `(with-attribute (:name
,name
) ,pattern
)))
323 (lambda* (nil nil pattern nil
)
326 (lambda* (nil nil pattern nil
)
328 (identifier (lambda* (x)
335 (data-type-name [params]
336 (lambda* (name params)
337 `(data :data-type ,name :params ,params)))
338 (data-type-name data-type-value
339 (lambda* (name value)
340 `(value :data-type ,name :value ,value)))
341 (data-type-value (lambda* (value)
342 `(value :data-type nil :value ,value)))
344 (:external any-uri-literal [inherit]
345 (lambda* (nil uri inherit)
346 `(external-ref :uri ,uri :inherit ,inherit)))
347 (:grammar { grammar-content* }
348 (lambda* (nil nil content nil)
349 `(with-grammar () ,@content)))
350 (\( pattern \) (lambda* (nil p nil) p)))
352 (data-except (data-type-name [params] - lead-annotated-primary
353 (lambda* (name params nil p
)
354 `(data :data-type
,name
358 (inner-particle (annotated-primary
359 (lambda* (p) `(%with-annotations-group
,p
)))
360 (repeated-primary follow-annotations
363 (%with-annotations
,a
)
366 (repeated-primary (annotated-primary *
367 (lambda* (p nil
) `(zero-or-more ,p
)))
369 (lambda* (p nil
) `(one-or-more ,p
)))
371 (lambda* (p nil
) `(optional ,p
))))
373 (annotated-primary (lead-annotated-primary follow-annotations
377 (annotated-data-except (lead-annotated-data-except follow-annotations
381 (lead-annotated-data-except data-except
382 (annotations data-except
384 `(with-annotations ,a
,p
))))
386 (lead-annotated-primary primary
389 `(with-annotations ,a
,p
)))
391 (lambda* (nil p nil
) p
))
392 (annotations \
( inner-pattern \
)
393 (lambda* (a nil p nil
)
394 `(let-annotations ,a
,p
))))
396 (particle-choice (particle \| particle
397 (lambda* (a nil b
) `(choice ,a
,b
)))
398 (particle \| particle-choice
399 (lambda* (a nil b
) `(choice ,a
,@(cdr b
)))))
401 (particle-group (particle \
, particle
402 (lambda* (a nil b
) `(group ,a
,b
)))
403 (particle \
, particle-group
404 (lambda* (a nil b
) `(group ,a
,@(cdr b
)))))
406 (particle-interleave (particle \
& particle
407 (lambda* (a nil b
) `(interleave ,a
,b
)))
408 (particle \
& particle-interleave
409 (lambda* (a nil b
) `(interleave ,a
,@(cdr b
)))))
411 (param (identifier-or-keyword = literal
412 (lambda* (name nil value
)
413 `(param ,name
,value
)))
414 (annotations identifier-or-keyword
= literal
415 (lambda* (a name nil value
)
416 `(with-annotations ,a
(param ,name
,value
)))))
419 (member grammar-content
* #'cons
))
421 (member annotated-component
422 annotated-element-not-keyword
)
424 (annotated-component component
425 (annotations component
427 `(with-annotations ,a
,c
))))
431 (:div
{ grammar-content
* }
432 (lambda* (nil nil content nil
)
433 `(with-div ,@content
)))
434 (:include any-uri-literal
[inherit] [include-content]
435 (lambda* (nil uri inherit content)
436 `(with-include (:inherit ,inherit :uri ,uri)
440 (include-member include-content* #'cons))
442 (include-member annotated-include-component
443 annotation-element-not-keyword)
445 (annotated-include-component include-component
446 (annotations include-component
448 `(with-annotations (,@a) ,c))))
450 (include-component start
452 (:div { grammar-content* }
453 (lambda* (nil nil content nil)
454 `(with-div ,@content))))
456 (start (:start assign-method pattern
457 (lambda* (nil method pattern)
458 `(with-start (:combine-method ,method) ,pattern))))
460 (define (identifier assign-method pattern
461 (lambda* (name method pattern)
462 `(with-definition (:name ,name :combine-method ,method)
465 (assign-method (= (constantly nil))
466 (\|= (constantly "choice"))
467 (&= (constantly "interleave")))
469 (name-class (inner-name-class (lambda (nc) `(without-annotations ,nc))))
471 (inner-name-class (annotated-simple-nc
472 (lambda (nc) `(%with-annotations-choice ,nc)))
474 (lambda (nc) `(%with-annotations ,nc)))
476 (lambda (nc) `(%with-annotations-choice ,nc))))
478 (simple-nc (name (lambda* (n) `(name ,n)))
479 (ns-name (lambda* (n) `(ns-name ,n)))
480 (* (constantly `(any-name)))
481 (\( name-class \) (lambda* (nil nc nil) nc)))
483 (follow-annotations ()
484 (>> annotation-element follow-annotations))
486 (annotations #+nil ()
489 `(annotation :elements ,e)))
490 ([ annotation-attributes annotation-elements ]
491 (lambda* (nil a e nil)
492 `(annotation :attributes ,a :elements ,e)))
493 (documentations [ annotation-attributes annotation-elements ]
494 (lambda* (d nil a e nil)
495 `(annotation :attributes ,a
496 :elements ,(append e d)))))
498 (annotation-attributes
499 ((constantly '(annotation-attributes)))
500 (foreign-attribute-name = literal annotation-attributes
501 (lambda* (name nil value rest)
502 `(annotation-attributes
503 (annotation-attribute ,name ,value)
506 (foreign-attribute-name prefixed-name)
508 (annotation-elements ()
509 (annotation-element annotation-elements #'cons))
511 (annotation-element (foreign-element-name annotation-attributes-content
513 `(with-annotation-element
517 (foreign-element-name identifier-or-keyword
520 (annotation-element-not-keyword (foreign-element-name-not-keyword
521 annotation-attributes-content
523 `(with-annotation-element
527 (foreign-element-name-not-keyword identifier prefixed-name)
529 (annotation-attributes-content ([ nested-annotation-attributes
530 annotation-content ]))
532 (nested-annotation-attributes
533 ((constantly '(annotation-attributes)))
534 (any-attribute-name = literal
535 nested-annotation-attributes
536 (lambda* (name nil value rest)
537 `(annotation-attributes
538 (annotation-attribute ,name ,value)
541 (any-attribute-name identifier-or-keyword prefixed-name)
543 (annotation-content ()
544 (nested-annotation-element annotation-content #'cons)
545 (literal annotation-content #'cons))
547 (nested-annotation-element (any-element-name annotation-attributes-content
549 `(with-annotation-element
553 (any-element-name identifier-or-keyword prefixed-name)
555 (prefixed-name cname)
557 (documentations (documentation)
558 (documentation documentations #'cons))
560 (documentation documentation-line
561 (documentation-line documentation
563 (concatenate 'string a b))))
565 (annotated-nc-except (lead-annotated-nc-except
570 (lead-annotated-nc-except nc-except
571 (annotations nc-except
573 `(with-annotations ,a ,p))))
575 (annotated-simple-nc (lead-annotated-simple-nc
577 (lambda (p a) `(progn ,p ,a))))
579 (lead-annotated-simple-nc
581 (\( inner-name-class \) (lambda* (nil nc nil) nc))
582 (annotations simple-nc
583 (lambda (a nc) `(with-annotations ,a ,nc)))
584 (annotations \( inner-name-class \)
585 (lambda (a nc) `(let-annotations ,a ,nc))))
587 (nc-except (ns-name - simple-nc
588 (lambda* (nc1 nil nc2) `(ns-name ,nc1 :except ,nc2)))
590 (lambda* (nil nil nc) `(any-name :except ,nc))))
592 (nc-choice (annotated-simple-nc \| annotated-simple-nc
594 `(name-choice ,a ,b)))
595 (annotated-simple-nc \| nc-choice
597 `(name-choice ,a ,@(cdr b)))))
599 (name identifier-or-keyword cname)
601 (data-type-name cname :string :token)
603 (data-type-value literal)
604 (any-uri-literal literal)
606 (namespace-uri-literal literal :inherit)
608 (inherit (:inherit = identifier-or-keyword
609 (lambda* (nil nil x) x)))
611 (identifier-or-keyword identifier keyword)
613 ;; identifier ::= (ncname - keyword) | quotedidentifier
614 ;; quotedidentifier ::= "\" ncname
616 ;; (ns-name (ncname \:*))
619 (ncname identifier-or-keyword)
621 (literal literal-segment
622 (literal-segment ~ literal
624 (concatenate 'string a b))))
626 ;; literalsegment ::= ...
628 (keyword :attribute :default :datatypes :div :element :empty :external
629 :grammar :include :inherit :list :mixed :namespace :notAllowed
630 :parent :start :string :text :token)
633 ([data-type-name] () data-type-name)
634 ([inherit] () inherit
)
635 ([params] () ({ params } (lambda* (nil p nil) p)))
636 (params () (param params #'cons))
637 ([include-content] () ({ include-content* }
638 (lambda* (nil content nil) content))))
641 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
642 ;;;; Conversion of sexps into SAX
643 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
645 (defun uncompact (list)
646 (funcall (or (get (car list) 'uncompactor)
647 (error "no uncompactor for ~A" (car list)))
650 (defmacro define-uncompactor (name (&rest args) &body body)
651 `(setf (get ',name 'uncompactor)
652 (lambda (.form.) (destructuring-bind ,args .form. ,@body))))
654 (defparameter *namespaces* '(("xml" . "http://www.w3.org/XML/1998/namespace")))
655 (defparameter *default-namespace* nil)
656 (defparameter *data-types*
657 '(("xsd" . "http://www.w3.org/2001/XMLSchema-datatypes")))
662 (defun lookup-prefix (prefix)
663 (cdr (assoc prefix *namespaces* :test 'equal)))
665 (defun lookup-default ()
666 (or *default-namespace* :inherit))
668 (defun lookup-data-type (name)
669 (cdr (assoc name *data-types* :test 'equal)))
671 (define-uncompactor with-namespace ((&key uri name default) &body body)
672 (when (xor (equal name "xml")
673 (equal uri "http://www.w3.org/XML/1998/namespace"))
674 (rng-error nil "invalid redeclaration of `xml' namespace"))
675 (when (equal name "xmlns")
676 (rng-error nil "invalid declaration of `xmlns' namespace"))
677 (let ((*namespaces* *namespaces*)
678 (*default-namespace* *default-namespace*))
680 (when (lookup-prefix name)
681 (rng-error nil "duplicate declaration of prefix ~A" name))
682 (push (cons name uri) *namespaces*))
684 (when *default-namespace*
685 (rng-error nil "default namespace already declared to ~A"
686 *default-namespace*))
687 (push (cons "" uri) *namespaces*)
688 (setf *default-namespace* uri))
689 (if (and name (not (or (eq uri :inherit) (equal uri ""))))
690 (cxml:with-namespace (name uri)
691 (mapc #'uncompact body))
692 (mapc #'uncompact body))))
694 (define-uncompactor with-data-type ((&key name uri) &body body)
695 (when (and (equal name "xsd")
696 (not (equal uri "http://www.w3.org/2001/XMLSchema-datatypes")))
697 (rng-error nil "invalid redeclaration of `xml' namespace"))
698 (when (and (lookup-data-type name) (not (equal name "xsd")))
699 (rng-error nil "duplicate declaration of library ~A" name))
700 (let ((*data-types* (acons name uri *data-types*)))
701 (mapc #'uncompact body)))
703 (defparameter *annotation-attributes* nil)
704 (defparameter *annotation-elements* nil)
705 (defparameter *annotation-wrap* nil)
707 (defmacro with-element (name-and-args &body body)
708 (destructuring-bind (prefix lname &rest args)
709 (if (atom name-and-args)
710 (list nil name-and-args)
712 `(invoke-with-element ,prefix
715 (lambda () ,@body))))
717 (defun invoke-with-element (prefix lname args body)
718 (if (and *annotation-attributes*
720 (cxml:with-element* (nil *annotation-wrap*)
721 (let ((*annotation-wrap* nil))
722 (invoke-with-element prefix lname args body)))
723 (let ((*annotation-wrap* nil))
724 (cxml:with-element* (prefix lname)
726 (when *annotation-attributes*
727 (uncompact *annotation-attributes*))
728 (dolist (elt *annotation-elements*)
730 ("a" "http://relaxng.org/ns/compatibility/annotations/1.0")
731 (cxml:with-element* ("a" "documentation")
735 (define-uncompactor with-grammar ((&optional) &body body)
736 (with-element "grammar"
737 (mapc #'uncompact body)))
739 (define-uncompactor with-start ((&key combine-method) &body body)
740 (with-element (nil "start"
741 (cxml:attribute "combine" combine-method))
742 (mapc #'uncompact body)))
744 (define-uncompactor ref (name)
745 (with-element (nil "ref"
746 (cxml:attribute "name" name))))
748 (define-uncompactor parent-ref (name)
749 (with-element (nil "parentRef"
750 (cxml:attribute "name" name))))
752 (define-uncompactor parent-ref (name)
753 (with-element (nil "parentRef" (cxml:attribute "name" name))))
755 (defun ns-attribute (uri-or-inherit)
756 (unless (eq uri-or-inherit :inherit)
757 (cxml:attribute "ns" uri-or-inherit)))
759 (define-uncompactor external-ref (&key uri inherit)
760 (let ((ns (if inherit (lookup-prefix inherit) (lookup-default))))
761 (with-element (nil "externalRef"
762 (cxml:attribute "href" (munge-schema-ref uri))
763 (ns-attribute ns)))))
767 (define-uncompactor with-element ((&key name) pattern)
768 (with-element "element"
769 (let ((*elementp* t))
771 (uncompact pattern)))
773 (define-uncompactor with-attribute ((&key name) pattern)
774 (with-element "attribute"
775 (let ((*elementp* nil))
777 (uncompact pattern)))
779 (define-uncompactor list (pattern)
781 (uncompact pattern)))
783 (define-uncompactor mixed (pattern)
784 (with-element "mixed"
785 (uncompact pattern)))
787 (define-uncompactor :empty ()
788 (with-element "empty"))
790 (define-uncompactor :text ()
791 (with-element "text"))
793 (defun uncompact-data-type (data-type)
796 (cxml:attribute "datatypeLibrary" "")
797 (cxml:attribute "type" "string"))
799 (cxml:attribute "datatypeLibrary" "")
800 (cxml:attribute "type" "token"))
802 (cxml:attribute "datatypeLibrary"
803 (lookup-data-type (car data-type)))
804 (cxml:attribute "type" (cdr data-type)))))
806 (define-uncompactor data (&key data-type params except)
807 (with-element (nil "data" (uncompact-data-type data-type))
808 (mapc #'uncompact params)
810 (with-element "except"
811 (uncompact except)))))
813 (define-uncompactor value (&key data-type value)
814 (with-element (nil "value" (uncompact-data-type data-type))
817 (define-uncompactor :notallowed ()
818 (with-element "notAllowed"))
820 (define-uncompactor with-definition ((&key name combine-method) &body body)
821 (with-element (nil "define"
822 (cxml:attribute "name" name)
823 (cxml:attribute "combine" combine-method))
824 (mapc #'uncompact body)))
826 (define-uncompactor with-div (&body body)
828 (mapc #'uncompact body)))
830 (define-uncompactor any-name (&key except)
831 (with-element "anyName"
833 (with-element "except"
834 (uncompact except)))))
836 (define-uncompactor ns-name (nc &key except)
837 (with-element (nil "nsName"
838 (ns-attribute (lookup-prefix nc)))
840 (with-element "except"
841 (uncompact except)))))
843 (define-uncompactor name-choice (&rest ncs)
844 (with-element "choice"
845 (mapc #'uncompact ncs)))
847 (defun destructure-cname-like (x)
849 (setf x (find x *keywords* :test 'string-equal)))
851 (setf x (cons (if *elementp* "" nil)
853 (values (lookup-prefix (car x))
856 (define-uncompactor name (x)
857 (multiple-value-bind (uri lname) (destructure-cname-like x)
863 (define-uncompactor choice (&rest body)
864 (with-element "choice"
865 (mapc #'uncompact body)))
867 (define-uncompactor group (&rest body)
868 (with-element "group"
869 (mapc #'uncompact body)))
871 (define-uncompactor interleave (&rest body)
872 (with-element "interleave"
873 (mapc #'uncompact body)))
875 (define-uncompactor one-or-more (p)
876 (with-element "oneOrMore"
879 (define-uncompactor optional (p)
880 (with-element "optional"
883 (define-uncompactor zero-or-more (p)
884 (with-element "zeroOrMore"
887 (defun munge-schema-ref (uri)
888 (if (search "://" uri)
889 (concatenate 'string "rnc+" uri)
890 (concatenate 'string "rnc+://" uri)))
892 (defun rnc-uri-p (uri)
893 (and (search "://" uri)
894 (equal (mismatch "rnc+" uri) 4)))
896 (defun follow-rnc-uri (uri)
897 (if (equal (mismatch "rnc+://" uri) 7)
900 ;; rnc+file:///usr/foo/...
903 (define-uncompactor with-include ((&key inherit uri) &body body)
904 (let ((ns (if inherit (lookup-prefix inherit) (lookup-default))))
905 (with-element (nil "include"
906 (cxml:attribute "href" (munge-schema-ref uri))
908 (mapc #'uncompact body))))
910 (define-uncompactor with-annotations
911 ((annotation &key attributes elements) &body body)
912 (check-type annotation (member annotation))
913 (let ((*annotation-attributes* attributes)
914 (*annotation-elements* elements))
915 (mapc #'uncompact body)))
917 (define-uncompactor without-annotations (&body body)
918 (let ((*annotation-attributes* nil)
919 (*annotation-elements* nil))
920 (mapc #'uncompact body)))
923 (define-uncompactor %with-annotations (&body body)
924 (mapc #'uncompact body))
926 (define-uncompactor %with-annotations-group (&body body)
927 (let ((*annotation-wrap* "group"))
928 (mapc #'uncompact body)))
930 (define-uncompactor %with-annotations-choice (&body body)
931 (let ((*annotation-wrap* "choice"))
932 (mapc #'uncompact body)))
934 (define-uncompactor progn (a b)
935 (when a (uncompact a))
936 (when b (uncompact b)))
938 (define-uncompactor annotation-attributes (&rest attrs)
939 (mapc #'uncompact attrs))
941 (define-uncompactor annotation-attribute (name value)
942 (cxml:attribute* (car name) (cdr name) value))
944 (define-uncompactor param (name value)
945 (with-element (nil "param"
946 (cxml:attribute "name" name))
949 (define-uncompactor with-annotation-element ((&key name) &body attrs)
950 (cxml:with-element name
951 (mapc #'uncompact attrs)))
954 ;;; zzz newline normalization: Wir lesen von einem character-stream, daher
955 ;;; macht das schon das Lisp fuer uns -- je nach Plattform. Aber nicht richtig.
956 (defun uncompact-file-1 (stream)
958 (let ((lexer (make-rng-lexer
959 (make-instance 'hex-stream :source stream))))
960 (yacc:parse-with-lexer
962 (multiple-value-bind (cat sem) (funcall lexer)
963 #+nil (print (list cat sem))
970 "failed to parse compact syntax at char ~A, ~A:~% ~A"
971 (file-position stream)
972 (cxml::safe-stream-sysid stream)
975 (defun uncompact-file (input &optional stream)
978 (pathname (with-open-file (s input) (uncompact-file-1 s)))
979 (stream (with-open-stream (s input) (uncompact-file-1 s))))))
981 (with-output-to-string (s)
982 (cxml:with-xml-output
984 (cxml:make-octet-stream-sink stream)
985 (cxml:make-character-stream-sink s))
986 (cxml:with-namespace ("" "http://relaxng.org/ns/structure/1.0")
987 (uncompact tree))))))
989 (defun parse-compact (pathname)
990 "@arg[pathname]{a pathname designator for a Relax NG compact file}
991 @return{a parsed @class{schema}}
992 @short{This function parses a Relax NG schema file in compact syntax}
993 and returns a parsed representation of that schema.
996 @see{make-validator}"
997 (parse-schema (named-string-xstream
998 (uncompact-file pathname)
999 (cxml::pathname-to-uri pathname))))
1001 (defun test-compact ()
1002 (dolist (p (directory "/home/david/src/nxml-mode-20041004/schema/*.rnc"))
1004 (with-open-file (s (make-pathname :type "rng" :defaults p)
1006 :if-exists :supersede)
1007 (uncompact-file p s))))