Improve parser recovery inside of a block
Review URL: https://chromiumcodereview.appspot.com//10024009 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@6305 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
@@ -113,7 +113,7 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
private final boolean isDietParse;
|
||||
private final Set<String> prefixes;
|
||||
private final boolean corelibParse;
|
||||
private Set<Integer> errorHistory = new HashSet<Integer>();
|
||||
private final Set<Integer> errorHistory = new HashSet<Integer>();
|
||||
private boolean isParsingInterface;
|
||||
private boolean isTopLevelAbstract;
|
||||
private DartScanner.Position topLevelAbstractModifierPosition;
|
||||
@@ -161,7 +161,7 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
STATIC_KEYWORD,
|
||||
TYPEDEF_KEYWORD
|
||||
};
|
||||
|
||||
|
||||
public DartParser(Source source,
|
||||
String sourceCode,
|
||||
DartCompilerListener listener) {
|
||||
@@ -278,12 +278,12 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
if (optional(Token.CLASS)) {
|
||||
isParsingClass = true;
|
||||
node = done(parseClass());
|
||||
} else if (peekPseudoKeyword(0, INTERFACE_KEYWORD)
|
||||
} else if (peekPseudoKeyword(0, INTERFACE_KEYWORD)
|
||||
&& peek(1).equals(Token.IDENTIFIER)) {
|
||||
consume(Token.IDENTIFIER);
|
||||
isParsingInterface = true;
|
||||
node = done(parseClass());
|
||||
} else if (peekPseudoKeyword(0, TYPEDEF_KEYWORD)
|
||||
} else if (peekPseudoKeyword(0, TYPEDEF_KEYWORD)
|
||||
&& (peek(1).equals(Token.IDENTIFIER) || peek(1).equals(Token.VOID))) {
|
||||
consume(Token.IDENTIFIER);
|
||||
node = done(parseFunctionTypeAlias());
|
||||
@@ -329,7 +329,7 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
|| peekPseudoKeyword(n, INTERFACE_KEYWORD)
|
||||
|| peekPseudoKeyword(n, TYPEDEF_KEYWORD);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 'interface' and 'typedef' are valid to use as names of fields and methods, so you can't
|
||||
* just blindly recover when you see them in any context. This does a further test to make
|
||||
@@ -340,10 +340,10 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
if (peek(0).equals(Token.CLASS)) {
|
||||
return true;
|
||||
}
|
||||
if (peekPseudoKeyword(0, INTERFACE_KEYWORD)
|
||||
if (peekPseudoKeyword(0, INTERFACE_KEYWORD)
|
||||
&& peek(1).equals(Token.IDENTIFIER)) {
|
||||
return true;
|
||||
} else if (peekPseudoKeyword(0, TYPEDEF_KEYWORD)
|
||||
} else if (peekPseudoKeyword(0, TYPEDEF_KEYWORD)
|
||||
&& (peek(1).equals(Token.IDENTIFIER) || peek(1).equals(Token.VOID))) {
|
||||
return true;
|
||||
}
|
||||
@@ -958,7 +958,7 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
member = parseMethodOrAccessor(modifiers, null);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
member = parseFieldDeclaration(modifiers, null);
|
||||
expectStatmentTerminator();
|
||||
break;
|
||||
@@ -990,13 +990,13 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
&& peek(1) != Token.ASSIGN
|
||||
&& peek(1) != Token.SEMICOLON) {
|
||||
type = parseTypeAnnotation();
|
||||
|
||||
|
||||
// Check again for malformed method starting with 'final': final String ^ foo() { }
|
||||
if (peek(0).equals(Token.IDENTIFIER) && looksLikeMethodOrAccessorDefinition()) {
|
||||
reportError(position(), ParserErrorCode.FINAL_IS_NOT_ALLOWED_ON_A_METHOD_DEFINITION);
|
||||
member = parseMethodOrAccessor(modifiers, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
member = parseFieldDeclaration(modifiers, type);
|
||||
expectStatmentTerminator();
|
||||
@@ -1061,8 +1061,8 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
* | set identifier (
|
||||
* | operator (
|
||||
* | operator <op> (
|
||||
* | identifier (
|
||||
* | identifier DOT identifier (
|
||||
* | identifier (
|
||||
* | identifier DOT identifier (
|
||||
* | identifier DOT identifier DOT identifier (
|
||||
*
|
||||
* @return <code>true</code> if the signature of a method has been found. No tokens are consumed.
|
||||
@@ -1085,40 +1085,40 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
if (peekPseudoKeyword(0, NEGATE_KEYWORD) && peek(1).equals(Token.LPAREN)) {
|
||||
return true;
|
||||
}
|
||||
// TODO(zundel): Look for valid operator overload tokens. For now just assuming
|
||||
// TODO(zundel): Look for valid operator overload tokens. For now just assuming
|
||||
// non-idents are good enough
|
||||
// operator ??? (
|
||||
if (!(peek(0).equals(Token.IDENTIFIER) && peek(1).equals(Token.LPAREN))) {
|
||||
return true;
|
||||
}
|
||||
if (peek(0).equals(Token.LBRACK) && peek(1).equals(Token.RBRACK)) {
|
||||
// operator [] (
|
||||
// operator [] (
|
||||
if (peek(2).equals(Token.LPAREN)) {
|
||||
return true;
|
||||
}
|
||||
// operator []= (
|
||||
// operator []= (
|
||||
if (peek(2).equals(Token.ASSIGN) && peek(3).equals(Token.LPAREN)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (peekPseudoKeyword(0, GETTER_KEYWORD)
|
||||
|| peekPseudoKeyword(0, SETTER_KEYWORD)) {
|
||||
next();
|
||||
// Using 'get' or 'set' as a field name is valid
|
||||
if (peek(0).equals(Token.SEMICOLON) || peek(0).equals(Token.ASSIGN)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Using 'get' or 'set' as a method name is valid (but discouraged)
|
||||
if (peek(0).equals(Token.LPAREN)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// normal case: get foo (
|
||||
if (peek(0).equals(Token.IDENTIFIER) && peek(1).equals(Token.LPAREN)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1227,7 +1227,7 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(operation.getSyntax());
|
||||
if (found) {
|
||||
@@ -1858,9 +1858,9 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
Position prevPositionStart = ctx.getTokenLocation().getBegin();
|
||||
Position prevPositionEnd = ctx.getTokenLocation().getEnd();
|
||||
Token token = next();
|
||||
if (lastResult instanceof DartSuperExpression
|
||||
if (lastResult instanceof DartSuperExpression
|
||||
&& (token == Token.AND || token == Token.OR)) {
|
||||
reportErrorAtPosition(prevPositionStart, prevPositionEnd,
|
||||
reportErrorAtPosition(prevPositionStart, prevPositionEnd,
|
||||
ParserErrorCode.SUPER_IS_NOT_VALID_AS_A_BOOLEAN_OPERAND);
|
||||
}
|
||||
DartExpression right;
|
||||
@@ -1879,7 +1879,7 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
if (right instanceof DartSuperExpression) {
|
||||
reportError(position(), ParserErrorCode.SUPER_CANNOT_BE_USED_AS_THE_SECOND_OPERAND);
|
||||
}
|
||||
|
||||
|
||||
lastResult = right;
|
||||
result = doneWithoutConsuming(new DartBinaryExpression(token, result, right));
|
||||
if ((token == Token.IS)
|
||||
@@ -1924,7 +1924,7 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
expect(Token.LPAREN);
|
||||
// SEMICOLON is for error recovery
|
||||
boolean namedArgumentParsed = false;
|
||||
while (!match(Token.RPAREN) && !match(Token.EOS) && !match(Token.SEMICOLON)) {
|
||||
outer: while (!match(Token.RPAREN) && !match(Token.EOS) && !match(Token.SEMICOLON)) {
|
||||
beginParameter();
|
||||
DartExpression expression;
|
||||
if (peek(1) == Token.COLON) {
|
||||
@@ -1946,9 +1946,19 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
case RPAREN:
|
||||
break;
|
||||
default:
|
||||
// Make sure that the parser's state is advanced.
|
||||
Token actual = peek(0);
|
||||
ctx.advance();
|
||||
Set<Token> terminals = collectTerminalAnnotations();
|
||||
if (terminals.contains(actual) || looksLikeTopLevelKeyword()) {
|
||||
// Looks like a method already on the stack could use this token.
|
||||
ctx.begin();
|
||||
reportError(ctx.getTokenLocation().getEnd(),
|
||||
ParserErrorCode.EXPECTED_COMMA_OR_RIGHT_PAREN, actual);
|
||||
ctx.rollback();
|
||||
break outer;
|
||||
} else {
|
||||
// Advance the parser state if no other method on the stack can use this token.
|
||||
ctx.advance();
|
||||
}
|
||||
reportError(ctx.getTokenLocation().getEnd(),
|
||||
ParserErrorCode.EXPECTED_COMMA_OR_RIGHT_PAREN, actual);
|
||||
break;
|
||||
@@ -1972,9 +1982,9 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
private DartExpression parseConditionalExpression() {
|
||||
beginConditionalExpression();
|
||||
DartExpression result = parseBinaryExpression(4);
|
||||
if (result instanceof DartSuperExpression) {
|
||||
if (result instanceof DartSuperExpression) {
|
||||
reportError(position(), ParserErrorCode.SUPER_IS_NOT_VALID_ALONE_OR_AS_A_BOOLEAN_OPERAND);
|
||||
}
|
||||
}
|
||||
if (peek(0) != Token.CONDITIONAL) {
|
||||
return done(result);
|
||||
}
|
||||
@@ -2078,7 +2088,7 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
case STRING_SEGMENT:
|
||||
case STRING_EMBED_EXP_START:
|
||||
return parseStringInterpolation();
|
||||
|
||||
|
||||
default:
|
||||
DartExpression expression = parseExpression();
|
||||
reportError(position(), ParserErrorCode.EXPECTED_STRING_LITERAL);
|
||||
@@ -2182,7 +2192,13 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
if (unexpectedString == null && unexpected != Token.EOS) {
|
||||
unexpectedString = unexpected.getSyntax();
|
||||
}
|
||||
next();
|
||||
|
||||
// Don't eat tokens that could be used to successfully terminate a non-terminal
|
||||
// further up the stack.
|
||||
Set<Token> terminals = collectTerminalAnnotations();
|
||||
if (!looksLikeTopLevelKeyword() && !terminals.contains(unexpected)) {
|
||||
next();
|
||||
}
|
||||
reportUnexpectedToken(position(), null, unexpected);
|
||||
StringBuilder tokenStr = new StringBuilder();
|
||||
if (unexpectedString != null) {
|
||||
@@ -2324,7 +2340,7 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
ensureAssignable(result);
|
||||
consume(token);
|
||||
result = doneWithoutConsuming(new DartUnaryExpression(token, result, false));
|
||||
}
|
||||
}
|
||||
|
||||
return done(result);
|
||||
}
|
||||
@@ -2368,8 +2384,8 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
|
||||
private class DartStringInterpolationBuilder {
|
||||
|
||||
private List<DartStringLiteral> strings = new ArrayList<DartStringLiteral>();
|
||||
private List<DartExpression> expressions = new ArrayList<DartExpression>();
|
||||
private final List<DartStringLiteral> strings = new ArrayList<DartStringLiteral>();
|
||||
private final List<DartExpression> expressions = new ArrayList<DartExpression>();
|
||||
private LastSeenNode lastSeen = LastSeenNode.NONE;
|
||||
|
||||
DartStringInterpolationBuilder() {
|
||||
@@ -2942,6 +2958,7 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
* ;
|
||||
* </pre>
|
||||
*/
|
||||
@Terminals(tokens={Token.RBRACE})
|
||||
private DartBlock parseBlock() {
|
||||
if (isDietParse) {
|
||||
expect(Token.LBRACE);
|
||||
@@ -2963,15 +2980,16 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
// Return an empty block so we don't generate unparseable code.
|
||||
return emptyBlock;
|
||||
} else {
|
||||
beginBlock();
|
||||
List<DartStatement> statements = new ArrayList<DartStatement>();
|
||||
Token nextToken = peek(0);
|
||||
if (!nextToken.equals(Token.LBRACE)
|
||||
&& (looksLikeTopLevelKeyword() || nextToken.equals(Token.RBRACE))) {
|
||||
beginBlock();
|
||||
// Allow recovery back to the top level.
|
||||
reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
|
||||
return done(new DartBlock(new ArrayList<DartStatement>()));
|
||||
}
|
||||
}
|
||||
beginBlock();
|
||||
List<DartStatement> statements = new ArrayList<DartStatement>();
|
||||
expect(Token.LBRACE);
|
||||
while (!match(Token.RBRACE) && !EOS()) {
|
||||
if (looksLikeTopLevelKeyword()) {
|
||||
@@ -3266,12 +3284,12 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
|
||||
// Things that we know can't be valid statements get a synthetic error statement
|
||||
case RBRACE:
|
||||
case CLASS:
|
||||
case CLASS:
|
||||
// no need to create a separate parser event as the AST node is enough
|
||||
beginEmptyStatement();
|
||||
// TODO(jat): other tokens that should be caught here?
|
||||
return done(parseErrorStatement());
|
||||
|
||||
|
||||
case IDENTIFIER:
|
||||
// We have already eliminated function declarations earlier, so check for:
|
||||
// a) variable declarations;
|
||||
@@ -3399,7 +3417,8 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
*/
|
||||
private void expectCloseParen() {
|
||||
int parenCount = 1;
|
||||
switch (peek(0)) {
|
||||
Token nextToken = peek(0);
|
||||
switch (nextToken) {
|
||||
case RPAREN:
|
||||
expect(Token.RPAREN);
|
||||
return;
|
||||
@@ -3407,14 +3426,20 @@ public class DartParser extends CompletionHooksParserBase {
|
||||
case EOS:
|
||||
case LBRACE:
|
||||
case SEMICOLON:
|
||||
reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
|
||||
reportError(position(), ParserErrorCode.EXPECTED_TOKEN, Token.RPAREN.getSyntax(),
|
||||
nextToken.getSyntax());
|
||||
return;
|
||||
|
||||
case LPAREN:
|
||||
++parenCount;
|
||||
//$FALL-THROUGH$
|
||||
default:
|
||||
reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
|
||||
reportError(position(), ParserErrorCode.EXPECTED_TOKEN, Token.RPAREN.getSyntax(),
|
||||
nextToken.getSyntax());
|
||||
Set<Token> terminals = this.collectTerminalAnnotations();
|
||||
if (terminals.contains(nextToken) || looksLikeTopLevelKeyword()) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,17 @@
|
||||
package com.google.dart.compiler.parser;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.dart.compiler.ast.DartBinaryExpression;
|
||||
import com.google.dart.compiler.ast.DartClass;
|
||||
import com.google.dart.compiler.ast.DartExprStmt;
|
||||
import com.google.dart.compiler.ast.DartFieldDefinition;
|
||||
import com.google.dart.compiler.ast.DartIdentifier;
|
||||
import com.google.dart.compiler.ast.DartMethodDefinition;
|
||||
import com.google.dart.compiler.ast.DartPropertyAccess;
|
||||
import com.google.dart.compiler.ast.DartUnit;
|
||||
import com.google.dart.compiler.ast.DartUnqualifiedInvocation;
|
||||
import com.google.dart.compiler.ast.DartVariable;
|
||||
import com.google.dart.compiler.ast.DartVariableStatement;
|
||||
|
||||
public class ParserRecoveryTest extends AbstractParserTest {
|
||||
|
||||
@@ -17,7 +23,7 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
public void testStringsErrors() {
|
||||
// Implemented elsewhere
|
||||
}
|
||||
|
||||
|
||||
public void testVarOnMethodDefinition() {
|
||||
// This syntax is illegal, and should produce errors, but since it is a common error,
|
||||
// we want to make sure it produce a valid AST for editor users
|
||||
@@ -37,9 +43,9 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
assertEquals("f2", ((DartIdentifier)(f2.getName())).getName());
|
||||
// Make sure that parsing continue
|
||||
DartMethodDefinition f3 = (DartMethodDefinition)(A.getMembers().get(1));
|
||||
assertEquals("f3", ((DartIdentifier)(f3.getName())).getName());
|
||||
assertEquals("f3", ((DartIdentifier)(f3.getName())).getName());
|
||||
}
|
||||
|
||||
|
||||
public void testFinalOnMethodDefinition() {
|
||||
// This syntax is illegal, and should produce errors, but since it is a common error,
|
||||
// we want to make sure it produce a valid AST for editor users
|
||||
@@ -62,9 +68,9 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
DartMethodDefinition f3 = (DartMethodDefinition)(A.getMembers().get(1));
|
||||
assertEquals("f3", ((DartIdentifier)(f3.getName())).getName());
|
||||
DartMethodDefinition f4 = (DartMethodDefinition)(A.getMembers().get(2));
|
||||
assertEquals("f4", ((DartIdentifier)(f4.getName())).getName());
|
||||
assertEquals("f4", ((DartIdentifier)(f4.getName())).getName());
|
||||
}
|
||||
|
||||
|
||||
public void testRecoverToTopLevel1() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_to_toplevel1.dart",
|
||||
Joiner.on("\n").join(
|
||||
@@ -104,8 +110,8 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
assertEquals("B", B.getName().getName());
|
||||
DartFieldDefinition B_b = (DartFieldDefinition)B.getMembers().get(0);
|
||||
assertEquals("b", B_b.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testRecoverToTopLevel3() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_to_toplevel3.dart",
|
||||
Joiner.on("\n").join(
|
||||
@@ -125,8 +131,8 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
assertEquals("B", B.getName().getName());
|
||||
DartFieldDefinition B_b = (DartFieldDefinition)B.getMembers().get(0);
|
||||
assertEquals("b", B_b.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testRecoverToTopLevel4() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_to_toplevel4.dart",
|
||||
Joiner.on("\n").join(
|
||||
@@ -146,8 +152,8 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
assertEquals("B", B.getName().getName());
|
||||
DartFieldDefinition B_b = (DartFieldDefinition)B.getMembers().get(0);
|
||||
assertEquals("b", B_b.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testRecoverToTopLevel5() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_to_toplevel5.dart",
|
||||
Joiner.on("\n").join(
|
||||
@@ -167,8 +173,8 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
assertEquals("B", B.getName().getName());
|
||||
DartFieldDefinition B_b = (DartFieldDefinition)B.getMembers().get(0);
|
||||
assertEquals("b", B_b.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testRecoverToTopLevel6() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_to_toplevel6.dart",
|
||||
Joiner.on("\n").join(
|
||||
@@ -188,8 +194,8 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
assertEquals("B", B.getName().getName());
|
||||
DartFieldDefinition B_b = (DartFieldDefinition)B.getMembers().get(0);
|
||||
assertEquals("b", B_b.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testRecoverToTopLevel7() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_to_toplevel7.dart",
|
||||
Joiner.on("\n").join(
|
||||
@@ -209,8 +215,8 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
assertEquals("B", B.getName().getName());
|
||||
DartFieldDefinition B_b = (DartFieldDefinition)B.getMembers().get(0);
|
||||
assertEquals("b", B_b.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testRecoverToTopLevel8() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_to_toplevel8.dart",
|
||||
Joiner.on("\n").join(
|
||||
@@ -232,8 +238,8 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
assertEquals("B", B.getName().getName());
|
||||
DartFieldDefinition B_b = (DartFieldDefinition)B.getMembers().get(0);
|
||||
assertEquals("b", B_b.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testReservedWordClass() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_reserved_word_class",
|
||||
Joiner.on("\n").join(
|
||||
@@ -247,21 +253,21 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
assertEquals("foo", foo.getName().getName());
|
||||
DartMethodDefinition mainMethod = (DartMethodDefinition)unit.getTopLevelNodes().get(1);
|
||||
assertEquals("main", ((DartIdentifier)mainMethod.getName()).getName());
|
||||
// The recovery on 'int class' closes the main method, assuming int class = 10 is a
|
||||
// The recovery on 'int class' closes the main method, assuming int class = 10 is a
|
||||
// new toplevel so 'print' ends up as a bogus top level node.
|
||||
DartClass bar = (DartClass)unit.getTopLevelNodes().get(3);
|
||||
assertEquals("bar", bar.getName().getName());
|
||||
assertEquals("bar", bar.getName().getName());
|
||||
}
|
||||
|
||||
|
||||
public void testBadOperatorRecovery() {
|
||||
DartUnit unit = parseUnit("phony_bad_operator_recovery",
|
||||
Joiner.on("\n").join(
|
||||
"class foo {",
|
||||
" operator / (arg) {}",
|
||||
" operator /= (arg) {}",
|
||||
" operator /= (arg) {}",
|
||||
" operator ][ (arg) {}",
|
||||
" operator === (arg) {}",
|
||||
" operator + (arg) {}",
|
||||
" operator + (arg) {}",
|
||||
"}"),
|
||||
ParserErrorCode.OPERATOR_IS_NOT_USER_DEFINABLE, 3, 12,
|
||||
ParserErrorCode.OPERATOR_IS_NOT_USER_DEFINABLE, 4, 12,
|
||||
@@ -275,11 +281,11 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
DartMethodDefinition opNonsense = (DartMethodDefinition)foo.getMembers().get(2);
|
||||
assertEquals("][", ((DartIdentifier)opNonsense.getName()).getName());
|
||||
DartMethodDefinition opEquiv = (DartMethodDefinition)foo.getMembers().get(3);
|
||||
assertEquals("===", ((DartIdentifier)opEquiv.getName()).getName());
|
||||
assertEquals("===", ((DartIdentifier)opEquiv.getName()).getName());
|
||||
DartMethodDefinition opPlus = (DartMethodDefinition)foo.getMembers().get(4);
|
||||
assertEquals("+", ((DartIdentifier)opPlus.getName()).getName());
|
||||
}
|
||||
|
||||
|
||||
public void testPropertyAccessInArgumentListRecovery1() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_property_access1.dart",
|
||||
Joiner.on("\n").join(
|
||||
@@ -293,7 +299,7 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
DartFieldDefinition after = (DartFieldDefinition)unit.getTopLevelNodes().get(2);
|
||||
assertEquals("after", after.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
|
||||
public void testPropertyAccessInArgumentListRecovery2() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_property_access2.dart",
|
||||
Joiner.on("\n").join(
|
||||
@@ -307,7 +313,7 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
DartFieldDefinition after = (DartFieldDefinition)unit.getTopLevelNodes().get(2);
|
||||
assertEquals("after", after.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
|
||||
public void testPropertyAccessInArgumentListRecovery3() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_property_access3.dart",
|
||||
Joiner.on("\n").join(
|
||||
@@ -321,7 +327,7 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
DartFieldDefinition after = (DartFieldDefinition)unit.getTopLevelNodes().get(2);
|
||||
assertEquals("after", after.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
|
||||
public void testPropertyAccessInArgumentListRecovery4() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_property_access4.dart",
|
||||
Joiner.on("\n").join(
|
||||
@@ -335,4 +341,108 @@ public class ParserRecoveryTest extends AbstractParserTest {
|
||||
DartFieldDefinition after = (DartFieldDefinition)unit.getTopLevelNodes().get(2);
|
||||
assertEquals("after", after.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
public void testRecoverInBlock1() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_in_block1.dart",
|
||||
Joiner.on("\n").join(
|
||||
"var before;",
|
||||
"bad() { foo( }", // unterminated invocation
|
||||
"var after;"));
|
||||
DartFieldDefinition before = (DartFieldDefinition)unit.getTopLevelNodes().get(0);
|
||||
assertEquals("before", before.getFields().get(0).getName().getName());
|
||||
DartMethodDefinition bad = (DartMethodDefinition)unit.getTopLevelNodes().get(1);
|
||||
assertEquals("bad", ((DartIdentifier)bad.getName()).getName());
|
||||
DartUnqualifiedInvocation invocation = (DartUnqualifiedInvocation)
|
||||
((DartExprStmt)bad.getFunction().getBody().getStatements().get(0)).getExpression();
|
||||
assertEquals("foo", invocation.getTarget().getName());
|
||||
DartFieldDefinition after = (DartFieldDefinition)unit.getTopLevelNodes().get(2);
|
||||
assertEquals("after", after.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
public void testRecoverInBlock2() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_in_block2.dart",
|
||||
Joiner.on("\n").join(
|
||||
"var before;",
|
||||
"bad() { foo }", // unterminated statement
|
||||
"var after;"));
|
||||
DartFieldDefinition before = (DartFieldDefinition)unit.getTopLevelNodes().get(0);
|
||||
assertEquals("before", before.getFields().get(0).getName().getName());
|
||||
DartMethodDefinition bad = (DartMethodDefinition)unit.getTopLevelNodes().get(1);
|
||||
assertEquals("bad", ((DartIdentifier)bad.getName()).getName());
|
||||
DartIdentifier ident = (DartIdentifier)
|
||||
((DartExprStmt)bad.getFunction().getBody().getStatements().get(0)).getExpression();
|
||||
assertEquals("foo", ident.getName());
|
||||
DartFieldDefinition after = (DartFieldDefinition)unit.getTopLevelNodes().get(2);
|
||||
assertEquals("after", after.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
public void testRecoverInBlock3() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_in_block3.dart",
|
||||
Joiner.on("\n").join(
|
||||
"var before;",
|
||||
"bad() { foo. }", // unterminated statement
|
||||
"var after;"));
|
||||
DartFieldDefinition before = (DartFieldDefinition)unit.getTopLevelNodes().get(0);
|
||||
assertEquals("before", before.getFields().get(0).getName().getName());
|
||||
DartMethodDefinition bad = (DartMethodDefinition)unit.getTopLevelNodes().get(1);
|
||||
assertEquals("bad", ((DartIdentifier)bad.getName()).getName());
|
||||
DartPropertyAccess prop = (DartPropertyAccess)
|
||||
((DartExprStmt)bad.getFunction().getBody().getStatements().get(0)).getExpression();
|
||||
assertEquals("foo", ((DartIdentifier)prop.getQualifier()).getName());
|
||||
DartFieldDefinition after = (DartFieldDefinition)unit.getTopLevelNodes().get(2);
|
||||
assertEquals("after", after.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
public void testRecoverInBlock4() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_in_block4.dart",
|
||||
Joiner.on("\n").join(
|
||||
"var before;",
|
||||
"bad() { var foo = }", // unterminated variable decl
|
||||
"var after;"));
|
||||
DartFieldDefinition before = (DartFieldDefinition)unit.getTopLevelNodes().get(0);
|
||||
assertEquals("before", before.getFields().get(0).getName().getName());
|
||||
DartMethodDefinition bad = (DartMethodDefinition)unit.getTopLevelNodes().get(1);
|
||||
assertEquals("bad", ((DartIdentifier)bad.getName()).getName());
|
||||
DartVariable foo = ((DartVariableStatement)bad.getFunction().getBody().getStatements().get(0))
|
||||
.getVariables().get(0);
|
||||
assertEquals("foo", foo.getVariableName());
|
||||
DartFieldDefinition after = (DartFieldDefinition)unit.getTopLevelNodes().get(2);
|
||||
assertEquals("after", after.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
public void testRecoverInBlock5() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_in_block5.dart",
|
||||
Joiner.on("\n").join(
|
||||
"var before;",
|
||||
"bad() { foo(bar. }", // unterminated invocation
|
||||
"var after;"));
|
||||
DartFieldDefinition before = (DartFieldDefinition)unit.getTopLevelNodes().get(0);
|
||||
assertEquals("before", before.getFields().get(0).getName().getName());
|
||||
DartMethodDefinition bad = (DartMethodDefinition)unit.getTopLevelNodes().get(1);
|
||||
assertEquals("bad", ((DartIdentifier)bad.getName()).getName());
|
||||
DartUnqualifiedInvocation invocation = (DartUnqualifiedInvocation)
|
||||
((DartExprStmt)bad.getFunction().getBody().getStatements().get(0)).getExpression();
|
||||
assertEquals("foo", invocation.getTarget().getName());
|
||||
DartPropertyAccess arg0 = (DartPropertyAccess)invocation.getArguments().get(0);
|
||||
assertEquals("bar", ((DartIdentifier)arg0.getQualifier()).getName());
|
||||
DartFieldDefinition after = (DartFieldDefinition)unit.getTopLevelNodes().get(2);
|
||||
assertEquals("after", after.getFields().get(0).getName().getName());
|
||||
}
|
||||
|
||||
public void testRecoverInBlock6() {
|
||||
DartUnit unit = parseUnitUnspecifiedErrors("phony_recover_in_block6.dart",
|
||||
Joiner.on("\n").join(
|
||||
"var before;",
|
||||
"bad() { foo + }", // incomplete expression
|
||||
"var after;"));
|
||||
DartFieldDefinition before = (DartFieldDefinition)unit.getTopLevelNodes().get(0);
|
||||
assertEquals("before", before.getFields().get(0).getName().getName());
|
||||
DartMethodDefinition bad = (DartMethodDefinition)unit.getTopLevelNodes().get(1);
|
||||
assertEquals("bad", ((DartIdentifier)bad.getName()).getName());
|
||||
DartBinaryExpression expr = (DartBinaryExpression)
|
||||
((DartExprStmt)bad.getFunction().getBody().getStatements().get(0)).getExpression();
|
||||
assertEquals("foo", ((DartIdentifier)expr.getArg1()).getName());
|
||||
DartFieldDefinition after = (DartFieldDefinition)unit.getTopLevelNodes().get(2);
|
||||
assertEquals("after", after.getFields().get(0).getName().getName());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user