[project @ 2000-10-25 10:23:57 by sewardj]
[ghc-hetmet.git] / ghc / compiler / main / CmdLineOpts.lhs
1 %
2 % (c) The University of Glasgow, 1996-2000
3 %
4 \section[CmdLineOpts]{Things to do with command-line options}
5
6 \begin{code}
7
8 module CmdLineOpts (
9         CoreToDo(..),
10         SimplifierSwitch(..), isAmongSimpl,
11         StgToDo(..),
12         SwitchResult(..),
13         HscLang(..),
14         DynFlag(..),    -- needed non-abstractly by DriverFlags
15         DynFlags(..),
16
17         intSwitchSet,
18         switchIsOn,
19         isStaticHscFlag,
20
21         opt_PprStyle_NoPrags,
22         opt_PprUserLength,
23         opt_PprStyle_Debug,
24
25         dopt,
26
27         -- other dynamic flags
28         dopt_CoreToDo,
29         dopt_StgToDo,
30         dopt_HscLang,
31         dopt_OutName,
32
33         -- profiling opts
34         opt_AutoSccsOnAllToplevs,
35         opt_AutoSccsOnExportedToplevs,
36         opt_AutoSccsOnIndividualCafs,
37         opt_AutoSccsOnDicts,
38         opt_SccProfilingOn,
39         opt_DoTickyProfiling,
40
41         -- language opts
42         opt_AllStrict,
43         opt_DictsStrict,
44         opt_MaxContextReductionDepth,
45         opt_IrrefutableTuples,
46         opt_NumbersStrict,
47         opt_Parallel,
48         opt_SMP,
49
50         -- optimisation opts
51         opt_DoSemiTagging,
52         opt_FoldrBuildOn,
53         opt_LiberateCaseThreshold,
54         opt_StgDoLetNoEscapes,
55         opt_UnfoldCasms,
56         opt_UsageSPOn,
57         opt_UnboxStrictFields,
58         opt_SimplNoPreInlining,
59         opt_SimplDoEtaReduction,
60         opt_SimplDoLambdaEtaExpansion,
61         opt_SimplCaseOfCase,
62         opt_SimplCaseMerge,
63         opt_SimplPedanticBottoms,
64         opt_SimplExcessPrecision,
65
66         -- Unfolding control
67         opt_UF_HiFileThreshold,
68         opt_UF_CreationThreshold,
69         opt_UF_UseThreshold,
70         opt_UF_FunAppDiscount,
71         opt_UF_KeenessFactor,
72         opt_UF_UpdateInPlace,
73         opt_UF_CheapOp,
74         opt_UF_DearOp,
75
76         -- misc opts
77         opt_InPackage,
78         opt_EmitCExternDecls,
79         opt_EnsureSplittableC,
80         opt_GranMacros,
81         opt_HiVersion,
82         opt_HistorySize,
83         opt_IgnoreAsserts,
84         opt_IgnoreIfacePragmas,
85         opt_NoHiCheck,
86         opt_NoImplicitPrelude,
87         opt_OmitBlackHoling,
88         opt_OmitInterfacePragmas,
89         opt_NoPruneTyDecls,
90         opt_NoPruneDecls,
91         opt_Static,
92         opt_Unregisterised,
93         opt_Verbose
94     ) where
95
96 #include "HsVersions.h"
97
98 import Array    ( array, (//) )
99 import GlaExts
100 import Argv
101 import Constants        -- Default values for some flags
102 import Util
103 import FastTypes
104
105 import Maybes           ( firstJust )
106 import Panic            ( panic )
107
108 #if __GLASGOW_HASKELL__ < 301
109 import ArrBase  ( Array(..) )
110 #else
111 import PrelArr  ( Array(..) )
112 #endif
113 \end{code}
114
115 %************************************************************************
116 %*                                                                      *
117 \subsection{Command-line options}
118 %*                                                                      *
119 %************************************************************************
120
121 The hsc command-line options are split into two categories:
122
123   - static flags
124   - dynamic flags
125
126 Static flags are represented by top-level values of type Bool or Int,
127 for example.  They therefore have the same value throughout the
128 invocation of hsc.
129
130 Dynamic flags are represented by an abstract type, DynFlags, which is
131 passed into hsc by the compilation manager for every compilation.
132 Dynamic flags are those that change on a per-compilation basis,
133 perhaps because they may be present in the OPTIONS pragma at the top
134 of a module.
135
136 Other flag-related blurb:
137
138 A list of {\em ToDo}s is things to be done in a particular part of
139 processing.  A (fictitious) example for the Core-to-Core simplifier
140 might be: run the simplifier, then run the strictness analyser, then
141 run the simplifier again (three ``todos'').
142
143 There are three ``to-do processing centers'' at the moment.  In the
144 main loop (\tr{main/Main.lhs}), in the Core-to-Core processing loop
145 (\tr{simplCore/SimplCore.lhs), and in the STG-to-STG processing loop
146 (\tr{simplStg/SimplStg.lhs}).
147
148 %************************************************************************
149 %*                                                                      *
150 \subsection{Datatypes associated with command-line options}
151 %*                                                                      *
152 %************************************************************************
153
154 \begin{code}
155 data SwitchResult
156   = SwBool      Bool            -- on/off
157   | SwString    FAST_STRING     -- nothing or a String
158   | SwInt       Int             -- nothing or an Int
159 \end{code}
160
161 \begin{code}
162 data CoreToDo           -- These are diff core-to-core passes,
163                         -- which may be invoked in any order,
164                         -- as many times as you like.
165
166   = CoreDoSimplify      -- The core-to-core simplifier.
167         (SimplifierSwitch -> SwitchResult)
168                         -- Each run of the simplifier can take a different
169                         -- set of simplifier-specific flags.
170   | CoreDoFloatInwards
171   | CoreDoFloatOutwards Bool    -- True <=> float lambdas to top level
172   | CoreLiberateCase
173   | CoreDoPrintCore
174   | CoreDoStaticArgs
175   | CoreDoStrictness
176   | CoreDoWorkerWrapper
177   | CoreDoSpecialising
178   | CoreDoUSPInf
179   | CoreDoCPResult
180   | CoreDoGlomBinds
181   | CoreCSE
182
183   | CoreDoNothing        -- useful when building up lists of these things
184 \end{code}
185
186 \begin{code}
187 data StgToDo
188   = StgDoStaticArgs
189   | StgDoLambdaLift
190   | StgDoMassageForProfiling  -- should be (next to) last
191   -- There's also setStgVarInfo, but its absolute "lastness"
192   -- is so critical that it is hardwired in (no flag).
193   | D_stg_stats
194 \end{code}
195
196 \begin{code}
197 data SimplifierSwitch
198   = MaxSimplifierIterations Int
199   | SimplInlinePhase Int
200   | DontApplyRules
201   | NoCaseOfCase
202   | SimplLetToCase
203 \end{code}
204
205 %************************************************************************
206 %*                                                                      *
207 \subsection{Dynamic command-line options}
208 %*                                                                      *
209 %************************************************************************
210
211 \begin{code}
212 data DynFlag
213
214    -- debugging flags
215    = Opt_D_dump_all
216    | Opt_D_dump_most
217    | Opt_D_dump_absC
218    | Opt_D_dump_asm
219    | Opt_D_dump_cpranal
220    | Opt_D_dump_deriv
221    | Opt_D_dump_ds
222    | Opt_D_dump_flatC
223    | Opt_D_dump_foreign
224    | Opt_D_dump_inlinings
225    | Opt_D_dump_occur_anal
226    | Opt_D_dump_parsed
227    | Opt_D_dump_realC
228    | Opt_D_dump_rn
229    | Opt_D_dump_simpl
230    | Opt_D_dump_simpl_iterations
231    | Opt_D_dump_spec
232    | Opt_D_dump_stg
233    | Opt_D_dump_stranal
234    | Opt_D_dump_tc
235    | Opt_D_dump_types
236    | Opt_D_dump_rules
237    | Opt_D_dump_usagesp
238    | Opt_D_dump_cse
239    | Opt_D_dump_worker_wrapper
240    | Opt_D_show_passes
241    | Opt_D_dump_rn_trace
242    | Opt_D_dump_rn_stats
243    | Opt_D_dump_stix
244    | Opt_D_dump_simpl_stats
245    | Opt_D_source_stats
246    | Opt_D_verbose_core2core
247    | Opt_D_verbose_stg2stg
248    | Opt_D_dump_hi_diffs
249    | Opt_D_dump_minimal_imports
250    | Opt_DoCoreLinting
251    | Opt_DoStgLinting
252    | Opt_DoUSPLinting
253
254    | Opt_WarnDuplicateExports
255    | Opt_WarnHiShadows
256    | Opt_WarnIncompletePatterns
257    | Opt_WarnMissingFields
258    | Opt_WarnMissingMethods
259    | Opt_WarnMissingSigs
260    | Opt_WarnNameShadowing
261    | Opt_WarnOverlappingPatterns
262    | Opt_WarnSimplePatterns
263    | Opt_WarnTypeDefaults
264    | Opt_WarnUnusedBinds
265    | Opt_WarnUnusedImports
266    | Opt_WarnUnusedMatches
267    | Opt_WarnDeprecations
268
269    -- language opts
270    | Opt_AllowOverlappingInstances
271    | Opt_AllowUndecidableInstances
272    | Opt_GlasgowExts
273    | Opt_Generics
274
275    -- misc
276    | Opt_ReportCompile
277    deriving (Eq)
278
279 data DynFlags = DynFlags {
280   coreToDo   :: CoreToDo,
281   stgToDo    :: StgToDo,
282   hscLang    :: HscLang,
283   hscOutName :: String,  -- name of the file in which to place output
284   flags      :: [DynFlag]
285  }
286
287 dopt :: DynFlag -> DynFlags -> Bool
288 dopt f dflags  = f `elem` (flags dflags)
289
290 dopt_CoreToDo :: DynFlags -> CoreToDo
291 dopt_CoreToDo = coreToDo
292
293 dopt_StgToDo :: DynFlags -> StgToDo
294 dopt_StgToDo = stgToDo
295
296 dopt_OutName :: DynFlags -> String
297 dopt_OutName = hscOutName
298
299 data HscLang
300   = HscC
301   | HscAsm
302   | HscJava
303   | HscInterpreted
304     deriving Eq
305
306 dopt_HscLang :: DynFlags -> HscLang
307 dopt_HscLang = hscLang
308 \end{code}
309
310 %************************************************************************
311 %*                                                                      *
312 \subsection{Classifying command-line options}
313 %*                                                                      *
314 %************************************************************************
315
316 \begin{code}
317 lookUp           :: FAST_STRING -> Bool
318 lookup_int       :: String -> Maybe Int
319 lookup_def_int   :: String -> Int -> Int
320 lookup_def_float :: String -> Float -> Float
321 lookup_str       :: String -> Maybe String
322
323 lookUp     sw = sw `elem` argv
324         
325 lookup_str sw = firstJust (map (startsWith sw) unpacked_opts)
326
327 lookup_int sw = case (lookup_str sw) of
328                   Nothing -> Nothing
329                   Just xx -> Just (read xx)
330
331 lookup_def_int sw def = case (lookup_str sw) of
332                             Nothing -> def              -- Use default
333                             Just xx -> read xx
334
335 lookup_def_char sw def = case (lookup_str sw) of
336                             Just (xx:_) -> xx
337                             _           -> def          -- Use default
338
339 lookup_def_float sw def = case (lookup_str sw) of
340                             Nothing -> def              -- Use default
341                             Just xx -> read xx
342
343 unpacked_opts = map _UNPK_ argv
344
345 {-
346  Putting the compiler options into temporary at-files
347  may turn out to be necessary later on if we turn hsc into
348  a pure Win32 application where I think there's a command-line
349  length limit of 255. unpacked_opts understands the @ option.
350
351 unpacked_opts :: [String]
352 unpacked_opts =
353   concat $
354   map (expandAts) $
355   map _UNPK_ argv
356   where
357    expandAts ('@':fname) = words (unsafePerformIO (readFile fname))
358    expandAts l = [l]
359 -}
360 \end{code}
361
362 %************************************************************************
363 %*                                                                      *
364 \subsection{Static options}
365 %*                                                                      *
366 %************************************************************************
367
368 \begin{code}
369 -- debugging opts
370 opt_PprStyle_NoPrags            = lookUp  SLIT("-dppr-noprags")
371 opt_PprStyle_Debug              = lookUp  SLIT("-dppr-debug")
372 opt_PprUserLength               = lookup_def_int "-dppr-user-length" 5 --ToDo: give this a name
373
374 -- profiling opts
375 opt_AutoSccsOnAllToplevs        = lookUp  SLIT("-fauto-sccs-on-all-toplevs")
376 opt_AutoSccsOnExportedToplevs   = lookUp  SLIT("-fauto-sccs-on-exported-toplevs")
377 opt_AutoSccsOnIndividualCafs    = lookUp  SLIT("-fauto-sccs-on-individual-cafs")
378 opt_AutoSccsOnDicts             = lookUp  SLIT("-fauto-sccs-on-dicts")
379 opt_SccProfilingOn              = lookUp  SLIT("-fscc-profiling")
380 opt_DoTickyProfiling            = lookUp  SLIT("-fticky-ticky")
381
382 -- language opts
383 opt_AllStrict                   = lookUp  SLIT("-fall-strict")
384 opt_DictsStrict                 = lookUp  SLIT("-fdicts-strict")
385 opt_IrrefutableTuples           = lookUp  SLIT("-firrefutable-tuples")
386 opt_MaxContextReductionDepth    = lookup_def_int "-fcontext-stack" mAX_CONTEXT_REDUCTION_DEPTH
387 opt_NumbersStrict               = lookUp  SLIT("-fnumbers-strict")
388 opt_Parallel                    = lookUp  SLIT("-fparallel")
389 opt_SMP                         = lookUp  SLIT("-fsmp")
390
391 -- optimisation opts
392 opt_DoSemiTagging               = lookUp  SLIT("-fsemi-tagging")
393 opt_FoldrBuildOn                = lookUp  SLIT("-ffoldr-build-on")
394 opt_LiberateCaseThreshold       = lookup_def_int "-fliberate-case-threshold" (10::Int)
395 opt_StgDoLetNoEscapes           = lookUp  SLIT("-flet-no-escape")
396 opt_UnfoldCasms                 = lookUp SLIT("-funfold-casms-in-hi-file")
397 opt_UsageSPOn                   = lookUp  SLIT("-fusagesp-on")
398 opt_UnboxStrictFields           = lookUp  SLIT("-funbox-strict-fields")
399
400 {-
401    The optional '-inpackage=P' flag tells what package
402    we are compiling this module for.
403    The Prelude, for example is compiled with '-package prelude'
404 -}
405 opt_InPackage                   = case lookup_str "-inpackage=" of
406                                     Just p  -> _PK_ p
407                                     Nothing -> SLIT("Main")     -- The package name if none is specified
408
409 opt_EmitCExternDecls            = lookUp  SLIT("-femit-extern-decls")
410 opt_EnsureSplittableC           = lookUp  SLIT("-fglobalise-toplev-names")
411 opt_GranMacros                  = lookUp  SLIT("-fgransim")
412 opt_HiVersion                   = lookup_def_int "-fhi-version=" 0 -- what version we're compiling.
413 opt_HistorySize                 = lookup_def_int "-fhistory-size" 20
414 opt_IgnoreAsserts               = lookUp  SLIT("-fignore-asserts")
415 opt_IgnoreIfacePragmas          = lookUp  SLIT("-fignore-interface-pragmas")
416 opt_NoHiCheck                   = lookUp  SLIT("-fno-hi-version-check")
417 opt_NoImplicitPrelude           = lookUp  SLIT("-fno-implicit-prelude")
418 opt_OmitBlackHoling             = lookUp  SLIT("-dno-black-holing")
419 opt_OmitInterfacePragmas        = lookUp  SLIT("-fomit-interface-pragmas")
420
421 -- Simplifier switches
422 opt_SimplNoPreInlining          = lookUp SLIT("-fno-pre-inlining")
423         -- NoPreInlining is there just to see how bad things
424         -- get if you don't do it!
425 opt_SimplDoEtaReduction         = lookUp SLIT("-fdo-eta-reduction")
426 opt_SimplDoLambdaEtaExpansion   = lookUp SLIT("-fdo-lambda-eta-expansion")
427 opt_SimplCaseOfCase             = lookUp SLIT("-fcase-of-case")
428 opt_SimplCaseMerge              = lookUp SLIT("-fcase-merge")
429 opt_SimplPedanticBottoms        = lookUp SLIT("-fpedantic-bottoms")
430 opt_SimplExcessPrecision        = lookUp SLIT("-fexcess-precision")
431
432 -- Unfolding control
433 opt_UF_HiFileThreshold          = lookup_def_int "-funfolding-interface-threshold" (45::Int)
434 opt_UF_CreationThreshold        = lookup_def_int "-funfolding-creation-threshold"  (45::Int)
435 opt_UF_UseThreshold             = lookup_def_int "-funfolding-use-threshold"       (8::Int)     -- Discounts can be big
436 opt_UF_FunAppDiscount           = lookup_def_int "-funfolding-fun-discount"        (6::Int)     -- It's great to inline a fn
437 opt_UF_KeenessFactor            = lookup_def_float "-funfolding-keeness-factor"    (1.5::Float)
438 opt_UF_UpdateInPlace            = lookUp  SLIT("-funfolding-update-in-place")
439
440 opt_UF_CheapOp  = ( 1 :: Int)   -- Only one instruction; and the args are charged for
441 opt_UF_DearOp   = ( 4 :: Int)
442                         
443 opt_NoPruneDecls                = lookUp SLIT("-fno-prune-decls")
444 opt_NoPruneTyDecls              = lookUp SLIT("-fno-prune-tydecls")
445 opt_Static                      = lookUp SLIT("-static")
446 opt_Unregisterised              = lookUp SLIT("-funregisterised")
447 opt_Verbose                     = lookUp SLIT("-v")
448 \end{code}
449
450 %************************************************************************
451 %*                                                                      *
452 \subsection{List of static hsc flags}
453 %*                                                                      *
454 %************************************************************************
455
456 \begin{code}
457 isStaticHscFlag f =
458   f `elem` [
459         "-fauto-sccs-on-all-toplevs",
460         "-fauto-sccs-on-exported-toplevs",
461         "-fauto-sccs-on-individual-cafs",
462         "-fauto-sccs-on-dicts",
463         "-fscc-profiling",
464         "-fticky-ticky",
465         "-fall-strict",
466         "-fdicts-strict",
467         "-fgenerics",
468         "-firrefutable-tuples",
469         "-fnumbers-strict",
470         "-fparallel",
471         "-fsmp",
472         "-fsemi-tagging",
473         "-ffoldr-build-on",
474         "-flet-no-escape",
475         "-funfold-casms-in-hi-file",
476         "-fusagesp-on",
477         "-funbox-strict-fields",
478         "-femit-extern-decls",
479         "-fglobalise-toplev-names",
480         "-fgransim",
481         "-fignore-asserts",
482         "-fignore-interface-pragmas",
483         "-fno-hi-version-check",
484         "-fno-implicit-prelude",
485         "-dno-black-holing",
486         "-fomit-interface-pragmas",
487         "-fno-pre-inlining",
488         "-fdo-eta-reduction",
489         "-fdo-lambda-eta-expansion",
490         "-fcase-of-case",
491         "-fcase-merge",
492         "-fpedantic-bottoms",
493         "-fexcess-precision",
494         "-funfolding-update-in-place",
495         "-freport-compile",
496         "-fno-prune-decls",
497         "-fno-prune-tydecls",
498         "-static",
499         "-funregisterised",
500         "-v" ]
501   || any (flip prefixMatch f) [
502         "-fcontext-stack",
503         "-fliberate-case-threshold",
504         "-fhi-version=",
505         "-fhistory-size",
506         "-funfolding-interface-threshold",
507         "-funfolding-creation-threshold",
508         "-funfolding-use-threshold",
509         "-funfolding-fun-discount",
510         "-funfolding-keeness-factor"
511      ]
512 \end{code}
513
514 %************************************************************************
515 %*                                                                      *
516 \subsection{Switch ordering}
517 %*                                                                      *
518 %************************************************************************
519
520 These things behave just like enumeration types.
521
522 \begin{code}
523 instance Eq SimplifierSwitch where
524     a == b = tagOf_SimplSwitch a ==# tagOf_SimplSwitch b
525
526 instance Ord SimplifierSwitch where
527     a <  b  = tagOf_SimplSwitch a <# tagOf_SimplSwitch b
528     a <= b  = tagOf_SimplSwitch a <=# tagOf_SimplSwitch b
529
530
531 tagOf_SimplSwitch (SimplInlinePhase _)          = _ILIT(1)
532 tagOf_SimplSwitch (MaxSimplifierIterations _)   = _ILIT(2)
533 tagOf_SimplSwitch DontApplyRules                = _ILIT(3)
534 tagOf_SimplSwitch SimplLetToCase                = _ILIT(4)
535 tagOf_SimplSwitch NoCaseOfCase                  = _ILIT(5)
536
537 -- If you add anything here, be sure to change lAST_SIMPL_SWITCH_TAG, too!
538
539 lAST_SIMPL_SWITCH_TAG = 5
540 \end{code}
541
542 %************************************************************************
543 %*                                                                      *
544 \subsection{Switch lookup}
545 %*                                                                      *
546 %************************************************************************
547
548 \begin{code}
549 isAmongSimpl :: [SimplifierSwitch] -> SimplifierSwitch -> SwitchResult
550 isAmongSimpl on_switches                -- Switches mentioned later occur *earlier*
551                                         -- in the list; defaults right at the end.
552   = let
553         tidied_on_switches = foldl rm_dups [] on_switches
554                 -- The fold*l* ensures that we keep the latest switches;
555                 -- ie the ones that occur earliest in the list.
556
557         sw_tbl :: Array Int SwitchResult
558         sw_tbl = (array (0, lAST_SIMPL_SWITCH_TAG) -- bounds...
559                         all_undefined)
560                  // defined_elems
561
562         all_undefined = [ (i, SwBool False) | i <- [0 .. lAST_SIMPL_SWITCH_TAG ] ]
563
564         defined_elems = map mk_assoc_elem tidied_on_switches
565     in
566     -- (avoid some unboxing, bounds checking, and other horrible things:)
567 #if __GLASGOW_HASKELL__ < 405
568     case sw_tbl of { Array bounds_who_needs_'em stuff ->
569 #else
570     case sw_tbl of { Array _ _ stuff ->
571 #endif
572     \ switch ->
573         case (indexArray# stuff (tagOf_SimplSwitch switch)) of
574 #if __GLASGOW_HASKELL__ < 400
575           Lift v -> v
576 #elif __GLASGOW_HASKELL__ < 403
577           (# _, v #) -> v
578 #else
579           (# v #) -> v
580 #endif
581     }
582   where
583     mk_assoc_elem k@(MaxSimplifierIterations lvl)
584         = (iBox (tagOf_SimplSwitch k), SwInt lvl)
585     mk_assoc_elem k@(SimplInlinePhase n)
586         = (iBox (tagOf_SimplSwitch k), SwInt n)
587     mk_assoc_elem k
588         = (iBox (tagOf_SimplSwitch k), SwBool True) -- I'm here, Mom!
589
590     -- cannot have duplicates if we are going to use the array thing
591     rm_dups switches_so_far switch
592       = if switch `is_elem` switches_so_far
593         then switches_so_far
594         else switch : switches_so_far
595       where
596         sw `is_elem` []     = False
597         sw `is_elem` (s:ss) = (tagOf_SimplSwitch sw) ==# (tagOf_SimplSwitch s)
598                             || sw `is_elem` ss
599 \end{code}
600
601 Default settings for simplifier switches
602
603 \begin{code}
604 defaultSimplSwitches = [MaxSimplifierIterations 1]
605 \end{code}
606
607 %************************************************************************
608 %*                                                                      *
609 \subsection{Misc functions for command-line options}
610 %*                                                                      *
611 %************************************************************************
612
613
614 \begin{code}
615 switchIsOn :: (switch -> SwitchResult) -> switch -> Bool
616
617 switchIsOn lookup_fn switch
618   = case (lookup_fn switch) of
619       SwBool False -> False
620       _            -> True
621
622 intSwitchSet :: (switch -> SwitchResult)
623              -> (Int -> switch)
624              -> Maybe Int
625
626 intSwitchSet lookup_fn switch
627   = case (lookup_fn (switch (panic "intSwitchSet"))) of
628       SwInt int -> Just int
629       _         -> Nothing
630 \end{code}
631
632 \begin{code}
633 startsWith :: String -> String -> Maybe String
634 -- startsWith pfx (pfx++rest) = Just rest
635
636 startsWith []     str = Just str
637 startsWith (c:cs) (s:ss)
638   = if c /= s then Nothing else startsWith cs ss
639 startsWith  _     []  = Nothing
640
641 endsWith  :: String -> String -> Maybe String
642 endsWith cs ss
643   = case (startsWith (reverse cs) (reverse ss)) of
644       Nothing -> Nothing
645       Just rs -> Just (reverse rs)
646 \end{code}