home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / utilities / h / hugs / lhs / literate < prev   
Encoding:
Text File  |  1995-02-14  |  4.2 KB  |  104 lines

  1. Literate comments
  2. -----------------
  3.  
  4. [This file contains an executable version of the program for
  5. processing literate scripts that appears in Appendix C of the Haskell
  6. report, version 1.2.]
  7.  
  8. Many Haskell implementations support the ``literate comment''
  9. convention, first developed by Richard Bird and Philip Wadler for
  10. Orwell, and inspired in turn by Donald Knuth's ``literate programming''.
  11. The convention is not part of the Haskell language, but it is
  12. supported by the implementations known to us (Chalmers, Glasgow,
  13. and Yale).
  14.  
  15. The literate style encourages comments by making them the default.
  16. A line in which ">" is the first character is treated as part of
  17. the program; all other lines are comment.  Within the program part,
  18. the usual "--" and "{- -}" comment conventions may still be used.
  19. To capture some cases where one omits an ">" by mistake, it is an
  20. error for a program line to appear adjacent to a non-blank comment
  21. line, where a line is taken as blank if it consists only of
  22. whitespace.
  23.  
  24. By convention, the style of comment is indicated by the file
  25. extension, with ".hs" indicating a usual Haskell file, and ".lhs"
  26. indicating a literate Haskell file.
  27.  
  28. To make this precise, we present a literate Haskell program to
  29. convert literate programs.  The program expects a single name "file"
  30. on the command line, reads "file.lhs", and either writes the
  31. corresponding program to "file.hs" or prints error messages to
  32. "stderr". [ For Risc OS computers it reads "hs.file" and writes
  33. to "lhs.file".]
  34.  
  35. Each of the lines in a literate script is a program line, a blank
  36. line, or a comment line.  In the first case, the text is kept with
  37. the line.
  38.  
  39. > data Classified  =  Program String | Blank | Comment
  40.  
  41. In a literate program, program lines begins with a `>' character,
  42. blank lines contain only whitespace, and all other lines are comment
  43. lines.
  44.  
  45. > classify                              ::  String -> Classified
  46. > classify ('>':s)                      =   Program s
  47. > classify s  |  all isSpace s          =   Blank
  48. > classify s  |  otherwise              =   Comment
  49.  
  50. In the corresponding program, program lines have the leading `>'
  51. replaced by a leading space, to preserve tab alignments.
  52.  
  53. > unclassify                            ::  Classified -> String
  54. > unclassify (Program s)                =   " " ++ s
  55. > unclassify Blank                      =   ""
  56. > unclassify Comment                    =   ""
  57.  
  58. Process a literate program into error messages (if any) and the
  59. corresponding non-literate program.
  60.  
  61. > process       ::  String -> (String, String)
  62. > process lhs   =   (es, hs)
  63. >               where   cs  =  map classify (lines lhs)
  64. >                       es  =  unlines (errors cs)
  65. >                       hs  =  unlines (map unclassify cs)
  66.  
  67. Check that each program line is not adjacent to a comment line.
  68.  
  69. > errors        ::  [Classified] -> [String]
  70. > errors cs     =   concat (zipWith3 adjacent [1..] cs (tail cs))
  71.  
  72. Given a line number and a pair of adjacent lines, generate a list
  73. of error messages, which will contain either one entry or none.
  74.  
  75. > adjacent      ::  Int -> Classified -> Classified -> [String]
  76. > adjacent n (Program _) Comment  =  [message n "program" "comment"]
  77. > adjacent n Comment (Program _)  =  [message n "comment" "program"]
  78. > adjacent n this           next  =  []
  79.  
  80. > message n p c = "Line "++show n++": "++p++" line before "++c++" line."
  81.  
  82. Get one argument from the command line; complain if too many or
  83. too few.
  84.  
  85. > getArg  ::  FailCont -> StrCont -> Dialogue
  86. > getArg fail succ
  87. >         =   getArgs                                     fail (\strs ->
  88. >             case strs of
  89. >               [str] -> succ str
  90. >               _     -> fail (OtherError "Too many or too few args"))
  91.  
  92. The main program gets name "file", reads "file.lhs", and either
  93. writes the corresponding program to "file.hs" or appends error
  94. messages to "stderr". 
  95. [ For Risc OS computers it reads "hs.file" and writes to "lhs.file".]
  96.  
  97. > main    ::  Dialogue
  98. > main    =   getArg                                      exit (\file ->
  99. >             readFile (".lhs" ++ file)                   exit (\lhs ->
  100. >             case (process lhs) of
  101. >               ([],hs) -> writeFile (".hs" ++ file) hs   exit done
  102. >               (es,_)  -> appendChan stderr es           exit done))
  103.  
  104.