]> gitweb.factorcode.org Git - factor.git/blob - basis/unicode/data/data.factor
Merge branch 'master' of git://factorcode.org/git/factor
[factor.git] / basis / unicode / data / data.factor
1 ! Copyright (C) 2008, 2009 Daniel Ehrenberg.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: combinators.short-circuit assocs math kernel sequences
4 io.files hashtables quotations splitting grouping arrays io
5 math.parser hash2 math.order byte-arrays words namespaces words
6 compiler.units parser io.encodings.ascii values interval-maps
7 ascii sets combinators locals math.ranges sorting make
8 strings.parser io.encodings.utf8 memoize ;
9 IN: unicode.data
10
11 VALUE: simple-lower
12 VALUE: simple-upper
13 VALUE: simple-title
14 VALUE: canonical-map
15 VALUE: combine-map
16 VALUE: class-map
17 VALUE: compatibility-map
18 VALUE: category-map
19 VALUE: name-map
20 VALUE: special-casing
21 VALUE: properties
22
23 : canonical-entry ( char -- seq ) canonical-map at ;
24 : combine-chars ( a b -- char/f ) combine-map hash2 ;
25 : compatibility-entry ( char -- seq ) compatibility-map at  ;
26 : combining-class ( char -- n ) class-map at ;
27 : non-starter? ( char -- ? ) combining-class { 0 f } member? not ;
28 : name>char ( name -- char ) name-map at ;
29 : char>name ( char -- name ) name-map value-at ;
30 : property? ( char property -- ? ) properties at interval-key? ;
31
32 ! For non-existent characters, use Cn
33 CONSTANT: categories
34     { "Cn"
35       "Lu" "Ll" "Lt" "Lm" "Lo"
36       "Mn" "Mc" "Me"
37       "Nd" "Nl" "No"
38       "Pc" "Pd" "Ps" "Pe" "Pi" "Pf" "Po"
39       "Sm" "Sc" "Sk" "So"
40       "Zs" "Zl" "Zp"
41       "Cc" "Cf" "Cs" "Co" }
42
43 MEMO: categories-map ( -- hashtable )
44     categories <enum> [ swap ] H{ } assoc-map-as ;
45
46 CONSTANT: num-chars HEX: 2FA1E
47
48 : category# ( char -- category )
49     ! There are a few characters that should be Cn
50     ! that this gives Cf or Mn
51     ! Cf = 26; Mn = 5; Cn = 29
52     ! Use a compressed array instead?
53     dup category-map ?nth [ ] [
54         dup HEX: E0001 HEX: E007F between?
55         [ drop 26 ] [
56             HEX: E0100 HEX: E01EF between?  5 29 ?
57         ] if
58     ] ?if ;
59
60 : category ( char -- category )
61     category# categories nth ;
62
63 ! Loading data from UnicodeData.txt
64
65 : split-; ( line -- array )
66     ";" split [ [ blank? ] trim ] map ;
67
68 : data ( filename -- data )
69     ascii file-lines [ split-; ] map ;
70
71 : load-data ( -- data )
72     "vocab:unicode/data/UnicodeData.txt" data ;
73
74 : filter-comments ( lines -- lines )
75     [ "#@" split first ] map harvest ;
76
77 : (process-data) ( index data -- newdata )
78     filter-comments
79     [ [ nth ] keep first swap ] with { } map>assoc
80     [ [ hex> ] dip ] assoc-map ;
81
82 : process-data ( index data -- hash )
83     (process-data) [ hex> ] assoc-map [ nip ] assoc-filter >hashtable ;
84
85 : (chain-decomposed) ( hash value -- newvalue )
86     [
87         2dup swap at
88         [ (chain-decomposed) ] [ 1array nip ] ?if
89     ] with map concat ;
90
91 : chain-decomposed ( hash -- newhash )
92     dup [ swap (chain-decomposed) ] curry assoc-map ;
93
94 : first* ( seq -- ? )
95     second { [ empty? ] [ first ] } 1|| ;
96
97 : (process-decomposed) ( data -- alist )
98     5 swap (process-data)
99     [ " " split [ hex> ] map ] assoc-map ;
100
101 : exclusions-file ( -- filename )
102     "vocab:unicode/data/CompositionExclusions.txt" ;
103
104 : exclusions ( -- set )
105     exclusions-file utf8 file-lines
106     [ "#" split1 drop [ blank? ] trim-tail hex> ] map harvest ;
107
108 : remove-exclusions ( alist -- alist )
109     exclusions [ dup ] H{ } map>assoc assoc-diff ;
110
111 : process-canonical ( data -- hash2 hash )
112     (process-decomposed) [ first* ] filter
113     [
114         [ second length 2 = ] filter remove-exclusions
115         ! using 1009 as the size, the maximum load is 4
116         [ first2 first2 rot 3array ] map 1009 alist>hash2
117     ] [ >hashtable chain-decomposed ] bi ;
118
119 : process-compatibility ( data -- hash )
120     (process-decomposed)
121     [ dup first* [ first2 rest 2array ] unless ] map
122     [ second empty? not ] filter
123     >hashtable chain-decomposed ;
124
125 : process-combining ( data -- hash )
126     3 swap (process-data)
127     [ string>number ] assoc-map
128     [ nip zero? not ] assoc-filter
129     >hashtable ;
130
131 ! the maximum unicode char in the first 3 planes
132
133 : ?set-nth ( val index seq -- )
134     2dup bounds-check? [ set-nth ] [ 3drop ] if ;
135
136 :: fill-ranges ( table -- table )
137     name-map >alist sort-values keys
138     [ { [ "first>" tail? ] [ "last>" tail? ] } 1|| ] filter
139     2 group [
140         [ name>char ] bi@ [ [a,b] ] [ table ?nth ] bi
141         [ swap table ?set-nth ] curry each
142     ] assoc-each table ;
143
144 :: process-category ( data -- category-listing )
145     num-chars <byte-array> :> table
146     2 data (process-data) [| char cat |
147         cat categories-map at char table ?set-nth
148     ] assoc-each table fill-ranges ;
149
150 : process-names ( data -- names-hash )
151     1 swap (process-data) [
152         >lower { { CHAR: \s CHAR: - } } substitute swap
153     ] H{ } assoc-map-as ;
154
155 : multihex ( hexstring -- string )
156     " " split [ hex> ] map sift ;
157
158 TUPLE: code-point lower title upper ;
159
160 C: <code-point> code-point
161
162 : set-code-point ( seq -- )
163     4 head [ multihex ] map first4
164     <code-point> swap first set ;
165
166 ! Extra properties
167 : properties-lines ( -- lines )
168     "vocab:unicode/data/PropList.txt"
169     ascii file-lines ;
170
171 : parse-properties ( -- {{[a,b],prop}} )
172     properties-lines filter-comments [
173         split-; first2
174         [ ".." split1 [ dup ] unless* [ hex> ] bi@ 2array ] dip
175     ] { } map>assoc ;
176
177 : properties>intervals ( properties -- assoc[str,interval] )
178     dup values prune [ f ] H{ } map>assoc
179     [ [ push-at ] curry assoc-each ] keep
180     [ <interval-set> ] assoc-map ;
181
182 : load-properties ( -- assoc )
183     parse-properties properties>intervals ;
184
185 ! Special casing data
186 : load-special-casing ( -- special-casing )
187     "vocab:unicode/data/SpecialCasing.txt" data
188     [ length 5 = ] filter
189     [ [ set-code-point ] each ] H{ } make-assoc ;
190
191 load-data {
192     [ process-names to: name-map ]
193     [ 13 swap process-data to: simple-lower ]
194     [ 12 swap process-data to: simple-upper ]
195     [ 14 swap process-data simple-upper assoc-union to: simple-title ]
196     [ process-combining to: class-map ]
197     [ process-canonical to: canonical-map to: combine-map ]
198     [ process-compatibility to: compatibility-map ]
199     [ process-category to: category-map ]
200 } cleave
201
202 : postprocess-class ( -- )
203     combine-map [ [ second ] map ] map concat
204     [ combining-class not ] filter
205     [ 0 swap class-map set-at ] each ;
206
207 postprocess-class
208
209 load-special-casing to: special-casing
210
211 load-properties to: properties
212
213 [ name>char [ "Invalid character" throw ] unless* ]
214 name>char-hook set-global