mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fixes PY-71, introduces parts in multi-part statements.
Slight fixes to autoindenter.
This commit is contained in:
@@ -27,7 +27,7 @@ public interface PyElementTypes {
|
||||
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 EXCEPT_PART = new PyElementType("EXCEPT_PART", PyExceptPartImpl.class);
|
||||
PyElementType PRINT_TARGET = new PyElementType("PRINT_TARGET", PyPrintTargetImpl.class);
|
||||
PyElementType DECORATOR = new PyElementType("DECORATOR", PyDecoratorImpl.class);
|
||||
|
||||
@@ -100,6 +100,8 @@ public interface PyElementTypes {
|
||||
REPR_EXPRESSION, GENERATOR_EXPRESSION, CONDITIONAL_EXPRESSION, YIELD_EXPRESSION,
|
||||
TARGET_EXPRESSION);
|
||||
|
||||
TokenSet LIST_LIKE_EXPRESSIONS = TokenSet.create(LIST_LITERAL_EXPRESSION, LIST_COMP_EXPRESSION, TUPLE_EXPRESSION);
|
||||
|
||||
TokenSet STATEMENT_LISTS = TokenSet.create(STATEMENT_LIST);
|
||||
|
||||
TokenSet BINARY_OPS = TokenSet.create(PyTokenTypes.OR_KEYWORD, PyTokenTypes.AND_KEYWORD, PyTokenTypes.LT, PyTokenTypes.GT,
|
||||
@@ -108,4 +110,19 @@ public interface PyElementTypes {
|
||||
PyTokenTypes.IN_KEYWORD, PyTokenTypes.IS_KEYWORD, PyTokenTypes.NOT_KEYWORD, PyTokenTypes.PLUS,
|
||||
PyTokenTypes.MINUS, PyTokenTypes.MULT, PyTokenTypes.FLOORDIV, PyTokenTypes.DIV, PyTokenTypes.PERC);
|
||||
|
||||
// Parts
|
||||
PyElementType IF_PART_IF = new PyElementType("IF_IF", PyIfPartIfImpl.class);
|
||||
PyElementType IF_PART_ELIF = new PyElementType("IF_ELIF", PyIfPartElifImpl.class);
|
||||
|
||||
PyElementType FOR_PART = new PyElementType("FOR_PART", PyForPartImpl.class);
|
||||
PyElementType WHILE_PART = new PyElementType("WHILE_PART", PyWhilePartImpl.class);
|
||||
|
||||
PyElementType TRY_PART = new PyElementType("TRY_PART", PyTryPartImpl.class);
|
||||
PyElementType FINALLY_PART = new PyElementType("FINALLY_PART", PyFinallyPartImpl.class);
|
||||
|
||||
PyElementType ELSE_PART = new PyElementType("ELSE_PART", PyElsePartImpl.class);
|
||||
|
||||
TokenSet PARTS = TokenSet.create(IF_PART_IF, IF_PART_ELIF, FOR_PART, WHILE_PART, TRY_PART, FINALLY_PART, ELSE_PART);
|
||||
TokenSet ELIFS = TokenSet.create(IF_PART_ELIF);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,15 +18,19 @@ package com.jetbrains.python.formatter;
|
||||
|
||||
import com.intellij.formatting.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyStatementList;
|
||||
import com.jetbrains.python.psi.PyStatementPart;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -223,14 +227,35 @@ public class PyBlock implements Block {
|
||||
public ChildAttributes getChildAttributes(int newChildIndex) {
|
||||
int statementListsBelow = 0;
|
||||
if (newChildIndex > 0) {
|
||||
// always pass decision to a sane block from top level from file or definition
|
||||
if (_node.getPsi() instanceof PyFile || _node.getElementType() == PyTokenTypes.COLON) {
|
||||
return ChildAttributes.DELEGATE_TO_PREV_CHILD;
|
||||
}
|
||||
|
||||
PyBlock insertAfterBlock = (PyBlock)_subBlocks.get(newChildIndex - 1);
|
||||
|
||||
System.out.println( // XXX debug
|
||||
"getChildAttributes(" + newChildIndex + "): " + ((PyBlock)insertAfterBlock).getNode().getPsi().toString() +
|
||||
" " + insertAfterBlock.getTextRange().getStartOffset()
|
||||
+ ":" + insertAfterBlock.getTextRange().getLength()
|
||||
);
|
||||
|
||||
ASTNode prevNode = insertAfterBlock.getNode();
|
||||
PsiElement prevElt = prevNode.getPsi();
|
||||
|
||||
// stmt lists, parts and definitions should also think for themselves
|
||||
if (prevElt instanceof PyStatementList || prevElt instanceof PyStatementPart) {
|
||||
return ChildAttributes.DELEGATE_TO_PREV_CHILD;
|
||||
}
|
||||
|
||||
ASTNode lastChild = insertAfterBlock.getNode();
|
||||
|
||||
// HACK? This code fragment is needed to make testClass2() pass,
|
||||
// but I don't quite understand why it is necessary and why the formatter
|
||||
// doesn't request childAttributes from the correct block
|
||||
while (lastChild != null) {
|
||||
if (lastChild.getElementType() == PyElementTypes.STATEMENT_LIST && hasLineBreakBefore(lastChild)) {
|
||||
IElementType last_type = lastChild.getElementType();
|
||||
if ( last_type == PyElementTypes.STATEMENT_LIST && hasLineBreakBefore(lastChild)) {
|
||||
statementListsBelow++;
|
||||
}
|
||||
else if (statementListsBelow > 0 && lastChild.getPsi() instanceof PsiErrorElement) {
|
||||
@@ -251,11 +276,19 @@ public class PyBlock implements Block {
|
||||
// the innermost block, so we need to resolve the situation here. Nested
|
||||
// delegation sometimes causes NPEs in formatter core, so we calculate the
|
||||
// correct indent manually.
|
||||
if (statementListsBelow > 1) {
|
||||
if (statementListsBelow > 0) { // was 1... strange
|
||||
int indent = _settings.getIndentSize(_language.getAssociatedFileType());
|
||||
return new ChildAttributes(Indent.getSpaceIndent(indent * statementListsBelow), null);
|
||||
}
|
||||
|
||||
/*
|
||||
// it might be something like "def foo(): # comment" or "[1, # comment"; jump up to the real thing
|
||||
if (_node instanceof PsiComment || _node instanceof PsiWhiteSpace) {
|
||||
get
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
return new ChildAttributes(getChildIndent(newChildIndex), getChildAlignment());
|
||||
}
|
||||
|
||||
@@ -273,6 +306,13 @@ public class PyBlock implements Block {
|
||||
PyBlock insertAfterBlock = (PyBlock)_subBlocks.get(newChildIndex - 1);
|
||||
ASTNode afterNode = insertAfterBlock.getNode();
|
||||
|
||||
System.out.println( // XXX debug
|
||||
"getChildIndent(" + newChildIndex + "): " + ((PyBlock)insertAfterBlock).getNode().getPsi().toString() +
|
||||
" " + insertAfterBlock.getTextRange().getStartOffset()
|
||||
+ ":" + insertAfterBlock.getTextRange().getLength()
|
||||
);
|
||||
|
||||
|
||||
// handle pressing Enter after colon and before first statement in
|
||||
// existing statement list
|
||||
if (afterNode.getElementType() == PyElementTypes.STATEMENT_LIST || afterNode.getElementType() == PyTokenTypes.COLON) {
|
||||
@@ -286,8 +326,47 @@ public class PyBlock implements Block {
|
||||
return Indent.getNormalIndent();
|
||||
}
|
||||
}
|
||||
else if (lastChild != null && PyElementTypes.LIST_LIKE_EXPRESSIONS.contains(lastChild.getElementType())) {
|
||||
// handle pressing enter at the end of a list literal when there's no closing paren or bracket
|
||||
ASTNode lastLastChild = lastChild.getLastChildNode();
|
||||
if (lastLastChild != null && lastLastChild.getPsi() instanceof PsiErrorElement) {
|
||||
// we're at a place like this: [foo, ... bar, <caret>
|
||||
// we'd rather align to foo. this may be not a multiple of tabs.
|
||||
PsiElement expr = lastChild.getPsi();
|
||||
PsiElement exprItem = expr.getFirstChild();
|
||||
boolean found = false;
|
||||
while (exprItem != null) { // find a worthy element to align to
|
||||
if (exprItem instanceof PyElement) {
|
||||
found = true; // align to foo in "[foo,"
|
||||
break;
|
||||
}
|
||||
if (exprItem instanceof PsiComment) {
|
||||
found = true; // align to foo in "[ # foo,"
|
||||
break;
|
||||
}
|
||||
exprItem = exprItem.getNextSibling();
|
||||
}
|
||||
if (found) {
|
||||
PsiDocumentManager docMgr = PsiDocumentManager.getInstance(exprItem.getProject());
|
||||
Document doc = docMgr.getDocument(exprItem.getContainingFile());
|
||||
if (doc != null) {
|
||||
int line_num = doc.getLineNumber(exprItem.getTextOffset());
|
||||
int item_col = exprItem.getTextOffset() - doc.getLineStartOffset(line_num);
|
||||
PsiElement here_elt = getNode().getPsi();
|
||||
line_num = doc.getLineNumber(here_elt.getTextOffset());
|
||||
int node_col = here_elt.getTextOffset() - doc.getLineStartOffset(line_num);
|
||||
int padding = item_col - node_col;
|
||||
if (padding > 0) { // negative is a syntax error, but possible
|
||||
return Indent.getSpaceIndent(padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Indent.getContinuationIndent(); // a fallback
|
||||
}
|
||||
}
|
||||
|
||||
if (_listElementTypes.contains(_node.getElementType())) {
|
||||
// constructs that imply indent for their children
|
||||
if (_listElementTypes.contains(_node.getElementType()) || _node.getPsi() instanceof PyStatementPart) {
|
||||
return Indent.getNormalIndent();
|
||||
}
|
||||
|
||||
|
||||
@@ -483,62 +483,83 @@ public class StatementParsing
|
||||
private void parseIfStatement() {
|
||||
assertCurrentToken(PyTokenTypes.IF_KEYWORD);
|
||||
final PsiBuilder.Marker ifStatement = myBuilder.mark();
|
||||
final PsiBuilder.Marker ifPart = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
getExpressionParser().parseExpression();
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
parseSuite();
|
||||
ifPart.done(PyElementTypes.IF_PART_IF);
|
||||
PsiBuilder.Marker elifPart = myBuilder.mark();
|
||||
while (myBuilder.getTokenType() == PyTokenTypes.ELIF_KEYWORD) {
|
||||
myBuilder.advanceLexer();
|
||||
getExpressionParser().parseExpression();
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
parseSuite();
|
||||
elifPart.done(PyElementTypes.IF_PART_ELIF);
|
||||
elifPart = myBuilder.mark();
|
||||
}
|
||||
elifPart.drop(); // we always kept an open extra elif
|
||||
final PsiBuilder.Marker elsePart = myBuilder.mark();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.ELSE_KEYWORD) {
|
||||
myBuilder.advanceLexer();
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
parseSuite();
|
||||
elsePart.done(PyElementTypes.ELSE_PART);
|
||||
}
|
||||
else elsePart.drop();
|
||||
ifStatement.done(PyElementTypes.IF_STATEMENT);
|
||||
}
|
||||
|
||||
private void parseForStatement() {
|
||||
assertCurrentToken(PyTokenTypes.FOR_KEYWORD);
|
||||
final PsiBuilder.Marker statement = myBuilder.mark();
|
||||
final PsiBuilder.Marker forPart = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
getExpressionParser().parseExpression(true, true);
|
||||
checkMatches(PyTokenTypes.IN_KEYWORD, "'in' expected");
|
||||
getExpressionParser().parseExpression();
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
parseSuite();
|
||||
forPart.done(PyElementTypes.FOR_PART);
|
||||
final PsiBuilder.Marker elsePart = myBuilder.mark();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.ELSE_KEYWORD) {
|
||||
myBuilder.advanceLexer();
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
parseSuite();
|
||||
elsePart.done(PyElementTypes.ELSE_PART);
|
||||
}
|
||||
else elsePart.drop();
|
||||
statement.done(PyElementTypes.FOR_STATEMENT);
|
||||
}
|
||||
|
||||
private void parseWhileStatement() {
|
||||
assertCurrentToken(PyTokenTypes.WHILE_KEYWORD);
|
||||
final PsiBuilder.Marker statement = myBuilder.mark();
|
||||
final PsiBuilder.Marker whilePart = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
getExpressionParser().parseExpression();
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
parseSuite();
|
||||
whilePart.done(PyElementTypes.WHILE_PART);
|
||||
final PsiBuilder.Marker elsePart = myBuilder.mark();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.ELSE_KEYWORD) {
|
||||
myBuilder.advanceLexer();
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
parseSuite();
|
||||
elsePart.done(PyElementTypes.ELSE_PART);
|
||||
}
|
||||
else elsePart.drop();
|
||||
statement.done(PyElementTypes.WHILE_STATEMENT);
|
||||
}
|
||||
|
||||
private void parseTryStatement() {
|
||||
assertCurrentToken(PyTokenTypes.TRY_KEYWORD);
|
||||
final PsiBuilder.Marker statement = myBuilder.mark();
|
||||
final PsiBuilder.Marker tryPart = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
parseSuite();
|
||||
tryPart.done(PyElementTypes.TRY_PART);
|
||||
boolean haveExceptClause = false;
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.EXCEPT_KEYWORD) {
|
||||
haveExceptClause = true;
|
||||
@@ -558,23 +579,31 @@ public class StatementParsing
|
||||
}
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
parseSuite();
|
||||
exceptBlock.done(PyElementTypes.EXCEPT_BLOCK);
|
||||
exceptBlock.done(PyElementTypes.EXCEPT_PART);
|
||||
}
|
||||
final PsiBuilder.Marker elsePart = myBuilder.mark();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.ELSE_KEYWORD) {
|
||||
myBuilder.advanceLexer();
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
parseSuite();
|
||||
elsePart.done(PyElementTypes.ELSE_PART);
|
||||
}
|
||||
else elsePart.drop();
|
||||
}
|
||||
final PsiBuilder.Marker finallyPart = myBuilder.mark();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.FINALLY_KEYWORD) {
|
||||
myBuilder.advanceLexer();
|
||||
checkMatches(PyTokenTypes.COLON, "colon expected");
|
||||
parseSuite();
|
||||
finallyPart.done(PyElementTypes.FINALLY_PART);
|
||||
}
|
||||
else if (!haveExceptClause) {
|
||||
myBuilder.error("'except' or 'finally' expected");
|
||||
// much better to have a statement of incorrectly determined type
|
||||
// than "TRY" and "COLON" tokens attached to nothing
|
||||
else {
|
||||
finallyPart.drop();
|
||||
if (!haveExceptClause) {
|
||||
myBuilder.error("'except' or 'finally' expected");
|
||||
// much better to have a statement of incorrectly determined type
|
||||
// than "TRY" and "COLON" tokens attached to nothing
|
||||
}
|
||||
}
|
||||
statement.done(PyElementTypes.TRY_EXCEPT_STATEMENT);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A statement part that has a condition before it.
|
||||
* User: dcheryasov
|
||||
* Date: Mar 16, 2009 4:44:25 AM
|
||||
*/
|
||||
public interface PyConditionalStatementPart extends PyStatementPart {
|
||||
/**
|
||||
* @return the condition expression.
|
||||
*/
|
||||
@Nullable
|
||||
PyExpression getCondition();
|
||||
}
|
||||
@@ -158,7 +158,7 @@ public class PyElementVisitor extends PsiElementVisitor {
|
||||
visitPyElement(node);
|
||||
}
|
||||
|
||||
public void visitPyExceptBlock(final PyExceptBlock node) {
|
||||
public void visitPyExceptBlock(final PyExceptPart node) {
|
||||
visitPyElement(node);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* The 'else:' part of various compound statements.
|
||||
* User: dcheryasov
|
||||
* Date: Mar 15, 2009 9:34:51 PM
|
||||
*/
|
||||
public interface PyElsePart extends PyStatementPart {
|
||||
/**
|
||||
* @return the body of the 'else' part.
|
||||
*/
|
||||
@Nullable
|
||||
PyStatementList getStatementList();
|
||||
}
|
||||
+2
-4
@@ -17,7 +17,6 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
@@ -26,10 +25,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
* Time: 23:37:32
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public interface PyExceptBlock extends PyElement, NameDefiner {
|
||||
PyExceptBlock[] EMPTY_ARRAY = new PyExceptBlock[0];
|
||||
public interface PyExceptPart extends PyElement, NameDefiner, PyStatementPart {
|
||||
PyExceptPart[] EMPTY_ARRAY = new PyExceptPart[0];
|
||||
|
||||
@Nullable PyExpression getExceptClass();
|
||||
@Nullable PyExpression getTarget();
|
||||
@NotNull PyStatementList getStatementList();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
/**
|
||||
* The 'finally' part.
|
||||
* @see PyTryPart
|
||||
* User: dcheryasov
|
||||
* Date: Mar 16, 2009 6:29:22 AM
|
||||
*/
|
||||
public interface PyFinallyPart extends PyStatementPart {
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Main part of a 'for' statement
|
||||
* User: dcheryasov
|
||||
* Date: Mar 15, 2009 8:55:22 PM
|
||||
*/
|
||||
public interface PyForPart extends PyStatementPart {
|
||||
/**
|
||||
* @return target: the "x" in "<code>for x in (1, 2, 3)</code>".
|
||||
*/
|
||||
@Nullable
|
||||
PyExpression getTarget();
|
||||
|
||||
/**
|
||||
* @return source of iteration: the "(1, 2, 3)" in "<code>for x in (1, 2, 3)</code>".
|
||||
*/
|
||||
@Nullable
|
||||
PyExpression getSource();
|
||||
|
||||
}
|
||||
@@ -20,15 +20,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: yole
|
||||
* Date: 29.05.2005
|
||||
* Time: 21:20:52
|
||||
* To change this template use File | Settings | File Templates.
|
||||
* The 'for/else' statement.
|
||||
*/
|
||||
public interface PyForStatement extends PyStatement, NameDefiner {
|
||||
@NotNull PyStatementList getStatementList();
|
||||
@Nullable PyStatementList getElseStatementList();
|
||||
@Nullable PyExpression getTargetExpression();
|
||||
@Nullable PyExpression getLoopExpression();
|
||||
@NotNull PyForPart getForPart();
|
||||
@Nullable PyElsePart getElsePart();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
/**
|
||||
* Branches of an 'if' statement.
|
||||
* @see PyElsePart
|
||||
* User: dcheryasov
|
||||
* Date: Mar 12, 2009 2:16:00 AM
|
||||
*/
|
||||
public interface PyIfPart extends PyConditionalStatementPart {
|
||||
PyIfPart[] EMPTY_ARRAY = new PyIfPart[0];
|
||||
/**
|
||||
* @return true for a 'elif' part.
|
||||
*/
|
||||
boolean isElif();
|
||||
|
||||
}
|
||||
@@ -20,14 +20,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: yole
|
||||
* Date: 29.05.2005
|
||||
* Time: 21:07:48
|
||||
* To change this template use File | Settings | File Templates.
|
||||
* The 'if/elif/else' statement.
|
||||
*/
|
||||
public interface PyIfStatement extends PyStatement {
|
||||
@NotNull PyExpression[] getConditions();
|
||||
@NotNull PyStatementList[] getStatementLists();
|
||||
@Nullable PyStatementList getElseStatementList();
|
||||
@NotNull PyIfPart getIfPart();
|
||||
@NotNull PyIfPart[] getElifParts();
|
||||
@Nullable PyElsePart getElsePart();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Abstract part of a multipart statement.
|
||||
* User: dcheryasov
|
||||
* Date: Mar 16, 2009 4:34:59 AM
|
||||
*/
|
||||
public interface PyStatementPart extends PyElement {
|
||||
PyStatementPart[] EMPTY_ARRAY = new PyStatementPart[0];
|
||||
|
||||
/**
|
||||
* @return the body of the part.
|
||||
*/
|
||||
@Nullable
|
||||
PyStatementList getStatementList();
|
||||
}
|
||||
@@ -20,22 +20,20 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: yole
|
||||
* The 'try/except/else/finally' statement.
|
||||
* Date: 02.06.2005
|
||||
* Time: 23:14:36
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public interface PyTryExceptStatement extends PyStatement {
|
||||
@NotNull
|
||||
PyStatementList getTryStatementList();
|
||||
PyTryPart getTryPart();
|
||||
|
||||
@NotNull
|
||||
PyExceptBlock[] getExceptBlocks();
|
||||
PyExceptPart[] getExceptParts();
|
||||
|
||||
@Nullable
|
||||
PyStatementList getElseStatementList();
|
||||
PyElsePart getElsePart();
|
||||
|
||||
@Nullable
|
||||
PyStatementList getFinallyStatementList();
|
||||
PyFinallyPart getFinallyPart();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
/**
|
||||
* The 'try' part.
|
||||
* @see PyExceptPart
|
||||
* @see PyFinallyPart
|
||||
* @see PyElsePart
|
||||
* User: dcheryasov
|
||||
* Date: Mar 16, 2009 6:26:40 AM
|
||||
*/
|
||||
public interface PyTryPart extends PyStatementPart {
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
/**
|
||||
* The 'while' part of a cycle.
|
||||
* @see PyElsePart
|
||||
* User: dcheryasov
|
||||
* Date: Mar 16, 2009 4:25:59 AM
|
||||
*/
|
||||
public interface PyWhilePart extends PyConditionalStatementPart {
|
||||
}
|
||||
@@ -20,13 +20,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: yole
|
||||
* Date: 29.05.2005
|
||||
* Time: 15:47:19
|
||||
* To change this template use File | Settings | File Templates.
|
||||
* The 'while' statement.
|
||||
*/
|
||||
public interface PyWhileStatement extends PyLoopStatement {
|
||||
@NotNull PyStatementList getStatementList();
|
||||
@Nullable PyStatementList getElseStatementList();
|
||||
@NotNull PyWhilePart getWhilePart();
|
||||
@Nullable PyElsePart getElsePart();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.jetbrains.python.psi.PyConditionalStatementPart;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.intellij.lang.ASTNode;
|
||||
|
||||
/**
|
||||
* User: dcheryasov
|
||||
* Date: Mar 16, 2009 4:46:26 AM
|
||||
*/
|
||||
public abstract class PyConditionalStatementPartImpl extends PyStatementPartImpl implements PyConditionalStatementPart {
|
||||
public PyConditionalStatementPartImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
public PyExpression getCondition() {
|
||||
ASTNode n = getNode().findChildByType(PyElementTypes.EXPRESSIONS);
|
||||
if (n != null) {
|
||||
return (PyExpression)n.getPsi();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.jetbrains.python.psi.PyElsePart;
|
||||
import com.jetbrains.python.psi.PyStatementList;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.intellij.lang.ASTNode;
|
||||
|
||||
/**
|
||||
* User: dcheryasov
|
||||
* Date: Mar 15, 2009 9:40:35 PM
|
||||
*/
|
||||
public class PyElsePartImpl extends PyElementImpl implements PyElsePart {
|
||||
|
||||
public PyElsePartImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
public PyStatementList getStatementList() {
|
||||
ASTNode n = getNode().findChildByType(PyElementTypes.STATEMENT_LISTS);
|
||||
if (n != null) {
|
||||
return (PyStatementList)n.getPsi();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -29,8 +29,8 @@ import com.jetbrains.python.psi.*;
|
||||
* Time: 23:37:49
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class PyExceptBlockImpl extends PyElementImpl implements PyExceptBlock {
|
||||
public PyExceptBlockImpl(ASTNode astNode) {
|
||||
public class PyExceptPartImpl extends PyElementImpl implements PyExceptPart {
|
||||
public PyExceptPartImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.psi.PyFinallyPart;
|
||||
|
||||
/**
|
||||
* User: dcheryasov
|
||||
* Date: Mar 16, 2009 6:58:03 AM
|
||||
*/
|
||||
public class PyFinallyPartImpl extends PyStatementPartImpl implements PyFinallyPart{
|
||||
public PyFinallyPartImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.psi.PyElementType;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyForPart;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: dcheryasov
|
||||
* Date: Mar 15, 2009 9:57:48 PM
|
||||
*/
|
||||
public class PyForPartImpl extends PyStatementPartImpl implements PyForPart {
|
||||
public PyForPartImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that given node actually follows a node of given type, skipping whitespace.
|
||||
* @param node node to check.
|
||||
* @param eltType type of a node that must precede the node we're checking.
|
||||
* @return true if node is really a next sibling to a node of eltType type.
|
||||
*/
|
||||
protected static boolean followsNodeOfType(ASTNode node, PyElementType eltType) {
|
||||
if (node != null) {
|
||||
PsiElement checker = node.getPsi();
|
||||
checker = checker.getPrevSibling(); // step from the source node
|
||||
while (checker != null) {
|
||||
ASTNode ch_node = checker.getNode();
|
||||
if (ch_node == null) return false;
|
||||
else {
|
||||
if (ch_node.getElementType() == eltType) {
|
||||
return true;
|
||||
}
|
||||
else if (!(checker instanceof PsiWhiteSpace)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
checker = checker.getPrevSibling();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public PyExpression getTarget() {
|
||||
ASTNode n = getNode().findChildByType(PyElementTypes.EXPRESSIONS);
|
||||
if (followsNodeOfType(n, PyTokenTypes.FOR_KEYWORD)) {
|
||||
return (PyExpression)n.getPsi(); // can't be null, 'if' would fail
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
|
||||
public PyExpression getSource() {
|
||||
List<PsiElement> exprs = findChildrenByType(PyElementTypes.EXPRESSIONS);
|
||||
// normally there are 2 exprs, the second is the source.
|
||||
if (exprs.size() != 2) return null; // could be a parsing error
|
||||
PyExpression ret = (PyExpression)exprs.get(1);
|
||||
if (followsNodeOfType(ret.getNode(), PyTokenTypes.IN_KEYWORD)) return ret;
|
||||
else return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,20 +21,15 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.ResolveState;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.PyStatementList;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: yole
|
||||
* Date: 29.05.2005
|
||||
* Time: 21:21:12
|
||||
* To change this template use File | Settings | File Templates.
|
||||
* Date: 29.05.2005 (initial)
|
||||
*/
|
||||
public class PyForStatementImpl extends PyElementImpl implements PyForStatement {
|
||||
public class PyForStatementImpl extends PyPartitionedElementImpl implements PyForStatement {
|
||||
public PyForStatementImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
@@ -44,24 +39,13 @@ public class PyForStatementImpl extends PyElementImpl implements PyForStatement
|
||||
pyVisitor.visitPyForStatement(this);
|
||||
}
|
||||
|
||||
public PyElsePart getElsePart() {
|
||||
return (PyElsePart)getPart(PyElementTypes.ELSE_PART);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PyStatementList getStatementList() {
|
||||
return childToPsiNotNull(PyElementTypes.STATEMENT_LISTS, 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PyStatementList getElseStatementList() {
|
||||
return childToPsi(PyElementTypes.STATEMENT_LISTS, 1);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PyExpression getTargetExpression() {
|
||||
return childToPsi(PyElementTypes.EXPRESSIONS, 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PyExpression getLoopExpression() {
|
||||
return childToPsi(PyElementTypes.EXPRESSIONS, 1);
|
||||
public PyForPart getForPart() {
|
||||
return (PyForPart)getPartNotNull(PyElementTypes.FOR_PART);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,25 +53,29 @@ public class PyForStatementImpl extends PyElementImpl implements PyForStatement
|
||||
@NotNull ResolveState substitutor,
|
||||
PsiElement lastParent,
|
||||
@NotNull PsiElement place) {
|
||||
final PyExpression target = getTargetExpression();
|
||||
PyForPart forPart = getForPart();
|
||||
final PyExpression target = forPart.getTarget();
|
||||
if (target != null && target != lastParent && !target.processDeclarations(processor, substitutor, null, place)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PyStatementList statementList = getStatementList();
|
||||
if (statementList != lastParent && !statementList.processDeclarations(processor, substitutor, null, place)) {
|
||||
final PyStatementList statementList = forPart.getStatementList();
|
||||
if (statementList != null && statementList != lastParent && !statementList.processDeclarations(processor, substitutor, null, place)) {
|
||||
return false;
|
||||
}
|
||||
PyStatementList elseList = getElseStatementList();
|
||||
if (elseList != null && elseList != lastParent) {
|
||||
return elseList.processDeclarations(processor, substitutor, null, place);
|
||||
PyElsePart elsePart = getElsePart();
|
||||
if (elsePart != null) {
|
||||
PyStatementList elseList = elsePart.getStatementList();
|
||||
if (elseList != null && elseList != lastParent) {
|
||||
return elseList.processDeclarations(processor, substitutor, null, place);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Iterable<PyElement> iterateNames() {
|
||||
PyExpression tgt = getTargetExpression();
|
||||
PyExpression tgt = getForPart().getTarget();
|
||||
if (tgt instanceof PyReferenceExpression) return new SingleIterable<PyElement>(tgt);
|
||||
else {
|
||||
return PyUtil.flattenedParens(new PyElement[]{tgt});
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.psi.PyIfPart;
|
||||
|
||||
/**
|
||||
* PyIfPart that represents an 'elif' part.
|
||||
* User: dcheryasov
|
||||
* Date: Mar 12, 2009 5:21:11 PM
|
||||
*/
|
||||
public class PyIfPartElifImpl extends PyConditionalStatementPartImpl implements PyIfPart {
|
||||
public PyIfPartElifImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
public boolean isElif() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.psi.PyIfPart;
|
||||
|
||||
/**
|
||||
* PyIfPart that represents an 'if' part.
|
||||
* User: dcheryasov
|
||||
* Date: Mar 12, 2009 2:33:39 AM
|
||||
*/
|
||||
public class PyIfPartIfImpl extends PyConditionalStatementPartImpl implements PyIfPart {
|
||||
|
||||
public PyIfPartIfImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
public boolean isElif() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,12 +22,8 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.ResolveState;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyIfStatement;
|
||||
import com.jetbrains.python.psi.PyStatementList;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
@@ -36,65 +32,61 @@ import org.jetbrains.annotations.Nullable;
|
||||
* Time: 21:08:06
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class PyIfStatementImpl extends PyElementImpl implements PyIfStatement {
|
||||
private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.psi.impl.PyIfStatementImpl");
|
||||
public class PyIfStatementImpl extends PyPartitionedElementImpl implements PyIfStatement {
|
||||
private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.psi.impl.PyIfStatementImpl");
|
||||
|
||||
public PyIfStatementImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
public PyIfStatementImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
@Override protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyIfStatement(this);
|
||||
}
|
||||
@Override protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyIfStatement(this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PyIfPart getIfPart() {
|
||||
return (PyIfPart)getPartNotNull(PyElementTypes.IF_PART_IF);
|
||||
}
|
||||
|
||||
@NotNull public PyExpression[] getConditions() {
|
||||
return childrenToPsi(PyElementTypes.EXPRESSIONS, PyExpression.EMPTY_ARRAY);
|
||||
}
|
||||
@NotNull
|
||||
public PyIfPart[] getElifParts() {
|
||||
return childrenToPsi(PyElementTypes.ELIFS, PyIfPart.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@NotNull public PyStatementList[] getStatementLists() {
|
||||
final ASTNode[] conditions = getNode().getChildren(PyElementTypes.EXPRESSIONS);
|
||||
final PyStatementList[] statementLists = childrenToPsi(PyElementTypes.STATEMENT_LISTS, PyStatementList.EMPTY_ARRAY);
|
||||
LOG.assertTrue(statementLists.length == conditions.length || statementLists.length == conditions.length+1);
|
||||
if (statementLists.length > conditions.length) {
|
||||
final PyStatementList[] result = new PyStatementList[conditions.length];
|
||||
System.arraycopy(statementLists, 0, result, 0, conditions.length);
|
||||
return result;
|
||||
}
|
||||
return statementLists;
|
||||
}
|
||||
public PyElsePart getElsePart() {
|
||||
return (PyElsePart)getPart(PyElementTypes.ELSE_PART);
|
||||
}
|
||||
|
||||
public @Nullable PyStatementList getElseStatementList() {
|
||||
final ASTNode[] conditions = getNode().getChildren(PyElementTypes.EXPRESSIONS);
|
||||
final PyStatementList[] statementLists = childrenToPsi(PyElementTypes.STATEMENT_LISTS, PyStatementList.EMPTY_ARRAY);
|
||||
LOG.assertTrue(statementLists.length == conditions.length || statementLists.length == conditions.length+1);
|
||||
if (statementLists.length > conditions.length) {
|
||||
return statementLists [statementLists.length-1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
|
||||
@Override public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
|
||||
@NotNull ResolveState substitutor,
|
||||
PsiElement lastParent,
|
||||
@NotNull PsiElement place)
|
||||
{
|
||||
if (lastParent != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PyStatementList[] statementLists = getStatementLists();
|
||||
for (PyStatementList statementList: statementLists) {
|
||||
if (!statementList.processDeclarations(processor, substitutor, lastParent, place)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PyStatementList elseList = getElseStatementList();
|
||||
//noinspection RedundantIfStatement
|
||||
if (elseList != null && !elseList.processDeclarations(processor, substitutor, lastParent, place)) {
|
||||
if (lastParent != null) {
|
||||
return true;
|
||||
}
|
||||
for (PyStatementPart part : getParts()) {
|
||||
PyStatementList stmtList = part.getStatementList();
|
||||
if (stmtList != null && !stmtList.processDeclarations(processor, substitutor, lastParent, place)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
PyStatementList[] statementLists = getStatementLists();
|
||||
for (PyStatementList statementList: statementLists) {
|
||||
if (!statementList.processDeclarations(processor, substitutor, lastParent, place)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PyStatementList elseList = getElseStatementList();
|
||||
//noinspection RedundantIfStatement
|
||||
if (elseList != null && !elseList.processDeclarations(processor, substitutor, lastParent, place)) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.psi.PyElementType;
|
||||
import com.jetbrains.python.psi.PyStatementPart;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Common parts functionality.
|
||||
* User: dcheryasov
|
||||
* Date: Mar 19, 2009 2:51:15 AM
|
||||
*/
|
||||
public class PyPartitionedElementImpl extends PyElementImpl {
|
||||
public PyPartitionedElementImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
PyStatementPart[] getParts() {
|
||||
return childrenToPsi(PyElementTypes.PARTS, PyStatementPart.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected PyStatementPart getPart(PyElementType which) {
|
||||
ASTNode n = getNode().findChildByType(which);
|
||||
if (n == null) return null;
|
||||
return (PyStatementPart)n.getPsi();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected PyStatementPart getPartNotNull(PyElementType which) {
|
||||
ASTNode n = getNode().findChildByType(which);
|
||||
assert n != null;
|
||||
return (PyStatementPart)n.getPsi();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.jetbrains.python.psi.PyStatementPart;
|
||||
import com.jetbrains.python.psi.PyStatementList;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.intellij.lang.ASTNode;
|
||||
|
||||
/**
|
||||
* Abstract statement part implementation; extracts the statements list.
|
||||
* User: dcheryasov
|
||||
* Date: Mar 16, 2009 4:36:50 AM
|
||||
*/
|
||||
public abstract class PyStatementPartImpl extends PyElementImpl implements PyStatementPart {
|
||||
protected PyStatementPartImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
public PyStatementList getStatementList() {
|
||||
ASTNode n = getNode().findChildByType(PyElementTypes.STATEMENT_LISTS);
|
||||
if (n != null) {
|
||||
return (PyStatementList)n.getPsi();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -22,13 +22,8 @@ import com.intellij.psi.ResolveState;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyExceptBlock;
|
||||
import com.jetbrains.python.psi.PyStatementList;
|
||||
import com.jetbrains.python.psi.PyTryExceptStatement;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
@@ -37,8 +32,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
* Time: 23:14:57
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class PyTryExceptStatementImpl extends PyElementImpl implements PyTryExceptStatement {
|
||||
private static final TokenSet EXCEPT_BLOCKS = TokenSet.create(PyElementTypes.EXCEPT_BLOCK);
|
||||
public class PyTryExceptStatementImpl extends PyPartitionedElementImpl implements PyTryExceptStatement {
|
||||
private static final TokenSet EXCEPT_BLOCKS = TokenSet.create(PyElementTypes.EXCEPT_PART);
|
||||
|
||||
public PyTryExceptStatementImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
@@ -50,45 +45,22 @@ public class PyTryExceptStatementImpl extends PyElementImpl implements PyTryExce
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PyStatementList getTryStatementList() {
|
||||
return childToPsiNotNull(PyElementTypes.STATEMENT_LISTS, 0);
|
||||
public PyExceptPart[] getExceptParts() {
|
||||
return childrenToPsi(EXCEPT_BLOCKS, PyExceptPart.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
public PyElsePart getElsePart() {
|
||||
return (PyElsePart)getPart(PyElementTypes.ELSE_PART);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PyExceptBlock[] getExceptBlocks() {
|
||||
return childrenToPsi(EXCEPT_BLOCKS, PyExceptBlock.EMPTY_ARRAY);
|
||||
public PyTryPart getTryPart() {
|
||||
return (PyTryPart)getPartNotNull(PyElementTypes.TRY_PART);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PyStatementList getElseStatementList() {
|
||||
final ASTNode node = getNode().findChildByType(PyTokenTypes.ELSE_KEYWORD);
|
||||
if (node != null) {
|
||||
return (PyStatementList)findNextChildOfType(node, PyElementTypes.STATEMENT_LISTS);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PyStatementList getFinallyStatementList() {
|
||||
final ASTNode node = getNode().findChildByType(PyTokenTypes.FINALLY_KEYWORD);
|
||||
if (node != null) {
|
||||
return (PyStatementList)findNextChildOfType(node, PyElementTypes.STATEMENT_LISTS);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement findNextChildOfType(ASTNode node, final TokenSet matchTokens) {
|
||||
ASTNode sibling = node.getTreeNext();
|
||||
while (sibling != null) {
|
||||
if (matchTokens.contains(sibling.getElementType())) {
|
||||
return sibling.getPsi();
|
||||
}
|
||||
sibling = sibling.getTreeNext();
|
||||
}
|
||||
return null;
|
||||
public PyFinallyPart getFinallyPart() {
|
||||
return (PyFinallyPart)getPart(PyElementTypes.FINALLY_PART);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,21 +68,28 @@ public class PyTryExceptStatementImpl extends PyElementImpl implements PyTryExce
|
||||
@NotNull ResolveState substitutor,
|
||||
PsiElement lastParent,
|
||||
@NotNull PsiElement place) {
|
||||
final PyStatementList tryStatementList = getTryStatementList();
|
||||
if (tryStatementList != lastParent && !tryStatementList.processDeclarations(processor, substitutor, null, place)) {
|
||||
/*
|
||||
final PyStatementList tryStatementList = getTryPart().getStatementList();
|
||||
if (tryStatementList != null && tryStatementList != lastParent && !tryStatementList.processDeclarations(processor, substitutor, null, place)) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
for (PyExceptBlock block : getExceptBlocks()) {
|
||||
if (block != lastParent && !block.processDeclarations(processor, substitutor, null, place)) {
|
||||
for (PyStatementPart part : /*getExceptParts()*/ getParts()) {
|
||||
if (part != lastParent && !part.processDeclarations(processor, substitutor, null, place)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PyStatementList elseStatementList = getElseStatementList();
|
||||
if (elseStatementList != null && elseStatementList != lastParent) {
|
||||
return elseStatementList.processDeclarations(processor, substitutor, null, place);
|
||||
/*
|
||||
final PyElsePart elsePart = getElsePart();
|
||||
if (elsePart != null) {
|
||||
PyStatementList elseStatementList = elsePart.getStatementList();
|
||||
if (elseStatementList != null && elseStatementList != lastParent) {
|
||||
return elseStatementList.processDeclarations(processor, substitutor, null, place);
|
||||
}
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.psi.PyTryPart;
|
||||
|
||||
/**
|
||||
* User: dcheryasov
|
||||
* Date: Mar 16, 2009 6:56:55 AM
|
||||
*/
|
||||
public class PyTryPartImpl extends PyStatementPartImpl implements PyTryPart {
|
||||
public PyTryPartImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.psi.PyWhilePart;
|
||||
|
||||
/**
|
||||
* User: dcheryasov
|
||||
* Date: Mar 16, 2009 4:33:32 AM
|
||||
*/
|
||||
public class PyWhilePartImpl extends PyConditionalStatementPartImpl implements PyWhilePart {
|
||||
public PyWhilePartImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,9 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.ResolveState;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyStatementList;
|
||||
import com.jetbrains.python.psi.PyWhileStatement;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
@@ -34,39 +31,51 @@ import com.jetbrains.python.psi.PyWhileStatement;
|
||||
* Time: 15:47:44
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class PyWhileStatementImpl extends PyElementImpl implements PyWhileStatement {
|
||||
public PyWhileStatementImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
public class PyWhileStatementImpl extends PyPartitionedElementImpl implements PyWhileStatement {
|
||||
public PyWhileStatementImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
@Override protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyWhileStatement(this);
|
||||
}
|
||||
@Override protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyWhileStatement(this);
|
||||
}
|
||||
|
||||
public @NotNull PyStatementList getStatementList() {
|
||||
return childToPsiNotNull(PyElementTypes.STATEMENT_LISTS, 0);
|
||||
}
|
||||
@NotNull
|
||||
public PyWhilePart getWhilePart() {
|
||||
return (PyWhilePart)getPartNotNull(PyElementTypes.WHILE_PART);
|
||||
}
|
||||
|
||||
public @Nullable PyStatementList getElseStatementList() {
|
||||
return childToPsi(PyElementTypes.STATEMENT_LISTS, 1);
|
||||
}
|
||||
public PyElsePart getElsePart() {
|
||||
return (PyElsePart)getPart(PyElementTypes.ELSE_PART);
|
||||
}
|
||||
|
||||
@Override public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
|
||||
@Override public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
|
||||
@NotNull ResolveState substitutor,
|
||||
PsiElement lastParent,
|
||||
@NotNull PsiElement place)
|
||||
{
|
||||
if (lastParent != null) {
|
||||
return true;
|
||||
}
|
||||
if (lastParent != null) return true;
|
||||
|
||||
if (!getStatementList().processDeclarations(processor, substitutor, null, place)) {
|
||||
return false;
|
||||
for (PyStatementPart part : getParts()) {
|
||||
PyStatementList stmtList = part.getStatementList();
|
||||
if (stmtList != null) {
|
||||
return stmtList.processDeclarations(processor, substitutor, null, place);
|
||||
}
|
||||
PyStatementList elseList = getElseStatementList();
|
||||
}
|
||||
|
||||
/*
|
||||
final PyStatementList whileStmts = getWhilePart().getStatementList();
|
||||
if (whileStmts != null && !whileStmts.processDeclarations(processor, substitutor, null, place)) {
|
||||
return false;
|
||||
}
|
||||
final PyElsePart elsePart = getElsePart();
|
||||
if (elsePart != null) {
|
||||
PyStatementList elseList = elsePart.getStatementList();
|
||||
if (elseList != null) {
|
||||
return elseList.processDeclarations(processor, substitutor, null, place);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class AssignTargetAnnotator extends PyAnnotator {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitPyExceptBlock(final PyExceptBlock node) {
|
||||
@Override public void visitPyExceptBlock(final PyExceptPart node) {
|
||||
PyExpression target = node.getTarget();
|
||||
if (target != null) {
|
||||
target.accept(new ExprVisitor(Operation.Except));
|
||||
@@ -56,7 +56,7 @@ public class AssignTargetAnnotator extends PyAnnotator {
|
||||
}
|
||||
|
||||
@Override public void visitPyForStatement(final PyForStatement node) {
|
||||
PyExpression target = node.getTargetExpression();
|
||||
PyExpression target = node.getForPart().getTarget();
|
||||
if (target != null) {
|
||||
target.accept(new ExprVisitor(Operation.For));
|
||||
}
|
||||
|
||||
@@ -16,42 +16,36 @@
|
||||
|
||||
package com.jetbrains.python.validation;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import static com.jetbrains.python.PyBundle.message;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.psi.PyBreakStatement;
|
||||
import com.jetbrains.python.psi.PyContinueStatement;
|
||||
import com.jetbrains.python.psi.PyTryExceptStatement;
|
||||
import com.jetbrains.python.psi.*;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: yole
|
||||
* Date: 13.06.2005
|
||||
* Time: 15:01:05
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class BreakContinueAnnotator extends PyAnnotator {
|
||||
@Override public void visitPyBreakStatement(final PyBreakStatement node) {
|
||||
if (node.getContainingElement(PyElementTypes.LOOPS) == null) {
|
||||
getHolder().createErrorAnnotation(node, message("ANN.break.outside.loop"));
|
||||
}
|
||||
@Override public void visitPyBreakStatement(final PyBreakStatement node) {
|
||||
if (node.getContainingElement(PyElementTypes.LOOPS) == null) {
|
||||
getHolder().createErrorAnnotation(node, message("ANN.break.outside.loop"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitPyContinueStatement(final PyContinueStatement node) {
|
||||
if (node.getContainingElement(PyElementTypes.LOOPS) == null) {
|
||||
getHolder().createErrorAnnotation(node, message("ANN.continue.outside.loop"));
|
||||
return;
|
||||
}
|
||||
PyTryExceptStatement tryStatement = node.getContainingElement(PyTryExceptStatement.class);
|
||||
if (tryStatement != null) {
|
||||
PsiElement parent = node.getParent();
|
||||
while (parent != null) {
|
||||
if (parent == tryStatement.getFinallyStatementList()) {
|
||||
getHolder().createErrorAnnotation(node, message("ANN.cant.continue.in.finally"));
|
||||
break;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
}
|
||||
@Override public void visitPyContinueStatement(final PyContinueStatement node) {
|
||||
final PyElement loopStmt = node.getContainingElement(PyElementTypes.LOOPS); // closest loop to contain the 'continue'
|
||||
if (loopStmt == null) {
|
||||
getHolder().createErrorAnnotation(node, message("ANN.continue.outside.loop"));
|
||||
return;
|
||||
}
|
||||
PyTryExceptStatement tryStmt = node.getContainingElement(PyTryExceptStatement.class);
|
||||
if (tryStmt != null) {
|
||||
final PyFinallyPart finallyPart = tryStmt.getFinallyPart();
|
||||
if (finallyPart != null && PsiTreeUtil.isAncestor(loopStmt, finallyPart, true)) {
|
||||
getHolder().createErrorAnnotation(node, message("ANN.cant.continue.in.finally"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.jetbrains.python.validation;
|
||||
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.psi.PyExceptBlock;
|
||||
import com.jetbrains.python.psi.PyExceptPart;
|
||||
import com.jetbrains.python.psi.PyTryExceptStatement;
|
||||
|
||||
/**
|
||||
@@ -27,13 +27,13 @@ import com.jetbrains.python.psi.PyTryExceptStatement;
|
||||
*/
|
||||
public class TryExceptAnnotator extends PyAnnotator {
|
||||
@Override public void visitPyTryExceptStatement(final PyTryExceptStatement node) {
|
||||
PyExceptBlock[] exceptBlocks = node.getExceptBlocks();
|
||||
PyExceptPart[] exceptParts = node.getExceptParts();
|
||||
boolean haveDefaultExcept = false;
|
||||
for(PyExceptBlock block: exceptBlocks) {
|
||||
for(PyExceptPart part : exceptParts) {
|
||||
if (haveDefaultExcept) {
|
||||
getHolder().createErrorAnnotation(block, PyBundle.message("ANN.default.except.must.be.last"));
|
||||
getHolder().createErrorAnnotation(part, PyBundle.message("ANN.default.except.must.be.last"));
|
||||
}
|
||||
if (block.getExceptClass() == null) {
|
||||
if (part.getExceptClass() == null) {
|
||||
haveDefaultExcept = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
if 0:
|
||||
pass
|
||||
|
||||
if 1:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
|
||||
if 2:
|
||||
pass
|
||||
elif 3:
|
||||
pass
|
||||
|
||||
if 4:
|
||||
pass
|
||||
elif 5:
|
||||
pass
|
||||
else:
|
||||
1
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
PyFile:IfStatement.py
|
||||
PyIfStatement
|
||||
PyIfPartIf
|
||||
PsiElement(Py:IF_KEYWORD)('if')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('0')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
PsiWhiteSpace('\n\n')
|
||||
PyIfStatement
|
||||
PyIfPartIf
|
||||
PsiElement(Py:IF_KEYWORD)('if')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('1')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
PsiWhiteSpace('\n')
|
||||
PyElsePart
|
||||
PsiElement(Py:ELSE_KEYWORD)('else')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
PsiWhiteSpace('\n\n')
|
||||
PyIfStatement
|
||||
PyIfPartIf
|
||||
PsiElement(Py:IF_KEYWORD)('if')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('2')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
PsiWhiteSpace('\n')
|
||||
PyIfPartElif
|
||||
PsiElement(Py:ELIF_KEYWORD)('elif')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('3')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
PsiWhiteSpace('\n\n')
|
||||
PyIfStatement
|
||||
PyIfPartIf
|
||||
PsiElement(Py:IF_KEYWORD)('if')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('4')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
PsiWhiteSpace(' \n')
|
||||
PyIfPartElif
|
||||
PsiElement(Py:ELIF_KEYWORD)('elif')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('5')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
PsiWhiteSpace('\n')
|
||||
PyElsePart
|
||||
PsiElement(Py:ELSE_KEYWORD)('else')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyExpressionStatement
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('1')
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
PyFile:TryExceptFinally.py
|
||||
PyTryExceptStatement
|
||||
PsiElement(Py:TRY_KEYWORD)('try')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyExpressionStatement
|
||||
PyReferenceExpression: x
|
||||
PsiElement(Py:IDENTIFIER)('x')
|
||||
PyTryPart
|
||||
PsiElement(Py:TRY_KEYWORD)('try')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyExpressionStatement
|
||||
PyReferenceExpression: x
|
||||
PsiElement(Py:IDENTIFIER)('x')
|
||||
PsiWhiteSpace('\n')
|
||||
PyExceptBlock
|
||||
PyExceptPart
|
||||
PsiElement(Py:EXCEPT_KEYWORD)('except')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
@@ -17,10 +18,11 @@ PyFile:TryExceptFinally.py
|
||||
PyReferenceExpression: y
|
||||
PsiElement(Py:IDENTIFIER)('y')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiElement(Py:FINALLY_KEYWORD)('finally')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyExpressionStatement
|
||||
PyReferenceExpression: z
|
||||
PsiElement(Py:IDENTIFIER)('z')
|
||||
PyFinallyPart
|
||||
PsiElement(Py:FINALLY_KEYWORD)('finally')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyExpressionStatement
|
||||
PyReferenceExpression: z
|
||||
PsiElement(Py:IDENTIFIER)('z')
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
PyFile:TryFinally.py
|
||||
PyTryExceptStatement
|
||||
PsiElement(Py:TRY_KEYWORD)('try')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyExpressionStatement
|
||||
PyReferenceExpression: x
|
||||
PsiElement(Py:IDENTIFIER)('x')
|
||||
PyTryPart
|
||||
PsiElement(Py:TRY_KEYWORD)('try')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyExpressionStatement
|
||||
PyReferenceExpression: x
|
||||
PsiElement(Py:IDENTIFIER)('x')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiElement(Py:FINALLY_KEYWORD)('finally')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyExpressionStatement
|
||||
PyReferenceExpression: z
|
||||
PsiElement(Py:IDENTIFIER)('z')
|
||||
PyFinallyPart
|
||||
PsiElement(Py:FINALLY_KEYWORD)('finally')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyExpressionStatement
|
||||
PyReferenceExpression: z
|
||||
PsiElement(Py:IDENTIFIER)('z')
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# for stmt
|
||||
<stmt>for <target>x in <source>list:
|
||||
pass
|
||||
e<else>lse:
|
||||
pass
|
||||
@@ -0,0 +1,3 @@
|
||||
# only if
|
||||
<the_if>if <the_cond>True:
|
||||
pass
|
||||
@@ -0,0 +1,7 @@
|
||||
# if, elif, and else
|
||||
<the_if>if <the_cond>True:
|
||||
<then_stmt>pass
|
||||
elif <elif_cond>0:
|
||||
<elif_stmt>pass
|
||||
else:
|
||||
<else_stmt>pass
|
||||
@@ -0,0 +1,5 @@
|
||||
# if and else
|
||||
<the_if>if <the_cond>True:
|
||||
<then_stmt>pass
|
||||
else:
|
||||
<else_stmt>pass
|
||||
@@ -0,0 +1,12 @@
|
||||
# try and friends
|
||||
<stmt>try:
|
||||
p<body>ass
|
||||
e<ex1>xcept ArithmeticError, e:
|
||||
pass
|
||||
e<ex2>xcept:
|
||||
pass
|
||||
e<else>lse:
|
||||
pass
|
||||
f<finally>inally:
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# while stmt
|
||||
<stmt>while <cond>True:
|
||||
pass
|
||||
e<else>lse:
|
||||
pass
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.jetbrains.python;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.testFramework.PsiTestCase;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Base for cases that need marked PSI elements.
|
||||
* User: dcheryasov
|
||||
* Date: Mar 14, 2009 11:57:52 PM
|
||||
*/
|
||||
public abstract class MarkedTestCase extends PsiTestCase {
|
||||
|
||||
/**
|
||||
* Marker "as expected", any alphanumeric sting in angle brackets.
|
||||
*/
|
||||
public final @NonNls String MARKER = "<[a-zA-Z0-9_]+>";
|
||||
|
||||
/**
|
||||
* Uses MARKER as regexp.
|
||||
* @see #configureByFileText(String, String, String)
|
||||
* @param filePath file to load and parse
|
||||
* @return a mapping of markers to PSI elements
|
||||
* @throws Exception
|
||||
*/
|
||||
protected Map<String, PsiElement> configureByFile(@NonNls String filePath) throws Exception {
|
||||
return configureByFile(filePath, MARKER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like <a href="#configureByFileText(String, String, String)">configureByFileText</a>, but with a file to be read.
|
||||
* @param filePath file to read and parse
|
||||
* @param markerRegexp regexp for markers
|
||||
* @return a mapping of markers to PSI elements
|
||||
* @throws Exception
|
||||
*/
|
||||
protected Map<String, PsiElement> configureByFile(@NonNls String filePath, @NonNls String markerRegexp)
|
||||
throws Exception
|
||||
{
|
||||
final String fullPath = getTestDataPath() + filePath;
|
||||
final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath.replace(File.separatorChar, '/'));
|
||||
assertNotNull("file " + filePath + " not found", vFile);
|
||||
|
||||
String fileText = StringUtil.convertLineSeparators(VfsUtil.loadText(vFile), "\n");
|
||||
|
||||
final String fileName = vFile.getName();
|
||||
|
||||
return configureByFileText(fileText, fileName, markerRegexp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Typically a text is marked with patterns: "foo <ref1>bar() + <ref2>baz", etc, and the result is
|
||||
* a map where strings "<ref1>" and "<ref2>" are mapped to PSI elements for "bar" and "baz".
|
||||
* @param fileText text to parse
|
||||
* @param fileName name to give to the PSI file
|
||||
* @param markerRegexp regexp to detect markers in the text
|
||||
* @return mapping of markers to the PSI elements
|
||||
* @throws Exception
|
||||
*/
|
||||
protected Map<String, PsiElement> configureByFileText(String fileText, String fileName, @NonNls String markerRegexp)
|
||||
throws Exception
|
||||
{
|
||||
// build a map of marks to positions, and the text with marks stripped
|
||||
Pattern pat = Pattern.compile(markerRegexp);
|
||||
Matcher mat = pat.matcher(fileText);
|
||||
int rest_index = 0; // from here on fileText is not yet looked at
|
||||
Map<String, Integer> offsets = new HashMap<String, Integer>();
|
||||
StringBuffer text = new StringBuffer();
|
||||
while (mat.find(rest_index)) {
|
||||
String mark = mat.group();
|
||||
CharSequence prev_part = fileText.subSequence(rest_index, mat.start());
|
||||
text.append(prev_part);
|
||||
offsets.put(mark, text.length());
|
||||
rest_index = mat.end();
|
||||
}
|
||||
if (rest_index < fileText.length()) text.append(fileText.substring(rest_index));
|
||||
|
||||
// create a file and map marks to PSI elements
|
||||
Map<String, PsiElement> result = new HashMap<String, PsiElement>();
|
||||
myFile = createFile(myModule, fileName, text.toString());
|
||||
for (Map.Entry<String, Integer> entry : offsets.entrySet()) {
|
||||
result.put(entry.getKey(), myFile.findElementAt(entry.getValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Map<String, PsiElement> loadTest() throws Exception {
|
||||
String fname = getTestName(false) + ".py";
|
||||
return configureByFile(fname);
|
||||
}
|
||||
|
||||
protected abstract String getTestDataPath();
|
||||
}
|
||||
@@ -19,6 +19,10 @@ public class PythonParsingTest extends ParsingTestCase {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
public void testIfStatement() throws Exception {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
public void testConditionalExpression() throws Exception {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
package com.jetbrains.python;
|
||||
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.psi.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Tests statement parts.
|
||||
* User: dcheryasov
|
||||
* Date: Mar 15, 2009 3:11:01 AM
|
||||
*/
|
||||
public class StatementPartsTest extends MarkedTestCase {
|
||||
|
||||
protected String getTestDataPath() {
|
||||
return PathManager.getHomePath() + "/plugins/python/testData/psi/parts/";
|
||||
}
|
||||
|
||||
public void testIf() throws Exception {
|
||||
Map<String, PsiElement> marks = loadTest();
|
||||
assertEquals(2, marks.size());
|
||||
PsiElement elt = marks.get("<the_if>").getParent().getParent(); // if_keyword -> if_part -> if_stmt
|
||||
assertTrue(elt instanceof PyIfStatement);
|
||||
PyIfStatement if_stmt = (PyIfStatement)elt;
|
||||
PyIfPart if_part = if_stmt.getIfPart();
|
||||
assertFalse(if_part.isElif());
|
||||
PyExpression if_cond = if_part.getCondition();
|
||||
assertEquals(marks.get("<the_cond>").getParent(), if_cond);
|
||||
}
|
||||
|
||||
public void testIfElse() throws Exception {
|
||||
Map<String, PsiElement> marks = loadTest();
|
||||
assertEquals(4, marks.size());
|
||||
PsiElement elt = marks.get("<the_if>").getParent().getParent(); // if_keyword -> if_part -> if_stmt
|
||||
assertTrue(elt instanceof PyIfStatement);
|
||||
PyIfStatement if_stmt = (PyIfStatement)elt;
|
||||
|
||||
PyIfPart if_part = if_stmt.getIfPart();
|
||||
assertFalse(if_part.isElif());
|
||||
PyExpression if_cond = if_part.getCondition();
|
||||
assertEquals(marks.get("<the_cond>").getParent(), if_cond);
|
||||
|
||||
PyStatementList stmt_list = if_part.getStatementList();
|
||||
assertNotNull(stmt_list);
|
||||
assertEquals(marks.get("<then_stmt>").getParent().getParent(), stmt_list); // keyword -> stmt -> stmt_list
|
||||
|
||||
PyElsePart else_part = if_stmt.getElsePart();
|
||||
assertNotNull(else_part);
|
||||
|
||||
stmt_list = else_part.getStatementList();
|
||||
assertNotNull(stmt_list);
|
||||
assertEquals(marks.get("<else_stmt>").getParent().getParent(), stmt_list); // keyword -> stmt -> stmt_list
|
||||
|
||||
}
|
||||
|
||||
public void testIfElifElse() throws Exception {
|
||||
Map<String, PsiElement> marks = loadTest();
|
||||
assertEquals(6, marks.size());
|
||||
PsiElement elt = marks.get("<the_if>").getParent().getParent(); // if_keyword -> if_part -> if_stmt
|
||||
assertTrue(elt instanceof PyIfStatement);
|
||||
PyIfStatement if_stmt = (PyIfStatement)elt;
|
||||
|
||||
PyIfPart if_part = if_stmt.getIfPart();
|
||||
assertFalse(if_part.isElif());
|
||||
PyExpression if_cond = if_part.getCondition();
|
||||
assertEquals(marks.get("<the_cond>").getParent(), if_cond);
|
||||
|
||||
PyStatementList stmt_list = if_part.getStatementList();
|
||||
assertNotNull(stmt_list);
|
||||
assertEquals(marks.get("<then_stmt>").getParent().getParent(), stmt_list); // keyword -> stmt -> stmt_list
|
||||
|
||||
PyElsePart else_part = if_stmt.getElsePart();
|
||||
assertNotNull(else_part);
|
||||
|
||||
stmt_list = else_part.getStatementList();
|
||||
assertNotNull(stmt_list);
|
||||
assertEquals(marks.get("<else_stmt>").getParent().getParent(), stmt_list); // keyword -> stmt -> stmt_list
|
||||
|
||||
PyIfPart elif_part = if_stmt.getElifParts()[0];
|
||||
assertTrue(elif_part.isElif());
|
||||
if_cond = elif_part.getCondition();
|
||||
assertEquals(marks.get("<elif_cond>").getParent(), if_cond);
|
||||
|
||||
stmt_list = elif_part.getStatementList();
|
||||
assertNotNull(stmt_list);
|
||||
assertEquals(marks.get("<elif_stmt>").getParent().getParent(), stmt_list); // keyword -> stmt -> stmt_list
|
||||
|
||||
}
|
||||
|
||||
public void testWhile() throws Exception {
|
||||
Map<String, PsiElement> marks = loadTest();
|
||||
assertEquals(3, marks.size());
|
||||
|
||||
PsiElement elt = marks.get("<stmt>").getParent().getParent(); // keyword -> part -> stmt
|
||||
assertTrue(elt instanceof PyWhileStatement);
|
||||
PyWhileStatement while_stmt = (PyWhileStatement)elt;
|
||||
|
||||
PyWhilePart while_part = while_stmt.getWhilePart();
|
||||
|
||||
PyExpression cond = while_part.getCondition();
|
||||
assertEquals(marks.get("<cond>").getParent(), cond);
|
||||
|
||||
elt = marks.get("<else>").getParent(); // keyword -> part
|
||||
assertTrue(elt instanceof PyElsePart);
|
||||
assertEquals(while_stmt.getElsePart(), elt);
|
||||
}
|
||||
|
||||
public void testFor() throws Exception {
|
||||
Map<String, PsiElement> marks = loadTest();
|
||||
assertEquals(4, marks.size());
|
||||
|
||||
PsiElement elt = marks.get("<stmt>").getParent().getParent(); // keyword -> part -> stmt
|
||||
assertTrue(elt instanceof PyForStatement);
|
||||
PyForStatement stmt = (PyForStatement)elt;
|
||||
|
||||
PyForPart for_part = stmt.getForPart();
|
||||
|
||||
PyExpression target = for_part.getTarget();
|
||||
assertEquals(marks.get("<target>").getParent(), target); // ident -> expr
|
||||
|
||||
PyExpression source = for_part.getSource();
|
||||
assertEquals(marks.get("<source>").getParent(), source); // ident -> expr
|
||||
|
||||
elt = marks.get("<else>").getParent(); // keyword -> part
|
||||
assertTrue(elt instanceof PyElsePart);
|
||||
assertEquals(stmt.getElsePart(), elt);
|
||||
}
|
||||
|
||||
public void testTry() throws Exception {
|
||||
Map<String, PsiElement> marks = loadTest();
|
||||
assertEquals(6, marks.size());
|
||||
|
||||
PsiElement elt = marks.get("<stmt>").getParent().getParent(); // keyword -> part -> stmt
|
||||
assertTrue(elt instanceof PyTryExceptStatement);
|
||||
PyTryExceptStatement stmt = (PyTryExceptStatement)elt;
|
||||
|
||||
PyTryPart try_part = stmt.getTryPart();
|
||||
PyStatementList stmt_list = try_part.getStatementList();
|
||||
assertNotNull(stmt_list);
|
||||
assertEquals(marks.get("<body>").getParent().getParent(), stmt_list); // keyword -> stmt -> stmt_list
|
||||
|
||||
PyExceptPart exc_part = stmt.getExceptParts()[0];
|
||||
assertEquals("ArithmeticError", exc_part.getExceptClass().getText());
|
||||
assertEquals(marks.get("<ex1>").getParent(), exc_part);
|
||||
|
||||
exc_part = (PyExceptPart)marks.get("<ex2>").getParent(); // keyword -> part
|
||||
assertEquals(stmt.getExceptParts()[1], exc_part);
|
||||
assertNull(exc_part.getExceptClass());
|
||||
|
||||
elt = marks.get("<else>").getParent(); // keyword -> part
|
||||
assertTrue(elt instanceof PyElsePart);
|
||||
assertEquals(stmt.getElsePart(), elt);
|
||||
|
||||
elt = marks.get("<finally>").getParent(); // keyword -> part
|
||||
assertTrue(elt instanceof PyFinallyPart);
|
||||
assertEquals(stmt.getFinallyPart(), elt);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user