mirror of https://github.com/apple/pkl-swift
156 lines
4.6 KiB
Plaintext
156 lines
4.6 KiB
Plaintext
//===----------------------------------------------------------------------===//
|
|
// Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@Unlisted
|
|
module pkl.swift.internal.SwiftNamespace
|
|
|
|
import "pkl:reflect"
|
|
import "ClassGen.pkl"
|
|
import "EnumGen.pkl"
|
|
import "TypeAliasGen.pkl"
|
|
import "SwiftMapping.pkl"
|
|
import "Gen.pkl"
|
|
import "utils.pkl"
|
|
|
|
`module`: reflect.Module
|
|
|
|
/// All mappings used by the module, including imports.
|
|
mappings: List<SwiftMapping>
|
|
|
|
/// The name of the Pkl module.
|
|
pklModuleName: String
|
|
|
|
/// The mappings originate from this module.
|
|
moduleMappings: List<SwiftMapping>
|
|
|
|
/// The Swift namespace in which to place these mappings.
|
|
namespaceName: String
|
|
|
|
indent: String
|
|
|
|
local function describeLocation(src: reflect.TypeDeclaration) =
|
|
let (memberType =
|
|
if (src is reflect.Class && src.enclosingDeclaration.moduleClass == src) "module"
|
|
else if (src is reflect.Class) "class"
|
|
else "typealias"
|
|
)
|
|
"* \(memberType) `\(src.reflectee)` (\(src.location.displayUri))"
|
|
|
|
local function hasUniqueNames(): Boolean =
|
|
let (names = moduleMappings.map((it) -> it.name))
|
|
if (names.isDistinct) true
|
|
else
|
|
let (duplicateNames = moduleMappings.filter((it) -> moduleMappings.count((m) -> m.name == it.name) > 1))
|
|
let (locations = duplicateNames.map((it) -> describeLocation(it.source)).join("\n"))
|
|
throw("""
|
|
Conflict: multiple Pkl declarations compute to Swift name `\(duplicateNames.first.name)`.
|
|
|
|
To resolve this conflict, add a `@swift.Name` annotation to any of the following declarations:
|
|
|
|
\(locations)
|
|
|
|
For example:
|
|
|
|
```
|
|
@swift.Name { value = "CrabCakes" }
|
|
class Crab_Cakes
|
|
```
|
|
""")
|
|
|
|
local generated: List<Gen>(hasUniqueNames()) = moduleMappings.map((it) ->
|
|
if (it is SwiftMapping.Class)
|
|
new ClassGen {
|
|
indent = module.indent
|
|
mappings = module.mappings
|
|
mapping = it
|
|
namespaceName = it.namespaceName
|
|
}
|
|
else if (it is SwiftMapping.Enum)
|
|
new EnumGen {
|
|
indent = module.indent
|
|
mappings = module.mappings
|
|
mapping = it
|
|
namespaceName = it.namespaceName
|
|
}
|
|
else
|
|
new TypeAliasGen {
|
|
indent = module.indent
|
|
mappings = module.mappings
|
|
mapping = it
|
|
namespaceName = it.namespaceName
|
|
}
|
|
)
|
|
|
|
local topLevelContents = generated.mapNonNull((g) -> g.topLevelContents)
|
|
|
|
local convenienceLoaders = """
|
|
/// Load the Pkl module at the given source and evaluate it into `\(namespaceName).Module`.
|
|
///
|
|
/// - Parameter source: The source of the Pkl module.
|
|
public static func loadFrom(source: ModuleSource) async throws -> \(namespaceName).Module {
|
|
\(module.indent)try await PklSwift.withEvaluator { evaluator in
|
|
\(module.indent.repeat(2))try await loadFrom(evaluator: evaluator, source: source)
|
|
\(module.indent)}
|
|
}
|
|
|
|
/// Load the Pkl module at the given source and evaluate it with the given evaluator into
|
|
/// `\(namespaceName).Module`.
|
|
///
|
|
/// - Parameter evaluator: The evaluator to use for evaluation.
|
|
/// - Parameter source: The module to evaluate.
|
|
public static func loadFrom(
|
|
\(module.indent)evaluator: PklSwift.Evaluator,
|
|
\(module.indent)source: PklSwift.ModuleSource
|
|
) async throws -> \(namespaceName).Module {
|
|
\(module.indent)try await evaluator.evaluateModule(source: source, as: Module.self)
|
|
}
|
|
"""
|
|
|
|
contents = new Listing {
|
|
utils.renderHeaderComment(`module`)
|
|
"""
|
|
import PklSwift
|
|
|
|
public enum \(namespaceName) {}
|
|
|
|
"""
|
|
when (topLevelContents.length > 0) {
|
|
topLevelContents.join("\n")
|
|
}
|
|
"""
|
|
extension \(namespaceName) {
|
|
"""
|
|
for (gen in generated) {
|
|
when (gen != generated.first) {
|
|
""
|
|
}
|
|
module.indent + gen.contents.replaceAll(Regex("\n(?!\n)"), "\n\(module.indent)")
|
|
}
|
|
when (!`module`.modifiers.contains("open") && !`module`.modifiers.contains("abstract")) {
|
|
""
|
|
module.indent + convenienceLoaders.replaceAll(Regex("\n(?!\n)"), "\n\(module.indent)")
|
|
}
|
|
"}"
|
|
}.join("\n")
|
|
|
|
output {
|
|
files {
|
|
["\(namespaceName).pkl.swift"] {
|
|
text = contents
|
|
}
|
|
}
|
|
}
|