Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into wasm32-wasi-test
Browse files Browse the repository at this point in the history
  • Loading branch information
kkebo committed May 1, 2024
2 parents 909dcef + d643ebb commit 5b4cbb8
Show file tree
Hide file tree
Showing 22 changed files with 536 additions and 338 deletions.
16 changes: 9 additions & 7 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ let package = Package(
name: "_SwiftSyntaxCShims"
),

.target(
name: "_AtomicBool"
),

.target(
name: "_InstructionCounter"
),
Expand Down Expand Up @@ -77,7 +73,7 @@ let package = Package(

.target(
name: "SwiftCompilerPlugin",
dependencies: ["SwiftCompilerPluginMessageHandling", "SwiftSyntaxMacros", "_SwiftSyntaxCShims"],
dependencies: ["SwiftCompilerPluginMessageHandling", "SwiftSyntaxMacros"],
exclude: ["CMakeLists.txt"]
),

Expand All @@ -91,6 +87,7 @@ let package = Package(
.target(
name: "SwiftCompilerPluginMessageHandling",
dependencies: [
"_SwiftSyntaxCShims",
"SwiftDiagnostics",
"SwiftOperators",
"SwiftParser",
Expand Down Expand Up @@ -131,7 +128,7 @@ let package = Package(

.target(
name: "SwiftSyntax",
dependencies: ["_AtomicBool", "SwiftSyntax509", "SwiftSyntax510", "SwiftSyntax600"],
dependencies: ["_SwiftSyntaxCShims", "SwiftSyntax509", "SwiftSyntax510", "SwiftSyntax600"],
exclude: ["CMakeLists.txt"],
swiftSettings: swiftSyntaxSwiftSettings
),
Expand Down Expand Up @@ -298,7 +295,12 @@ let package = Package(
exclude: ["Inputs"]
),
],
swiftLanguageVersions: [.v5]
// Disable Swift 6 mode when the `SWIFTSYNTAX_DISABLE_SWIFT_6_MODE` environment variable is set. This works around the following
// issue: The self-hosted SwiftPM job has Xcode 15.3 (Swift 5.10) installed and builds a Swift 6 SwiftPM from source.
// It then tries to build itself as a fat binary using the just-built Swift 6 SwiftPM, which uses xcbuild from Xcode
// as the build system. But the xcbuild in the installed Xcode is too old and doesn't know about Swift 6 mode, so it
// fails with: SWIFT_VERSION '6' is unsupported, supported versions are: 4.0, 4.2, 5.0 (rdar://126952308)
swiftLanguageVersions: hasEnvironmentVariable("SWIFTSYNTAX_DISABLE_SWIFT_6_MODE") ? [.v5] : [.v5, .version("6")]
)

// This is a fake target that depends on all targets in the package.
Expand Down
5 changes: 4 additions & 1 deletion Release Notes/510.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
- `SyntaxStringInterpolation.appendInterpolation(_: (some SyntaxProtocol)?)`
- Description: Allows optional syntax nodes to be used inside string interpolation of syntax nodes. If the node is `nil`, nothing will get added to the string interpolation.
- Pull Request: https://github.com/apple/swift-syntax/pull/2085

- `SyntaxCollection.index(at:)`
- Description: Returns the index of the n-th element in a `SyntaxCollection`. This computation is in O(n) and `SyntaxCollection` is not subscriptable by an integer.
- Pull Request: https://github.com/apple/swift-syntax/pull/2014

- Convenience initializer `ClosureCaptureSyntax.init()`
- Description: Provides a convenience initializer for `ClosureCaptureSyntax` that takes a concrete `name` argument and automatically adds `equal = TokenSyntax.equalToken()` to it.
- Issue: https://github.com/apple/swift-syntax/issues/1984
- Pull Request: https://github.com/apple/swift-syntax/pull/2127

- Convenience initializer `EnumCaseParameterSyntax.init()`
- Description: Provides a convenience initializer for `EnumCaseParameterSyntax` that takes a concrete `firstName` value and adds `colon = TokenSyntax.colonToken()` automatically to it.
- Issue: https://github.com/apple/swift-syntax/issues/1984
Expand All @@ -30,7 +33,7 @@
- Issue: https://github.com/apple/swift-syntax/issues/2092
- Pull Request: https://github.com/apple/swift-syntax/pull/2108

- Same-Type Casts
- Same-Type Casts
- Description: `is`, `as`, and `cast` overloads on `SyntaxProtocol` with same-type conversions are marked as deprecated. The deprecated methods emit a warning indicating the cast will always succeed.
- Issue: https://github.com/apple/swift-syntax/issues/2092
- Pull Request: https://github.com/apple/swift-syntax/pull/2108
Expand Down
10 changes: 10 additions & 0 deletions Release Notes/601.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@

## New APIs

- `IntegerLiteralExprSyntax` and `FloatLiteralExprSyntax` now have a computed `representedLiteralValue` property.
- Description: Allows retrieving the represented literal value when valid.
- Issue: https://github.com/apple/swift-syntax/issues/405
- Pull Request: https://github.com/apple/swift-syntax/pull/2605

## API Behavior Changes

## Deprecations

## API-Incompatible Changes

- Moved `Radix` and `IntegerLiteralExprSyntax.radix` from `SwiftRefactor` to `SwiftSyntax`.
- Description: Allows retrieving the radix value from the `literal.text`.
- Issue: https://github.com/apple/swift-syntax/issues/405
- Pull Request: https://github.com/apple/swift-syntax/pull/2605

## Template

- *Affected API or two word description*
Expand Down
1 change: 0 additions & 1 deletion Sources/SwiftCompilerPlugin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,4 @@ add_swift_syntax_library(SwiftCompilerPlugin
target_link_swift_syntax_libraries(SwiftCompilerPlugin PUBLIC
SwiftSyntaxMacros
SwiftCompilerPluginMessageHandling
_SwiftSyntaxCShims
)
196 changes: 11 additions & 185 deletions Sources/SwiftCompilerPlugin/CompilerPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,13 @@
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// NOTE: This basic plugin mechanism is mostly copied from
// https://github.com/apple/swift-package-manager/blob/main/Sources/PackagePlugin/Plugin.swift

#if swift(>=6.0)
private import _SwiftSyntaxCShims
public import SwiftSyntaxMacros
@_spi(PluginMessage) private import SwiftCompilerPluginMessageHandling
#if canImport(Darwin)
private import Darwin
#elseif canImport(Glibc)
private import Glibc
#elseif canImport(ucrt)
private import ucrt
#elseif canImport(WASILibc)
private import WASILibc
#endif
#else
import _SwiftSyntaxCShims
import SwiftSyntaxMacros
@_spi(PluginMessage) import SwiftCompilerPluginMessageHandling
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(ucrt)
import ucrt
#elseif canImport(WASILibc)
import WASILibc
#endif
#endif

//
Expand Down Expand Up @@ -96,7 +74,12 @@ extension CompilerPlugin {
}
}

let pluginPath = CommandLine.arguments.first ?? "<unknown>"
let pluginPath: String
if CommandLine.argc > 0, let cPluginPath = CommandLine.unsafeArgv[0] {
pluginPath = String(cString: cPluginPath)
} else {
pluginPath = "<unknown>"
}
throw CompilerPluginError(
message:
"macro implementation type '\(moduleName).\(typeName)' could not be found in executable plugin '\(pluginPath)'"
Expand All @@ -121,171 +104,14 @@ struct MacroProviderAdapter<Plugin: CompilerPlugin>: PluginProvider {
}
}

#if canImport(ucrt)
private let dup = _dup(_:)
private let fileno = _fileno(_:)
private let dup2 = _dup2(_:_:)
private let close = _close(_:)
private let read = _read(_:_:_:)
private let write = _write(_:_:_:)
#endif

extension CompilerPlugin {

/// Main entry point of the plugin — sets up a communication channel with
/// the plugin host and runs the main message loop.
/// Main entry point of the plugin — sets up a standard I/O communication
/// channel with the plugin host and runs the main message loop.
public static func main() throws {
#if os(WASI)
internalError("CompilerPlugin.main() is not implemented in WASI.")
#else
let stdin = _ss_stdin()
let stdout = _ss_stdout()
let stderr = _ss_stderr()

// Duplicate the `stdin` file descriptor, which we will then use for
// receiving messages from the plugin host.
let inputFD = dup(fileno(stdin))
guard inputFD >= 0 else {
internalError("Could not duplicate `stdin`: \(describe(errno: _ss_errno())).")
}

// Having duplicated the original standard-input descriptor, we close
// `stdin` so that attempts by the plugin to read console input (which
// are usually a mistake) return errors instead of blocking.
guard close(fileno(stdin)) >= 0 else {
internalError("Could not close `stdin`: \(describe(errno: _ss_errno())).")
}

// Duplicate the `stdout` file descriptor, which we will then use for
// sending messages to the plugin host.
let outputFD = dup(fileno(stdout))
guard outputFD >= 0 else {
internalError("Could not dup `stdout`: \(describe(errno: _ss_errno())).")
}

// Having duplicated the original standard-output descriptor, redirect
// `stdout` to `stderr` so that all free-form text output goes there.
guard dup2(fileno(stderr), fileno(stdout)) >= 0 else {
internalError("Could not dup2 `stdout` to `stderr`: \(describe(errno: _ss_errno())).")
}

#if canImport(ucrt)
// Set I/O to binary mode. Avoid CRLF translation, and Ctrl+Z (0x1A) as EOF.
_ = _setmode(inputFD, _O_BINARY)
_ = _setmode(outputFD, _O_BINARY)
#endif

// Open a message channel for communicating with the plugin host.
let connection = PluginHostConnection(
inputStream: inputFD,
outputStream: outputFD
)

// Handle messages from the host until the input stream is closed,
// indicating that we're done.
let connection = try StandardIOMessageConnection()
let provider = MacroProviderAdapter(plugin: Self())
let impl = CompilerPluginMessageHandler(connection: connection, provider: provider)
do {
try impl.main()
} catch {
// Emit a diagnostic and indicate failure to the plugin host,
// and exit with an error code.
internalError(String(describing: error))
}
#endif
}

// Private function to report internal errors and then exit.
fileprivate static func internalError(_ message: String) -> Never {
fputs("Internal Error: \(message)\n", _ss_stderr())
exit(1)
}
}

internal struct PluginHostConnection: MessageConnection {
// File descriptor for input from the host.
fileprivate let inputStream: CInt
// File descriptor for output to the host.
fileprivate let outputStream: CInt

func sendMessage<TX: Encodable>(_ message: TX) throws {
// Encode the message as JSON.
let payload = try JSON.encode(message)

// Write the header (a 64-bit length field in little endian byte order).
let count = payload.count
var header = UInt64(count).littleEndian
try withUnsafeBytes(of: &header) { try _write(outputStream, contentsOf: $0) }

// Write the JSON payload.
try payload.withUnsafeBytes { try _write(outputStream, contentsOf: $0) }
}

func waitForNextMessage<RX: Decodable>(_ ty: RX.Type) throws -> RX? {
// Read the header (a 64-bit length field in little endian byte order).
var header: UInt64 = 0
do {
try withUnsafeMutableBytes(of: &header) { try _read(inputStream, into: $0) }
} catch IOError.readReachedEndOfInput {
// Connection closed.
return nil
}

// Read the JSON payload.
let count = Int(UInt64(littleEndian: header))
let data = UnsafeMutableRawBufferPointer.allocate(byteCount: count, alignment: 1)
defer { data.deallocate() }
try _read(inputStream, into: data)

// Decode and return the message.
return try JSON.decode(ty, from: UnsafeBufferPointer(data.bindMemory(to: UInt8.self)))
}
}

/// Write the buffer to the file descriptor. Throws an error on failure.
private func _write(_ fd: CInt, contentsOf buffer: UnsafeRawBufferPointer) throws {
guard var ptr = buffer.baseAddress else { return }
let endPtr = ptr.advanced(by: buffer.count)
while ptr != endPtr {
switch write(fd, ptr, numericCast(endPtr - ptr)) {
case -1: throw IOError.writeFailed(errno: _ss_errno())
case 0: throw IOError.writeFailed(errno: 0) /* unreachable */
case let n: ptr += Int(n)
}
let impl = CompilerPluginMessageListener(connection: connection, provider: provider)
impl.main()
}
}

/// Fill the buffer from the file descriptor. Throws an error on failure.
/// If the file descriptor reached the end-of-file before filling up the entire
/// buffer, throws IOError.readReachedEndOfInput
private func _read(_ fd: CInt, into buffer: UnsafeMutableRawBufferPointer) throws {
guard var ptr = buffer.baseAddress else { return }
let endPtr = ptr.advanced(by: buffer.count)
while ptr != endPtr {
switch read(fd, ptr, numericCast(endPtr - ptr)) {
case -1: throw IOError.readFailed(errno: _ss_errno())
case 0: throw IOError.readReachedEndOfInput
case let n: ptr += Int(n)
}
}
}

private enum IOError: Error, CustomStringConvertible {
case readReachedEndOfInput
case readFailed(errno: CInt)
case writeFailed(errno: CInt)

var description: String {
switch self {
case .readReachedEndOfInput: "read(2) reached end-of-file"
case .readFailed(let errno): "read(2) failed: \(describe(errno: errno))"
case .writeFailed(let errno): "write(2) failed: \(describe(errno: errno))"
}
}
}

// Private function to construct an error message from an `errno` code.
private func describe(errno: CInt) -> String {
if let cStr = strerror(errno) { return String(cString: cStr) }
return String(describing: errno)
}
8 changes: 7 additions & 1 deletion Sources/SwiftCompilerPluginMessageHandling/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ add_swift_syntax_library(SwiftCompilerPluginMessageHandling
JSON/JSON.swift
JSON/JSONDecoding.swift
JSON/JSONEncoding.swift
StandardIOMessageConnection.swift
)

target_link_swift_syntax_libraries(SwiftCompilerPluginMessageHandling PUBLIC
Expand All @@ -26,4 +27,9 @@ target_link_swift_syntax_libraries(SwiftCompilerPluginMessageHandling PUBLIC
SwiftParser
SwiftSyntaxMacros
SwiftSyntaxMacroExpansion
SwiftOperators)
SwiftOperators
)

target_link_swift_syntax_libraries(SwiftCompilerPluginMessageHandling PRIVATE
_SwiftSyntaxCShims
)

0 comments on commit 5b4cbb8

Please sign in to comment.