|
1 | | -import Foundation |
2 | 1 | import SwiftParser |
3 | 2 | import SwiftSyntax |
4 | 3 | import SwiftSyntaxMacros |
5 | 4 |
|
| 5 | +#if canImport(Darwin) |
| 6 | +import Darwin |
| 7 | +#elseif canImport(Glibc) |
| 8 | +import Glibc |
| 9 | +#elseif canImport(Musl) |
| 10 | +import Musl |
| 11 | +#elseif canImport(Android) |
| 12 | +import Android |
| 13 | +#elseif os(WASI) |
| 14 | +import WASILibc |
| 15 | +#elseif os(Windows) |
| 16 | +import CRT |
| 17 | +import WinSDK |
| 18 | +#endif |
| 19 | + |
6 | 20 | @main |
7 | 21 | class SwiftMacroTestGen: SyntaxVisitor { |
8 | 22 | static func main() { |
9 | 23 | if CommandLine.argc < 2 { |
10 | | - print("error: missing module name (passed 1 argument, expected 2)") |
| 24 | + printError("missing module name (passed 0 arguments, expected 2)") |
11 | 25 | exit(1) |
12 | 26 | } |
13 | | - let contents = |
14 | | - if CommandLine.argc > 2 { |
15 | | - read(file: CommandLine.arguments[2]) |
16 | | - } else { |
17 | | - readStdin() |
18 | | - } |
| 27 | + if CommandLine.argc < 3 { |
| 28 | + printError("missing module name (passed 1 argument, expected 2)") |
| 29 | + exit(1) |
| 30 | + } |
| 31 | + let contents = read(file: CommandLine.arguments[2]) |
19 | 32 | let syntaxTree = Parser.parse(source: contents) |
20 | 33 | print("import \(CommandLine.arguments[1])\n") |
21 | 34 | let visitor = SwiftMacroTestGen(viewMode: .all) |
@@ -101,23 +114,27 @@ class TypeAliasReplacer: SyntaxRewriter { |
101 | 114 | } |
102 | 115 |
|
103 | 116 | func read(file path: String) -> String { |
104 | | - do { |
105 | | - return try String(contentsOfFile: path, encoding: .utf8) |
106 | | - } catch { |
107 | | - print("Error reading file \(path): \(error.localizedDescription)") |
| 117 | + guard let f = fopen(path, "r") else { |
| 118 | + printError("could not open file \(path)") |
108 | 119 | exit(1) |
109 | 120 | } |
110 | | -} |
111 | | - |
112 | | -func readStdin() -> String { |
113 | | - if let data = try? FileHandle.standardInput.readToEnd(), |
114 | | - let input = String(data: data, encoding: .utf8) |
115 | | - { |
116 | | - return input |
117 | | - } else { |
118 | | - print("Error reading stdin)") |
| 121 | + if fseek(f, 0, SEEK_END) != 0 { |
| 122 | + printError("could not read file \(path)") |
| 123 | + exit(1) |
| 124 | + } |
| 125 | + let len = Int(ftell(f)) |
| 126 | + if len < 0 { |
| 127 | + printError("could not read size of file \(path)") |
119 | 128 | exit(1) |
120 | 129 | } |
| 130 | + rewind(f) |
| 131 | + let contents = String( |
| 132 | + unsafeUninitializedCapacity: len, |
| 133 | + initializingUTF8With: { stringBuffer in |
| 134 | + fread(UnsafeMutableRawPointer(stringBuffer.baseAddress!), 1, len, f) |
| 135 | + }) |
| 136 | + fclose(f) |
| 137 | + return contents |
121 | 138 | } |
122 | 139 |
|
123 | 140 | func createBody(_ f: FunctionDeclSyntax, selfParam: TokenSyntax?) -> CodeBlockSyntax { |
@@ -190,6 +207,17 @@ extension TypeSyntax { |
190 | 207 | } |
191 | 208 | } |
192 | 209 |
|
| 210 | +// String.contains is not available without Foundation |
| 211 | +extension String { |
| 212 | + public func contains(_ other: String) -> Bool { |
| 213 | + return self.withCString({ this in |
| 214 | + return other.withCString({ that in |
| 215 | + return strstr(this, that) != nil |
| 216 | + }) |
| 217 | + }) |
| 218 | + } |
| 219 | +} |
| 220 | + |
193 | 221 | func addSelfParam(_ params: FunctionParameterListSyntax, _ type: TokenSyntax, _ name: TokenSyntax) |
194 | 222 | -> FunctionParameterListSyntax |
195 | 223 | { |
@@ -282,3 +310,7 @@ extension AttributeListSyntax.Element { |
282 | 310 | } |
283 | 311 | } |
284 | 312 | } |
| 313 | + |
| 314 | +func printError(_ s: String) { |
| 315 | + fputs("error: \(s)\n", stderr) |
| 316 | +} |
0 commit comments