KT-847 Allow "this" without {} in string templates
This commit is contained in:
committed by
Nikolay Krasko
parent
94ad86e79e
commit
55c11d0f44
@@ -1,9 +1,11 @@
|
|||||||
package org.jetbrains.jet.lang.parsing;
|
package org.jetbrains.jet.lang.parsing;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.intellij.lang.PsiBuilder;
|
import com.intellij.lang.PsiBuilder;
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import com.intellij.psi.tree.TokenSet;
|
import com.intellij.psi.tree.TokenSet;
|
||||||
import org.jetbrains.jet.JetNodeType;
|
import org.jetbrains.jet.JetNodeType;
|
||||||
|
import org.jetbrains.jet.lexer.JetToken;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
import java.util.*;
|
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 = 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 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(
|
private static final TokenSet TYPE_ARGUMENT_LIST_STOPPERS = TokenSet.create(
|
||||||
INTEGER_LITERAL, FLOAT_LITERAL, CHARACTER_LITERAL, OPEN_QUOTE, RAW_STRING_LITERAL,
|
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,
|
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
|
* stringTemplateElement
|
||||||
* : RegularStringPart
|
* : RegularStringPart
|
||||||
* : ShortTemplateEntrySTART SimpleName
|
* : ShortTemplateEntrySTART (SimpleName | "this")
|
||||||
* : EscapeSequence
|
* : EscapeSequence
|
||||||
* : longTemplate
|
* : longTemplate
|
||||||
* ;
|
* ;
|
||||||
@@ -611,9 +623,25 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
|||||||
PsiBuilder.Marker entry = mark();
|
PsiBuilder.Marker entry = mark();
|
||||||
advance(); // SHORT_TEMPLATE_ENTRY_START
|
advance(); // SHORT_TEMPLATE_ENTRY_START
|
||||||
|
|
||||||
PsiBuilder.Marker reference = mark();
|
if (at(THIS_KEYWORD)) {
|
||||||
expect(IDENTIFIER, "Expecting a name");
|
PsiBuilder.Marker thisExpression = mark();
|
||||||
reference.done(REFERENCE_EXPRESSION);
|
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);
|
entry.done(SHORT_STRING_TEMPLATE_ENTRY);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public class CallResolver {
|
|||||||
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) calleeExpression;
|
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) calleeExpression;
|
||||||
String referencedName = nameExpression.getReferencedName();
|
String referencedName = nameExpression.getReferencedName();
|
||||||
if (referencedName == null) {
|
if (referencedName == null) {
|
||||||
return null;
|
return OverloadResolutionResultsImpl.nameNotFound();
|
||||||
}
|
}
|
||||||
TaskPrioritizer<VariableDescriptor> task_prioritizer;
|
TaskPrioritizer<VariableDescriptor> task_prioritizer;
|
||||||
if (nameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
|
if (nameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
|
||||||
|
|||||||
+1
-1
@@ -916,7 +916,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
public void visitStringTemplateEntryWithExpression(JetStringTemplateEntryWithExpression entry) {
|
public void visitStringTemplateEntryWithExpression(JetStringTemplateEntryWithExpression entry) {
|
||||||
JetExpression entryExpression = entry.getExpression();
|
JetExpression entryExpression = entry.getExpression();
|
||||||
if (entryExpression != null) {
|
if (entryExpression != null) {
|
||||||
facade.getType(entryExpression, context.replaceScope(context.scope));
|
facade.getType(entryExpression, context);
|
||||||
}
|
}
|
||||||
value[0] = CompileTimeConstantResolver.OUT_OF_RANGE;
|
value[0] = CompileTimeConstantResolver.OUT_OF_RANGE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,10 @@ LONG_TEMPLATE_ENTRY_END=\}
|
|||||||
yypushback(yylength() - 1);
|
yypushback(yylength() - 1);
|
||||||
return JetTokens.SHORT_TEMPLATE_ENTRY_START;
|
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; }
|
<SHORT_TEMPLATE_ENTRY> {IDENTIFIER} { popState(); return JetTokens.IDENTIFIER; }
|
||||||
|
|
||||||
<STRING> {LONELY_DOLLAR} { return JetTokens.REGULAR_STRING_PART; }
|
<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
|
fun buzz(f : fun () : Any?) : Int = 1
|
||||||
val sdf = 1
|
val sdf = 1
|
||||||
val foo = 3;
|
val foo = 3;
|
||||||
|
"$this must be$as$t"
|
||||||
"$abc"
|
"$abc"
|
||||||
"$abc\"
|
"$abc\"
|
||||||
"$"
|
"$"
|
||||||
|
|||||||
@@ -157,6 +157,25 @@ JetFile: StringTemplates.jet
|
|||||||
PsiElement(INTEGER_LITERAL)('3')
|
PsiElement(INTEGER_LITERAL)('3')
|
||||||
PsiElement(SEMICOLON)(';')
|
PsiElement(SEMICOLON)(';')
|
||||||
PsiWhiteSpace('\n ')
|
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
|
STRING_TEMPLATE
|
||||||
PsiElement(OPEN_QUOTE)('"')
|
PsiElement(OPEN_QUOTE)('"')
|
||||||
SHORT_STRING_TEMPLATE_ENTRY
|
SHORT_STRING_TEMPLATE_ENTRY
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ label
|
|||||||
|
|
||||||
literalConstant
|
literalConstant
|
||||||
: "true" | "false"
|
: "true" | "false"
|
||||||
: StringWithTemplates
|
: stringTemplate
|
||||||
: NoEscapeString
|
: NoEscapeString
|
||||||
: IntegerLiteral
|
: IntegerLiteral
|
||||||
: HexadecimalLiteral
|
: HexadecimalLiteral
|
||||||
@@ -143,6 +143,22 @@ literalConstant
|
|||||||
: "null"
|
: "null"
|
||||||
;
|
;
|
||||||
|
|
||||||
|
stringTemplate
|
||||||
|
: "\"" stringTemplateElement* "\""
|
||||||
|
;
|
||||||
|
|
||||||
|
stringTemplateElement
|
||||||
|
: RegularStringPart
|
||||||
|
: ShortTemplateEntrySTART (SimpleName | "this")
|
||||||
|
: EscapeSequence
|
||||||
|
: longTemplate
|
||||||
|
;
|
||||||
|
|
||||||
|
longTemplate
|
||||||
|
: "${" expression "}"
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
isRHS
|
isRHS
|
||||||
: pattern
|
: pattern
|
||||||
;
|
;
|
||||||
|
|||||||
Reference in New Issue
Block a user