// repetition.beh -- Repetition conversion
// $Id: repetition.beh,v 1.4 2003/01/22 20:34:33 dougo Exp $

// What we want to do is convert the repetition class definition
//
//    Foo_List ~ "a" Foo { (@ lookahead @) "b" Foo "c" } "d".
//
// into two construction class definitions, a container
//
//    Foo_List = "a" <first> Nonempty_Foo_List "d".
//
// and a link node
//
//    Nonempty_Foo_List = <it> Foo
//		[ (@ lookahead @) "b" <next> Nonempty_Foo_List "c" ].
//
// If the repetition class is possibly empty (i.e. Foo_List ~ { Foo }),
// then the <first> part of the new Foo_List class is optional, and
// the lookahead is added in this optional part as well.

ClassGraph {
  /** Convert all repetition classes to (pairs of) construction
      classes with recursive edges. */
  void convertRepetition()
    via RepetitionClass
    bypassing -> *,nonempty,*
    to { PlainSyntax, PrintIndent, PrintUnindent, PrintSkip, PrintSpace,
	 ClassName }
  {
    {{
      ClassGraph cg;
      ClassName classname;
      String container, linknode, linknodename;
      boolean inRepeatedPart;
    }}
    before ClassGraph {{ cg = host; }}
    before ClassDef {{
      classname = host.get_classname();
      container = null;
    }}
    before RepetitionClass {{
      container = "= ";
      linknodename = RepetitionClass.makeLinknodeName(classname);
    }}
    before Syntax {{
      if (inRepeatedPart)
	linknode += host + " ";
      else
	container += host + " ";
    }}
    before RepeatedPart {{
      String first = "<first> " + linknodename;
      inRepeatedPart = true;
      linknode = "[ ";
      LocalLookahead l = host.get_locallookahead();
      if (l != null) {
	linknode += l + " ";
      }
      if (host.get_nonempty() == null) {
	// The repetition is possibly empty; make the link node optional.
	if (l != null) {
	  first = l + " " + first;
	}
	first = "[ " + first + " ] ";
      }
      container += first;
    }}
    before ClassName {{
      linknode = "= <it> " + host + " " + linknode
	       + "<next> " + linknodename + " ";
    }}
    after RepeatedPart {{
      linknode += "].";
      inRepeatedPart = false;
    }}
    after RepetitionClass {{
      container += ".";
    }}
    after ClassDef {{
      if (container != null) {
	// Replace the repetition class with the new container class.
	host.set_classparts(ConstructionClass.parse(container));
	// Add the class definition for the new link node class.
	ClassDef linknodedef = host.deepCopy();
	linknodedef.set_paramclassname(ParamClassName.parse(linknodename));
	linknodedef.set_classparts(ConstructionClass.parse(linknode));
	linknodedef.set_eoftoken(null);
	cg.addClassDef(linknodedef);
      }
    }}
  }
}

RepetitionClass {
  static String makeLinknodeName(ClassName classname) {{
    return "Nonempty_" + classname;
  }}
}