blob: 59ceeb2875a1f1e0ef63de594ffdbb16cbb801c5 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2007, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.r.core.source;
import org.eclipse.jface.text.IRegion;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.ecommons.text.BasicHeuristicTokenScanner;
import org.eclipse.statet.ecommons.text.core.sections.DocContentSections;
import org.eclipse.statet.r.core.rlang.RTokens;
/**
*
*/
@NonNullByDefault
public class RHeuristicTokenScanner extends BasicHeuristicTokenScanner {
public static final int CURLY_BRACKET_TYPE= 0;
public static final int ROUND_BRACKET_TYPE= 1;
public static final int SQUARE_BRACKET_TYPE= 2;
public static int getBracketType(final char c) {
switch (c) {
case '{':
case '}':
return CURLY_BRACKET_TYPE;
case '(':
case ')':
return ROUND_BRACKET_TYPE;
case '[':
case ']':
return SQUARE_BRACKET_TYPE;
default:
throw new IllegalArgumentException();
}
}
public static RHeuristicTokenScanner create(final DocContentSections documentContentInfo) {
return (documentContentInfo.getPrimaryType() == RDocumentConstants.R_PARTITIONING) ?
new RHeuristicTokenScanner(documentContentInfo) :
new RChunkHeuristicTokenScanner(documentContentInfo);
}
protected RHeuristicTokenScanner(final DocContentSections documentContentInfo) {
super(documentContentInfo, RDocumentConstants.R_DEFAULT_CONTENT_CONSTRAINT);
}
public @Nullable IRegion findRWord(final int position, final boolean isDotSeparator, final boolean allowEnd) {
return findRegion(position, new StopCondition() {
@Override
public boolean stop() {
return (RTokens.isRobustSeparator(RHeuristicTokenScanner.this.ch, isDotSeparator));
}
}, true);
}
private class BracketBalanceCondition extends PartitionBasedCondition {
private int type;
private boolean open;
@Override
protected boolean matchesChar() {
switch (RHeuristicTokenScanner.this.ch) {
case '{':
this.type= CURLY_BRACKET_TYPE;
this.open= true;
return true;
case '}':
this.type= CURLY_BRACKET_TYPE;
this.open= false;
return true;
case '(':
this.type= ROUND_BRACKET_TYPE;
this.open= true;
return true;
case ')':
this.type= ROUND_BRACKET_TYPE;
this.open= false;
this.open= false;
return true;
case '[':
this.type= SQUARE_BRACKET_TYPE;
this.open= true;
return true;
case ']':
this.type= SQUARE_BRACKET_TYPE;
this.open= false;
return true;
}
return false;
}
}
/**
* Computes bracket balance
*
* @param backwardOffset searching backward before this offset
* @param forwardOffset searching forward after (including) this offset
* @param initial initial balance (e.g. known or not yet inserted between backward and forward offset)
* @param searchType interesting bracket type
* @return
* @see #getBracketType(char)
*/
public int[] computeBracketBalance(int backwardOffset, int forwardOffset, final int[] initial, final int searchType) {
final int[] compute= new int[3];
final BracketBalanceCondition condition= new BracketBalanceCondition();
int breakType= -1;
ITER_BACKWARD : while (--backwardOffset >= 0) {
backwardOffset= scanBackward(backwardOffset, -1, condition);
if (backwardOffset != NOT_FOUND) {
if (condition.open) {
compute[condition.type]++;
if (condition.type != searchType && compute[condition.type] > 0) {
breakType= condition.type;
break ITER_BACKWARD;
}
}
else {
compute[condition.type]--;
}
}
else {
break ITER_BACKWARD;
}
}
final int bound= getDocument().getLength();
for (int i= 0; i < compute.length; i++) {
if (compute[i] < 0) {
compute[i]= 0;
}
compute[i]= compute[i] + initial[i];
}
ITER_FORWARD : while (forwardOffset < bound) {
forwardOffset= scanForward(forwardOffset, bound, condition);
if (forwardOffset != NOT_FOUND) {
if (condition.open) {
compute[condition.type]++;
}
else {
compute[condition.type]--;
}
if (breakType >= 0 && compute[breakType] == 0) {
break ITER_FORWARD;
}
forwardOffset++;
}
else {
break ITER_FORWARD;
}
}
return compute;
}
}