Merge from gnus--devo--0
[emacs.git] / lisp / nxml / rng-match.el
blob1f7501d9f2af011d236447890261902db4d58dd6
1 ;;; rng-match.el --- matching of RELAX NG patterns against XML events
3 ;; Copyright (C) 2003, 2007, 2008 Free Software Foundation, Inc.
5 ;; Author: James Clark
6 ;; Keywords: XML, RelaxNG
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 3, or (at your option)
13 ;; any later version.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 ;; Boston, MA 02110-1301, USA.
25 ;;; Commentary:
27 ;; This uses the algorithm described in
28 ;; http://www.thaiopensource.com/relaxng/derivative.html
30 ;; The schema to be used is contained in the variable
31 ;; rng-current-schema. It has the form described in the file
32 ;; rng-pttrn.el.
34 ;;; Code:
36 (require 'rng-pttrn)
37 (require 'rng-util)
38 (require 'rng-dt)
40 (defvar rng-not-allowed-ipattern nil)
41 (defvar rng-empty-ipattern nil)
42 (defvar rng-text-ipattern nil)
44 (defvar rng-compile-table nil)
46 (defvar rng-being-compiled nil
47 "Contains a list of ref patterns currently being compiled.
48 Used to detect illegal recursive references.")
50 (defvar rng-ipattern-table nil)
52 (defvar rng-last-ipattern-index nil)
54 (defvar rng-match-state nil
55 "An ipattern representing the current state of validation.")
57 ;;; Inline functions
59 (defsubst rng-update-match-state (new-state)
60 (if (and (eq new-state rng-not-allowed-ipattern)
61 (not (eq rng-match-state rng-not-allowed-ipattern)))
62 nil
63 (setq rng-match-state new-state)
64 t))
66 ;;; Interned patterns
68 (eval-when-compile
69 (defun rng-ipattern-slot-accessor-name (slot-name)
70 (intern (concat "rng-ipattern-get-"
71 (symbol-name slot-name))))
73 (defun rng-ipattern-slot-setter-name (slot-name)
74 (intern (concat "rng-ipattern-set-"
75 (symbol-name slot-name)))))
77 (defmacro rng-ipattern-defslot (slot-name index)
78 `(progn
79 (defsubst ,(rng-ipattern-slot-accessor-name slot-name) (ipattern)
80 (aref ipattern ,index))
81 (defsubst ,(rng-ipattern-slot-setter-name slot-name) (ipattern value)
82 (aset ipattern ,index value))))
84 (rng-ipattern-defslot type 0)
85 (rng-ipattern-defslot index 1)
86 (rng-ipattern-defslot name-class 2)
87 (rng-ipattern-defslot datatype 2)
88 (rng-ipattern-defslot after 2)
89 (rng-ipattern-defslot child 3)
90 (rng-ipattern-defslot value-object 3)
91 (rng-ipattern-defslot nullable 4)
92 (rng-ipattern-defslot memo-text-typed 5)
93 (rng-ipattern-defslot memo-map-start-tag-open-deriv 6)
94 (rng-ipattern-defslot memo-map-start-attribute-deriv 7)
95 (rng-ipattern-defslot memo-start-tag-close-deriv 8)
96 (rng-ipattern-defslot memo-text-only-deriv 9)
97 (rng-ipattern-defslot memo-mixed-text-deriv 10)
98 (rng-ipattern-defslot memo-map-data-deriv 11)
99 (rng-ipattern-defslot memo-end-tag-deriv 12)
101 (defconst rng-memo-map-alist-max 10)
103 (defsubst rng-memo-map-get (key mm)
104 "Return the value associated with KEY in memo-map MM."
105 (let ((found (assoc key mm)))
106 (if found
107 (cdr found)
108 (and mm
109 (let ((head (car mm)))
110 (and (hash-table-p head)
111 (gethash key head)))))))
113 (defun rng-memo-map-add (key value mm &optional weakness)
114 "Associate KEY with VALUE in memo-map MM and return the new memo-map.
115 The new memo-map may or may not be a different object from MM.
117 Alists are better for small maps. Hash tables are better for large
118 maps. A memo-map therefore starts off as an alist and switches to a
119 hash table for large memo-maps. A memo-map is always a list. An empty
120 memo-map is represented by nil. A large memo-map is represented by a
121 list containing just a hash-table. A small memo map is represented by
122 a list whose cdr is an alist and whose car is the number of entries in
123 the alist. The complete memo-map can be passed to assoc without
124 problems: assoc ignores any members that are not cons cells. There is
125 therefore minimal overhead in successful lookups on small lists
126 \(which is the most common case)."
127 (if (null mm)
128 (list 1 (cons key value))
129 (let ((head (car mm)))
130 (cond ((hash-table-p head)
131 (puthash key value head)
133 ((>= head rng-memo-map-alist-max)
134 (let ((ht (make-hash-table :test 'equal
135 :weakness weakness
136 :size (* 2 rng-memo-map-alist-max))))
137 (setq mm (cdr mm))
138 (while mm
139 (setq head (car mm))
140 (puthash (car head) (cdr head) ht)
141 (setq mm (cdr mm)))
142 (cons ht nil)))
143 (t (cons (1+ head)
144 (cons (cons key value)
145 (cdr mm))))))))
147 (defsubst rng-make-ipattern (type index name-class child nullable)
148 (vector type index name-class child nullable
149 ;; 5 memo-text-typed
150 'unknown
151 ;; 6 memo-map-start-tag-open-deriv
153 ;; 7 memo-map-start-attribute-deriv
155 ;; 8 memo-start-tag-close-deriv
157 ;; 9 memo-text-only-deriv
159 ;; 10 memo-mixed-text-deriv
161 ;; 11 memo-map-data-deriv
163 ;; 12 memo-end-tag-deriv
164 nil))
166 (defun rng-ipattern-maybe-init ()
167 (unless rng-ipattern-table
168 (setq rng-ipattern-table (make-hash-table :test 'equal))
169 (setq rng-last-ipattern-index -1)))
171 (defun rng-ipattern-clear ()
172 (when rng-ipattern-table
173 (clrhash rng-ipattern-table))
174 (setq rng-last-ipattern-index -1))
176 (defsubst rng-gen-ipattern-index ()
177 (setq rng-last-ipattern-index (1+ rng-last-ipattern-index)))
179 (defun rng-put-ipattern (key type name-class child nullable)
180 (let ((ipattern
181 (rng-make-ipattern type
182 (rng-gen-ipattern-index)
183 name-class
184 child
185 nullable)))
186 (puthash key ipattern rng-ipattern-table)
187 ipattern))
189 (defun rng-get-ipattern (key)
190 (gethash key rng-ipattern-table))
192 (or rng-not-allowed-ipattern
193 (setq rng-not-allowed-ipattern
194 (rng-make-ipattern 'not-allowed -3 nil nil nil)))
196 (or rng-empty-ipattern
197 (setq rng-empty-ipattern
198 (rng-make-ipattern 'empty -2 nil nil t)))
200 (or rng-text-ipattern
201 (setq rng-text-ipattern
202 (rng-make-ipattern 'text -1 nil nil t)))
204 (defconst rng-const-ipatterns
205 (list rng-not-allowed-ipattern
206 rng-empty-ipattern
207 rng-text-ipattern))
209 (defun rng-intern-after (child after)
210 (if (eq child rng-not-allowed-ipattern)
211 rng-not-allowed-ipattern
212 (let ((key (list 'after
213 (rng-ipattern-get-index child)
214 (rng-ipattern-get-index after))))
215 (or (rng-get-ipattern key)
216 (rng-put-ipattern key
217 'after
218 after
219 child
220 nil)))))
222 (defun rng-intern-attribute (name-class ipattern)
223 (if (eq ipattern rng-not-allowed-ipattern)
224 rng-not-allowed-ipattern
225 (let ((key (list 'attribute
226 name-class
227 (rng-ipattern-get-index ipattern))))
228 (or (rng-get-ipattern key)
229 (rng-put-ipattern key
230 'attribute
231 name-class
232 ipattern
233 nil)))))
235 (defun rng-intern-data (dt matches-anything)
236 (let ((key (list 'data dt)))
237 (or (rng-get-ipattern key)
238 (let ((ipattern (rng-put-ipattern key
239 'data
242 matches-anything)))
243 (rng-ipattern-set-memo-text-typed ipattern
244 (not matches-anything))
245 ipattern))))
247 (defun rng-intern-data-except (dt ipattern)
248 (let ((key (list 'data-except dt ipattern)))
249 (or (rng-get-ipattern key)
250 (rng-put-ipattern key
251 'data-except
253 ipattern
254 nil))))
256 (defun rng-intern-value (dt obj)
257 (let ((key (list 'value dt obj)))
258 (or (rng-get-ipattern key)
259 (rng-put-ipattern key
260 'value
263 nil))))
265 (defun rng-intern-one-or-more (ipattern)
266 (or (rng-intern-one-or-more-shortcut ipattern)
267 (let ((key (cons 'one-or-more
268 (list (rng-ipattern-get-index ipattern)))))
269 (or (rng-get-ipattern key)
270 (rng-put-ipattern key
271 'one-or-more
273 ipattern
274 (rng-ipattern-get-nullable ipattern))))))
276 (defun rng-intern-one-or-more-shortcut (ipattern)
277 (cond ((eq ipattern rng-not-allowed-ipattern)
278 rng-not-allowed-ipattern)
279 ((eq ipattern rng-empty-ipattern)
280 rng-empty-ipattern)
281 ((eq (rng-ipattern-get-type ipattern) 'one-or-more)
282 ipattern)
283 (t nil)))
285 (defun rng-intern-list (ipattern)
286 (if (eq ipattern rng-not-allowed-ipattern)
287 rng-not-allowed-ipattern
288 (let ((key (cons 'list
289 (list (rng-ipattern-get-index ipattern)))))
290 (or (rng-get-ipattern key)
291 (rng-put-ipattern key
292 'list
294 ipattern
295 nil)))))
297 (defun rng-intern-group (ipatterns)
298 "Return a ipattern for the list of group members in IPATTERNS."
299 (or (rng-intern-group-shortcut ipatterns)
300 (let* ((tem (rng-normalize-group-list ipatterns))
301 (normalized (cdr tem)))
302 (or (rng-intern-group-shortcut normalized)
303 (let ((key (cons 'group
304 (mapcar 'rng-ipattern-get-index normalized))))
305 (or (rng-get-ipattern key)
306 (rng-put-ipattern key
307 'group
309 normalized
310 (car tem))))))))
312 (defun rng-intern-group-shortcut (ipatterns)
313 "Try to shortcut interning a group list. If successful, return the
314 interned pattern. Otherwise return nil."
315 (while (and ipatterns
316 (eq (car ipatterns) rng-empty-ipattern))
317 (setq ipatterns (cdr ipatterns)))
318 (if ipatterns
319 (let ((ret (car ipatterns)))
320 (if (eq ret rng-not-allowed-ipattern)
321 rng-not-allowed-ipattern
322 (setq ipatterns (cdr ipatterns))
323 (while (and ipatterns ret)
324 (let ((tem (car ipatterns)))
325 (cond ((eq tem rng-not-allowed-ipattern)
326 (setq ret tem)
327 (setq ipatterns nil))
328 ((eq tem rng-empty-ipattern)
329 (setq ipatterns (cdr ipatterns)))
331 ;; Stop here rather than continuing
332 ;; looking for not-allowed patterns.
333 ;; We do a complete scan elsewhere.
334 (setq ret nil)))))
335 ret))
336 rng-empty-ipattern))
338 (defun rng-normalize-group-list (ipatterns)
339 "Normalize a list containing members of a group.
340 Expands nested groups, removes empty members, handles notAllowed.
341 Returns a pair whose car says whether the list is nullable and whose
342 cdr is the normalized list."
343 (let ((nullable t)
344 (result nil)
345 member)
346 (while ipatterns
347 (setq member (car ipatterns))
348 (setq ipatterns (cdr ipatterns))
349 (when nullable
350 (setq nullable (rng-ipattern-get-nullable member)))
351 (cond ((eq (rng-ipattern-get-type member) 'group)
352 (setq result
353 (nconc (reverse (rng-ipattern-get-child member))
354 result)))
355 ((eq member rng-not-allowed-ipattern)
356 (setq result (list rng-not-allowed-ipattern))
357 (setq ipatterns nil))
358 ((not (eq member rng-empty-ipattern))
359 (setq result (cons member result)))))
360 (cons nullable (nreverse result))))
362 (defun rng-intern-interleave (ipatterns)
363 (or (rng-intern-group-shortcut ipatterns)
364 (let* ((tem (rng-normalize-interleave-list ipatterns))
365 (normalized (cdr tem)))
366 (or (rng-intern-group-shortcut normalized)
367 (let ((key (cons 'interleave
368 (mapcar 'rng-ipattern-get-index normalized))))
369 (or (rng-get-ipattern key)
370 (rng-put-ipattern key
371 'interleave
373 normalized
374 (car tem))))))))
376 (defun rng-normalize-interleave-list (ipatterns)
377 "Normalize a list containing members of an interleave.
378 Expands nested groups, removes empty members, handles notAllowed.
379 Returns a pair whose car says whether the list is nullable and whose
380 cdr is the normalized list."
381 (let ((nullable t)
382 (result nil)
383 member)
384 (while ipatterns
385 (setq member (car ipatterns))
386 (setq ipatterns (cdr ipatterns))
387 (when nullable
388 (setq nullable (rng-ipattern-get-nullable member)))
389 (cond ((eq (rng-ipattern-get-type member) 'interleave)
390 (setq result
391 (append (rng-ipattern-get-child member)
392 result)))
393 ((eq member rng-not-allowed-ipattern)
394 (setq result (list rng-not-allowed-ipattern))
395 (setq ipatterns nil))
396 ((not (eq member rng-empty-ipattern))
397 (setq result (cons member result)))))
398 (cons nullable (sort result 'rng-compare-ipattern))))
400 ;; Would be cleaner if this didn't modify IPATTERNS.
402 (defun rng-intern-choice (ipatterns)
403 "Return a choice ipattern for the list of choices in IPATTERNS.
404 May alter IPATTERNS."
405 (or (rng-intern-choice-shortcut ipatterns)
406 (let* ((tem (rng-normalize-choice-list ipatterns))
407 (normalized (cdr tem)))
408 (or (rng-intern-choice-shortcut normalized)
409 (rng-intern-choice1 normalized (car tem))))))
411 (defun rng-intern-optional (ipattern)
412 (cond ((rng-ipattern-get-nullable ipattern) ipattern)
413 ((eq ipattern rng-not-allowed-ipattern) rng-empty-ipattern)
414 (t (rng-intern-choice1
415 ;; This is sorted since the empty pattern
416 ;; is before everything except not allowed.
417 ;; It cannot have a duplicate empty pattern,
418 ;; since it is not nullable.
419 (cons rng-empty-ipattern
420 (if (eq (rng-ipattern-get-type ipattern) 'choice)
421 (rng-ipattern-get-child ipattern)
422 (list ipattern)))
423 t))))
426 (defun rng-intern-choice1 (normalized nullable)
427 (let ((key (cons 'choice
428 (mapcar 'rng-ipattern-get-index normalized))))
429 (or (rng-get-ipattern key)
430 (rng-put-ipattern key
431 'choice
433 normalized
434 nullable))))
436 (defun rng-intern-choice-shortcut (ipatterns)
437 "Try to shortcut interning a choice list. If successful, return the
438 interned pattern. Otherwise return nil."
439 (while (and ipatterns
440 (eq (car ipatterns)
441 rng-not-allowed-ipattern))
442 (setq ipatterns (cdr ipatterns)))
443 (if ipatterns
444 (let ((ret (car ipatterns)))
445 (setq ipatterns (cdr ipatterns))
446 (while (and ipatterns ret)
447 (or (eq (car ipatterns) rng-not-allowed-ipattern)
448 (eq (car ipatterns) ret)
449 (setq ret nil))
450 (setq ipatterns (cdr ipatterns)))
451 ret)
452 rng-not-allowed-ipattern))
454 (defun rng-normalize-choice-list (ipatterns)
455 "Normalize a list of choices, expanding nested choices, removing
456 not-allowed members, sorting by index and removing duplicates. Return
457 a pair whose car says whether the list is nullable and whose cdr is
458 the normalized list."
459 (let ((sorted t)
460 (nullable nil)
461 (head (cons nil ipatterns)))
462 (let ((tail head)
463 (final-tail nil)
464 (prev-index -100)
465 (cur ipatterns)
466 member)
467 ;; the cdr of tail is always cur
468 (while cur
469 (setq member (car cur))
470 (or nullable
471 (setq nullable (rng-ipattern-get-nullable member)))
472 (cond ((eq (rng-ipattern-get-type member) 'choice)
473 (setq final-tail
474 (append (rng-ipattern-get-child member)
475 final-tail))
476 (setq cur (cdr cur))
477 (setq sorted nil)
478 (setcdr tail cur))
479 ((eq member rng-not-allowed-ipattern)
480 (setq cur (cdr cur))
481 (setcdr tail cur))
483 (if (and sorted
484 (let ((cur-index (rng-ipattern-get-index member)))
485 (if (>= prev-index cur-index)
486 (or (= prev-index cur-index) ; will remove it
487 (setq sorted nil)) ; won't remove it
488 (setq prev-index cur-index)
489 ;; won't remove it
490 nil)))
491 (progn
492 ;; remove it
493 (setq cur (cdr cur))
494 (setcdr tail cur))
495 ;; don't remove it
496 (setq tail cur)
497 (setq cur (cdr cur))))))
498 (setcdr tail final-tail))
499 (setq head (cdr head))
500 (cons nullable
501 (if sorted
502 head
503 (rng-uniquify-eq (sort head 'rng-compare-ipattern))))))
505 (defun rng-compare-ipattern (p1 p2)
506 (< (rng-ipattern-get-index p1)
507 (rng-ipattern-get-index p2)))
509 ;;; Name classes
511 (defsubst rng-name-class-contains (nc nm)
512 (if (consp nc)
513 (equal nm nc)
514 (rng-name-class-contains1 nc nm)))
516 (defun rng-name-class-contains1 (nc nm)
517 (let ((type (aref nc 0)))
518 (cond ((eq type 'any-name) t)
519 ((eq type 'any-name-except)
520 (not (rng-name-class-contains (aref nc 1) nm)))
521 ((eq type 'ns-name)
522 (eq (car nm) (aref nc 1)))
523 ((eq type 'ns-name-except)
524 (and (eq (car nm) (aref nc 1))
525 (not (rng-name-class-contains (aref nc 2) nm))))
526 ((eq type 'choice)
527 (let ((choices (aref nc 1))
528 (ret nil))
529 (while choices
530 (if (rng-name-class-contains (car choices) nm)
531 (progn
532 (setq choices nil)
533 (setq ret t))
534 (setq choices (cdr choices))))
535 ret)))))
537 (defun rng-name-class-possible-names (nc accum)
538 "Return a list of possible names that nameclass NC can match.
540 Each possible name should be returned as a (NAMESPACE . LOCAL-NAME)
541 pair, where NAMESPACE is a symbol or nil and LOCAL-NAME is a string.
542 nil for NAMESPACE matches the absent namespace. ACCUM is a list of
543 names which should be appended to the returned list. The returned list
544 may contain duplicates."
545 (if (consp nc)
546 (cons nc accum)
547 (when (eq (aref nc 0) 'choice)
548 (let ((members (aref nc 1)) member)
549 (while members
550 (setq member (car members))
551 (setq accum
552 (if (consp member)
553 (cons member accum)
554 (rng-name-class-possible-names member
555 accum)))
556 (setq members (cdr members)))))
557 accum))
559 ;;; Debugging utilities
561 (defun rng-ipattern-to-string (ipattern)
562 (let ((type (rng-ipattern-get-type ipattern)))
563 (cond ((eq type 'after)
564 (concat (rng-ipattern-to-string
565 (rng-ipattern-get-child ipattern))
566 " </> "
567 (rng-ipattern-to-string
568 (rng-ipattern-get-after ipattern))))
569 ((eq type 'element)
570 (concat "element "
571 (rng-name-class-to-string
572 (rng-ipattern-get-name-class ipattern))
573 ;; we can get cycles with elements so don't print it out
574 " {...}"))
575 ((eq type 'attribute)
576 (concat "attribute "
577 (rng-name-class-to-string
578 (rng-ipattern-get-name-class ipattern))
579 " { "
580 (rng-ipattern-to-string
581 (rng-ipattern-get-child ipattern))
582 " } "))
583 ((eq type 'empty) "empty")
584 ((eq type 'text) "text")
585 ((eq type 'not-allowed) "notAllowed")
586 ((eq type 'one-or-more)
587 (concat (rng-ipattern-to-string
588 (rng-ipattern-get-child ipattern))
589 "+"))
590 ((eq type 'choice)
591 (concat "("
592 (mapconcat 'rng-ipattern-to-string
593 (rng-ipattern-get-child ipattern)
594 " | ")
595 ")"))
596 ((eq type 'group)
597 (concat "("
598 (mapconcat 'rng-ipattern-to-string
599 (rng-ipattern-get-child ipattern)
600 ", ")
601 ")"))
602 ((eq type 'interleave)
603 (concat "("
604 (mapconcat 'rng-ipattern-to-string
605 (rng-ipattern-get-child ipattern)
606 " & ")
607 ")"))
608 (t (symbol-name type)))))
610 (defun rng-name-class-to-string (nc)
611 (if (consp nc)
612 (cdr nc)
613 (let ((type (aref nc 0)))
614 (cond ((eq type 'choice)
615 (mapconcat 'rng-name-class-to-string
616 (aref nc 1)
617 "|"))
618 (t (concat (symbol-name type) "*"))))))
621 ;;; Compiling
623 (defun rng-compile-maybe-init ()
624 (unless rng-compile-table
625 (setq rng-compile-table (make-hash-table :test 'eq))))
627 (defun rng-compile-clear ()
628 (when rng-compile-table
629 (clrhash rng-compile-table)))
631 (defun rng-compile (pattern)
632 (or (gethash pattern rng-compile-table)
633 (let ((ipattern (apply (get (car pattern) 'rng-compile)
634 (cdr pattern))))
635 (puthash pattern ipattern rng-compile-table)
636 ipattern)))
638 (put 'empty 'rng-compile 'rng-compile-empty)
639 (put 'text 'rng-compile 'rng-compile-text)
640 (put 'not-allowed 'rng-compile 'rng-compile-not-allowed)
641 (put 'element 'rng-compile 'rng-compile-element)
642 (put 'attribute 'rng-compile 'rng-compile-attribute)
643 (put 'choice 'rng-compile 'rng-compile-choice)
644 (put 'optional 'rng-compile 'rng-compile-optional)
645 (put 'group 'rng-compile 'rng-compile-group)
646 (put 'interleave 'rng-compile 'rng-compile-interleave)
647 (put 'ref 'rng-compile 'rng-compile-ref)
648 (put 'one-or-more 'rng-compile 'rng-compile-one-or-more)
649 (put 'zero-or-more 'rng-compile 'rng-compile-zero-or-more)
650 (put 'mixed 'rng-compile 'rng-compile-mixed)
651 (put 'data 'rng-compile 'rng-compile-data)
652 (put 'data-except 'rng-compile 'rng-compile-data-except)
653 (put 'value 'rng-compile 'rng-compile-value)
654 (put 'list 'rng-compile 'rng-compile-list)
656 (defun rng-compile-not-allowed () rng-not-allowed-ipattern)
657 (defun rng-compile-empty () rng-empty-ipattern)
658 (defun rng-compile-text () rng-text-ipattern)
660 (defun rng-compile-element (name-class pattern)
661 ;; don't intern
662 (rng-make-ipattern 'element
663 (rng-gen-ipattern-index)
664 (rng-compile-name-class name-class)
665 pattern ; compile lazily
666 nil))
668 (defun rng-element-get-child (element)
669 (let ((tem (rng-ipattern-get-child element)))
670 (if (vectorp tem)
672 (rng-ipattern-set-child element (rng-compile tem)))))
674 (defun rng-compile-attribute (name-class pattern)
675 (rng-intern-attribute (rng-compile-name-class name-class)
676 (rng-compile pattern)))
678 (defun rng-compile-ref (pattern name)
679 (and (memq pattern rng-being-compiled)
680 (rng-compile-error "Reference loop on symbol %s" name))
681 (setq rng-being-compiled
682 (cons pattern rng-being-compiled))
683 (unwind-protect
684 (rng-compile pattern)
685 (setq rng-being-compiled
686 (cdr rng-being-compiled))))
688 (defun rng-compile-one-or-more (pattern)
689 (rng-intern-one-or-more (rng-compile pattern)))
691 (defun rng-compile-zero-or-more (pattern)
692 (rng-intern-optional
693 (rng-intern-one-or-more (rng-compile pattern))))
695 (defun rng-compile-optional (pattern)
696 (rng-intern-optional (rng-compile pattern)))
698 (defun rng-compile-mixed (pattern)
699 (rng-intern-interleave (cons rng-text-ipattern
700 (list (rng-compile pattern)))))
702 (defun rng-compile-list (pattern)
703 (rng-intern-list (rng-compile pattern)))
705 (defun rng-compile-choice (&rest patterns)
706 (rng-intern-choice (mapcar 'rng-compile patterns)))
708 (defun rng-compile-group (&rest patterns)
709 (rng-intern-group (mapcar 'rng-compile patterns)))
711 (defun rng-compile-interleave (&rest patterns)
712 (rng-intern-interleave (mapcar 'rng-compile patterns)))
714 (defun rng-compile-dt (name params)
715 (let ((rng-dt-error-reporter 'rng-compile-error))
716 (funcall (let ((uri (car name)))
717 (or (get uri 'rng-dt-compile)
718 (rng-compile-error "Unknown datatype library %s" uri)))
719 (cdr name)
720 params)))
722 (defun rng-compile-data (name params)
723 (let ((dt (rng-compile-dt name params)))
724 (rng-intern-data (cdr dt) (car dt))))
726 (defun rng-compile-data-except (name params pattern)
727 (rng-intern-data-except (cdr (rng-compile-dt name params))
728 (rng-compile pattern)))
730 (defun rng-compile-value (name str context)
731 (let* ((dt (cdr (rng-compile-dt name '())))
732 (rng-dt-namespace-context-getter (list 'identity context))
733 (obj (rng-dt-make-value dt str)))
734 (if obj
735 (rng-intern-value dt obj)
736 (rng-compile-error "Value %s is not a valid instance of the datatype %s"
738 name))))
740 (defun rng-compile-name-class (nc)
741 (let ((type (car nc)))
742 (cond ((eq type 'name) (nth 1 nc))
743 ((eq type 'any-name) [any-name])
744 ((eq type 'any-name-except)
745 (vector 'any-name-except
746 (rng-compile-name-class (nth 1 nc))))
747 ((eq type 'ns-name)
748 (vector 'ns-name (nth 1 nc)))
749 ((eq type 'ns-name-except)
750 (vector 'ns-name-except
751 (nth 1 nc)
752 (rng-compile-name-class (nth 2 nc))))
753 ((eq type 'choice)
754 (vector 'choice
755 (mapcar 'rng-compile-name-class (cdr nc))))
756 (t (error "Bad name-class type %s" type)))))
758 ;;; Searching patterns
760 ;; We write this non-recursively to avoid hitting max-lisp-eval-depth
761 ;; on large schemas.
763 (defun rng-map-element-attribute (function pattern accum &rest args)
764 (let ((searched (make-hash-table :test 'eq))
765 type todo patterns)
766 (while (progn
767 (setq type (car pattern))
768 (cond ((memq type '(element attribute))
769 (setq accum
770 (apply function
771 (cons pattern
772 (cons accum args))))
773 (setq pattern (nth 2 pattern)))
774 ((eq type 'ref)
775 (setq pattern (nth 1 pattern))
776 (if (gethash pattern searched)
777 (setq pattern nil)
778 (puthash pattern t searched)))
779 ((memq type '(choice group interleave))
780 (setq todo (cons (cdr pattern) todo))
781 (setq pattern nil))
782 ((memq type '(one-or-more
783 zero-or-more
784 optional
785 mixed))
786 (setq pattern (nth 1 pattern)))
787 (t (setq pattern nil)))
788 (cond (pattern)
789 (patterns
790 (setq pattern (car patterns))
791 (setq patterns (cdr patterns))
793 (todo
794 (setq patterns (car todo))
795 (setq todo (cdr todo))
796 (setq pattern (car patterns))
797 (setq patterns (cdr patterns))
798 t))))
799 accum))
801 (defun rng-find-element-content-pattern (pattern accum name)
802 (if (and (eq (car pattern) 'element)
803 (rng-search-name name (nth 1 pattern)))
804 (cons (rng-compile (nth 2 pattern)) accum)
805 accum))
807 (defun rng-search-name (name nc)
808 (let ((type (car nc)))
809 (cond ((eq type 'name)
810 (equal (cadr nc) name))
811 ((eq type 'choice)
812 (let ((choices (cdr nc))
813 (found nil))
814 (while (and choices (not found))
815 (if (rng-search-name name (car choices))
816 (setq found t)
817 (setq choices (cdr choices))))
818 found))
819 (t nil))))
821 (defun rng-find-name-class-uris (nc accum)
822 (let ((type (car nc)))
823 (cond ((eq type 'name)
824 (rng-accum-namespace-uri (car (nth 1 nc)) accum))
825 ((memq type '(ns-name ns-name-except))
826 (rng-accum-namespace-uri (nth 1 nc) accum))
827 ((eq type 'choice)
828 (let ((choices (cdr nc)))
829 (while choices
830 (setq accum
831 (rng-find-name-class-uris (car choices) accum))
832 (setq choices (cdr choices))))
833 accum)
834 (t accum))))
836 (defun rng-accum-namespace-uri (ns accum)
837 (if (and ns (not (memq ns accum)))
838 (cons ns accum)
839 accum))
841 ;;; Derivatives
843 (defun rng-ipattern-text-typed-p (ipattern)
844 (let ((memo (rng-ipattern-get-memo-text-typed ipattern)))
845 (if (eq memo 'unknown)
846 (rng-ipattern-set-memo-text-typed
847 ipattern
848 (rng-ipattern-compute-text-typed-p ipattern))
849 memo)))
851 (defun rng-ipattern-compute-text-typed-p (ipattern)
852 (let ((type (rng-ipattern-get-type ipattern)))
853 (cond ((eq type 'choice)
854 (let ((cur (rng-ipattern-get-child ipattern))
855 (ret nil))
856 (while (and cur (not ret))
857 (if (rng-ipattern-text-typed-p (car cur))
858 (setq ret t)
859 (setq cur (cdr cur))))
860 ret))
861 ((eq type 'group)
862 (let ((cur (rng-ipattern-get-child ipattern))
863 (ret nil)
864 member)
865 (while (and cur (not ret))
866 (setq member (car cur))
867 (if (rng-ipattern-text-typed-p member)
868 (setq ret t))
869 (setq cur
870 (and (rng-ipattern-get-nullable member)
871 (cdr cur))))
872 ret))
873 ((eq type 'after)
874 (rng-ipattern-text-typed-p (rng-ipattern-get-child ipattern)))
875 (t (and (memq type '(value list data data-except)) t)))))
877 (defun rng-start-tag-open-deriv (ipattern nm)
878 (or (rng-memo-map-get
880 (rng-ipattern-get-memo-map-start-tag-open-deriv ipattern))
881 (rng-ipattern-memo-start-tag-open-deriv
882 ipattern
884 (rng-compute-start-tag-open-deriv ipattern nm))))
886 (defun rng-ipattern-memo-start-tag-open-deriv (ipattern nm deriv)
887 (or (memq ipattern rng-const-ipatterns)
888 (rng-ipattern-set-memo-map-start-tag-open-deriv
889 ipattern
890 (rng-memo-map-add nm
891 deriv
892 (rng-ipattern-get-memo-map-start-tag-open-deriv
893 ipattern))))
894 deriv)
896 (defun rng-compute-start-tag-open-deriv (ipattern nm)
897 (let ((type (rng-ipattern-get-type ipattern)))
898 (cond ((eq type 'choice)
899 (rng-transform-choice `(lambda (p)
900 (rng-start-tag-open-deriv p ',nm))
901 ipattern))
902 ((eq type 'element)
903 (if (rng-name-class-contains
904 (rng-ipattern-get-name-class ipattern)
906 (rng-intern-after (rng-element-get-child ipattern)
907 rng-empty-ipattern)
908 rng-not-allowed-ipattern))
909 ((eq type 'group)
910 (rng-transform-group-nullable
911 `(lambda (p) (rng-start-tag-open-deriv p ',nm))
912 'rng-cons-group-after
913 ipattern))
914 ((eq type 'interleave)
915 (rng-transform-interleave-single
916 `(lambda (p) (rng-start-tag-open-deriv p ',nm))
917 'rng-subst-interleave-after
918 ipattern))
919 ((eq type 'one-or-more)
920 (rng-apply-after
921 `(lambda (p)
922 (rng-intern-group (list p ,(rng-intern-optional ipattern))))
923 (rng-start-tag-open-deriv (rng-ipattern-get-child ipattern)
924 nm)))
925 ((eq type 'after)
926 (rng-apply-after
927 `(lambda (p)
928 (rng-intern-after p
929 ,(rng-ipattern-get-after ipattern)))
930 (rng-start-tag-open-deriv (rng-ipattern-get-child ipattern)
931 nm)))
932 (t rng-not-allowed-ipattern))))
934 (defun rng-start-attribute-deriv (ipattern nm)
935 (or (rng-memo-map-get
937 (rng-ipattern-get-memo-map-start-attribute-deriv ipattern))
938 (rng-ipattern-memo-start-attribute-deriv
939 ipattern
941 (rng-compute-start-attribute-deriv ipattern nm))))
943 (defun rng-ipattern-memo-start-attribute-deriv (ipattern nm deriv)
944 (or (memq ipattern rng-const-ipatterns)
945 (rng-ipattern-set-memo-map-start-attribute-deriv
946 ipattern
947 (rng-memo-map-add
949 deriv
950 (rng-ipattern-get-memo-map-start-attribute-deriv ipattern))))
951 deriv)
953 (defun rng-compute-start-attribute-deriv (ipattern nm)
954 (let ((type (rng-ipattern-get-type ipattern)))
955 (cond ((eq type 'choice)
956 (rng-transform-choice `(lambda (p)
957 (rng-start-attribute-deriv p ',nm))
958 ipattern))
959 ((eq type 'attribute)
960 (if (rng-name-class-contains
961 (rng-ipattern-get-name-class ipattern)
963 (rng-intern-after (rng-ipattern-get-child ipattern)
964 rng-empty-ipattern)
965 rng-not-allowed-ipattern))
966 ((eq type 'group)
967 (rng-transform-interleave-single
968 `(lambda (p) (rng-start-attribute-deriv p ',nm))
969 'rng-subst-group-after
970 ipattern))
971 ((eq type 'interleave)
972 (rng-transform-interleave-single
973 `(lambda (p) (rng-start-attribute-deriv p ',nm))
974 'rng-subst-interleave-after
975 ipattern))
976 ((eq type 'one-or-more)
977 (rng-apply-after
978 `(lambda (p)
979 (rng-intern-group (list p ,(rng-intern-optional ipattern))))
980 (rng-start-attribute-deriv (rng-ipattern-get-child ipattern)
981 nm)))
982 ((eq type 'after)
983 (rng-apply-after
984 `(lambda (p)
985 (rng-intern-after p ,(rng-ipattern-get-after ipattern)))
986 (rng-start-attribute-deriv (rng-ipattern-get-child ipattern)
987 nm)))
988 (t rng-not-allowed-ipattern))))
990 (defun rng-cons-group-after (x y)
991 (rng-apply-after `(lambda (p) (rng-intern-group (cons p ',y)))
994 (defun rng-subst-group-after (new old list)
995 (rng-apply-after `(lambda (p)
996 (rng-intern-group (rng-substq p ,old ',list)))
997 new))
999 (defun rng-subst-interleave-after (new old list)
1000 (rng-apply-after `(lambda (p)
1001 (rng-intern-interleave (rng-substq p ,old ',list)))
1002 new))
1004 (defun rng-apply-after (f ipattern)
1005 (let ((type (rng-ipattern-get-type ipattern)))
1006 (cond ((eq type 'after)
1007 (rng-intern-after
1008 (rng-ipattern-get-child ipattern)
1009 (funcall f
1010 (rng-ipattern-get-after ipattern))))
1011 ((eq type 'choice)
1012 (rng-transform-choice `(lambda (x) (rng-apply-after ,f x))
1013 ipattern))
1014 (t rng-not-allowed-ipattern))))
1016 (defun rng-start-tag-close-deriv (ipattern)
1017 (or (rng-ipattern-get-memo-start-tag-close-deriv ipattern)
1018 (rng-ipattern-set-memo-start-tag-close-deriv
1019 ipattern
1020 (rng-compute-start-tag-close-deriv ipattern))))
1022 (defconst rng-transform-map
1023 '((choice . rng-transform-choice)
1024 (group . rng-transform-group)
1025 (interleave . rng-transform-interleave)
1026 (one-or-more . rng-transform-one-or-more)
1027 (after . rng-transform-after-child)))
1029 (defun rng-compute-start-tag-close-deriv (ipattern)
1030 (let* ((type (rng-ipattern-get-type ipattern)))
1031 (if (eq type 'attribute)
1032 rng-not-allowed-ipattern
1033 (let ((transform (assq type rng-transform-map)))
1034 (if transform
1035 (funcall (cdr transform)
1036 'rng-start-tag-close-deriv
1037 ipattern)
1038 ipattern)))))
1040 (defun rng-ignore-attributes-deriv (ipattern)
1041 (let* ((type (rng-ipattern-get-type ipattern)))
1042 (if (eq type 'attribute)
1043 rng-empty-ipattern
1044 (let ((transform (assq type rng-transform-map)))
1045 (if transform
1046 (funcall (cdr transform)
1047 'rng-ignore-attributes-deriv
1048 ipattern)
1049 ipattern)))))
1051 (defun rng-text-only-deriv (ipattern)
1052 (or (rng-ipattern-get-memo-text-only-deriv ipattern)
1053 (rng-ipattern-set-memo-text-only-deriv
1054 ipattern
1055 (rng-compute-text-only-deriv ipattern))))
1057 (defun rng-compute-text-only-deriv (ipattern)
1058 (let* ((type (rng-ipattern-get-type ipattern)))
1059 (if (eq type 'element)
1060 rng-not-allowed-ipattern
1061 (let ((transform (assq type
1062 '((choice . rng-transform-choice)
1063 (group . rng-transform-group)
1064 (interleave . rng-transform-interleave)
1065 (one-or-more . rng-transform-one-or-more)
1066 (after . rng-transform-after-child)))))
1067 (if transform
1068 (funcall (cdr transform)
1069 'rng-text-only-deriv
1070 ipattern)
1071 ipattern)))))
1073 (defun rng-mixed-text-deriv (ipattern)
1074 (or (rng-ipattern-get-memo-mixed-text-deriv ipattern)
1075 (rng-ipattern-set-memo-mixed-text-deriv
1076 ipattern
1077 (rng-compute-mixed-text-deriv ipattern))))
1079 (defun rng-compute-mixed-text-deriv (ipattern)
1080 (let ((type (rng-ipattern-get-type ipattern)))
1081 (cond ((eq type 'text) ipattern)
1082 ((eq type 'after)
1083 (rng-transform-after-child 'rng-mixed-text-deriv
1084 ipattern))
1085 ((eq type 'choice)
1086 (rng-transform-choice 'rng-mixed-text-deriv
1087 ipattern))
1088 ((eq type 'one-or-more)
1089 (rng-intern-group
1090 (list (rng-mixed-text-deriv
1091 (rng-ipattern-get-child ipattern))
1092 (rng-intern-optional ipattern))))
1093 ((eq type 'group)
1094 (rng-transform-group-nullable
1095 'rng-mixed-text-deriv
1096 (lambda (x y) (rng-intern-group (cons x y)))
1097 ipattern))
1098 ((eq type 'interleave)
1099 (rng-transform-interleave-single
1100 'rng-mixed-text-deriv
1101 (lambda (new old list) (rng-intern-interleave
1102 (rng-substq new old list)))
1103 ipattern))
1104 ((and (eq type 'data)
1105 (not (rng-ipattern-get-memo-text-typed ipattern)))
1106 ipattern)
1107 (t rng-not-allowed-ipattern))))
1109 (defun rng-end-tag-deriv (ipattern)
1110 (or (rng-ipattern-get-memo-end-tag-deriv ipattern)
1111 (rng-ipattern-set-memo-end-tag-deriv
1112 ipattern
1113 (rng-compute-end-tag-deriv ipattern))))
1115 (defun rng-compute-end-tag-deriv (ipattern)
1116 (let ((type (rng-ipattern-get-type ipattern)))
1117 (cond ((eq type 'choice)
1118 (rng-intern-choice
1119 (mapcar 'rng-end-tag-deriv
1120 (rng-ipattern-get-child ipattern))))
1121 ((eq type 'after)
1122 (if (rng-ipattern-get-nullable
1123 (rng-ipattern-get-child ipattern))
1124 (rng-ipattern-get-after ipattern)
1125 rng-not-allowed-ipattern))
1126 (t rng-not-allowed-ipattern))))
1128 (defun rng-data-deriv (ipattern value)
1129 (or (rng-memo-map-get value
1130 (rng-ipattern-get-memo-map-data-deriv ipattern))
1131 (and (rng-memo-map-get
1132 (cons value (rng-namespace-context-get-no-trace))
1133 (rng-ipattern-get-memo-map-data-deriv ipattern))
1134 (rng-memo-map-get
1135 (cons value (apply (car rng-dt-namespace-context-getter)
1136 (cdr rng-dt-namespace-context-getter)))
1137 (rng-ipattern-get-memo-map-data-deriv ipattern)))
1138 (let* ((used-context (vector nil))
1139 (rng-dt-namespace-context-getter
1140 (cons 'rng-namespace-context-tracer
1141 (cons used-context
1142 rng-dt-namespace-context-getter)))
1143 (deriv (rng-compute-data-deriv ipattern value)))
1144 (rng-ipattern-memo-data-deriv ipattern
1145 value
1146 (aref used-context 0)
1147 deriv))))
1149 (defun rng-namespace-context-tracer (used getter &rest args)
1150 (let ((context (apply getter args)))
1151 (aset used 0 context)
1152 context))
1154 (defun rng-namespace-context-get-no-trace ()
1155 (let ((tem rng-dt-namespace-context-getter))
1156 (while (and tem (eq (car tem) 'rng-namespace-context-tracer))
1157 (setq tem (cddr tem)))
1158 (apply (car tem) (cdr tem))))
1160 (defconst rng-memo-data-deriv-max-length 80
1161 "Don't memoize data-derivs for values longer than this.")
1163 (defun rng-ipattern-memo-data-deriv (ipattern value context deriv)
1164 (or (memq ipattern rng-const-ipatterns)
1165 (> (length value) rng-memo-data-deriv-max-length)
1166 (rng-ipattern-set-memo-map-data-deriv
1167 ipattern
1168 (rng-memo-map-add (if context (cons value context) value)
1169 deriv
1170 (rng-ipattern-get-memo-map-data-deriv ipattern)
1171 t)))
1172 deriv)
1174 (defun rng-compute-data-deriv (ipattern value)
1175 (let ((type (rng-ipattern-get-type ipattern)))
1176 (cond ((eq type 'text) ipattern)
1177 ((eq type 'choice)
1178 (rng-transform-choice `(lambda (p) (rng-data-deriv p ,value))
1179 ipattern))
1180 ((eq type 'group)
1181 (rng-transform-group-nullable
1182 `(lambda (p) (rng-data-deriv p ,value))
1183 (lambda (x y) (rng-intern-group (cons x y)))
1184 ipattern))
1185 ((eq type 'one-or-more)
1186 (rng-intern-group (list (rng-data-deriv
1187 (rng-ipattern-get-child ipattern)
1188 value)
1189 (rng-intern-optional ipattern))))
1190 ((eq type 'after)
1191 (let ((child (rng-ipattern-get-child ipattern)))
1192 (if (or (rng-ipattern-get-nullable
1193 (rng-data-deriv child value))
1194 (and (rng-ipattern-get-nullable child)
1195 (rng-blank-p value)))
1196 (rng-ipattern-get-after ipattern)
1197 rng-not-allowed-ipattern)))
1198 ((eq type 'data)
1199 (if (rng-dt-make-value (rng-ipattern-get-datatype ipattern)
1200 value)
1201 rng-empty-ipattern
1202 rng-not-allowed-ipattern))
1203 ((eq type 'data-except)
1204 (if (and (rng-dt-make-value (rng-ipattern-get-datatype ipattern)
1205 value)
1206 (not (rng-ipattern-get-nullable
1207 (rng-data-deriv
1208 (rng-ipattern-get-child ipattern)
1209 value))))
1210 rng-empty-ipattern
1211 rng-not-allowed-ipattern))
1212 ((eq type 'value)
1213 (if (equal (rng-dt-make-value (rng-ipattern-get-datatype ipattern)
1214 value)
1215 (rng-ipattern-get-value-object ipattern))
1216 rng-empty-ipattern
1217 rng-not-allowed-ipattern))
1218 ((eq type 'list)
1219 (let ((tokens (split-string value))
1220 (state (rng-ipattern-get-child ipattern)))
1221 (while (and tokens
1222 (not (eq state rng-not-allowed-ipattern)))
1223 (setq state (rng-data-deriv state (car tokens)))
1224 (setq tokens (cdr tokens)))
1225 (if (rng-ipattern-get-nullable state)
1226 rng-empty-ipattern
1227 rng-not-allowed-ipattern)))
1228 ;; don't think interleave can occur
1229 ;; since we do text-only-deriv first
1230 (t rng-not-allowed-ipattern))))
1232 (defun rng-transform-multi (f ipattern interner)
1233 (let* ((members (rng-ipattern-get-child ipattern))
1234 (transformed (mapcar f members)))
1235 (if (rng-members-eq members transformed)
1236 ipattern
1237 (funcall interner transformed))))
1239 (defun rng-transform-choice (f ipattern)
1240 (rng-transform-multi f ipattern 'rng-intern-choice))
1242 (defun rng-transform-group (f ipattern)
1243 (rng-transform-multi f ipattern 'rng-intern-group))
1245 (defun rng-transform-interleave (f ipattern)
1246 (rng-transform-multi f ipattern 'rng-intern-interleave))
1248 (defun rng-transform-one-or-more (f ipattern)
1249 (let* ((child (rng-ipattern-get-child ipattern))
1250 (transformed (funcall f child)))
1251 (if (eq child transformed)
1252 ipattern
1253 (rng-intern-one-or-more transformed))))
1255 (defun rng-transform-after-child (f ipattern)
1256 (let* ((child (rng-ipattern-get-child ipattern))
1257 (transformed (funcall f child)))
1258 (if (eq child transformed)
1259 ipattern
1260 (rng-intern-after transformed
1261 (rng-ipattern-get-after ipattern)))))
1263 (defun rng-transform-interleave-single (f subster ipattern)
1264 (let ((children (rng-ipattern-get-child ipattern))
1265 found)
1266 (while (and children (not found))
1267 (let* ((child (car children))
1268 (transformed (funcall f child)))
1269 (if (eq transformed rng-not-allowed-ipattern)
1270 (setq children (cdr children))
1271 (setq found
1272 (funcall subster
1273 transformed
1274 child
1275 (rng-ipattern-get-child ipattern))))))
1276 (or found
1277 rng-not-allowed-ipattern)))
1279 (defun rng-transform-group-nullable (f conser ipattern)
1280 "Given a group x1,...,xn,y1,...,yn where the xs are all
1281 nullable and y1 isn't, return a choice
1282 (conser f(x1) x2,...,xm,y1,...,yn)
1283 |(conser f(x2) x3,...,xm,y1,...,yn)
1284 |...
1285 |(conser f(xm) y1,...,yn)
1286 |(conser f(y1) y2,...,yn)"
1287 (rng-intern-choice
1288 (rng-transform-group-nullable-gen-choices
1290 conser
1291 (rng-ipattern-get-child ipattern))))
1293 (defun rng-transform-group-nullable-gen-choices (f conser members)
1294 (let ((head (car members))
1295 (tail (cdr members)))
1296 (if tail
1297 (cons (funcall conser (funcall f head) tail)
1298 (if (rng-ipattern-get-nullable head)
1299 (rng-transform-group-nullable-gen-choices f conser tail)
1300 nil))
1301 (list (funcall f head)))))
1303 (defun rng-members-eq (list1 list2)
1304 (while (and list1
1305 list2
1306 (eq (car list1) (car list2)))
1307 (setq list1 (cdr list1))
1308 (setq list2 (cdr list2)))
1309 (and (null list1) (null list2)))
1312 (defun rng-ipattern-after (ipattern)
1313 (let ((type (rng-ipattern-get-type ipattern)))
1314 (cond ((eq type 'choice)
1315 (rng-transform-choice 'rng-ipattern-after ipattern))
1316 ((eq type 'after)
1317 (rng-ipattern-get-after ipattern))
1318 ((eq type 'not-allowed)
1319 ipattern)
1320 (t (error "Internal error in rng-ipattern-after: unexpected type %s" type)))))
1322 (defun rng-unknown-start-tag-open-deriv (ipattern)
1323 (rng-intern-after (rng-compile rng-any-content) ipattern))
1325 (defun rng-ipattern-optionalize-elements (ipattern)
1326 (let* ((type (rng-ipattern-get-type ipattern))
1327 (transform (assq type rng-transform-map)))
1328 (cond (transform
1329 (funcall (cdr transform)
1330 'rng-ipattern-optionalize-elements
1331 ipattern))
1332 ((eq type 'element)
1333 (rng-intern-optional ipattern))
1334 (t ipattern))))
1336 (defun rng-ipattern-empty-before-p (ipattern)
1337 (let ((type (rng-ipattern-get-type ipattern)))
1338 (cond ((eq type 'after)
1339 (eq (rng-ipattern-get-child ipattern) rng-empty-ipattern))
1340 ((eq type 'choice)
1341 (let ((members (rng-ipattern-get-child ipattern))
1342 (ret t))
1343 (while (and members ret)
1344 (or (rng-ipattern-empty-before-p (car members))
1345 (setq ret nil))
1346 (setq members (cdr members)))
1347 ret))
1348 (t nil))))
1350 (defun rng-ipattern-possible-start-tags (ipattern accum)
1351 (let ((type (rng-ipattern-get-type ipattern)))
1352 (cond ((eq type 'after)
1353 (rng-ipattern-possible-start-tags
1354 (rng-ipattern-get-child ipattern)
1355 accum))
1356 ((memq type '(choice interleave))
1357 (let ((members (rng-ipattern-get-child ipattern)))
1358 (while members
1359 (setq accum
1360 (rng-ipattern-possible-start-tags (car members)
1361 accum))
1362 (setq members (cdr members))))
1363 accum)
1364 ((eq type 'group)
1365 (let ((members (rng-ipattern-get-child ipattern)))
1366 (while members
1367 (setq accum
1368 (rng-ipattern-possible-start-tags (car members)
1369 accum))
1370 (setq members
1371 (and (rng-ipattern-get-nullable (car members))
1372 (cdr members)))))
1373 accum)
1374 ((eq type 'element)
1375 (if (eq (rng-element-get-child ipattern) rng-not-allowed-ipattern)
1376 accum
1377 (rng-name-class-possible-names
1378 (rng-ipattern-get-name-class ipattern)
1379 accum)))
1380 ((eq type 'one-or-more)
1381 (rng-ipattern-possible-start-tags
1382 (rng-ipattern-get-child ipattern)
1383 accum))
1384 (t accum))))
1386 (defun rng-ipattern-start-tag-possible-p (ipattern)
1387 (let ((type (rng-ipattern-get-type ipattern)))
1388 (cond ((memq type '(after one-or-more))
1389 (rng-ipattern-start-tag-possible-p
1390 (rng-ipattern-get-child ipattern)))
1391 ((memq type '(choice interleave))
1392 (let ((members (rng-ipattern-get-child ipattern))
1393 (possible nil))
1394 (while (and members (not possible))
1395 (setq possible
1396 (rng-ipattern-start-tag-possible-p (car members)))
1397 (setq members (cdr members)))
1398 possible))
1399 ((eq type 'group)
1400 (let ((members (rng-ipattern-get-child ipattern))
1401 (possible nil))
1402 (while (and members (not possible))
1403 (setq possible
1404 (rng-ipattern-start-tag-possible-p (car members)))
1405 (setq members
1406 (and (rng-ipattern-get-nullable (car members))
1407 (cdr members))))
1408 possible))
1409 ((eq type 'element)
1410 (not (eq (rng-element-get-child ipattern)
1411 rng-not-allowed-ipattern)))
1412 (t nil))))
1414 (defun rng-ipattern-possible-attributes (ipattern accum)
1415 (let ((type (rng-ipattern-get-type ipattern)))
1416 (cond ((eq type 'after)
1417 (rng-ipattern-possible-attributes (rng-ipattern-get-child ipattern)
1418 accum))
1419 ((memq type '(choice interleave group))
1420 (let ((members (rng-ipattern-get-child ipattern)))
1421 (while members
1422 (setq accum
1423 (rng-ipattern-possible-attributes (car members)
1424 accum))
1425 (setq members (cdr members))))
1426 accum)
1427 ((eq type 'attribute)
1428 (rng-name-class-possible-names
1429 (rng-ipattern-get-name-class ipattern)
1430 accum))
1431 ((eq type 'one-or-more)
1432 (rng-ipattern-possible-attributes
1433 (rng-ipattern-get-child ipattern)
1434 accum))
1435 (t accum))))
1437 (defun rng-ipattern-possible-values (ipattern accum)
1438 (let ((type (rng-ipattern-get-type ipattern)))
1439 (cond ((eq type 'after)
1440 (rng-ipattern-possible-values (rng-ipattern-get-child ipattern)
1441 accum))
1442 ((eq type 'choice)
1443 (let ((members (rng-ipattern-get-child ipattern)))
1444 (while members
1445 (setq accum
1446 (rng-ipattern-possible-values (car members)
1447 accum))
1448 (setq members (cdr members))))
1449 accum)
1450 ((eq type 'value)
1451 (let ((value-object (rng-ipattern-get-value-object ipattern)))
1452 (if (stringp value-object)
1453 (cons value-object accum)
1454 accum)))
1455 (t accum))))
1457 (defun rng-ipattern-required-element (ipattern)
1458 (let ((type (rng-ipattern-get-type ipattern)))
1459 (cond ((memq type '(after one-or-more))
1460 (rng-ipattern-required-element (rng-ipattern-get-child ipattern)))
1461 ((eq type 'choice)
1462 (let* ((members (rng-ipattern-get-child ipattern))
1463 (required (rng-ipattern-required-element (car members))))
1464 (while (and required
1465 (setq members (cdr members)))
1466 (unless (equal required
1467 (rng-ipattern-required-element (car members)))
1468 (setq required nil)))
1469 required))
1470 ((eq type 'group)
1471 (let ((members (rng-ipattern-get-child ipattern))
1472 required)
1473 (while (and (not (setq required
1474 (rng-ipattern-required-element
1475 (car members))))
1476 (rng-ipattern-get-nullable (car members))
1477 (setq members (cdr members))))
1478 required))
1479 ((eq type 'interleave)
1480 (let ((members (rng-ipattern-get-child ipattern))
1481 required)
1482 (while members
1483 (let ((tem (rng-ipattern-required-element (car members))))
1484 (cond ((not tem)
1485 (setq members (cdr members)))
1486 ((not required)
1487 (setq required tem)
1488 (setq members (cdr members)))
1489 ((equal required tem)
1490 (setq members (cdr members)))
1492 (setq required nil)
1493 (setq members nil)))))
1494 required))
1495 ((eq type 'element)
1496 (let ((nc (rng-ipattern-get-name-class ipattern)))
1497 (and (consp nc)
1498 (not (eq (rng-element-get-child ipattern)
1499 rng-not-allowed-ipattern))
1500 nc))))))
1502 (defun rng-ipattern-required-attributes (ipattern accum)
1503 (let ((type (rng-ipattern-get-type ipattern)))
1504 (cond ((eq type 'after)
1505 (rng-ipattern-required-attributes (rng-ipattern-get-child ipattern)
1506 accum))
1507 ((memq type '(interleave group))
1508 (let ((members (rng-ipattern-get-child ipattern)))
1509 (while members
1510 (setq accum
1511 (rng-ipattern-required-attributes (car members)
1512 accum))
1513 (setq members (cdr members))))
1514 accum)
1515 ((eq type 'choice)
1516 (let ((members (rng-ipattern-get-child ipattern))
1517 in-all in-this new-in-all)
1518 (setq in-all
1519 (rng-ipattern-required-attributes (car members)
1520 nil))
1521 (while (and in-all (setq members (cdr members)))
1522 (setq in-this
1523 (rng-ipattern-required-attributes (car members) nil))
1524 (setq new-in-all nil)
1525 (while in-this
1526 (when (member (car in-this) in-all)
1527 (setq new-in-all
1528 (cons (car in-this) new-in-all)))
1529 (setq in-this (cdr in-this)))
1530 (setq in-all new-in-all))
1531 (append in-all accum)))
1532 ((eq type 'attribute)
1533 (let ((nc (rng-ipattern-get-name-class ipattern)))
1534 (if (consp nc)
1535 (cons nc accum)
1536 accum)))
1537 ((eq type 'one-or-more)
1538 (rng-ipattern-required-attributes (rng-ipattern-get-child ipattern)
1539 accum))
1540 (t accum))))
1542 (defun rng-compile-error (&rest args)
1543 (signal 'rng-compile-error
1544 (list (apply 'format args))))
1546 (put 'rng-compile-error
1547 'error-conditions
1548 '(error rng-error rng-compile-error))
1550 (put 'rng-compile-error
1551 'error-message
1552 "Incorrect schema")
1555 ;;; External API
1557 (defsubst rng-match-state () rng-match-state)
1559 (defsubst rng-set-match-state (state)
1560 (setq rng-match-state state))
1562 (defsubst rng-match-state-equal (state)
1563 (eq state rng-match-state))
1565 (defun rng-schema-changed ()
1566 (rng-ipattern-clear)
1567 (rng-compile-clear))
1569 (defun rng-match-init-buffer ()
1570 (make-local-variable 'rng-compile-table)
1571 (make-local-variable 'rng-ipattern-table)
1572 (make-local-variable 'rng-last-ipattern-index))
1574 (defun rng-match-start-document ()
1575 (rng-ipattern-maybe-init)
1576 (rng-compile-maybe-init)
1577 (add-hook 'rng-schema-change-hook 'rng-schema-changed nil t)
1578 (setq rng-match-state (rng-compile rng-current-schema)))
1580 (defun rng-match-start-tag-open (name)
1581 (rng-update-match-state (rng-start-tag-open-deriv rng-match-state
1582 name)))
1584 (defun rng-match-attribute-name (name)
1585 (rng-update-match-state (rng-start-attribute-deriv rng-match-state
1586 name)))
1588 (defun rng-match-attribute-value (value)
1589 (rng-update-match-state (rng-data-deriv rng-match-state
1590 value)))
1592 (defun rng-match-element-value (value)
1593 (and (rng-update-match-state (rng-text-only-deriv rng-match-state))
1594 (rng-update-match-state (rng-data-deriv rng-match-state
1595 value))))
1597 (defun rng-match-start-tag-close ()
1598 (rng-update-match-state (rng-start-tag-close-deriv rng-match-state)))
1600 (defun rng-match-mixed-text ()
1601 (rng-update-match-state (rng-mixed-text-deriv rng-match-state)))
1603 (defun rng-match-end-tag ()
1604 (rng-update-match-state (rng-end-tag-deriv rng-match-state)))
1606 (defun rng-match-after ()
1607 (rng-update-match-state
1608 (rng-ipattern-after rng-match-state)))
1610 (defun rng-match-out-of-context-start-tag-open (name)
1611 (let* ((found (rng-map-element-attribute 'rng-find-element-content-pattern
1612 rng-current-schema
1614 name))
1615 (content-pattern (if found
1616 (rng-intern-choice found)
1617 rng-not-allowed-ipattern)))
1618 (rng-update-match-state
1619 (rng-intern-after content-pattern rng-match-state))))
1621 (defun rng-match-possible-namespace-uris ()
1622 "Return a list of all the namespace URIs used in the current schema.
1623 The absent URI is not included, so the result is always list of symbols."
1624 (rng-map-element-attribute (lambda (pattern accum)
1625 (rng-find-name-class-uris (nth 1 pattern)
1626 accum))
1627 rng-current-schema
1628 nil))
1630 (defun rng-match-unknown-start-tag-open ()
1631 (rng-update-match-state
1632 (rng-unknown-start-tag-open-deriv rng-match-state)))
1634 (defun rng-match-optionalize-elements ()
1635 (rng-update-match-state
1636 (rng-ipattern-optionalize-elements rng-match-state)))
1638 (defun rng-match-ignore-attributes ()
1639 (rng-update-match-state
1640 (rng-ignore-attributes-deriv rng-match-state)))
1642 (defun rng-match-text-typed-p ()
1643 (rng-ipattern-text-typed-p rng-match-state))
1645 (defun rng-match-empty-content ()
1646 (if (rng-match-text-typed-p)
1647 (rng-match-element-value "")
1648 (rng-match-end-tag)))
1650 (defun rng-match-empty-before-p ()
1651 "Return non-nil if what can be matched before an end-tag is empty.
1652 In other words, return non-nil if the pattern for what can be matched
1653 for an end-tag is equivalent to empty."
1654 (rng-ipattern-empty-before-p rng-match-state))
1656 (defun rng-match-infer-start-tag-namespace (local-name)
1657 (let ((ncs (rng-ipattern-possible-start-tags rng-match-state nil))
1658 (nc nil)
1659 (ns nil))
1660 (while ncs
1661 (setq nc (car ncs))
1662 (if (and (equal (cdr nc) local-name)
1663 (symbolp (car nc)))
1664 (cond ((not ns)
1665 ;; first possible namespace
1666 (setq ns (car nc))
1667 (setq ncs (cdr ncs)))
1668 ((equal ns (car nc))
1669 ;; same as first namespace
1670 (setq ncs (cdr ncs)))
1672 ;; more than one possible namespace
1673 (setq ns nil)
1674 (setq ncs nil)))
1675 (setq ncs (cdr ncs))))
1676 ns))
1678 (defun rng-match-nullable-p ()
1679 (rng-ipattern-get-nullable rng-match-state))
1681 (defun rng-match-possible-start-tag-names ()
1682 "Return a list of possible names that would be valid for start-tags.
1684 Each possible name is returned as a (NAMESPACE . LOCAL-NAME) pair,
1685 where NAMESPACE is a symbol or nil (meaning the absent namespace) and
1686 LOCAL-NAME is a string. The returned list may contain duplicates."
1687 (rng-ipattern-possible-start-tags rng-match-state nil))
1689 ;; This is no longer used. It might be useful so leave it in for now.
1690 (defun rng-match-start-tag-possible-p ()
1691 "Return non-nil if a start-tag is possible."
1692 (rng-ipattern-start-tag-possible-p rng-match-state))
1694 (defun rng-match-possible-attribute-names ()
1695 "Return a list of possible names that would be valid for attributes.
1697 See the function `rng-match-possible-start-tag-names' for
1698 more information."
1699 (rng-ipattern-possible-attributes rng-match-state nil))
1701 (defun rng-match-possible-value-strings ()
1702 "Return a list of strings that would be valid as content.
1703 The list may contain duplicates. Typically, the list will not
1704 be exhaustive."
1705 (rng-ipattern-possible-values rng-match-state nil))
1707 (defun rng-match-required-element-name ()
1708 "Return the name of an element which must occur, or nil if none."
1709 (rng-ipattern-required-element rng-match-state))
1711 (defun rng-match-required-attribute-names ()
1712 "Return a list of names of attributes which must all occur."
1713 (rng-ipattern-required-attributes rng-match-state nil))
1715 (defmacro rng-match-save (&rest body)
1716 (let ((state (make-symbol "state")))
1717 `(let ((,state rng-match-state))
1718 (unwind-protect
1719 (progn ,@body)
1720 (setq rng-match-state ,state)))))
1722 (put 'rng-match-save 'lisp-indent-function 0)
1723 (def-edebug-spec rng-match-save t)
1725 (defmacro rng-match-with-schema (schema &rest body)
1726 `(let ((rng-current-schema ,schema)
1727 rng-match-state
1728 rng-compile-table
1729 rng-ipattern-table
1730 rng-last-ipattern-index)
1731 (rng-ipattern-maybe-init)
1732 (rng-compile-maybe-init)
1733 (setq rng-match-state (rng-compile rng-current-schema))
1734 ,@body))
1736 (put 'rng-match-with-schema 'lisp-indent-function 1)
1737 (def-edebug-spec rng-match-with-schema t)
1739 (provide 'rng-match)
1741 ;; arch-tag: c8c50733-edcf-49fb-85e2-0aac8749b7f8
1742 ;;; rng-match.el ends here