/*
* Reference ETL Parser for Java
* Copyright (c) 2000-2009 Constantine A Plotnikov
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.sf.etl.parsers.internal.term_parser.compiler.nodes;
import java.util.HashSet;
import java.util.ListIterator;
import java.util.Set;
import net.sf.etl.parsers.internal.term_parser.compiler.StateMachineBuilder;
import net.sf.etl.parsers.internal.term_parser.states.LookAheadSet;
import net.sf.etl.parsers.internal.term_parser.states.PhraseKindChoice;
import net.sf.etl.parsers.internal.term_parser.states.ReportErrorState;
import net.sf.etl.parsers.internal.term_parser.states.State;
import net.sf.etl.parsers.internal.term_parser.states.buildtime.NopState;
/**
* This node represents first choice construct. This construct tries to select
* the first node, and than the second node.
*
* @author const
*
*/
public class FirstChoiceNode extends GroupNode {
/**
* A constructor
*/
public FirstChoiceNode() {
// do nothing
}
/**
* {@inheritDoc}
*/
@Override
public State buildStates(StateMachineBuilder b, State normalExit,
State errorExit) {
final HashSet<StateMachineBuilder> visitedSet = new HashSet<StateMachineBuilder>();
State exit;
final LookAheadSet choiceLa = buildLookAhead(new HashSet<StateMachineBuilder>());
if (choiceLa.containsEmpty()) {
exit = normalExit;
} else {
exit = new ReportErrorState(errorExit,
"syntax.UnexpectedToken.expectingTokens",
new Object[] { choiceLa.toString() });
}
// note that later variants will be overridden the more earlier ones
for (ListIterator<Node> i = nodes().listIterator(nodes().size()); i
.hasPrevious();) {
Node node = i.previous();
exit = new NopState(exit);
exit = new PhraseKindChoice(exit);
final State state = node.buildStates(b, normalExit, errorExit);
final LookAheadSet la = node.buildLookAhead(visitedSet);
la.buildChoiceStates((PhraseKindChoice) exit, state);
}
return exit;
}
/**
* {@inheritDoc}
*/
@Override
protected boolean calcMatchesEmpty() {
assert nodes().size() < 2 : "First choice node must have at least two alternative";
for (final Node node : nodes()) {
if (node.matchesEmpty()) {
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
protected LookAheadSet createLookAhead(
Set<StateMachineBuilder> visitedBuilders) {
assert nodes().size() < 2 : "First choice node must have at least two alternative";
final LookAheadSet rc = new LookAheadSet();
for (final Node node : nodes()) {
rc.addAll(node.buildLookAhead(visitedBuilders));
}
return rc;
}
}