package bjc.pratt.blocks; import java.util.function.UnaryOperator; import bjc.pratt.ParserContext; import bjc.pratt.tokens.Token; import bjc.data.ITree; import bjc.data.Tree; import bjc.utils.parserutils.ParserException; /** * A parse block that can parse a sequnce of zero or more occurances of another * block. * * @author bjculkin * * @param * The key type of the tokens. * * @param * The value type of the tokens. * * @param * The state type of the parser. */ public class RepeatingParseBlock implements ParseBlock { private final ParseBlock innerBlock; private final K delim; private final K term; private final UnaryOperator onDelim; private final Token mark; /** * Create a new repeating block. * * @param inner * The inner block for elements. * * @param delimiter * The token that delimits elements in the sequence. * * @param terminator * The token that terminates the sequence. * * @param marker * The token to use as the node in the AST. * * @param action * The action to apply to the state after every delimiter. */ public RepeatingParseBlock(final ParseBlock inner, final K delimiter, final K terminator, final Token marker, final UnaryOperator action) { super(); if(inner == null) throw new NullPointerException("Inner block must not be null"); else if(delimiter == null) throw new NullPointerException("Delimiter must not be null"); else if(terminator == null) throw new NullPointerException("Terminator must not be null"); innerBlock = inner; delim = delimiter; term = terminator; mark = marker; onDelim = action; } @Override public ITree> parse(final ParserContext ctx) throws ParserException { final ITree> ret = new Tree<>(mark); Token tok = ctx.tokens.current(); while(!tok.getKey().equals(term)) { final ITree> kid = innerBlock.parse(ctx); ret.addChild(kid); tok = ctx.tokens.current(); ctx.tokens.expect(delim, term); if(onDelim != null) { ctx.state = onDelim.apply(ctx.state); } } return ret; } }