blob: 1a4546664b6acaba0a8b866b91e2d383f1fe56f1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.javascript2.editor.formatter;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.lexer.Token;
import org.netbeans.api.lexer.TokenSequence;
import org.netbeans.modules.javascript2.lexer.api.JsTokenId;
/**
* Utility methods extracted from {@link FormatVisitor}.
*
* @author Dusan Balek, Petr Hejl
*/
final class TokenUtils {
private final TokenSequence<? extends JsTokenId> ts;
private final FormatTokenStream tokenStream;
private final int formatFinish;
TokenUtils(TokenSequence<? extends JsTokenId> ts, FormatTokenStream tokenStream, int formatFinish) {
this.ts = ts;
this.tokenStream = tokenStream;
this.formatFinish = formatFinish;
}
public FormatToken getNextToken(int offset, JsTokenId expected) {
return getToken(offset, expected, false, false, null);
}
public FormatToken getNextToken(int offset, JsTokenId expected, int stop) {
return getToken(offset, expected, false, false, stop);
}
public FormatToken getNextToken(int offset, JsTokenId expected, boolean startFallback) {
return getToken(offset, expected, false, startFallback, null);
}
public FormatToken getPreviousToken(int offset, JsTokenId expected) {
return getPreviousToken(offset, expected, false);
}
public FormatToken getPreviousToken(int offset, JsTokenId expected, int stop) {
return getToken(offset, expected, true, false, stop);
}
public FormatToken getPreviousToken(int offset, JsTokenId expected, boolean startFallback) {
return getToken(offset, expected, true, startFallback, null);
}
private FormatToken getToken(int offset, JsTokenId expected, boolean backward,
boolean startFallback, Integer stopMark) {
ts.move(offset);
if (!ts.moveNext() && !ts.movePrevious()) {
return null;
}
Token<? extends JsTokenId> token = ts.token();
if (expected != null) {
while (expected != token.id()
&& (stopMark == null || ((stopMark >= ts.offset() && !backward) || (stopMark <=ts.offset() && backward)))
&& ((backward && ts.movePrevious()) || (!backward && ts.moveNext()))) {
token = ts.token();
}
if (expected != token.id()) {
return null;
}
}
if (stopMark != null && ((ts.offset() > stopMark && !backward) || (ts.offset() < stopMark && backward))) {
return null;
}
if (token != null) {
return getFallback(ts.offset(), startFallback);
}
return null;
}
public Token getPreviousNonEmptyToken(int offset) {
ts.move(offset);
if (!ts.moveNext() && !ts.movePrevious()) {
return null;
}
Token ret = null;
while (ts.movePrevious()) {
Token token = ts.token();
if ((token.id() != JsTokenId.BLOCK_COMMENT && token.id() != JsTokenId.DOC_COMMENT
&& token.id() != JsTokenId.LINE_COMMENT && token.id() != JsTokenId.EOL
&& token.id() != JsTokenId.WHITESPACE)) {
ret = token;
break;
}
}
return ret;
}
public Token getNextNonEmptyToken(int offset) {
ts.move(offset);
if (!ts.moveNext() && !ts.movePrevious()) {
return null;
}
Token ret = null;
while (ts.moveNext()) {
Token token = ts.token();
if ((token.id() != JsTokenId.BLOCK_COMMENT && token.id() != JsTokenId.DOC_COMMENT
&& token.id() != JsTokenId.LINE_COMMENT && token.id() != JsTokenId.EOL
&& token.id() != JsTokenId.WHITESPACE)) {
ret = token;
break;
}
}
return ret;
}
public FormatToken getPreviousNonWhiteToken(int offset, int stop, JsTokenId expected, boolean startFallback) {
assert stop <= offset;
FormatToken ret = getPreviousToken(offset, expected, startFallback);
if (startFallback && ret != null && ret.getKind() == FormatToken.Kind.SOURCE_START) {
return ret;
}
if (ret != null) {
if (expected == null) {
return ret;
}
Token token = null;
while (ts.movePrevious() && ts.offset() >= stop) {
Token current = ts.token();
if (current.id() != JsTokenId.WHITESPACE) {
token = current;
break;
}
}
if (token != null) {
return getFallback(ts.offset(), startFallback);
}
}
return null;
}
public FormatToken getFallback(int offset, boolean fallback) {
FormatToken ret = tokenStream.getToken(offset);
if (ret == null && fallback && offset < formatFinish) {
ret = tokenStream.getTokens().get(0);
assert ret != null && ret.getKind() == FormatToken.Kind.SOURCE_START;
}
return ret;
}
@CheckForNull
public static FormatToken findVirtualToken(FormatToken token, FormatToken.Kind kind,
boolean backwards) {
FormatToken result = backwards ? token.previous() : token.next();
while (result != null && result.isVirtual() && result.getKind() != kind) {
result = backwards ? result.previous() : result.next();
}
if (result != null && result.getKind() != kind) {
return null;
}
return result;
}
public static void appendTokenAfterLastVirtual(FormatToken previous,
FormatToken token) {
appendTokenAfterLastVirtual(previous, token, false);
}
public static void appendTokenAfterLastVirtual(FormatToken previous,
FormatToken token, boolean checkDuplicity) {
assert previous != null;
@NonNull
FormatToken current = previous;
FormatToken next = current.next();
while (next != null && next.isVirtual()) {
current = next;
next = next.next();
}
if (!checkDuplicity || !current.isVirtual() || !token.isVirtual()
|| current.getKind() != token.getKind()) {
appendToken(current, token);
}
}
public static void appendToken(FormatToken previous, FormatToken token) {
FormatToken original = previous.next();
previous.setNext(token);
token.setPrevious(previous);
token.setNext(original);
if (original != null) {
original.setPrevious(token);
}
}
}