@@ -152,6 +152,255 @@ public class ExportSwift {
152
152
)
153
153
}
154
154
155
+ /// Detects whether given expression is supported as default parameter value
156
+ private func isSupportedDefaultValueExpression( _ initClause: InitializerClauseSyntax ) -> Bool {
157
+ let expression = initClause. value
158
+
159
+ // Function calls are checked later in extractDefaultValue (as constructors are allowed)
160
+ if expression. is ( ArrayExprSyntax . self) { return false }
161
+ if expression. is ( DictionaryExprSyntax . self) { return false }
162
+ if expression. is ( BinaryOperatorExprSyntax . self) { return false }
163
+ if expression. is ( ClosureExprSyntax . self) { return false }
164
+
165
+ // Method call chains (e.g., obj.foo())
166
+ if let memberExpression = expression. as ( MemberAccessExprSyntax . self) ,
167
+ memberExpression. base? . is ( FunctionCallExprSyntax . self) == true
168
+ {
169
+ return false
170
+ }
171
+
172
+ return true
173
+ }
174
+
175
+ /// Extract enum case value from member access expression
176
+ private func extractEnumCaseValue(
177
+ from memberExpr: MemberAccessExprSyntax ,
178
+ type: BridgeType
179
+ ) -> DefaultValue ? {
180
+ let caseName = memberExpr. declName. baseName. text
181
+
182
+ let enumName : String ?
183
+ switch type {
184
+ case . caseEnum( let name) , . rawValueEnum( let name, _) , . associatedValueEnum( let name) :
185
+ enumName = name
186
+ case . optional( let wrappedType) :
187
+ switch wrappedType {
188
+ case . caseEnum( let name) , . rawValueEnum( let name, _) , . associatedValueEnum( let name) :
189
+ enumName = name
190
+ default :
191
+ return nil
192
+ }
193
+ default :
194
+ return nil
195
+ }
196
+
197
+ guard let enumName = enumName else { return nil }
198
+
199
+ if memberExpr. base == nil {
200
+ return . enumCase( enumName, caseName)
201
+ }
202
+
203
+ if let baseExpr = memberExpr. base? . as ( DeclReferenceExprSyntax . self) {
204
+ let baseName = baseExpr. baseName. text
205
+ let lastComponent = enumName. split ( separator: " . " ) . last. map ( String . init) ?? enumName
206
+ if baseName == enumName || baseName == lastComponent {
207
+ return . enumCase( enumName, caseName)
208
+ }
209
+ }
210
+
211
+ return nil
212
+ }
213
+
214
+ /// Extracts default value from parameter's default value clause
215
+ private func extractDefaultValue(
216
+ from defaultClause: InitializerClauseSyntax ? ,
217
+ type: BridgeType
218
+ ) -> DefaultValue ? {
219
+ guard let defaultClause = defaultClause else {
220
+ return nil
221
+ }
222
+
223
+ if !isSupportedDefaultValueExpression( defaultClause) {
224
+ diagnose (
225
+ node: defaultClause,
226
+ message: " Complex default parameter expressions are not supported " ,
227
+ hint: " Use simple literal values (e.g., \" text \" , 42, true, nil) or simple constants "
228
+ )
229
+ return nil
230
+ }
231
+
232
+ let expr = defaultClause. value
233
+
234
+ if expr. is ( NilLiteralExprSyntax . self) {
235
+ guard case . optional( _) = type else {
236
+ diagnose (
237
+ node: expr,
238
+ message: " nil is only valid for optional parameters " ,
239
+ hint: " Make the parameter optional by adding ? to the type "
240
+ )
241
+ return nil
242
+ }
243
+ return . null
244
+ }
245
+
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
+
279
+ if let memberExpr = expr. as ( MemberAccessExprSyntax . self) ,
280
+ let enumValue = extractEnumCaseValue ( from: memberExpr, type: type)
281
+ {
282
+ return enumValue
283
+ }
284
+
285
+ // Constructor calls (e.g., Greeter(name: "John"))
286
+ if let funcCall = expr. as ( FunctionCallExprSyntax . self) {
287
+ return extractConstructorDefaultValue ( from: funcCall, type: type)
288
+ }
289
+
290
+ diagnose (
291
+ node: expr,
292
+ message: " Unsupported default parameter value expression " ,
293
+ hint: " Use simple literal values like \" text \" , 42, true, false, nil, or enum cases like .caseName "
294
+ )
295
+ return nil
296
+ }
297
+
298
+ /// Extracts default value from a constructor call expression
299
+ private func extractConstructorDefaultValue(
300
+ from funcCall: FunctionCallExprSyntax ,
301
+ type: BridgeType
302
+ ) -> DefaultValue ? {
303
+ // Extract class name
304
+ guard let calledExpr = funcCall. calledExpression. as ( DeclReferenceExprSyntax . self) else {
305
+ diagnose (
306
+ node: funcCall,
307
+ message: " Complex constructor expressions are not supported " ,
308
+ hint: " Use a simple constructor call like ClassName() or ClassName(arg: value) "
309
+ )
310
+ return nil
311
+ }
312
+
313
+ let className = calledExpr. baseName. text
314
+
315
+ // Verify type matches
316
+ let expectedClassName : String ?
317
+ switch type {
318
+ case . swiftHeapObject( let name) :
319
+ expectedClassName = name. split ( separator: " . " ) . last. map ( String . init)
320
+ case . optional( . swiftHeapObject( let name) ) :
321
+ expectedClassName = name. split ( separator: " . " ) . last. map ( String . init)
322
+ default :
323
+ diagnose (
324
+ node: funcCall,
325
+ message: " Constructor calls are only supported for class types " ,
326
+ hint: " Parameter type should be a Swift class "
327
+ )
328
+ return nil
329
+ }
330
+
331
+ guard let expectedClassName = expectedClassName, className == expectedClassName else {
332
+ diagnose (
333
+ node: funcCall,
334
+ message: " Constructor class name ' \( className) ' doesn't match parameter type " ,
335
+ hint: " Ensure the constructor matches the parameter type "
336
+ )
337
+ return nil
338
+ }
339
+
340
+ // Handle parameterless constructor
341
+ if funcCall. arguments. isEmpty {
342
+ return . object( className)
343
+ }
344
+
345
+ // Extract arguments for constructor with parameters
346
+ var constructorArgs : [ DefaultValue ] = [ ]
347
+ 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 {
351
+ diagnose (
352
+ node: argument. expression,
353
+ message: " Constructor argument must be a literal value " ,
354
+ hint: " Use simple literals like \" text \" , 42, true, false in constructor arguments "
355
+ )
356
+ return nil
357
+ }
358
+
359
+ constructorArgs. append ( argValue)
360
+ }
361
+
362
+ return . objectWithArguments( className, constructorArgs)
363
+ }
364
+
365
+ /// Extracts a literal value from an expression for use in constructor arguments
366
+ private func extractConstructorArgumentValue( from expr: ExprSyntax ) -> DefaultValue ? {
367
+ // String literals
368
+ if let stringLiteral = expr. as ( StringLiteralExprSyntax . self) ,
369
+ let segment = stringLiteral. segments. first? . as ( StringSegmentSyntax . self)
370
+ {
371
+ return . string( segment. content. text)
372
+ }
373
+
374
+ // Boolean literals
375
+ if let boolLiteral = expr. as ( BooleanLiteralExprSyntax . self) {
376
+ return . bool( boolLiteral. literal. text == " true " )
377
+ }
378
+
379
+ // Integer literals
380
+ if let intLiteral = expr. as ( IntegerLiteralExprSyntax . self) ,
381
+ let intValue = Int ( intLiteral. literal. text)
382
+ {
383
+ return . int( intValue)
384
+ }
385
+
386
+ // Float literals
387
+ if let floatLiteral = expr. as ( FloatLiteralExprSyntax . self) {
388
+ if let floatValue = Float ( floatLiteral. literal. text) {
389
+ return . float( floatValue)
390
+ }
391
+ if let doubleValue = Double ( floatLiteral. literal. text) {
392
+ return . double( doubleValue)
393
+ }
394
+ }
395
+
396
+ // nil literal
397
+ if expr. is ( NilLiteralExprSyntax . self) {
398
+ return . null
399
+ }
400
+
401
+ return nil
402
+ }
403
+
155
404
override func visit( _ node: FunctionDeclSyntax ) -> SyntaxVisitorContinueKind {
156
405
guard node. attributes. hasJSAttribute ( ) else {
157
406
return . skipChildren
@@ -252,7 +501,10 @@ public class ExportSwift {
252
501
253
502
let name = param. secondName? . text ?? param. firstName. text
254
503
let label = param. firstName. text
255
- parameters. append ( Parameter ( label: label, name: name, type: type) )
504
+
505
+ let defaultValue = extractDefaultValue ( from: param. defaultValue, type: type)
506
+
507
+ parameters. append ( Parameter ( label: label, name: name, type: type, defaultValue: defaultValue) )
256
508
}
257
509
let returnType : BridgeType
258
510
if let returnClause = node. signature. returnClause {
@@ -409,7 +661,10 @@ public class ExportSwift {
409
661
}
410
662
let name = param. secondName? . text ?? param. firstName. text
411
663
let label = param. firstName. text
412
- parameters. append ( Parameter ( label: label, name: name, type: type) )
664
+
665
+ let defaultValue = extractDefaultValue ( from: param. defaultValue, type: type)
666
+
667
+ parameters. append ( Parameter ( label: label, name: name, type: type, defaultValue: defaultValue) )
413
668
}
414
669
415
670
guard let effects = collectEffects ( signature: node. signature) else {
@@ -1903,3 +2158,16 @@ extension WithModifiersSyntax {
1903
2158
}
1904
2159
}
1905
2160
}
2161
+
2162
+ fileprivate extension BridgeType {
2163
+ func matches( against expected: BridgeType ) -> Bool {
2164
+ switch ( self , expected) {
2165
+ case let ( lhs, rhs) where lhs == rhs:
2166
+ return true
2167
+ case ( . optional( let wrapped) , expected) :
2168
+ return wrapped == expected
2169
+ default :
2170
+ return false
2171
+ }
2172
+ }
2173
+ }
0 commit comments