/**
 * Pretty-print an ATerm to a Box using the given pretty-print tables.
 *
 * @author Merijn de Jonge <mdjonge@cs.uu.nl>
 * @author Martin Bravenboer <martin.bravenboer@gmail.com>
 */
module stratego/gpp/AstToBox
imports
  stratego/gpp/PpTableIO
  stratego/gpp/Instantiate
  stratego/gpp/Util

strategies

  /**
   * Pretty-prints an ATerm to a Box using the given pretty-print tables.
   *
   * @param List(PpTable)
   * @type a -> Box
   */
  ast2abox(|pptables) =
      where(tbl := <pptable-make-hashtable> pptables)
    ; trm2abox(|tbl)
    ; if is-list then
        !HV([], <id>)
      end

strategies

  trm2abox(|tbl) =
       trm2abox-string(|tbl)
    <+ trm2abox-int(|tbl)
    <+ trm2abox-real(|tbl)
    <+ trm2abox-list(|tbl)
    <+ trm2abox-appl(|tbl)
    <+ log(|Error(),"Cannot rewrite to box: ", <id>)
       ; fail

  trm2abox-string(|tbl) =
    !S(<is-string>)

  trm2abox-real(|tbl) =
    !S(<is-real; real-to-string>)

  trm2abox-int(|tbl) =
    !S(<is-int; int-to-string>)

  trm2abox-list(|tbl) =
    is-list; map(trm2abox(|tbl))

  trm2abox-appl(|tbl) =
    ?f#(args)
    ; where(<length> args => arity)
    ; <pptable-get-log(|tbl)> (arity, [f]) => (_, template)
    ; ![f] => currentpath
    ; let narg2abox(|n) = arg2abox(|tbl, n, currentpath)
       in <nmap(narg2abox | 1)> args => aboxes
      end
    ; <gpp-instantiate(|aboxes)> template

/**
 * Path is a list.
 * First element is the constructor name (string)
 * 
 */
strategies

  /**
   * @param n     Integer: Argument index
   * @param path  Path of the parent node
   * @param arg   Any term
   *   
   * @todo Store get-symbol in the table.
   */
  arg2abox(|tbl, n, path) =
      ?arg
    ; ![n | path] => new_path
    ; ( <hashtable-get(|new_path)> tbl => (full_path, template)
        ; <symbol2abox(|tbl, <pptable-path-get-symbol> full_path, new_path, template)> arg
      <+ <trm2abox(|tbl)> arg
      )

strategies

  symbol2abox(|tbl, symbol, path, template) =
       ?alt(_, _)
       ; symbol2abox-alt(|tbl, path, template)
       
    <+ (?Some(_) + None())
       ; symbol2abox-opt(|tbl, path, template)
    
    <+ where(!symbol; (?"iter" + ?"iter-star"))
       ; symbol2abox-iter(|tbl, path, template)
       
    <+ where(!symbol; (?"iter-sep" + ?"iter-star-sep"))
       ; symbol2abox-iter-sep(|tbl, path, template)
    
    <+ where(!symbol => "seq")
       ; symbol2abox-seq(|tbl, path, template)

  /**
   * Rule to format alt(n,[]), with empty list of arguments
   */
  symbol2abox-alt(|tbl, path, template) =
    ?alt(n, [])
    ; <gpp-instantiate(|[])> [<index(|n)> template]

  /**
   * Rule to format alt(n,[arg]), with non-empty list of arguments
   */
  symbol2abox-alt(|tbl, path, template) =
    ?alt(n, [arg])
    ; <arg2abox(|tbl, n, path)> arg => abox
    ; <gpp-instantiate(|[abox])> [<index(|n)> template]
   
  /**
   * Rule to format optional: Some(x)
   */
  symbol2abox-opt(|tbl, path, template) =
    ?Some(<id>)
    ; arg2abox(|tbl, 1, path) => abox
    ; <gpp-instantiate(|[abox])> template

  /**
   * Rule to format optinal: None
   */
  symbol2abox-opt(|tbl, path, template) =
    ?None(); ![]

  /**
   * Rule to format iter and iter-star list
   */
  symbol2abox-iter(|tbl, path, template) =
      map(arg2abox(|tbl, 1, path)) => abox
    ; <gpp-instantiate(| [abox])> template

  /**
   * Rule to format iter-sep and iter-star-sep list
   */
  symbol2abox-iter-sep(|tbl, path, template) =
    map(arg2abox(|tbl, 1, path))
    ; if <collect-om(?S(_), conc)> template => [_] then
        rec x(
           \ []     -> []  \
        <+ \ [e]    -> [e] \
        <+ \ [e | xs] -> [e, e| <x> xs] \
        )
      end 
    ; gpp-instantiate-sep-list(|template)

  /**
   * Rule ro format sequences
   */
  symbol2abox-seq(|tbl, path, template) =
    TupleToList
    ; nzip( \ (n, t) -> <arg2abox(|tbl, n, path)> t \ ) => abox
    ; <gpp-instantiate(|abox)> template

rules

  /**
   * Build a sepator list by formatting its elements which are numbered
   * tuples. Odd entries denote symbols and are formatted using the path
   * <path>.1; even entries denote separators and are formatted using the path
   * <path>.2
  BuildSepList(|path) :
    (n, s) -> abox
    where
      if <even> n then !1 else !1 end
      ; <arg2abox> (<id>, path, s) => abox
   */

  /**
   * The symbol of the SDF production is contained in the path of
   * pretty-print rules. Get-symbol returns the last symbol of a path.
   */
  pptable-path-get-symbol :
    Path(cons-name, selectors) -> symbol
    where
      <at-last(?[selector(_, symbol)])> selectors