mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Change the way decorators are parsed, add stub infrastrucuture.
This commit is contained in:
@@ -5,6 +5,7 @@ import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.*;
|
||||
import com.jetbrains.python.psi.impl.stubs.*;
|
||||
import com.jetbrains.python.psi.stubs.*;
|
||||
import com.jetbrains.python.psi.PyDecorator;
|
||||
|
||||
public interface PyElementTypes {
|
||||
|
||||
@@ -12,18 +13,23 @@ public interface PyElementTypes {
|
||||
PyStubElementType<PyClassStub, PyClass> CLASS_DECLARATION = new PyClassElementType();
|
||||
PyStubElementType<PyParameterListStub, PyParameterList> PARAMETER_LIST = new PyParameterListElementType();
|
||||
|
||||
//PyElementType DECORATOR_LIST = new PyElementType("DECORATOR", PyDecoratorListImpl.class);
|
||||
PyStubElementType<PyDecoratorListStub, PyDecoratorList> DECORATOR_LIST = new PyDecoratorListElementType();
|
||||
|
||||
TokenSet PARAMETER_LIST_SET = TokenSet.create(PARAMETER_LIST);
|
||||
|
||||
PyStubElementType<PyParameterStub, PyParameter> FORMAL_PARAMETER = new PyFormalParameterElementType();
|
||||
PyStubElementType<PyDecoratorStub, PyDecorator> DECORATOR_CALL = new PyDecoratorCallElementType();
|
||||
|
||||
TokenSet FORMAL_PARAMETER_SET = TokenSet.create(FORMAL_PARAMETER);
|
||||
|
||||
PyElementType DECORATED_FUNCTION_DECLARATION = new PyElementType("DECORATED_FUNCTION_DECLARATION", PyDecoratedFunctionImpl.class);
|
||||
// Deprecated PyElementType DECORATED_FUNCTION_DECLARATION = new PyElementType("DECORATED_FUNCTION_DECLARATION", PyDecoratedFunctionImpl.class);
|
||||
PyElementType ARGUMENT_LIST = new PyElementType("ARGUMENT_LIST", PyArgumentListImpl.class);
|
||||
PyElementType IMPORT_ELEMENT = new PyElementType("IMPORT_ELEMENT", PyImportElementImpl.class);
|
||||
PyElementType STAR_IMPORT_ELEMENT = new PyElementType("STAR_IMPORT_ELEMENT", PyStarImportElementImpl.class);
|
||||
PyElementType EXCEPT_BLOCK = new PyElementType("EXCEPT_BLOCK", PyExceptBlockImpl.class);
|
||||
PyElementType PRINT_TARGET = new PyElementType("PRINT_TARGET", PyPrintTargetImpl.class);
|
||||
PyElementType DECORATOR = new PyElementType("DECORATOR", PyDecoratorImpl.class);
|
||||
|
||||
// Statements
|
||||
PyElementType EXPRESSION_STATEMENT = new PyElementType("EXPRESSION_STATEMENT", PyExpressionStatementImpl.class);
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.jetbrains.python.parsing;
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import static com.jetbrains.python.PyBundle.message;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
|
||||
@@ -35,44 +36,56 @@ public class FunctionParsing extends Parsing {
|
||||
public void parseFunctionDeclaration() {
|
||||
assertCurrentToken(PyTokenTypes.DEF_KEYWORD);
|
||||
final PsiBuilder.Marker functionMarker = myBuilder.mark();
|
||||
parseFunctionInnards(functionMarker);
|
||||
}
|
||||
|
||||
protected void parseFunctionInnards(PsiBuilder.Marker functionMarker) {
|
||||
myBuilder.advanceLexer();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.IDENTIFIER) {
|
||||
myBuilder.advanceLexer();
|
||||
}
|
||||
else {
|
||||
myBuilder.error("function name expected");
|
||||
myBuilder.error(message("PARSE.expected.func.name"));
|
||||
}
|
||||
|
||||
parseParameterList();
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
checkMatches(PyTokenTypes.COLON, message("PARSE.expected.colon"));
|
||||
getStatementParser().parseSuite(functionMarker, PyElementTypes.FUNCTION_DECLARATION);
|
||||
}
|
||||
|
||||
public void parseDecoratedFunctionDeclaration() {
|
||||
assertCurrentToken(PyTokenTypes.AT);
|
||||
assertCurrentToken(PyTokenTypes.AT); // ??? need this?
|
||||
final PsiBuilder.Marker functionMarker = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
getStatementParser().parseDottedName();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.LPAR) {
|
||||
getExpressionParser().parseArgumentList(myBuilder);
|
||||
final PsiBuilder.Marker decoListMarker = myBuilder.mark();
|
||||
boolean decorated = false;
|
||||
while (myBuilder.getTokenType() == PyTokenTypes.AT) {
|
||||
PsiBuilder.Marker decoratorMarker = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
getStatementParser().parseDottedName();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.LPAR) {
|
||||
getExpressionParser().parseArgumentList(myBuilder);
|
||||
}
|
||||
checkMatches(PyTokenTypes.STATEMENT_BREAK, message("PARSE.expected.statement.break"));
|
||||
decoratorMarker.done(PyElementTypes.DECORATOR_CALL);
|
||||
decorated = true;
|
||||
}
|
||||
checkMatches(PyTokenTypes.STATEMENT_BREAK, "statement break expected");
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.AT) {
|
||||
parseDecoratedFunctionDeclaration();
|
||||
}
|
||||
else if (myBuilder.getTokenType() == PyTokenTypes.DEF_KEYWORD) {
|
||||
parseFunctionDeclaration();
|
||||
if (decorated) decoListMarker.done(PyElementTypes.DECORATOR_LIST);
|
||||
//else decoListMarker.rollbackTo();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.DEF_KEYWORD) {
|
||||
parseFunctionInnards(functionMarker); // it calls functionMarker.done()
|
||||
}
|
||||
else {
|
||||
myBuilder.error("'def' or '@' expected");
|
||||
myBuilder.error(message("PARSE.expected.@.or.def"));
|
||||
PsiBuilder.Marker parameterList = myBuilder.mark(); // To have non-empty parameters list at all the time.
|
||||
parameterList.done(PyElementTypes.PARAMETER_LIST);
|
||||
functionMarker.done(PyElementTypes.FUNCTION_DECLARATION);
|
||||
}
|
||||
functionMarker.done(PyElementTypes.DECORATED_FUNCTION_DECLARATION);
|
||||
}
|
||||
|
||||
private void parseParameterList() {
|
||||
final PsiBuilder.Marker parameterList;
|
||||
if (myBuilder.getTokenType() != PyTokenTypes.LPAR) {
|
||||
myBuilder.error("( expected");
|
||||
myBuilder.error(message("PARSE.expected.lpar"));
|
||||
parameterList = myBuilder.mark(); // To have non-empty parameters list at all the time.
|
||||
parameterList.done(PyElementTypes.PARAMETER_LIST);
|
||||
return;
|
||||
@@ -100,7 +113,7 @@ public class FunctionParsing extends Parsing {
|
||||
parseParameterSubList();
|
||||
}
|
||||
else {
|
||||
myBuilder.error(", or ( or ) expected");
|
||||
myBuilder.error(message("PARSE.expected.comma.lpar.rpar"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -120,7 +133,7 @@ public class FunctionParsing extends Parsing {
|
||||
parameter.done(PyElementTypes.FORMAL_PARAMETER);
|
||||
}
|
||||
else {
|
||||
myBuilder.error("formal parameter name expected");
|
||||
myBuilder.error(message("PARSE.expected.formal.param.name"));
|
||||
parameter.rollbackTo();
|
||||
}
|
||||
}
|
||||
@@ -149,7 +162,7 @@ public class FunctionParsing extends Parsing {
|
||||
break;
|
||||
}
|
||||
if (myBuilder.getTokenType() != PyTokenTypes.COMMA) {
|
||||
myBuilder.error(", or ( or ) expected");
|
||||
myBuilder.error(message("PARSE.expected.comma.lpar.rpar"));
|
||||
break;
|
||||
}
|
||||
myBuilder.advanceLexer();
|
||||
|
||||
@@ -50,4 +50,7 @@ public interface PyFunction extends PsiNamedElement, PyElement, NameDefiner, PyD
|
||||
|
||||
@Nullable
|
||||
PyClass getContainingClass();
|
||||
|
||||
@Nullable
|
||||
PyDecoratorList getDecoratorList();
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
|
||||
|
||||
@NotNull
|
||||
public PyParameterList getParameterList() {
|
||||
return (PyParameterList) getRequiredStubOrPsiChild(PyElementTypes.PARAMETER_LIST);
|
||||
return getRequiredStubOrPsiChild(PyElementTypes.PARAMETER_LIST);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -109,6 +109,11 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PyDecoratorList getDecoratorList() {
|
||||
return getStubOrPsiChild(PyElementTypes.DECORATOR_LIST); // PsiTreeUtil.getChildOfType(this, PyDecoratorList.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyFunction(this);
|
||||
|
||||
Reference in New Issue
Block a user