1use crate::PragmaState;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
5pub struct PerlVersion {
6 pub major: u32,
8 pub minor: u32,
10}
11
12impl PerlVersion {
13 pub const fn new(major: u32, minor: u32) -> Self {
15 Self { major, minor }
16 }
17}
18
19pub fn parse_perl_version(module: &str) -> Option<PerlVersion> {
28 let s = module.strip_prefix('v').unwrap_or(module);
29 let mut parts = s.splitn(3, '.');
30
31 let major = parse_version_component(parts.next()?)?;
32 let minor = match parts.next() {
33 Some(part) => parse_version_component(part)?,
34 None => 0,
35 };
36
37 Some(PerlVersion::new(major, minor))
38}
39
40fn parse_version_component(component: &str) -> Option<u32> {
41 let component = component.split_once('_').map_or(component, |(head, _)| head);
42 component.parse().ok()
43}
44
45#[must_use]
47pub fn version_implies_strict(version: PerlVersion) -> bool {
48 version >= PerlVersion::new(5, 12)
49}
50
51#[must_use]
53pub fn version_implies_warnings(version: PerlVersion) -> bool {
54 version >= PerlVersion::new(5, 35)
55}
56
57#[must_use]
67pub fn features_enabled_by_version(version: PerlVersion) -> Vec<&'static str> {
68 let bundle = if version < PerlVersion::new(5, 10) {
69 DEFAULT_FEATURES
70 } else if version >= PerlVersion::new(5, 42) {
71 BUNDLE_5_42_FEATURES
72 } else if version >= PerlVersion::new(5, 40) {
73 BUNDLE_5_40_FEATURES
74 } else if version >= PerlVersion::new(5, 38) {
75 BUNDLE_5_38_FEATURES
76 } else if version >= PerlVersion::new(5, 36) {
77 BUNDLE_5_36_FEATURES
78 } else if version >= PerlVersion::new(5, 34) {
79 BUNDLE_5_34_FEATURES
80 } else if version >= PerlVersion::new(5, 28) {
81 BUNDLE_5_28_FEATURES
82 } else if version >= PerlVersion::new(5, 24) {
83 BUNDLE_5_24_FEATURES
84 } else if version >= PerlVersion::new(5, 16) {
85 BUNDLE_5_16_FEATURES
86 } else if version >= PerlVersion::new(5, 12) {
87 BUNDLE_5_12_FEATURES
88 } else {
89 BUNDLE_5_10_FEATURES
90 };
91
92 bundle.to_vec()
93}
94
95pub(crate) const DEFAULT_FEATURES: &[&str] = &[
96 "indirect",
97 "multidimensional",
98 "bareword_filehandles",
99 "apostrophe_as_package_separator",
100 "smartmatch",
101];
102
103const BUNDLE_5_10_FEATURES: &[&str] = &[
104 "apostrophe_as_package_separator",
105 "bareword_filehandles",
106 "indirect",
107 "multidimensional",
108 "say",
109 "smartmatch",
110 "state",
111 "switch",
112];
113
114const BUNDLE_5_12_FEATURES: &[&str] = &[
115 "apostrophe_as_package_separator",
116 "bareword_filehandles",
117 "indirect",
118 "multidimensional",
119 "say",
120 "smartmatch",
121 "state",
122 "switch",
123 "unicode_strings",
124];
125
126const BUNDLE_5_16_FEATURES: &[&str] = &[
127 "apostrophe_as_package_separator",
128 "bareword_filehandles",
129 "current_sub",
130 "evalbytes",
131 "fc",
132 "indirect",
133 "multidimensional",
134 "say",
135 "smartmatch",
136 "state",
137 "switch",
138 "unicode_eval",
139 "unicode_strings",
140];
141
142const BUNDLE_5_24_FEATURES: &[&str] = &[
143 "apostrophe_as_package_separator",
144 "bareword_filehandles",
145 "current_sub",
146 "evalbytes",
147 "fc",
148 "indirect",
149 "multidimensional",
150 "postderef_qq",
151 "say",
152 "smartmatch",
153 "state",
154 "switch",
155 "unicode_eval",
156 "unicode_strings",
157];
158
159const BUNDLE_5_28_FEATURES: &[&str] = &[
160 "apostrophe_as_package_separator",
161 "bareword_filehandles",
162 "bitwise",
163 "current_sub",
164 "evalbytes",
165 "fc",
166 "indirect",
167 "multidimensional",
168 "postderef_qq",
169 "say",
170 "smartmatch",
171 "state",
172 "switch",
173 "unicode_eval",
174 "unicode_strings",
175];
176
177const BUNDLE_5_34_FEATURES: &[&str] = BUNDLE_5_28_FEATURES;
178
179const BUNDLE_5_36_FEATURES: &[&str] = &[
180 "apostrophe_as_package_separator",
181 "bareword_filehandles",
182 "bitwise",
183 "current_sub",
184 "evalbytes",
185 "fc",
186 "isa",
187 "postderef_qq",
188 "say",
189 "signatures",
190 "smartmatch",
191 "state",
192 "unicode_eval",
193 "unicode_strings",
194];
195
196const BUNDLE_5_38_FEATURES: &[&str] = &[
197 "apostrophe_as_package_separator",
198 "bitwise",
199 "current_sub",
200 "evalbytes",
201 "fc",
202 "isa",
203 "module_true",
204 "postderef_qq",
205 "say",
206 "signatures",
207 "smartmatch",
208 "state",
209 "unicode_eval",
210 "unicode_strings",
211];
212
213const BUNDLE_5_40_FEATURES: &[&str] = &[
214 "apostrophe_as_package_separator",
215 "bitwise",
216 "current_sub",
217 "evalbytes",
218 "fc",
219 "isa",
220 "module_true",
221 "postderef_qq",
222 "say",
223 "signatures",
224 "smartmatch",
225 "state",
226 "try",
227 "unicode_eval",
228 "unicode_strings",
229];
230
231const BUNDLE_5_42_FEATURES: &[&str] = &[
232 "bitwise",
233 "current_sub",
234 "evalbytes",
235 "fc",
236 "isa",
237 "module_true",
238 "postderef_qq",
239 "say",
240 "signatures",
241 "state",
242 "try",
243 "unicode_eval",
244 "unicode_strings",
245];
246
247pub(crate) fn enable_effective_version_semantics(state: &mut PragmaState, version: PerlVersion) {
248 if version_implies_strict(version) {
249 state.strict_vars = true;
250 state.strict_subs = true;
251 state.strict_refs = true;
252 }
253 if version_implies_warnings(version) {
254 state.warnings = true;
255 }
256 state.features = features_enabled_by_version(version);
259 state.unicode_strings = state.has_feature("unicode_strings");
260 state.signatures_strict = false;
261}