(* This file defines how to print a CST as a plain string.

   The CST is printed on a single line; no pretty-printing takes place.

   A space is used to separate tokens.

   Because this code makes naive use of string concatenation, it is not
   efficient: its time complexity is quadratic. Furthermore, the type
   [string] does not allow keeping track of fragility (that is, whether
   concatenation must or need not insert a space). For these reasons, it is
   recommended to replace [string] with an abstract data type that supports
   constant-time concatenation and keeps track of fragility; see Document
   and CST2Document. *)

let is_empty (s : string) =
  String.length s = 0

let is_newline (s : string) =
  String.length s = 1 && s.[0] = '\n'

class print = object

  (* The class [Parser.CST.reduce], which is generated by Menhir,
     already contains most of the printing logic. All we have to
     do is to give concrete definitions of the virtual methods. *)
  inherit [string] Parser.CST.reduce

  (* The methods [zero], [cat], [text] are specific to our choice
     of [string] as the result type. *)

  method zero = ""

  method cat s1 s2 =
    (* A space is in general needed to separate tokens. However, to ensure
       that [zero] is a unit for [cat], we must check whether [s1] or [s2]
       is empty; in that case, no space is required. This is a bit ad hoc. *)
    if is_empty s1 then s2
    else if is_empty s2 then s1
    else if is_newline s1 || is_newline s2 then s1 ^ s2
    else s1 ^ " " ^ s2

  method text s = s

  (* The following methods define how the tokens [INT] and [EOL] are
     printed. The methods associated with all other tokens are already
     defined by Menhir, based on the token aliases that we have provided
     in [parser.mly]. *)

  method visit_INT i =
    Printf.sprintf "%d" i

  method visit_EOL =
    "\n"

end

(* The entry point. *)

let main (m : Parser.CST.main) : string =
  (new print)#visit_main m
