Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3c8726e

Browse files
Merge pull request#417 from swiftwasm/yt/support-class-property
BridgeJS: Add property support
2 parents79a9c1b +8cedac7 commit3c8726e

File tree

20 files changed

+2570
-79
lines changed

20 files changed

+2570
-79
lines changed

‎Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.ExportSwift.json‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@
4747
}
4848
],
4949
"name" :"PlayBridgeJS",
50+
"properties" : [
51+
52+
],
5053
"swiftCallName" :"PlayBridgeJS"
5154
},
5255
{
@@ -117,6 +120,9 @@
117120
}
118121
],
119122
"name" :"PlayBridgeJSOutput",
123+
"properties" : [
124+
125+
],
120126
"swiftCallName" :"PlayBridgeJSOutput"
121127
}
122128
],

‎Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift‎

Lines changed: 146 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,75 @@ public class ExportSwift {
332332
return.skipChildren
333333
}
334334

335+
overridefunc visit(_ node:VariableDeclSyntax)->SyntaxVisitorContinueKind{
336+
guard node.attributes.hasJSAttribute()else{return.skipChildren}
337+
guard case.classBody(let className,let classKey)= stateelse{
338+
diagnose(node: node, message:"@JS var must be inside a @JS class")
339+
return.skipChildren
340+
}
341+
342+
iflet jsAttribute= node.attributes.firstJSAttribute,
343+
extractNamespace(from: jsAttribute)!=nil
344+
{
345+
diagnose(
346+
node: jsAttribute,
347+
message:"Namespace is not supported for property declarations",
348+
hint:"Remove the namespace from @JS attribute"
349+
)
350+
}
351+
352+
// Process each binding (variable declaration)
353+
forbindingin node.bindings{
354+
guardlet pattern= binding.pattern.as(IdentifierPatternSyntax.self)else{
355+
diagnose(node: binding.pattern, message:"Complex patterns not supported for @JS properties")
356+
continue
357+
}
358+
359+
letpropertyName= pattern.identifier.text
360+
361+
guardlet typeAnnotation= binding.typeAnnotationelse{
362+
diagnose(node: binding, message:"@JS property must have explicit type annotation")
363+
continue
364+
}
365+
366+
guardlet propertyType=self.parent.lookupType(for: typeAnnotation.type)else{
367+
diagnoseUnsupportedType(node: typeAnnotation.type, type: typeAnnotation.type.trimmedDescription)
368+
continue
369+
}
370+
371+
// Check if property is readonly
372+
letisLet= node.bindingSpecifier.tokenKind==.keyword(.let)
373+
letisGetterOnly= node.bindings.contains(where:{
374+
switch $0.accessorBlock?.accessors{
375+
case.accessors(let accessors):
376+
// Has accessors - check if it only has a getter (no setter, willSet, or didSet)
377+
return !accessors.contains(where:{ accessorin
378+
lettokenKind= accessor.accessorSpecifier.tokenKind
379+
return tokenKind==.keyword(.set) || tokenKind==.keyword(.willSet)
380+
|| tokenKind==.keyword(.didSet)
381+
})
382+
case.getter:
383+
// Has only a getter block
384+
returntrue
385+
casenil:
386+
// No accessor block - this is a stored property, not readonly
387+
returnfalse
388+
}
389+
})
390+
letisReadonly= isLet || isGetterOnly
391+
392+
letexportedProperty=ExportedProperty(
393+
name: propertyName,
394+
type: propertyType,
395+
isReadonly: isReadonly
396+
)
397+
398+
exportedClassByName[classKey]?.properties.append(exportedProperty)
399+
}
400+
401+
return.skipChildren
402+
}
403+
335404
overridefunc visit(_ node:ClassDeclSyntax)->SyntaxVisitorContinueKind{
336405
letname= node.name.text
337406

@@ -359,6 +428,7 @@ public class ExportSwift {
359428
swiftCallName: swiftCallName,
360429
constructor:nil,
361430
methods:[],
431+
properties:[],
362432
namespace: effectiveNamespace
363433
)
364434
letuniqueKey=classKey(name: name, namespace: effectiveNamespace)
@@ -689,7 +759,8 @@ public class ExportSwift {
689759

690760
classExportedThunkBuilder{
691761
varbody:[CodeBlockItemSyntax]=[]
692-
varabiParameterForwardings:[LabeledExprSyntax]=[]
762+
varliftedParameterExprs:[ExprSyntax]=[]
763+
varparameters:[Parameter]=[]
693764
varabiParameterSignatures:[(name:String, type:WasmCoreType)]=[]
694765
varabiReturnType:WasmCoreType?
695766
leteffects:Effects
@@ -708,38 +779,19 @@ public class ExportSwift {
708779
}
709780

710781
func liftParameter(param:Parameter){
782+
parameters.append(param)
711783
switch param.type{
712784
case.bool:
713-
abiParameterForwardings.append(
714-
LabeledExprSyntax(
715-
label: param.label,
716-
expression:ExprSyntax("\(raw: param.name) == 1")
717-
)
718-
)
785+
liftedParameterExprs.append(ExprSyntax("\(raw: param.name) == 1"))
719786
abiParameterSignatures.append((param.name,.i32))
720787
case.int:
721-
abiParameterForwardings.append(
722-
LabeledExprSyntax(
723-
label: param.label,
724-
expression:ExprSyntax("\(raw: param.type.swiftType)(\(raw: param.name))")
725-
)
726-
)
788+
liftedParameterExprs.append(ExprSyntax("\(raw: param.type.swiftType)(\(raw: param.name))"))
727789
abiParameterSignatures.append((param.name,.i32))
728790
case.float:
729-
abiParameterForwardings.append(
730-
LabeledExprSyntax(
731-
label: param.label,
732-
expression:ExprSyntax("\(raw: param.name)")
733-
)
734-
)
791+
liftedParameterExprs.append(ExprSyntax("\(raw: param.name)"))
735792
abiParameterSignatures.append((param.name,.f32))
736793
case.double:
737-
abiParameterForwardings.append(
738-
LabeledExprSyntax(
739-
label: param.label,
740-
expression:ExprSyntax("\(raw: param.name)")
741-
)
742-
)
794+
liftedParameterExprs.append(ExprSyntax("\(raw: param.name)"))
743795
abiParameterSignatures.append((param.name,.f64))
744796
case.string:
745797
letbytesLabel="\(param.name)Bytes"
@@ -751,21 +803,11 @@ public class ExportSwift {
751803
}
752804
"""
753805
append(prepare)
754-
abiParameterForwardings.append(
755-
LabeledExprSyntax(
756-
label: param.label,
757-
expression:ExprSyntax("\(raw: param.name)")
758-
)
759-
)
806+
liftedParameterExprs.append(ExprSyntax("\(raw: param.name)"))
760807
abiParameterSignatures.append((bytesLabel,.i32))
761808
abiParameterSignatures.append((lengthLabel,.i32))
762809
case.caseEnum(let enumName):
763-
abiParameterForwardings.append(
764-
LabeledExprSyntax(
765-
label: param.label,
766-
expression:ExprSyntax("\(raw: enumName)(bridgeJSRawValue:\(raw: param.name))!")
767-
)
768-
)
810+
liftedParameterExprs.append(ExprSyntax("\(raw: enumName)(bridgeJSRawValue:\(raw: param.name))!"))
769811
abiParameterSignatures.append((param.name,.i32))
770812
case.rawValueEnum(let enumName,let rawType):
771813
if rawType==.string{
@@ -778,12 +820,7 @@ public class ExportSwift {
778820
}
779821
"""
780822
append(prepare)
781-
abiParameterForwardings.append(
782-
LabeledExprSyntax(
783-
label: param.label,
784-
expression:ExprSyntax("\(raw: enumName)(rawValue:\(raw: param.name))!")
785-
)
786-
)
823+
liftedParameterExprs.append(ExprSyntax("\(raw: enumName)(rawValue:\(raw: param.name))!"))
787824
abiParameterSignatures.append((bytesLabel,.i32))
788825
abiParameterSignatures.append((lengthLabel,.i32))
789826
}else{
@@ -802,12 +839,7 @@ public class ExportSwift {
802839
conversionExpr="\(enumName)(rawValue:\(rawType.rawValue)(\(param.name)))!"
803840
}
804841

805-
abiParameterForwardings.append(
806-
LabeledExprSyntax(
807-
label: param.label,
808-
expression:ExprSyntax(stringLiteral: conversionExpr)
809-
)
810-
)
842+
liftedParameterExprs.append(ExprSyntax(stringLiteral: conversionExpr))
811843
iflet wasmType= rawType.wasmCoreType{
812844
abiParameterSignatures.append((param.name, wasmType))
813845
}
@@ -817,36 +849,35 @@ public class ExportSwift {
817849
case.namespaceEnum:
818850
break
819851
case.jsObject(nil):
820-
abiParameterForwardings.append(
821-
LabeledExprSyntax(
822-
label: param.label,
823-
expression:ExprSyntax("JSObject(id: UInt32(bitPattern:\(raw: param.name)))")
824-
)
825-
)
852+
liftedParameterExprs.append(ExprSyntax("JSObject(id: UInt32(bitPattern:\(raw: param.name)))"))
826853
abiParameterSignatures.append((param.name,.i32))
827854
case.jsObject(let name):
828-
abiParameterForwardings.append(
829-
LabeledExprSyntax(
830-
label: param.label,
831-
expression:ExprSyntax("\(raw: name)(takingThis: UInt32(bitPattern:\(raw: param.name)))")
832-
)
855+
liftedParameterExprs.append(
856+
ExprSyntax("\(raw: name)(takingThis: UInt32(bitPattern:\(raw: param.name)))")
833857
)
834858
abiParameterSignatures.append((param.name,.i32))
835859
case.swiftHeapObject:
836860
letobjectExpr:ExprSyntax=
837861
"Unmanaged<\(raw: param.type.swiftType)>.fromOpaque(\(raw: param.name)).takeUnretainedValue()"
838-
abiParameterForwardings.append(
839-
LabeledExprSyntax(label: param.label, expression: objectExpr)
840-
)
862+
liftedParameterExprs.append(objectExpr)
841863
abiParameterSignatures.append((param.name,.pointer))
842864
case.void:
843865
break
844866
}
845867
}
846868

869+
privatefunc removeFirstLiftedParameter()->(parameter:Parameter, expr:ExprSyntax){
870+
letparameter= parameters.removeFirst()
871+
letexpr= liftedParameterExprs.removeFirst()
872+
return(parameter, expr)
873+
}
874+
847875
privatefunc renderCallStatement(callee:ExprSyntax, returnType:BridgeType)->CodeBlockItemSyntax{
876+
letlabeledParams=zip(parameters, liftedParameterExprs).map{ param, exprin
877+
LabeledExprSyntax(label: param.label, expression: expr)
878+
}
848879
varcallExpr:ExprSyntax=
849-
"\(raw: callee)(\(raw:abiParameterForwardings.map{ $0.description}.joined(separator:",")))"
880+
"\(raw: callee)(\(raw:labeledParams.map{ $0.description}.joined(separator:",")))"
850881
if effects.isAsync{
851882
callExpr=ExprSyntax(
852883
AwaitExprSyntax(awaitKeyword:.keyword(.await).with(\.trailingTrivia,.space), expression: callExpr)
@@ -884,14 +915,30 @@ public class ExportSwift {
884915
}
885916

886917
func callMethod(klassName:String, methodName:String, returnType:BridgeType){
887-
let_selfParam=self.abiParameterForwardings.removeFirst()
918+
let(_, selfExpr)=removeFirstLiftedParameter()
888919
letitem=renderCallStatement(
889-
callee:"\(raw:_selfParam).\(raw: methodName)",
920+
callee:"\(raw:selfExpr).\(raw: methodName)",
890921
returnType: returnType
891922
)
892923
append(item)
893924
}
894925

926+
func callPropertyGetter(klassName:String, propertyName:String, returnType:BridgeType){
927+
let(_, selfExpr)=removeFirstLiftedParameter()
928+
letretMutability= returnType==.string?"var":"let"
929+
if returnType==.void{
930+
append("\(raw: selfExpr).\(raw: propertyName)")
931+
}else{
932+
append("\(raw: retMutability) ret =\(raw: selfExpr).\(raw: propertyName)")
933+
}
934+
}
935+
936+
func callPropertySetter(klassName:String, propertyName:String){
937+
let(_, selfExpr)=removeFirstLiftedParameter()
938+
let(_, newValueExpr)=removeFirstLiftedParameter()
939+
append("\(raw: selfExpr).\(raw: propertyName) =\(raw: newValueExpr)")
940+
}
941+
895942
func lowerReturnValue(returnType:BridgeType){
896943
if effects.isAsync{
897944
// Async functions always return a Promise, which is a JSObject
@@ -1157,6 +1204,39 @@ public class ExportSwift {
11571204
decls.append(builder.render(abiName: method.abiName))
11581205
}
11591206

1207+
// Generate property getters and setters
1208+
forpropertyin klass.properties{
1209+
// Generate getter
1210+
letgetterBuilder=ExportedThunkBuilder(effects:Effects(isAsync:false, isThrows:false))
1211+
getterBuilder.liftParameter(
1212+
param:Parameter(label:nil, name:"_self", type:.swiftHeapObject(klass.name))
1213+
)
1214+
getterBuilder.callPropertyGetter(
1215+
klassName: klass.name,
1216+
propertyName: property.name,
1217+
returnType: property.type
1218+
)
1219+
getterBuilder.lowerReturnValue(returnType: property.type)
1220+
decls.append(getterBuilder.render(abiName: property.getterAbiName(className: klass.name)))
1221+
1222+
// Generate setter if property is not readonly
1223+
if !property.isReadonly{
1224+
letsetterBuilder=ExportedThunkBuilder(effects:Effects(isAsync:false, isThrows:false))
1225+
setterBuilder.liftParameter(
1226+
param:Parameter(label:nil, name:"_self", type:.swiftHeapObject(klass.name))
1227+
)
1228+
setterBuilder.liftParameter(
1229+
param:Parameter(label:"value", name:"value", type: property.type)
1230+
)
1231+
setterBuilder.callPropertySetter(
1232+
klassName: klass.name,
1233+
propertyName: property.name
1234+
)
1235+
setterBuilder.lowerReturnValue(returnType:.void)
1236+
decls.append(setterBuilder.render(abiName: property.setterAbiName(className: klass.name)))
1237+
}
1238+
}
1239+
11601240
do{
11611241
decls.append(
11621242
"""

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp