KT-847 Allow "this" without {} in string templates

This commit is contained in:
Andrey Breslav
2011-12-15 20:54:30 +04:00
committed by Nikolay Krasko
parent 94ad86e79e
commit 55c11d0f44
9 changed files with 476 additions and 393 deletions
@@ -1,9 +1,11 @@
package org.jetbrains.jet.lang.parsing;
import com.google.common.collect.ImmutableMap;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.jet.JetNodeType;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.*;
@@ -18,6 +20,16 @@ public class JetExpressionParsing extends AbstractJetParsing {
private static final TokenSet WHEN_CONDITION_RECOVERY_SET = TokenSet.create(RBRACE, IN_KEYWORD, NOT_IN, IS_KEYWORD, NOT_IS, ELSE_KEYWORD);
private static final TokenSet WHEN_CONDITION_RECOVERY_SET_WITH_DOUBLE_ARROW = TokenSet.create(RBRACE, IN_KEYWORD, NOT_IN, IS_KEYWORD, NOT_IS, ELSE_KEYWORD, DOUBLE_ARROW, DOT);
private static final ImmutableMap<String, JetToken> KEYWORD_TEXTS = tokenSetToMap(KEYWORDS);
private static ImmutableMap<String, JetToken> tokenSetToMap(TokenSet tokens) {
ImmutableMap.Builder<String, JetToken> builder = ImmutableMap.builder();
for (IElementType token : tokens.getTypes()) {
builder.put(token.toString(), (JetToken) token);
}
return builder.build();
}
private static final TokenSet TYPE_ARGUMENT_LIST_STOPPERS = TokenSet.create(
INTEGER_LITERAL, FLOAT_LITERAL, CHARACTER_LITERAL, OPEN_QUOTE, RAW_STRING_LITERAL,
NAMESPACE_KEYWORD, AS_KEYWORD, TYPE_KEYWORD, TRAIT_KEYWORD, CLASS_KEYWORD, THIS_KEYWORD, VAL_KEYWORD, VAR_KEYWORD,
@@ -587,7 +599,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
/*
* stringTemplateElement
* : RegularStringPart
* : ShortTemplateEntrySTART SimpleName
* : ShortTemplateEntrySTART (SimpleName | "this")
* : EscapeSequence
* : longTemplate
* ;
@@ -611,9 +623,25 @@ public class JetExpressionParsing extends AbstractJetParsing {
PsiBuilder.Marker entry = mark();
advance(); // SHORT_TEMPLATE_ENTRY_START
PsiBuilder.Marker reference = mark();
expect(IDENTIFIER, "Expecting a name");
reference.done(REFERENCE_EXPRESSION);
if (at(THIS_KEYWORD)) {
PsiBuilder.Marker thisExpression = mark();
PsiBuilder.Marker reference = mark();
advance(); // THIS_KEYWORD
reference.done(REFERENCE_EXPRESSION);
thisExpression.done(THIS_EXPRESSION);
}
else {
JetToken keyword = KEYWORD_TEXTS.get(myBuilder.getTokenText());
if (keyword != null) {
myBuilder.remapCurrentToken(keyword);
errorAndAdvance("Keyword cannot be used as a reference");
}
else {
PsiBuilder.Marker reference = mark();
expect(IDENTIFIER, "Expecting a name");
reference.done(REFERENCE_EXPRESSION);
}
}
entry.done(SHORT_STRING_TEMPLATE_ENTRY);
}
@@ -59,7 +59,7 @@ public class CallResolver {
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) calleeExpression;
String referencedName = nameExpression.getReferencedName();
if (referencedName == null) {
return null;
return OverloadResolutionResultsImpl.nameNotFound();
}
TaskPrioritizer<VariableDescriptor> task_prioritizer;
if (nameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
@@ -916,7 +916,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
public void visitStringTemplateEntryWithExpression(JetStringTemplateEntryWithExpression entry) {
JetExpression entryExpression = entry.getExpression();
if (entryExpression != null) {
facade.getType(entryExpression, context.replaceScope(context.scope));
facade.getType(entryExpression, context);
}
value[0] = CompileTimeConstantResolver.OUT_OF_RANGE;
}
@@ -121,6 +121,10 @@ LONG_TEMPLATE_ENTRY_END=\}
yypushback(yylength() - 1);
return JetTokens.SHORT_TEMPLATE_ENTRY_START;
}
// Only *this* keyword is itself an expression valid in this position
// *null*, *true* and *false* are also keywords and expression, but it does not make sense to put them
// in a string template for it'd be easier to just type them in without a dollar
<SHORT_TEMPLATE_ENTRY> "this" { popState(); return JetTokens.THIS_KEYWORD; }
<SHORT_TEMPLATE_ENTRY> {IDENTIFIER} { popState(); return JetTokens.IDENTIFIER; }
<STRING> {LONELY_DOLLAR} { return JetTokens.REGULAR_STRING_PART; }
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,3 @@
fun <T> T.mustBe(t : T) {
"$this must be$<!SYNTAX!>as<!>$t"
}
@@ -7,6 +7,7 @@ fun demo() {
fun buzz(f : fun () : Any?) : Int = 1
val sdf = 1
val foo = 3;
"$this must be$as$t"
"$abc"
"$abc\"
"$"
+19
View File
@@ -157,6 +157,25 @@ JetFile: StringTemplates.jet
PsiElement(INTEGER_LITERAL)('3')
PsiElement(SEMICOLON)(';')
PsiWhiteSpace('\n ')
STRING_TEMPLATE
PsiElement(OPEN_QUOTE)('"')
SHORT_STRING_TEMPLATE_ENTRY
PsiElement(SHORT_TEMPLATE_ENTRY_START)('$')
THIS_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(this)('this')
LITERAL_STRING_TEMPLATE_ENTRY
PsiElement(REGULAR_STRING_PART)(' must be')
SHORT_STRING_TEMPLATE_ENTRY
PsiElement(SHORT_TEMPLATE_ENTRY_START)('$')
PsiErrorElement:Keyword cannot be used as a reference
PsiElement(as)('as')
SHORT_STRING_TEMPLATE_ENTRY
PsiElement(SHORT_TEMPLATE_ENTRY_START)('$')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('t')
PsiElement(CLOSING_QUOTE)('"')
PsiWhiteSpace('\n ')
STRING_TEMPLATE
PsiElement(OPEN_QUOTE)('"')
SHORT_STRING_TEMPLATE_ENTRY
+17 -1
View File
@@ -134,7 +134,7 @@ label
literalConstant
: "true" | "false"
: StringWithTemplates
: stringTemplate
: NoEscapeString
: IntegerLiteral
: HexadecimalLiteral
@@ -143,6 +143,22 @@ literalConstant
: "null"
;
stringTemplate
: "\"" stringTemplateElement* "\""
;
stringTemplateElement
: RegularStringPart
: ShortTemplateEntrySTART (SimpleName | "this")
: EscapeSequence
: longTemplate
;
longTemplate
: "${" expression "}"
;
isRHS
: pattern
;