Expression parser factored out
This commit is contained in:
Generated
+1
-1
@@ -24,7 +24,7 @@
|
|||||||
<component name="ProjectResources">
|
<component name="ProjectResources">
|
||||||
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
|
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
<component name="WebServicesPlugin" addRequiredLibraries="true" />
|
<component name="WebServicesPlugin" addRequiredLibraries="true" />
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package org.jetbrains.jet.lang.parsing;
|
||||||
|
|
||||||
|
import com.intellij.lang.PsiBuilder;
|
||||||
|
import com.intellij.psi.tree.IElementType;
|
||||||
|
import com.intellij.psi.tree.TokenSet;
|
||||||
|
import org.jetbrains.jet.lexer.JetKeywordToken;
|
||||||
|
import org.jetbrains.jet.lexer.JetToken;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lexer.JetTokens.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by IntelliJ IDEA.
|
||||||
|
* User: user
|
||||||
|
* Date: 12/16/10
|
||||||
|
* Time: 6:34 PM
|
||||||
|
* To change this template use File | Settings | File Templates.
|
||||||
|
*/
|
||||||
|
/*package*/ class AbstractJetParsing {
|
||||||
|
protected final SemanticWitespaceAwarePsiBuilder myBuilder;
|
||||||
|
|
||||||
|
public AbstractJetParsing(SemanticWitespaceAwarePsiBuilder builder) {
|
||||||
|
this.myBuilder = builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean expect(JetToken expectation, String message) {
|
||||||
|
return expect(expectation, message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PsiBuilder.Marker mark() {
|
||||||
|
return myBuilder.mark();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void error(String message) {
|
||||||
|
myBuilder.error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean expect(JetToken expectation, String message, TokenSet recoverySet) {
|
||||||
|
if (at(expectation)) {
|
||||||
|
advance(); // expectation
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorWithRecovery(message, recoverySet);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void errorWithRecovery(String message, TokenSet recoverySet) {
|
||||||
|
JetToken tt = tt();
|
||||||
|
if (recoverySet == null || recoverySet.contains(tt)
|
||||||
|
|| (recoverySet.contains(EOL_OR_SEMICOLON)
|
||||||
|
&& (tt == SEMICOLON || myBuilder.eolInLastWhitespace()))) {
|
||||||
|
error(message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errorAndAdvance(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void errorAndAdvance(String message) {
|
||||||
|
PsiBuilder.Marker err = mark();
|
||||||
|
advance(); // erroneous token
|
||||||
|
err.error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean eof() {
|
||||||
|
return myBuilder.eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void advance() {
|
||||||
|
myBuilder.advanceLexer();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JetToken tt() {
|
||||||
|
return (JetToken) myBuilder.getTokenType();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean at(final IElementType expectation) {
|
||||||
|
JetToken token = tt();
|
||||||
|
if (token == expectation) return true;
|
||||||
|
if (expectation == EOL_OR_SEMICOLON) {
|
||||||
|
if (token == SEMICOLON) return true;
|
||||||
|
if (myBuilder.eolInLastWhitespace()) return true;
|
||||||
|
}
|
||||||
|
if (token == IDENTIFIER && expectation instanceof JetKeywordToken) {
|
||||||
|
JetKeywordToken expectedKeyword = (JetKeywordToken) expectation;
|
||||||
|
if (expectedKeyword.isSoft() && expectedKeyword.getValue().equals(myBuilder.getTokenText())) {
|
||||||
|
myBuilder.remapCurrentToken(expectation);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IElementType lookahead(int k) {
|
||||||
|
PsiBuilder.Marker tmp = mark();
|
||||||
|
for (int i = 0; i < k; i++) advance();
|
||||||
|
|
||||||
|
JetToken tt = tt();
|
||||||
|
tmp.rollbackTo();
|
||||||
|
return tt;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void consumeIf(JetToken token) {
|
||||||
|
if (at(token)) advance(); // token
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package org.jetbrains.jet.lang.parsing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class JetExpressionParsing extends AbstractJetParsing {
|
||||||
|
public JetExpressionParsing(SemanticWitespaceAwarePsiBuilder builder) {
|
||||||
|
super(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* expression
|
||||||
|
* : "(" expression ")" // see tupleLiteral
|
||||||
|
* : literalConstant
|
||||||
|
* : functionLiteral
|
||||||
|
* : tupleLiteral
|
||||||
|
* : listLiteral
|
||||||
|
* : mapLiteral
|
||||||
|
* : range
|
||||||
|
* : "null"
|
||||||
|
* : "this" ("<" type ">")?
|
||||||
|
* : memberAccessExpression
|
||||||
|
* : expressionWithPrecedences
|
||||||
|
* : match
|
||||||
|
* : if
|
||||||
|
* : "typeof"
|
||||||
|
* : "new" constructorInvocation
|
||||||
|
* : objectLiteral
|
||||||
|
* : declaration
|
||||||
|
* : jump
|
||||||
|
* : loop
|
||||||
|
* // block is syntactically equivalent to a functionLiteral with no parameters
|
||||||
|
* ;
|
||||||
|
*/
|
||||||
|
public void parseExpression() {
|
||||||
|
advance(); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ import org.jetbrains.jet.JetNodeTypes;
|
|||||||
public class JetParser implements PsiParser {
|
public class JetParser implements PsiParser {
|
||||||
@NotNull
|
@NotNull
|
||||||
public ASTNode parse(IElementType iElementType, PsiBuilder psiBuilder) {
|
public ASTNode parse(IElementType iElementType, PsiBuilder psiBuilder) {
|
||||||
new JetParsing(psiBuilder).parseFile();
|
new JetParsing(new SemanticWitespaceAwarePsiBuilder(psiBuilder)).parseFile();
|
||||||
return psiBuilder.getTreeBuilt();
|
return psiBuilder.getTreeBuilt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
package org.jetbrains.jet.lang.parsing;
|
package org.jetbrains.jet.lang.parsing;
|
||||||
|
|
||||||
import com.intellij.lang.PsiBuilder;
|
import com.intellij.lang.PsiBuilder;
|
||||||
import com.intellij.lang.WhitespaceSkippedCallback;
|
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import com.intellij.psi.tree.TokenSet;
|
import com.intellij.psi.tree.TokenSet;
|
||||||
import org.jetbrains.jet.JetNodeType;
|
import org.jetbrains.jet.JetNodeType;
|
||||||
@@ -17,7 +16,7 @@ import java.util.Map;
|
|||||||
import static org.jetbrains.jet.JetNodeTypes.*;
|
import static org.jetbrains.jet.JetNodeTypes.*;
|
||||||
import static org.jetbrains.jet.lexer.JetTokens.*;
|
import static org.jetbrains.jet.lexer.JetTokens.*;
|
||||||
|
|
||||||
public class JetParsing {
|
public class JetParsing extends AbstractJetParsing {
|
||||||
private static final Map<String, IElementType> MODIFIER_KEYWORD_MAP = new HashMap<String, IElementType>();
|
private static final Map<String, IElementType> MODIFIER_KEYWORD_MAP = new HashMap<String, IElementType>();
|
||||||
static {
|
static {
|
||||||
for (IElementType softKeyword : MODIFIER_KEYWORDS.getTypes()) {
|
for (IElementType softKeyword : MODIFIER_KEYWORDS.getTypes()) {
|
||||||
@@ -34,24 +33,11 @@ public class JetParsing {
|
|||||||
private static final TokenSet NAMESPACE_NAME_RECOVERY_SET = TokenSet.create(DOT, EOL_OR_SEMICOLON);
|
private static final TokenSet NAMESPACE_NAME_RECOVERY_SET = TokenSet.create(DOT, EOL_OR_SEMICOLON);
|
||||||
private static final TokenSet TYPE_REF_FIRST = TokenSet.create(LBRACKET, IDENTIFIER, LBRACE, LPAR);
|
private static final TokenSet TYPE_REF_FIRST = TokenSet.create(LBRACKET, IDENTIFIER, LBRACE, LPAR);
|
||||||
|
|
||||||
private final WhitespaceSkippedCallback myWhitespaceSkippedCallback = new WhitespaceSkippedCallback() {
|
private final JetExpressionParsing myExpressionParsing;
|
||||||
public void onSkip(IElementType type, int start, int end) {
|
|
||||||
CharSequence whitespace = JetParsing.this.myBuilder.getOriginalText();
|
|
||||||
for (int i = start; i < end; i++) {
|
|
||||||
char c = whitespace.charAt(i);
|
|
||||||
if (c == '\n') {
|
|
||||||
myEOLInLastWhitespace = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private final PsiBuilder myBuilder;
|
|
||||||
private boolean myEOLInLastWhitespace;
|
|
||||||
|
|
||||||
public JetParsing(PsiBuilder myBuilder) {
|
public JetParsing(SemanticWitespaceAwarePsiBuilder builder) {
|
||||||
this.myBuilder = myBuilder;
|
super(builder);
|
||||||
myBuilder.setWhitespaceSkippedCallback(myWhitespaceSkippedCallback);
|
this.myExpressionParsing = new JetExpressionParsing(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -350,7 +336,7 @@ public class JetParsing {
|
|||||||
type = NAMED_ARGUMENT;
|
type = NAMED_ARGUMENT;
|
||||||
}
|
}
|
||||||
if (at(OUT_KEYWORD) || at(REF_KEYWORD)) advance(); // REF or OUT
|
if (at(OUT_KEYWORD) || at(REF_KEYWORD)) advance(); // REF or OUT
|
||||||
parseExpression();
|
myExpressionParsing.parseExpression();
|
||||||
argument.done(type);
|
argument.done(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,7 +531,7 @@ public class JetParsing {
|
|||||||
|
|
||||||
if (at(BY_KEYWORD)) {
|
if (at(BY_KEYWORD)) {
|
||||||
advance(); // BY_KEYWORD
|
advance(); // BY_KEYWORD
|
||||||
parseExpression();
|
myExpressionParsing.parseExpression();
|
||||||
delegator.done(DELEGATOR_BY);
|
delegator.done(DELEGATOR_BY);
|
||||||
}
|
}
|
||||||
else if (at(LPAR)) {
|
else if (at(LPAR)) {
|
||||||
@@ -625,39 +611,11 @@ public class JetParsing {
|
|||||||
|
|
||||||
if (at(EQ)) {
|
if (at(EQ)) {
|
||||||
advance(); // EQ
|
advance(); // EQ
|
||||||
parseExpression();
|
myExpressionParsing.parseExpression();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* expression
|
|
||||||
* : "(" expression ")" // see tupleLiteral
|
|
||||||
* : literalConstant
|
|
||||||
* : functionLiteral
|
|
||||||
* : tupleLiteral
|
|
||||||
* : listLiteral
|
|
||||||
* : mapLiteral
|
|
||||||
* : range
|
|
||||||
* : "null"
|
|
||||||
* : "this" ("<" type ">")?
|
|
||||||
* : memberAccessExpression
|
|
||||||
* : expressionWithPrecedences
|
|
||||||
* : match
|
|
||||||
* : if
|
|
||||||
* : "typeof"
|
|
||||||
* : "new" constructorInvocation
|
|
||||||
* : objectLiteral
|
|
||||||
* : declaration
|
|
||||||
* : jump
|
|
||||||
* : loop
|
|
||||||
* // block is syntactically equivalent to a functionLiteral with no parameters
|
|
||||||
* ;
|
|
||||||
*/
|
|
||||||
private void parseExpression() {
|
|
||||||
advance(); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* typeParameters
|
* typeParameters
|
||||||
* : ("<" typeParameter{","} ">"
|
* : ("<" typeParameter{","} ">"
|
||||||
@@ -892,93 +850,4 @@ public class JetParsing {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private boolean expect(JetToken expectation, String message) {
|
|
||||||
return expect(expectation, message, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PsiBuilder.Marker mark() {
|
|
||||||
return myBuilder.mark();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void error(String message) {
|
|
||||||
myBuilder.error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean expect(JetToken expectation, String message, TokenSet recoverySet) {
|
|
||||||
if (at(expectation)) {
|
|
||||||
advance(); // expectation
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
errorWithRecovery(message, recoverySet);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void errorWithRecovery(String message, TokenSet recoverySet) {
|
|
||||||
JetToken tt = tt();
|
|
||||||
if (recoverySet == null || recoverySet.contains(tt)
|
|
||||||
|| (recoverySet.contains(EOL_OR_SEMICOLON)
|
|
||||||
&& (tt == SEMICOLON || myEOLInLastWhitespace))) {
|
|
||||||
error(message);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
errorAndAdvance(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void errorAndAdvance(String message) {
|
|
||||||
PsiBuilder.Marker err = mark();
|
|
||||||
advance(); // erroneous token
|
|
||||||
err.error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean eof() {
|
|
||||||
return myBuilder.eof();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void advance() {
|
|
||||||
myEOLInLastWhitespace = false;
|
|
||||||
myBuilder.advanceLexer();
|
|
||||||
}
|
|
||||||
|
|
||||||
private JetToken tt() {
|
|
||||||
return (JetToken) myBuilder.getTokenType();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean at(final IElementType expectation) {
|
|
||||||
JetToken token = tt();
|
|
||||||
if (token == expectation) return true;
|
|
||||||
if (expectation == EOL_OR_SEMICOLON) {
|
|
||||||
if (token == SEMICOLON) return true;
|
|
||||||
if (myEOLInLastWhitespace) return true;
|
|
||||||
}
|
|
||||||
if (token == IDENTIFIER && expectation instanceof JetKeywordToken) {
|
|
||||||
JetKeywordToken expectedKeyword = (JetKeywordToken) expectation;
|
|
||||||
if (expectedKeyword.isSoft() && expectedKeyword.getValue().equals(myBuilder.getTokenText())) {
|
|
||||||
myBuilder.remapCurrentToken(expectation);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IElementType lookahead(int k) {
|
|
||||||
PsiBuilder.Marker tmp = mark();
|
|
||||||
for (int i = 0; i < k; i++) advance();
|
|
||||||
|
|
||||||
JetToken tt = tt();
|
|
||||||
tmp.rollbackTo();
|
|
||||||
return tt;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void consumeIf(JetToken token) {
|
|
||||||
if (at(token)) advance(); // token
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package org.jetbrains.jet.lang.parsing;
|
||||||
|
|
||||||
|
import com.intellij.lang.*;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.openapi.util.Key;
|
||||||
|
import com.intellij.psi.tree.IElementType;
|
||||||
|
import com.intellij.psi.tree.TokenSet;
|
||||||
|
import com.intellij.util.diff.FlyweightCapableTreeStructure;
|
||||||
|
import org.jetbrains.annotations.NonNls;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copied from JavaParserUtil
|
||||||
|
*
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class PsiBuilderAdapter implements PsiBuilder {
|
||||||
|
protected final PsiBuilder myDelegate;
|
||||||
|
|
||||||
|
public PsiBuilderAdapter(final PsiBuilder delegate) {
|
||||||
|
myDelegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project getProject() {
|
||||||
|
return myDelegate.getProject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharSequence getOriginalText() {
|
||||||
|
return myDelegate.getOriginalText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void advanceLexer() {
|
||||||
|
myDelegate.advanceLexer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public IElementType getTokenType() {
|
||||||
|
return myDelegate.getTokenType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTokenTypeRemapper(final ITokenTypeRemapper remapper) {
|
||||||
|
myDelegate.setTokenTypeRemapper(remapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWhitespaceSkippedCallback(WhitespaceSkippedCallback callback) {
|
||||||
|
myDelegate.setWhitespaceSkippedCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remapCurrentToken(IElementType type) {
|
||||||
|
myDelegate.remapCurrentToken(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IElementType lookAhead(int steps) {
|
||||||
|
return myDelegate.lookAhead(steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@NonNls
|
||||||
|
public String getTokenText() {
|
||||||
|
return myDelegate.getTokenText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCurrentOffset() {
|
||||||
|
return myDelegate.getCurrentOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Marker mark() {
|
||||||
|
return myDelegate.mark();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void error(final String messageText) {
|
||||||
|
myDelegate.error(messageText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean eof() {
|
||||||
|
return myDelegate.eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ASTNode getTreeBuilt() {
|
||||||
|
return myDelegate.getTreeBuilt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FlyweightCapableTreeStructure<LighterASTNode> getLightTree() {
|
||||||
|
return myDelegate.getLightTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDebugMode(final boolean dbgMode) {
|
||||||
|
myDelegate.setDebugMode(dbgMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enforceCommentTokens(final TokenSet tokens) {
|
||||||
|
myDelegate.enforceCommentTokens(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public LighterASTNode getLatestDoneMarker() {
|
||||||
|
return myDelegate.getLatestDoneMarker();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public <T> T getUserData(@NotNull final Key<T> key) {
|
||||||
|
return myDelegate.getUserData(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void putUserData(@NotNull final Key<T> key, @Nullable final T value) {
|
||||||
|
myDelegate.putUserData(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T getUserDataUnprotected(@NotNull final Key<T> key) {
|
||||||
|
return myDelegate.getUserDataUnprotected(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void putUserDataUnprotected(@NotNull Key<T> key, @Nullable T value) {
|
||||||
|
myDelegate.putUserDataUnprotected(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package org.jetbrains.jet.lang.parsing;
|
||||||
|
|
||||||
|
|
||||||
|
import com.intellij.lang.PsiBuilder;
|
||||||
|
import com.intellij.lang.WhitespaceSkippedCallback;
|
||||||
|
import com.intellij.psi.tree.IElementType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class SemanticWitespaceAwarePsiBuilder extends PsiBuilderAdapter {
|
||||||
|
private final WhitespaceSkippedCallback myWhitespaceSkippedCallback = new WhitespaceSkippedCallback() {
|
||||||
|
public void onSkip(IElementType type, int start, int end) {
|
||||||
|
CharSequence whitespace = getOriginalText();
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
char c = whitespace.charAt(i);
|
||||||
|
if (c == '\n') {
|
||||||
|
myEOLInLastWhitespace = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private boolean myEOLInLastWhitespace;
|
||||||
|
|
||||||
|
public SemanticWitespaceAwarePsiBuilder(final PsiBuilder delegate) {
|
||||||
|
super(delegate);
|
||||||
|
delegate.setWhitespaceSkippedCallback(myWhitespaceSkippedCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void advanceLexer() {
|
||||||
|
myEOLInLastWhitespace = false;
|
||||||
|
super.advanceLexer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean eolInLastWhitespace() {
|
||||||
|
return myEOLInLastWhitespace;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user