diff --git a/python/psi-api/src/com/jetbrains/python/PyTokenTypes.java b/python/psi-api/src/com/jetbrains/python/PyTokenTypes.java
index be858df92181..3e5c2037de96 100644
--- a/python/psi-api/src/com/jetbrains/python/PyTokenTypes.java
+++ b/python/psi-api/src/com/jetbrains/python/PyTokenTypes.java
@@ -74,6 +74,7 @@ public class PyTokenTypes {
public static final PyElementType NONLOCAL_KEYWORD = new PyElementType("NONLOCAL_KEYWORD");
public static final PyElementType DEBUG_KEYWORD = new PyElementType("DEBUG_KEYWORD");
public static final PyElementType ASYNC_KEYWORD = new PyElementType("ASYNC_KEYWORD");
+ public static final PyElementType AWAIT_KEYWORD = new PyElementType("AWAIT_KEYWORD", "__await__");
public static final PyElementType INTEGER_LITERAL = new PyElementType("INTEGER_LITERAL");
public static final PyElementType FLOAT_LITERAL = new PyElementType("FLOAT_LITERAL");
diff --git a/python/src/com/jetbrains/python/PyElementTypes.java b/python/src/com/jetbrains/python/PyElementTypes.java
index 400e21b178c7..7d104bafb6af 100644
--- a/python/src/com/jetbrains/python/PyElementTypes.java
+++ b/python/src/com/jetbrains/python/PyElementTypes.java
@@ -130,7 +130,8 @@ public interface PyElementTypes {
PyTokenTypes.MINUS, PyTokenTypes.MULT, PyTokenTypes.AT, PyTokenTypes.FLOORDIV, PyTokenTypes.DIV,
PyTokenTypes.PERC, PyTokenTypes.EXP);
- TokenSet UNARY_OPS = TokenSet.create(PyTokenTypes.NOT_KEYWORD, PyTokenTypes.PLUS, PyTokenTypes.MINUS, PyTokenTypes.TILDE);
+ TokenSet UNARY_OPS = TokenSet.create(PyTokenTypes.NOT_KEYWORD, PyTokenTypes.PLUS, PyTokenTypes.MINUS, PyTokenTypes.TILDE,
+ PyTokenTypes.AWAIT_KEYWORD);
// Parts
PyElementType IF_PART_IF = new PyElementType("IF_IF", PyIfPartIfImpl.class);
diff --git a/python/src/com/jetbrains/python/PythonTokenSetContributor.java b/python/src/com/jetbrains/python/PythonTokenSetContributor.java
index 51a42589109b..ac3d95c17b30 100644
--- a/python/src/com/jetbrains/python/PythonTokenSetContributor.java
+++ b/python/src/com/jetbrains/python/PythonTokenSetContributor.java
@@ -73,7 +73,7 @@ public class PythonTokenSetContributor extends PythonDialectsTokenSetContributor
LAMBDA_KEYWORD, NOT_KEYWORD, OR_KEYWORD, PASS_KEYWORD, PRINT_KEYWORD,
RAISE_KEYWORD, RETURN_KEYWORD, TRY_KEYWORD, WITH_KEYWORD, WHILE_KEYWORD,
YIELD_KEYWORD,
- NONE_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD, NONLOCAL_KEYWORD, DEBUG_KEYWORD, ASYNC_KEYWORD);
+ NONE_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD, NONLOCAL_KEYWORD, DEBUG_KEYWORD, ASYNC_KEYWORD, AWAIT_KEYWORD);
}
@NotNull
diff --git a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
index 850f3fec2b8c..616c3d954449 100644
--- a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
+++ b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
@@ -915,7 +915,7 @@ public class ExpressionParsing extends Parsing {
private boolean parsePowerExpression(boolean isTargetExpression) {
PsiBuilder.Marker expr = myBuilder.mark();
- if (!parseMemberExpression(isTargetExpression)) {
+ if (!parseAwaitExpression(isTargetExpression)) {
expr.drop();
return false;
}
@@ -933,4 +933,19 @@ public class ExpressionParsing extends Parsing {
return true;
}
+
+ private boolean parseAwaitExpression(boolean isTargetExpression) {
+ if (atToken(PyTokenTypes.AWAIT_KEYWORD)) {
+ PsiBuilder.Marker expr = myBuilder.mark();
+ myBuilder.advanceLexer();
+ if (!parseMemberExpression(isTargetExpression)) {
+ myBuilder.error(message("PARSE.expected.expression"));
+ }
+ expr.done(PyElementTypes.PREFIX_EXPRESSION);
+ return true;
+ }
+ else {
+ return parseMemberExpression(isTargetExpression);
+ }
+ }
}
diff --git a/python/src/com/jetbrains/python/parsing/StatementParsing.java b/python/src/com/jetbrains/python/parsing/StatementParsing.java
index bd6b423c033e..e5c7124c7a5d 100644
--- a/python/src/com/jetbrains/python/parsing/StatementParsing.java
+++ b/python/src/com/jetbrains/python/parsing/StatementParsing.java
@@ -51,6 +51,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
@NonNls protected static final String TOK_NONLOCAL = "nonlocal";
@NonNls protected static final String TOK_EXEC = "exec";
@NonNls protected static final String TOK_ASYNC = "async";
+ @NonNls protected static final String TOK_AWAIT = "await";
private static final String EXPRESSION_EXPECTED = "Expression expected";
public static final String IDENTIFIER_EXPECTED = "Identifier expected";
@@ -937,9 +938,16 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
if (isWordAtPosition(text, start, end, TOK_NONLOCAL)) {
return PyTokenTypes.NONLOCAL_KEYWORD;
}
- if (myContext.getLanguageLevel().isAtLeast(LanguageLevel.PYTHON35) && isWordAtPosition(text, start, end, TOK_ASYNC)) {
- if (myContext.getScope().isAsync() || myBuilder.lookAhead(1) == PyTokenTypes.DEF_KEYWORD) {
- return PyTokenTypes.ASYNC_KEYWORD;
+ if (myContext.getLanguageLevel().isAtLeast(LanguageLevel.PYTHON35)) {
+ if (isWordAtPosition(text, start, end, TOK_ASYNC)) {
+ if (myContext.getScope().isAsync() || myBuilder.lookAhead(1) == PyTokenTypes.DEF_KEYWORD) {
+ return PyTokenTypes.ASYNC_KEYWORD;
+ }
+ }
+ if (isWordAtPosition(text, start, end, TOK_AWAIT)) {
+ if (myContext.getScope().isAsync()) {
+ return PyTokenTypes.AWAIT_KEYWORD;
+ }
}
}
}
diff --git a/python/src/com/jetbrains/python/validation/DumbAwareHighlightingAnnotator.java b/python/src/com/jetbrains/python/validation/DumbAwareHighlightingAnnotator.java
index 717d59f8e37d..b90f8697c6a2 100644
--- a/python/src/com/jetbrains/python/validation/DumbAwareHighlightingAnnotator.java
+++ b/python/src/com/jetbrains/python/validation/DumbAwareHighlightingAnnotator.java
@@ -22,10 +22,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.highlighting.PyHighlighter;
-import com.jetbrains.python.psi.PyFile;
-import com.jetbrains.python.psi.PyForStatement;
-import com.jetbrains.python.psi.PyFunction;
-import com.jetbrains.python.psi.PyWithStatement;
+import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
/**
@@ -34,17 +31,22 @@ import org.jetbrains.annotations.NotNull;
public class DumbAwareHighlightingAnnotator extends PyAnnotator implements HighlightRangeExtension {
@Override
public void visitPyFunction(PyFunction node) {
- highlightAsyncKeyword(node);
+ highlightKeyword(node, PyTokenTypes.ASYNC_KEYWORD);
}
@Override
public void visitPyForStatement(PyForStatement node) {
- highlightAsyncKeyword(node);
+ highlightKeyword(node, PyTokenTypes.ASYNC_KEYWORD);
}
@Override
public void visitPyWithStatement(PyWithStatement node) {
- highlightAsyncKeyword(node);
+ highlightKeyword(node, PyTokenTypes.ASYNC_KEYWORD);
+ }
+
+ @Override
+ public void visitPyPrefixExpression(PyPrefixExpression node) {
+ highlightKeyword(node, PyTokenTypes.AWAIT_KEYWORD);
}
@Override
@@ -52,8 +54,8 @@ public class DumbAwareHighlightingAnnotator extends PyAnnotator implements Highl
return file instanceof PyFile;
}
- private void highlightAsyncKeyword(@NotNull PsiElement node) {
- final ASTNode asyncNode = node.getNode().findChildByType(PyTokenTypes.ASYNC_KEYWORD);
+ private void highlightKeyword(@NotNull PsiElement node, @NotNull PyElementType elementType) {
+ final ASTNode asyncNode = node.getNode().findChildByType(elementType);
if (asyncNode != null) {
final Annotation annotation = getHolder().createInfoAnnotation(asyncNode, null);
annotation.setTextAttributes(PyHighlighter.PY_KEYWORD);
diff --git a/python/testData/highlighting/await.py b/python/testData/highlighting/await.py
new file mode 100644
index 000000000000..ec8e80b683b2
--- /dev/null
+++ b/python/testData/highlighting/await.py
@@ -0,0 +1,5 @@
+async def foo():
+ await x
+
+
+await = 0
diff --git a/python/testData/psi/Await.py b/python/testData/psi/Await.py
new file mode 100644
index 000000000000..58bfdcaaa1dd
--- /dev/null
+++ b/python/testData/psi/Await.py
@@ -0,0 +1,5 @@
+async def f(x):
+ await x
+
+
+await = 1
diff --git a/python/testData/psi/Await.txt b/python/testData/psi/Await.txt
new file mode 100644
index 000000000000..9b5ee093ceb9
--- /dev/null
+++ b/python/testData/psi/Await.txt
@@ -0,0 +1,30 @@
+PyFile:Await.py
+ PyFunction('f')
+ PsiElement(Py:ASYNC_KEYWORD)('async')
+ PsiWhiteSpace(' ')
+ PsiElement(Py:DEF_KEYWORD)('def')
+ PsiWhiteSpace(' ')
+ PsiElement(Py:IDENTIFIER)('f')
+ PyParameterList
+ PsiElement(Py:LPAR)('(')
+ PyNamedParameter('x')
+ PsiElement(Py:IDENTIFIER)('x')
+ PsiElement(Py:RPAR)(')')
+ PsiElement(Py:COLON)(':')
+ PsiWhiteSpace('\n ')
+ PyStatementList
+ PyExpressionStatement
+ PyPrefixExpression
+ PsiElement(Py:AWAIT_KEYWORD)('await')
+ PsiWhiteSpace(' ')
+ PyReferenceExpression: x
+ PsiElement(Py:IDENTIFIER)('x')
+ PsiWhiteSpace('\n\n\n')
+ PyAssignmentStatement
+ PyTargetExpression: await
+ PsiElement(Py:IDENTIFIER)('await')
+ PsiWhiteSpace(' ')
+ PsiElement(Py:EQ)('=')
+ PsiWhiteSpace(' ')
+ PyNumericLiteralExpression
+ PsiElement(Py:INTEGER_LITERAL)('1')
\ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
index 83e625b7d3bc..3095bda21611 100644
--- a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
@@ -233,6 +233,10 @@ public class PythonHighlightingTest extends PyTestCase {
doTest(LanguageLevel.PYTHON35, true, true);
}
+ public void testAwait() {
+ doTest(LanguageLevel.PYTHON35, true, true);
+ }
+
// ---
private void doTest(final LanguageLevel languageLevel, final boolean checkWarnings, final boolean checkInfos) {
PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), languageLevel);
diff --git a/python/testSrc/com/jetbrains/python/PythonParsingTest.java b/python/testSrc/com/jetbrains/python/PythonParsingTest.java
index ecf2c39f46f3..99172dce2e48 100644
--- a/python/testSrc/com/jetbrains/python/PythonParsingTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonParsingTest.java
@@ -498,6 +498,10 @@ public class PythonParsingTest extends ParsingTestCase {
doTest(LanguageLevel.PYTHON35);
}
+ public void testAwait() {
+ doTest(LanguageLevel.PYTHON35);
+ }
+
public void doTest(LanguageLevel languageLevel) {
LanguageLevel prev = myLanguageLevel;
myLanguageLevel = languageLevel;