Commit c2d9d21a authored by Gregory.Shrago's avatar Gregory.Shrago
Browse files

#143 back-port: some common stuff

parent 43a55b60
Showing with 143 additions and 66 deletions
+143 -66
......@@ -7,6 +7,7 @@ import com.intellij.lang.PsiBuilder;
import com.intellij.openapi.util.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.IFileElementType;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FilteredTraverserBase;
......@@ -73,7 +74,7 @@ public class SyntaxTraverser<T> extends FilteredTraverserBase<T, SyntaxTraverser
@NotNull
public static SyntaxTraverser<LighterASTNode> lightTraverser(@NotNull PsiBuilder builder) {
LighterASTApi api = new LighterASTApi(builder);
return new SyntaxTraverser<LighterASTNode>(api, Meta.<LighterASTNode>empty().withRoots(JBIterable.of(api.flyweightStructure.getRoot())));
return new SyntaxTraverser<LighterASTNode>(api, Meta.<LighterASTNode>empty().withRoots(JBIterable.of(api.getStructure().getRoot())));
}
public final Api<T> api;
......@@ -126,7 +127,7 @@ public class SyntaxTraverser<T> extends FilteredTraverserBase<T, SyntaxTraverser
@Nullable
public T getRawDeepestLast() {
for (T result = getRoot(), last; result != null; result = last) {
for (T result = JBIterable.from(getRoots()).last(), last; result != null; result = last) {
JBIterable<T> children = children(result);
if (children.isEmpty()) return result;
//noinspection AssignmentToForLoopParameter
......@@ -295,7 +296,8 @@ public class SyntaxTraverser<T> extends FilteredTraverserBase<T, SyntaxTraverser
@NotNull
@Override
public IElementType typeOf(@NotNull PsiElement node) {
return node.getNode().getElementType();
IElementType type = PsiUtilCore.getElementType(node);
return type != null ? type : IElementType.find((short)0);
}
@NotNull
......@@ -371,16 +373,14 @@ public class SyntaxTraverser<T> extends FilteredTraverserBase<T, SyntaxTraverser
}
private abstract static class FlyweightApi<T> extends Api<T> {
final FlyweightCapableTreeStructure<T> flyweightStructure;
public FlyweightApi(@NotNull FlyweightCapableTreeStructure<T> structure) {
flyweightStructure = structure;
}
@NotNull
abstract FlyweightCapableTreeStructure<T> getStructure();
@Nullable
@Override
public T parent(@NotNull T node) {
return flyweightStructure.getParent(node);
return getStructure().getParent(node);
}
@NotNull
......@@ -389,26 +389,23 @@ public class SyntaxTraverser<T> extends FilteredTraverserBase<T, SyntaxTraverser
return new JBIterable<T>() {
@Override
public Iterator<T> iterator() {
FlyweightCapableTreeStructure<T> structure = getStructure();
Ref<T[]> ref = Ref.create();
int count = flyweightStructure.getChildren(flyweightStructure.prepareForGetChildren(node), ref);
int count = structure.getChildren(structure.prepareForGetChildren(node), ref);
if (count == 0) return ContainerUtil.emptyIterator();
T[] array = ref.get();
LinkedList<T> list = ContainerUtil.newLinkedList();
for (int i = 0; i < count; i++) {
T child = array[i];
IElementType childType = typeOf(child);
// skip TokenType.* types, errors cannot be properly handled (no parents)
if (childType == TokenType.ERROR_ELEMENT) {
// todo remember error
continue;
}
else if (childType == TokenType.WHITE_SPACE || childType == TokenType.BAD_CHARACTER) {
// tokens and errors getParent() == null
if (childType == TokenType.WHITE_SPACE || childType == TokenType.BAD_CHARACTER) {
continue;
}
array[i] = null; // do not dispose meaningful TokenNodes
list.addLast(child);
}
flyweightStructure.disposeChildren(array, count);
structure.disposeChildren(array, count);
return list.iterator();
}
};
......@@ -417,12 +414,24 @@ public class SyntaxTraverser<T> extends FilteredTraverserBase<T, SyntaxTraverser
private static class LighterASTApi extends FlyweightApi<LighterASTNode> {
private final PsiBuilder builder;
private final ThreadLocalCachedValue<FlyweightCapableTreeStructure<LighterASTNode>> structure =
new ThreadLocalCachedValue<FlyweightCapableTreeStructure<LighterASTNode>>() {
@Override
protected FlyweightCapableTreeStructure<LighterASTNode> create() {
return builder.getLightTree();
}
};
public LighterASTApi(PsiBuilder builder) {
super(builder.getLightTree());
public LighterASTApi(final PsiBuilder builder) {
this.builder = builder;
}
@NotNull
@Override
FlyweightCapableTreeStructure<LighterASTNode> getStructure() {
return structure.getValue();
}
@NotNull
@Override
public IElementType typeOf(@NotNull LighterASTNode node) {
......
......@@ -248,6 +248,14 @@ public class GeneratedParserUtilBase {
return false;
}
public static boolean nextTokenIsSmart(PsiBuilder builder, IElementType token) {
return nextTokenIsFast(builder, token) || ErrorState.get(builder).completionState != null;
}
public static boolean nextTokenIsSmart(PsiBuilder builder, IElementType... tokens) {
return nextTokenIsFast(builder, tokens) || ErrorState.get(builder).completionState != null;
}
public static boolean nextTokenIs(PsiBuilder builder, String frameName, IElementType... tokens) {
ErrorState state = ErrorState.get(builder);
if (state.completionState != null) return true;
......@@ -353,37 +361,9 @@ public class GeneratedParserUtilBase {
private static void addCompletionVariant(@NotNull PsiBuilder builder, @NotNull CompletionState completionState, Object o) {
int offset = builder.getCurrentOffset();
if (!builder.eof() && offset == builder.rawTokenTypeStart(1)) return; // suppress for zero-length tokens
boolean add = false;
int diff = completionState.offset - offset;
String text = completionState.convertItem(o);
int length = text == null? 0 : text.length();
if (length == 0) return;
if (diff == 0) {
add = true;
}
else if (diff > 0 && diff <= length) {
CharSequence fragment = builder.getOriginalText().subSequence(offset, completionState.offset);
add = completionState.prefixMatches(fragment.toString(), text);
}
else if (diff < 0) {
for (int i=-1; ; i--) {
IElementType type = builder.rawLookup(i);
int tokenStart = builder.rawTokenTypeStart(i);
if (isWhitespaceOrComment(builder, type)) {
diff = completionState.offset - tokenStart;
}
else if (type != null && tokenStart < completionState.offset) {
CharSequence fragment = builder.getOriginalText().subSequence(tokenStart, completionState.offset);
if (completionState.prefixMatches(fragment.toString(), text)) {
diff = completionState.offset - tokenStart;
}
break;
}
else break;
}
add = diff >= 0 && diff < length;
}
boolean add = length != 0 && completionState.prefixMatches(builder, text);
add = add && length > 1 && !(text.charAt(0) == '<' && text.charAt(length - 1) == '>') &&
!(text.charAt(0) == '\'' && text.charAt(length - 1) == '\'' && length < 5);
if (add) {
......@@ -689,6 +669,14 @@ public class GeneratedParserUtilBase {
}
}
public static boolean withProtectedLastVariantPos(PsiBuilder builder, int level, Parser parser) {
ErrorState state = ErrorState.get(builder);
int backup = state.lastExpectedVariantPos;
boolean result = parser.parse(builder, level);
state.lastExpectedVariantPos = backup;
return result;
}
private static int getLastVariantPos(ErrorState state, int defValue) {
return state.lastExpectedVariantPos < 0? defValue : state.lastExpectedVariantPos;
}
......@@ -759,6 +747,38 @@ public class GeneratedParserUtilBase {
items.add(text);
}
public boolean prefixMatches(@NotNull PsiBuilder builder, @NotNull String text) {
int builderOffset = builder.getCurrentOffset();
int diff = offset - builderOffset;
int length = text.length();
if (diff == 0) {
return true;
}
else if (diff > 0 && diff <= length) {
CharSequence fragment = builder.getOriginalText().subSequence(builderOffset, offset);
return prefixMatches(fragment.toString(), text);
}
else if (diff < 0) {
for (int i=-1; ; i--) {
IElementType type = builder.rawLookup(i);
int tokenStart = builder.rawTokenTypeStart(i);
if (isWhitespaceOrComment(builder, type)) {
diff = offset - tokenStart;
}
else if (type != null && tokenStart < offset) {
CharSequence fragment = builder.getOriginalText().subSequence(tokenStart, offset);
if (prefixMatches(fragment.toString(), text)) {
diff = offset - tokenStart;
}
break;
}
else break;
}
return diff >= 0 && diff < length;
}
return false;
}
public boolean prefixMatches(@NotNull String prefix, @NotNull String variant) {
boolean matches = new CamelHumpMatcher(prefix, false).prefixMatches(variant.replace(' ', '_'));
if (matches && StringUtil.isWhiteSpace(prefix.charAt(prefix.length() - 1))) {
......
......@@ -17,9 +17,10 @@
package com.intellij.openapi.util;
import com.intellij.reference.SoftReference;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Function;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
/**
......@@ -45,6 +46,10 @@ public class Conditions {
return (Condition<T>)Condition.NOT_NULL;
}
public static <T> Condition<T> constant(boolean value) {
return (Condition<T>)(value ? TRUE : FALSE);
}
public static <T> Condition<T> instanceOf(final Class<?> clazz) {
return new Condition<T>() {
@Override
......@@ -106,23 +111,15 @@ public class Conditions {
};
}
public static <T> Condition<T> oneOf(final T... options) {
return new Condition<T>() {
@Override
public boolean value(T t) {
return ArrayUtilRt.find(options, t) >= 0;
}
};
public static <T> Condition<T> oneOf(T... options) {
return oneOf(Arrays.asList(options));
}
public static <T> Condition<T> oneOf(final Iterable<? extends T> options) {
public static <T> Condition<T> oneOf(final Collection<? extends T> options) {
return new Condition<T>() {
@Override
public boolean value(T t) {
for (T option : options) {
if (Comparing.equal(option, t)) return true;
}
return false;
return options.contains(t);
}
};
}
......
......@@ -25,11 +25,37 @@ import java.util.Map;
*/
public class Functions {
public static <A> Function.Mono<A> id() {
return (Function.Mono<A>)Function.ID;
}
public static <A, B> Function<A, B> constant(final B b) {
return new Function<A, B>() {
@Override
public B fun(A a) {
return b;
}
};
}
public static <A, B> Function<A, B> identity() {
return Function.ID;
}
public static <A> Function<A, String> toString() {
public static <A, B> Function<A, B> cast(Class<B> clazz) {
return Function.ID;
}
public static <A, B, C> Function<A, C> compose(final Function<A, B> f1, final Function<B, ? extends C> f2) {
return new Function<A, C>() {
@Override
public C fun(A a) {
return f2.fun(f1.fun(a));
}
};
}
public static <A> Function<A, String> TO_STRING() {
return Function.TO_STRING;
}
......@@ -49,7 +75,7 @@ public class Functions {
}
};
public static <T> Function<T, Class> toClass() {
public static <T> Function<T, Class> TO_CLASS() {
return (Function<T, Class>)TO_CLASS;
}
......@@ -74,4 +100,13 @@ public class Functions {
public static <B> Function<Pair<?, B>, B> pairSecond() {
return (Function<Pair<?, B>, B>)PAIR_SECOND;
}
public static Function.Mono<Integer> intIncrement() {
return new Function.Mono<Integer>() {
@Override
public Integer fun(Integer integer) {
return integer + 1;
}
};
}
}
......@@ -152,8 +152,8 @@ public abstract class FilteredTraverserBase<T, Self extends FilteredTraverserBas
}
@NotNull
public JBIterable<T> children(@NotNull T node) {
if (isAlwaysLeaf(node)) {
public JBIterable<T> children(@Nullable T node) {
if (node == null || isAlwaysLeaf(node)) {
return JBIterable.empty();
}
else if (meta.regard.next == null && meta.forceDisregard.next == null) {
......@@ -181,7 +181,7 @@ public abstract class FilteredTraverserBase<T, Self extends FilteredTraverserBas
public abstract static class EdgeFilter<T> extends JBIterable.StatefulFilter<T> {
protected T curParent;
protected T edgeSource;
}
......@@ -283,7 +283,7 @@ public abstract class FilteredTraverserBase<T, Self extends FilteredTraverserBas
if (impl != (invert ? Condition.TRUE : Condition.FALSE)) {
copy = new Cond<Object>(invert ? not(impl) : impl, copy);
if (impl instanceof EdgeFilter) {
((EdgeFilter)impl).curParent = parent;
((EdgeFilter)impl).edgeSource = parent;
}
}
if (c.next == null) {
......
......@@ -202,6 +202,9 @@ public abstract class JBIterable<E> implements Iterable<E> {
* Returns the number of elements in this iterable.
*/
public final int size() {
if (myIterable instanceof Collection) {
return ((Collection)myIterable).size();
}
int count = 0;
for (E ignored : myIterable) {
count++;
......@@ -223,6 +226,16 @@ public abstract class JBIterable<E> implements Iterable<E> {
return false;
}
/**
* Returns element at index if it is present; otherwise {@code null}
*/
public final E get(int index) {
if (myIterable instanceof List) {
return index >= ((List)myIterable).size() ? null : ((List<E>)myIterable).get(index);
}
return skip(index).first();
}
/**
* Returns a {@code JBIterable} whose iterators traverse first the elements of this iterable,
* followed by those of {@code other}. The iterators are not polled until necessary.
......@@ -412,6 +425,9 @@ public abstract class JBIterable<E> implements Iterable<E> {
* Determines whether this iterable is empty.
*/
public final boolean isEmpty() {
if (myIterable instanceof Collection) {
return ((Collection)myIterable).isEmpty();
}
return !myIterable.iterator().hasNext();
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment