Parsing dynamic in extension receiver position

This commit is contained in:
Andrey Breslav
2014-11-14 18:59:14 +03:00
parent 4f3158abb3
commit f58b30706e
11 changed files with 239 additions and 6 deletions
@@ -1527,7 +1527,8 @@ public class JetParsing extends AbstractJetParsing {
parseAnnotations(REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS);
IElementType lookahead = lookahead(1);
if (at(IDENTIFIER) && lookahead(1) != DOT && lookahead != LT && lookahead != LPAR && at(DYNAMIC_KEYWORD)) {
IElementType lookahead2 = lookahead(2);
if (at(IDENTIFIER) && !(lookahead == DOT && lookahead2 == IDENTIFIER) && lookahead != LT && at(DYNAMIC_KEYWORD)) {
PsiBuilder.Marker dynamicType = mark();
advance(); // DYNAMIC_KEYWORD
dynamicType.done(DYNAMIC_TYPE);
@@ -17,6 +17,8 @@
package org.jetbrains.jet.lang.parsing;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
public interface SemanticWhitespaceAwarePsiBuilder extends PsiBuilder {
// TODO: comments go to wrong place when an empty element is created, see IElementType.isLeftBound()
@@ -29,4 +31,6 @@ public interface SemanticWhitespaceAwarePsiBuilder extends PsiBuilder {
void restoreJoiningComplexTokensState();
void enableJoiningComplexTokens();
void disableJoiningComplexTokens();
boolean isWhitespaceOrComment(@NotNull IElementType elementType);
}
@@ -17,6 +17,8 @@
package org.jetbrains.jet.lang.parsing;
import com.intellij.lang.impl.PsiBuilderAdapter;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
public class SemanticWhitespaceAwarePsiBuilderAdapter extends PsiBuilderAdapter implements SemanticWhitespaceAwarePsiBuilder {
@@ -62,4 +64,9 @@ public class SemanticWhitespaceAwarePsiBuilderAdapter extends PsiBuilderAdapter
public void disableJoiningComplexTokens() {
myBuilder.disableJoiningComplexTokens();
}
@Override
public boolean isWhitespaceOrComment(@NotNull IElementType elementType) {
return myBuilder.isWhitespaceOrComment(elementType);
}
}
@@ -19,9 +19,12 @@ package org.jetbrains.jet.lang.parsing;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.impl.PsiBuilderAdapter;
import com.intellij.lang.impl.PsiBuilderImpl;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lexer.JetTokens;
import com.intellij.util.containers.Stack;
@@ -35,10 +38,36 @@ public class SemanticWhitespaceAwarePsiBuilderImpl extends PsiBuilderAdapter imp
private final Stack<Boolean> newlinesEnabled = new Stack<Boolean>();
private final PsiBuilderImpl delegateImpl;
public SemanticWhitespaceAwarePsiBuilderImpl(PsiBuilder delegate) {
super(delegate);
newlinesEnabled.push(true);
joinComplexTokens.push(true);
delegateImpl = findPsiBuilderImpl(delegate);
}
@Nullable
private static PsiBuilderImpl findPsiBuilderImpl(PsiBuilder builder) {
// This is a hackish workaround for PsiBuilder interface not exposing isWhitespaceOrComment() method
// We have to unwrap all the adapters to find an Impl inside
while (true) {
if (builder instanceof PsiBuilderImpl) {
return (PsiBuilderImpl) builder;
}
if (!(builder instanceof PsiBuilderAdapter)) {
return null;
}
builder = ((PsiBuilderAdapter) builder).getDelegate();
}
}
@Override
public boolean isWhitespaceOrComment(@NotNull IElementType elementType) {
assert delegateImpl != null : "PsiBuilderImpl not found";
return delegateImpl.whitespaceOrComment(elementType);
}
@Override
@@ -30,8 +30,7 @@ public class TruncatedSemanticWhitespaceAwarePsiBuilder extends SemanticWhitespa
@Override
public boolean eof() {
if (super.eof()) return true;
return myEOFPosition >= 0 && getCurrentOffset() >= myEOFPosition;
return super.eof() || isOffsetBeyondEof(getCurrentOffset());
}
@Override
@@ -46,4 +45,35 @@ public class TruncatedSemanticWhitespaceAwarePsiBuilder extends SemanticWhitespa
return super.getTokenType();
}
@Override
public IElementType lookAhead(int steps) {
if (eof()) return null;
int rawLookAheadSteps = rawLookAhead(steps);
if (isOffsetBeyondEof(rawTokenTypeStart(rawLookAheadSteps))) return null;
return super.rawLookup(rawLookAheadSteps);
}
private int rawLookAhead(int steps) {
// This code reproduces the behavior of PsiBuilderImpl.lookAhead(), but returns a number of raw steps instead of a token type
// This is required for implementing truncated builder behavior
int cur = 0;
while (steps > 0) {
cur++;
IElementType rawTokenType = rawLookup(cur);
while (rawTokenType != null && isWhitespaceOrComment(rawTokenType)) {
cur++;
rawTokenType = rawLookup(cur);
}
steps--;
}
return cur;
}
private boolean isOffsetBeyondEof(int offsetFromCurrent) {
return myEOFPosition >= 0 && offsetFromCurrent >= myEOFPosition;
}
}