IJ-CR-6485 IDEA-263365 - fix VfsUtilCore.pathEqualsTo for WSL paths
[idea/community.git] / python / python-psi-api / src / com / jetbrains / python / psi / LanguageLevel.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.jetbrains.python.psi;
17
18 import com.google.common.collect.ImmutableList;
19 import com.intellij.psi.PsiElement;
20 import com.intellij.util.ArrayUtil;
21 import org.jetbrains.annotations.ApiStatus;
22 import org.jetbrains.annotations.Contract;
23 import org.jetbrains.annotations.NotNull;
24 import org.jetbrains.annotations.Nullable;
25
26 import java.util.List;
27 import java.util.stream.Collectors;
28 import java.util.stream.Stream;
29
30 /**
31  * @author yole
32  */
33 public enum LanguageLevel {
34
35   /**
36    * @apiNote This level is not supported since 2018.1.
37    */
38   PYTHON24(204),
39   /**
40    * @apiNote This level is not supported since 2018.1.
41    */
42   PYTHON25(205),
43   /**
44    * @apiNote This level is not supported since 2019.1.
45    */
46   PYTHON26(206),
47   PYTHON27(207),
48   /**
49    * @apiNote This level is not supported since 2018.1.
50    * Use it only to distinguish Python 2 and Python 3.
51    * Consider using {@link LanguageLevel#isPython2()}.
52    * Replace {@code level.isOlderThan(PYTHON30)} with {@code level.isPython2()}
53    * and {@code level.isAtLeast(PYTHON30)} with {@code !level.isPython2()}.
54    */
55   PYTHON30(300),
56   /**
57    * @apiNote This level is not supported since 2018.1.
58    */
59   PYTHON31(301),
60   /**
61    * @apiNote This level is not supported since 2018.1.
62    */
63   PYTHON32(302),
64   /**
65    * @apiNote This level is not supported since 2018.1.
66    */
67   PYTHON33(303),
68   /**
69    * @apiNote This level is not supported since 2019.1.
70    */
71   PYTHON34(304),
72   /**
73    * @apiNote This level is not supported since 2020.3.
74    */
75   PYTHON35(305),
76   PYTHON36(306),
77   PYTHON37(307),
78   PYTHON38(308),
79   PYTHON39(309),
80   PYTHON310(310);
81
82   /**
83    * This value is mostly bound to the compatibility of our debugger and helpers.
84    * You're free to gradually drop support of versions not mentioned here if they present too much hassle to maintain.
85    */
86   public static final List<LanguageLevel> SUPPORTED_LEVELS =
87     ImmutableList.copyOf(
88       Stream
89         .of(values())
90         .filter(v -> v.isAtLeast(PYTHON36) || v == PYTHON27)
91         .collect(Collectors.toList())
92     );
93
94   private static final LanguageLevel DEFAULT2 = PYTHON27;
95   private static final LanguageLevel DEFAULT3 = PYTHON310;
96
97   @ApiStatus.Internal
98   public static LanguageLevel FORCE_LANGUAGE_LEVEL = null;
99
100   @NotNull
101   public static LanguageLevel getDefault() {
102     return getLatest();
103   }
104
105   private final int myVersion;
106
107   LanguageLevel(int version) {
108     myVersion = version;
109   }
110
111   public int getMajorVersion() {
112     return myVersion / 100;
113   }
114
115   public int getMinorVersion() {
116     return myVersion % 100;
117   }
118
119   public boolean hasPrintStatement() {
120     return isPython2();
121   }
122
123   public boolean isPython2() {
124     return getMajorVersion() == 2;
125   }
126
127   public boolean isPy3K() {
128     return getMajorVersion() == 3;
129   }
130
131   public boolean isOlderThan(@NotNull LanguageLevel other) {
132     return myVersion < other.myVersion;
133   }
134
135   public boolean isAtLeast(@NotNull LanguageLevel other) {
136     return myVersion >= other.myVersion;
137   }
138
139   @Nullable
140   @Contract("null->null;!null->!null")
141   public static LanguageLevel fromPythonVersion(@Nullable String pythonVersion) {
142     if (pythonVersion == null) return null;
143
144     if (pythonVersion.startsWith("2")) {
145       if (pythonVersion.startsWith("2.4")) {
146         return PYTHON24;
147       }
148       if (pythonVersion.startsWith("2.5")) {
149         return PYTHON25;
150       }
151       if (pythonVersion.startsWith("2.6")) {
152         return PYTHON26;
153       }
154       if (pythonVersion.startsWith("2.7")) {
155         return PYTHON27;
156       }
157       return DEFAULT2;
158     }
159     if (pythonVersion.startsWith("3")) {
160       if (pythonVersion.startsWith("3.0")) {
161         return PYTHON30;
162       }
163       if (pythonVersion.startsWith("3.1.") || pythonVersion.equals("3.1")) {
164         return PYTHON31;
165       }
166       if (pythonVersion.startsWith("3.2")) {
167         return PYTHON32;
168       }
169       if (pythonVersion.startsWith("3.3")) {
170         return PYTHON33;
171       }
172       if (pythonVersion.startsWith("3.4")) {
173         return PYTHON34;
174       }
175       if (pythonVersion.startsWith("3.5")) {
176         return PYTHON35;
177       }
178       if (pythonVersion.startsWith("3.6")) {
179         return PYTHON36;
180       }
181       if (pythonVersion.startsWith("3.7")) {
182         return PYTHON37;
183       }
184       if (pythonVersion.startsWith("3.8")) {
185         return PYTHON38;
186       }
187       if (pythonVersion.startsWith("3.9")) {
188         return PYTHON39;
189       }
190       if (pythonVersion.startsWith("3.10")) {
191         return PYTHON310;
192       }
193       return DEFAULT3;
194     }
195     return getDefault();
196   }
197
198   @NotNull
199   public String toPythonVersion() {
200     return getMajorVersion() + "." + getMinorVersion();
201   }
202
203   @NotNull
204   public static LanguageLevel forElement(@NotNull PsiElement element) {
205     return PyPsiFacade.getInstance(element.getProject()).getLanguageLevel(element);
206   }
207
208   @NotNull
209   public static LanguageLevel getLatest() {
210     return ArrayUtil.getLastElement(values());
211   }
212
213   @Override
214   public String toString() {
215     return toPythonVersion();
216   }
217 }