package com.floreysoft.jmte.token; import java.util.ArrayList; import java.util.List; import com.floreysoft.jmte.util.StartEndPair; import com.floreysoft.jmte.util.Util; public class TokenStream { private final Lexer lexer = new Lexer(); private final String sourceName; private final String input; private final List<StartEndPair> scan; private final String splitStart; private final String splitEnd; private transient List<Token> tokens = null; private transient int currentTokenIndex = -1; private transient Token currentToken = null; public TokenStream(String sourceName, String input, String splitStart, String splitEnd) { this.sourceName = sourceName; this.input = input; this.splitStart = splitStart; this.splitEnd = splitEnd; this.scan = Util.scan(input, splitStart, splitEnd, true); } private void fillTokens() { this.tokens = new ArrayList<Token>(); final char[] inputChars = input.toCharArray(); int offset = 0; int index = 0; for (StartEndPair startEndPair : scan) { int plainTextLengthBeforeNextToken = startEndPair.start - splitStart.length() - offset; if (plainTextLengthBeforeNextToken != 0) { AbstractToken token = new PlainTextToken(Util.NO_QUOTE_MINI_PARSER.unescape(new String(inputChars, offset, plainTextLengthBeforeNextToken))); token.setTokenIndex(index++); tokens.add(token); } offset = startEndPair.end + splitEnd.length(); AbstractToken token = lexer.nextToken(inputChars, startEndPair.start, startEndPair.end); // == null means this is a comment or other skipable stuff if (token == null) { continue; } token.setSourceName(sourceName); token.setTokenIndex(index++); tokens.add(token); } // do not forget to add the final chunk of pure text (might be the // only // chunk indeed) int remainingChars = input.length() - offset; if (remainingChars != 0) { AbstractToken token = new PlainTextToken(Util.NO_QUOTE_MINI_PARSER.unescape(new String(inputChars, offset, remainingChars))); token.setTokenIndex(index++); tokens.add(token); } } private void initTokens() { if (this.tokens == null) { fillTokens(); this.currentTokenIndex = 0; } } public Token nextToken() { initTokens(); if (currentTokenIndex < tokens.size()) { currentToken = tokens.get(currentTokenIndex++); } else { currentToken = null; } return currentToken; } public void consume() { nextToken(); } public Token currentToken() { return currentToken; } public void rewind(Token tokenToRewindTo) { initTokens(); this.currentTokenIndex = tokenToRewindTo.getTokenIndex() + 1; consume(); } public List<Token> getAllTokens() { initTokens(); return this.tokens; } public void prefill() { initTokens(); } public void reset() { currentTokenIndex = 0; } }