--- /dev/null
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.psi;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Mikhail Golubev
+ */
+public interface PyAnnotationOwner {
+ @Nullable
+ PyAnnotation getAnnotation();
+}
/**
* Describes an assignment statement.
*/
-public interface PyAssignmentStatement extends PyStatement, PyNamedElementContainer {
+public interface PyAssignmentStatement extends PyStatement, PyNamedElementContainer, PyAnnotationOwner {
/**
* @return the left-hand side of the statement; each item may consist of many elements.
public void visitPyWithItem(PyWithItem node) {
visitPyElement(node);
}
+
+ public void visitPyTypeDeclarationStatement(PyTypeDeclarationStatement node) {
+ visitPyStatement(node);
+ }
}
*/
public interface PyFunction extends PsiNamedElement, StubBasedPsiElement<PyFunctionStub>, PsiNameIdentifierOwner, PyStatement, PyCallable,
PyDocStringOwner, ScopeOwner, PyDecoratable, PyTypedElement, PyStatementListContainer,
- PyPossibleClassMember, PyTypeCommentOwner {
+ PyPossibleClassMember, PyTypeCommentOwner, PyAnnotationOwner {
PyFunction[] EMPTY_ARRAY = new PyFunction[0];
ArrayFactory<PyFunction> ARRAY_FACTORY = count -> new PyFunction[count];
import com.intellij.psi.StubBasedPsiElement;
import com.jetbrains.python.psi.stubs.PyNamedParameterStub;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/**
* Represents a named parameter, as opposed to a tuple parameter.
*/
-public interface PyNamedParameter extends PyParameter, PsiNamedElement, PsiNameIdentifierOwner, PyExpression, PyTypeCommentOwner, StubBasedPsiElement<PyNamedParameterStub> {
+public interface PyNamedParameter extends PyParameter, PsiNamedElement, PsiNameIdentifierOwner, PyExpression, PyTypeCommentOwner,
+ PyAnnotationOwner, StubBasedPsiElement<PyNamedParameterStub> {
boolean isPositionalContainer();
boolean isKeywordContainer();
*/
@NotNull
String getRepr(boolean includeDefaultValue);
-
- @Nullable
- PyAnnotation getAnnotation();
}
--- /dev/null
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.psi;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Mikhail Golubev
+ */
+public interface PyTypeDeclarationStatement extends PyStatement, PyAnnotationOwner {
+ @NotNull
+ PyExpression getTarget();
+}
PyElementType DEL_STATEMENT = new PyElementType("DEL_STATEMENT", PyDelStatementImpl.class);
PyElementType EXEC_STATEMENT = new PyElementType("EXEC_STATEMENT", PyExecStatementImpl.class);
PyElementType FOR_STATEMENT = new PyElementType("FOR_STATEMENT", PyForStatementImpl.class);
+ PyElementType TYPE_DECLARATION_STATEMENT = new PyElementType("TYPE_DECLARATION_STATEMENT", PyTypeDeclarationStatementImpl.class);
PyStubElementType<PyFromImportStatementStub, PyFromImportStatement> FROM_IMPORT_STATEMENT = new PyFromImportStatementElementType();
PyStubElementType<PyImportStatementStub, PyImportStatement> IMPORT_STATEMENT = new PyImportStatementElementType();
--- /dev/null
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python;
+
+import com.intellij.lang.ASTNode;
+import com.jetbrains.python.psi.PyAnnotation;
+import com.jetbrains.python.psi.PyElementVisitor;
+import com.jetbrains.python.psi.PyExpression;
+import com.jetbrains.python.psi.PyTypeDeclarationStatement;
+import com.jetbrains.python.psi.impl.PyElementImpl;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Mikhail Golubev
+ */
+public class PyTypeDeclarationStatementImpl extends PyElementImpl implements PyTypeDeclarationStatement {
+ public PyTypeDeclarationStatementImpl(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @NotNull
+ @Override
+ public PyExpression getTarget() {
+ return findNotNullChildByClass(PyExpression.class);
+ }
+
+ @Nullable
+ @Override
+ public PyAnnotation getAnnotation() {
+ return findChildByClass(PyAnnotation.class);
+ }
+
+ @Override
+ protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
+ pyVisitor.visitPyTypeDeclarationStatement(this);
+ }
+}
@NotNull
@Override
public TokenSet getStatementTokens() {
- return TokenSet.create(EXPRESSION_STATEMENT, ASSIGNMENT_STATEMENT, AUG_ASSIGNMENT_STATEMENT, ASSERT_STATEMENT,
- BREAK_STATEMENT, CONTINUE_STATEMENT, DEL_STATEMENT, EXEC_STATEMENT, FOR_STATEMENT,
+ return TokenSet.create(EXPRESSION_STATEMENT, ASSIGNMENT_STATEMENT, TYPE_DECLARATION_STATEMENT, AUG_ASSIGNMENT_STATEMENT,
+ ASSERT_STATEMENT, BREAK_STATEMENT, CONTINUE_STATEMENT, DEL_STATEMENT, EXEC_STATEMENT, FOR_STATEMENT,
FROM_IMPORT_STATEMENT, GLOBAL_STATEMENT, IMPORT_STATEMENT, IF_STATEMENT, PASS_STATEMENT,
PRINT_STATEMENT, RAISE_STATEMENT, RETURN_STATEMENT, TRY_EXCEPT_STATEMENT, WITH_STATEMENT,
WHILE_STATEMENT, NONLOCAL_STATEMENT, CLASS_DECLARATION, FUNCTION_DECLARATION);
return true;
}
- protected void parseParameterAnnotation() {
+ public void parseParameterAnnotation() {
if (myContext.getLanguageLevel().isPy3K() && atToken(PyTokenTypes.COLON)) {
PsiBuilder.Marker annotationMarker = myBuilder.mark();
nextToken();
builder.error(EXPRESSION_EXPECTED);
}
}
- else if (builder.getTokenType() == PyTokenTypes.EQ) {
- statementType = PyElementTypes.ASSIGNMENT_STATEMENT;
+ else if (atToken(PyTokenTypes.EQ) || (atToken(PyTokenTypes.COLON) && myContext.getLanguageLevel().isPy3K())) {
exprStatement.rollbackTo();
exprStatement = builder.mark();
getExpressionParser().parseExpression(false, true);
- LOG.assertTrue(builder.getTokenType() == PyTokenTypes.EQ, builder.getTokenType());
- builder.advanceLexer();
+ LOG.assertTrue(builder.getTokenType() == PyTokenTypes.EQ || builder.getTokenType() == PyTokenTypes.COLON, builder.getTokenType());
- while (true) {
- PsiBuilder.Marker maybeExprMarker = builder.mark();
- final boolean isYieldExpr = builder.getTokenType() == PyTokenTypes.YIELD_KEYWORD;
- if (!getExpressionParser().parseYieldOrTupleExpression(false)) {
- maybeExprMarker.drop();
- builder.error(EXPRESSION_EXPECTED);
- break;
- }
- if (builder.getTokenType() == PyTokenTypes.EQ) {
- if (isYieldExpr) {
+ if (builder.getTokenType() == PyTokenTypes.COLON) {
+ statementType = PyElementTypes.TYPE_DECLARATION_STATEMENT;
+ getFunctionParser().parseParameterAnnotation();
+ }
+
+ if (builder.getTokenType() == PyTokenTypes.EQ) {
+ statementType = PyElementTypes.ASSIGNMENT_STATEMENT;
+ builder.advanceLexer();
+
+ while (true) {
+ PsiBuilder.Marker maybeExprMarker = builder.mark();
+ final boolean isYieldExpr = builder.getTokenType() == PyTokenTypes.YIELD_KEYWORD;
+ if (!getExpressionParser().parseYieldOrTupleExpression(false)) {
maybeExprMarker.drop();
- builder.error("Cannot assign to 'yield' expression");
+ builder.error(EXPRESSION_EXPECTED);
+ break;
+ }
+ if (builder.getTokenType() == PyTokenTypes.EQ) {
+ if (isYieldExpr) {
+ maybeExprMarker.drop();
+ builder.error("Cannot assign to 'yield' expression");
+ }
+ else {
+ maybeExprMarker.rollbackTo();
+ getExpressionParser().parseExpression(false, true);
+ LOG.assertTrue(builder.getTokenType() == PyTokenTypes.EQ, builder.getTokenType());
+ }
+ builder.advanceLexer();
}
else {
- maybeExprMarker.rollbackTo();
- getExpressionParser().parseExpression(false, true);
- LOG.assertTrue(builder.getTokenType() == PyTokenTypes.EQ, builder.getTokenType());
+ maybeExprMarker.drop();
+ break;
}
- builder.advanceLexer();
- }
- else {
- maybeExprMarker.drop();
- break;
}
}
}
return targets.toArray(new PyExpression[targets.size()]);
}
+ @Nullable
+ @Override
+ public PyAnnotation getAnnotation() {
+ return findChildByClass(PyAnnotation.class);
+ }
+
private static void addCandidate(List<PyExpression> candidates, PyExpression psi) {
if (psi instanceof PyParenthesizedExpression) {
addCandidate(candidates, ((PyParenthesizedExpression)psi).getContainedExpression());
--- /dev/null
+class C:
+ x: int
+ y: None = 42
+
+ def m(self, d):
+ x: List[bool]
+ d['foo']: str
+ (d['bar']): float
--- /dev/null
+PyFile:VariableAnnotations.py
+ PyClass: C
+ PsiElement(Py:CLASS_KEYWORD)('class')
+ PsiWhiteSpace(' ')
+ PsiElement(Py:IDENTIFIER)('C')
+ PyArgumentList
+ <empty list>
+ PsiElement(Py:COLON)(':')
+ PsiWhiteSpace('\n ')
+ PyStatementList
+ PyTypeDeclarationStatement
+ PyTargetExpression: x
+ PsiElement(Py:IDENTIFIER)('x')
+ PyAnnotation
+ PsiElement(Py:COLON)(':')
+ PsiWhiteSpace(' ')
+ PyReferenceExpression: int
+ PsiElement(Py:IDENTIFIER)('int')
+ PsiWhiteSpace('\n ')
+ PyAssignmentStatement
+ PyTargetExpression: y
+ PsiElement(Py:IDENTIFIER)('y')
+ PyAnnotation
+ PsiElement(Py:COLON)(':')
+ PsiWhiteSpace(' ')
+ PyNoneLiteralExpression
+ PsiElement(Py:NONE_KEYWORD)('None')
+ PsiWhiteSpace(' ')
+ PsiElement(Py:EQ)('=')
+ PsiWhiteSpace(' ')
+ PyNumericLiteralExpression
+ PsiElement(Py:INTEGER_LITERAL)('42')
+ PsiWhiteSpace('\n\n ')
+ PyFunction('m')
+ PsiElement(Py:DEF_KEYWORD)('def')
+ PsiWhiteSpace(' ')
+ PsiElement(Py:IDENTIFIER)('m')
+ PyParameterList
+ PsiElement(Py:LPAR)('(')
+ PyNamedParameter('self')
+ PsiElement(Py:IDENTIFIER)('self')
+ PsiElement(Py:COMMA)(',')
+ PsiWhiteSpace(' ')
+ PyNamedParameter('d')
+ PsiElement(Py:IDENTIFIER)('d')
+ PsiElement(Py:RPAR)(')')
+ PsiElement(Py:COLON)(':')
+ PsiWhiteSpace('\n ')
+ PyStatementList
+ PyTypeDeclarationStatement
+ PyTargetExpression: x
+ PsiElement(Py:IDENTIFIER)('x')
+ PyAnnotation
+ PsiElement(Py:COLON)(':')
+ PsiWhiteSpace(' ')
+ PySubscriptionExpression
+ PyReferenceExpression: List
+ PsiElement(Py:IDENTIFIER)('List')
+ PsiElement(Py:LBRACKET)('[')
+ PyReferenceExpression: bool
+ PsiElement(Py:IDENTIFIER)('bool')
+ PsiElement(Py:RBRACKET)(']')
+ PsiWhiteSpace('\n ')
+ PyTypeDeclarationStatement
+ PySubscriptionExpression
+ PyReferenceExpression: d
+ PsiElement(Py:IDENTIFIER)('d')
+ PsiElement(Py:LBRACKET)('[')
+ PyStringLiteralExpression: foo
+ PsiElement(Py:SINGLE_QUOTED_STRING)(''foo'')
+ PsiElement(Py:RBRACKET)(']')
+ PyAnnotation
+ PsiElement(Py:COLON)(':')
+ PsiWhiteSpace(' ')
+ PyReferenceExpression: str
+ PsiElement(Py:IDENTIFIER)('str')
+ PsiWhiteSpace('\n ')
+ PyTypeDeclarationStatement
+ PyParenthesizedExpression
+ PsiElement(Py:LPAR)('(')
+ PySubscriptionExpression
+ PyReferenceExpression: d
+ PsiElement(Py:IDENTIFIER)('d')
+ PsiElement(Py:LBRACKET)('[')
+ PyStringLiteralExpression: bar
+ PsiElement(Py:SINGLE_QUOTED_STRING)(''bar'')
+ PsiElement(Py:RBRACKET)(']')
+ PsiElement(Py:RPAR)(')')
+ PyAnnotation
+ PsiElement(Py:COLON)(':')
+ PsiWhiteSpace(' ')
+ PyReferenceExpression: float
+ PsiElement(Py:IDENTIFIER)('float')
\ No newline at end of file
doTest(LanguageLevel.PYTHON35);
}
+ public void testVariableAnnotations() {
+ doTest(LanguageLevel.PYTHON36);
+ }
+
public void doTest(LanguageLevel languageLevel) {
LanguageLevel prev = myLanguageLevel;
myLanguageLevel = languageLevel;