6552edaba65b1410fdfd9e9cec4ab3168527dcc0
[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   /**
112    * @return an int where major and minor version are represented decimally: "version 2.5" is 25.
113    * @deprecated please migrate to {@link LanguageLevel#getMajorVersion()} and {@link LanguageLevel#getMinorVersion()}
114    * since this method disclose {@link LanguageLevel} internals.
115    */
116   @Deprecated
117   @ApiStatus.ScheduledForRemoval(inVersion = "2021.1")
118   public int getVersion() {
119     return myVersion;
120   }
121
122   public int getMajorVersion() {
123     return myVersion / 100;
124   }
125
126   public int getMinorVersion() {
127     return myVersion % 100;
128   }
129
130   public boolean hasPrintStatement() {
131     return isPython2();
132   }
133
134   public boolean isPython2() {
135     return getMajorVersion() == 2;
136   }
137
138   public boolean isPy3K() {
139     return getMajorVersion() == 3;
140   }
141
142   public boolean isOlderThan(@NotNull LanguageLevel other) {
143     return myVersion < other.myVersion;
144   }
145
146   public boolean isAtLeast(@NotNull LanguageLevel other) {
147     return myVersion >= other.myVersion;
148   }
149
150   @Nullable
151   @Contract("null->null;!null->!null")
152   public static LanguageLevel fromPythonVersion(@Nullable String pythonVersion) {
153     if (pythonVersion == null) return null;
154
155     if (pythonVersion.startsWith("2")) {
156       if (pythonVersion.startsWith("2.4")) {
157         return PYTHON24;
158       }
159       if (pythonVersion.startsWith("2.5")) {
160         return PYTHON25;
161       }
162       if (pythonVersion.startsWith("2.6")) {
163         return PYTHON26;
164       }
165       if (pythonVersion.startsWith("2.7")) {
166         return PYTHON27;
167       }
168       return DEFAULT2;
169     }
170     if (pythonVersion.startsWith("3")) {
171       if (pythonVersion.startsWith("3.0")) {
172         return PYTHON30;
173       }
174       if (pythonVersion.startsWith("3.1.") || pythonVersion.equals("3.1")) {
175         return PYTHON31;
176       }
177       if (pythonVersion.startsWith("3.2")) {
178         return PYTHON32;
179       }
180       if (pythonVersion.startsWith("3.3")) {
181         return PYTHON33;
182       }
183       if (pythonVersion.startsWith("3.4")) {
184         return PYTHON34;
185       }
186       if (pythonVersion.startsWith("3.5")) {
187         return PYTHON35;
188       }
189       if (pythonVersion.startsWith("3.6")) {
190         return PYTHON36;
191       }
192       if (pythonVersion.startsWith("3.7")) {
193         return PYTHON37;
194       }
195       if (pythonVersion.startsWith("3.8")) {
196         return PYTHON38;
197       }
198       if (pythonVersion.startsWith("3.9")) {
199         return PYTHON39;
200       }
201       if (pythonVersion.startsWith("3.10")) {
202         return PYTHON310;
203       }
204       return DEFAULT3;
205     }
206     return getDefault();
207   }
208
209   @NotNull
210   public String toPythonVersion() {
211     return getMajorVersion() + "." + getMinorVersion();
212   }
213
214   @NotNull
215   public static LanguageLevel forElement(@NotNull PsiElement element) {
216     return PyPsiFacade.getInstance(element.getProject()).getLanguageLevel(element);
217   }
218
219   @NotNull
220   public static LanguageLevel getLatest() {
221     return ArrayUtil.getLastElement(values());
222   }
223
224   @Override
225   public String toString() {
226     return toPythonVersion();
227   }
228 }