/** * Copyright 2010-2017 Evgeny Gryaznov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package org.textmapper.idea.lang.templates.lexer; import com.intellij.lexer.LexerBase; import com.intellij.psi.TokenType; import com.intellij.psi.tree.IElementType; import org.textmapper.templates.ast.TemplatesLexer; import org.textmapper.templates.ast.TemplatesLexer.Span; import org.textmapper.templates.ast.TemplatesLexer.Tokens; import java.io.IOException; /** * Gryaznov Evgeny, 3/1/12 */ public class LtplLexerAdapter extends LexerBase implements LtplTokenTypes { private CharSequence myText; private TemplatesLexer lexer; private Span token; private int fDocumentLength; private int fTokenOffset; private int fState; private int fTokenLength; private IElementType current; public LtplLexerAdapter() { } public void start(final CharSequence buffer, int startOffset, int endOffset, int initialState) { myText = buffer; fDocumentLength = endOffset; String input = buffer.toString().substring(startOffset, endOffset); try { if (lexer == null) { lexer = new IdeaLtplLexer(input); } else { lexer.reset(input); } } catch (IOException ex) { /* never happens */ } lexer.setOffset(startOffset); fTokenOffset = startOffset; lexer.setState(initialState); fState = initialState; fTokenLength = 0; token = null; current = null; } public int getState() { locateToken(); return fState; } public IElementType getTokenType() { locateToken(); return current; } public int getTokenStart() { locateToken(); return fTokenOffset; } public int getTokenEnd() { locateToken(); return fTokenOffset + fTokenLength; } public void advance() { locateToken(); current = null; } public CharSequence getBufferSequence() { return myText; } public int getBufferEnd() { return fDocumentLength; } private void locateToken() { if (current == null) { current = nextToken(); } } public IElementType nextToken() { fTokenOffset += fTokenLength; if (token == null) { fState = lexer.getState(); readNext(); } if (fTokenOffset < token.offset) { fTokenLength = token.offset - fTokenOffset; return TokenType.BAD_CHARACTER; } int symbol = token.symbol; fTokenLength = token.endoffset - fTokenOffset; Span currentToken = token; token = null; switch (symbol) { case Tokens.identifier: return IDENTIFIER; case Tokens.any: return ANY; case Tokens.escdollar: return OP_ESCDOLLAR; case Tokens.escid: return ESCID; case Tokens.escint: return ESCINT; case Tokens.DollarLbrace: return OP_DOLLARLCURLY; case Tokens.DollarDiv: return OP_DOLLARSLASH; case Tokens.icon: return ICON; case Tokens.ccon: return CCON; // keywords case Tokens.Lcall: return KW_CALL; case Tokens.Lcached: return KW_CACHED; case Tokens.Lcase: return KW_CASE; case Tokens.Lend: return KW_END; case Tokens.Lelse: return KW_ELSE; case Tokens.Leval: return KW_EVAL; case Tokens.Lfalse: return KW_FALSE; case Tokens.Lfor: return KW_FOR; case Tokens.Lfile: return KW_FILE; case Tokens.Lforeach: return KW_FOREACH; case Tokens.Lgrep: return KW_GREP; case Tokens.Lif: return KW_IF; case Tokens.Lin: return KW_IN; case Tokens.Limport: return KW_IMPORT; case Tokens.Lis: return KW_IS; case Tokens.Lmap: return KW_MAP; case Tokens.Lnew: return KW_NEW; case Tokens.Lnull: return KW_NULL; case Tokens.Lquery: return KW_QUERY; case Tokens.Lswitch: return KW_SWITCH; case Tokens.Lseparator: return KW_SEPARATOR; case Tokens.Ltemplate: return KW_TEMPLATE; case Tokens.Ltrue: return KW_TRUE; case Tokens.Lself: return KW_SELF; case Tokens.Lassert: return KW_ASSERT; // operators case Tokens.Lbrace: return OP_LCURLY; case Tokens.Rbrace: return OP_RCURLY; case Tokens.MinusRbrace: return OP_MINUSRCURLY; case Tokens.Plus: return OP_PLUS; case Tokens.Minus: return OP_MINUS; case Tokens.Mult: return OP_MULT; case Tokens.Div: return OP_SLASH; case Tokens.Rem: return OP_PERCENT; case Tokens.Excl: return OP_EXCLAMATION; case Tokens.Or: return OP_OR; case Tokens.Lbrack: return OP_LSQUARE; case Tokens.Rbrack: return OP_RSQUARE; case Tokens.Lparen: return OP_LPAREN; case Tokens.Rparen: return OP_RPAREN; case Tokens.Dot: return OP_DOT; case Tokens.Comma: return OP_COMMA; case Tokens.AndAnd: return OP_AMPERSANDAMPERSAND; case Tokens.OrOr: return OP_OROR; case Tokens.AssignAssign: return OP_EQUALEQUAL; case Tokens.Assign: return OP_EQUAL; case Tokens.ExclAssign: return OP_EXCLAMATIONEQUAL; case Tokens.MinusGt: return OP_MINUSGREATER; case Tokens.AssignGt: return OP_EQUALGREATER; case Tokens.LtAssign: return OP_LESSEQUAL; case Tokens.GtAssign: return OP_GREATEREQUAL; case Tokens.Lt: return OP_LESS; case Tokens.Gt: return OP_GREATER; case Tokens.Colon: return OP_COLON; case Tokens.Quest: return OP_QUESTIONMARK; case Tokens._skip: return WHITESPACE; } /* default, eoi */ token = currentToken; assert token.symbol == Tokens.eoi && token.endoffset == fDocumentLength; return null; } private void readNext() { try { token = lexer.next(); } catch (IOException e) { /* never happens */ } } private static class IdeaLtplLexer extends TemplatesLexer { public IdeaLtplLexer(CharSequence input) throws IOException { super(input, (message, line, offset, endoffset) -> { }); } @Override protected boolean createToken(Span token, int ruleIndex) throws IOException { super.createToken(token, ruleIndex); return true; } } }