#lang scheme/base
(require "../base.ss")
(define (quotable-literal? stx)
(define datum (syntax->datum stx))
(or (boolean? datum)
(number? datum)
(string? datum)
(bytes? datum)))
(define xml-identifier-regexp
(let* ([name-start-char (string-append ":"
"A-Z"
"_"
"a-z"
"\xC0-\xD6"
"\xD8-\xF6"
"\xF8-\u2FF"
"\u370-\u37D"
"\u37F-\u1FFF"
"\u200C-\u200D"
"\u2070-\u218F"
"\u2C00-\u2FEF"
"\u3001-\uD7FF"
"\uF900-\uFDCF"
"\uFDF0-\uFFFD"
"\U10000-\UEFFFF")]
[name-char (string-append name-start-char
"."
"0-9"
"\xB7"
"\u0300-\u036F"
"\u203F-\u2040"
"-")])
(regexp (format "^[~a][~a]*$" name-start-char name-char))))
(define (xml-identifier? stx)
(and (identifier? stx)
(regexp-match xml-identifier-regexp (symbol->string (syntax->datum stx)))
#t))
(define (xml-identifier-guard id-stx [form-stx id-stx])
(cond [(not (xml-identifier? id-stx))
(raise-syntax-error 'mirrors/xml "invalid XML identifier" form-stx (and (not (eq? id-stx form-stx)) id-stx))]
[(memq (syntax->datum id-stx)
(if (eq? (quote-case-restriction) 'lower)
lowercase-quote-symbols
uppercase-quote-symbols))
(raise-syntax-error 'mirrors/xml
(if (eq? (quote-case-restriction) 'lower)
"cannot use this identifier here (possible double quoting error): switch the surrounding quote macro to \"XML\" or another uppercase equivalent"
"cannot use this identifier here (possible double quoting error): switch the surrounding quote macro to \"xml\" or another lowercase equivalent")
form-stx
(and (not (eq? id-stx form-stx)) id-stx))]
[else #t]))
(define (identifier->string stx)
(symbol->string (syntax->datum stx)))
(provide/contract
[quotable-literal? (-> syntax? boolean?)]
[xml-identifier-regexp regexp?]
[xml-identifier? (-> syntax? boolean?)]
[xml-identifier-guard (->* (syntax?) ((or/c syntax? #f)) boolean?)]
[identifier->string (-> syntax? string?)])