Skip to content

Commit e144554

Browse files
committed
BridgeJS: Fix constructor and negative numbers support
BridgeJS: Clean up BridgeJS: Simplified syntax for defaults in .js
1 parent 451c248 commit e144554

File tree

14 files changed

+1035
-259
lines changed

14 files changed

+1035
-259
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 53 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -243,50 +243,20 @@ public class ExportSwift {
243243
return .null
244244
}
245245

246-
if let stringLiteral = expr.as(StringLiteralExprSyntax.self),
247-
let segment = stringLiteral.segments.first?.as(StringSegmentSyntax.self),
248-
type.matches(against: .string)
249-
{
250-
return .string(segment.content.text)
251-
}
252-
253-
if let boolLiteral = expr.as(BooleanLiteralExprSyntax.self),
254-
type.matches(against: .bool)
255-
{
256-
return .bool(boolLiteral.literal.text == "true")
257-
}
258-
259-
if let intLiteral = expr.as(IntegerLiteralExprSyntax.self),
260-
let intValue = Int(intLiteral.literal.text),
261-
type.matches(against: .int)
262-
{
263-
return .int(intValue)
264-
}
265-
266-
if let floatLiteral = expr.as(FloatLiteralExprSyntax.self) {
267-
if type.matches(against: .float),
268-
let floatValue = Float(floatLiteral.literal.text)
269-
{
270-
return .float(floatValue)
271-
}
272-
if type.matches(against: .double),
273-
let doubleValue = Double(floatLiteral.literal.text)
274-
{
275-
return .double(doubleValue)
276-
}
277-
}
278-
279246
if let memberExpr = expr.as(MemberAccessExprSyntax.self),
280247
let enumValue = extractEnumCaseValue(from: memberExpr, type: type)
281248
{
282249
return enumValue
283250
}
284251

285-
// Constructor calls (e.g., Greeter(name: "John"))
286252
if let funcCall = expr.as(FunctionCallExprSyntax.self) {
287253
return extractConstructorDefaultValue(from: funcCall, type: type)
288254
}
289255

256+
if let literalValue = extractLiteralValue(from: expr, type: type) {
257+
return literalValue
258+
}
259+
290260
diagnose(
291261
node: expr,
292262
message: "Unsupported default parameter value expression",
@@ -300,7 +270,6 @@ public class ExportSwift {
300270
from funcCall: FunctionCallExprSyntax,
301271
type: BridgeType
302272
) -> DefaultValue? {
303-
// Extract class name
304273
guard let calledExpr = funcCall.calledExpression.as(DeclReferenceExprSyntax.self) else {
305274
diagnose(
306275
node: funcCall,
@@ -311,8 +280,6 @@ public class ExportSwift {
311280
}
312281

313282
let className = calledExpr.baseName.text
314-
315-
// Verify type matches
316283
let expectedClassName: String?
317284
switch type {
318285
case .swiftHeapObject(let name):
@@ -337,17 +304,13 @@ public class ExportSwift {
337304
return nil
338305
}
339306

340-
// Handle parameterless constructor
341307
if funcCall.arguments.isEmpty {
342308
return .object(className)
343309
}
344310

345-
// Extract arguments for constructor with parameters
346311
var constructorArgs: [DefaultValue] = []
347312
for argument in funcCall.arguments {
348-
// Recursively extract the argument's default value
349-
// For now, only support literals in constructor arguments
350-
guard let argValue = extractConstructorArgumentValue(from: argument.expression) else {
313+
guard let argValue = extractLiteralValue(from: argument.expression) else {
351314
diagnose(
352315
node: argument.expression,
353316
message: "Constructor argument must be a literal value",
@@ -362,42 +325,64 @@ public class ExportSwift {
362325
return .objectWithArguments(className, constructorArgs)
363326
}
364327

365-
/// Extracts a literal value from an expression for use in constructor arguments
366-
private func extractConstructorArgumentValue(from expr: ExprSyntax) -> DefaultValue? {
367-
// String literals
328+
/// Extracts a literal value from an expression with optional type checking
329+
private func extractLiteralValue(from expr: ExprSyntax, type: BridgeType? = nil) -> DefaultValue? {
330+
if expr.is(NilLiteralExprSyntax.self) {
331+
return .null
332+
}
333+
368334
if let stringLiteral = expr.as(StringLiteralExprSyntax.self),
369335
let segment = stringLiteral.segments.first?.as(StringSegmentSyntax.self)
370336
{
371-
return .string(segment.content.text)
337+
let value = DefaultValue.string(segment.content.text)
338+
if let type = type, !type.isCompatibleWith(.string) {
339+
return nil
340+
}
341+
return value
372342
}
373343

374-
// Boolean literals
375344
if let boolLiteral = expr.as(BooleanLiteralExprSyntax.self) {
376-
return .bool(boolLiteral.literal.text == "true")
345+
let value = DefaultValue.bool(boolLiteral.literal.text == "true")
346+
if let type = type, !type.isCompatibleWith(.bool) {
347+
return nil
348+
}
349+
return value
350+
}
351+
352+
var numericExpr = expr
353+
var isNegative = false
354+
if let prefixExpr = expr.as(PrefixOperatorExprSyntax.self),
355+
prefixExpr.operator.text == "-"
356+
{
357+
numericExpr = prefixExpr.expression
358+
isNegative = true
377359
}
378360

379-
// Integer literals
380-
if let intLiteral = expr.as(IntegerLiteralExprSyntax.self),
361+
if let intLiteral = numericExpr.as(IntegerLiteralExprSyntax.self),
381362
let intValue = Int(intLiteral.literal.text)
382363
{
383-
return .int(intValue)
364+
let value = DefaultValue.int(isNegative ? -intValue : intValue)
365+
if let type = type, !type.isCompatibleWith(.int) {
366+
return nil
367+
}
368+
return value
384369
}
385370

386-
// Float literals
387-
if let floatLiteral = expr.as(FloatLiteralExprSyntax.self) {
371+
if let floatLiteral = numericExpr.as(FloatLiteralExprSyntax.self) {
388372
if let floatValue = Float(floatLiteral.literal.text) {
389-
return .float(floatValue)
373+
let value = DefaultValue.float(isNegative ? -floatValue : floatValue)
374+
if type == nil || type?.isCompatibleWith(.float) == true {
375+
return value
376+
}
390377
}
391378
if let doubleValue = Double(floatLiteral.literal.text) {
392-
return .double(doubleValue)
379+
let value = DefaultValue.double(isNegative ? -doubleValue : doubleValue)
380+
if type == nil || type?.isCompatibleWith(.double) == true {
381+
return value
382+
}
393383
}
394384
}
395385

396-
// nil literal
397-
if expr.is(NilLiteralExprSyntax.self) {
398-
return .null
399-
}
400-
401386
return nil
402387
}
403388

@@ -885,7 +870,7 @@ public class ExportSwift {
885870
swiftCallName: swiftCallName,
886871
explicitAccessControl: explicitAccessControl,
887872
cases: [], // Will be populated in visit(EnumCaseDeclSyntax)
888-
rawType: rawType,
873+
rawType: SwiftEnumRawType(rawType),
889874
namespace: effectiveNamespace,
890875
emitStyle: emitStyle,
891876
staticMethods: [],
@@ -923,9 +908,7 @@ public class ExportSwift {
923908

924909
if case .tsEnum = emitStyle {
925910
// Check for Bool raw type limitation
926-
if let raw = exportedEnum.rawType,
927-
let rawEnum = SwiftEnumRawType.from(raw), rawEnum == .bool
928-
{
911+
if exportedEnum.rawType == .bool {
929912
diagnose(
930913
node: jsAttribute,
931914
message: "TypeScript enum style is not supported for Bool raw-value enums",
@@ -1180,7 +1163,7 @@ public class ExportSwift {
11801163
return Constants.supportedRawTypes.contains(typeName)
11811164
}?.type.trimmedDescription
11821165

1183-
if let rawTypeString, let rawType = SwiftEnumRawType.from(rawTypeString) {
1166+
if let rawType = SwiftEnumRawType(rawTypeString) {
11841167
return .rawValueEnum(swiftCallName, rawType)
11851168
} else {
11861169
let hasAnyCases = enumDecl.memberBlock.members.contains { member in
@@ -2160,12 +2143,13 @@ extension WithModifiersSyntax {
21602143
}
21612144

21622145
fileprivate extension BridgeType {
2163-
func matches(against expected: BridgeType) -> Bool {
2164-
switch (self, expected) {
2146+
/// Returns true if a value of `expectedType` can be assigned to this type.
2147+
func isCompatibleWith(_ expectedType: BridgeType) -> Bool {
2148+
switch (self, expectedType) {
21652149
case let (lhs, rhs) where lhs == rhs:
21662150
return true
2167-
case (.optional(let wrapped), expected):
2168-
return wrapped == expected
2151+
case (.optional(let wrapped), expectedType):
2152+
return wrapped == expectedType
21692153
default:
21702154
return false
21712155
}

0 commit comments

Comments
 (0)