Token stream predicates for lookahead

This commit is contained in:
Andrey Breslav
2010-12-29 16:56:44 +03:00
parent 9d9ee762e1
commit 88b5c26fe3
11 changed files with 317 additions and 122 deletions
@@ -155,35 +155,20 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
error.error(mesage);
}
/*
* Looks for a the last top-level (not inside any {} [] () <>) '.' occurring before a
* top-level occurrence of a token from the <code>stopSet</code>
*
* Returns -1 if no occurrence is found
*/
protected int findLastBefore(TokenSet lookFor, TokenSet stopAt, boolean dontStopRightAfterOccurrence) {
protected int matchTokenStreamPredicate(TokenStreamPattern pattern) {
PsiBuilder.Marker currentPosition = mark();
int lastOccurrence = -1;
int openAngleBrackets = 0;
int openBraces = 0;
int openParentheses = 0;
int openBrackets = 0;
IElementType previousToken = null;
while (!eof()) {
if (atSet(lookFor)
&& openAngleBrackets == 0
if (pattern.processToken(
myBuilder.getCurrentOffset(),
openAngleBrackets == 0
&& openBrackets == 0
&& openBraces == 0
&& openParentheses == 0) {
lastOccurrence = myBuilder.getCurrentOffset();
}
if (atSet(stopAt)) {
if (openAngleBrackets == 0
&& openBrackets == 0
&& openBraces == 0
&& openParentheses == 0
&& (!dontStopRightAfterOccurrence
|| !lookFor.contains(previousToken))) break;
&& openParentheses == 0)) {
break;
}
if (at(LPAR)) {
openParentheses++;
@@ -209,15 +194,65 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
else if (at(RBRACKET)) {
openBrackets--;
}
previousToken = tt();
advance(); // skip token
}
currentPosition.rollbackTo();
return lastOccurrence;
return pattern.result();
}
/*
* Looks for a the last top-level (not inside any {} [] () <>) '.' occurring before a
* top-level occurrence of a token from the <code>stopSet</code>
*
* Returns -1 if no occurrence is found
*/
protected int findLastBefore(TokenSet lookFor, TokenSet stopAt, boolean dontStopRightAfterOccurrence) {
return matchTokenStreamPredicate(new LastBefore(new AtSet(lookFor), new AtSet(stopAt), dontStopRightAfterOccurrence));
}
protected boolean eol() {
return myBuilder.eolInLastWhitespace() || eof();
}
protected class At implements TokenStreamPredicate {
private final IElementType lookFor;
private final boolean topLevelOnly;
public At(IElementType lookFor, boolean topLevelOnly) {
this.lookFor = lookFor;
this.topLevelOnly = topLevelOnly;
}
public At(IElementType lookFor) {
this(lookFor, true);
}
@Override
public boolean matching(boolean topLevel) {
return (topLevel || !topLevelOnly) && at(lookFor);
}
}
protected class AtSet implements TokenStreamPredicate {
private final TokenSet lookFor;
private final boolean topLevelOnly;
public AtSet(TokenSet lookFor, boolean topLevelOnly) {
this.lookFor = lookFor;
this.topLevelOnly = topLevelOnly;
}
public AtSet(TokenSet lookFor) {
this(lookFor, true);
}
@Override
public boolean matching(boolean topLevel) {
return (topLevel || !topLevelOnly) && atSet(lookFor);
}
}
}
@@ -0,0 +1,15 @@
package org.jetbrains.jet.lang.parsing;
/**
* @author abreslav
*/
public abstract class AbstractTokenStreamPattern implements TokenStreamPattern {
protected int lastOccurrence = -1;
@Override
public int result() {
return lastOccurrence;
}
}
@@ -0,0 +1,26 @@
package org.jetbrains.jet.lang.parsing;
/**
* @author abreslav
*/
public class FirstBefore extends AbstractTokenStreamPattern {
private final TokenStreamPredicate lookFor;
private final TokenStreamPredicate stopAt;
public FirstBefore(TokenStreamPredicate lookFor, TokenStreamPredicate stopAt) {
this.lookFor = lookFor;
this.stopAt = stopAt;
}
@Override
public boolean processToken(int offset, boolean topLevel) {
if (lookFor.matching(topLevel)) {
lastOccurrence = offset;
return true;
}
if (stopAt.matching(topLevel)) {
return true;
}
return false;
}
}
@@ -694,9 +694,26 @@ public class JetParsing extends AbstractJetParsing {
advance(); // VAL_KEYWORD or VAR_KEYWORD
// TODO: EOL_OR_SEMICOLON is too restrictive here
TokenSet propertyNameFollow = TokenSet.create(COLON, EQ, LBRACE, SEMICOLON, EOL_OR_SEMICOLON);
TokenSet propertyNameFollow = TokenSet.create(COLON, EQ, LBRACE, SEMICOLON);
int lastDot = findLastBefore(TokenSet.create(DOT), propertyNameFollow, true);
// int lastDot = findLastBefore(TokenSet.create(DOT), propertyNameFollow, true);
// TODO: constant
int lastDot = matchTokenStreamPredicate(new FirstBefore(new TokenStreamPredicate() {
@Override
public boolean matching(boolean topLevel) {
return topLevel
&& at(DOT);
}
}, new TokenStreamPredicate() {
@Override
public boolean matching(boolean topLevel) {
if (lookahead(1) == IDENTIFIER) {
IElementType lookahead2 = lookahead(2);
return lookahead2 != LT && lookahead2 != DOT;
}
return false;
}
}));
if (lastDot == -1) {
parseAttributeList();
@@ -1258,6 +1275,7 @@ public class JetParsing extends AbstractJetParsing {
int lastLPar = findLastBefore(TokenSet.create(LPAR), TokenSet.create(RBRACE, COLON), false);
if (lastLPar >= 0 && lastLPar > myBuilder.getCurrentOffset()) {
PsiBuilder.Marker receiverType = mark();
// TODO : -1 is a hack
createTruncatedBuilder(lastLPar - 1).parseTypeRef();
receiverType.done(RECEIVER_TYPE);
advance(); // DOT
@@ -0,0 +1,37 @@
package org.jetbrains.jet.lang.parsing;
/**
* @author abreslav
*/
public class LastBefore extends AbstractTokenStreamPattern {
private final boolean dontStopRightAfterOccurrence;
private final TokenStreamPredicate lookFor;
private final TokenStreamPredicate stopAt;
private boolean previousLookForResult;
public LastBefore(TokenStreamPredicate lookFor, TokenStreamPredicate stopAt, boolean dontStopRightAfterOccurrence) {
this.lookFor = lookFor;
this.stopAt = stopAt;
this.dontStopRightAfterOccurrence = dontStopRightAfterOccurrence;
}
public LastBefore(TokenStreamPredicate lookFor, TokenStreamPredicate stopAt) {
this(lookFor, stopAt, false);
}
@Override
public boolean processToken(int offset, boolean topLevel) {
boolean lookForResult = lookFor.matching(topLevel);
if (lookForResult) {
lastOccurrence = offset;
}
if (stopAt.matching(topLevel)) {
if (topLevel
&& (!dontStopRightAfterOccurrence
|| !previousLookForResult)) return true;
}
previousLookForResult = lookForResult;
return false;
}
}
@@ -0,0 +1,22 @@
package org.jetbrains.jet.lang.parsing;
/**
* @author abreslav
*/
public interface TokenStreamPattern {
/**
* Called on each token
*
*
*
* @param offset
* @param topLevel indicates if no brackets (of types () [] {} <>) are currently unmatched
* @return <code>true</code> to stop
*/
boolean processToken(int offset, boolean topLevel);
/**
* @return the position where the predicate has matched, -1 if no match was found
*/
int result();
}
@@ -0,0 +1,8 @@
package org.jetbrains.jet.lang.parsing;
/**
* @author abreslav
*/
public interface TokenStreamPredicate {
boolean matching(boolean topLevel);
}