Change the way decorators are parsed, add stub infrastrucuture.

This commit is contained in:
Dmitry Cheryasov
2008-12-25 05:49:46 +03:00
parent 25245d6cfc
commit a3b40ba86e
4 changed files with 48 additions and 21 deletions
@@ -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);