New Java parser (work in progress)

This commit is contained in:
Roman Shevchenko
2010-07-30 20:26:27 +04:00
parent 487f40c3f5
commit afb6253c83
17 changed files with 213 additions and 24 deletions
@@ -773,7 +773,7 @@ public class ExpressionParser {
}
private static void emptyExpression(final PsiBuilder builder) {
builder.mark().done(JavaElementType.EMPTY_EXPRESSION);
emptyElement(builder, JavaElementType.EMPTY_EXPRESSION);
}
@Nullable
@@ -110,13 +110,7 @@ public class StatementParser {
parseStatements(builder, (parseUntilEof ? BraceMode.TILL_LAST : BraceMode.TILL_FIRST));
// todo: check closing brace
//final TreeElement lastChild = elementToAdd.getLastChildNode();
//if (lastChild == null || lastChild.getElementType() != JavaTokenType.RBRACE){
// CompositeElement errorElement = Factory.createErrorElement(JavaErrorMessages.message("expected.rbrace"));
// elementToAdd.rawAddChildren(errorElement);
// elementToAdd.putUserData(TreeUtil.UNCLOSED_ELEMENT_PROPERTY, "");
//}
expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace"));
codeBlock.done(JavaElementType.CODE_BLOCK);
return codeBlock;
@@ -128,29 +122,26 @@ public class StatementParser {
if (statement != null) continue;
final IElementType tokenType = builder.getTokenType();
final PsiBuilder.Marker error = builder.mark();
builder.advanceLexer();
if (tokenType == JavaTokenType.RBRACE) {
if (braceMode == BraceMode.TILL_FIRST) {
error.drop();
return;
}
else if (braceMode == BraceMode.TILL_LAST) {
if (builder.getTokenType() == null) {
error.drop();
if (nextTokenType(builder) == null) {
return;
}
}
}
final PsiBuilder.Marker error = builder.mark();
builder.advanceLexer();
if (tokenType == JavaTokenType.ELSE_KEYWORD) {
error.error(JavaErrorMessages.message("else.without.if"));
}
else if (tokenType == JavaTokenType.CATCH_KEYWORD) {
error.error(JavaErrorMessages.message("catch.without.try"));
}
else if (tokenType == JavaTokenType.FINAL_KEYWORD) {
else if (tokenType == JavaTokenType.FINALLY_KEYWORD) {
error.error(JavaErrorMessages.message("finally.without.try"));
}
else {
@@ -516,22 +507,44 @@ public class StatementParser {
return statement;
}
@NotNull
@Nullable
private static PsiBuilder.Marker parseSwitchLabelStatement(final PsiBuilder builder) {
// todo: implement
throw new UnsupportedOperationException(builder.toString());
final PsiBuilder.Marker statement = builder.mark();
final boolean isCase = builder.getTokenType() == JavaTokenType.CASE_KEYWORD;
builder.advanceLexer();
if (isCase) {
final PsiBuilder.Marker expr = ExpressionParser.parse(builder);
if (expr == null) {
statement.rollbackTo();
return null;
}
}
expectOrError(builder, JavaTokenType.COLON, JavaErrorMessages.message("expected.colon"));
statement.done(JavaElementType.SWITCH_LABEL_STATEMENT);
return statement;
}
@NotNull
private static PsiBuilder.Marker parseBreakStatement(final PsiBuilder builder) {
// todo: implement
throw new UnsupportedOperationException(builder.toString());
final PsiBuilder.Marker statement = builder.mark();
builder.advanceLexer();
expect(builder, JavaTokenType.IDENTIFIER);
semicolon(builder);
statement.done(JavaElementType.BREAK_STATEMENT);
return statement;
}
@NotNull
private static PsiBuilder.Marker parseContinueStatement(final PsiBuilder builder) {
// todo: implement
throw new UnsupportedOperationException(builder.toString());
final PsiBuilder.Marker statement = builder.mark();
builder.advanceLexer();
expect(builder, JavaTokenType.IDENTIFIER);
semicolon(builder);
statement.done(JavaElementType.CONTINUE_STATEMENT);
return statement;
}
@NotNull
@@ -91,7 +91,7 @@ public interface JavaElementType {
IElementType ARRAY_INITIALIZER_EXPRESSION = new IJavaElementType("ARRAY_INITIALIZER_EXPRESSION");
IElementType INSTANCE_OF_EXPRESSION = new IJavaElementType("INSTANCE_OF_EXPRESSION");
IElementType CLASS_OBJECT_ACCESS_EXPRESSION = new IJavaElementType("CLASS_OBJECT_ACCESS_EXPRESSION");
IElementType EMPTY_EXPRESSION = new IJavaElementType("EMPTY_EXPRESSION");
IElementType EMPTY_EXPRESSION = new IJavaElementType("EMPTY_EXPRESSION", true);
IElementType EXPRESSION_LIST = new IJavaElementType("EXPRESSION_LIST", true);
@@ -123,6 +123,8 @@ public interface JavaElementType {
IElementType ANNOTATION_PARAMETER_LIST = new IJavaElementType("ANNOTATION_PARAMETER_LIST", true);
IElementType METHOD_RECEIVER = new IJavaElementType("METHOD_RECEIVER");
IElementType INSTANT_CODE_BLOCK = new IJavaElementType("CODE_BLOCK");
ILazyParseableElementType CODE_BLOCK = new IErrorCounterReparseableElementType("CODE_BLOCK", StdLanguages.JAVA) {
@Override
public ASTNode createNode(CharSequence text) {
@@ -0,0 +1,8 @@
PsiJavaFile:BlockEmpty.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiEmptyStatement
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,6 @@
PsiJavaFile:BlockIncomplete0.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiErrorElement:'}' expected
<empty list>
PsiWhiteSpace(' ')
@@ -0,0 +1,11 @@
PsiJavaFile:BlockIncomplete1.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
PsiErrorElement:'}' expected
<empty list>
@@ -0,0 +1,20 @@
PsiJavaFile:BlockIncomplete2.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiErrorElement:'else' without 'if'
PsiKeyword:else('else')
PsiEmptyStatement
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiErrorElement:'catch' without 'try'
PsiKeyword:catch('catch')
PsiEmptyStatement
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiErrorElement:'finally' without 'try'
PsiKeyword:finally('finally')
PsiEmptyStatement
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,9 @@
PsiJavaFile:BreakNormal0.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiBreakStatement
PsiKeyword:break('break')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,11 @@
PsiJavaFile:BreakNormal1.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiBreakStatement
PsiKeyword:break('break')
PsiWhiteSpace(' ')
PsiIdentifier:LABEL('LABEL')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,9 @@
PsiJavaFile:ContinueNormal0.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiContinueStatement
PsiKeyword:continue('continue')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,11 @@
PsiJavaFile:ContinueNormal1.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiContinueStatement
PsiKeyword:continue('continue')
PsiWhiteSpace(' ')
PsiIdentifier:LABEL('LABEL')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,8 @@
PsiJavaFile:SwitchLabelsIncomplete0.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected token
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,13 @@
PsiJavaFile:SwitchLabelsIncomplete1.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiSwitchLabelStatement
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiLiteralExpression:2
PsiJavaToken:INTEGER_LITERAL('2')
PsiErrorElement:':' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,10 @@
PsiJavaFile:SwitchLabelsIncomplete2.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiSwitchLabelStatement
PsiKeyword:default('default')
PsiErrorElement:':' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,18 @@
PsiJavaFile:SwitchLabelsIncomplete3.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiSwitchLabelStatement
PsiKeyword:default('default')
PsiErrorElement:':' expected
<empty list>
PsiWhiteSpace(' ')
PsiExpressionStatement
PsiLiteralExpression:3
PsiJavaToken:INTEGER_LITERAL('3')
PsiErrorElement:';' expected
<empty list>
PsiErrorElement:Unexpected token
PsiJavaToken:COLON(':')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -0,0 +1,24 @@
PsiJavaFile:SwitchLabelsNormal.java
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiSwitchLabelStatement
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiLiteralExpression:1
PsiJavaToken:INTEGER_LITERAL('1')
PsiJavaToken:COLON(':')
PsiWhiteSpace(' ')
PsiBreakStatement
PsiKeyword:break('break')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiSwitchLabelStatement
PsiKeyword:default('default')
PsiJavaToken:COLON(':')
PsiWhiteSpace(' ')
PsiBreakStatement
PsiKeyword:break('break')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -31,7 +31,17 @@ public class StatementParserTest extends JavaParsingTestCase {
public void testAssignmentSimple() { doParserTest("{ int[] a;\n a[0] = 0; }"); }
public void testBlockSimple() { doParserTest("{ {} }"); }
//public void testAnonymousInSmartCompletion() { doParserTest("{ new Foo(hash\n#) {};\n new Foo(hash\n#, bar) {};\n new Foo(hash\n#x) {}; }"); } // todo: spaces
public void testBlockEmpty() { doParserTest("{ ; }"); }
public void testAnonymousInSmartCompletion() { doParserTest("{ new Foo(hash\n#) {};\n new Foo(hash\n#, bar) {};\n new Foo(hash\n#x) {}; }"); }
public void testBlockIncomplete0() { doParserTest("{ "); }
public void testBlockIncomplete1() { doParserTest("{ { }"); }
public void testBlockIncomplete2() { doParserTest("{ else; catch; finally; }"); }
public void testBreakNormal0() { doParserTest("{ break; }"); }
public void testBreakNormal1() { doParserTest("{ break LABEL; }"); }
public void testContinueNormal0() { doParserTest("{ continue; }"); }
public void testContinueNormal1() { doParserTest("{ continue LABEL; }"); }
public void testLocalVar() { doParserTest("{ List<Integer> list; }"); }
public void testFor() { doParserTest("{ for(Iterator<String> it = null; it.hasNext();) { String s = it.next(); } }"); }
@@ -84,6 +94,12 @@ public class StatementParserTest extends JavaParsingTestCase {
public void testSwitchIncomplete4() { doParserTest("{ switch(){} }"); }
public void testSwitchIncomplete5() { doParserTest("{ switch(\n foo(); }"); }
public void testSwitchLabelsNormal() { doParserTest("{ case 1: break; default: break; }"); }
public void testSwitchLabelsIncomplete0() { doParserTest("{ case }"); }
public void testSwitchLabelsIncomplete1() { doParserTest("{ case 2 }"); }
public void testSwitchLabelsIncomplete2() { doParserTest("{ default }"); }
public void testSwitchLabelsIncomplete3() { doParserTest("{ default 3: }"); }
public void testSyncNormal() { doParserTest("{ synchronized(o){} }"); }
public void testSyncIncomplete0() { doParserTest("{ synchronized }"); }
public void testSyncIncomplete1() { doParserTest("{ synchronized( }"); }