mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-21 18:23:59 +00:00
3b7b181bde
`string-search` is easier to understand, less error-prone, much faster, does not pollute the regexp cache, and does not mutate global state. Use it where applicable and obviously safe (erring on the conservative side). * admin/authors.el (authors-canonical-file-name) (authors-scan-change-log): * lisp/apropos.el (apropos-command) (apropos-documentation-property, apropos-symbols-internal): * lisp/arc-mode.el (archive-arc-summarize) (archive-zoo-summarize): * lisp/calc/calc-aent.el (math-read-factor): * lisp/calc/calc-ext.el (math-read-big-expr) (math-format-nice-expr, math-format-number-fancy): * lisp/calc/calc-forms.el (math-read-angle-brackets): * lisp/calc/calc-graph.el (calc-graph-set-range): * lisp/calc/calc-keypd.el (calc-keypad-press): * lisp/calc/calc-lang.el (tex, latex, math-read-big-rec): * lisp/calc/calc-prog.el (calc-fix-token-name) (calc-user-define-permanent, math-define-exp): * lisp/calc/calc.el (calc-record, calcDigit-key) (calc-count-lines): * lisp/calc/calcalg2.el (calc-solve-for, calc-poly-roots) (math-do-integral): * lisp/calc/calcalg3.el (calc-find-root, calc-find-minimum) (calc-get-fit-variables): * lisp/cedet/ede/speedbar.el (ede-tag-expand): * lisp/cedet/semantic/java.el (semantic-java-expand-tag): * lisp/cedet/semantic/sb.el (semantic-sb-show-extra) (semantic-sb-expand-group): * lisp/cedet/semantic/wisent/python.el (semantic-python-instance-variable-p): * lisp/cus-edit.el (get): * lisp/descr-text.el (describe-text-sexp): * lisp/dired-aux.el (dired-compress-file): * lisp/dired-x.el (dired-make-relative-symlink): * lisp/dired.el (dired-glob-regexp): * lisp/dos-fns.el (dos-convert-standard-filename, dos-8+3-filename): * lisp/edmacro.el (edmacro-format-keys): * lisp/emacs-lisp/eieio-opt.el (eieio-sb-expand): * lisp/emacs-lisp/eieio-speedbar.el (eieio-speedbar-object-expand): * lisp/emacs-lisp/lisp-mnt.el (lm-keywords-list): * lisp/emacs-lisp/warnings.el (display-warning): * lisp/emulation/viper-ex.el (viper-ex-read-file-name) (ex-print-display-lines): * lisp/env.el (read-envvar-name, setenv): * lisp/epa-mail.el (epa-mail-encrypt): * lisp/epg.el (epg--start): * lisp/erc/erc-backend.el (erc-parse-server-response): * lisp/erc/erc-dcc.el (erc-dcc-member): * lisp/erc/erc-speedbar.el (erc-speedbar-expand-server) (erc-speedbar-expand-channel, erc-speedbar-expand-user): * lisp/erc/erc.el (erc-send-input): * lisp/eshell/em-glob.el (eshell-glob-entries): * lisp/eshell/esh-proc.el (eshell-needs-pipe-p): * lisp/eshell/esh-util.el (eshell-convert): * lisp/eshell/esh-var.el (eshell-envvar-names): * lisp/faces.el (x-resolve-font-name): * lisp/ffap.el (ffap-file-at-point): * lisp/files.el (wildcard-to-regexp, shell-quote-wildcard-pattern): * lisp/forms.el (forms--update): * lisp/frameset.el (frameset-filter-unshelve-param): * lisp/gnus/gnus-art.el (article-decode-charset): * lisp/gnus/gnus-kill.el (gnus-kill-parse-rn-kill-file): * lisp/gnus/gnus-mlspl.el (gnus-group-split-fancy): * lisp/gnus/gnus-msg.el (gnus-summary-resend-message-insert-gcc) (gnus-inews-insert-gcc): * lisp/gnus/gnus-rfc1843.el (rfc1843-decode-article-body): * lisp/gnus/gnus-search.el (gnus-search-indexed-parse-output) (gnus-search--complete-key-data): * lisp/gnus/gnus-spec.el (gnus-parse-simple-format): * lisp/gnus/gnus-sum.el (gnus-summary-refer-article): * lisp/gnus/gnus-util.el (gnus-extract-address-components) (gnus-newsgroup-directory-form): * lisp/gnus/gnus-uu.el (gnus-uu-grab-view): * lisp/gnus/gnus.el (gnus-group-native-p, gnus-short-group-name): * lisp/gnus/message.el (message-check-news-header-syntax) (message-make-message-id, message-user-mail-address) (message-make-fqdn, message-get-reply-headers, message-followup): * lisp/gnus/mm-decode.el (mm-dissect-buffer): * lisp/gnus/nnheader.el (nnheader-insert): * lisp/gnus/nnimap.el (nnimap-process-quirk) (nnimap-imap-ranges-to-gnus-ranges): * lisp/gnus/nnmaildir.el (nnmaildir--ensure-suffix): * lisp/gnus/nnmairix.el (nnmairix-determine-original-group-from-path): * lisp/gnus/nnrss.el (nnrss-match-macro): * lisp/gnus/nntp.el (nntp-find-group-and-number): * lisp/help-fns.el (help--symbol-completion-table-affixation): * lisp/help.el (help-function-arglist): * lisp/hippie-exp.el (he-concat-directory-file-name): * lisp/htmlfontify.el (hfy-relstub): * lisp/ido.el (ido-make-prompt, ido-complete, ido-copy-current-word) (ido-exhibit): * lisp/image/image-converter.el (image-convert-p): * lisp/info-xref.el (info-xref-docstrings): * lisp/info.el (Info-toc-build, Info-follow-reference) (Info-backward-node, Info-finder-find-node) (Info-speedbar-expand-node): * lisp/international/mule-diag.el (print-fontset-element): * lisp/language/korea-util.el (default-korean-keyboard): * lisp/linum.el (linum-after-change): * lisp/mail/ietf-drums.el (ietf-drums-parse-address): * lisp/mail/mail-utils.el (mail-dont-reply-to): * lisp/mail/rfc2047.el (rfc2047-encode-1, rfc2047-decode-string): * lisp/mail/rfc2231.el (rfc2231-parse-string): * lisp/mail/rmailkwd.el (rmail-set-label): * lisp/mail/rmailsum.el (rmail-header-summary): * lisp/mail/smtpmail.el (smtpmail-maybe-append-domain) (smtpmail-user-mail-address): * lisp/mail/uce.el (uce-reply-to-uce): * lisp/man.el (Man-default-man-entry): * lisp/mh-e/mh-alias.el (mh-alias-gecos-name) (mh-alias-minibuffer-confirm-address): * lisp/mh-e/mh-comp.el (mh-forwarded-letter-subject): * lisp/mh-e/mh-speed.el (mh-speed-parse-flists-output): * lisp/mh-e/mh-utils.el (mh-collect-folder-names-filter) (mh-folder-completion-function): * lisp/minibuffer.el (completion--make-envvar-table) (completion-file-name-table, completion-flex-try-completion) (completion-flex-all-completions): * lisp/mpc.el (mpc--proc-quote-string, mpc-cmd-special-tag-p) (mpc-constraints-tag-lookup): * lisp/net/ange-ftp.el (ange-ftp-send-cmd) (ange-ftp-allow-child-lookup): * lisp/net/mailcap.el (mailcap-mime-types): * lisp/net/mairix.el (mairix-search-thread-this-article): * lisp/net/pop3.el (pop3-open-server): * lisp/net/soap-client.el (soap-decode-xs-complex-type): * lisp/net/socks.el (socks-filter): * lisp/nxml/nxml-outln.el (nxml-highlighted-qname): * lisp/nxml/rng-cmpct.el (rng-c-expand-name, rng-c-expand-datatype): * lisp/nxml/rng-uri.el (rng-uri-file-name-1): * lisp/obsolete/complete.el (partial-completion-mode) (PC-do-completion): * lisp/obsolete/longlines.el (longlines-encode-string): * lisp/obsolete/nnir.el (nnir-compose-result): * lisp/obsolete/terminal.el (te-quote-arg-for-sh): * lisp/obsolete/tpu-edt.el (tpu-check-search-case): * lisp/obsolete/url-ns.el (isPlainHostName): * lisp/pcmpl-unix.el (pcomplete/scp): * lisp/play/dunnet.el (dun-listify-string2, dun-get-path) (dun-unix-parse, dun-doassign, dun-cat, dun-batch-unix-interface): * lisp/progmodes/ebnf2ps.el: (ebnf-eps-header-footer-comment): * lisp/progmodes/gdb-mi.el (gdb-var-delete) (gdb-speedbar-expand-node, gdbmi-bnf-incomplete-record-result): * lisp/progmodes/gud.el (gud-find-expr): * lisp/progmodes/idlw-help.el (idlwave-do-context-help1): * lisp/progmodes/idlw-shell.el (idlwave-shell-mode) (idlwave-shell-filter-hidden-output, idlwave-shell-filter): * lisp/progmodes/idlwave.el (idlwave-skip-label-or-case) (idlwave-routine-info): * lisp/progmodes/octave.el (inferior-octave-completion-at-point): * lisp/progmodes/sh-script.el (sh-add-completer): * lisp/progmodes/sql.el (defun): * lisp/progmodes/xscheme.el (xscheme-process-filter): * lisp/replace.el (query-replace-compile-replacement) (map-query-replace-regexp): * lisp/shell.el (shell--command-completion-data) (shell-environment-variable-completion): * lisp/simple.el (display-message-or-buffer): * lisp/speedbar.el (speedbar-dired, speedbar-tag-file) (speedbar-tag-expand): * lisp/subr.el (split-string-and-unquote): * lisp/tar-mode.el (tar-extract): * lisp/term.el (term-command-hook, serial-read-name): * lisp/textmodes/bibtex.el (bibtex-print-help-message): * lisp/textmodes/ispell.el (ispell-lookup-words, ispell-filter) (ispell-parse-output, ispell-buffer-local-parsing): * lisp/textmodes/reftex-cite.el (reftex-do-citation): * lisp/textmodes/reftex-parse.el (reftex-notice-new): * lisp/textmodes/reftex-ref.el (reftex-show-entry): * lisp/textmodes/reftex.el (reftex-compile-variables): * lisp/textmodes/tex-mode.el (tex-send-command) (tex-start-tex, tex-append): * lisp/thingatpt.el (thing-at-point-url-at-point): * lisp/tmm.el (tmm-add-one-shortcut): * lisp/transient.el (transient-format-key): * lisp/url/url-auth.el (url-basic-auth) (url-digest-auth-directory-id-assoc): * lisp/url/url-news.el (url-news): * lisp/url/url-util.el (url-parse-query-string): * lisp/vc/vc-cvs.el (vc-cvs-parse-entry): * lisp/wid-browse.el (widget-browse-sexp): * lisp/woman.el (woman-parse-colon-path, woman-mini-help) (WoMan-getpage-in-background, woman-negative-vertical-space): * lisp/xml.el: * test/lisp/emacs-lisp/check-declare-tests.el (check-declare-tests-warn): * test/lisp/files-tests.el (files-tests-file-name-non-special-dired-compress-handler): * test/lisp/net/network-stream-tests.el (server-process-filter): * test/src/coding-tests.el (ert-test-unibyte-buffer-dos-eol-decode): Use `string-search` instead of `string-match` and `string-match-p`.
926 lines
28 KiB
EmacsLisp
926 lines
28 KiB
EmacsLisp
;;; rng-cmpct.el --- parsing of RELAX NG Compact Syntax schemas -*- lexical-binding:t -*-
|
|
|
|
;; Copyright (C) 2003, 2007-2021 Free Software Foundation, Inc.
|
|
|
|
;; Author: James Clark
|
|
;; Keywords: wp, hypermedia, languages, XML, RelaxNG
|
|
|
|
;; This file is part of GNU Emacs.
|
|
|
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
;; (at your option) any later version.
|
|
|
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
;;; Commentary:
|
|
|
|
;; This parses a RELAX NG Compact Syntax schema into the form
|
|
;; specified in rng-pttrn.el.
|
|
;;
|
|
;; RELAX NG Compact Syntax is specified by
|
|
;; https://relaxng.org/compact.html
|
|
;;
|
|
;; This file uses the prefix "rng-c-".
|
|
|
|
;;; Code:
|
|
|
|
(require 'nxml-util)
|
|
(require 'rng-util)
|
|
(require 'rng-uri)
|
|
(require 'rng-pttrn)
|
|
|
|
;;;###autoload
|
|
(defun rng-c-load-schema (filename)
|
|
"Load a schema in RELAX NG compact syntax from FILENAME.
|
|
Return a pattern."
|
|
(rng-c-parse-file filename))
|
|
|
|
;;; Error handling
|
|
|
|
(define-error 'rng-c-incorrect-schema
|
|
"Incorrect schema" '(rng-error nxml-file-parse-error))
|
|
|
|
(defun rng-c-signal-incorrect-schema (filename pos message)
|
|
(nxml-signal-file-parse-error filename
|
|
pos
|
|
message
|
|
'rng-c-incorrect-schema))
|
|
|
|
;;; Lexing
|
|
|
|
(defconst rng-c-keywords
|
|
'("attribute"
|
|
"default"
|
|
"datatypes"
|
|
"div"
|
|
"element"
|
|
"empty"
|
|
"external"
|
|
"grammar"
|
|
"include"
|
|
"inherit"
|
|
"list"
|
|
"mixed"
|
|
"namespace"
|
|
"notAllowed"
|
|
"parent"
|
|
"start"
|
|
"string"
|
|
"text"
|
|
"token")
|
|
"List of strings that are keywords in the compact syntax.")
|
|
|
|
(defconst rng-c-anchored-keyword-re
|
|
(concat "\\`\\(" (regexp-opt rng-c-keywords) "\\)\\'")
|
|
"Regular expression to match a keyword in the compact syntax.")
|
|
|
|
(defvar rng-c-syntax-table nil
|
|
"Syntax table for parsing the compact syntax.")
|
|
|
|
(if rng-c-syntax-table
|
|
()
|
|
(setq rng-c-syntax-table (make-syntax-table))
|
|
(modify-syntax-entry ?# "<" rng-c-syntax-table)
|
|
(modify-syntax-entry ?\n ">" rng-c-syntax-table)
|
|
(modify-syntax-entry ?- "w" rng-c-syntax-table)
|
|
(modify-syntax-entry ?. "w" rng-c-syntax-table)
|
|
(modify-syntax-entry ?_ "w" rng-c-syntax-table)
|
|
(modify-syntax-entry ?: "_" rng-c-syntax-table))
|
|
|
|
(defconst rng-c-literal-1-re
|
|
"'\\(''\\([^']\\|'[^']\\|''[^']\\)*''\\|[^'\n]*\\)'"
|
|
"Regular expression to match a single-quoted literal.")
|
|
|
|
(defconst rng-c-literal-2-re
|
|
(string-replace "'" "\"" rng-c-literal-1-re)
|
|
"Regular expression to match a double-quoted literal.")
|
|
|
|
(defconst rng-c-ncname-re "\\w+")
|
|
|
|
(defconst rng-c-anchored-ncname-re
|
|
(concat "\\`" rng-c-ncname-re "\\'"))
|
|
|
|
(defconst rng-c-token-re
|
|
(concat "[&|]=" "\\|"
|
|
"[][()|&,*+?{}~=-]" "\\|"
|
|
rng-c-literal-1-re "\\|"
|
|
rng-c-literal-2-re "\\|"
|
|
rng-c-ncname-re "\\(:\\(\\*\\|" rng-c-ncname-re "\\)\\)?" "\\|"
|
|
"\\\\" rng-c-ncname-re "\\|"
|
|
">>")
|
|
"Regular expression to match a token in the compact syntax.")
|
|
|
|
(defun rng-c-init-buffer ()
|
|
(setq case-fold-search nil) ; automatically becomes buffer-local when set
|
|
(set-buffer-multibyte t)
|
|
(set-syntax-table rng-c-syntax-table))
|
|
|
|
(defvar-local rng-c-current-token nil)
|
|
|
|
(defun rng-c-advance ()
|
|
(cond ((looking-at rng-c-token-re)
|
|
(setq rng-c-current-token (match-string 0))
|
|
(goto-char (match-end 0))
|
|
(forward-comment (point-max)))
|
|
((= (point) (point-max))
|
|
(setq rng-c-current-token ""))
|
|
(t (rng-c-error "Invalid token"))))
|
|
|
|
(defconst rng-c-anchored-datatype-name-re
|
|
(concat "\\`" rng-c-ncname-re ":" rng-c-ncname-re "\\'"))
|
|
|
|
(defsubst rng-c-current-token-keyword-p ()
|
|
(string-match rng-c-anchored-keyword-re rng-c-current-token))
|
|
|
|
(defsubst rng-c-current-token-prefixed-name-p ()
|
|
(string-match rng-c-anchored-datatype-name-re rng-c-current-token))
|
|
|
|
(defsubst rng-c-current-token-literal-p ()
|
|
(string-match "\\`['\"]" rng-c-current-token))
|
|
|
|
(defsubst rng-c-current-token-quoted-identifier-p ()
|
|
(string-match "\\`\\\\" rng-c-current-token))
|
|
|
|
(defsubst rng-c-current-token-ncname-p ()
|
|
(string-match rng-c-anchored-ncname-re rng-c-current-token))
|
|
|
|
(defsubst rng-c-current-token-ns-name-p ()
|
|
(let ((len (length rng-c-current-token)))
|
|
(and (> len 0)
|
|
(= (aref rng-c-current-token (- len 1)) ?*))))
|
|
|
|
;;; Namespaces
|
|
|
|
(defvar rng-c-inherit-namespace nil)
|
|
|
|
(defvar rng-c-default-namespace nil)
|
|
|
|
(defvar rng-c-default-namespace-declared nil)
|
|
|
|
(defvar rng-c-namespace-decls nil
|
|
"Alist of namespace declarations.")
|
|
|
|
(defconst rng-c-no-namespace nil)
|
|
|
|
(defun rng-c-declare-standard-namespaces ()
|
|
(setq rng-c-namespace-decls
|
|
(cons (cons "xml" nxml-xml-namespace-uri)
|
|
rng-c-namespace-decls))
|
|
(when (and (not rng-c-default-namespace-declared)
|
|
rng-c-inherit-namespace)
|
|
(setq rng-c-default-namespace rng-c-inherit-namespace)))
|
|
|
|
(defun rng-c-expand-name (prefixed-name)
|
|
(let ((i (string-search ":" prefixed-name)))
|
|
(rng-make-name (rng-c-lookup-prefix (substring prefixed-name
|
|
0
|
|
i))
|
|
(substring prefixed-name (+ i 1)))))
|
|
|
|
(defun rng-c-lookup-prefix (prefix)
|
|
(let ((binding (assoc prefix rng-c-namespace-decls)))
|
|
(or binding (rng-c-error "Undefined prefix %s" prefix))
|
|
(cdr binding)))
|
|
|
|
(defun rng-c-unqualified-namespace (attribute)
|
|
(if attribute
|
|
rng-c-no-namespace
|
|
rng-c-default-namespace))
|
|
|
|
(defun rng-c-make-context ()
|
|
(cons rng-c-default-namespace rng-c-namespace-decls))
|
|
|
|
;;; Datatypes
|
|
|
|
(defconst rng-string-datatype
|
|
(rng-make-datatype rng-builtin-datatypes-uri "string"))
|
|
|
|
(defconst rng-token-datatype
|
|
(rng-make-datatype rng-builtin-datatypes-uri "token"))
|
|
|
|
(defvar rng-c-datatype-decls nil
|
|
"Alist of datatype declarations.
|
|
Contains a list of pairs (PREFIX . URI) where PREFIX is a string
|
|
and URI is a symbol.")
|
|
|
|
(defun rng-c-declare-standard-datatypes ()
|
|
(setq rng-c-datatype-decls
|
|
(cons (cons "xsd" rng-xsd-datatypes-uri)
|
|
rng-c-datatype-decls)))
|
|
|
|
(defun rng-c-lookup-datatype-prefix (prefix)
|
|
(let ((binding (assoc prefix rng-c-datatype-decls)))
|
|
(or binding (rng-c-error "Undefined prefix %s" prefix))
|
|
(cdr binding)))
|
|
|
|
(defun rng-c-expand-datatype (prefixed-name)
|
|
(let ((i (string-search ":" prefixed-name)))
|
|
(rng-make-datatype
|
|
(rng-c-lookup-datatype-prefix (substring prefixed-name 0 i))
|
|
(substring prefixed-name (+ i 1)))))
|
|
|
|
;;; Grammars
|
|
|
|
(defvar rng-c-current-grammar nil)
|
|
(defvar rng-c-parent-grammar nil)
|
|
|
|
(defun rng-c-make-grammar ()
|
|
(make-hash-table :test 'equal))
|
|
|
|
(defconst rng-c-about-override-slot 0)
|
|
(defconst rng-c-about-combine-slot 1)
|
|
|
|
(defun rng-c-lookup-create (name grammar)
|
|
"Return a def object for NAME.
|
|
A def object is a pair \(ABOUT . REF) where REF is returned by
|
|
`rng-make-ref'.
|
|
ABOUT is a two-element vector [OVERRIDE COMBINE].
|
|
COMBINE is either nil, choice or interleave.
|
|
OVERRIDE is either nil, require or t."
|
|
(let ((def (gethash name grammar)))
|
|
(if def
|
|
def
|
|
(progn
|
|
(setq def (cons (vector nil nil) (rng-make-ref name)))
|
|
(puthash name def grammar)
|
|
def))))
|
|
|
|
(defun rng-c-make-ref (name)
|
|
(or rng-c-current-grammar
|
|
(rng-c-error "Reference not in a grammar"))
|
|
(cdr (rng-c-lookup-create name rng-c-current-grammar)))
|
|
|
|
(defun rng-c-make-parent-ref (name)
|
|
(or rng-c-parent-grammar
|
|
(rng-c-error "Reference to non-existent parent grammar"))
|
|
(cdr (rng-c-lookup-create name rng-c-parent-grammar)))
|
|
|
|
(defvar rng-c-overrides nil
|
|
"Contains a list of (NAME . DEF) pairs.")
|
|
|
|
(defun rng-c-merge-combine (def combine name)
|
|
(let* ((about (car def))
|
|
(current-combine (aref about rng-c-about-combine-slot)))
|
|
(if combine
|
|
(if current-combine
|
|
(or (eq combine current-combine)
|
|
(rng-c-error "Inconsistent combine for %s" name))
|
|
(aset about rng-c-about-combine-slot combine))
|
|
current-combine)))
|
|
|
|
(defun rng-c-prepare-define (name combine in-include)
|
|
(let* ((def (rng-c-lookup-create name rng-c-current-grammar))
|
|
(about (car def))
|
|
(overridden (aref about rng-c-about-override-slot)))
|
|
(and in-include
|
|
(setq rng-c-overrides (cons (cons name def) rng-c-overrides)))
|
|
(cond (overridden (and (eq overridden 'require)
|
|
(aset about rng-c-about-override-slot t))
|
|
nil)
|
|
(t (setq combine (rng-c-merge-combine def combine name))
|
|
(and (rng-ref-get (cdr def))
|
|
(not combine)
|
|
(rng-c-error "Duplicate definition of %s" name))
|
|
def))))
|
|
|
|
(defun rng-c-start-include (overrides)
|
|
(mapcar (lambda (name-def)
|
|
(let* ((def (cdr name-def))
|
|
(about (car def))
|
|
(save (aref about rng-c-about-override-slot)))
|
|
(aset about rng-c-about-override-slot 'require)
|
|
(cons save name-def)))
|
|
overrides))
|
|
|
|
(defun rng-c-end-include (overrides)
|
|
(mapcar (lambda (o)
|
|
(let* ((saved (car o))
|
|
(name-def (cdr o))
|
|
(name (car name-def))
|
|
(def (cdr name-def))
|
|
(about (car def)))
|
|
(and (eq (aref about rng-c-about-override-slot) 'require)
|
|
(rng-c-error "Definition of %s in include did not override definition in included file" name))
|
|
(aset about rng-c-about-override-slot saved)))
|
|
overrides))
|
|
|
|
(defun rng-c-define (def value)
|
|
(and def
|
|
(let ((current-value (rng-ref-get (cdr def))))
|
|
(rng-ref-set (cdr def)
|
|
(if current-value
|
|
(if (eq (aref (car def) rng-c-about-combine-slot)
|
|
'choice)
|
|
(rng-make-choice (list current-value value))
|
|
(rng-make-interleave (list current-value value)))
|
|
value)))))
|
|
|
|
(defun rng-c-finish-grammar ()
|
|
(maphash (lambda (key def)
|
|
(or (rng-ref-get (cdr def))
|
|
(rng-c-error "Reference to undefined pattern %s" key)))
|
|
rng-c-current-grammar)
|
|
(rng-ref-get (cdr (or (gethash 'start rng-c-current-grammar)
|
|
(rng-c-error "No definition of start")))))
|
|
|
|
;;; Parsing
|
|
|
|
(defvar-local rng-c-escape-positions nil)
|
|
|
|
(defvar-local rng-c-file-name nil)
|
|
|
|
(defvar rng-c-file-index nil)
|
|
|
|
(defun rng-c-parse-file (filename &optional context)
|
|
(with-current-buffer (get-buffer-create (rng-c-buffer-name context))
|
|
(erase-buffer)
|
|
(rng-c-init-buffer)
|
|
(setq rng-c-file-name
|
|
(car (insert-file-contents filename)))
|
|
(setq rng-c-escape-positions nil)
|
|
(rng-c-process-escapes)
|
|
(rng-c-parse-top-level context)))
|
|
|
|
(defun rng-c-buffer-name (context)
|
|
(concat " *RNC Input"
|
|
(if context
|
|
(concat "<"
|
|
(number-to-string (setq rng-c-file-index
|
|
(1+ rng-c-file-index)))
|
|
">*")
|
|
(setq rng-c-file-index 1)
|
|
"*")))
|
|
|
|
(defun rng-c-process-escapes ()
|
|
;; Check for any NULs, since we will use NUL chars
|
|
;; for internal purposes.
|
|
(let ((pos (search-forward "\C-@" nil t)))
|
|
(and pos
|
|
(rng-c-error "Nul character found (binary file?)")))
|
|
(let ((offset 0))
|
|
(while (re-search-forward "\\\\x+{\\([[:xdigit:]]+\\)}"
|
|
(point-max)
|
|
t)
|
|
(let* ((ch (decode-char 'ucs (string-to-number (match-string 1) 16))))
|
|
(if (and ch (> ch 0))
|
|
(let ((begin (match-beginning 0))
|
|
(end (match-end 0)))
|
|
(delete-region begin end)
|
|
;; Represent an escaped newline by nul, so
|
|
;; that we can distinguish it from a literal newline.
|
|
;; We will translate it back into a real newline later.
|
|
(insert (if (eq ch ?\n) 0 ch))
|
|
(setq offset (+ offset (- end begin 1)))
|
|
(setq rng-c-escape-positions
|
|
(cons (cons (point) offset)
|
|
rng-c-escape-positions)))
|
|
(rng-c-error "Invalid character escape")))))
|
|
(goto-char 1))
|
|
|
|
(defun rng-c-translate-position (pos)
|
|
(let ((tem rng-c-escape-positions))
|
|
(while (and tem
|
|
(> (caar tem) pos))
|
|
(setq tem (cdr tem)))
|
|
(if tem
|
|
(+ pos (cdar tem))
|
|
pos)))
|
|
|
|
(defun rng-c-error (&rest args)
|
|
(rng-c-signal-incorrect-schema rng-c-file-name
|
|
(rng-c-translate-position (point))
|
|
(apply #'format-message args)))
|
|
|
|
(defun rng-c-parse-top-level (context)
|
|
(let ((rng-c-namespace-decls nil)
|
|
(rng-c-default-namespace nil)
|
|
(rng-c-datatype-decls nil))
|
|
(goto-char (point-min))
|
|
(forward-comment (point-max))
|
|
(rng-c-advance)
|
|
(rng-c-parse-decls)
|
|
(let ((p (if (eq context 'include)
|
|
(if (rng-c-implicit-grammar-p)
|
|
(rng-c-parse-grammar-body "")
|
|
(rng-c-parse-included-grammar))
|
|
(if (rng-c-implicit-grammar-p)
|
|
(rng-c-parse-implicit-grammar)
|
|
(rng-c-parse-pattern)))))
|
|
(or (string-equal rng-c-current-token "")
|
|
(rng-c-error "Unexpected characters after pattern"))
|
|
p)))
|
|
|
|
(defun rng-c-parse-included-grammar ()
|
|
(or (string-equal rng-c-current-token "grammar")
|
|
(rng-c-error "Included schema is not a grammar"))
|
|
(rng-c-advance)
|
|
(rng-c-expect "{")
|
|
(rng-c-parse-grammar-body "}"))
|
|
|
|
(defun rng-c-implicit-grammar-p ()
|
|
(or (and (or (rng-c-current-token-prefixed-name-p)
|
|
(rng-c-current-token-quoted-identifier-p)
|
|
(and (rng-c-current-token-ncname-p)
|
|
(not (rng-c-current-token-keyword-p))))
|
|
(looking-at "\\["))
|
|
(and (string-equal rng-c-current-token "[")
|
|
(rng-c-parse-lead-annotation)
|
|
nil)
|
|
(member rng-c-current-token '("div" "include" ""))
|
|
(looking-at "[|&]?=")))
|
|
|
|
(defun rng-c-parse-decls ()
|
|
(setq rng-c-default-namespace-declared nil)
|
|
(while (progn
|
|
(let ((binding
|
|
(assoc rng-c-current-token
|
|
'(("namespace" . rng-c-parse-namespace)
|
|
("datatypes" . rng-c-parse-datatypes)
|
|
("default" . rng-c-parse-default)))))
|
|
(if binding
|
|
(progn
|
|
(rng-c-advance)
|
|
(funcall (cdr binding))
|
|
t)
|
|
nil))))
|
|
(rng-c-declare-standard-datatypes)
|
|
(rng-c-declare-standard-namespaces))
|
|
|
|
(defun rng-c-parse-datatypes ()
|
|
(let ((prefix (rng-c-parse-identifier-or-keyword)))
|
|
(or (not (assoc prefix rng-c-datatype-decls))
|
|
(rng-c-error "Duplicate datatypes declaration for prefix %s" prefix))
|
|
(rng-c-expect "=")
|
|
(setq rng-c-datatype-decls
|
|
(cons (cons prefix
|
|
(rng-make-datatypes-uri (rng-c-parse-literal)))
|
|
rng-c-datatype-decls))))
|
|
|
|
(defun rng-c-parse-namespace ()
|
|
(rng-c-declare-namespace nil
|
|
(rng-c-parse-identifier-or-keyword)))
|
|
|
|
(defun rng-c-parse-default ()
|
|
(rng-c-expect "namespace")
|
|
(rng-c-declare-namespace t
|
|
(if (string-equal rng-c-current-token "=")
|
|
nil
|
|
(rng-c-parse-identifier-or-keyword))))
|
|
|
|
(defun rng-c-declare-namespace (declare-default prefix)
|
|
(rng-c-expect "=")
|
|
(let ((ns (cond ((string-equal rng-c-current-token "inherit")
|
|
(rng-c-advance)
|
|
rng-c-inherit-namespace)
|
|
(t
|
|
(nxml-make-namespace (rng-c-parse-literal))))))
|
|
(and prefix
|
|
(or (not (assoc prefix rng-c-namespace-decls))
|
|
(rng-c-error "Duplicate namespace declaration for prefix %s"
|
|
prefix))
|
|
(setq rng-c-namespace-decls
|
|
(cons (cons prefix ns) rng-c-namespace-decls)))
|
|
(and declare-default
|
|
(or (not rng-c-default-namespace-declared)
|
|
(rng-c-error "Duplicate default namespace declaration"))
|
|
(setq rng-c-default-namespace-declared t)
|
|
(setq rng-c-default-namespace ns))))
|
|
|
|
(defun rng-c-parse-implicit-grammar ()
|
|
(let* ((rng-c-parent-grammar rng-c-current-grammar)
|
|
(rng-c-current-grammar (rng-c-make-grammar)))
|
|
(rng-c-parse-grammar-body "")
|
|
(rng-c-finish-grammar)))
|
|
|
|
(defun rng-c-parse-grammar-body (close-token &optional in-include)
|
|
(while (not (string-equal rng-c-current-token close-token))
|
|
(cond ((rng-c-current-token-keyword-p)
|
|
(let ((kw (intern rng-c-current-token)))
|
|
(cond ((eq kw 'start)
|
|
(rng-c-parse-define 'start in-include))
|
|
((eq kw 'div)
|
|
(rng-c-advance)
|
|
(rng-c-parse-div in-include))
|
|
((eq kw 'include)
|
|
(and in-include
|
|
(rng-c-error "Nested include"))
|
|
(rng-c-advance)
|
|
(rng-c-parse-include))
|
|
(t (rng-c-error "Invalid grammar keyword")))))
|
|
((rng-c-current-token-ncname-p)
|
|
(if (looking-at "\\[")
|
|
(rng-c-parse-annotation-element)
|
|
(rng-c-parse-define rng-c-current-token
|
|
in-include)))
|
|
((rng-c-current-token-quoted-identifier-p)
|
|
(if (looking-at "\\[")
|
|
(rng-c-parse-annotation-element)
|
|
(rng-c-parse-define (substring rng-c-current-token 1)
|
|
in-include)))
|
|
((rng-c-current-token-prefixed-name-p)
|
|
(rng-c-parse-annotation-element))
|
|
((string-equal rng-c-current-token "[")
|
|
(rng-c-parse-lead-annotation)
|
|
(and (string-equal rng-c-current-token close-token)
|
|
(rng-c-error "Missing annotation subject"))
|
|
(and (looking-at "\\[")
|
|
(rng-c-error "Leading annotation applied to annotation")))
|
|
(t (rng-c-error "Invalid grammar content"))))
|
|
(or (string-equal rng-c-current-token "")
|
|
(rng-c-advance)))
|
|
|
|
(defun rng-c-parse-div (in-include)
|
|
(rng-c-expect "{")
|
|
(rng-c-parse-grammar-body "}" in-include))
|
|
|
|
(defun rng-c-parse-include ()
|
|
(let* ((filename (rng-c-expand-file (rng-c-parse-literal)))
|
|
(rng-c-inherit-namespace (rng-c-parse-opt-inherit))
|
|
overrides)
|
|
(cond ((string-equal rng-c-current-token "{")
|
|
(rng-c-advance)
|
|
(let ((rng-c-overrides nil))
|
|
(rng-c-parse-grammar-body "}" t)
|
|
(setq overrides rng-c-overrides))
|
|
(setq overrides (rng-c-start-include overrides))
|
|
(rng-c-parse-file filename 'include)
|
|
(rng-c-end-include overrides))
|
|
(t (rng-c-parse-file filename 'include)))))
|
|
|
|
(defun rng-c-parse-define (name in-include)
|
|
(rng-c-advance)
|
|
(let ((assign (assoc rng-c-current-token
|
|
'(("=" . nil)
|
|
("|=" . choice)
|
|
("&=" . interleave)))))
|
|
(or assign
|
|
(rng-c-error "Expected assignment operator"))
|
|
(rng-c-advance)
|
|
(let ((ref (rng-c-prepare-define name (cdr assign) in-include)))
|
|
(rng-c-define ref (rng-c-parse-pattern)))))
|
|
|
|
(defvar rng-c-had-except nil)
|
|
|
|
(defun rng-c-parse-pattern ()
|
|
(let* ((rng-c-had-except nil)
|
|
(p (rng-c-parse-repeated))
|
|
(op (assoc rng-c-current-token
|
|
'(("|" . rng-make-choice)
|
|
("," . rng-make-group)
|
|
("&" . rng-make-interleave)))))
|
|
(if op
|
|
(if rng-c-had-except
|
|
(rng-c-error "Parentheses required around pattern using -")
|
|
(let* ((patterns (cons p nil))
|
|
(tail patterns)
|
|
(connector rng-c-current-token))
|
|
(while (progn
|
|
(rng-c-advance)
|
|
(let ((newcdr (cons (rng-c-parse-repeated) nil)))
|
|
(setcdr tail newcdr)
|
|
(setq tail newcdr))
|
|
(string-equal rng-c-current-token connector)))
|
|
(funcall (cdr op) patterns)))
|
|
p)))
|
|
|
|
(defun rng-c-parse-repeated ()
|
|
(let ((p (rng-c-parse-follow-annotations
|
|
(rng-c-parse-primary)))
|
|
(op (assoc rng-c-current-token
|
|
'(("*" . rng-make-zero-or-more)
|
|
("+" . rng-make-one-or-more)
|
|
("?" . rng-make-optional)))))
|
|
(if op
|
|
(if rng-c-had-except
|
|
(rng-c-error "Parentheses required around pattern using -")
|
|
(rng-c-parse-follow-annotations
|
|
(progn
|
|
(rng-c-advance)
|
|
(funcall (cdr op) p))))
|
|
p)))
|
|
|
|
(defun rng-c-parse-primary ()
|
|
"Parse a primary expression.
|
|
The current token must be the first token of the expression.
|
|
After parsing the current token should be the token following
|
|
the primary expression."
|
|
(cond ((rng-c-current-token-keyword-p)
|
|
(let ((parse-function (get (intern rng-c-current-token)
|
|
'rng-c-pattern)))
|
|
(or parse-function
|
|
(rng-c-error "Keyword %s does not introduce a pattern"
|
|
rng-c-current-token))
|
|
(rng-c-advance)
|
|
(funcall parse-function)))
|
|
((rng-c-current-token-ncname-p)
|
|
(rng-c-advance-with (rng-c-make-ref rng-c-current-token)))
|
|
((string-equal rng-c-current-token "(")
|
|
(rng-c-advance)
|
|
(let ((p (rng-c-parse-pattern)))
|
|
(rng-c-expect ")")
|
|
p))
|
|
((rng-c-current-token-prefixed-name-p)
|
|
(let ((name (rng-c-expand-datatype rng-c-current-token)))
|
|
(rng-c-advance)
|
|
(rng-c-parse-data name)))
|
|
((rng-c-current-token-literal-p)
|
|
(rng-make-value rng-token-datatype (rng-c-parse-literal) nil))
|
|
((rng-c-current-token-quoted-identifier-p)
|
|
(rng-c-advance-with
|
|
(rng-c-make-ref (substring rng-c-current-token 1))))
|
|
((string-equal rng-c-current-token "[")
|
|
(rng-c-parse-lead-annotation)
|
|
(rng-c-parse-primary))
|
|
(t (rng-c-error "Invalid pattern"))))
|
|
|
|
(defun rng-c-parse-parent ()
|
|
(and (rng-c-current-token-keyword-p)
|
|
(rng-c-error "Keyword following parent was not quoted"
|
|
rng-c-current-token))
|
|
(rng-c-make-parent-ref (rng-c-parse-identifier-or-keyword)))
|
|
|
|
(defun rng-c-parse-literal ()
|
|
(rng-c-fix-escaped-newlines
|
|
(apply 'concat (rng-c-parse-literal-segments))))
|
|
|
|
(defun rng-c-parse-literal-segments ()
|
|
(let ((str (rng-c-parse-literal-segment)))
|
|
(cons str
|
|
(cond ((string-equal rng-c-current-token "~")
|
|
(rng-c-advance)
|
|
(rng-c-parse-literal-segments))
|
|
(t nil)))))
|
|
|
|
(defun rng-c-parse-literal-segment ()
|
|
(or (rng-c-current-token-literal-p)
|
|
(rng-c-error "Expected a literal"))
|
|
(rng-c-advance-with
|
|
(let ((n (if (and (>= (length rng-c-current-token) 6)
|
|
(eq (aref rng-c-current-token 0)
|
|
(aref rng-c-current-token 1)))
|
|
3
|
|
1)))
|
|
(substring rng-c-current-token n (- n)))))
|
|
|
|
(defun rng-c-fix-escaped-newlines (str)
|
|
(subst-char-in-string ?\C-@ ?\n str))
|
|
|
|
(defun rng-c-parse-identifier-or-keyword ()
|
|
(cond ((rng-c-current-token-ncname-p)
|
|
(rng-c-advance-with rng-c-current-token))
|
|
((rng-c-current-token-quoted-identifier-p)
|
|
(rng-c-advance-with (substring rng-c-current-token 1)))
|
|
(t (rng-c-error "Expected identifier or keyword"))))
|
|
|
|
(put 'string 'rng-c-pattern 'rng-c-parse-string)
|
|
(put 'token 'rng-c-pattern 'rng-c-parse-token)
|
|
(put 'element 'rng-c-pattern 'rng-c-parse-element)
|
|
(put 'attribute 'rng-c-pattern 'rng-c-parse-attribute)
|
|
(put 'list 'rng-c-pattern 'rng-c-parse-list)
|
|
(put 'mixed 'rng-c-pattern 'rng-c-parse-mixed)
|
|
(put 'text 'rng-c-pattern 'rng-c-parse-text)
|
|
(put 'empty 'rng-c-pattern 'rng-c-parse-empty)
|
|
(put 'notAllowed 'rng-c-pattern 'rng-c-parse-not-allowed)
|
|
(put 'grammar 'rng-c-pattern 'rng-c-parse-grammar)
|
|
(put 'parent 'rng-c-pattern 'rng-c-parse-parent)
|
|
(put 'external 'rng-c-pattern 'rng-c-parse-external)
|
|
|
|
(defun rng-c-parse-element ()
|
|
(let ((name-class (rng-c-parse-name-class nil)))
|
|
(rng-c-expect "{")
|
|
(let ((pattern (rng-c-parse-pattern)))
|
|
(rng-c-expect "}")
|
|
(rng-make-element name-class pattern))))
|
|
|
|
(defun rng-c-parse-attribute ()
|
|
(let ((name-class (rng-c-parse-name-class 'attribute)))
|
|
(rng-c-expect "{")
|
|
(let ((pattern (rng-c-parse-pattern)))
|
|
(rng-c-expect "}")
|
|
(rng-make-attribute name-class pattern))))
|
|
|
|
(defun rng-c-parse-name-class (attribute)
|
|
(let* ((rng-c-had-except nil)
|
|
(name-class
|
|
(rng-c-parse-follow-annotations
|
|
(rng-c-parse-primary-name-class attribute))))
|
|
(if (string-equal rng-c-current-token "|")
|
|
(let* ((name-classes (cons name-class nil))
|
|
(tail name-classes))
|
|
(or (not rng-c-had-except)
|
|
(rng-c-error "Parentheses required around name-class using - operator"))
|
|
(while (progn
|
|
(rng-c-advance)
|
|
(let ((newcdr
|
|
(cons (rng-c-parse-follow-annotations
|
|
(rng-c-parse-primary-name-class attribute))
|
|
nil)))
|
|
(setcdr tail newcdr)
|
|
(setq tail newcdr))
|
|
(string-equal rng-c-current-token "|")))
|
|
(rng-make-choice-name-class name-classes))
|
|
name-class)))
|
|
|
|
(defun rng-c-parse-primary-name-class (attribute)
|
|
(cond ((rng-c-current-token-ncname-p)
|
|
(rng-c-advance-with
|
|
(rng-make-name-name-class
|
|
(rng-make-name (rng-c-unqualified-namespace attribute)
|
|
rng-c-current-token))))
|
|
((rng-c-current-token-prefixed-name-p)
|
|
(rng-c-advance-with
|
|
(rng-make-name-name-class
|
|
(rng-c-expand-name rng-c-current-token))))
|
|
((string-equal rng-c-current-token "*")
|
|
(let ((except (rng-c-parse-opt-except-name-class attribute)))
|
|
(if except
|
|
(rng-make-any-name-except-name-class except)
|
|
(rng-make-any-name-name-class))))
|
|
((rng-c-current-token-ns-name-p)
|
|
(let* ((ns
|
|
(rng-c-lookup-prefix (substring rng-c-current-token
|
|
0
|
|
-2)))
|
|
(except (rng-c-parse-opt-except-name-class attribute)))
|
|
(if except
|
|
(rng-make-ns-name-except-name-class ns except)
|
|
(rng-make-ns-name-name-class ns))))
|
|
((string-equal rng-c-current-token "(")
|
|
(rng-c-advance)
|
|
(let ((name-class (rng-c-parse-name-class attribute)))
|
|
(rng-c-expect ")")
|
|
name-class))
|
|
((rng-c-current-token-quoted-identifier-p)
|
|
(rng-c-advance-with
|
|
(rng-make-name-name-class
|
|
(rng-make-name (rng-c-unqualified-namespace attribute)
|
|
(substring rng-c-current-token 1)))))
|
|
((string-equal rng-c-current-token "[")
|
|
(rng-c-parse-lead-annotation)
|
|
(rng-c-parse-primary-name-class attribute))
|
|
(t (rng-c-error "Bad name class"))))
|
|
|
|
(defun rng-c-parse-opt-except-name-class (attribute)
|
|
(rng-c-advance)
|
|
(and (string-equal rng-c-current-token "-")
|
|
(or (not rng-c-had-except)
|
|
(rng-c-error "Parentheses required around name-class using - operator"))
|
|
(setq rng-c-had-except t)
|
|
(progn
|
|
(rng-c-advance)
|
|
(rng-c-parse-primary-name-class attribute))))
|
|
|
|
(defun rng-c-parse-mixed ()
|
|
(rng-c-expect "{")
|
|
(let ((pattern (rng-make-mixed (rng-c-parse-pattern))))
|
|
(rng-c-expect "}")
|
|
pattern))
|
|
|
|
(defun rng-c-parse-list ()
|
|
(rng-c-expect "{")
|
|
(let ((pattern (rng-make-list (rng-c-parse-pattern))))
|
|
(rng-c-expect "}")
|
|
pattern))
|
|
|
|
(defun rng-c-parse-text ()
|
|
(rng-make-text))
|
|
|
|
(defun rng-c-parse-empty ()
|
|
(rng-make-empty))
|
|
|
|
(defun rng-c-parse-not-allowed ()
|
|
(rng-make-not-allowed))
|
|
|
|
(defun rng-c-parse-string ()
|
|
(rng-c-parse-data rng-string-datatype))
|
|
|
|
(defun rng-c-parse-token ()
|
|
(rng-c-parse-data rng-token-datatype))
|
|
|
|
(defun rng-c-parse-data (name)
|
|
(if (rng-c-current-token-literal-p)
|
|
(rng-make-value name
|
|
(rng-c-parse-literal)
|
|
(and (car name)
|
|
(rng-c-make-context)))
|
|
(let ((params (rng-c-parse-optional-params)))
|
|
(if (string-equal rng-c-current-token "-")
|
|
(progn
|
|
(if rng-c-had-except
|
|
(rng-c-error "Parentheses required around pattern using -")
|
|
(setq rng-c-had-except t))
|
|
(rng-c-advance)
|
|
(rng-make-data-except name
|
|
params
|
|
(rng-c-parse-primary)))
|
|
(rng-make-data name params)))))
|
|
|
|
(defun rng-c-parse-optional-params ()
|
|
(and (string-equal rng-c-current-token "{")
|
|
(let* ((head (cons nil nil))
|
|
(tail head))
|
|
(rng-c-advance)
|
|
(while (not (string-equal rng-c-current-token "}"))
|
|
(and (string-equal rng-c-current-token "[")
|
|
(rng-c-parse-lead-annotation))
|
|
(let ((name (rng-c-parse-identifier-or-keyword)))
|
|
(rng-c-expect "=")
|
|
(let ((newcdr (cons (cons (intern name)
|
|
(rng-c-parse-literal))
|
|
nil)))
|
|
(setcdr tail newcdr)
|
|
(setq tail newcdr))))
|
|
(rng-c-advance)
|
|
(cdr head))))
|
|
|
|
(defun rng-c-parse-external ()
|
|
(let* ((filename (rng-c-expand-file (rng-c-parse-literal)))
|
|
(rng-c-inherit-namespace (rng-c-parse-opt-inherit)))
|
|
(rng-c-parse-file filename 'external)))
|
|
|
|
(defun rng-c-expand-file (uri)
|
|
(condition-case err
|
|
(rng-uri-file-name (rng-uri-resolve uri
|
|
(rng-file-name-uri rng-c-file-name)))
|
|
(rng-uri-error
|
|
(rng-c-error (cadr err)))))
|
|
|
|
(defun rng-c-parse-opt-inherit ()
|
|
(cond ((string-equal rng-c-current-token "inherit")
|
|
(rng-c-advance)
|
|
(rng-c-expect "=")
|
|
(rng-c-lookup-prefix (rng-c-parse-identifier-or-keyword)))
|
|
(t rng-c-default-namespace)))
|
|
|
|
(defun rng-c-parse-grammar ()
|
|
(rng-c-expect "{")
|
|
(let* ((rng-c-parent-grammar rng-c-current-grammar)
|
|
(rng-c-current-grammar (rng-c-make-grammar)))
|
|
(rng-c-parse-grammar-body "}")
|
|
(rng-c-finish-grammar)))
|
|
|
|
(defun rng-c-parse-lead-annotation ()
|
|
(rng-c-parse-annotation-body)
|
|
(and (string-equal rng-c-current-token "[")
|
|
(rng-c-error "Multiple leading annotations")))
|
|
|
|
(defun rng-c-parse-follow-annotations (obj)
|
|
(while (string-equal rng-c-current-token ">>")
|
|
(rng-c-advance)
|
|
(if (rng-c-current-token-prefixed-name-p)
|
|
(rng-c-advance)
|
|
(rng-c-parse-identifier-or-keyword))
|
|
(rng-c-parse-annotation-body t))
|
|
obj)
|
|
|
|
(defun rng-c-parse-annotation-element ()
|
|
(rng-c-advance)
|
|
(rng-c-parse-annotation-body t))
|
|
|
|
;; XXX need stricter checking of attribute names
|
|
;; XXX don't allow attributes after text
|
|
|
|
(defun rng-c-parse-annotation-body (&optional allow-text)
|
|
"Current token is [. Parse up to matching ].
|
|
Current token after parse is token following ]."
|
|
(or (string-equal rng-c-current-token "[")
|
|
(rng-c-error "Expected ["))
|
|
(rng-c-advance)
|
|
(while (not (string-equal rng-c-current-token "]"))
|
|
(cond ((rng-c-current-token-literal-p)
|
|
(or allow-text
|
|
(rng-c-error "Out of place text within annotation"))
|
|
(rng-c-parse-literal))
|
|
(t
|
|
(if (rng-c-current-token-prefixed-name-p)
|
|
(rng-c-advance)
|
|
(rng-c-parse-identifier-or-keyword))
|
|
(cond ((string-equal rng-c-current-token "[")
|
|
(rng-c-parse-annotation-body t))
|
|
((string-equal rng-c-current-token "=")
|
|
(rng-c-advance)
|
|
(rng-c-parse-literal))
|
|
(t (rng-c-error "Expected = or ["))))))
|
|
(rng-c-advance))
|
|
|
|
(defun rng-c-advance-with (pattern)
|
|
(rng-c-advance)
|
|
pattern)
|
|
|
|
(defun rng-c-expect (str)
|
|
(or (string-equal rng-c-current-token str)
|
|
(rng-c-error "Expected `%s' but got `%s'" str rng-c-current-token))
|
|
(rng-c-advance))
|
|
|
|
(provide 'rng-cmpct)
|
|
|
|
;;; rng-cmpct.el ends here
|