@@ -155,14 +155,43 @@ class ExportSwift {
155155 abiName = " bjs_ \( className) _ \( name) "
156156 }
157157
158+ guard let effects = collectEffects ( signature: node. signature) else {
159+ return nil
160+ }
161+
158162 return ExportedFunction (
159163 name: name,
160164 abiName: abiName,
161165 parameters: parameters,
162- returnType: returnType
166+ returnType: returnType,
167+ effects: effects
163168 )
164169 }
165170
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+
166195 override func visit( _ node: InitializerDeclSyntax ) -> SyntaxVisitorContinueKind {
167196 guard node. attributes. hasJSAttribute ( ) else { return . skipChildren }
168197 guard case . classBody( let name) = state else {
@@ -180,9 +209,14 @@ class ExportSwift {
180209 parameters. append ( Parameter ( label: label, name: name, type: type) )
181210 }
182211
212+ guard let effects = collectEffects ( signature: node. signature) else {
213+ return . skipChildren
214+ }
215+
183216 let constructor = ExportedConstructor (
184217 abiName: " bjs_ \( name) _init " ,
185- parameters: parameters
218+ parameters: parameters,
219+ effects: effects
186220 )
187221 exportedClasses [ name] ? . constructor = constructor
188222 return . skipChildren
@@ -245,6 +279,8 @@ class ExportSwift {
245279
246280 @_extern(wasm, module: " bjs " , name: " swift_js_retain " )
247281 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)
248284 """
249285
250286 func renderSwiftGlue( ) -> String ? {
@@ -268,6 +304,11 @@ class ExportSwift {
268304 var abiParameterForwardings : [ LabeledExprSyntax ] = [ ]
269305 var abiParameterSignatures : [ ( name: String , type: WasmCoreType ) ] = [ ]
270306 var abiReturnType : WasmCoreType ?
307+ let effects : Effects
308+
309+ init ( effects: Effects ) {
310+ self . effects = effects
311+ }
271312
272313 func liftParameter( param: Parameter ) {
273314 switch param. type {
@@ -350,35 +391,40 @@ class ExportSwift {
350391 }
351392 }
352393
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+ }
354408 let retMutability = returnType == . string ? " var " : " let "
355- let callExpr : ExprSyntax =
356- " \( raw: name) ( \( raw: abiParameterForwardings. map { $0. description } . joined ( separator: " , " ) ) ) "
357409 if returnType == . void {
358- body . append ( " \( raw: callExpr) " )
410+ return StmtSyntax ( " \( raw: callExpr) " )
359411 } else {
360- body. append (
361- """
362- \( raw: retMutability) ret = \( raw: callExpr)
363- """
364- )
412+ return StmtSyntax ( " \( raw: retMutability) ret = \( raw: callExpr) " )
365413 }
366414 }
367415
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+
368421 func callMethod( klassName: String , methodName: String , returnType: BridgeType ) {
369422 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) ) )
382428 }
383429
384430 func lowerReturnValue( returnType: BridgeType ) {
@@ -440,19 +486,54 @@ class ExportSwift {
440486 }
441487
442488 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+ }
443511 return """
444512 @_expose(wasm, " \( raw: abiName) " )
445513 @_cdecl( " \( raw: abiName) " )
446514 public func _ \( raw: abiName) ( \( raw: parameterSignature ( ) ) ) -> \( raw: returnSignature ( ) ) {
447- \( CodeBlockItemListSyntax ( body) )
515+ \( body)
448516 }
449517 """
450518 }
451519
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+
452531 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: " , " )
456537 }
457538
458539 func returnSignature( ) -> String {
@@ -461,7 +542,7 @@ class ExportSwift {
461542 }
462543
463544 func renderSingleExportedFunction( function: ExportedFunction ) -> DeclSyntax {
464- let builder = ExportedThunkBuilder ( )
545+ let builder = ExportedThunkBuilder ( effects : function . effects )
465546 for param in function. parameters {
466547 builder. liftParameter ( param: param)
467548 }
@@ -520,7 +601,7 @@ class ExportSwift {
520601 func renderSingleExportedClass( klass: ExportedClass ) -> [ DeclSyntax ] {
521602 var decls : [ DeclSyntax ] = [ ]
522603 if let constructor = klass. constructor {
523- let builder = ExportedThunkBuilder ( )
604+ let builder = ExportedThunkBuilder ( effects : constructor . effects )
524605 for param in constructor. parameters {
525606 builder. liftParameter ( param: param)
526607 }
@@ -529,7 +610,7 @@ class ExportSwift {
529610 decls. append ( builder. render ( abiName: constructor. abiName) )
530611 }
531612 for method in klass. methods {
532- let builder = ExportedThunkBuilder ( )
613+ let builder = ExportedThunkBuilder ( effects : method . effects )
533614 builder. liftParameter (
534615 param: Parameter ( label: nil , name: " _self " , type: . swiftHeapObject( klass. name) )
535616 )
0 commit comments