Expression parser factored out

This commit is contained in:
Andrey Breslav
2010-12-16 19:02:15 +03:00
parent 0783a878dc
commit ddf0213e44
7 changed files with 319 additions and 141 deletions
+1 -1
View File
@@ -24,7 +24,7 @@
<component name="ProjectResources">
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
</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" />
</component>
<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 {
@NotNull
public ASTNode parse(IElementType iElementType, PsiBuilder psiBuilder) {
new JetParsing(psiBuilder).parseFile();
new JetParsing(new SemanticWitespaceAwarePsiBuilder(psiBuilder)).parseFile();
return psiBuilder.getTreeBuilt();
}
}
@@ -4,7 +4,6 @@
package org.jetbrains.jet.lang.parsing;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.WhitespaceSkippedCallback;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.jet.JetNodeType;
@@ -17,7 +16,7 @@ import java.util.Map;
import static org.jetbrains.jet.JetNodeTypes.*;
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>();
static {
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 TYPE_REF_FIRST = TokenSet.create(LBRACKET, IDENTIFIER, LBRACE, LPAR);
private final WhitespaceSkippedCallback myWhitespaceSkippedCallback = new WhitespaceSkippedCallback() {
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;
private final JetExpressionParsing myExpressionParsing;
public JetParsing(PsiBuilder myBuilder) {
this.myBuilder = myBuilder;
myBuilder.setWhitespaceSkippedCallback(myWhitespaceSkippedCallback);
public JetParsing(SemanticWitespaceAwarePsiBuilder builder) {
super(builder);
this.myExpressionParsing = new JetExpressionParsing(builder);
}
/*
@@ -350,7 +336,7 @@ public class JetParsing {
type = NAMED_ARGUMENT;
}
if (at(OUT_KEYWORD) || at(REF_KEYWORD)) advance(); // REF or OUT
parseExpression();
myExpressionParsing.parseExpression();
argument.done(type);
}
@@ -545,7 +531,7 @@ public class JetParsing {
if (at(BY_KEYWORD)) {
advance(); // BY_KEYWORD
parseExpression();
myExpressionParsing.parseExpression();
delegator.done(DELEGATOR_BY);
}
else if (at(LPAR)) {
@@ -625,39 +611,11 @@ public class JetParsing {
if (at(EQ)) {
advance(); // EQ
parseExpression();
myExpressionParsing.parseExpression();
}
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
* : ("<" typeParameter{","} ">"
@@ -892,93 +850,4 @@ public class JetParsing {
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;
}
}