Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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: 0 additions & 1 deletion Sources/Commands/GenerateCode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ public struct GenerateCode: ParsableCommand {
*/

import JavaScriptKit
import ECMAScript


"""
Expand Down
6 changes: 3 additions & 3 deletions Sources/WebIDL/IntermediateRepresentation/IRGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public class IRGenerator {
}
}

ir.registerProtocol(withTypeName: mixin.identifier, inheritsFrom: [], requiredMembers: [], defaultImplementations: members)
ir.registerProtocol(withTypeName: mixin.identifier, inheritsFrom: [], requiredMembers: [], defaultImplementations: members, kind: .mixin)
}

func handleEnum(_ enumeration: Enum) {
Expand Down Expand Up @@ -183,7 +183,7 @@ public class IRGenerator {
return handleReadOnlyMember(readOnlyMember)

case .stringifier:
// Not required: JSBridgedType conforms to CustomStringConvertible
// Not required: JSBridgedClass conforms to CustomStringConvertible
return nil

case .staticMember(let staticMember, _):
Expand Down Expand Up @@ -222,7 +222,7 @@ public class IRGenerator {
}
}

ir.registerProtocol(withTypeName: callbackInterface.identifer, inheritsFrom: [], requiredMembers: requiredMembers, defaultImplementations: defaultImplementations)
ir.registerProtocol(withTypeName: callbackInterface.identifer, inheritsFrom: [], requiredMembers: requiredMembers, defaultImplementations: defaultImplementations, kind: .callback)
}

func handleTypedef(_ typedef: Typedef) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ public class IntermediateRepresentation: Collection {
}

@discardableResult
func registerProtocol(withTypeName typeName: String, inheritsFrom: Set<NodePointer>, requiredMembers: [MemberNode], defaultImplementations: [MemberNode]) -> NodePointer {
func registerProtocol(withTypeName typeName: String, inheritsFrom: Set<NodePointer>, requiredMembers: [MemberNode], defaultImplementations: [MemberNode], kind: ProtocolNode.Kind) -> NodePointer {

let nodePointer = existingOrNewNodePointer(for: typeName)
let typeErasedPointer = existingOrNewNodePointer(for: "Any\(typeName)")
Expand All @@ -252,7 +252,7 @@ public class IntermediateRepresentation: Collection {
existingProtocolNode.requiredMembers.append(contentsOf: requiredMembers)
existingProtocolNode.defaultImplementations.append(contentsOf: defaultImplementations)
} else {
nodePointer.node = ProtocolNode(typeName: typeName, inheritsFrom: inheritsFrom, requiredMembers: requiredMembers, defaultImplementations: defaultImplementations)
nodePointer.node = ProtocolNode(typeName: typeName, inheritsFrom: inheritsFrom, requiredMembers: requiredMembers, defaultImplementations: defaultImplementations, kind: kind)
typeErasedPointer.node = TypeErasedWrapperStructNode(wrapped: nodePointer)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,23 +107,23 @@ class ConstructorNode: MemberNode, Equatable {

let returnValue: String
if closureNode.returnType.identifier == "Void" {
returnValue = "; return .undefined"
returnValue = ""
} else {
returnValue = ".fromJSValue()"
returnValue = ".fromJSValue()!"
}

let argumentCount = closureNode.arguments.count
let closureArguments = (0 ..< argumentCount)
.map { "$0[\($0)].fromJSValue()" }
.map { "$0[\($0)].fromJSValue()!" }
.joined(separator: ", ")
return "JSFunctionRef.from({ \($0.label)(\(closureArguments))\(returnValue) })"
return "JSClosure { \($0.label)(\(closureArguments))\(returnValue) }"
} else {
return $0.label + ".jsValue()"
}
}
declaration += """
{
self.init(objectRef: \(className).classRef.new(\(passedParameters.joined(separator: ", "))))
self.init(withCompatibleObject: \(className).constructor.new(\(passedParameters.joined(separator: ", "))))
}
"""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,72 @@ class MethodNode: MemberNode, Equatable {
true
}

// swiftlint:disable cyclomatic_complexity function_body_length
private func _swiftDeclaration(inContext context: MemberNodeContext, withImplementation: Bool) -> [String] {

var declarations = [String]()
private func _generateOverloads() -> [[ParameterNode]] {
var parameters = self.parameters

var removedParameter = false
var overloads = [parameters]
repeat {
removedParameter = false
if let index = parameters.lastIndex(where: { $0.isOmittable && $0.defaultValue == nil }) {
parameters.removeSubrange( index ..< parameters.endIndex)
overloads.append(parameters)
removedParameter = true
}
} while removedParameter || parameters.contains(where: { $0.isOmittable && $0.defaultValue == nil })

for parameter in parameters {
let unwrapped: ProtocolNode
if let optional = parameter.dataType.node as? OptionalNode {
guard let node = optional.wrapped.node as? ProtocolNode else { continue }
unwrapped = node
} else {
guard let node = parameter.dataType.node as? ProtocolNode else { continue }
unwrapped = node
}
guard unwrapped.kind == .callback else { continue }
for params in overloads {
var params = params
guard let idx = params.firstIndex(where: { $0.label == parameter.label }) else { continue }
let param = params[idx]
guard let method = unwrapped.requiredMembers.first(where: { $0.isMethod && !$0.isStatic && !$0.isSubscript }) as? MethodNode else { continue }
let closureNode = ClosureNode(arguments: method.parameters.map { $0.dataType }, returnType: method.returnType)
let typeNode: TypeNode

if let optional = parameter.dataType.node as? OptionalNode {
typeNode = OptionalNode(
wrapped: NodePointer(
identifier: optional.wrapped.identifier,
node: closureNode
)
)
} else {
typeNode = closureNode
}

params[idx] = ParameterNode(
label: param.label,
dataType: NodePointer(
identifier: param.dataType.identifier,
node: typeNode
),
isVariadic: param.isVariadic,
isOmittable: param.isOmittable,
defaultValue: param.defaultValue
)
overloads.append(params)
}
}

return overloads
}

// swiftlint:disable cyclomatic_complexity function_body_length
private func _swiftDeclaration(inContext context: MemberNodeContext, withImplementation: Bool) -> [String] {

var declarations = [String]()
let overloads = _generateOverloads()

for parameters in overloads {
var declaration: String

switch context {
Expand Down Expand Up @@ -59,7 +115,11 @@ class MethodNode: MemberNode, Equatable {
typeConstraints.append("\(type): \(dataTypeNode.swiftTypeName)")
}
} else if dataTypeNode.isClosure {
type = "@escaping \(dataTypeNode.swiftTypeName)"
if dataTypeNode.isOptional {
type = dataTypeNode.swiftTypeName
} else {
type = "@escaping \(dataTypeNode.swiftTypeName)"
}
} else {
type = dataTypeNode.swiftTypeName
}
Expand Down Expand Up @@ -103,29 +163,41 @@ class MethodNode: MemberNode, Equatable {
let dataTypeNode = unwrapNode($0.dataType)
if dataTypeNode.isClosure {

let closureOptional: Bool
let closureNode: ClosureNode
if let cNode = dataTypeNode as? ClosureNode {
closureNode = cNode
closureNode = cNode
closureOptional = false
} else if let aliasNode = dataTypeNode as? AliasNode, let cNode = aliasNode.aliased as? ClosureNode {
closureNode = cNode
closureOptional = false
} else if let aliasNode = dataTypeNode as? AliasNode, let optionalNode = aliasNode.aliased as? OptionalNode, let cNode = optionalNode.wrapped.node as? ClosureNode {
closureNode = cNode
closureOptional = false // FIXME: or true?
} else if let optionalNode = dataTypeNode as? OptionalNode, let cNode = optionalNode.wrapped.node as? ClosureNode {
closureNode = cNode
closureOptional = true
} else {
fatalError("Unknown closure type.")
fatalError("Unknown closure type \(dataTypeNode).")
}

let returnValue: String
if closureNode.returnType.identifier == "Void" {
returnValue = "; return .undefined"
returnValue = ""
} else {
returnValue = ".fromJSValue()"
returnValue = ".jsValue()"
}

let argumentCount = closureNode.arguments.count
let closureArguments = (0 ..< argumentCount)
.map { "$0[\($0)].fromJSValue()" }
.map { "$0[\($0)].fromJSValue()!" }
.joined(separator: ", ")
return "JSFunctionRef.from({ \($0.label)(\(closureArguments))\(returnValue) })"
let closureCode = "JSClosure { \($0.label)\(closureOptional ? "!" : "")(\(closureArguments))\(returnValue) }"
if closureOptional {
return "\($0.label) == nil ? nil : \(closureCode)"
} else {
return closureCode
}
} else {
return $0.label + ".jsValue()"
}
Expand All @@ -134,31 +206,26 @@ class MethodNode: MemberNode, Equatable {
if returnType.identifier == "Void" {
declaration += """
{
_ = objectRef.\(name)!(\(passedParameters.joined(separator: ", ")))
_ = jsObject.\(name)!(\(passedParameters.joined(separator: ", ")))
}
"""
} else if unwrapNode(returnType).isProtocol {
declaration += """
{
return objectRef.\(name)!(\(passedParameters.joined(separator: ", "))).fromJSValue() as \(unwrapNode(returnType).typeErasedSwiftType)
return jsObject.\(name)!(\(passedParameters.joined(separator: ", "))).fromJSValue()! as \(unwrapNode(returnType).typeErasedSwiftType)
}
"""
} else {
declaration += """
{
return objectRef.\(name)!(\(passedParameters.joined(separator: ", "))).fromJSValue()
return jsObject.\(name)!(\(passedParameters.joined(separator: ", "))).fromJSValue()!
}
"""
}
}

declarations.append(declaration)

if let index = parameters.lastIndex(where: { $0.isOmittable && $0.defaultValue == nil }) {
parameters.removeSubrange( index ..< parameters.endIndex)
removedParameter = true
}
} while removedParameter || parameters.contains(where: { $0.isOmittable && $0.defaultValue == nil })
}

return declarations
}
Expand Down
Loading