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:
zundel@google.com
2012-04-07 17:25:37 +00:00
parent c79da818cc
commit bfbc8f4ff4
2 changed files with 205 additions and 70 deletions
@@ -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());
}
}