package org.develnext.jphp.core.syntax.generators; import org.develnext.jphp.core.tokenizer.token.CommentToken; import org.develnext.jphp.core.tokenizer.token.expr.value.NameToken; import php.runtime.common.Messages; import php.runtime.exceptions.ParseException; import php.runtime.exceptions.support.ErrorType; import org.develnext.jphp.core.syntax.SyntaxAnalyzer; import org.develnext.jphp.core.tokenizer.token.BreakToken; import org.develnext.jphp.core.tokenizer.token.SemicolonToken; import org.develnext.jphp.core.tokenizer.token.Token; import org.develnext.jphp.core.tokenizer.token.expr.BraceExprToken; import java.util.ListIterator; abstract public class Generator<T extends Token> { protected final SyntaxAnalyzer analyzer; public Generator(SyntaxAnalyzer analyzer) { this.analyzer = analyzer; } public boolean isAutomatic(){ return true; } public boolean isSingleton(){ return true; } protected void unexpectedToken(ListIterator<Token> iterator){ unexpectedToken(iterator.previous()); } /** * @throws ParseException * @param token */ protected void unexpectedToken(Token token){ analyzer.getEnvironment().error( token.toTraceInfo(analyzer.getContext()), ErrorType.E_PARSE, Messages.ERR_PARSE_UNEXPECTED_X.fetch(token.getWord()) ); } protected void unexpectedToken(Token token, Object expected){ unexpectedToken(token, expected, true); } protected void unexpectedToken(Token token, Object expected, boolean quotes){ analyzer.getEnvironment().error( token.toTraceInfo(analyzer.getContext()), ErrorType.E_PARSE, quotes ? Messages.ERR_PARSE_UNEXPECTED_X_EXPECTED_Y.fetch(token.getWord(), expected) : Messages.ERR_PARSE_UNEXPECTED_X_EXPECTED_Y_NO_QUOTES.fetch(token.getWord(), expected) ); } @SuppressWarnings("unchecked") protected <K extends Token> K nextAndExpected(ListIterator<Token> iterator, Class<K> clazz){ Token next = nextToken(iterator); if (!isTokenClass(next, clazz)) unexpectedToken(next); return (K) next; } @SuppressWarnings("unchecked") protected <K extends Token> K nextAndExpectedSensitive(ListIterator<Token> iterator, Class<K> clazz){ Token next = nextTokenSensitive(iterator); if (!isTokenClass(next, clazz)) unexpectedToken(next); return (K) next; } @SuppressWarnings("unchecked") protected boolean isTokenClass(Token token, Class<? extends Token>... classes){ if (token == null) return false; if (classes == null) return false; Class<? extends Token> current = token.getClass(); for (Class<? extends Token> clazz : classes){ if (clazz != null && (clazz == current || clazz.isAssignableFrom(current))) return true; } return false; } protected boolean isOpenedBrace(Token token, BraceExprToken.Kind kind){ if (token instanceof BraceExprToken) return ((BraceExprToken) token).isOpened(kind); return false; } protected boolean isClosedBrace(Token token, BraceExprToken.Kind kind){ if (token instanceof BraceExprToken) return ((BraceExprToken) token).isClosed(kind); return false; } protected boolean isBreak(Token token){ return token instanceof SemicolonToken || token instanceof BreakToken; } protected boolean isClosedBrace(Token token){ if (token instanceof BraceExprToken) return ((BraceExprToken) token).isClosed(); return false; } protected void unexpectedEnd(Token token){ analyzer.getEnvironment().error( token.toTraceInfo(analyzer.getContext()), ErrorType.E_PARSE, Messages.ERR_PARSE_UNEXPECTED_END_OF_FILE ); } protected void checkUnexpectedEnd(ListIterator<Token> iterator){ if (!iterator.hasNext()){ iterator.previous(); Token current = iterator.next(); analyzer.getEnvironment().error( current.toTraceInfo(analyzer.getContext()), ErrorType.E_PARSE, Messages.ERR_PARSE_UNEXPECTED_END_OF_FILE ); } } protected Token makeSensitive(Token token) { if (token instanceof NameToken) { return token; } if (token.isNamedToken()) { return new NameToken(token.getMeta()); } return token; } /** * Processes named token and returns them as named tokens. */ @SafeVarargs protected final Token nextTokenSensitive(ListIterator<Token> iterator, Class<? extends Token>... excludes) { Token token = nextToken(iterator); if (token instanceof NameToken) { return token; } if (excludes != null && isTokenClass(token, excludes)) { return token; } if (token.isNamedToken()) { return new NameToken(token.getMeta()); } return token; } protected Token nextToken(ListIterator<Token> iterator){ checkUnexpectedEnd(iterator); Token tk = iterator.next(); if (tk instanceof CommentToken) return nextToken(iterator); return tk; } protected Token nextTokenAndPrev(ListIterator<Token> iterator){ checkUnexpectedEnd(iterator); Token result = iterator.next(); if (result instanceof CommentToken) { return nextTokenAndPrev(iterator); } iterator.previous(); return result; } abstract public T getToken(Token current, ListIterator<Token> iterator); }