Index: compiler/java/com/google/dart/compiler/parser/DartParser.java |
diff --git a/compiler/java/com/google/dart/compiler/parser/DartParser.java b/compiler/java/com/google/dart/compiler/parser/DartParser.java |
index eda9237afbf361346914e95d8dcaf53123ffec99..ae498ad2a39187116d0f7963bae64caa525881c2 100644 |
--- a/compiler/java/com/google/dart/compiler/parser/DartParser.java |
+++ b/compiler/java/com/google/dart/compiler/parser/DartParser.java |
@@ -2059,6 +2059,50 @@ public class DartParser extends CompletionHooksParserBase { |
return done(null); |
} |
+ private enum LastSeenNode { |
+ NONE, |
+ STRING, |
+ EXPRESSION; |
+ } |
+ |
+ private class DartStringInterpolationBuilder { |
+ |
+ private List<DartStringLiteral> strings = new ArrayList<DartStringLiteral>(); |
+ private List<DartExpression> expressions = new ArrayList<DartExpression>(); |
+ private LastSeenNode lastSeen = LastSeenNode.NONE; |
+ |
+ DartStringInterpolationBuilder() { |
+ } |
+ |
+ void addString(DartStringLiteral string) { |
+ if (lastSeen == LastSeenNode.STRING) { |
+ expressions.add(new DartSyntheticErrorExpression()); |
+ } |
+ strings.add(string); |
+ lastSeen = LastSeenNode.STRING; |
+ } |
+ |
+ void addExpression(DartExpression expression) { |
+ switch (lastSeen) { |
+ case EXPRESSION: |
+ case NONE: |
+ strings.add(DartStringLiteral.get("")); |
+ break; |
+ default: |
+ break; |
+ } |
+ expressions.add(expression); |
+ lastSeen = LastSeenNode.EXPRESSION; |
+ } |
+ |
+ DartStringInterpolation buildInterpolation() { |
+ if (strings.size() == expressions.size()) { |
+ strings.add(DartStringLiteral.get("")); |
+ } |
+ return new DartStringInterpolation(strings, expressions); |
+ } |
+ } |
+ |
/** |
* <pre> |
* string-interpolation |
@@ -2074,35 +2118,25 @@ public class DartParser extends CompletionHooksParserBase { |
throw new InternalCompilerException("Invariant broken"); |
} |
beginStringInterpolation(); |
- List<DartStringLiteral> strings = new ArrayList<DartStringLiteral>(); |
- List<DartExpression> expressions = new ArrayList<DartExpression>(); |
- |
+ DartStringInterpolationBuilder builder = new DartStringInterpolationBuilder(); |
boolean inString = true; |
while (inString) { // Iterate until we find the last string segment. |
switch (peek(0)) { |
case STRING_SEGMENT: { |
- assert strings.size() == expressions.size() : "Invariant broken"; |
beginStringSegment(); |
consume(Token.STRING_SEGMENT); |
- strings.add(done(DartStringLiteral.get(ctx.getTokenString()))); |
+ builder.addString(done(DartStringLiteral.get(ctx.getTokenString()))); |
break; |
} |
case STRING_LAST_SEGMENT: { |
- assert strings.size() == expressions.size() : "Invariant broken"; |
beginStringSegment(); |
consume(Token.STRING_LAST_SEGMENT); |
- strings.add(done(DartStringLiteral.get(ctx.getTokenString()))); |
+ builder.addString(done(DartStringLiteral.get(ctx.getTokenString()))); |
inString = false; |
break; |
} |
case STRING_EMBED_EXP_START: { |
consume(Token.STRING_EMBED_EXP_START); |
- if (strings.size() == expressions.size()) { |
- // Ensure that strings and expressions are alternating, add empty |
- // strings if we see 2 consecutive expressions. |
- beginStringSegment(); |
- strings.add(done(DartStringLiteral.get(""))); |
- } |
/* |
* We check for ILLEGAL specifically here to give nicer error |
* messages, and because the scanner doesn't generate a |
@@ -2112,30 +2146,45 @@ public class DartParser extends CompletionHooksParserBase { |
if (peek(0) == Token.ILLEGAL) { |
reportError(position(), ParserErrorCode.UNEXPECTED_TOKEN_IN_STRING_INTERPOLATION, |
next()); |
- expressions.add(new DartSyntheticErrorExpression(ctx.getTokenString())); |
+ builder.addExpression(new DartSyntheticErrorExpression("")); |
break; |
} else { |
- DartExpression expr = parseExpression(); |
- expressions.add(expr); |
+ builder.addExpression(parseExpression()); |
} |
+ Token lookAhead = peek(0); |
+ String lookAheadString = getPeekTokenValue(0); |
if (!expect(Token.STRING_EMBED_EXP_END)) { |
- return done(new DartSyntheticErrorExpression()); |
+ String errorText = null; |
+ if (lookAheadString != null && lookAheadString.length() > 0) { |
+ errorText = lookAheadString; |
+ } else if (lookAhead.getSyntax() != null && lookAhead.getSyntax().length() > 0) { |
+ errorText = lookAhead.getSyntax(); |
+ } |
+ if (errorText != null) { |
+ builder.addExpression(new DartSyntheticErrorExpression(errorText)); |
+ } |
+ inString = !(Token.STRING_LAST_SEGMENT == lookAhead); |
} |
break; |
} |
case EOS: { |
reportError(position(), ParserErrorCode.INCOMPLETE_STRING_LITERAL); |
- return done(null); |
+ inString = false; |
+ break; |
} |
default: { |
+ String errorText = getPeekTokenValue(0) != null && getPeekTokenValue(0).length() > 0 |
+ ? getPeekTokenValue(0) : null; |
+ if(errorText != null) { |
+ builder.addExpression(new DartSyntheticErrorExpression(getPeekTokenValue(0))); |
+ } |
reportError(position(), ParserErrorCode.UNEXPECTED_TOKEN_IN_STRING_INTERPOLATION, |
next()); |
break; |
} |
} |
} |
- assert (strings.size() == expressions.size() + 1) : "Invariant broken"; |
- return done(new DartStringInterpolation(strings, expressions)); |
+ return builder.buildInterpolation(); |
} |
/** |