@@ -155,14 +155,43 @@ class ExportSwift {
155
155
abiName = " bjs_ \( className) _ \( name) "
156
156
}
157
157
158
+ guard let effects = collectEffects ( signature: node. signature) else {
159
+ return nil
160
+ }
161
+
158
162
return ExportedFunction (
159
163
name: name,
160
164
abiName: abiName,
161
165
parameters: parameters,
162
- returnType: returnType
166
+ returnType: returnType,
167
+ effects: effects
163
168
)
164
169
}
165
170
171
+ private func collectEffects( signature: FunctionSignatureSyntax ) -> Effects ? {
172
+ let isAsync = signature. effectSpecifiers? . asyncSpecifier != nil
173
+ var isThrows = false
174
+ if let throwsClause: ThrowsClauseSyntax = signature. effectSpecifiers? . throwsClause {
175
+ // Limit the thrown type to JSException for now
176
+ guard let thrownType = throwsClause. type else {
177
+ diagnose (
178
+ node: throwsClause,
179
+ message: " Thrown type is not specified, only JSException is supported for now "
180
+ )
181
+ return nil
182
+ }
183
+ guard thrownType. trimmedDescription == " JSException " else {
184
+ diagnose (
185
+ node: throwsClause,
186
+ message: " Only JSException is supported for thrown type, got \( thrownType. trimmedDescription) "
187
+ )
188
+ return nil
189
+ }
190
+ isThrows = true
191
+ }
192
+ return Effects ( isAsync: isAsync, isThrows: isThrows)
193
+ }
194
+
166
195
override func visit( _ node: InitializerDeclSyntax ) -> SyntaxVisitorContinueKind {
167
196
guard node. attributes. hasJSAttribute ( ) else { return . skipChildren }
168
197
guard case . classBody( let name) = state else {
@@ -180,9 +209,14 @@ class ExportSwift {
180
209
parameters. append ( Parameter ( label: label, name: name, type: type) )
181
210
}
182
211
212
+ guard let effects = collectEffects ( signature: node. signature) else {
213
+ return . skipChildren
214
+ }
215
+
183
216
let constructor = ExportedConstructor (
184
217
abiName: " bjs_ \( name) _init " ,
185
- parameters: parameters
218
+ parameters: parameters,
219
+ effects: effects
186
220
)
187
221
exportedClasses [ name] ? . constructor = constructor
188
222
return . skipChildren
@@ -245,6 +279,8 @@ class ExportSwift {
245
279
246
280
@_extern(wasm, module: " bjs " , name: " swift_js_retain " )
247
281
private func _swift_js_retain(_ ptr: Int32) -> Int32
282
+ @_extern(wasm, module: " bjs " , name: " swift_js_throw " )
283
+ private func _swift_js_throw(_ id: Int32)
248
284
"""
249
285
250
286
func renderSwiftGlue( ) -> String ? {
@@ -268,6 +304,11 @@ class ExportSwift {
268
304
var abiParameterForwardings : [ LabeledExprSyntax ] = [ ]
269
305
var abiParameterSignatures : [ ( name: String , type: WasmCoreType ) ] = [ ]
270
306
var abiReturnType : WasmCoreType ?
307
+ let effects : Effects
308
+
309
+ init ( effects: Effects ) {
310
+ self . effects = effects
311
+ }
271
312
272
313
func liftParameter( param: Parameter ) {
273
314
switch param. type {
@@ -350,35 +391,40 @@ class ExportSwift {
350
391
}
351
392
}
352
393
353
- func call( name: String , returnType: BridgeType ) {
394
+ private func renderCallStatement( callee: ExprSyntax , returnType: BridgeType ) -> StmtSyntax {
395
+ var callExpr : ExprSyntax =
396
+ " \( raw: callee) ( \( raw: abiParameterForwardings. map { $0. description } . joined ( separator: " , " ) ) ) "
397
+ if effects. isAsync {
398
+ callExpr = ExprSyntax ( AwaitExprSyntax ( awaitKeyword: . keyword( . await ) , expression: callExpr) )
399
+ }
400
+ if effects. isThrows {
401
+ callExpr = ExprSyntax (
402
+ TryExprSyntax (
403
+ tryKeyword: . keyword( . try ) . with ( \. trailingTrivia, . space) ,
404
+ expression: callExpr
405
+ )
406
+ )
407
+ }
354
408
let retMutability = returnType == . string ? " var " : " let "
355
- let callExpr : ExprSyntax =
356
- " \( raw: name) ( \( raw: abiParameterForwardings. map { $0. description } . joined ( separator: " , " ) ) ) "
357
409
if returnType == . void {
358
- body . append ( " \( raw: callExpr) " )
410
+ return StmtSyntax ( " \( raw: callExpr) " )
359
411
} else {
360
- body. append (
361
- """
362
- \( raw: retMutability) ret = \( raw: callExpr)
363
- """
364
- )
412
+ return StmtSyntax ( " \( raw: retMutability) ret = \( raw: callExpr) " )
365
413
}
366
414
}
367
415
416
+ func call( name: String , returnType: BridgeType ) {
417
+ let stmt = renderCallStatement ( callee: " \( raw: name) " , returnType: returnType)
418
+ body. append ( CodeBlockItemSyntax ( item: . stmt( stmt) ) )
419
+ }
420
+
368
421
func callMethod( klassName: String , methodName: String , returnType: BridgeType ) {
369
422
let _selfParam = self . abiParameterForwardings. removeFirst ( )
370
- let retMutability = returnType == . string ? " var " : " let "
371
- let callExpr : ExprSyntax =
372
- " \( raw: _selfParam) . \( raw: methodName) ( \( raw: abiParameterForwardings. map { $0. description } . joined ( separator: " , " ) ) ) "
373
- if returnType == . void {
374
- body. append ( " \( raw: callExpr) " )
375
- } else {
376
- body. append (
377
- """
378
- \( raw: retMutability) ret = \( raw: callExpr)
379
- """
380
- )
381
- }
423
+ let stmt = renderCallStatement (
424
+ callee: " \( raw: _selfParam) . \( raw: methodName) " ,
425
+ returnType: returnType
426
+ )
427
+ body. append ( CodeBlockItemSyntax ( item: . stmt( stmt) ) )
382
428
}
383
429
384
430
func lowerReturnValue( returnType: BridgeType ) {
@@ -440,19 +486,54 @@ class ExportSwift {
440
486
}
441
487
442
488
func render( abiName: String ) -> DeclSyntax {
489
+ let body : CodeBlockItemListSyntax
490
+ if effects. isThrows {
491
+ body = """
492
+ do {
493
+ \( CodeBlockItemListSyntax ( self . body) )
494
+ } catch let error {
495
+ if let error = error.thrownValue.object {
496
+ withExtendedLifetime(error) {
497
+ _swift_js_throw(Int32(bitPattern: $0.id))
498
+ }
499
+ } else {
500
+ let jsError = JSError(message: String(describing: error))
501
+ withExtendedLifetime(jsError.jsObject) {
502
+ _swift_js_throw(Int32(bitPattern: $0.id))
503
+ }
504
+ }
505
+ \( raw: returnPlaceholderStmt ( ) )
506
+ }
507
+ """
508
+ } else {
509
+ body = CodeBlockItemListSyntax ( self . body)
510
+ }
443
511
return """
444
512
@_expose(wasm, " \( raw: abiName) " )
445
513
@_cdecl( " \( raw: abiName) " )
446
514
public func _ \( raw: abiName) ( \( raw: parameterSignature ( ) ) ) -> \( raw: returnSignature ( ) ) {
447
- \( CodeBlockItemListSyntax ( body) )
515
+ \( body)
448
516
}
449
517
"""
450
518
}
451
519
520
+ private func returnPlaceholderStmt( ) -> String {
521
+ switch abiReturnType {
522
+ case . i32: return " return 0 "
523
+ case . i64: return " return 0 "
524
+ case . f32: return " return 0.0 "
525
+ case . f64: return " return 0.0 "
526
+ case . pointer: return " return UnsafeMutableRawPointer(bitPattern: -1) "
527
+ case . none: return " return "
528
+ }
529
+ }
530
+
452
531
func parameterSignature( ) -> String {
453
- abiParameterSignatures. map { " \( $0. name) : \( $0. type. swiftType) " } . joined (
454
- separator: " , "
455
- )
532
+ var nameAndType : [ ( name: String , abiType: String ) ] = [ ]
533
+ for (name, type) in abiParameterSignatures {
534
+ nameAndType. append ( ( name, type. swiftType) )
535
+ }
536
+ return nameAndType. map { " \( $0. name) : \( $0. abiType) " } . joined ( separator: " , " )
456
537
}
457
538
458
539
func returnSignature( ) -> String {
@@ -461,7 +542,7 @@ class ExportSwift {
461
542
}
462
543
463
544
func renderSingleExportedFunction( function: ExportedFunction ) -> DeclSyntax {
464
- let builder = ExportedThunkBuilder ( )
545
+ let builder = ExportedThunkBuilder ( effects : function . effects )
465
546
for param in function. parameters {
466
547
builder. liftParameter ( param: param)
467
548
}
@@ -520,7 +601,7 @@ class ExportSwift {
520
601
func renderSingleExportedClass( klass: ExportedClass ) -> [ DeclSyntax ] {
521
602
var decls : [ DeclSyntax ] = [ ]
522
603
if let constructor = klass. constructor {
523
- let builder = ExportedThunkBuilder ( )
604
+ let builder = ExportedThunkBuilder ( effects : constructor . effects )
524
605
for param in constructor. parameters {
525
606
builder. liftParameter ( param: param)
526
607
}
@@ -529,7 +610,7 @@ class ExportSwift {
529
610
decls. append ( builder. render ( abiName: constructor. abiName) )
530
611
}
531
612
for method in klass. methods {
532
- let builder = ExportedThunkBuilder ( )
613
+ let builder = ExportedThunkBuilder ( effects : method . effects )
533
614
builder. liftParameter (
534
615
param: Parameter ( label: nil , name: " _self " , type: . swiftHeapObject( klass. name) )
535
616
)
0 commit comments