|
6 | 6 | # In order for this to work, ABI-impacting declarations need to be annotated |
7 | 7 | # with special comments in the following format: |
8 | 8 | # |
9 | | -# /*System 0.0.2*/ |
| 9 | +# @available(/*System 0.0.2*/iOS 8, *) |
10 | 10 | # public func greeting() -> String { |
11 | 11 | # "Hello" |
12 | 12 | # } |
13 | 13 | # |
| 14 | +# (The iOS 8 availability is a dummy no-op declaration -- it only has to be there because |
| 15 | +# `@available(*)` isn't valid syntax, and commenting out the entire `@available` attribute |
| 16 | +# would interfere with parser tools for doc comments. `iOS 8` is the shortest version string that |
| 17 | +# matches the minimum possible deployment target for Swift code, so we use that as our dummy |
| 18 | +# availability version. `@available(iOS 8, *)` is functionally equivalent to not having an |
| 19 | +# `@available` attribute at all.) |
| 20 | +# |
14 | 21 | # The script adds full availability incantations to these comments. It can run |
15 | 22 | # in one of two modes: |
16 | 23 | # |
|
19 | 26 | # availability across `SystemPackage` and the ABI-stable `System` module that |
20 | 27 | # ships in Apple's OS releases: |
21 | 28 | # |
22 | | -# /*System 0.0.2, @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)*/ |
| 29 | +# @available(/*System 0.0.2: macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0*/iOS 8, *) |
23 | 30 | # public func greeting() -> String { |
24 | 31 | # "Hello" |
25 | 32 | # } |
26 | 33 | # |
27 | | -# `expand-availability.py --attributes` adds actual availability attributes. |
| 34 | +# `expand-availability.py --attributes` adds actual availability declarations. |
28 | 35 | # This is used by maintainers to build ABI stable releases of System on Apple's |
29 | 36 | # platforms: |
30 | 37 | # |
31 | | -# /*System 0.0.2*/@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) |
| 38 | +# @available(/*System 0.0.2: */macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) |
32 | 39 | # public func greeting() -> String { |
33 | 40 | # "Hello" |
34 | 41 | # } |
@@ -65,22 +72,44 @@ def swift_sources_in(path): |
65 | 72 | result.append(os.path.join(dir, file)) |
66 | 73 | return result |
67 | 74 |
|
68 | | -macro_pattern = re.compile( |
| 75 | +# Old-style syntax: |
| 76 | +# /*System 0.0.2*/ |
| 77 | +# /*System 0.0.2, @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)*/ |
| 78 | +# /*System 0.0.2*/@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) |
| 79 | +old_macro_pattern = re.compile( |
69 | 80 | r"/\*(System [^ *]+)(, @available\([^)]*\))?\*/(@available\([^)]*\))?") |
70 | 81 |
|
| 82 | +# New-style comments: |
| 83 | +# @available(/*SwiftSystem 0.0.2*/macOS 10, *) |
| 84 | +# @available(/*SwiftSystem 0.0.2: macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0*/iOS 8, *) |
| 85 | +# @available(/*SwiftSystem 0.0.2*/macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) |
| 86 | +# |
| 87 | +# These do not interfere with our tools' ability to find doc comments. |
| 88 | +macro_pattern = re.compile( |
| 89 | + r"@available\(/\*(System [^ *:]+)[^*/)]*\*/([^)]*)\*\)") |
| 90 | + |
| 91 | +def available_attribute(filename, lineno, symbolic_version): |
| 92 | + expansion = versions[symbolic_version] |
| 93 | + if expansion is None: |
| 94 | + raise ValueError("{0}:{1}: error: Unknown System version '{0}'" |
| 95 | + .format(fileinput.filename(), fileinput.lineno(), symbolic_version)) |
| 96 | + if args.attributes: |
| 97 | + attribute = "@available(/*{0}*/{1}, *)".format(symbolic_version, expansion) |
| 98 | + else: |
| 99 | + # Sadly `@available(*)` is not valid syntax, so we have to mention at least one actual |
| 100 | + # platform here. |
| 101 | + attribute = "@available(/*{0}: {1}*/iOS 8, *)".format(symbolic_version, expansion) |
| 102 | + return attribute |
| 103 | + |
| 104 | + |
71 | 105 | sources = swift_sources_in("Sources") + swift_sources_in("Tests") |
72 | 106 | for line in fileinput.input(files=sources, inplace=True): |
73 | 107 | match = re.search(macro_pattern, line) |
| 108 | + if match is None: |
| 109 | + match = re.search(old_macro_pattern, line) |
74 | 110 | if match: |
75 | | - system_version = match.group(1) |
76 | | - expansion = versions[system_version] |
77 | | - if expansion is None: |
78 | | - raise ValueError("{0}:{1}: error: Unknown System version '{0}'" |
79 | | - .format(fileinput.filename(), fileinput.lineno(), |
80 | | - system_version)) |
81 | | - if args.attributes: |
82 | | - replacement = "/*{0}*/@available({1}, *)".format(system_version, expansion) |
83 | | - else: |
84 | | - replacement = "/*{0}, @available({1}, *)*/".format(system_version, expansion) |
| 111 | + symbolic_version = match.group(1) |
| 112 | + replacement = available_attribute( |
| 113 | + fileinput.filename(), fileinput.lineno(), symbolic_version) |
85 | 114 | line = line[:match.start()] + replacement + line[match.end():] |
86 | 115 | print(line, end="") |
0 commit comments