Merge branch 'python3.5'

This commit is contained in:
Andrey Vlasovskikh
2015-03-25 12:00:11 +03:00
25 changed files with 820 additions and 505 deletions
File diff suppressed because it is too large Load Diff
@@ -357,8 +357,23 @@ public class PyNames {
.put("__round__", new BuiltinDescription("(self, n=None)"))
.build();
public static ImmutableMap<String, BuiltinDescription> PY35_BUILTIN_METHODS = ImmutableMap.<String, BuiltinDescription>builder()
.putAll(PY3_BUILTIN_METHODS)
.put("__imatmul__", _self_other_descr)
.put("__matmul__", _self_other_descr)
.put("__rmatmul__", _self_other_descr)
.build();
public static ImmutableMap<String, BuiltinDescription> getBuiltinMethods(LanguageLevel level) {
return level.isPy3K() ? PY3_BUILTIN_METHODS : PY2_BUILTIN_METHODS;
if (level.isAtLeast(LanguageLevel.PYTHON35)) {
return PY35_BUILTIN_METHODS;
}
else if (level.isAtLeast(LanguageLevel.PYTHON30)) {
return PY3_BUILTIN_METHODS;
}
else {
return PY2_BUILTIN_METHODS;
}
}
// canonical names, not forced by interpreter
@@ -118,7 +118,7 @@ public class PyTokenTypes {
public static final PyElementType RBRACKET = new PyElementType("RBRACKET");// ]
public static final PyElementType LBRACE = new PyElementType("LBRACE");// {
public static final PyElementType RBRACE = new PyElementType("RBRACE");// }
public static final PyElementType AT = new PyElementType("AT");// @
public static final PyElementType AT = new PyElementType("AT", "__matmul__");// @
public static final PyElementType COMMA = new PyElementType("COMMA");// ,
public static final PyElementType COLON = new PyElementType("COLON");// :
public static final PyElementType DOT = new PyElementType("DOT");// .
@@ -128,6 +128,7 @@ public class PyTokenTypes {
public static final PyElementType PLUSEQ = new PyElementType("PLUSEQ");// +=
public static final PyElementType MINUSEQ = new PyElementType("MINUSEQ");// -=
public static final PyElementType MULTEQ = new PyElementType("MULTEQ");// *=
public static final PyElementType ATEQ = new PyElementType("ATEQ"); // @=
public static final PyElementType DIVEQ = new PyElementType("DIVEQ"); // /=
public static final PyElementType FLOORDIVEQ = new PyElementType("FLOORDIVEQ"); // //=
public static final PyElementType PERCEQ = new PyElementType("PERCEQ");// %=
@@ -139,10 +140,10 @@ public class PyTokenTypes {
public static final PyElementType EXPEQ = new PyElementType("EXPEQ");// **=
public static final TokenSet OPERATIONS = TokenSet.create(
PLUS, MINUS, MULT, EXP, DIV, FLOORDIV, PERC, LTLT, GTGT, AND, OR,
PLUS, MINUS, MULT, AT, EXP, DIV, FLOORDIV, PERC, LTLT, GTGT, AND, OR,
XOR, TILDE, LT, GT, LE, GE, EQEQ, NE, NE_OLD, AT, COLON, TICK, EQ,
PLUSEQ, MINUSEQ,
MULTEQ, DIVEQ, FLOORDIVEQ, PERCEQ, ANDEQ, OREQ, XOREQ, LTLTEQ, GTGTEQ,
MULTEQ, ATEQ, DIVEQ, FLOORDIVEQ, PERCEQ, ANDEQ, OREQ, XOREQ, LTLTEQ, GTGTEQ,
EXPEQ);
public static final TokenSet COMPARISON_OPERATIONS = TokenSet.create(
@@ -150,8 +151,8 @@ public class PyTokenTypes {
public static final TokenSet SHIFT_OPERATIONS = TokenSet.create(LTLT, GTGT);
public static final TokenSet ADDITIVE_OPERATIONS = TokenSet.create(PLUS, MINUS);
public static final TokenSet MULTIPLICATIVE_OPERATIONS = TokenSet.create(MULT, FLOORDIV, DIV, PERC);
public static final TokenSet MULTIPLICATIVE_OR_EXP = TokenSet.create(MULT, FLOORDIV, DIV, PERC, EXP);
public static final TokenSet MULTIPLICATIVE_OPERATIONS = TokenSet.create(MULT, AT, FLOORDIV, DIV, PERC);
public static final TokenSet MULTIPLICATIVE_OR_EXP = TokenSet.create(MULT, AT, FLOORDIV, DIV, PERC, EXP);
public static final TokenSet UNARY_OPERATIONS = TokenSet.create(PLUS, MINUS, TILDE);
public static final TokenSet BITWISE_OPERATIONS = TokenSet.create(AND, OR, XOR);
public static final TokenSet EQUALITY_OPERATIONS = TokenSet.create(EQEQ, NE, NE_OLD);
@@ -162,7 +163,7 @@ public class PyTokenTypes {
public static final TokenSet OPEN_BRACES = TokenSet.create(LBRACKET, LBRACE, LPAR);
public static final TokenSet CLOSE_BRACES = TokenSet.create(RBRACKET, RBRACE, RPAR);
public static final TokenSet AUG_ASSIGN_OPERATIONS = TokenSet.create(PLUSEQ, MINUSEQ, MULTEQ, DIVEQ,
public static final TokenSet AUG_ASSIGN_OPERATIONS = TokenSet.create(PLUSEQ, MINUSEQ, MULTEQ, ATEQ, DIVEQ,
PERCEQ, EXPEQ, GTGTEQ, LTLTEQ, ANDEQ, OREQ, XOREQ, FLOORDIVEQ);
public static final PyElementType BACKSLASH = new PyElementType("BACKSLASH");
@@ -32,10 +32,11 @@ public enum LanguageLevel {
PYTHON31(31, true, false, true, true),
PYTHON32(32, true, false, true, true),
PYTHON33(33, true, false, true, true),
PYTHON34(34, true, false, true, true);
PYTHON34(34, true, false, true, true),
PYTHON35(35, true, false, true, true);
private static LanguageLevel DEFAULT2 = PYTHON27;
private static LanguageLevel DEFAULT3 = PYTHON33;
private static LanguageLevel DEFAULT3 = PYTHON34;
public static LanguageLevel FORCE_LANGUAGE_LEVEL = null;
@@ -121,6 +122,9 @@ public enum LanguageLevel {
if (pythonVersion.startsWith("3.4")) {
return PYTHON34;
}
if (pythonVersion.startsWith("3.5")) {
return PYTHON35;
}
return DEFAULT3;
}
return getDefault();
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -26,4 +27,6 @@ public interface PyAugAssignmentStatement extends PyStatement {
PyExpression getTarget();
@Nullable
PyExpression getValue();
@Nullable
PsiElement getOperation();
}
@@ -127,7 +127,8 @@ public interface PyElementTypes {
PyTokenTypes.OR, PyTokenTypes.XOR, PyTokenTypes.AND, PyTokenTypes.LTLT, PyTokenTypes.GTGT,
PyTokenTypes.EQEQ, PyTokenTypes.GE, PyTokenTypes.LE, PyTokenTypes.NE, PyTokenTypes.NE_OLD,
PyTokenTypes.IN_KEYWORD, PyTokenTypes.IS_KEYWORD, PyTokenTypes.NOT_KEYWORD, PyTokenTypes.PLUS,
PyTokenTypes.MINUS, PyTokenTypes.MULT, PyTokenTypes.FLOORDIV, PyTokenTypes.DIV, PyTokenTypes.PERC, PyTokenTypes.EXP);
PyTokenTypes.MINUS, PyTokenTypes.MULT, PyTokenTypes.AT, PyTokenTypes.FLOORDIV, PyTokenTypes.DIV,
PyTokenTypes.PERC, PyTokenTypes.EXP);
TokenSet UNARY_OPS = TokenSet.create(PyTokenTypes.NOT_KEYWORD, PyTokenTypes.PLUS, PyTokenTypes.MINUS, PyTokenTypes.TILDE);
@@ -108,6 +108,7 @@ public class PythonFormattingModelBuilder implements FormattingModelBuilderEx, C
.between(FROM_KEYWORD, DOT).spaces(1)
.between(DOT, IMPORT_KEYWORD).spaces(1)
.around(DOT).spaces(0)
.aroundInside(AT, DECORATOR_CALL).none()
.before(SEMICOLON).spaceIf(commonSettings.SPACE_BEFORE_SEMICOLON)
.withinPairInside(LPAR, RPAR, ARGUMENT_LIST).spaceIf(commonSettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES)
.withinPairInside(LPAR, RPAR, PARAMETER_LIST).spaceIf(commonSettings.SPACE_WITHIN_METHOD_PARENTHESES)
@@ -160,6 +160,7 @@ return PyTokenTypes.DOCSTRING; }
"-=" { return PyTokenTypes.MINUSEQ; }
"**=" { return PyTokenTypes.EXPEQ; }
"*=" { return PyTokenTypes.MULTEQ; }
"@=" { return PyTokenTypes.ATEQ; }
"//=" { return PyTokenTypes.FLOORDIVEQ; }
"/=" { return PyTokenTypes.DIVEQ; }
"%=" { return PyTokenTypes.PERCEQ; }
@@ -453,7 +453,7 @@ public class PyReplaceExpressionUtil implements PyElementTypes {
else if (expr instanceof PyBinaryExpression) {
final IElementType opType = getOperationType(expr);
if (opType == EXP) priority = 3;
if (opType == MULT || opType == DIV || opType == PERC || opType == FLOORDIV) priority = 4;
if (opType == MULT || opType == AT || opType == DIV || opType == PERC || opType == FLOORDIV) priority = 4;
if (opType == PLUS || opType == MINUS) priority = 5;
if (opType == LTLT || opType == GTGT) priority = 6;
if (opType == AND) priority = 7;
@@ -50,7 +50,6 @@ import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyAugAssignmentStatementImpl;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.jetbrains.python.refactoring.PyDefUseUtil;
import com.jetbrains.python.refactoring.PyReplaceExpressionUtil;
@@ -315,8 +314,8 @@ public class PyInlineLocalHandler extends InlineActionHandler {
private static PyExpression prepareValue(@NotNull PyStatement def, @NotNull String localName, @NotNull Project project) {
final PyExpression value = getValue(def);
assert value != null;
if (def instanceof PyAugAssignmentStatementImpl) {
final PyAugAssignmentStatementImpl expression = (PyAugAssignmentStatementImpl)def;
if (def instanceof PyAugAssignmentStatement) {
final PyAugAssignmentStatement expression = (PyAugAssignmentStatement)def;
final PsiElement operation = expression.getOperation();
assert operation != null;
final String op = operation.getText().replace('=', ' ');
@@ -919,6 +919,7 @@ ihave
ilog
imagetext
imagnumber
imatmul
imode
impls
importfile
@@ -1242,6 +1243,7 @@ mapdict
mapstar
markedsectionclose
markobject
matmul
maxamount
maxbinsize
maxcache
@@ -1702,6 +1704,7 @@ ripemd
rlecoderengine
rledecoderengine
rlshift
rmatmul
rmcolorizer
rmenu
rmod
@@ -22,6 +22,7 @@ import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.PyNames;
@@ -50,10 +51,10 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
AVAILABLE_PREFIXES.put(LanguageLevel.PYTHON30, Sets.newHashSet("R", "B"));
AVAILABLE_PREFIXES.put(LanguageLevel.PYTHON31, Sets.newHashSet("R", "B", "BR"));
AVAILABLE_PREFIXES.put(LanguageLevel.PYTHON32, Sets.newHashSet("R", "B", "BR"));
AVAILABLE_PREFIXES.put(LanguageLevel.PYTHON33, Sets.newHashSet("R", "U", "B", "BR", "RB"));
AVAILABLE_PREFIXES.put(LanguageLevel.PYTHON34, Sets.newHashSet("R", "U", "B", "BR", "RB"));
}
private static final Set<String> DEFAULT_PREFIXES = Sets.newHashSet(Sets.newHashSet("R", "U", "B", "BR", "RB"));
public CompatibilityVisitor(List<LanguageLevel> versionsToProcess) {
myVersionsToProcess = versionsToProcess;
}
@@ -195,6 +196,22 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
}
commonRegisterProblem(message, " not support <>, use != instead.", len, node, new ReplaceNotEqOperatorQuickFix());
}
else if (node.isOperator("@")) {
checkMatrixMultiplicationOperator(node.getPsiOperator());
}
}
private void checkMatrixMultiplicationOperator(PsiElement node) {
boolean problem = false;
for (LanguageLevel level : myVersionsToProcess) {
if (level.isOlderThan(LanguageLevel.PYTHON35)) {
problem = true;
break;
}
}
if (problem) {
registerProblem(node, "Python versions < 3.5 do not support matrix multiplication operators");
}
}
@Override
@@ -254,7 +271,8 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
final LanguageLevel languageLevel = myVersionsToProcess.get(i);
if (prefix.isEmpty()) continue;
final Set<String> prefixes = AVAILABLE_PREFIXES.get(languageLevel);
final Set<String> prefixesForLanguageLevel = AVAILABLE_PREFIXES.get(languageLevel);
final Set<String> prefixes = prefixesForLanguageLevel != null ? prefixesForLanguageLevel : DEFAULT_PREFIXES;
if (!prefixes.contains(prefix))
len = appendLanguageLevel(message, len, languageLevel);
}
@@ -541,6 +559,18 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
}
}
@Override
public void visitPyAugAssignmentStatement(PyAugAssignmentStatement node) {
super.visitPyAugAssignmentStatement(node);
final PsiElement operation = node.getOperation();
if (operation != null) {
final IElementType operationType = operation.getNode().getElementType();
if (PyTokenTypes.ATEQ.equals(operationType)) {
checkMatrixMultiplicationOperator(operation);
}
}
}
private static class YieldVisitor extends PyElementVisitor {
private boolean _haveYield = false;
@@ -0,0 +1,2 @@
class C:
def __matmul__(self, other):
+2
View File
@@ -0,0 +1,2 @@
class C:
def __matmul<caret>
@@ -0,0 +1,2 @@
x <warning descr="Python versions < 3.5 do not support matrix multiplication operators">@</warning> y
x <warning descr="Python versions < 3.5 do not support matrix multiplication operators">@=</warning> y
+5
View File
@@ -0,0 +1,5 @@
x @ y
x @ y @ z
x @ y * z
x + y @ z
z @= x
+67
View File
@@ -0,0 +1,67 @@
PyFile:MatMul.py
PyExpressionStatement
PyBinaryExpression
PyReferenceExpression: x
PsiElement(Py:IDENTIFIER)('x')
PsiWhiteSpace(' ')
PsiElement(Py:AT)('@')
PsiWhiteSpace(' ')
PyReferenceExpression: y
PsiElement(Py:IDENTIFIER)('y')
PsiWhiteSpace('\n')
PyExpressionStatement
PyBinaryExpression
PyBinaryExpression
PyReferenceExpression: x
PsiElement(Py:IDENTIFIER)('x')
PsiWhiteSpace(' ')
PsiElement(Py:AT)('@')
PsiWhiteSpace(' ')
PyReferenceExpression: y
PsiElement(Py:IDENTIFIER)('y')
PsiWhiteSpace(' ')
PsiElement(Py:AT)('@')
PsiWhiteSpace(' ')
PyReferenceExpression: z
PsiElement(Py:IDENTIFIER)('z')
PsiWhiteSpace('\n')
PyExpressionStatement
PyBinaryExpression
PyBinaryExpression
PyReferenceExpression: x
PsiElement(Py:IDENTIFIER)('x')
PsiWhiteSpace(' ')
PsiElement(Py:AT)('@')
PsiWhiteSpace(' ')
PyReferenceExpression: y
PsiElement(Py:IDENTIFIER)('y')
PsiWhiteSpace(' ')
PsiElement(Py:MULT)('*')
PsiWhiteSpace(' ')
PyReferenceExpression: z
PsiElement(Py:IDENTIFIER)('z')
PsiWhiteSpace('\n')
PyExpressionStatement
PyBinaryExpression
PyReferenceExpression: x
PsiElement(Py:IDENTIFIER)('x')
PsiWhiteSpace(' ')
PsiElement(Py:PLUS)('+')
PsiWhiteSpace(' ')
PyBinaryExpression
PyReferenceExpression: y
PsiElement(Py:IDENTIFIER)('y')
PsiWhiteSpace(' ')
PsiElement(Py:AT)('@')
PsiWhiteSpace(' ')
PyReferenceExpression: z
PsiElement(Py:IDENTIFIER)('z')
PsiWhiteSpace('\n')
PyAugAssignmentStatement
PyReferenceExpression: z
PsiElement(Py:IDENTIFIER)('z')
PsiWhiteSpace(' ')
PsiElement(Py:ATEQ)('@=')
PsiWhiteSpace(' ')
PyReferenceExpression: x
PsiElement(Py:IDENTIFIER)('x')
@@ -0,0 +1,57 @@
(y @ z)[::-5]
(y @ z)[5]
(y @ z)(5)
(y @ z).foo
-(y @ z)
+(y @ z)
~(y @ z)
5 ** (y @ z)
(y @ z) ** 5
5 * y @ z
y @ z * 5
5 / (y @ z)
y @ z / 5
5 // (y @ z)
y @ z // 5
5 + y @ z
y @ z + 5
y @ z - 5
5 - y @ z
5 >> y @ z
y @ z << 5
5 & y @ z
y @ z & 5
5 ^ y @ z
y @ z ^ 5
5 | y @ z
y @ z | 5
() in y @ z
y @ z in ()
5 is y @ z
y @ z is 5
5 < y @ z
y @ z < 5
not y @ z
5 and y @ z
y @ z and 5
5 or y @ z
y @ z or 5
y @ z if y @ z else y @ z
+8
View File
@@ -0,0 +1,8 @@
class C:
def __matmul__(self, other):
return self
x = C()
x @ y
# <ref>
+8
View File
@@ -0,0 +1,8 @@
class C:
def __rmatmul__(self, other):
return self
x = C()
y @ x
# <ref>
@@ -141,4 +141,14 @@ public class Py3CompletionTest extends PyTestCase {
public void testNotImportedSubmodulesOfNamespacePackage() {
doMultiFileTest();
}
// PY-15390
public void testMatMul() {
runWithLanguageLevel(LanguageLevel.PYTHON35, new Runnable() {
@Override
public void run() {
doTest();
}
});
}
}
@@ -571,4 +571,14 @@ public class PyResolveTest extends PyResolveTestCase {
public void testResolveAttributesUsingOldStyleMROWhenUnresolvedAncestorsAndC3Fails() {
assertResolvesTo(PyFunction.class, "foo");
}
// PY-15390
public void testMatMul() {
assertResolvesTo(PyFunction.class, "__matmul__");
}
// PY-15390
public void testRMatMul() {
assertResolvesTo(PyFunction.class, "__rmatmul__");
}
}
@@ -468,6 +468,11 @@ public class PythonParsingTest extends ParsingTestCase {
doTest();
}
// PY-15390
public void testMatMul() {
doTest(LanguageLevel.PYTHON35);
}
public void doTest(LanguageLevel languageLevel) {
LanguageLevel prev = myLanguageLevel;
myLanguageLevel = languageLevel;
@@ -150,6 +150,11 @@ public class PyCompatibilityInspectionTest extends PyTestCase {
doTest();
}
// PY-15390
public void testMatMul() {
doTest(LanguageLevel.PYTHON35);
}
private void doTest(@NotNull LanguageLevel level) {
runWithLanguageLevel(level, new Runnable() {
@Override
@@ -145,6 +145,11 @@ public class PyInlineLocalTest extends PyTestCase {
checkOperatorPrecedence("x = 10 if True else 2", "conditional");
}
// PY-15390
public void testMatMulPrecedence() throws Exception {
checkOperatorPrecedence("x = y @ z", "matrixMultiplication");
}
private void checkOperatorPrecedence(@NotNull final String firstLine, @NotNull String resultPrefix) throws Exception {
myFixture.configureByFile("/refactoring/inlinelocal/operatorPrecedence/template.py");
WriteCommandAction.runWriteCommandAction(myFixture.getProject(), new Runnable() {