diff --git a/python/src/com/jetbrains/python/PyElementTypes.java b/python/src/com/jetbrains/python/PyElementTypes.java index 560aadff5d39..aa9f8be0814a 100644 --- a/python/src/com/jetbrains/python/PyElementTypes.java +++ b/python/src/com/jetbrains/python/PyElementTypes.java @@ -75,6 +75,8 @@ public interface PyElementTypes { PyElementType FLOAT_LITERAL_EXPRESSION = new PyElementType("FLOAT_LITERAL_EXPRESSION", PyNumericLiteralExpressionImpl.class); PyElementType IMAGINARY_LITERAL_EXPRESSION = new PyElementType("IMAGINARY_LITERAL_EXPRESSION", PyNumericLiteralExpressionImpl.class); PyElementType STRING_LITERAL_EXPRESSION = new PyElementType("STRING_LITERAL_EXPRESSION", PyStringLiteralExpressionImpl.class); + PyElementType NONE_LITERAL_EXPRESSION = new PyElementType("NONE_LITERAL_EXPRESSION", PyNoneLiteralExpressionImpl.class); + PyElementType BOOL_LITERAL_EXPRESSION = new PyElementType("BOOL_LITERAL_EXPRESSION", PyBoolLiteralExpressionImpl.class); PyElementType PARENTHESIZED_EXPRESSION = new PyElementType("PARENTHESIZED_EXPRESSION", PyParenthesizedExpressionImpl.class); PyElementType SUBSCRIPTION_EXPRESSION = new PyElementType("SUBSCRIPTION_EXPRESSION", PySubscriptionExpressionImpl.class); PyElementType SLICE_EXPRESSION = new PyElementType("SLICE_EXPRESSION", PySliceExpressionImpl.class); diff --git a/python/src/com/jetbrains/python/PyTokenTypes.java b/python/src/com/jetbrains/python/PyTokenTypes.java index ff436fcc583b..7fce0f9792b8 100644 --- a/python/src/com/jetbrains/python/PyTokenTypes.java +++ b/python/src/com/jetbrains/python/PyTokenTypes.java @@ -52,6 +52,11 @@ public class PyTokenTypes { public static final PyElementType WHILE_KEYWORD = new PyElementType("WHILE_KEYWORD"); public static final PyElementType YIELD_KEYWORD = new PyElementType("YIELD_KEYWORD"); + // new keywords in Python 3 + public static final PyElementType NONE_KEYWORD = new PyElementType("NONE_KEYWORD"); + public static final PyElementType TRUE_KEYWORD = new PyElementType("TRUE_KEYWORD"); + public static final PyElementType FALSE_KEYWORD = new PyElementType("FALSE_KEYWORD"); + public static final TokenSet KEYWORDS = TokenSet.create( AND_KEYWORD, AS_KEYWORD, ASSERT_KEYWORD, BREAK_KEYWORD, CLASS_KEYWORD, CONTINUE_KEYWORD, DEF_KEYWORD, DEL_KEYWORD, ELIF_KEYWORD, ELSE_KEYWORD, @@ -60,7 +65,8 @@ public class PyTokenTypes { GLOBAL_KEYWORD, IF_KEYWORD, IMPORT_KEYWORD, IN_KEYWORD, IS_KEYWORD, LAMBDA_KEYWORD, NOT_KEYWORD, OR_KEYWORD, PASS_KEYWORD, PRINT_KEYWORD, RAISE_KEYWORD, RETURN_KEYWORD, TRY_KEYWORD, WITH_KEYWORD, WHILE_KEYWORD, - YIELD_KEYWORD); + YIELD_KEYWORD, + NONE_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD); public static final PyElementType INTEGER_LITERAL = new PyElementType("INTEGER_LITERAL"); public static final PyElementType FLOAT_LITERAL = new PyElementType("FLOAT_LITERAL"); diff --git a/python/src/com/jetbrains/python/lexer/PythonHighlightingLexer.java b/python/src/com/jetbrains/python/lexer/PythonHighlightingLexer.java index 1e4bc2fc0226..65836fa7e3ef 100644 --- a/python/src/com/jetbrains/python/lexer/PythonHighlightingLexer.java +++ b/python/src/com/jetbrains/python/lexer/PythonHighlightingLexer.java @@ -25,6 +25,12 @@ public class PythonHighlightingLexer extends PythonLexer { final String tokenText = getTokenText(); if (tokenText.equals("print")) return PyTokenTypes.PRINT_KEYWORD; } + if (myLanguageLevel.isPy3K()) { + final String tokenText = getTokenText(); + if (tokenText.equals("None")) return PyTokenTypes.NONE_KEYWORD; + if (tokenText.equals("True")) return PyTokenTypes.TRUE_KEYWORD; + if (tokenText.equals("False")) return PyTokenTypes.FALSE_KEYWORD; + } return super.getTokenType(); } } diff --git a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java index 3d24cb42350b..5bd0b6b868f0 100644 --- a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java +++ b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java @@ -41,6 +41,14 @@ public class ExpressionParsing extends Parsing { buildTokenElement(PyElementTypes.IMAGINARY_LITERAL_EXPRESSION, builder); return true; } + else if (firstToken == PyTokenTypes.NONE_KEYWORD) { + buildTokenElement(PyElementTypes.NONE_LITERAL_EXPRESSION, builder); + return true; + } + else if (firstToken == PyTokenTypes.TRUE_KEYWORD || firstToken == PyTokenTypes.FALSE_KEYWORD) { + buildTokenElement(PyElementTypes.BOOL_LITERAL_EXPRESSION, builder); + return true; + } else if (firstToken == PyTokenTypes.STRING_LITERAL) { final PsiBuilder.Marker marker = builder.mark(); while (builder.getTokenType() == PyTokenTypes.STRING_LITERAL) { diff --git a/python/src/com/jetbrains/python/parsing/StatementParsing.java b/python/src/com/jetbrains/python/parsing/StatementParsing.java index 15bcac11b194..55657216ed3f 100644 --- a/python/src/com/jetbrains/python/parsing/StatementParsing.java +++ b/python/src/com/jetbrains/python/parsing/StatementParsing.java @@ -26,6 +26,9 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper { @NonNls protected static final String TOK_WITH = "with"; @NonNls protected static final String TOK_AS = "as"; @NonNls protected static final String TOK_PRINT = "print"; + @NonNls protected static final String TOK_NONE = "None"; + @NonNls protected static final String TOK_TRUE = "True"; + @NonNls protected static final String TOK_FALSE = "False"; protected enum Phase {NONE, FROM, FUTURE, IMPORT} // 'from __future__ import' phase private Phase myFutureImportPhase = Phase.NONE; @@ -745,6 +748,17 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper { isWordAtPosition(text, start, end, TOK_PRINT)) { return PyTokenTypes.PRINT_KEYWORD; } + else if (myContext.getLanguageLevel().isPy3K() && source == PyTokenTypes.IDENTIFIER) { + if (isWordAtPosition(text, start, end, TOK_NONE)) { + return PyTokenTypes.NONE_KEYWORD; + } + if (isWordAtPosition(text, start, end, TOK_TRUE)) { + return PyTokenTypes.TRUE_KEYWORD; + } + if (isWordAtPosition(text, start, end, TOK_FALSE)) { + return PyTokenTypes.FALSE_KEYWORD; + } + } return source; } diff --git a/python/src/com/jetbrains/python/psi/PyBoolLiteralExpression.java b/python/src/com/jetbrains/python/psi/PyBoolLiteralExpression.java new file mode 100644 index 000000000000..8b74cc9b860f --- /dev/null +++ b/python/src/com/jetbrains/python/psi/PyBoolLiteralExpression.java @@ -0,0 +1,7 @@ +package com.jetbrains.python.psi; + +/** + * @author yole + */ +public interface PyBoolLiteralExpression extends PyLiteralExpression { +} diff --git a/python/src/com/jetbrains/python/psi/PyNoneLiteralExpression.java b/python/src/com/jetbrains/python/psi/PyNoneLiteralExpression.java new file mode 100644 index 000000000000..21cb99ce50b7 --- /dev/null +++ b/python/src/com/jetbrains/python/psi/PyNoneLiteralExpression.java @@ -0,0 +1,7 @@ +package com.jetbrains.python.psi; + +/** + * @author yole + */ +public interface PyNoneLiteralExpression extends PyLiteralExpression { +} diff --git a/python/src/com/jetbrains/python/psi/impl/PyBoolLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBoolLiteralExpressionImpl.java new file mode 100644 index 000000000000..cbbc8ae73b84 --- /dev/null +++ b/python/src/com/jetbrains/python/psi/impl/PyBoolLiteralExpressionImpl.java @@ -0,0 +1,19 @@ +package com.jetbrains.python.psi.impl; + +import com.intellij.lang.ASTNode; +import com.jetbrains.python.psi.PyBoolLiteralExpression; +import com.jetbrains.python.psi.types.PyType; + +/** + * @author yole + */ +public class PyBoolLiteralExpressionImpl extends PyElementImpl implements PyBoolLiteralExpression { + public PyBoolLiteralExpressionImpl(ASTNode astNode) { + super(astNode); + } + + public PyType getType() { + // TODO + return null; + } +} diff --git a/python/src/com/jetbrains/python/psi/impl/PyNoneLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNoneLiteralExpressionImpl.java new file mode 100644 index 000000000000..75c0024ba5e9 --- /dev/null +++ b/python/src/com/jetbrains/python/psi/impl/PyNoneLiteralExpressionImpl.java @@ -0,0 +1,19 @@ +package com.jetbrains.python.psi.impl; + +import com.intellij.lang.ASTNode; +import com.jetbrains.python.psi.PyNoneLiteralExpression; +import com.jetbrains.python.psi.types.PyNoneType; +import com.jetbrains.python.psi.types.PyType; + +/** + * @author yole + */ +public class PyNoneLiteralExpressionImpl extends PyElementImpl implements PyNoneLiteralExpression { + public PyNoneLiteralExpressionImpl(ASTNode astNode) { + super(astNode); + } + + public PyType getType() { + return PyNoneType.INSTANCE; + } +} diff --git a/python/testData/psi/KeywordOnlyArgument.txt b/python/testData/psi/KeywordOnlyArgument.txt index 269aa839d26d..a4c0d45d9dd6 100644 --- a/python/testData/psi/KeywordOnlyArgument.txt +++ b/python/testData/psi/KeywordOnlyArgument.txt @@ -20,8 +20,8 @@ PyFile:KeywordOnlyArgument.py PyNamedParameter('key') PsiElement(Py:IDENTIFIER)('key') PsiElement(Py:EQ)('=') - PyReferenceExpression: None - PsiElement(Py:IDENTIFIER)('None') + PyNoneLiteralExpression + PsiElement(Py:NONE_KEYWORD)('None') PsiElement(Py:RPAR)(')') PsiElement(Py:COLON)(':') PsiWhiteSpace(' ') diff --git a/python/testData/psi/Py3KKeywords.py b/python/testData/psi/Py3KKeywords.py new file mode 100644 index 000000000000..dbc2d6f190a2 --- /dev/null +++ b/python/testData/psi/Py3KKeywords.py @@ -0,0 +1,3 @@ +None +True +False diff --git a/python/testData/psi/Py3KKeywords.txt b/python/testData/psi/Py3KKeywords.txt new file mode 100644 index 000000000000..a42b906ee21a --- /dev/null +++ b/python/testData/psi/Py3KKeywords.txt @@ -0,0 +1,12 @@ +PyFile:Py3KKeywords.py + PyExpressionStatement + PyNoneLiteralExpression + PsiElement(Py:NONE_KEYWORD)('None') + PsiWhiteSpace('\n') + PyExpressionStatement + PyBoolLiteralExpression + PsiElement(Py:TRUE_KEYWORD)('True') + PsiWhiteSpace('\n') + PyExpressionStatement + PyBoolLiteralExpression + PsiElement(Py:FALSE_KEYWORD)('False') \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PythonParsingTest.java b/python/testSrc/com/jetbrains/python/PythonParsingTest.java index 27cb7a9743e5..8cee56ce44c7 100644 --- a/python/testSrc/com/jetbrains/python/PythonParsingTest.java +++ b/python/testSrc/com/jetbrains/python/PythonParsingTest.java @@ -1,6 +1,7 @@ package com.jetbrains.python; import com.intellij.testFramework.ParsingTestCase; +import com.intellij.testFramework.TestDataPath; import com.jetbrains.python.fixtures.PyLightFixtureTestCase; import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher; @@ -8,6 +9,7 @@ import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher; /** * @author yole */ +@TestDataPath("$CONTENT_ROOT/../testData/psi/") public class PythonParsingTest extends ParsingTestCase { public PythonParsingTest() { super("", "py"); @@ -97,7 +99,7 @@ public class PythonParsingTest extends ParsingTestCase { } public void testWithStatement26() throws Exception { - doTest(LanguageLevel.PYTHON26); + doTest(LanguageLevel.PYTHON26); } public void testPrintAsFunction26() throws Exception { @@ -120,6 +122,10 @@ public class PythonParsingTest extends ParsingTestCase { doTest(LanguageLevel.PYTHON30); } + public void testPy3KKeywords() throws Exception { + doTest(LanguageLevel.PYTHON30); + } + public void doTest() throws Exception { doTest(LanguageLevel.PYTHON25); }