[python] extract python parser to a separate module

Merge-request: IJ-MR-116296
Merged-by: Vladimir Koshelev <Vladimir.Koshelev@jetbrains.com>

GitOrigin-RevId: e7559fb3215d757e6273543e4aa27d52df755e63
This commit is contained in:
Vladimir Koshelev
2023-10-09 11:56:10 +00:00
committed by intellij-monorepo-bot
parent 609391377b
commit 29f0eb6c77
76 changed files with 3494 additions and 572 deletions

View File

@@ -13,5 +13,6 @@
<orderEntry type="module" module-name="intellij.platform.util.ui" />
<orderEntry type="library" name="Guava" level="project" />
<orderEntry type="module" module-name="intellij.platform.analysis" />
<orderEntry type="module" module-name="intellij.python.parser" exported="" />
</component>
</module>

View File

@@ -49,13 +49,6 @@
dynamic="true"/>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<fileType name="Python"
language="Python"
extensions="py;pyw"
hashBangs="python"
implementationClass="com.jetbrains.python.PythonFileType"
fieldName="INSTANCE"/>
<iconMapper mappingFile="PythonPsiApiIconMappings.json"/>
<projectService serviceInterface="com.jetbrains.python.psi.types.TypeEvalContextCache"
serviceImplementation="com.jetbrains.python.psi.types.TypeEvalContextCacheImpl"/>
</extensions>

View File

@@ -1,679 +0,0 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python;
import com.google.common.collect.ImmutableMap;
import com.intellij.openapi.util.NlsSafe;
import com.jetbrains.python.psi.LanguageLevel;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.regex.Pattern;
@NonNls
public final class PyNames {
public static final String SITE_PACKAGES = "site-packages";
public static final String DIST_PACKAGES = "dist-packages";
/**
* int type
*/
public static final String TYPE_INT = "int";
public static final String TYPE_LONG = "long";
/**
* unicode string type (see {@link #TYPE_STRING_TYPES}
*/
public static final String TYPE_UNICODE = "unicode";
/**
* string type (see {@link #TYPE_STRING_TYPES}
*/
public static final String TYPE_STR = "str";
/**
* Any string type
*/
public static final List<String> TYPE_STRING_TYPES = List.of(TYPE_UNICODE, TYPE_STR);
/**
* date type
*/
public static final String TYPE_DATE = "datetime.date";
/**
* datetime type
*/
public static final String TYPE_DATE_TIME = "datetime.datetime";
/**
* time type
*/
public static final String TYPE_TIME = "datetime.time";
public static final String TYPE_BYTES = "bytes";
public static final String TYPE_BYTEARRAY = "bytearray";
public static final String TYPE_ENUM = "enum.Enum";
public static final String PYTHON_SDK_ID_NAME = "Python SDK";
public static final String VERBOSE_REG_EXP_LANGUAGE_ID = "PythonVerboseRegExp";
@NonNls public static final String PYTHON_MODULE_ID = "PYTHON_MODULE";
public static final String TESTCASE_SETUP_NAME = "setUp";
public static final String PY_DOCSTRING_ID = "Doctest";
public static final String END_WILDCARD = ".*";
private PyNames() {
}
public static final String INIT = "__init__";
public static final String DUNDER_DICT = "__dict__";
public static final String DOT_PY = ".py";
public static final String DOT_PYI = ".pyi";
public static final String INIT_DOT_PY = INIT + DOT_PY;
public static final String INIT_DOT_PYI = INIT + DOT_PYI;
public static final String SETUP_DOT_PY = "setup" + DOT_PY;
public static final String NEW = "__new__";
public static final String GETATTR = "__getattr__";
public static final String GETATTRIBUTE = "__getattribute__";
public static final String GET = "__get__";
public static final String __CLASS__ = "__class__";
public static final String DUNDER_METACLASS = "__metaclass__";
public static final @NlsSafe String METACLASS = "metaclass";
public static final String TYPE = "type";
public static final String SUPER = "super";
public static final String OBJECT = "object";
public static final String NONE = "None";
public static final String TRUE = "True";
public static final String FALSE = "False";
public static final String ELLIPSIS = "...";
public static final String FUNCTION = "function";
public static final String TYPES_FUNCTION_TYPE = "types.FunctionType";
public static final String TYPES_METHOD_TYPE = "types.UnboundMethodType";
public static final String FUTURE_MODULE = "__future__";
public static final String UNICODE_LITERALS = "unicode_literals";
public static final String CLASSMETHOD = "classmethod";
public static final String STATICMETHOD = "staticmethod";
public static final String OVERLOAD = "overload";
public static final String PROPERTY = "property";
public static final String SETTER = "setter";
public static final String DELETER = "deleter";
public static final String GETTER = "getter";
public static final String ALL = "__all__";
public static final String SLOTS = "__slots__";
public static final String DEBUG = "__debug__";
public static final String ISINSTANCE = "isinstance";
public static final String ASSERT_IS_INSTANCE = "assertIsInstance";
public static final String HAS_ATTR = "hasattr";
public static final String ISSUBCLASS = "issubclass";
public static final String DOC = "__doc__";
public static final String DOCFORMAT = "__docformat__";
public static final String DIRNAME = "dirname";
public static final String ABSPATH = "abspath";
public static final String NORMPATH = "normpath";
public static final String REALPATH = "realpath";
public static final String JOIN = "join";
public static final String REPLACE = "replace";
public static final String FILE = "__file__";
public static final String PARDIR = "pardir";
public static final String CURDIR = "curdir";
public static final String WARN = "warn";
public static final String DEPRECATION_WARNING = "DeprecationWarning";
public static final String PENDING_DEPRECATION_WARNING = "PendingDeprecationWarning";
public static final String CONTAINER = "Container";
public static final String HASHABLE = "Hashable";
public static final String ITERABLE = "Iterable";
public static final String ITERATOR = "Iterator";
public static final String SIZED = "Sized";
public static final String CALLABLE = "Callable";
public static final String SEQUENCE = "Sequence";
public static final String MAPPING = "Mapping";
public static final String MUTABLE_MAPPING = "MutableMapping";
public static final String ABC_SET = "Set";
public static final String ABC_MUTABLE_SET = "MutableSet";
public static final String AWAITABLE = "Awaitable";
public static final String ASYNC_ITERABLE = "AsyncIterable";
public static final String ABC_NUMBER = "Number";
public static final String ABC_COMPLEX = "Complex";
public static final String ABC_REAL = "Real";
public static final String ABC_RATIONAL = "Rational";
public static final String ABC_INTEGRAL = "Integral";
public static final String CONTAINS = "__contains__";
public static final String HASH = "__hash__";
public static final String ITER = "__iter__";
public static final String NEXT = "next";
public static final String DUNDER_NEXT = "__next__";
public static final String LEN = "__len__";
public static final String CALL = "__call__";
public static final String GETITEM = "__getitem__";
public static final String SETITEM = "__setitem__";
public static final String DELITEM = "__delitem__";
public static final String POS = "__pos__";
public static final String NEG = "__neg__";
public static final String DIV = "__div__";
public static final String TRUEDIV = "__truediv__";
public static final String AITER = "__aiter__";
public static final String ANEXT = "__anext__";
public static final String AENTER = "__aenter__";
public static final String AEXIT = "__aexit__";
public static final String DUNDER_AWAIT = "__await__";
public static final String SIZEOF = "__sizeof__";
public static final String INIT_SUBCLASS = "__init_subclass__";
public static final String COMPLEX = "__complex__";
public static final String FLOAT = "__float__";
public static final String INT = "__int__";
public static final String BYTES = "__bytes__";
public static final String ABS = "__abs__";
public static final String ROUND = "__round__";
public static final String CLASS_GETITEM = "__class_getitem__";
public static final String PREPARE = "__prepare__";
public static final String NAME = "__name__";
public static final String ENTER = "__enter__";
public static final String EXIT = "__exit__";
public static final String CALLABLE_BUILTIN = "callable";
public static final String NAMEDTUPLE = "namedtuple";
public static final String COLLECTIONS = "collections";
public static final String COLLECTIONS_NAMEDTUPLE_PY2 = COLLECTIONS + "." + NAMEDTUPLE;
public static final String COLLECTIONS_NAMEDTUPLE_PY3 = COLLECTIONS + "." + INIT + "." + NAMEDTUPLE;
public static final String FORMAT = "format";
public static final String ABSTRACTMETHOD = "abstractmethod";
public static final String ABSTRACTPROPERTY = "abstractproperty";
public static final String ABC_META_CLASS = "ABCMeta";
public static final String ABC = "abc.ABC";
public static final String ABC_META = "abc.ABCMeta";
public static final String TUPLE = "tuple";
public static final String SET = "set";
public static final String SLICE = "slice";
public static final String DICT = "dict";
public static final String KEYS = "keys";
public static final String APPEND = "append";
public static final String EXTEND = "extend";
public static final String UPDATE = "update";
public static final String CLEAR = "clear";
public static final String POP = "pop";
public static final String POPITEM = "popitem";
public static final String SETDEFAULT = "setdefault";
public static final String PASS = "pass";
public static final String TEST_CASE = "TestCase";
public static final String PYCACHE = "__pycache__";
public static final String NOT_IMPLEMENTED_ERROR = "NotImplementedError";
public static final @NlsSafe String UNKNOWN_TYPE = "Any";
public static final @NlsSafe String UNNAMED_ELEMENT = "<unnamed>";
public static final String UNDERSCORE = "_";
/**
* Contains all known predefined names of "__foo__" form.
*/
public static final Set<String> UNDERSCORED_ATTRIBUTES = Set.of(
"__all__",
"__annotations__",
"__author__",
"__bases__",
"__closure__",
"__code__",
"__defaults__",
"__dict__",
"__dir__",
"__doc__",
"__docformat__",
"__file__",
"__func__",
"__globals__",
"__kwdefaults__",
"__members__",
"__metaclass__",
"__mod__",
"__module__",
"__mro__",
"__name__",
"__path__",
"__qualname__",
"__self__",
"__slots__",
"__version__"
);
public static final Set<String> COMPARISON_OPERATORS = Set.of(
"__eq__",
"__ne__",
"__lt__",
"__le__",
"__gt__",
"__ge__",
"__cmp__",
"__contains__"
);
public static final Set<String> SUBSCRIPTION_OPERATORS = Set.of(
GETITEM,
SETITEM,
DELITEM
);
public static class BuiltinDescription {
private final String mySignature;
public BuiltinDescription(String signature) {
mySignature = signature;
}
public String getSignature() {
return mySignature;
}
// TODO: doc string, too
}
private static final BuiltinDescription _only_self_descr = new BuiltinDescription("(self)");
private static final BuiltinDescription _self_other_descr = new BuiltinDescription("(self, other)");
private static final BuiltinDescription _self_item_descr = new BuiltinDescription("(self, item)");
private static final BuiltinDescription _self_key_descr = new BuiltinDescription("(self, key)");
private static final BuiltinDescription _exit_descr = new BuiltinDescription("(self, exc_type, exc_val, exc_tb)");
@SuppressWarnings("JavacQuirks")
private static final Map<String, BuiltinDescription> BuiltinMethods = Map.ofEntries(
Map.entry(ABS, _only_self_descr),
Map.entry("__add__", _self_other_descr),
Map.entry("__and__", _self_other_descr),
//_BuiltinMethodsMap.entry("__all__", _only_self_descr);
//_BuiltinMethodsMap.entry("__author__", _only_self_descr);
//_BuiltinMethodsMap.entry("__bases__", _only_self_descr);
Map.entry("__call__", new BuiltinDescription("(self, *args, **kwargs)")),
Map.entry("__ceil__", _only_self_descr),
//_BuiltinMethodsMap.entry("__class__", _only_self_descr);
Map.entry("__cmp__", _self_other_descr),
Map.entry("__coerce__", _self_other_descr),
Map.entry(COMPLEX, _only_self_descr),
Map.entry("__contains__", _self_item_descr),
Map.entry("__copy__", _only_self_descr),
//_BuiltinMethodsMap.entry("__debug__", _only_self_descr);
Map.entry("__deepcopy__", new BuiltinDescription("(self, memodict={})")),
Map.entry("__del__", _only_self_descr),
Map.entry("__delete__", new BuiltinDescription("(self, instance)")),
Map.entry("__delattr__", _self_item_descr),
Map.entry("__delitem__", _self_key_descr),
Map.entry("__delslice__", new BuiltinDescription("(self, i, j)")),
//_BuiltinMethodsMap.entry("__dict__", _only_self_descr);
Map.entry("__divmod__", _self_other_descr),
//_BuiltinMethodsMap.entry("__doc__", _only_self_descr);
//_BuiltinMethodsMap.entry("__docformat__", _only_self_descr);
Map.entry("__enter__", _only_self_descr),
Map.entry("__exit__", _exit_descr),
Map.entry("__eq__", _self_other_descr),
//_BuiltinMethodsMap.entry("__file__", _only_self_descr);
Map.entry(FLOAT, _only_self_descr),
Map.entry("__floor__", _only_self_descr),
Map.entry("__floordiv__", _self_other_descr),
//_BuiltinMethodsMap.entry("__future__", _only_self_descr);
Map.entry("__ge__", _self_other_descr),
Map.entry("__get__", new BuiltinDescription("(self, instance, owner)")),
Map.entry("__getattr__", _self_item_descr),
Map.entry("__getattribute__", _self_item_descr),
Map.entry("__getinitargs__", _only_self_descr),
Map.entry("__getitem__", _self_item_descr),
Map.entry("__getnewargs__", _only_self_descr),
//_BuiltinMethodsMap.entry("__getslice__", new BuiltinDescription("(self, i, j)"));
Map.entry("__getstate__", _only_self_descr),
Map.entry("__gt__", _self_other_descr),
Map.entry("__hash__", _only_self_descr),
Map.entry("__hex__", _only_self_descr),
Map.entry("__iadd__", _self_other_descr),
Map.entry("__iand__", _self_other_descr),
Map.entry("__idiv__", _self_other_descr),
Map.entry("__ifloordiv__", _self_other_descr),
//_BuiltinMethodsMap.entry("__import__", _only_self_descr);
Map.entry("__ilshift__", _self_other_descr),
Map.entry("__imod__", _self_other_descr),
Map.entry("__imul__", _self_other_descr),
Map.entry("__index__", _only_self_descr),
Map.entry(INIT, _only_self_descr),
Map.entry(INT, _only_self_descr),
Map.entry("__invert__", _only_self_descr),
Map.entry("__ior__", _self_other_descr),
Map.entry("__ipow__", _self_other_descr),
Map.entry("__irshift__", _self_other_descr),
Map.entry("__isub__", _self_other_descr),
Map.entry("__iter__", _only_self_descr),
Map.entry("__itruediv__", _self_other_descr),
Map.entry("__ixor__", _self_other_descr),
Map.entry("__le__", _self_other_descr),
Map.entry("__len__", _only_self_descr),
Map.entry("__long__", _only_self_descr),
Map.entry("__lshift__", _self_other_descr),
Map.entry("__lt__", _self_other_descr),
//_BuiltinMethodsMap.entry("__members__", _only_self_descr);
//_BuiltinMethodsMap.entry("__metaclass__", _only_self_descr);
Map.entry("__missing__", _self_key_descr),
Map.entry("__mod__", _self_other_descr),
//_BuiltinMethodsMap.entry("__mro__", _only_self_descr);
Map.entry("__mul__", _self_other_descr),
//_BuiltinMethodsMap.entry("__name__", _only_self_descr);
Map.entry("__ne__", _self_other_descr),
Map.entry("__neg__", _only_self_descr),
Map.entry(NEW, new BuiltinDescription("(cls, *args, **kwargs)")),
Map.entry("__oct__", _only_self_descr),
Map.entry("__or__", _self_other_descr),
//_BuiltinMethodsMap.entry("__path__", _only_self_descr);
Map.entry("__pos__", _only_self_descr),
Map.entry("__pow__", new BuiltinDescription("(self, power, modulo=None)")),
Map.entry("__radd__", _self_other_descr),
Map.entry("__rand__", _self_other_descr),
Map.entry("__rdiv__", _self_other_descr),
Map.entry("__rdivmod__", _self_other_descr),
Map.entry("__reduce__", _only_self_descr),
Map.entry("__reduce_ex__", new BuiltinDescription("(self, protocol)")),
Map.entry("__repr__", _only_self_descr),
Map.entry("__reversed__", _only_self_descr),
Map.entry("__rfloordiv__", _self_other_descr),
Map.entry("__rlshift__", _self_other_descr),
Map.entry("__rmod__", _self_other_descr),
Map.entry("__rmul__", _self_other_descr),
Map.entry("__ror__", _self_other_descr),
Map.entry("__rpow__", _self_other_descr),
Map.entry("__rrshift__", _self_other_descr),
Map.entry("__rshift__", _self_other_descr),
Map.entry("__rsub__", _self_other_descr),
Map.entry("__rtruediv__", _self_other_descr),
Map.entry("__rxor__", _self_other_descr),
Map.entry("__set__", new BuiltinDescription("(self, instance, value)")),
Map.entry("__setattr__", new BuiltinDescription("(self, key, value)")),
Map.entry("__setitem__", new BuiltinDescription("(self, key, value)")),
Map.entry("__setslice__", new BuiltinDescription("(self, i, j, sequence)")),
Map.entry("__setstate__", new BuiltinDescription("(self, state)")),
Map.entry(SIZEOF, _only_self_descr),
//_BuiltinMethodsMap.entry("__self__", _only_self_descr);
//_BuiltinMethodsMap.entry("__slots__", _only_self_descr);
Map.entry("__str__", _only_self_descr),
Map.entry("__sub__", _self_other_descr),
Map.entry("__truediv__", _self_other_descr),
Map.entry("__trunc__", _only_self_descr),
Map.entry("__unicode__", _only_self_descr),
//_BuiltinMethodsMap.entry("__version__", _only_self_descr);
Map.entry("__xor__", _self_other_descr));
private static final Map<String, BuiltinDescription> PY2_BUILTIN_METHODS = concat(
BuiltinMethods,
Map.entry("__nonzero__", _only_self_descr),
Map.entry("__div__", _self_other_descr),
Map.entry(NEXT, _only_self_descr));
private static final Map<String, BuiltinDescription> PY3_BUILTIN_METHODS = concat(
BuiltinMethods,
Map.entry("__bool__", _only_self_descr),
Map.entry(BYTES, _only_self_descr),
Map.entry("__format__", new BuiltinDescription("(self, format_spec)")),
Map.entry("__instancecheck__", new BuiltinDescription("(self, instance)")),
Map.entry(PREPARE, new BuiltinDescription("(metacls, name, bases)")),
Map.entry(ROUND, new BuiltinDescription("(self, n=None)")),
Map.entry("__subclasscheck__", new BuiltinDescription("(self, subclass)")),
Map.entry(DUNDER_NEXT, _only_self_descr));
private static final Map<String, BuiltinDescription> PY35_BUILTIN_METHODS = concat(
PY3_BUILTIN_METHODS,
Map.entry("__imatmul__", _self_other_descr),
Map.entry("__matmul__", _self_other_descr),
Map.entry("__rmatmul__", _self_other_descr),
Map.entry(DUNDER_AWAIT, _only_self_descr),
Map.entry(AENTER, _only_self_descr),
Map.entry(AEXIT, _exit_descr),
Map.entry(AITER, _only_self_descr),
Map.entry(ANEXT, _only_self_descr));
/**
* @deprecated use {@link #getBuiltinMethods(LanguageLevel)} instead
*/
@Deprecated
public static final ImmutableMap<String, BuiltinDescription> PY36_BUILTIN_METHODS = ImmutableMap.<String, BuiltinDescription>builder().putAll(concat(
PY35_BUILTIN_METHODS,
Map.entry(INIT_SUBCLASS, new BuiltinDescription("(cls, **kwargs)")),
Map.entry("__set_name__", new BuiltinDescription("(self, owner, name)")),
Map.entry("__fspath__", _only_self_descr))).build();
private static final Map<String, BuiltinDescription> PY37_BUILTIN_METHODS = concat(
PY36_BUILTIN_METHODS,
Map.entry(CLASS_GETITEM, new BuiltinDescription("(cls, item)")),
Map.entry("__mro_entries__", new BuiltinDescription("(self, bases)")));
@NotNull
private static final Map<String, BuiltinDescription> PY37_MODULE_BUILTIN_METHODS = Map.of(
"__getattr__", new BuiltinDescription("(name)"),
"__dir__", new BuiltinDescription("()"));
@SafeVarargs
private static <K,V> Map<K,V> concat(Map<? extends K, ? extends V> map, Map.Entry<K,V>... additional) {
Map<K, V> r = new HashMap<>(map);
r.putAll(Map.ofEntries(additional));
return Map.copyOf(r);
}
@NotNull
public static Map<String, BuiltinDescription> getBuiltinMethods(@NotNull LanguageLevel level) {
if (level.isAtLeast(LanguageLevel.PYTHON37)) {
return PY37_BUILTIN_METHODS;
}
else if (level.isAtLeast(LanguageLevel.PYTHON36)) {
return PY36_BUILTIN_METHODS;
}
else if (level.isAtLeast(LanguageLevel.PYTHON35)) {
return PY35_BUILTIN_METHODS;
}
else if (!level.isPython2()) {
return PY3_BUILTIN_METHODS;
}
else {
return PY2_BUILTIN_METHODS;
}
}
public static @NotNull Map<String, BuiltinDescription> getModuleBuiltinMethods(@NotNull LanguageLevel level) {
if (level.isAtLeast(LanguageLevel.PYTHON37)) {
return PY37_MODULE_BUILTIN_METHODS;
}
return Collections.emptyMap();
}
// canonical names, not forced by interpreter
public static final String CANONICAL_SELF = "self";
public static final String CANONICAL_CLS = "cls";
public static final String BASESTRING = "basestring";
/*
Python keywords
*/
public static final String CLASS = "class";
public static final String DEF = "def";
public static final String IF = "if";
public static final String ELSE = "else";
public static final String ELIF = "elif";
public static final String TRY = "try";
public static final String EXCEPT = "except";
public static final String FINALLY = "finally";
public static final String WHILE = "while";
public static final String FOR = "for";
public static final String WITH = "with";
public static final String AS = "as";
public static final String ASSERT = "assert";
public static final String DEL = "del";
public static final String EXEC = "exec";
public static final String FROM = "from";
public static final String IMPORT = "import";
public static final String RAISE = "raise";
public static final String PRINT = "print";
public static final String BREAK = "break";
public static final String CONTINUE = "continue";
public static final String GLOBAL = "global";
public static final String RETURN = "return";
public static final String YIELD = "yield";
public static final String NONLOCAL = "nonlocal";
public static final String AND = "and";
public static final String OR = "or";
public static final String IS = "is";
public static final String IN = "in";
public static final String NOT = "not";
public static final String LAMBDA = "lambda";
public static final String ASYNC = "async";
public static final String AWAIT = "await";
public static final String MATCH = "match";
public static final String CASE = "case";
/**
* Contains keywords as of CPython 2.5.
*/
public static final Set<String> KEYWORDS = Set.of(
AND,
DEL,
FROM,
NOT,
WHILE,
AS,
ELIF,
GLOBAL,
OR,
WITH,
ASSERT,
ELSE,
IF,
PASS,
YIELD,
BREAK,
EXCEPT,
IMPORT,
PRINT,
CLASS,
EXEC,
IN,
RAISE,
CONTINUE,
FINALLY,
IS,
RETURN,
DEF,
FOR,
LAMBDA,
TRY
);
public static final Set<String> BUILTIN_INTERFACES = Set.of(
CALLABLE, HASHABLE, ITERABLE, ITERATOR, SIZED, CONTAINER, SEQUENCE, MAPPING, ABC_COMPLEX, ABC_REAL, ABC_RATIONAL, ABC_INTEGRAL,
ABC_NUMBER
);
/**
* TODO: dependency on language level.
*
* @param name what to check
* @return true iff the name is either a keyword or a reserved name, like None.
*/
public static boolean isReserved(@Nullable @NonNls String name) {
return name != null && KEYWORDS.contains(name) || NONE.equals(name);
}
// NOTE: includes unicode only good for py3k
public static final String IDENTIFIER_RE = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*";
private final static Pattern IDENTIFIER_PATTERN = Pattern.compile(IDENTIFIER_RE);
/**
* TODO: dependency on language level.
*
* @param name what to check
* @return true iff name is not reserved and is a well-formed identifier.
*/
public static boolean isIdentifier(@NotNull @NonNls String name) {
return !isReserved(name) && isIdentifierString(name);
}
public static boolean isIdentifierString(@NotNull @NonNls String name) {
return IDENTIFIER_PATTERN.matcher(name).matches();
}
public static boolean isRightOperatorName(@Nullable String name) {
if ("__rshift__".equals(name)) return false;
return name != null && (name.matches("__r[a-z]+__") || CONTAINS.equals(name));
}
public static boolean isRightOperatorName(@Nullable String referencedName, @Nullable String calleeName) {
if (isRightOperatorName(calleeName)) return true;
return referencedName != null && calleeName != null && calleeName.equals(leftToRightComparisonOperatorName(referencedName));
}
@Nullable
public static String leftToRightOperatorName(@Nullable String name) {
if (name == null) return null;
final String rightComparisonOperatorName = leftToRightComparisonOperatorName(name);
if (rightComparisonOperatorName != null) return rightComparisonOperatorName;
return name.replaceFirst("__([a-z]+)__", "__r$1__");
}
@Nullable
private static String leftToRightComparisonOperatorName(@NotNull String name) {
return switch (name) {
case "__lt__" -> "__gt__";
case "__gt__" -> "__lt__";
case "__ge__" -> "__le__";
case "__le__" -> "__ge__";
case "__eq__", "__ne__" -> name;
default -> null;
};
}
/**
* Available in Python 3 and Python 2 starting from 2.6.
* <p/>
* Attributes {@code __doc__}, {@code __dict__} and {@code __module__} should be inherited from object.
*/
public static final Set<String> FUNCTION_SPECIAL_ATTRIBUTES = Set.of(
"__defaults__",
"__globals__",
"__closure__",
"__code__",
"__name__"
);
public static final Set<String> LEGACY_FUNCTION_SPECIAL_ATTRIBUTES = Set.of(
"func_defaults",
"func_globals",
"func_closure",
"func_code",
"func_name",
"func_doc",
"func_dict"
);
public static final Set<String> PY3_ONLY_FUNCTION_SPECIAL_ATTRIBUTES = Set.of("__annotations__", "__kwdefaults__");
public static final Set<String> METHOD_SPECIAL_ATTRIBUTES = Set.of("__func__", "__self__", "__name__");
public static final Set<String> LEGACY_METHOD_SPECIAL_ATTRIBUTES = Set.of("im_func", "im_self", "im_class");
public static final String MRO = "mro";
}

View File

@@ -1,192 +0,0 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.jetbrains.python.psi.PyElementType;
public final class PyTokenTypes {
private PyTokenTypes() {
}
public static final PyElementType IDENTIFIER = new PyElementType("IDENTIFIER");
public static final PyElementType LINE_BREAK = new PyElementType("LINE_BREAK");
public static final PyElementType STATEMENT_BREAK = new PyElementType("STATEMENT_BREAK");
public static final PyElementType SPACE = new PyElementType("SPACE");
public static final PyElementType TAB = new PyElementType("TAB");
public static final PyElementType FORMFEED = new PyElementType("FORMFEED");
public static final IElementType BAD_CHARACTER = TokenType.BAD_CHARACTER;
public static final PyElementType INCONSISTENT_DEDENT = new PyElementType("INCONSISTENT_DEDENT");
public static final PyElementType END_OF_LINE_COMMENT = new PyElementType("END_OF_LINE_COMMENT");
public static final PyElementType AND_KEYWORD = new PyElementType("AND_KEYWORD");
public static final PyElementType AS_KEYWORD = new PyElementType("AS_KEYWORD");
public static final PyElementType ASSERT_KEYWORD = new PyElementType("ASSERT_KEYWORD");
public static final PyElementType BREAK_KEYWORD = new PyElementType("BREAK_KEYWORD");
public static final PyElementType CASE_KEYWORD = new PyElementType("CASE_KEYWORD");
public static final PyElementType CLASS_KEYWORD = new PyElementType("CLASS_KEYWORD");
public static final PyElementType CONTINUE_KEYWORD = new PyElementType("CONTINUE_KEYWORD");
public static final PyElementType DEF_KEYWORD = new PyElementType("DEF_KEYWORD");
public static final PyElementType DEL_KEYWORD = new PyElementType("DEL_KEYWORD");
public static final PyElementType ELIF_KEYWORD = new PyElementType("ELIF_KEYWORD");
public static final PyElementType ELSE_KEYWORD = new PyElementType("ELSE_KEYWORD");
public static final PyElementType EXCEPT_KEYWORD = new PyElementType("EXCEPT_KEYWORD");
public static final PyElementType EXEC_KEYWORD = new PyElementType("EXEC_KEYWORD");
public static final PyElementType FINALLY_KEYWORD = new PyElementType("FINALLY_KEYWORD");
public static final PyElementType FOR_KEYWORD = new PyElementType("FOR_KEYWORD");
public static final PyElementType FROM_KEYWORD = new PyElementType("FROM_KEYWORD");
public static final PyElementType GLOBAL_KEYWORD = new PyElementType("GLOBAL_KEYWORD");
public static final PyElementType IF_KEYWORD = new PyElementType("IF_KEYWORD");
public static final PyElementType IMPORT_KEYWORD = new PyElementType("IMPORT_KEYWORD");
public static final PyElementType IN_KEYWORD = new PyElementType("IN_KEYWORD", "__contains__");
public static final PyElementType IS_KEYWORD = new PyElementType("IS_KEYWORD");
public static final PyElementType LAMBDA_KEYWORD = new PyElementType("LAMBDA_KEYWORD");
public static final PyElementType MATCH_KEYWORD = new PyElementType("MATCH_KEYWORD");
public static final PyElementType TYPE_KEYWORD = new PyElementType("TYPE_KEYWORD");
public static final PyElementType NOT_KEYWORD = new PyElementType("NOT_KEYWORD");
public static final PyElementType OR_KEYWORD = new PyElementType("OR_KEYWORD");
public static final PyElementType PASS_KEYWORD = new PyElementType("PASS_KEYWORD");
public static final PyElementType PRINT_KEYWORD = new PyElementType("PRINT_KEYWORD");
public static final PyElementType RAISE_KEYWORD = new PyElementType("RAISE_KEYWORD");
public static final PyElementType RETURN_KEYWORD = new PyElementType("RETURN_KEYWORD");
public static final PyElementType TRY_KEYWORD = new PyElementType("TRY_KEYWORD");
public static final PyElementType WITH_KEYWORD = new PyElementType("WITH_KEYWORD");
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 PyElementType NONLOCAL_KEYWORD = new PyElementType("NONLOCAL_KEYWORD");
public static final PyElementType DEBUG_KEYWORD = new PyElementType("DEBUG_KEYWORD");
public static final PyElementType ASYNC_KEYWORD = new PyElementType("ASYNC_KEYWORD");
public static final PyElementType AWAIT_KEYWORD = new PyElementType("AWAIT_KEYWORD", "__await__");
public static final PyElementType INTEGER_LITERAL = new PyElementType("INTEGER_LITERAL");
public static final PyElementType FLOAT_LITERAL = new PyElementType("FLOAT_LITERAL");
public static final PyElementType IMAGINARY_LITERAL = new PyElementType("IMAGINARY_LITERAL");
public static final PyElementType SINGLE_QUOTED_STRING = new PyElementType("SINGLE_QUOTED_STRING");
public static final PyElementType TRIPLE_QUOTED_STRING = new PyElementType("TRIPLE_QUOTED_STRING");
public static final PyElementType SINGLE_QUOTED_UNICODE = new PyElementType("SINGLE_QUOTED_UNICODE");
public static final PyElementType TRIPLE_QUOTED_UNICODE = new PyElementType("TRIPLE_QUOTED_UNICODE");
public static final PyElementType DOCSTRING = new PyElementType("DOCSTRING");
public static final TokenSet UNICODE_NODES = TokenSet.create(TRIPLE_QUOTED_UNICODE, SINGLE_QUOTED_UNICODE);
public static final TokenSet TRIPLE_NODES = TokenSet.create(TRIPLE_QUOTED_UNICODE, TRIPLE_QUOTED_STRING);
public static final TokenSet STRING_NODES = TokenSet.orSet(UNICODE_NODES, TokenSet.create(SINGLE_QUOTED_STRING,
TRIPLE_QUOTED_STRING, DOCSTRING));
// Operators
public static final PyElementType PLUS = new PyElementType("PLUS", "__add__");// +
public static final PyElementType MINUS = new PyElementType("MINUS", "__sub__");// -
public static final PyElementType MULT = new PyElementType("MULT", "__mul__");// *
public static final PyElementType EXP = new PyElementType("EXP", "__pow__");// **
public static final PyElementType DIV = new PyElementType("DIV", "__div__"); // /
public static final PyElementType FLOORDIV = new PyElementType("FLOORDIV", "__floordiv__"); // //
public static final PyElementType PERC = new PyElementType("PERC", "__mod__");// %
public static final PyElementType LTLT = new PyElementType("LTLT", "__lshift__");// <<
public static final PyElementType GTGT = new PyElementType("GTGT", "__rshift__");// >>
public static final PyElementType AND = new PyElementType("AND", "__and__");// &
public static final PyElementType OR = new PyElementType("OR", "__or__");// |
public static final PyElementType XOR = new PyElementType("XOR", "__xor__");// ^
public static final PyElementType TILDE = new PyElementType("TILDE", "__invert__");// ~
public static final PyElementType LT = new PyElementType("LT", "__lt__");// <
public static final PyElementType GT = new PyElementType("GT", "__gt__");// >
public static final PyElementType LE = new PyElementType("LE", "__le__");// <=
public static final PyElementType GE = new PyElementType("GE", "__ge__");// >=
public static final PyElementType EQEQ = new PyElementType("EQEQ", "__eq__");// ==
public static final PyElementType NE = new PyElementType("NE", "__ne__");// !=
public static final PyElementType NE_OLD = new PyElementType("NE_OLD", "__ne__");// <>
// Delimiters
public static final PyElementType LPAR = new PyElementType("LPAR");// (
public static final PyElementType RPAR = new PyElementType("RPAR");// )
public static final PyElementType LBRACKET = new PyElementType("LBRACKET");// [
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", "__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");// .
public static final PyElementType TICK = new PyElementType("TICK");// `
public static final PyElementType EQ = new PyElementType("EQ");// =
public static final PyElementType SEMICOLON = new PyElementType("SEMICOLON");// ;
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");// %=
public static final PyElementType ANDEQ = new PyElementType("ANDEQ");// &=
public static final PyElementType OREQ = new PyElementType("OREQ");// |=
public static final PyElementType XOREQ = new PyElementType("XOREQ");// ^=
public static final PyElementType LTLTEQ = new PyElementType("LTLTEQ");// <<=
public static final PyElementType GTGTEQ = new PyElementType("GTGTEQ");// >>=
public static final PyElementType EXPEQ = new PyElementType("EXPEQ");// **=
public static final PyElementType RARROW = new PyElementType("RARROW");// ->
public static final PyElementType COLONEQ = new PyElementType("COLONEQ");// :=
public static final TokenSet OPERATIONS = TokenSet.create(
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, ATEQ, DIVEQ, FLOORDIVEQ, PERCEQ, ANDEQ, OREQ, XOREQ, LTLTEQ, GTGTEQ,
EXPEQ, COLONEQ);
public static final TokenSet COMPARISON_OPERATIONS = TokenSet.create(
LT, GT, EQEQ, GE, LE, NE, NE_OLD, IN_KEYWORD, IS_KEYWORD, NOT_KEYWORD);
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, AT, FLOORDIV, DIV, PERC);
public static final TokenSet STAR_OPERATORS = TokenSet.create(MULT, 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);
public static final TokenSet RELATIONAL_OPERATIONS = TokenSet.create(LT, GT, LE, GE);
public static final TokenSet END_OF_STATEMENT = TokenSet.create(STATEMENT_BREAK, SEMICOLON);
public static final TokenSet WHITESPACE = TokenSet.create(SPACE, TAB, FORMFEED);
public static final TokenSet WHITESPACE_OR_LINEBREAK = TokenSet.create(SPACE, TAB, FORMFEED, LINE_BREAK);
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 ALL_BRACES = TokenSet.orSet(OPEN_BRACES, CLOSE_BRACES);
public static final TokenSet NUMERIC_LITERALS = TokenSet.create(FLOAT_LITERAL, INTEGER_LITERAL, IMAGINARY_LITERAL);
public static final TokenSet BOOL_LITERALS = TokenSet.create(TRUE_KEYWORD, FALSE_KEYWORD);
public static final TokenSet SCALAR_LITERALS = TokenSet.orSet(BOOL_LITERALS, NUMERIC_LITERALS, TokenSet.create(NONE_KEYWORD));
public static final TokenSet EXPRESSION_KEYWORDS = TokenSet.create(TRUE_KEYWORD, FALSE_KEYWORD, NONE_KEYWORD);
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");
public static final PyElementType INDENT = new PyElementType("INDENT");
public static final PyElementType DEDENT = new PyElementType("DEDENT");
public static final PyElementType FSTRING_TEXT = new PyElementType("FSTRING_TEXT");
public static final PyElementType FSTRING_RAW_TEXT = new PyElementType("FSTRING_RAW_TEXT");
public static final PyElementType FSTRING_START = new PyElementType("FSTRING_START");
public static final PyElementType FSTRING_END = new PyElementType("FSTRING_END");
public static final PyElementType FSTRING_FRAGMENT_START = new PyElementType("FSTRING_FRAGMENT_START");
public static final PyElementType FSTRING_FRAGMENT_END = new PyElementType("FSTRING_FRAGMENT_END");
public static final PyElementType FSTRING_FRAGMENT_FORMAT_START = new PyElementType("FSTRING_FRAGMENT_FORMAT_START");
public static final PyElementType FSTRING_FRAGMENT_TYPE_CONVERSION = new PyElementType("FSTRING_FRAGMENT_TYPE_CONVERSION");
public static final TokenSet FSTRING_TOKENS = TokenSet.create(FSTRING_TEXT,
FSTRING_RAW_TEXT,
FSTRING_START,
FSTRING_END,
FSTRING_FRAGMENT_START,
FSTRING_FRAGMENT_END,
FSTRING_FRAGMENT_FORMAT_START,
FSTRING_FRAGMENT_TYPE_CONVERSION);
public static final TokenSet FSTRING_TEXT_TOKENS = TokenSet.create(FSTRING_TEXT, FSTRING_RAW_TEXT);
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
/**
* Contributes element types of various kinds specific for a particular Python dialect.
*
*/
public interface PythonDialectsTokenSetContributor {
ExtensionPointName<PythonDialectsTokenSetContributor> EP_NAME = ExtensionPointName.create("Pythonid.dialectsTokenSetContributor");
/**
* Returns element types that are subclasses of {@link com.jetbrains.python.psi.PyStatement}.
*/
@NotNull
TokenSet getStatementTokens();
/**
* Returns element types that are subclasses of {@link com.jetbrains.python.psi.PyExpression}.
*/
@NotNull
TokenSet getExpressionTokens();
/**
* Returns element types that are language keywords.
*/
@NotNull
TokenSet getKeywordTokens();
/**
* Returns element types that are subclasses of {@link com.jetbrains.python.psi.PyParameter}.
*/
@NotNull
TokenSet getParameterTokens();
/**
* Returns element types that are subclasses of {@link com.jetbrains.python.psi.PyFunction}.
*/
@NotNull
TokenSet getFunctionDeclarationTokens();
/**
* Returns element types that can be used as unbalanced braces recovery tokens in the lexer.
*/
@NotNull
TokenSet getUnbalancedBracesRecoveryTokens();
/**
* Returns element types that are subclasses of {@link com.jetbrains.python.psi.PyReferenceExpression}.
*/
@NotNull
TokenSet getReferenceExpressionTokens();
}

View File

@@ -1,144 +0,0 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.util.text.CharSequenceReader;
import icons.PythonPsiApiIcons;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PythonFileType extends LanguageFileType {
private static final Pattern ENCODING_PATTERN = Pattern.compile("coding[:=]\\s*([-\\w.]+)");
public static final int MAX_CHARSET_ENCODING_LINE = 2;
public static final PythonFileType INSTANCE = new PythonFileType();
private PythonFileType() {
this(PythonLanguage.INSTANCE);
}
protected PythonFileType(Language language) {
super(language);
}
@Override
@NotNull
@NonNls
public String getName() {
return "Python";
}
@Override
@NotNull
@NlsSafe
public String getDescription() {
return "Python";
}
@Override
@NotNull
public String getDefaultExtension() {
return "py";
}
@Override
public Icon getIcon() {
return PythonPsiApiIcons.PythonFile;
}
@Override
public String getCharset(@NotNull VirtualFile file, byte @NotNull [] content) {
if (CharsetToolkit.hasUTF8Bom(content)) {
return CharsetToolkit.UTF8;
}
ByteBuffer bytes = ByteBuffer.wrap(content, 0, Math.min(256, content.length));
String decoded = StandardCharsets.UTF_8.decode(bytes).toString();
return getCharsetFromEncodingDeclaration(StringUtil.convertLineSeparators(decoded));
}
@Override
public Charset extractCharsetFromFileContent(@Nullable Project project, @Nullable VirtualFile file, @NotNull CharSequence content) {
final String charsetName = getCharsetFromEncodingDeclaration(content);
if (charsetName == null) {
return null;
}
try {
return Charset.forName(charsetName);
}
catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
return null;
}
}
@Nullable
public static String getCharsetFromEncodingDeclaration(@NotNull PsiFile file) {
final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
final String content;
if (document != null && document.getLineCount() > MAX_CHARSET_ENCODING_LINE) {
final int offset = document.getLineEndOffset(MAX_CHARSET_ENCODING_LINE);
content = document.getText(TextRange.create(0, offset));
}
else {
content = file.getText();
}
return getCharsetFromEncodingDeclaration(content);
}
@Nullable
private static String getCharsetFromEncodingDeclaration(@Nullable CharSequence content) {
if (content == null || content.length() == 0) {
return null;
}
try (BufferedReader reader = new BufferedReader(new CharSequenceReader(content))) {
for (int i = 0; i < MAX_CHARSET_ENCODING_LINE; i++) {
final String line = reader.readLine();
if (line == null) {
return null;
}
final Matcher matcher = ENCODING_PATTERN.matcher(line);
if (matcher.find()) {
final String charset = matcher.group(1);
return normalizeCharset(charset);
}
}
}
catch (IOException ignored) {
}
return null;
}
@Nullable
private static String normalizeCharset(String charset) {
if (charset == null) {
return null;
}
charset = StringUtil.toLowerCase(charset);
if ("latin-1".equals(charset)) {
return "iso-8859-1";
}
return charset;
}
}

View File

@@ -1,23 +0,0 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python;
import com.intellij.lang.Language;
public class PythonLanguage extends Language {
public static final PythonLanguage INSTANCE = new PythonLanguage();
public static PythonLanguage getInstance() {
return INSTANCE;
}
protected PythonLanguage() {
super("Python");
}
@Override
public boolean isCaseSensitive() {
return true; // http://jetbrains-feed.appspot.com/message/372001
}
}

View File

@@ -1,75 +0,0 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.psi;
import org.jetbrains.annotations.NotNull;
/**
* Lists interesting features importable from __future__.
* {@code .toString()} returns the Python name of the feature.
* <br/>
*/
public enum FutureFeature {
DIVISION("division", LanguageLevel.PYTHON24, LanguageLevel.PYTHON30), // actually since 2.2
ABSOLUTE_IMPORT("absolute_import", LanguageLevel.PYTHON25, LanguageLevel.PYTHON30),
PRINT_FUNCTION("print_function", LanguageLevel.PYTHON26, LanguageLevel.PYTHON30),
UNICODE_LITERALS("unicode_literals", LanguageLevel.PYTHON26, LanguageLevel.PYTHON30),
ANNOTATIONS("annotations", LanguageLevel.PYTHON37, LanguageLevel.PYTHON312)
// NOTE: only add new features to the end unless you want to break existing stubs that rely on ordinal
;
@NotNull
private final String myName;
@NotNull
private final LanguageLevel myOptionalVersion;
@NotNull
private final LanguageLevel myRequiredVersion;
/**
* @param name what is imported from __future__
* @param proposed version in which the feature has become importable
* @param included version in which the feature is included by default
*/
FutureFeature(@NotNull String name, @NotNull LanguageLevel proposed, @NotNull LanguageLevel included) {
myName = name;
myOptionalVersion = proposed;
myRequiredVersion = included;
}
/**
* @return the Python importable name of the feature.
*/
@Override
public String toString() {
return myName;
}
/**
* @return true iff the feature can either be imported from __future__ at given level, or is already built-in.
*/
public boolean availableAt(@NotNull LanguageLevel level) {
return level.isAtLeast(myOptionalVersion);
}
/**
* @return true iff the feature is already present (required) at given level, and there's no need to import it.
*/
public boolean requiredAt(@NotNull LanguageLevel level) {
return level.isAtLeast(myRequiredVersion);
}
}

View File

@@ -1,210 +0,0 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python.psi;
import com.intellij.psi.PsiElement;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;
public enum LanguageLevel {
/**
* @apiNote This level is not supported since 2018.1.
*/
PYTHON24(204),
/**
* @apiNote This level is not supported since 2018.1.
*/
PYTHON25(205),
/**
* @apiNote This level is not supported since 2019.1.
*/
PYTHON26(206),
PYTHON27(207),
/**
* @apiNote This level is not supported since 2018.1.
* Use it only to distinguish Python 2 and Python 3.
* Consider using {@link LanguageLevel#isPython2()}.
* Replace {@code level.isOlderThan(PYTHON30)} with {@code level.isPython2()}
* and {@code level.isAtLeast(PYTHON30)} with {@code !level.isPython2()}.
*/
PYTHON30(300),
/**
* @apiNote This level is not supported since 2018.1.
*/
PYTHON31(301),
/**
* @apiNote This level is not supported since 2018.1.
*/
PYTHON32(302),
/**
* @apiNote This level is not supported since 2018.1.
*/
PYTHON33(303),
/**
* @apiNote This level is not supported since 2019.1.
*/
PYTHON34(304),
/**
* @apiNote This level is not supported since 2020.3.
*/
PYTHON35(305),
PYTHON36(306),
PYTHON37(307),
PYTHON38(308),
PYTHON39(309),
PYTHON310(310),
PYTHON311(311),
PYTHON312(312);
public static final Comparator<LanguageLevel> VERSION_COMPARATOR = (first, second) -> {
return first == second ? 0 : first.isOlderThan(second) ? -1 : 1;
};
/**
* This value is mostly bound to the compatibility of our debugger and helpers.
* You're free to gradually drop support of versions not mentioned here if they present too much hassle to maintain.
*/
public static final List<LanguageLevel> SUPPORTED_LEVELS =
Stream
.of(values())
.filter(v -> v.isAtLeast(PYTHON36) || v == PYTHON27)
.toList();
private static final LanguageLevel DEFAULT2 = PYTHON27;
private static final LanguageLevel DEFAULT3 = PYTHON310;
@ApiStatus.Internal
public static LanguageLevel FORCE_LANGUAGE_LEVEL = null;
@NotNull
public static LanguageLevel getDefault() {
return getLatest();
}
private final int myVersion;
LanguageLevel(int version) {
myVersion = version;
}
public int getMajorVersion() {
return myVersion / 100;
}
public int getMinorVersion() {
return myVersion % 100;
}
public boolean hasPrintStatement() {
return isPython2();
}
public boolean isPython2() {
return getMajorVersion() == 2;
}
public boolean isPy3K() {
return getMajorVersion() == 3;
}
public boolean isOlderThan(@NotNull LanguageLevel other) {
return myVersion < other.myVersion;
}
public boolean isAtLeast(@NotNull LanguageLevel other) {
return myVersion >= other.myVersion;
}
@Nullable
@Contract("null->null;!null->!null")
public static LanguageLevel fromPythonVersion(@Nullable String pythonVersion) {
if (pythonVersion == null) return null;
if (pythonVersion.startsWith("2")) {
if (pythonVersion.startsWith("2.4")) {
return PYTHON24;
}
if (pythonVersion.startsWith("2.5")) {
return PYTHON25;
}
if (pythonVersion.startsWith("2.6")) {
return PYTHON26;
}
if (pythonVersion.startsWith("2.7")) {
return PYTHON27;
}
return DEFAULT2;
}
if (pythonVersion.startsWith("3")) {
if (pythonVersion.startsWith("3.0")) {
return PYTHON30;
}
if (pythonVersion.startsWith("3.1.") || pythonVersion.equals("3.1")) {
return PYTHON31;
}
if (pythonVersion.startsWith("3.2")) {
return PYTHON32;
}
if (pythonVersion.startsWith("3.3")) {
return PYTHON33;
}
if (pythonVersion.startsWith("3.4")) {
return PYTHON34;
}
if (pythonVersion.startsWith("3.5")) {
return PYTHON35;
}
if (pythonVersion.startsWith("3.6")) {
return PYTHON36;
}
if (pythonVersion.startsWith("3.7")) {
return PYTHON37;
}
if (pythonVersion.startsWith("3.8")) {
return PYTHON38;
}
if (pythonVersion.startsWith("3.9")) {
return PYTHON39;
}
if (pythonVersion.startsWith("3.10")) {
return PYTHON310;
}
if (pythonVersion.startsWith("3.11")) {
return PYTHON311;
}
if (pythonVersion.startsWith("3.12")) {
return PYTHON312;
}
return DEFAULT3;
}
return getDefault();
}
@NotNull
public String toPythonVersion() {
return getMajorVersion() + "." + getMinorVersion();
}
@NotNull
public static LanguageLevel forElement(@NotNull PsiElement element) {
return PyPsiFacade.getInstance(element.getProject()).getLanguageLevel(element);
}
@NotNull
public static LanguageLevel getLatest() {
return ArrayUtil.getLastElement(values());
}
@Override
public String toString() {
return toPythonVersion();
}
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.jetbrains.python.PythonFileType;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
public class PyElementType extends IElementType {
@NotNull private final Function<? super ASTNode, ? extends PsiElement> myPsiCreator;
private final String mySpecialMethodName;
public PyElementType(@NotNull @NonNls String debugName) {
super(debugName, PythonFileType.INSTANCE.getLanguage());
myPsiCreator = node -> { throw new IllegalStateException("Cannot create an element for " + node.getElementType() + " without element class");};
mySpecialMethodName = null;
}
public PyElementType(@NotNull @NonNls String debugName, @NotNull Function<? super ASTNode, ? extends PsiElement> creator) {
super(debugName, PythonFileType.INSTANCE.getLanguage());
myPsiCreator = creator;
mySpecialMethodName = null;
}
public PyElementType(@NotNull @NonNls String debugName, @NotNull @NonNls String specialMethodName) {
super(debugName, PythonFileType.INSTANCE.getLanguage());
myPsiCreator = node -> { throw new IllegalStateException("Cannot create an element for " + node.getElementType() + " without element class");};
mySpecialMethodName = specialMethodName;
}
@NotNull
public PsiElement createElement(@NotNull ASTNode node) {
return myPsiCreator.apply(node);
}
/**
* @return name of special method for operation marked by this token; e.g. "__add__" for "+".
*/
@Nullable
public String getSpecialMethodName() {
return mySpecialMethodName;
}
@Override
public String toString() {
return "Py:" + super.toString();
}
}

View File

@@ -1,116 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.psi;
import com.google.common.collect.ImmutableList;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PyStringLiteralCoreUtil {
/**
* Valid string prefix characters (lowercased) as defined in Python lexer.
*/
public static final String PREFIX_CHARACTERS = "ubcrf";
/**
* Maximum length of a string prefix as defined in Python lexer.
*/
public static final int MAX_PREFIX_LENGTH = 3;
private static final ImmutableList<String> QUOTES = ImmutableList.of("'''", "\"\"\"", "'", "\"");
protected PyStringLiteralCoreUtil() {
}
/**
* Returns a pair where the first element is the prefix combined with the opening quote and the second is the closing quote.
* <p>
* If the given string literal is not properly quoted, e.g. the closing quote has fewer quotes as opposed to the
* opening one, or it's missing altogether this method returns null.
* <p>
* Examples:
* <pre>
* ur"foo" -> ("ur, ")
* ur'bar -> null
* """baz""" -> (""", """)
* '''quux' -> null
* </pre>
*/
@Nullable
public static Pair<String, String> getQuotes(@NotNull String text) {
final String prefix = getPrefix(text);
final String mainText = text.substring(prefix.length());
for (String quote : QUOTES) {
final Pair<String, String> quotes = getQuotes(mainText, prefix, quote);
if (quotes != null) {
return quotes;
}
}
return null;
}
/**
* Finds the end offset of the string prefix starting from {@code startOffset} in the given char sequence.
* String prefix may contain only up to {@link #MAX_PREFIX_LENGTH} characters from {@link #PREFIX_CHARACTERS}
* (case insensitively).
*
* @return end offset of found string prefix
*/
public static int getPrefixEndOffset(@NotNull CharSequence text, int startOffset) {
int offset;
for (offset = startOffset; offset < Math.min(startOffset + MAX_PREFIX_LENGTH, text.length()); offset++) {
if (PREFIX_CHARACTERS.indexOf(Character.toLowerCase(text.charAt(offset))) < 0) {
break;
}
}
return offset;
}
@NotNull
public static String getPrefix(@NotNull CharSequence text) {
return getPrefix(text, 0);
}
/**
* Extracts string prefix from the given char sequence using {@link #getPrefixEndOffset(CharSequence, int)}.
*
* @return extracted string prefix
* @see #getPrefixEndOffset(CharSequence, int)
*/
@NotNull
public static String getPrefix(@NotNull CharSequence text, int startOffset) {
return text.subSequence(startOffset, getPrefixEndOffset(text, startOffset)).toString();
}
@Nullable
private static Pair<String, String> getQuotes(@NotNull String text, @NotNull String prefix, @NotNull String quote) {
final int length = text.length();
final int n = quote.length();
if (length >= 2 * n && text.startsWith(quote) && text.endsWith(quote)) {
return Pair.create(prefix + text.substring(0, n), text.substring(length - n));
}
return null;
}
public static String stripQuotesAroundValue(String text) {
Pair<String, String> quotes = getQuotes(text);
if (quotes == null) {
return text;
}
return text.substring(quotes.first.length(), text.length() - quotes.second.length());
}
/**
* Handles unicode and raw strings
*
* @return false if no quotes found, true otherwise
* sdfs -> false
* ur'x' -> true
* "string" -> true
*/
public static boolean isQuoted(@Nullable String text) {
return text != null && getQuotes(text) != null;
}
}

View File

@@ -6,6 +6,7 @@ import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -721,6 +722,29 @@ public final class PyPsiUtils {
}
}
@Nullable
public static String getStringValue(@Nullable PsiElement o) {
if (o == null) {
return null;
}
if (o instanceof PyStringLiteralExpression literalExpression) {
return literalExpression.getStringValue();
}
else {
return o.getText();
}
}
public static TextRange getStringValueTextRange(PsiElement element) {
if (element instanceof PyStringLiteralExpression) {
final List<TextRange> ranges = ((PyStringLiteralExpression)element).getStringValueTextRanges();
return ranges.get(0);
}
else {
return new TextRange(0, element.getTextLength());
}
}
@Nullable
public static PsiComment findSameLineComment(@NotNull PsiElement elem) {
// If `elem` is a compound multi-line element, stick to its first line nonetheless