2007-10-25 16:27:34 -04:00
|
|
|
;;; Ikarus Scheme -- A compiler for R6RS Scheme.
|
|
|
|
;;; Copyright (C) 2006,2007 Abdulaziz Ghuloum
|
|
|
|
;;;
|
|
|
|
;;; This program is free software: you can redistribute it and/or modify
|
|
|
|
;;; it under the terms of the GNU General Public License version 3 as
|
|
|
|
;;; published by the Free Software Foundation.
|
|
|
|
;;;
|
|
|
|
;;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2007-08-28 21:36:34 -04:00
|
|
|
|
2007-09-13 06:27:31 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
2007-08-28 21:36:34 -04:00
|
|
|
(library (ikarus unicode-data)
|
2007-09-13 06:27:31 -04:00
|
|
|
|
|
|
|
(export
|
|
|
|
unicode-printable-char? char-downcase char-upcase
|
|
|
|
char-titlecase char-foldcase char-ci=? char-ci<? char-ci<=?
|
|
|
|
char-ci>? char-ci>=? string-ci=? string-ci<? string-ci<=?
|
|
|
|
string-ci>? string-ci>=? string-foldcase char-general-category
|
|
|
|
char-alphabetic? char-numeric? char-whitespace?
|
|
|
|
char-upper-case? char-lower-case? char-title-case? )
|
|
|
|
|
2007-08-28 21:36:34 -04:00
|
|
|
(import
|
|
|
|
(ikarus system $fx)
|
|
|
|
(ikarus system $vectors)
|
|
|
|
(ikarus system $chars)
|
|
|
|
(ikarus system $pairs)
|
|
|
|
(ikarus system $strings)
|
2007-09-13 06:27:31 -04:00
|
|
|
(except (ikarus)
|
|
|
|
char-downcase char-upcase char-titlecase char-foldcase
|
|
|
|
char-ci=? char-ci<? char-ci<=? char-ci>? char-ci>=?
|
|
|
|
string-ci=? string-ci<? string-ci<=? string-ci>?
|
|
|
|
string-ci>=? string-foldcase char-general-category
|
|
|
|
char-alphabetic? char-numeric? char-whitespace?
|
|
|
|
char-upper-case? char-lower-case? char-title-case? ))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(include "unicode/unicode-char-cases.ss")
|
2007-09-13 06:11:26 -04:00
|
|
|
(include "unicode/unicode-charinfo.ss")
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(define (binary-search n v)
|
|
|
|
(let ([k ($fx- ($vector-length v) 1)])
|
|
|
|
(let f ([i 0] [k k] [n n] [v v])
|
|
|
|
(cond
|
|
|
|
[($fx= i k) i]
|
|
|
|
[else
|
|
|
|
(let ([j ($fxsra ($fx+ i ($fx+ k 1)) 1)])
|
|
|
|
(cond
|
|
|
|
[($fx<= ($vector-ref v j) n) (f j k n v)]
|
|
|
|
[else (f i ($fx- j 1) n v)]))]))))
|
|
|
|
|
2007-09-13 06:11:26 -04:00
|
|
|
(define (lookup-char-info c)
|
2007-09-03 04:42:46 -04:00
|
|
|
(let ([v unicode-categories-lookup-vector]
|
|
|
|
[t unicode-categories-values-vector])
|
|
|
|
(define (f i k n)
|
|
|
|
(cond
|
2007-09-13 15:59:39 -04:00
|
|
|
[($fx= i k)
|
|
|
|
(let ([idx ($vector-ref t i)])
|
2007-09-03 04:42:46 -04:00
|
|
|
(if (fixnum? idx)
|
|
|
|
idx
|
2007-09-13 15:59:39 -04:00
|
|
|
(let ([idx2 ($fx- n ($vector-ref v i))])
|
|
|
|
($vector-ref idx idx2))))]
|
2007-09-03 04:42:46 -04:00
|
|
|
[else
|
2007-09-13 15:59:39 -04:00
|
|
|
(let ([j ($fxsra ($fx+ i ($fx+ k 1)) 1)])
|
2007-09-03 04:42:46 -04:00
|
|
|
(cond
|
2007-09-13 15:59:39 -04:00
|
|
|
[($fx<= ($vector-ref v j) n) (f j k n)]
|
|
|
|
[else (f i ($fx- j 1) n)]))]))
|
2007-09-13 06:11:26 -04:00
|
|
|
(f 0 (fx- (vector-length v) 1) (char->integer c))))
|
|
|
|
|
|
|
|
(define (char-general-category c)
|
|
|
|
(if (char? c)
|
|
|
|
(vector-ref unicode-categories-name-vector
|
|
|
|
(fxlogand 63 (lookup-char-info c)))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'char-general-category "not a char" c)))
|
2007-09-03 04:42:46 -04:00
|
|
|
|
2007-09-13 06:27:31 -04:00
|
|
|
(define (char-has-property? c prop-val who)
|
|
|
|
(if (char? c)
|
|
|
|
(not (fxzero? (fxlogand (lookup-char-info c) prop-val)))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error who "not a char" c)))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
2007-09-13 06:11:26 -04:00
|
|
|
(define (unicode-printable-char? c)
|
2007-09-13 06:27:31 -04:00
|
|
|
(char-has-property? c constituent-property 'unicode-printable-char?))
|
|
|
|
(define (char-alphabetic? c)
|
|
|
|
(char-has-property? c alphabetic-property 'char-alphabetic?))
|
|
|
|
(define (char-numeric? c)
|
|
|
|
(char-has-property? c numeric-property 'char-numeric?))
|
|
|
|
(define (char-whitespace? c)
|
|
|
|
(char-has-property? c whitespace-property 'char-whitespace?))
|
|
|
|
(define (char-upper-case? c)
|
|
|
|
(char-has-property? c uppercase-property 'char-upper-case?))
|
|
|
|
(define (char-lower-case? c)
|
|
|
|
(char-has-property? c lowercase-property 'char-lower-case?))
|
|
|
|
(define (char-title-case? c)
|
|
|
|
(char-has-property? c titlecase-property 'char-title-case?))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
2007-09-13 06:27:31 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
2007-08-28 21:36:34 -04:00
|
|
|
(define (convert-char x adjustment-vec)
|
|
|
|
(let ([n ($char->fixnum x)])
|
|
|
|
(let ([idx (binary-search n charcase-search-vector)])
|
|
|
|
(let ([adj ($vector-ref adjustment-vec idx)])
|
|
|
|
($fx+ adj n)))))
|
|
|
|
|
|
|
|
(define (char-downcase x)
|
|
|
|
(if (char? x)
|
|
|
|
($fixnum->char
|
|
|
|
(convert-char x char-downcase-adjustment-vector))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'char-downcase "not a character" x)))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(define (char-upcase x)
|
|
|
|
(if (char? x)
|
|
|
|
($fixnum->char
|
|
|
|
(convert-char x char-upcase-adjustment-vector))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'char-downcase "not a character" x)))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(define (char-titlecase x)
|
|
|
|
(if (char? x)
|
|
|
|
($fixnum->char
|
|
|
|
(convert-char x char-titlecase-adjustment-vector))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'char-downcase "not a character" x)))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(define (char-foldcase x)
|
|
|
|
(if (char? x)
|
|
|
|
($fixnum->char ($fold x))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'char-downcase "not a character" x)))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(define ($fold x)
|
|
|
|
(convert-char x char-foldcase-adjustment-vector))
|
|
|
|
|
2007-10-25 14:32:26 -04:00
|
|
|
(define (char-ci-loop c0 ls p? who)
|
|
|
|
(or (null? ls)
|
|
|
|
(let ([c1 (car ls)])
|
|
|
|
(unless (char? c1) (error who "not a char" c1))
|
|
|
|
(let ([c1 ($fold c1)])
|
|
|
|
(if (p? c0 c1)
|
|
|
|
(char-ci-loop c1 (cdr ls) p? who)
|
|
|
|
(let f ([ls (cdr ls)] [who who])
|
|
|
|
(cond
|
|
|
|
[(null? ls) #f]
|
|
|
|
[(char? (car ls))
|
|
|
|
(f (cdr ls) who)]
|
|
|
|
[else (error who "not a char" (car ls))])))))))
|
|
|
|
|
2007-08-28 21:36:34 -04:00
|
|
|
(define char-ci=?
|
|
|
|
(case-lambda
|
|
|
|
[(x y)
|
|
|
|
(if (char? x)
|
|
|
|
(or (eq? x y)
|
|
|
|
(if (char? y)
|
|
|
|
($fx= ($fold x) ($fold y))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'char-ci=? "not a char" y)))
|
|
|
|
(error 'char-ci=? "not a char" x))]
|
2007-08-28 21:36:34 -04:00
|
|
|
[(x)
|
2007-10-25 14:32:26 -04:00
|
|
|
(or (char? x) (error 'char-ci=? "not a char" x))]
|
|
|
|
[(x . x*)
|
|
|
|
(if (char? x)
|
|
|
|
(char-ci-loop x x* char=? 'char-ci=?)
|
|
|
|
(error 'char-ci=? "not a char" x))]))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(define char-ci<?
|
|
|
|
(case-lambda
|
|
|
|
[(x y)
|
|
|
|
(if (char? x)
|
|
|
|
(or (eq? x y)
|
|
|
|
(if (char? y)
|
|
|
|
($fx< ($fold x) ($fold y))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'char-ci<? "not a char" y)))
|
|
|
|
(error 'char-ci<? "not a char" x))]
|
2007-08-28 21:36:34 -04:00
|
|
|
[(x)
|
2007-10-25 14:32:26 -04:00
|
|
|
(or (char? x) (error 'char-ci<? "not a char" x))]
|
|
|
|
[(x . x*)
|
|
|
|
(if (char? x)
|
|
|
|
(char-ci-loop x x* char<? 'char-ci<?)
|
|
|
|
(error 'char-ci<? "not a char" x))]))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(define char-ci<=?
|
|
|
|
(case-lambda
|
|
|
|
[(x y)
|
|
|
|
(if (char? x)
|
|
|
|
(or (eq? x y)
|
|
|
|
(if (char? y)
|
|
|
|
($fx<= ($fold x) ($fold y))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'char-ci<=? "not a char" y)))
|
|
|
|
(error 'char-ci<=? "not a char" x))]
|
2007-08-28 21:36:34 -04:00
|
|
|
[(x)
|
2007-10-25 14:32:26 -04:00
|
|
|
(or (char? x) (error 'char-ci<=? "not a char" x))]
|
|
|
|
[(x . x*)
|
|
|
|
(if (char? x)
|
|
|
|
(char-ci-loop x x* char<=? 'char-ci<=?)
|
|
|
|
(error 'char-ci<=? "not a char" x))]))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(define char-ci>?
|
|
|
|
(case-lambda
|
|
|
|
[(x y)
|
|
|
|
(if (char? x)
|
|
|
|
(or (eq? x y)
|
|
|
|
(if (char? y)
|
|
|
|
($fx> ($fold x) ($fold y))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'char-ci>? "not a char" y)))
|
|
|
|
(error 'char-ci>? "not a char" x))]
|
2007-08-28 21:36:34 -04:00
|
|
|
[(x)
|
2007-10-25 14:32:26 -04:00
|
|
|
(or (char? x) (error 'char-ci>? "not a char" x))]
|
|
|
|
[(x . x*)
|
|
|
|
(if (char? x)
|
|
|
|
(char-ci-loop x x* char>? 'char-ci>?)
|
|
|
|
(error 'char-ci>? "not a char" x))]))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(define char-ci>=?
|
|
|
|
(case-lambda
|
|
|
|
[(x y)
|
|
|
|
(if (char? x)
|
|
|
|
(or (eq? x y)
|
|
|
|
(if (char? y)
|
|
|
|
($fx>= ($fold x) ($fold y))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'char-ci>=? "not a char" y)))
|
|
|
|
(error 'char-ci>=? "not a char" x))]
|
2007-08-28 21:36:34 -04:00
|
|
|
[(x)
|
2007-10-25 14:32:26 -04:00
|
|
|
(or (char? x) (error 'char-ci>=? "not a char" x))]
|
|
|
|
[(x . x*)
|
|
|
|
(if (char? x)
|
|
|
|
(char-ci-loop x x* char>=? 'char-ci>=?)
|
|
|
|
(error 'char-ci>=? "not a char" x))]))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(define ($string-foldcase str)
|
2007-12-10 07:28:03 -05:00
|
|
|
(let-values ([(p e) (open-string-output-port)])
|
|
|
|
(let f ([str str] [i 0] [n (string-length str)])
|
|
|
|
(cond
|
|
|
|
[($fx= i n) (e)]
|
|
|
|
[else
|
|
|
|
(let* ([n ($char->fixnum ($string-ref str i))])
|
|
|
|
(let ([n/ls
|
|
|
|
(vector-ref string-foldcase-adjustment-vector
|
|
|
|
(binary-search n charcase-search-vector))])
|
|
|
|
(if (fixnum? n/ls)
|
|
|
|
(write-char ($fixnum->char ($fx+ n n/ls)) p)
|
|
|
|
(let f ([ls n/ls])
|
|
|
|
(write-char ($car ls) p)
|
|
|
|
(let ([ls ($cdr ls)])
|
|
|
|
(if (pair? ls)
|
|
|
|
(f ls)
|
|
|
|
(write-char ls p)))))))
|
|
|
|
(f str ($fxadd1 i) n)]))))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
|
|
|
(define (string-foldcase str)
|
|
|
|
(if (string? str)
|
|
|
|
($string-foldcase str)
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'string-foldcase "not a string" str)))
|
2007-08-28 21:36:34 -04:00
|
|
|
|
2007-09-15 00:14:47 -04:00
|
|
|
;;; FIXME: case-insensitive comparison procedures are slow.
|
|
|
|
|
2007-09-03 00:17:15 -04:00
|
|
|
(define string-ci-cmp
|
|
|
|
(lambda (who cmp)
|
|
|
|
(case-lambda
|
|
|
|
[(s1 s2)
|
|
|
|
(if (string? s1)
|
|
|
|
(if (string? s2)
|
|
|
|
(cmp ($string-foldcase s1) ($string-foldcase s2))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error who "not a string" s2))
|
|
|
|
(error who "not a string" s1))]
|
2007-09-03 00:17:15 -04:00
|
|
|
[(s1 . s*)
|
|
|
|
(if (string? s1)
|
|
|
|
(let ([s1 ($string-foldcase s1)])
|
|
|
|
(let f ([s1 s1] [s* s*])
|
|
|
|
(cond
|
|
|
|
[(null? s*) #t]
|
|
|
|
[else
|
|
|
|
(let ([s2 (car s*)])
|
|
|
|
(if (string? s2)
|
|
|
|
(let ([s2 ($string-foldcase s2)])
|
|
|
|
(if (cmp s1 s2)
|
|
|
|
(f s2 (cdr s*))
|
|
|
|
(let f ([s* (cdr s*)])
|
|
|
|
(cond
|
|
|
|
[(null? s*) #f]
|
|
|
|
[(string? (car s*))
|
|
|
|
(f (cdr s*))]
|
|
|
|
[else
|
2007-10-25 14:32:26 -04:00
|
|
|
(error who "not a string"
|
2007-09-03 00:17:15 -04:00
|
|
|
(car s*))]))))
|
2007-10-25 14:32:26 -04:00
|
|
|
(error who "not a string" s2)))])))
|
|
|
|
(error who "not a string" s1))])))
|
2007-09-03 00:17:15 -04:00
|
|
|
|
|
|
|
|
|
|
|
(define string-ci=? (string-ci-cmp 'string-ci=? string=?))
|
|
|
|
(define string-ci<? (string-ci-cmp 'string-ci<? string<?))
|
|
|
|
(define string-ci<=? (string-ci-cmp 'string-ci<=? string<=?))
|
|
|
|
(define string-ci>? (string-ci-cmp 'string-ci>? string>?))
|
|
|
|
(define string-ci>=? (string-ci-cmp 'string-ci>=? string>=?))
|
|
|
|
|
|
|
|
|
2007-08-28 21:36:34 -04:00
|
|
|
)
|
|
|
|
|