[project @ 1997-03-14 08:02:40 by simonpj]
[nofib.git] / real / hpg / Main.lhs
1 % GenProg.lhs - program generation module for the HPG
2
3 % @(#)GenProg.lhs       1.20 dated 92/07/20 at 17:30:37
4
5 % Crown Copyright 1992
6
7 \section{Generating the program}
8 \label{genprog}
9
10 This module gathers the others together to generate and print the program.
11 \begin{haskell}
12
13 > module Main (
14 >     main
15 >     ) where
16
17 > import Config
18 > import Types
19 > import Env
20 > import Utils
21 > import GenType
22 > import GenVal
23 > import GenExp
24 > import System -- 1.3 
25 > import IO     -- 1.3
26
27 \end{haskell}
28
29 \prog{main} is the name of the main \HPG\ function.
30 The Haskell report requires that the entry point to the program executable
31 is called \prog{main} and is of type \prog{IO ()e}.
32 \begin{haskell}
33
34 > main :: IO ()
35 > main  =  do
36 >   argv <- getArgs
37 >   parse_args defaultArgs (unlines argv)
38
39 \end{haskell}
40
41 The data type \prog{Args} is used to package up the command line arguments
42 and give their types.
43 \begin{haskell}
44
45 > data Args  =  MkArgs (Int,Int,Int) Int Int Int Int Int String Output
46 >               deriving ()
47
48 \end{haskell}
49
50 The parameters to the program generator, and their command line flags, are:
51 \begin{enumerate}
52 \item A 3-tuple of seeds for the random number generator --- \prog{s}.
53 \item The number of type declarations to be generated and their
54     depth --- \prog{nt} and \prog{dt} respectively.
55 \item The number of value declarations to be generated and their
56     maximum depth --- \prog{nv} and \prog{dv} respectively.
57 \item The depth of the expressions to be generated --- \prog{de}.
58 \item A module name, \prog{mn}, for the output program.
59 \item A stream, \prog{op}, to which the program will be written.
60 \end{enumerate}
61
62 The default values of these parameters are given by \prog{defaultArgs}.
63 \begin{haskell}
64
65 > defaultArgs :: Args
66 > defaultArgs  =  MkArgs (9807,65,32975) 4 4 4 4 4 "Main" default_output
67
68 \end{haskell}
69
70 \prog{parse\_args} parses values passed to \prog{hpg} from the command line.
71 It is edited from output produced by \prog{mkhprog}, a command line parser
72 generator (see~\cite{north} for further details).
73 \begin{haskell}
74
75 > parse_args :: Args -> String -> IO ()
76 > parse_args (MkArgs x1 x2 x3 x4 x5 x6 x7 x8) ('-':'s':rest)
77 >     =  readval reads
78 >        (\val -> parse_args (MkArgs val x2 x3 x4 x5 x6 x7 x8)) rest
79 > parse_args (MkArgs x1 x2 x3 x4 x5 x6 x7 x8) ('-':'n':'t':rest)
80 >     =  readval reads
81 >        (\val -> parse_args (MkArgs x1 val x3 x4 x5 x6 x7 x8)) rest
82 > parse_args (MkArgs x1 x2 x3 x4 x5 x6 x7 x8) ('-':'d':'t':rest)
83 >     =  readval reads
84 >        (\val -> parse_args (MkArgs x1 x2 val x4 x5 x6 x7 x8)) rest
85 > parse_args (MkArgs x1 x2 x3 x4 x5 x6 x7 x8) ('-':'n':'v':rest)
86 >     =  readval reads
87 >        (\val -> parse_args (MkArgs x1 x2 x3 val x5 x6 x7 x8)) rest
88 > parse_args (MkArgs x1 x2 x3 x4 x5 x6 x7 x8) ('-':'d':'v':rest)
89 >     =  readval reads
90 >        (\val -> parse_args (MkArgs x1 x2 x3 x4 val x6 x7 x8)) rest
91 > parse_args (MkArgs x1 x2 x3 x4 x5 x6 x7 x8) ('-':'d':'e':rest)
92 >     =  readval reads
93 >        (\val -> parse_args (MkArgs x1 x2 x3 x4 x5 val x7 x8)) rest
94 > parse_args (MkArgs x1 x2 x3 x4 x5 x6 x7 x8) ('-':'m':rest)
95 >     =  readstring (\str -> parse_args (MkArgs x1 x2 x3 x4 x5 x6 str x8)) rest
96 > parse_args (MkArgs x1 x2 x3 x4 x5 x6 x7 x8) ('-':'o':rest)
97 >     =  readstring (\str -> parse_args
98 >                         (MkArgs x1 x2 x3 x4 x5 x6 x7 (set_output str))) rest
99 > parse_args (MkArgs x1 x2 x3 x4 x5 x6 x7 x8) ""
100 >     =  hpg x1 x2 x3 x4 x5 x6 x7 x8
101 > parse_args (MkArgs x1 x2 x3 x4 x5 x6 x7 x8) _
102 >     =  usage defaultArgs
103
104 \end{haskell}
105
106 \prog{hpg s nt dt nv dv de mn} generates a program with features as
107 described above.
108 It prints to the given output stream first a header giving the \HPG\ version
109 number and the supplied parameters, and then the generated program.
110 \begin{haskell}
111
112 > hpg :: (Int, Int, Int) -> Int -> Int -> Int -> Int -> Int -> String
113 >        -> Output -> Answer
114 > hpg s nt dt nv dv de mn op
115 >     =  print_str (head "")
116 >                  (gen_types max_vnts max_flds nt dt c1) (make_Env s op)
117 >        where
118 >        c1     =  gen_vals nv dv c2
119 >        c2     =  gen_exps de print_program
120 >        head   =  showString "-- HPG version " . version
121 >                  . newline
122 >                  . showString "-- Output from hpg "
123 >                  . sep_list space id
124 >                             [shows s, shows nt, shows dt, shows nv, shows dv,
125 >                              shows de]
126 >                  . newline
127 >                  . sep_list newline id [shead, thead, vhead, ehead]
128 >                  . newline . newline . mhead . newline . newline
129 >        shead  =  showString "-- Random number generator seeds: " . shows s
130 >        thead  =  showString "-- " . shows nt . showString " types, of depth "
131 >                  . shows dt
132 >        vhead  =  showString "-- " . shows nv . showString " values, of depth "
133 >                  . shows dv
134 >        ehead  =  showString "-- Expression depth: " . shows de
135 >        mhead  =  mod_name . space . showString mn . space . lbrack
136 >                  . main_name . rbrack . space . where_name . space . lbrace
137
138 \end{haskell}
139
140 \subsection{Printing programs}
141
142 This section deals with printing of the generated program.
143
144 \prog{print\_program vnes} prints a program consisting of the type
145 and value declarations in the environment, followed by a test of the
146 equivalence of the (value name, expression) pairs in \prog{vnes}.
147 \begin{haskell}
148
149 > print_program :: Xscont (Val_name, Expression)
150 > print_program vnes
151 >     =  get_all_type_decls (\tds -> get_all_val_decls (\vds ->
152 >            print_str (split_str line_len
153 >                ((sep_list dsep id (map showsType_decl tds
154 >                                    ++ map showsVal_decl vds)
155 >                 . dsep ) ""))
156 >                (print_test vnes)))
157 >        where
158 >        dsep  =  decl_sep . newline
159
160
161 \end{haskell}
162
163 \prog{print\_test vnes} prints a function, called \prog{main}, which prints
164 a list of \prog{bool}, one for each (value name, expression) pair
165 in \prog{vnes}.
166 The value of the \prog{bool} corresponding to \prog{(vn,e)} is
167 \prog{vn = e}.
168 \begin{haskell}
169
170 > print_test :: Xscont (Val_name, Expression)
171 > print_test vnes
172 >     =  print_str (split_str line_len
173 >                             ((main_name . val_def . showString print_name
174 >                               . space . lsq
175 >                               . sep_list list_separator showspair vnes . rsq
176 >                               . newline . rbrace)
177 >                              "")) finish
178 >        where
179 >        showspair (vn, e)  =  showString vn . space . showString eq_name
180 >                              . space . shows e
181
182 \end{haskell}
183
184 \subsection{Auxiliary functions}
185 This section contains the auxiliary functions used in parsing command
186 line arguments.
187 The functions are generated by \prog{mkhprog} (see~\cite{north} for
188 further details).
189
190 \prog{readstring} reads a string from the command line.
191 \begin{haskell}
192
193 > readstring :: (String -> String -> IO ()) -> String -> IO ()
194 > readstring f ""  =  f "" ""
195 > readstring f cs@(c:cs')
196 >     =  f s t
197 >        where
198 >        st      =  if c == '\n' then cs' else cs
199 >        (s,t1)  =  span ((/=) '\n') st
200 >        t       =  if t1 == "" then t1 else (tail t1)
201
202 \end{haskell}
203
204 \prog{readval} reads a value of arbitrary type from the command line.
205 It is used for reading integers and the random number generator seed
206 values.
207 \begin{haskell}
208
209 > readval :: (Read a) => ReadS a -> (a -> String -> IO ()) -> String
210 >                        -> IO ()
211 > readval readsfn f str
212 >     =  case thing of
213 >            []    -> usage defaultArgs
214 >            (_:_) -> f val (if str' == "" then str' else (tail str'))
215 >        where
216 >        thing        =  readsfn str
217 >        (val, str')  =  head thing
218
219 \end{haskell}
220
221 \prog{usage} is called if the command line contains invalid flags or values.
222 It prints a message giving a template for usage of \prog{hpg}.
223 \begin{haskell}
224
225 > usage :: Args -> IO ()
226 > usage (MkArgs s nt dt nv dv de mn _)
227 >     =  hPutStr stderr
228 >        ("Usage: hpg [-s (Int,Int,Int)] [-nt Int] [-dt Int] \
229 >                    \[-nv Int] [-dv Int] [-de Int] [-m String] [-o String]\n\
230 >         \    -s   random number generator seeds (default " ++ show s ++ ")\n\
231 >         \    -nt  number of types to be generated (" ++ show nt ++ ")\n\
232 >         \    -dt  depth of generated types (" ++ show dt ++ ")\n\
233 >         \    -nv  number of values to be generated (" ++ show nv ++ ")\n\
234 >         \    -dv  depth of values to be generated (" ++ show dv ++ ")\n\
235 >         \    -de  depth of expressions to be generated (" ++ show de ++ ")\n\
236 >         \    -m   output module name (" ++ mn ++ ")\n\
237 >         \    -o   output file name (stdout)\n")
238
239 \end{haskell}