Skip to content

Commit 722fa70

Browse files
committed
BridgeJS: Reduce repetition for properties declaration
1 parent fac9cbd commit 722fa70

File tree

10 files changed

+172
-270
lines changed

10 files changed

+172
-270
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 98 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -277,14 +277,11 @@ public class ExportSwift {
277277

278278
switch state {
279279
case .topLevel:
280-
abiName = "bjs_\(name)"
281280
staticContext = nil
282281
case .classBody(let className, _):
283282
if isStatic {
284-
abiName = "bjs_\(className)_static_\(name)"
285283
staticContext = .className(className)
286284
} else {
287-
abiName = "bjs_\(className)_\(name)"
288285
staticContext = nil
289286
}
290287
case .enumBody(let enumName, let enumKey):
@@ -295,16 +292,21 @@ public class ExportSwift {
295292

296293
let isNamespaceEnum = exportedEnumByName[enumKey]?.cases.isEmpty ?? true
297294
staticContext = isNamespaceEnum ? .namespaceEnum : .enumName(enumName)
298-
299-
if isNamespaceEnum, let namespace = finalNamespace, !namespace.isEmpty {
300-
// For namespace enums, use ONLY the resolved namespace to avoid duplication
301-
// The finalNamespace already contains the correct namespace path
302-
let abiNamespace = namespace.joined(separator: "_")
303-
abiName = "bjs_\(abiNamespace)_static_\(name)"
304-
} else {
305-
abiName = "bjs_\(enumName)_static_\(name)"
306-
}
307295
}
296+
297+
let classNameForABI: String?
298+
if case .classBody(let className, _) = state {
299+
classNameForABI = className
300+
} else {
301+
classNameForABI = nil
302+
}
303+
abiName = ABINameGenerator.generateABIName(
304+
baseName: name,
305+
namespace: finalNamespace,
306+
staticContext: isStatic ? staticContext : nil,
307+
operation: nil,
308+
className: classNameForABI
309+
)
308310

309311
guard let effects = collectEffects(signature: node.signature, isStatic: isStatic) else {
310312
return nil
@@ -316,7 +318,7 @@ public class ExportSwift {
316318
parameters: parameters,
317319
returnType: returnType,
318320
effects: effects,
319-
namespace: finalNamespace, // UPDATED: Use resolved namespace
321+
namespace: finalNamespace,
320322
staticContext: staticContext
321323
)
322324
}
@@ -991,50 +993,7 @@ public class ExportSwift {
991993
}
992994

993995
for staticProperty in enumDef.staticProperties {
994-
let getterBuilder = ExportedThunkBuilder(
995-
effects: Effects(isAsync: false, isThrows: false, isStatic: true)
996-
)
997-
998-
// Use context-aware call name based on static context and namespace
999-
let staticCallName: String
1000-
if let staticContext = staticProperty.staticContext {
1001-
switch staticContext {
1002-
case .className(let className):
1003-
staticCallName = "\(className).\(staticProperty.name)"
1004-
case .enumName(let enumName):
1005-
staticCallName = "\(enumName).\(staticProperty.name)"
1006-
case .namespaceEnum:
1007-
// For namespace enums and explicit namespace, use the namespace property
1008-
if let namespace = staticProperty.namespace, !namespace.isEmpty {
1009-
let namespacePath = namespace.joined(separator: ".")
1010-
staticCallName = "\(namespacePath).\(staticProperty.name)"
1011-
} else {
1012-
// Fallback to using the enum's swift call name
1013-
staticCallName = "\(enumDef.swiftCallName).\(staticProperty.name)"
1014-
}
1015-
}
1016-
} else {
1017-
staticCallName = "\(enumDef.swiftCallName).\(staticProperty.name)"
1018-
}
1019-
1020-
getterBuilder.callStaticProperty(name: staticCallName, returnType: staticProperty.type)
1021-
try getterBuilder.lowerReturnValue(returnType: staticProperty.type)
1022-
decls.append(getterBuilder.render(abiName: staticProperty.getterAbiName(className: enumDef.name)))
1023-
1024-
if !staticProperty.isReadonly {
1025-
let setterBuilder = ExportedThunkBuilder(
1026-
effects: Effects(isAsync: false, isThrows: false, isStatic: true)
1027-
)
1028-
try setterBuilder.liftParameter(
1029-
param: Parameter(label: "value", name: "value", type: staticProperty.type)
1030-
)
1031-
setterBuilder.callStaticPropertySetter(
1032-
klassName: staticCallName.components(separatedBy: ".").dropLast().joined(separator: "."),
1033-
propertyName: staticProperty.name
1034-
)
1035-
try setterBuilder.lowerReturnValue(returnType: .void)
1036-
decls.append(setterBuilder.render(abiName: staticProperty.setterAbiName(className: enumDef.name)))
1037-
}
996+
decls.append(contentsOf: try renderSingleExportedProperty(property: staticProperty, context: .enumStatic(enumDef: enumDef)))
1038997
}
1039998
}
1040999

@@ -1141,7 +1100,7 @@ public class ExportSwift {
11411100

11421101
func callStaticProperty(name: String, returnType: BridgeType) {
11431102
if returnType == .void {
1144-
append("let ret = \(raw: name)")
1103+
append("\(raw: name)")
11451104
} else {
11461105
append("let ret = \(raw: name)")
11471106
}
@@ -1450,6 +1409,83 @@ public class ExportSwift {
14501409
return cases
14511410
}
14521411
}
1412+
1413+
/// Context for property rendering that determines call behavior and ABI generation
1414+
private enum PropertyRenderingContext {
1415+
case enumStatic(enumDef: ExportedEnum)
1416+
case classStatic(klass: ExportedClass)
1417+
case classInstance(klass: ExportedClass)
1418+
}
1419+
1420+
/// Renders getter and setter Swift thunk code for a property in any context
1421+
/// This unified function eliminates duplication between enum static, class static, and class instance property rendering
1422+
private func renderSingleExportedProperty(property: ExportedProperty, context: PropertyRenderingContext) throws -> [DeclSyntax] {
1423+
var decls: [DeclSyntax] = []
1424+
1425+
let (callName, className, isStatic): (String, String, Bool)
1426+
switch context {
1427+
case .enumStatic(let enumDef):
1428+
callName = property.callName(prefix: enumDef.swiftCallName)
1429+
className = enumDef.name
1430+
isStatic = true
1431+
case .classStatic(let klass):
1432+
callName = property.callName()
1433+
className = klass.name
1434+
isStatic = true
1435+
1436+
case .classInstance(let klass):
1437+
callName = property.callName()
1438+
className = klass.name
1439+
isStatic = false
1440+
}
1441+
1442+
let getterBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false, isStatic: isStatic))
1443+
1444+
if !isStatic {
1445+
try getterBuilder.liftParameter(
1446+
param: Parameter(label: nil, name: "_self", type: .swiftHeapObject(className))
1447+
)
1448+
}
1449+
1450+
if isStatic {
1451+
getterBuilder.callStaticProperty(name: callName, returnType: property.type)
1452+
} else {
1453+
getterBuilder.callPropertyGetter(klassName: className, propertyName: callName, returnType: property.type)
1454+
}
1455+
1456+
try getterBuilder.lowerReturnValue(returnType: property.type)
1457+
decls.append(getterBuilder.render(abiName: property.getterAbiName(className: className)))
1458+
1459+
// Generate property setter if not readonly
1460+
if !property.isReadonly {
1461+
let setterBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false, isStatic: isStatic))
1462+
1463+
// Lift parameters based on property type
1464+
if !isStatic {
1465+
// Instance properties need _self parameter
1466+
try setterBuilder.liftParameter(
1467+
param: Parameter(label: nil, name: "_self", type: .swiftHeapObject(className))
1468+
)
1469+
}
1470+
1471+
try setterBuilder.liftParameter(
1472+
param: Parameter(label: "value", name: "value", type: property.type)
1473+
)
1474+
1475+
if isStatic {
1476+
let klassName = callName.components(separatedBy: ".").dropLast().joined(separator: ".")
1477+
setterBuilder.callStaticPropertySetter(klassName: klassName, propertyName: property.name)
1478+
} else {
1479+
setterBuilder.callPropertySetter(klassName: className, propertyName: callName)
1480+
}
1481+
1482+
try setterBuilder.lowerReturnValue(returnType: .void)
1483+
decls.append(setterBuilder.render(abiName: property.setterAbiName(className: className)))
1484+
}
1485+
1486+
return decls
1487+
}
1488+
14531489

14541490
func renderSingleExportedFunction(function: ExportedFunction) throws -> DeclSyntax {
14551491
let builder = ExportedThunkBuilder(effects: function.effects)
@@ -1460,16 +1496,12 @@ public class ExportSwift {
14601496
if function.effects.isStatic, let staticContext = function.staticContext {
14611497
let callName: String
14621498
switch staticContext {
1463-
case .className(let className):
1464-
callName = "\(className).\(function.name)"
1465-
case .enumName(let enumName):
1466-
callName = "\(enumName).\(function.name)"
1499+
case .className(let baseName), .enumName(let baseName):
1500+
callName = "\(baseName).\(function.name)"
14671501
case .namespaceEnum:
1468-
// For namespace enums and explicit namespace, use the namespace property
14691502
if let namespace = function.namespace, !namespace.isEmpty {
14701503
callName = "\(namespace.joined(separator: ".")).\(function.name)"
14711504
} else {
1472-
// Fallback to just the function name for functions without namespace
14731505
callName = function.name
14741506
}
14751507
}
@@ -1569,60 +1601,9 @@ public class ExportSwift {
15691601
// Generate property getters and setters
15701602
for property in klass.properties {
15711603
if property.isStatic {
1572-
// Generate static property getter
1573-
let getterBuilder = ExportedThunkBuilder(
1574-
effects: Effects(isAsync: false, isThrows: false, isStatic: true)
1575-
)
1576-
let staticCallName = "\(klass.swiftCallName).\(property.name)"
1577-
getterBuilder.callStaticProperty(name: staticCallName, returnType: property.type)
1578-
try getterBuilder.lowerReturnValue(returnType: property.type)
1579-
decls.append(getterBuilder.render(abiName: property.getterAbiName(className: klass.name)))
1580-
1581-
// Generate static property setter if not readonly
1582-
if !property.isReadonly {
1583-
let setterBuilder = ExportedThunkBuilder(
1584-
effects: Effects(isAsync: false, isThrows: false, isStatic: true)
1585-
)
1586-
try setterBuilder.liftParameter(
1587-
param: Parameter(label: "value", name: "value", type: property.type)
1588-
)
1589-
setterBuilder.callStaticPropertySetter(
1590-
klassName: klass.swiftCallName,
1591-
propertyName: property.name
1592-
)
1593-
try setterBuilder.lowerReturnValue(returnType: .void)
1594-
decls.append(setterBuilder.render(abiName: property.setterAbiName(className: klass.name)))
1595-
}
1604+
decls.append(contentsOf: try renderSingleExportedProperty(property: property, context: .classStatic(klass: klass)))
15961605
} else {
1597-
// Generate instance property getter
1598-
let getterBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false))
1599-
try getterBuilder.liftParameter(
1600-
param: Parameter(label: nil, name: "_self", type: .swiftHeapObject(klass.name))
1601-
)
1602-
getterBuilder.callPropertyGetter(
1603-
klassName: klass.name,
1604-
propertyName: property.name,
1605-
returnType: property.type
1606-
)
1607-
try getterBuilder.lowerReturnValue(returnType: property.type)
1608-
decls.append(getterBuilder.render(abiName: property.getterAbiName(className: klass.name)))
1609-
1610-
// Generate instance property setter if not readonly
1611-
if !property.isReadonly {
1612-
let setterBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false))
1613-
try setterBuilder.liftParameter(
1614-
param: Parameter(label: nil, name: "_self", type: .swiftHeapObject(klass.name))
1615-
)
1616-
try setterBuilder.liftParameter(
1617-
param: Parameter(label: "value", name: "value", type: property.type)
1618-
)
1619-
setterBuilder.callPropertySetter(
1620-
klassName: klass.name,
1621-
propertyName: property.name
1622-
)
1623-
try setterBuilder.lowerReturnValue(returnType: .void)
1624-
decls.append(setterBuilder.render(abiName: property.setterAbiName(className: klass.name)))
1625-
}
1606+
decls.append(contentsOf: try renderSingleExportedProperty(property: property, context: .classInstance(klass: klass)))
16261607
}
16271608
}
16281609

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,11 +1128,9 @@ extension BridgeJSLink {
11281128
case .enumName(let enumName):
11291129
return try renderEnumStaticFunction(function: function, enumName: enumName)
11301130
case .namespaceEnum:
1131-
// Use function's namespace property for namespace enum
11321131
if let namespace = function.namespace, !namespace.isEmpty {
11331132
return try renderNamespaceFunction(function: function, namespace: namespace.joined(separator: "."))
11341133
} else {
1135-
// Fallback to regular function rendering
11361134
return try renderExportedFunction(function: function)
11371135
}
11381136
}
@@ -1250,7 +1248,7 @@ extension BridgeJSLink {
12501248
// Generate getter assignment
12511249
let getterThunkBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false))
12521250
let getterReturnExpr = try getterThunkBuilder.call(
1253-
abiName: property.getterAbiName(className: enumName),
1251+
abiName: property.getterAbiName(),
12541252
returnType: property.type
12551253
)
12561254

@@ -1278,7 +1276,7 @@ extension BridgeJSLink {
12781276
param: Parameter(label: "value", name: "value", type: property.type)
12791277
)
12801278
_ = try setterThunkBuilder.call(
1281-
abiName: property.setterAbiName(className: enumName),
1279+
abiName: property.setterAbiName(),
12821280
returnType: .void
12831281
)
12841282

@@ -1321,7 +1319,7 @@ extension BridgeJSLink {
13211319
// Use the last component of namespace as the className for ABI name generation
13221320
let className = namespacePath.components(separatedBy: ".").last ?? namespacePath
13231321
let getterReturnExpr = try getterThunkBuilder.call(
1324-
abiName: property.getterAbiName(className: className),
1322+
abiName: property.getterAbiName(),
13251323
returnType: property.type
13261324
)
13271325

@@ -1351,7 +1349,7 @@ extension BridgeJSLink {
13511349
param: Parameter(label: "value", name: "value", type: property.type)
13521350
)
13531351
_ = try setterThunkBuilder.call(
1354-
abiName: property.setterAbiName(className: className),
1352+
abiName: property.setterAbiName(),
13551353
returnType: .void
13561354
)
13571355

@@ -1488,7 +1486,7 @@ extension BridgeJSLink {
14881486
// Generate static property getter
14891487
let getterThunkBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false))
14901488
let getterReturnExpr = try getterThunkBuilder.call(
1491-
abiName: property.getterAbiName(className: klass.name),
1489+
abiName: property.getterAbiName(),
14921490
returnType: property.type
14931491
)
14941492

@@ -1510,7 +1508,7 @@ extension BridgeJSLink {
15101508
param: Parameter(label: "value", name: "value", type: property.type)
15111509
)
15121510
_ = try setterThunkBuilder.call(
1513-
abiName: property.setterAbiName(className: klass.name),
1511+
abiName: property.setterAbiName(),
15141512
returnType: .void
15151513
)
15161514

0 commit comments

Comments
 (0)