--- /dev/null
+(**************************************************************************)
+(* *)
+(* Menhir *)
+(* *)
+(* François Pottier, INRIA Rocquencourt *)
+(* Yann Régis-Gianas, PPS, Université Paris Diderot *)
+(* *)
+(* Copyright 2005-2008 Institut National de Recherche en Informatique *)
+(* et en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0, with the change *)
+(* described in file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+(* A debugging pretty-printer for [IL]. Newlines are used liberally, so as to
+ facilitate diffs. *)
+
+open IL
+open Printf
+
+module Make (X : sig
+
+ (* This is the channel that is being written to. *)
+
+ val f: out_channel
+
+end) = struct
+
+(* ------------------------------------------------------------------------- *)
+(* XML-style trees. *)
+
+type tree =
+ | Node of string * tree list
+
+let node label ts =
+ Node (label, ts)
+
+(* ------------------------------------------------------------------------- *)
+(* Dealing with newlines and indentation. *)
+
+let maxindent =
+ 120
+
+let whitespace =
+ String.make maxindent ' '
+
+let indentation =
+ ref 0
+
+let line =
+ ref 1
+
+(* [rawnl] is, in principle, the only place where writing a newline
+ character to the output channel is permitted. This ensures that the
+ line counter remains correct. But see also [stretch] and [typ0]. *)
+
+let rawnl f =
+ incr line;
+ output_char f '\n'
+
+let nl f =
+ rawnl f;
+ output f whitespace 0 !indentation
+
+let indent ofs producer f x =
+ let old_indentation = !indentation in
+ let new_indentation = old_indentation + ofs in
+ if new_indentation <= maxindent then
+ indentation := new_indentation;
+ nl f;
+ producer f x;
+ indentation := old_indentation
+
+(* ------------------------------------------------------------------------- *)
+(* Tree printers. *)
+
+let rec print_tree f = function
+ | Node (label, []) ->
+ output_char f '<';
+ output_string f label;
+ output_char f '/';
+ output_char f '>';
+ nl f
+ | Node (label, ts) ->
+ output_char f '<';
+ output_string f label;
+ output_char f '>';
+ indent 2 print_trees f ts;
+ output_char f '<';
+ output_char f '/';
+ output_string f label;
+ output_char f '>';
+ nl f
+
+and print_trees f = function
+ | [] ->
+ ()
+ | t :: ts ->
+ print_tree f t;
+ print_trees f ts
+
+(* ------------------------------------------------------------------------- *)
+(* Expression-to-tree converter. *)
+
+let rec expr e =
+ match e with
+ | EComment (c, e) ->
+ node "comment" [ string c; expr e ]
+ | EPatComment (s, p, e) ->
+ node "patcomment" [ string s; pat p; expr e ]
+ | ELet (pes, e2) ->
+ node "let" ( patexprs pes @ [ expr e2 ])
+ | ERecordWrite (e1, field, e2) ->
+ node "recordwrite" [ expr e1; string field; expr e2 ]
+ | EMatch (e, brs) ->
+ node "match" ( expr e :: branches brs )
+ | ETry (e, brs) ->
+ node "try" ( expr e :: branches brs )
+ | EIfThen (e1, e2) ->
+ node "ifthen" [ expr e1; expr e2 ]
+ | EIfThenElse (e0, e1, e2) ->
+ node "ifthenelse" [ expr e0; expr e1; expr e2 ]
+ | EFun (ps, e) ->
+ node "fun" ( pats ps @ [ expr e ])
+ | EApp (e, args) ->
+ node "app" ( expr e :: exprs args )
+ | ERaise e ->
+ node "raise" [ expr e ]
+ | EMagic e ->
+ node "magic" [ expr e ]
+ | ERepr e ->
+ node "repr" [ expr e ]
+ | EData (d, args) ->
+ node "data" ( string d :: exprs args )
+ | EVar v ->
+ node "var" [ string v ]
+ | ETextual action ->
+ node "text" [ stretch action ]
+ | EUnit ->
+ node "unit" []
+ | EIntConst k ->
+ node "int" [ int k ]
+ | EStringConst s ->
+ node "string" [ string s ]
+ | ETuple es ->
+ node "tuple" ( exprs es )
+ | EAnnot (e, s) ->
+ node "annot" [ expr e; scheme s ]
+ | ERecordAccess (e, field) ->
+ node "recordaccess" [ expr e; string field ]
+ | ERecord fs ->
+ node "record" (fields fs)
+ | EArray fs ->
+ node "array" (exprs fs)
+ | EArrayAccess (e1, e2) ->
+ node "arrayaccess" [ expr e1; expr e2 ]
+
+and exprs es =
+ List.map expr es
+
+and stretch stretch =
+ string stretch.Stretch.stretch_content
+
+and branches brs =
+ List.map branch brs
+
+and branch br =
+ node "branch" [ pat br.branchpat; expr br.branchbody ]
+
+and fields fs =
+ List.map field fs
+
+and field (label, e) =
+ node "field" [ string label; expr e ]
+
+and pats ps =
+ List.map pat ps
+
+and pat = function
+ | PUnit ->
+ node "punit" []
+ | PWildcard ->
+ node "pwildcard" []
+ | PVar x ->
+ node "pvar" [ string x ]
+ | PTuple ps ->
+ node "ptuple" (pats ps)
+ | PAnnot (p, t) ->
+ node "pannot" [ pat p; typ t ]
+ | PData (d, args) ->
+ node "pdata" (string d :: pats args)
+ | PRecord fps ->
+ node "precord" (fpats fps)
+ | POr ps ->
+ node "por" (pats ps)
+
+and fpats fps =
+ List.map fpat fps
+
+and fpat (_, p) =
+ pat p
+
+and patexprs pes =
+ List.map patexpr pes
+
+and patexpr (p, e) =
+ node "patexpr" [ pat p; expr e ]
+
+and string s =
+ node s []
+
+and int k =
+ node (string_of_int k) []
+
+and bool b =
+ node (if b then "true" else "false") []
+
+and scheme s =
+ string "omitted" (* TEMPORARY to be completed, someday *)
+
+and typ t =
+ string "omitted" (* TEMPORARY to be completed, someday *)
+
+(* ------------------------------------------------------------------------- *)
+(* Convert to a tree, then print the tree. *)
+
+let expr e =
+ print_tree X.f (expr e)
+
+end
+