/*
* 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.Set;
import net.sf.etl.parsers.PhraseTokens;
import net.sf.etl.parsers.TermContext;
import net.sf.etl.parsers.Terms;
import net.sf.etl.parsers.internal.term_parser.compiler.StateMachineBuilder;
import net.sf.etl.parsers.internal.term_parser.states.AdvanceState;
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.ReportControl;
import net.sf.etl.parsers.internal.term_parser.states.ReportErrorState;
import net.sf.etl.parsers.internal.term_parser.states.SkipIgnorableState;
import net.sf.etl.parsers.internal.term_parser.states.State;
import net.sf.etl.parsers.internal.term_parser.states.UnreachableState;
/**
* A block node. This node usually directly invokes sequence of the nodes. Note
* that due to inheritance conflict
*
* @author const
*/
public class BlockNode extends AbstractTermContextScopeNode {
/**
* A constructor
*
* @param context
* a term context
*/
public BlockNode(TermContext context) {
super(context);
}
/**
* This method is not implemented here because the method
* {@link #buildStates(StateMachineBuilder, State, State)} is implemented.
* {@inheritDoc}
*/
@Override
protected State buildStartState(StateMachineBuilder b, State bodyStates,
State errorExit, State errorCloseState) {
assert false : "This methods are never called.";
return null;
}
/**
* This method is not implemented here because the method
* {@link #buildStates(StateMachineBuilder, State, State)} is implemented.
* {@inheritDoc}
*/
@Override
protected State buildEndState(StateMachineBuilder b, State normalExit,
State errorExit) {
assert false : "This methods are never called.";
return null;
}
/**
* {@inheritDoc}
*/
@Override
public State buildStates(StateMachineBuilder b, State normalExit,
State errorExit) {
// This method is implemented here because segment production
// cannot actually produce an error. So case for error handling is
// unclear. Even if segment terminator is missed, a segment and
// block terminate anyway. This error recovery is provided by phrase
// parser so it does not have to be checked here.
final State unreachable = new UnreachableState(
"Segment sequence never exits with error");
// --- compile end of block ---
State head = normalExit;
// after block end ignorable should be skipped
head = new SkipIgnorableState(head, true);
// advance to next token after block end
head = new AdvanceState(head);
// report the token
head = new ReportControl(head, Terms.BLOCK_END, context());
// The called production will exit segment sequence only if end of block
// is reached if block has ever started. The assertion below is not
// actually needed and is just overhead. It is still left here for
// testing.
final PhraseKindChoice endChoice = new PhraseKindChoice(unreachable);
endChoice.onKind(PhraseTokens.END_BLOCK, head);
head = endChoice;
// --- compile a body ---
head = innerNode().buildStates(b, head, unreachable);
// --- compile start of block ---
// after block end ignorable should be skipped
head = new SkipIgnorableState(head, false);
// advance to next token after block end
head = new AdvanceState(head);
// report the token
head = new ReportControl(head, Terms.BLOCK_START, context());
// Here the choice is significant
final PhraseKindChoice startChoice = new PhraseKindChoice(
new ReportErrorState(errorExit,
"syntax.UnexpectedToken.expectingBlock",
new Object[] { context() }));
startChoice.onKind(PhraseTokens.START_BLOCK, head);
head = startChoice;
return head;
}
/**
* {@inheritDoc}
*/
@Override
protected boolean calcMatchesEmpty() {
return false;
}
/**
* {@inheritDoc}
*/
@Override
protected LookAheadSet createLookAhead(
Set<StateMachineBuilder> visitedBuilders) {
return LookAheadSet.get(PhraseTokens.START_BLOCK);
}
}