package edu.berkeley.sbp;
import edu.berkeley.sbp.util.*;
import edu.berkeley.sbp.*;
import edu.berkeley.sbp.*;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import java.lang.ref.*;
/**
* an element which can produce one of several alternatives.
*
*
* Unlike the other Elements, Union is not immutable once
* constructed. To simulate this desirable feature, it is immutable
* once examined by taking its iterator or calling contains().
*/
public class Union extends Element implements Iterable {
private final String name;
private final boolean synthetic;
private boolean viewed = false;
private final List alternatives = new ArrayList();
public Union(String name) { this(name, false); }
/**
* Since every cycle in a non-degenerate grammar contains at
* least one Union, every instance of this class must be able to
* display itself in both "long form" (list of the long forms of
* its alternatives) and "short form" (some name).
*
* @param shortForm the "short form" display; for display purposes only
* @param synthetic if true, this Union's "long form" is "obvious" and should not be displayed when printing the grammar
*/
public Union(String name, boolean synthetic) {
this.name = name;
this.synthetic = synthetic;
}
public boolean contains(Sequence s) {
viewed = true;
return alternatives.contains(s);
}
/** iterator over this Union's Sequences */
public Iterator iterator() {
viewed = true;
return alternatives.iterator();
}
/** adds an alternative */
public void add(Sequence s) {
/*
FIXME
if (viewed)
throw new RuntimeException("attempt to add a Sequence to a Union that has already been examined:\n "+this);
*/
if (alternatives.contains(s)) return;
alternatives.add(s);
}
/** adds a one-element sequence */
public void add(Element e) {
add(Sequence.create(e));
}
// Epsilon Form //////////////////////////////////////////////////////////////////////////////
// FIXME
private Forest.Many epsilonForm = null;
Forest epsilonForm() {
if (epsilonForm != null) return epsilonForm;
epsilonForm = new Forest.Many();
for(Sequence s : this) {
// FIXME FIXME FIXME
if (new Walk.Cache().possiblyEpsilon(s))
epsilonForm.merge(s.epsilonForm());
}
return epsilonForm;
}
// Display //////////////////////////////////////////////////////////////////////////////
public String getName() {
if (name != null) return name;
return "(anon_union)";
}
public String toString() {
viewed = true;
if (name != null) return name;
StringBuffer sb = new StringBuffer();
sb.append("(");
bodyToString(sb, "", " | ");
sb.append(")");
return sb.toString();
}
/** display this union in long/expanded form */
public StringBuffer toString(StringBuffer sb) {
viewed = true;
if (synthetic) return sb;
boolean first = true;
String before = StringUtil.pad(15, getName()) + " = ";
if (alternatives.size()==0) {
sb.append(before);
} else {
bodyToString(sb,
before,
"\n" + StringUtil.pad(15, "") + " | ");
sb.append('\n');
}
return sb;
}
private void bodyToString(StringBuffer sb, String before, String between) {
viewed = true;
boolean first = true;
for(Sequence s : this) {
// FIXME: what to do here about printing out negated sequences?
sb.append(first ? before : between);
first = false;
sb.append(s.toString());
}
}
}