package bjc.pratt.blocks; import java.util.function.UnaryOperator; import bjc.pratt.ParseBlock; import bjc.pratt.ParserContext; import bjc.pratt.Token; import bjc.utils.data.ITree; import bjc.utils.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 ParseBlock innerBlock; private K delim; private K term; private UnaryOperator onDelim; private 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(ParseBlock inner, K delimiter, K terminator, Token marker, 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(ParserContext ctx) throws ParserException { ITree> ret = new Tree<>(mark); Token tok = ctx.tokens.current(); while (!tok.getKey().equals(term)) { 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; } }