1
(**************************************************************************)
5
(* Fran�ois Pottier and Yann R�gis-Gianas, INRIA Rocquencourt *)
7
(* Copyright 2005 Institut National de Recherche en Informatique et *)
8
(* en Automatique. All rights reserved. This file is distributed *)
9
(* under the terms of the Q Public License version 1.0, with the *)
10
(* change described in file LICENSE. *)
12
(**************************************************************************)
14
(* A pretty-printer for [IL]. *)
21
(* This is the channel that is being written to. *)
25
(* If [raw_stretch_action] is set, then we print the semantic actions
26
as they are found into the original source code. *)
27
val raw_stretch_action: bool
29
(* This controls the way we print Objective Caml stretches (types and
30
semantic actions). We either surround them with #line directives
31
(for better error reports if the generated code is ill-typed) or
32
don't (for better readability). The value is either [None] -- do
33
not provide #line directives -- or [Some filename] -- do provide
34
them. [filename] is the name of the file that is being written
37
val locate_stretches: string option
41
(* ------------------------------------------------------------------------- *)
42
(* Dealing with newlines and indentation. *)
48
String.make maxindent ' '
56
(* [rawnl] is, in principle, the only place where writing a newline
57
character to the output channel is permitted. This ensures that the
58
line counter remains correct. But see also [stretch] and [typ0]. *)
66
output f whitespace 0 !indentation
68
let indent ofs producer f x =
69
let old_indentation = !indentation in
70
let new_indentation = old_indentation + ofs in
71
if new_indentation <= maxindent then
72
indentation := new_indentation;
75
indentation := old_indentation
77
(* This produces a #line directive. *)
79
let sharp f line file =
80
fprintf f "%t# %d \"%s\"%t" rawnl line file rawnl
82
(* ------------------------------------------------------------------------- *)
83
(* Printers of atomic elements. *)
99
output_string f "let rec "
102
output_string f "let "
105
output_string f "type "
108
output_string f "exception "
111
output_string f "and "
117
output_string f " | "
119
(* ------------------------------------------------------------------------- *)
122
let rec list elem sep f = function
126
fprintf f "%t%a%a" sep elem e (list elem sep) es
128
let rec typeparams p0 p1 f = function
132
fprintf f "%a " p0 param
134
fprintf f "(%a%a) " p1 param (list p1 comma) params
136
(* ------------------------------------------------------------------------- *)
137
(* Expression printer. *)
139
(* We use symbolic constants that stand for subsets of the
140
expression constructors. We do not use numeric levels
141
to stand for subsets, because our subsets do not form
142
a linear inclusion chain. *)
148
| AllButFunTryMatchSeq
149
| AllButLetFunTryMatch
150
| AllButLetFunTryMatchSeq
156
(* This computes the intersection of a subset with the
157
constraint "should not be a sequence". *)
159
let andNotSeq = function
164
| AllButFunTryMatchSeq ->
166
| AllButLetFunTryMatch
167
| AllButLetFunTryMatchSeq ->
168
AllButLetFunTryMatchSeq
177
(* This defines the semantics of subsets by relating
178
expressions with subsets. *)
191
| AllButFunTryMatchSeq
192
| AllButLetFunTryMatch
193
| AllButLetFunTryMatchSeq
202
| ELet ((PUnit, _) :: _, _) ->
206
| AllButFunTryMatchSeq
207
| AllButLetFunTryMatchSeq
215
| ELet (_ :: _, _) ->
218
| AllButLetFunTryMatch
219
| AllButLetFunTryMatchSeq
265
| ERecordAccess (_, _)
271
let rec exprlet k pes f e2 =
275
| (PUnit, e1) :: pes ->
276
fprintf f "%a%t%a" (exprk AllButLetFunTryMatch) e1 seminl (exprlet k pes) e2
277
| (PVar id1, EAnnot (e1, ts1)) :: pes ->
278
(* TEMPORARY current ocaml does not support type schemes here; drop quantifiers, if any *)
279
fprintf f "let %s : %a = %a in%t%a" id1 typ ts1.body (* scheme ts1 *) expr e1 nl (exprlet k pes) e2
280
| (PVar id1, EFun (ps1, e1)) :: pes ->
281
fprintf f "let %s%a = %a in%t%t%a" id1 (list pat0 space) ps1 (indent 2 expr) e1 nl nl (exprlet k pes) e2
282
| (p1, (ELet _ as e1)) :: pes ->
283
fprintf f "let %a =%a%tin%t%a" pat p1 (indent 2 expr) e1 nl nl (exprlet k pes) e2
285
fprintf f "let %a = %a in%t%a" pat p1 expr e1 nl (exprlet k pes) e2
291
exprk OnlyAppOrAtom f e
300
if Settings.comment then
301
fprintf f "(* %s *)%t%a" c nl (exprk k) e
304
| EPatComment (s, p, e) ->
305
if Settings.comment then
306
fprintf f "(* %s%a *)%t%a" s pat p nl (exprk k) e
311
| ERecordWrite (e1, field, e2) ->
312
fprintf f "%a.%s <- %a" atom e1 field (exprk (andNotSeq k)) e2
316
fprintf f "match %a with%a" expr e (branches k) brs
320
fprintf f "try%a%twith%a" (indent 2 expr) e nl (branches k) brs
321
| EIfThen (e1, e2) ->
322
fprintf f "if %a then%a" expr e1 (indent 2 (exprk (andNotSeq k))) e2
323
| EIfThenElse (e0, e1, e2) ->
324
fprintf f "if %a then%a%telse%a"
325
expr e0 (indent 2 (exprk AllButIfThenSeq)) e1 nl (indent 2 (exprk (andNotSeq k))) e2
327
fprintf f "fun%a ->%a" (list pat0 space) ps (indent 2 (exprk k)) e
328
| EApp (EVar op, [ e1; e2 ])
329
when op.[0] = '(' && op.[String.length op - 1] = ')' ->
330
let op = String.sub op 1 (String.length op - 2) in
331
fprintf f "%a %s %a" app e1 op app e2
333
fprintf f "%a%a" app e (list atom space) args
335
fprintf f "raise %a" atom e
337
fprintf f "Obj.magic %a" atom e
340
| EData (d, [ arg ]) ->
341
fprintf f "%s %a" d atom arg
342
| EData (d, arg :: args) ->
343
fprintf f "%s (%a%a)" d app arg (list app comma) args
347
stretch (X.raw_stretch_action) f action
356
fprintf f "\"%s\"" (String.escaped s)
361
| ETuple (e :: es) ->
362
fprintf f "(%a%a)" app e (list app comma) es
364
(* TEMPORARY current ocaml does not support type schemes here; drop quantifiers, if any *)
365
fprintf f "(%a : %a)" app e typ s.body (* should be scheme s *)
366
| ERecordAccess (e, field) ->
367
fprintf f "%a.%s" atom e field
369
fprintf f "{%a%t}" (indent 2 fields) fs nl
371
fprintf f "(%a)" expr e
373
and stretch raw f stretch =
374
let content = stretch.Stretch.stretch_content
375
and raw_content = stretch.Stretch.stretch_raw_content in
376
match X.locate_stretches with
378
sharp f stretch.Stretch.stretch_linenum stretch.Stretch.stretch_filename;
379
output_string f content;
380
line := !line + stretch.Stretch.stretch_linecount;
381
sharp f (!line + 2) basename;
382
output f whitespace 0 !indentation
384
output_string f (if raw then raw_content else content)
386
and branches k f = function
390
fprintf f "%t| %a" nl (branch k) br
392
fprintf f "%t| %a%a" nl (branch AllButFunTryMatch) br (branches k) brs
395
fprintf f "%a ->%a" pat br.branchpat (indent 4 (exprk k)) br.branchbody
397
and fields f = function
401
fprintf f "%a%a" field fl (list field seminl) fls
403
and field f (label, e) =
404
fprintf f "%s = %a" label app e
406
and pat0 f = function
419
| PTuple (p :: ps) ->
420
fprintf f "(%a%a)" pat1 p (list pat1 comma) ps
422
fprintf f "(%a : %a)" pat p typ t
424
fprintf f "(%a)" pat p
426
and pat1 f = function
427
| PData (d, [ arg ]) ->
428
fprintf f "%s %a" d pat0 arg
429
| PData (d, arg :: args) ->
430
fprintf f "%s (%a%a)" d pat1 arg (list pat1 comma) args
436
and pat2 f = function
440
fprintf f "%a%a" pat2 p (list pat2 bar) ps
452
and typ0 f = function
453
| TypTextual (Stretch.Declared ocamltype) ->
454
(* Parentheses are necessary to avoid confusion between 1-ary
455
data constructor with n arguments and n-ary data constructor. *)
456
fprintf f "(%a)" (stretch true) ocamltype
457
| TypTextual (Stretch.Inferred t) ->
458
line := !line + LineCount.count 0 (Lexing.from_string t);
462
| TypApp (t, params) ->
463
fprintf f "%a%s" (typeparams typ0 typ) params t
465
fprintf f "(%a)" typ t
467
and typ1 f = function
472
| TypTuple (t :: ts) ->
473
fprintf f "%a%a" typ0 t (list typ0 times) ts
477
and typ2 f = function
478
| TypArrow (t1, t2) ->
479
fprintf f "%a -> %a" typ1 t1 typ2 t2
486
and scheme f scheme =
487
match scheme.quantifiers with
491
fprintf f "%a. %a" (list typevar space) qs typ scheme.body
493
(* ------------------------------------------------------------------------- *)
494
(* Toplevel definition printer. *)
496
let datavalparams f = function
499
| valparam :: valparams ->
500
fprintf f " of %a%a" typ valparam (list typ times) valparams
502
let datatypeparams f = function
506
fprintf f "(* %a*)" (list typ space) typs (* TEMPORARY not great *)
509
fprintf f " | %s%a%a" def.dataname datavalparams def.datavalparams datatypeparams def.datatypeparams
512
fprintf f " %s%s: %a"
513
(if def.modifiable then "mutable " else "")
517
let typerhs f = function
520
| TDefRecord (field :: fields) ->
521
fprintf f " = {%t%a%a%t}" nl fielddef field (list fielddef seminl) fields nl
525
fprintf f " = %a" (list datadef nl) defs
527
let typeconstraint f = function
531
fprintf f "%tconstraint %a = %a" nl typ t1 typ t2
534
fprintf f "%a%s%a%a%t%t"
535
(typeparams typevar typevar) def.typeparams
538
typeconstraint def.typeconstraint
541
let rec pdefs pdef sep1 sep2 f = function
545
fprintf f "%t%a%a" sep1 pdef def (pdefs pdef sep2 sep2) defs
547
let valdef f = function
548
| { valpat = PVar id; valval = EAnnot (e, ts) } ->
549
(* TEMPORARY current ocaml does not support type schemes here; drop quantifiers, if any *)
550
fprintf f "%s : %a =%a%t%t" id typ ts.body (* scheme ts *) (indent 2 expr) e nl nl
551
| { valpat = p; valval = e } ->
552
fprintf f "%a =%a%t%t" pat p (indent 2 expr) e nl nl
555
pdefs valdef letrec et
558
pdefs valdef letnonrec letnonrec
561
pdefs typedef keytyp et
564
fprintf f "%s%t%t" def.excname nl nl
569
let functorparams intf body b f params =
572
fprintf f "%a%!" body b
574
fprintf f "module Make%a%t%s%t%a%t%tend%t%!"
575
(list (stretch false) nl) params
576
nl (if intf then ": sig" else "= struct") nl
581
List.iter (stretch false f) p.prologue;
582
fprintf f "%a%a%a%a" excdefs p.excdefs typedefs p.typedefs nonrecvaldefs p.nonrecvaldefs valdefs p.valdefs;
583
List.iter (output_string f) p.postlogue
585
let valdecl f (x, ts) =
586
fprintf f "val %s: %a" x typ ts.body
589
fprintf f "%a%a%a%!" excdefs i.excdecls typedefs i.typedecls (list valdecl nl) i.valdecls
592
functorparams false program p X.f p.paramdefs
595
functorparams true interface i X.f i.paramdecls