[project @ 2000-05-22 14:16:09 by simonmar]
[ghc-hetmet.git] / ghc / compiler / basicTypes / OccName.lhs
1
2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
3 %
4
5 \section[OccName]{@OccName@}
6
7 \begin{code}
8 module OccName (
9         -- The NameSpace type; abstact
10         NameSpace, tcName, clsName, tcClsName, dataName, varName, ipName,
11         tvName, uvName, nameSpaceString, 
12
13         -- The OccName type
14         OccName,        -- Abstract, instance of Outputable
15         pprOccName, 
16
17         mkSrcOccFS, mkSysOcc, mkSysOccFS, mkCCallOcc, mkSrcVarOcc, mkKindOccFS,
18         mkSuperDictSelOcc, mkDFunOcc, mkForeignExportOcc,
19         mkDictOcc, mkIPOcc, mkWorkerOcc, mkMethodOcc, mkDefaultMethodOcc,
20         mkDerivedTyConOcc, mkClassTyConOcc, mkClassDataConOcc, mkSpecOcc,
21         
22         isTvOcc, isUvOcc, isDataOcc, isDataSymOcc, isSymOcc, isIPOcc, isValOcc,
23
24         occNameFS, occNameString, occNameUserString, occNameSpace, occNameFlavour, 
25         setOccNameSpace,
26
27         -- Tidying up
28         TidyOccEnv, emptyTidyOccEnv, tidyOccName, initTidyOccEnv,
29
30         -- Encoding
31         EncodedString, EncodedFS, UserString, UserFS, encode, encodeFS, decode, pprEncodedFS,
32
33         -- The basic form of names
34         isLexCon, isLexVar, isLexId, isLexSym,
35         isLexConId, isLexConSym, isLexVarId, isLexVarSym,
36         isLowerISO, isUpperISO
37
38     ) where
39
40 #include "HsVersions.h"
41
42 import Char     ( isDigit, isAlpha, isUpper, isLower, ISALPHANUM, ord, chr, digitToInt, intToDigit )
43 import Util     ( thenCmp )
44 import FiniteMap ( FiniteMap, emptyFM, lookupFM, addToFM, elemFM )
45 import Outputable
46 import GlaExts
47 \end{code}
48
49 We hold both module names and identifier names in a 'Z-encoded' form
50 that makes them acceptable both as a C identifier and as a Haskell
51 (prefix) identifier. 
52
53 They can always be decoded again when printing error messages
54 or anything else for the user, but it does make sense for it
55 to be represented here in encoded form, so that when generating
56 code the encoding operation is not performed on each occurrence.
57
58 These type synonyms help documentation.
59
60 \begin{code}
61 type UserFS    = FAST_STRING    -- As the user typed it
62 type EncodedFS = FAST_STRING    -- Encoded form
63
64 type UserString = String        -- As the user typed it
65 type EncodedString = String     -- Encoded form
66
67
68 pprEncodedFS :: EncodedFS -> SDoc
69 pprEncodedFS fs
70   = getPprStyle         $ \ sty ->
71     if userStyle sty then
72         text (decode (_UNPK_ fs))
73     else
74         ptext fs
75 \end{code}
76
77 %************************************************************************
78 %*                                                                      *
79 \subsection{Name space}
80 %*                                                                      *
81 %************************************************************************
82
83 \begin{code}
84 data NameSpace = VarName        -- Variables
85                | IPName         -- Implicit Parameters
86                | DataName       -- Data constructors
87                | TvName         -- Type variables
88                | UvName         -- Usage variables
89                | TcClsName      -- Type constructors and classes; Haskell has them
90                                 -- in the same name space for now.
91                deriving( Eq, Ord )
92
93 -- Though type constructors and classes are in the same name space now,
94 -- the NameSpace type is abstract, so we can easily separate them later
95 tcName    = TcClsName           -- Type constructors
96 clsName   = TcClsName           -- Classes
97 tcClsName = TcClsName           -- Not sure which!
98
99 dataName = DataName
100 tvName   = TvName
101 uvName   = UvName
102 varName  = VarName
103 ipName   = IPName
104
105
106 nameSpaceString :: NameSpace -> String
107 nameSpaceString DataName  = "Data constructor"
108 nameSpaceString VarName   = "Variable"
109 nameSpaceString IPName    = "Implicit Param"
110 nameSpaceString TvName    = "Type variable"
111 nameSpaceString UvName    = "Usage variable"
112 nameSpaceString TcClsName = "Type constructor or class"
113 \end{code}
114
115
116 %************************************************************************
117 %*                                                                      *
118 \subsection[Name-pieces-datatypes]{The @OccName@ datatypes}
119 %*                                                                      *
120 %************************************************************************
121
122 \begin{code}
123 data OccName = OccName 
124                         NameSpace
125                         EncodedFS
126 \end{code}
127
128
129 \begin{code}
130 instance Eq OccName where
131     (OccName sp1 s1) == (OccName sp2 s2) = s1 == s2 && sp1 == sp2
132
133 instance Ord OccName where
134     compare (OccName sp1 s1) (OccName sp2 s2) = (s1  `compare` s2) `thenCmp`
135                                                 (sp1 `compare` sp2)
136 \end{code}
137
138
139 %************************************************************************
140 %*                                                                      *
141 \subsection{Printing}
142 %*                                                                      *
143 %************************************************************************
144  
145 \begin{code}
146 instance Outputable OccName where
147     ppr = pprOccName
148
149 pprOccName :: OccName -> SDoc
150 pprOccName (OccName sp occ) = pprEncodedFS occ
151 \end{code}
152
153
154 %************************************************************************
155 %*                                                                      *
156 \subsection{Construction}
157 %*                                                                      *
158 %************************************************************************
159
160 *Sys* things do no encoding; the caller should ensure that the thing is
161 already encoded
162
163 \begin{code}
164 mkSysOcc :: NameSpace -> EncodedString -> OccName
165 mkSysOcc occ_sp str = ASSERT2( alreadyEncoded str, text str )
166                       OccName occ_sp (_PK_ str)
167
168 mkSysOccFS :: NameSpace -> EncodedFS -> OccName
169 mkSysOccFS occ_sp fs = ASSERT2( alreadyEncodedFS fs, ppr fs )
170                        OccName occ_sp fs
171
172 mkCCallOcc :: EncodedString -> OccName
173 -- This version of mkSysOcc doesn't check that the string is already encoded,
174 -- because it will be something like "{__ccall f dyn Int# -> Int#}" 
175 -- This encodes a lot into something that then parses like an Id.
176 -- But then alreadyEncoded complains about the braces!
177 mkCCallOcc str = OccName varName (_PK_ str)
178
179 -- Kind constructors get a speical function.  Uniquely, they are not encoded,
180 -- so that they have names like '*'.  This means that *even in interface files*
181 -- we'll get kinds like (* -> (* -> *)).  We can't use mkSysOcc because it
182 -- has an ASSERT that doesn't hold.
183 mkKindOccFS :: NameSpace -> EncodedFS -> OccName
184 mkKindOccFS occ_sp fs = OccName occ_sp fs
185 \end{code}
186
187 *Source-code* things are encoded.
188
189 \begin{code}
190 mkSrcOccFS :: NameSpace -> UserFS -> OccName
191 mkSrcOccFS occ_sp fs = mkSysOccFS occ_sp (encodeFS fs)
192
193 mkSrcVarOcc :: UserFS -> OccName
194 mkSrcVarOcc fs = mkSysOccFS varName (encodeFS fs)
195 \end{code}
196
197
198
199 %************************************************************************
200 %*                                                                      *
201 \subsection{Predicates and taking them apart}
202 %*                                                                      *
203 %************************************************************************
204
205 \begin{code} 
206 occNameFS :: OccName -> EncodedFS
207 occNameFS (OccName _ s) = s
208
209 occNameString :: OccName -> EncodedString
210 occNameString (OccName _ s) = _UNPK_ s
211
212 occNameUserString :: OccName -> UserString
213 occNameUserString occ = decode (occNameString occ)
214
215 occNameSpace :: OccName -> NameSpace
216 occNameSpace (OccName sp _) = sp
217
218 setOccNameSpace :: OccName -> NameSpace -> OccName
219 setOccNameSpace (OccName _ occ) sp = OccName sp occ
220
221 -- occNameFlavour is used only to generate good error messages
222 occNameFlavour :: OccName -> String
223 occNameFlavour (OccName sp _) = nameSpaceString sp
224 \end{code}
225
226 \begin{code}
227 isTvOcc, isDataSymOcc, isSymOcc, isUvOcc :: OccName -> Bool
228
229 isTvOcc (OccName TvName _) = True
230 isTvOcc other              = False
231
232 isUvOcc (OccName UvName _) = True
233 isUvOcc other              = False
234
235 isValOcc (OccName VarName  _) = True
236 isValOcc (OccName DataName _) = True
237 isValOcc other                = False
238
239 -- Data constructor operator (starts with ':', or '[]')
240 -- Pretty inefficient!
241 isDataSymOcc (OccName DataName s) = isLexConSym (decodeFS s)
242 isDataSymOcc other                = False
243
244 isDataOcc (OccName DataName _) = True
245 isDataOcc other                = False
246
247 -- Any operator (data constructor or variable)
248 -- Pretty inefficient!
249 isSymOcc (OccName DataName s) = isLexConSym (decodeFS s)
250 isSymOcc (OccName VarName s)  = isLexSym (decodeFS s)
251
252 isIPOcc (OccName IPName _) = True
253 isIPOcc _                  = False
254 \end{code}
255
256
257 %************************************************************************
258 %*                                                                      *
259 \subsection{Making system names}
260 %*                                                                      *
261 %************************************************************************
262
263 Here's our convention for splitting up the interface file name space:
264
265         d...            dictionary identifiers
266                         (local variables, so no name-clash worries)
267
268         $f...           dict-fun identifiers (from inst decls)
269         $dm...          default methods
270         $p...           superclass selectors
271         $w...           workers
272         $T...           compiler-generated tycons for dictionaries
273         $D...           ...ditto data cons
274         $sf..           specialised version of f
275
276         in encoded form these appear as Zdfxxx etc
277
278         :...            keywords (export:, letrec: etc.)
279
280 This knowledge is encoded in the following functions.
281
282
283 @mk_deriv@ generates an @OccName@ from the one-char prefix and a string.
284 NB: The string must already be encoded!
285
286 \begin{code}
287 mk_deriv :: NameSpace 
288          -> String              -- Distinguishes one sort of derived name from another
289          -> EncodedString       -- Must be already encoded!!  We don't want to encode it a 
290                                 -- second time because encoding isn't itempotent
291          -> OccName
292
293 mk_deriv occ_sp sys_prefix str = mkSysOcc occ_sp (encode sys_prefix ++ str)
294 \end{code}
295
296 \begin{code}
297 mkDictOcc, mkIPOcc, mkWorkerOcc, mkDefaultMethodOcc,
298            mkClassTyConOcc, mkClassDataConOcc, mkSpecOcc
299    :: OccName -> OccName
300
301 -- These derived variables have a prefix that no Haskell value could have
302 mkWorkerOcc        = mk_simple_deriv varName  "$w"
303 mkDefaultMethodOcc = mk_simple_deriv varName  "$dm"
304 mkDerivedTyConOcc  = mk_simple_deriv tcName   ":"       -- The : prefix makes sure it classifies
305 mkClassTyConOcc    = mk_simple_deriv tcName   ":T"      -- as a tycon/datacon
306 mkClassDataConOcc  = mk_simple_deriv dataName ":D"      --
307 mkDictOcc          = mk_simple_deriv varName  "$d"
308 mkIPOcc            = mk_simple_deriv varName  "$i"
309 mkSpecOcc          = mk_simple_deriv varName  "$s"
310 mkForeignExportOcc = mk_simple_deriv varName  "$f"
311
312 mk_simple_deriv sp px occ = mk_deriv sp px (occNameString occ)
313 \end{code}
314
315 \begin{code}
316 mkSuperDictSelOcc :: Int        -- Index of superclass, eg 3
317                   -> OccName    -- Class, eg "Ord"
318                   -> OccName    -- eg "p3Ord"
319 mkSuperDictSelOcc index cls_occ
320   = mk_deriv varName "$p" (show index ++ occNameString cls_occ)
321 \end{code}
322
323
324 \begin{code}
325 mkDFunOcc :: EncodedString      -- Typically the class and type glommed together e.g. "OrdMaybe"
326           -> Int                -- Unique to distinguish dfuns which share the previous two
327                                 --      eg 3
328           -- The requirement is that the (string,index) pair be unique in this module
329
330           -> OccName    -- "$fOrdMaybe3"
331
332 mkDFunOcc string index
333   = mk_deriv VarName "$f" (show_index ++ string)
334   where
335     show_index | index == 0 = ""
336                | otherwise  = show index
337 \end{code}
338
339 We used to add a '$m' to indicate a method, but that gives rise to bad
340 error messages from the type checker when we print the function name or pattern
341 of an instance-decl binding.  Why? Because the binding is zapped
342 to use the method name in place of the selector name.
343 (See TcClassDcl.tcMethodBind)
344
345 The way it is now, -ddump-xx output may look confusing, but
346 you can always say -dppr-debug to get the uniques.
347
348 However, we *do* have to zap the first character to be lower case,
349 because overloaded constructors (blarg) generate methods too.
350 And convert to VarName space
351
352 e.g. a call to constructor MkFoo where
353         data (Ord a) => Foo a = MkFoo a
354
355 If this is necessary, we do it by prefixing '$m'.  These 
356 guys never show up in error messages.  What a hack.
357
358 \begin{code}
359 mkMethodOcc :: OccName -> OccName
360 mkMethodOcc occ@(OccName VarName fs) = occ
361 mkMethodOcc occ                      = mk_simple_deriv varName "$m" occ
362 \end{code}
363
364
365 %************************************************************************
366 %*                                                                      *
367 \subsection{Tidying them up}
368 %*                                                                      *
369 %************************************************************************
370
371 Before we print chunks of code we like to rename it so that
372 we don't have to print lots of silly uniques in it.  But we mustn't
373 accidentally introduce name clashes!  So the idea is that we leave the
374 OccName alone unless it accidentally clashes with one that is already
375 in scope; if so, we tack on '1' at the end and try again, then '2', and
376 so on till we find a unique one.
377
378 There's a wrinkle for operators.  Consider '>>='.  We can't use '>>=1' 
379 because that isn't a single lexeme.  So we encode it to 'lle' and *then*
380 tack on the '1', if necessary.
381
382 \begin{code}
383 type TidyOccEnv = FiniteMap FAST_STRING Int     -- The in-scope OccNames
384 emptyTidyOccEnv = emptyFM
385
386 initTidyOccEnv :: [OccName] -> TidyOccEnv       -- Initialise with names to avoid!
387 initTidyOccEnv = foldl (\env (OccName _ fs) -> addToFM env fs 1) emptyTidyOccEnv
388
389 tidyOccName :: TidyOccEnv -> OccName -> (TidyOccEnv, OccName)
390
391 tidyOccName in_scope occ@(OccName occ_sp fs)
392   | not (fs `elemFM` in_scope)
393   = (addToFM in_scope fs 1, occ)        -- First occurrence
394
395   | otherwise                           -- Already occurs
396   = go in_scope (_UNPK_ fs)
397   where
398
399     go in_scope str = case lookupFM in_scope pk_str of
400                         Just n  -> go (addToFM in_scope pk_str (n+1)) (str ++ show n)
401                                 -- Need to go round again, just in case "t3" (say) 
402                                 -- clashes with a "t3" that's already in scope
403
404                         Nothing -> (addToFM in_scope pk_str 1, mkSysOccFS occ_sp pk_str)
405                                 -- str is now unique
406                     where
407                       pk_str = _PK_ str
408 \end{code}
409
410
411 %************************************************************************
412 %*                                                                      *
413 \subsection{The 'Z' encoding}
414 %*                                                                      *
415 %************************************************************************
416
417 This is the main name-encoding and decoding function.  It encodes any
418 string into a string that is acceptable as a C name.  This is the name
419 by which things are known right through the compiler.
420
421 The basic encoding scheme is this.  
422
423 * Tuples (,,,) are coded as Z3T
424
425 * Alphabetic characters (upper and lower) and digits
426         all translate to themselves; 
427         except 'Z', which translates to 'ZZ'
428         and    'z', which translates to 'zz'
429   We need both so that we can preserve the variable/tycon distinction
430
431 * Most other printable characters translate to 'Zx' for some
432         alphabetic character x
433
434 * The others translate as 'Zxdd' where 'dd' is exactly two hexadecimal
435         digits for the ord of the character
436
437         Before          After
438         --------------------------
439         Trak            Trak
440         foo_wib         foo_wib
441         >               Zg
442         >1              Zg1
443         foo#            fooZh
444         foo##           fooZhZh
445         foo##1          fooZhXh1
446         fooZ            fooZZ   
447         :+              ZcZp
448         ()              Z0T
449         (,,,,)          Z4T
450
451
452 \begin{code}
453 -- alreadyEncoded is used in ASSERTs to check for encoded
454 -- strings.  It isn't fail-safe, of course, because, say 'zh' might
455 -- be encoded or not.
456 alreadyEncoded :: String -> Bool
457 alreadyEncoded s = all ok s
458                  where
459                    ok ' ' = True                -- This is a bit of a lie; if we really wanted spaces
460                                                 -- in names we'd have to encode them.  But we do put
461                                                 -- spaces in ccall "occurrences", and we don't want to
462                                                 -- reject them here
463                    ok ch  = ISALPHANUM ch
464
465 alreadyEncodedFS :: FAST_STRING -> Bool
466 alreadyEncodedFS fs = alreadyEncoded (_UNPK_ fs)
467
468 encode :: UserString -> EncodedString
469 encode cs = case maybe_tuple cs of
470                 Just n  -> 'Z' : show n ++ "T"          -- Tuples go to Z2T etc
471                 Nothing -> go cs
472           where
473                 go []     = []
474                 go (c:cs) = encode_ch c ++ go cs
475
476 -- ToDo: Unboxed tuples too, perhaps?
477 maybe_tuple ('(' : cs) = check_tuple (0::Int) cs
478 maybe_tuple other      = Nothing
479
480 check_tuple :: Int -> String -> Maybe Int
481 check_tuple n (',' : cs) = check_tuple (n+1) cs
482 check_tuple n ")"        = Just n
483 check_tuple n other      = Nothing
484
485 encodeFS :: UserFS -> EncodedFS
486 encodeFS fast_str  | all unencodedChar str = fast_str
487                    | otherwise             = _PK_ (encode str)
488                    where
489                      str = _UNPK_ fast_str
490
491 unencodedChar :: Char -> Bool   -- True for chars that don't need encoding
492 unencodedChar 'Z' = False
493 unencodedChar 'z' = False
494 unencodedChar c   = ISALPHANUM c
495
496 encode_ch :: Char -> EncodedString
497 encode_ch c | unencodedChar c = [c]     -- Common case first
498
499 -- Constructors
500 encode_ch '('  = "ZL"   -- Needed for things like (,), and (->)
501 encode_ch ')'  = "ZR"   -- For symmetry with (
502 encode_ch '['  = "ZM"
503 encode_ch ']'  = "ZN"
504 encode_ch ':'  = "ZC"
505 encode_ch 'Z'  = "ZZ"
506
507 -- Variables
508 encode_ch 'z'  = "zz"
509 encode_ch '&'  = "za"
510 encode_ch '|'  = "zb"
511 encode_ch '^'  = "zc"
512 encode_ch '$'  = "zd"
513 encode_ch '='  = "ze"
514 encode_ch '>'  = "zg"
515 encode_ch '#'  = "zh"
516 encode_ch '.'  = "zi"
517 encode_ch '<'  = "zl"
518 encode_ch '-'  = "zm"
519 encode_ch '!'  = "zn"
520 encode_ch '+'  = "zp"
521 encode_ch '\'' = "zq"
522 encode_ch '\\' = "zr"
523 encode_ch '/'  = "zs"
524 encode_ch '*'  = "zt"
525 encode_ch '_'  = "zu"
526 encode_ch '%'  = "zv"
527 encode_ch c    = ['z', 'x', intToDigit hi, intToDigit lo]
528                where
529                  (hi,lo) = ord c `quotRem` 16
530 \end{code}
531
532 Decode is used for user printing.
533
534 \begin{code}
535 decodeFS :: FAST_STRING -> FAST_STRING
536 decodeFS fs = _PK_ (decode (_UNPK_ fs))
537
538 decode :: EncodedString -> UserString
539 decode [] = []
540 decode ('Z' : rest) = decode_escape rest
541 decode ('z' : rest) = decode_escape rest
542 decode (c   : rest) = c : decode rest
543
544 decode_escape :: EncodedString -> UserString
545
546 decode_escape ('Z' : rest) = 'Z' : decode rest
547 decode_escape ('C' : rest) = ':' : decode rest
548 decode_escape ('L' : rest) = '(' : decode rest
549 decode_escape ('R' : rest) = ')' : decode rest
550 decode_escape ('M' : rest) = '[' : decode rest
551 decode_escape ('N' : rest) = ']' : decode rest
552
553 decode_escape ('z' : rest) = 'z' : decode rest
554 decode_escape ('a' : rest) = '&' : decode rest
555 decode_escape ('b' : rest) = '|' : decode rest
556 decode_escape ('d' : rest) = '$' : decode rest
557 decode_escape ('e' : rest) = '=' : decode rest
558 decode_escape ('g' : rest) = '>' : decode rest
559 decode_escape ('h' : rest) = '#' : decode rest
560 decode_escape ('i' : rest) = '.' : decode rest
561 decode_escape ('l' : rest) = '<' : decode rest
562 decode_escape ('m' : rest) = '-' : decode rest
563 decode_escape ('n' : rest) = '!' : decode rest
564 decode_escape ('p' : rest) = '+' : decode rest
565 decode_escape ('q' : rest) = '\'' : decode rest
566 decode_escape ('r' : rest) = '\\' : decode rest
567 decode_escape ('s' : rest) = '/' : decode rest
568 decode_escape ('t' : rest) = '*' : decode rest
569 decode_escape ('u' : rest) = '^' : decode rest
570 decode_escape ('v' : rest) = '%' : decode rest
571 decode_escape ('x' : d1 : d2 : rest) = chr (digitToInt d1 * 16 + digitToInt d2)  : decode rest
572
573 -- Tuples are coded as Z23T
574 decode_escape (c : rest)
575   | isDigit c = go (digitToInt c) rest
576   where
577     go n (c : rest) | isDigit c = go (10*n + digitToInt c) rest
578     go n ('T' : rest)           = '(' : replicate n ',' ++ ')' : decode rest
579     go n other = pprPanic "decode_escape" (ppr n <+> text (c:rest))
580
581 decode_escape (c : rest) = pprTrace "decode_escape" (char c) (decode rest)
582 \end{code}
583
584
585 %************************************************************************
586 %*                                                                      *
587 n\subsection{Lexical categories}
588 %*                                                                      *
589 %************************************************************************
590
591 These functions test strings to see if they fit the lexical categories
592 defined in the Haskell report.
593
594 \begin{code}
595 isLexCon,   isLexVar,    isLexId,    isLexSym    :: FAST_STRING -> Bool
596 isLexConId, isLexConSym, isLexVarId, isLexVarSym :: FAST_STRING -> Bool
597
598 isLexCon cs = isLexConId  cs || isLexConSym cs
599 isLexVar cs = isLexVarId  cs || isLexVarSym cs
600
601 isLexId  cs = isLexConId  cs || isLexVarId  cs
602 isLexSym cs = isLexConSym cs || isLexVarSym cs
603
604 -------------
605
606 isLexConId cs                           -- Prefix type or data constructors
607   | _NULL_ cs        = False            --      e.g. "Foo", "[]", "(,)" 
608   | cs == SLIT("[]") = True
609   | c  == '('        = True     -- (), (,), (,,), ...
610   | otherwise        = isUpper c || isUpperISO c
611   where                                 
612     c = _HEAD_ cs
613
614 isLexVarId cs                           -- Ordinary prefix identifiers
615   | _NULL_ cs    = False                --      e.g. "x", "_x"
616   | otherwise    = isLower c || isLowerISO c || c == '_'
617   where
618     c = _HEAD_ cs
619
620 isLexConSym cs                          -- Infix type or data constructors
621   | _NULL_ cs   = False                 --      e.g. ":-:", ":", "->"
622   | otherwise   = c  == ':'
623                || cs == SLIT("->")
624   where
625     c = _HEAD_ cs
626
627 isLexVarSym cs                          -- Infix identifiers
628   | _NULL_ cs = False                   --      e.g. "+"
629   | otherwise = isSymbolASCII c
630              || isSymbolISO c
631   where
632     c = _HEAD_ cs
633
634 -------------
635 isSymbolASCII c = c `elem` "!#$%&*+./<=>?@\\^|~-"
636 isSymbolISO   c = ord c `elem` (0xd7 : 0xf7 : [0xa1 .. 0xbf])
637 isUpperISO    (C# c#) = c# `geChar#` '\xc0'# && c# `leChar#` '\xde'# && c# `neChar#` '\xd7'#
638         --0xc0 <= oc && oc <= 0xde && oc /= 0xd7 where oc = ord c
639 isLowerISO    (C# c#) = c# `geChar#` '\xdf'# && c# `leChar#` '\xff'# && c# `neChar#` '\xf7'#
640         --0xdf <= oc && oc <= 0xff && oc /= 0xf7 where oc = ord c
641 \end{code}