Skip to content

[Plugin] Add 'loadPluginLibrary' message #1411

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Sources/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ add_subdirectory(SwiftParserDiagnostics)
add_subdirectory(SwiftOperators)
add_subdirectory(SwiftSyntaxBuilder)
add_subdirectory(SwiftSyntaxMacros)
add_subdirectory(SwiftCompilerPluginMessageHandling)
add_subdirectory(IDEUtils)
22 changes: 22 additions & 0 deletions Sources/SwiftCompilerPluginMessageHandling/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See http://swift.org/LICENSE.txt for license information
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors

add_swift_host_library(SwiftCompilerPluginMessageHandling
CompilerPluginMessageHandler.swift
Diagnostics.swift
Macros.swift
PluginMacroExpansionContext.swift
PluginMessages.swift
)

target_link_libraries(SwiftCompilerPluginMessageHandling PUBLIC
SwiftSyntax
SwiftDiagnostics
SwiftParser
SwiftSyntaxMacros
SwiftOperators)
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,23 @@

import SwiftSyntaxMacros

/// Optional features.
public enum PluginFeature: String {
case loadPluginLibrary = "load-plugin-library"
}

/// A type that provides the actual plugin functions.
public protocol PluginProvider {
/// Resolve macro type by the module name and the type name.
func resolveMacro(moduleName: String, typeName: String) -> Macro.Type?

/// Load dynamic link library at `libraryPath`. Implementations can use
/// `moduleName` to associate the loaded library with it.
func loadPluginLibrary(libraryPath: String, moduleName: String) throws

/// Optional plugin features. This is sent to the host so the it can decide
/// the behavior depending on these.
var features: [PluginFeature] { get }
}

/// Low level message connection to the plugin host.
Expand Down Expand Up @@ -67,9 +81,11 @@ extension CompilerPluginMessageHandler {
fileprivate func handleMessage(_ message: HostToPluginMessage) throws {
switch message {
case .getCapability:
try self.sendMessage(
.getCapabilityResult(capability: PluginMessage.capability)
let capability = PluginMessage.PluginCapability(
protocolVersion: PluginMessage.PROTOCOL_VERSION_NUMBER,
features: provider.features.map({ $0.rawValue })
)
try self.sendMessage(.getCapabilityResult(capability: capability))

case .expandFreestandingMacro(let macro, let discriminator, let expandingSyntax):
try expandFreestandingMacro(
Expand All @@ -87,6 +103,42 @@ extension CompilerPluginMessageHandler {
declSyntax: declSyntax,
parentDeclSyntax: parentDeclSyntax
)

case .loadPluginLibrary(let libraryPath, let moduleName):
var diags: [PluginMessage.Diagnostic] = []
do {
try provider.loadPluginLibrary(libraryPath: libraryPath, moduleName: moduleName)
} catch {
diags.append(
PluginMessage.Diagnostic(
message: String(describing: error),
severity: .error,
position: .invalid,
highlights: [],
notes: [],
fixIts: []
)
)
}
try self.sendMessage(.loadPluginLibraryResult(loaded: diags.isEmpty, diagnostics: diags));
}
}
}

struct UnimplementedError: Error, CustomStringConvertible {
var description: String { "unimplemented" }
}

/// Default implementation of 'PluginProvider' requirements.
public extension PluginProvider {
var features: [PluginFeature] {
// No optional features by default.
return []
}

func loadPluginLibrary(libraryPath: String, moduleName: String) throws {
// This should be unreachable. The host should not call 'loadPluginLibrary'
// unless the feature is not declared.
throw UnimplementedError()
}
}
28 changes: 23 additions & 5 deletions Sources/SwiftCompilerPluginMessageHandling/PluginMessages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@
// NOTE: Types in this file should be self-contained and should not depend on any non-stdlib types.

internal enum HostToPluginMessage: Codable {
/// Get capability of this plugin.
case getCapability

/// Expand a '@freestanding' macro.
case expandFreestandingMacro(
macro: PluginMessage.MacroReference,
discriminator: String,
syntax: PluginMessage.Syntax
)

/// Expand an '@attached' macro.
case expandAttachedMacro(
macro: PluginMessage.MacroReference,
macroRole: PluginMessage.MacroRole,
Expand All @@ -30,9 +33,21 @@ internal enum HostToPluginMessage: Codable {
declSyntax: PluginMessage.Syntax,
parentDeclSyntax: PluginMessage.Syntax?
)

/// Optionally implemented message to load a dynamic link library.
/// 'moduleName' can be used as a hint indicating that the library
/// provides the specified module.
case loadPluginLibrary(
libraryPath: String,
moduleName: String
)
}

internal enum PluginToHostMessage: Codable {
case getCapabilityResult(
capability: PluginMessage.PluginCapability
)

case expandFreestandingMacroResult(
expandedSource: String?,
diagnostics: [PluginMessage.Diagnostic]
Expand All @@ -43,18 +58,21 @@ internal enum PluginToHostMessage: Codable {
diagnostics: [PluginMessage.Diagnostic]
)

case getCapabilityResult(capability: PluginMessage.PluginCapability)
case loadPluginLibraryResult(
loaded: Bool,
diagnostics: [PluginMessage.Diagnostic]
)
}

/*namespace*/ internal enum PluginMessage {
static var PROTOCOL_VERSION_NUMBER: Int { 3 } // Renamed 'customAttributeSyntax' to 'attributeSyntax'.
static var PROTOCOL_VERSION_NUMBER: Int { 4 } // Added 'loadPluginLibrary'.

struct PluginCapability: Codable {
var protocolVersion: Int
}

static var capability: PluginCapability {
PluginCapability(protocolVersion: PluginMessage.PROTOCOL_VERSION_NUMBER)
/// Optional features this plugin provides.
/// * 'load-plugin-library': 'loadPluginLibrary' message is implemented.
var features: [String]?
}

struct MacroReference: Codable {
Expand Down