From b0c806fdfb97f8a2217ce9b51eb30a8136710af6 Mon Sep 17 00:00:00 2001 From: Nike Date: Wed, 18 Dec 2024 14:32:09 -0500 Subject: [PATCH 01/14] Initial commit for branch --- .../parse_compound_declaration.dart | 10 ++++++++++ .../lib/src/parser/parsers/parse_declarations.dart | 1 + 2 files changed, 11 insertions(+) diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart index cf3e9a27a6..0940833db9 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart @@ -8,6 +8,7 @@ import '../../../ast/declarations/compounds/class_declaration.dart'; import '../../../ast/declarations/compounds/members/initializer_declaration.dart'; import '../../../ast/declarations/compounds/members/method_declaration.dart'; import '../../../ast/declarations/compounds/members/property_declaration.dart'; +import '../../../ast/declarations/compounds/protocol_declaration.dart'; import '../../../ast/declarations/compounds/struct_declaration.dart'; import '../../_core/parsed_symbolgraph.dart'; import '../../_core/utils.dart'; @@ -107,3 +108,12 @@ StructDeclaration parseStructDeclaration( symbolgraph, ); } + +// This won't work as there's more for a protocol declaration +// Placing this here as placeholder declaration +ProtocolDeclaration parseProtocolDeclaration( + ParsedSymbol protocolSymbol, + ParsedSymbolgraph symbolgraph +) { + return _parseCompoundDeclaration(protocolSymbol, ProtocolDeclaration.new, symbolgraph); +} \ No newline at end of file diff --git a/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart b/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart index 36b74c4f4d..ff2bf50eb7 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart @@ -56,6 +56,7 @@ Declaration parseDeclaration( 'swift.init' => parseInitializerDeclaration(symbolJson, symbolgraph), 'swift.func' => parseGlobalFunctionDeclaration(symbolJson, symbolgraph), 'swift.var' => parseGlobalVariableDeclaration(symbolJson, symbolgraph), + 'swift.protocol' => parseProtocolDeclaration(parsedSymbol, symbolgraph), _ => throw Exception( 'Symbol of type $symbolType is not implemented yet.', ), From 6f6d50f56df6c50fc7cf68b65dfb942cac8255ef Mon Sep 17 00:00:00 2001 From: Nike Date: Wed, 18 Dec 2024 15:21:29 -0500 Subject: [PATCH 02/14] implemented parsing basic protocols with inheritance (conformance) --- .../compounds/protocol_declaration.dart | 17 ++- .../src/parser/_core/parsed_symbolgraph.dart | 4 + .../parse_compound_declaration.dart | 119 +++++++++++++++++- 3 files changed, 138 insertions(+), 2 deletions(-) diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart index 197b5ee6df..28e6c3da5f 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart @@ -4,13 +4,14 @@ import '../../_core/interfaces/compound_declaration.dart'; import '../../_core/interfaces/nestable_declaration.dart'; +import '../../_core/interfaces/objc_annotatable.dart'; import '../../_core/shared/referred_type.dart'; import 'members/initializer_declaration.dart'; import 'members/method_declaration.dart'; import 'members/property_declaration.dart'; /// Describes the declaration of a Swift protocol. -class ProtocolDeclaration implements CompoundDeclaration { +class ProtocolDeclaration implements CompoundDeclaration, ObjCAnnotatable { @override String id; @@ -23,9 +24,20 @@ class ProtocolDeclaration implements CompoundDeclaration { @override covariant List methods; + /// Only present if indicated with `@objc` + @override + List optionalProperties; + + /// Only present if indicated with `@objc` + @override + List optionalMethods; + @override List> conformedProtocols; + @override + bool hasObjCAnnotation; + @override List typeParams; @@ -46,7 +58,10 @@ class ProtocolDeclaration implements CompoundDeclaration { required this.initializers, required this.conformedProtocols, required this.typeParams, + this.hasObjCAnnotation = false, this.nestingParent, this.nestedDeclarations = const [], + this.optionalMethods = const [], + this.optionalProperties = const [], }); } diff --git a/pkgs/swift2objc/lib/src/parser/_core/parsed_symbolgraph.dart b/pkgs/swift2objc/lib/src/parser/_core/parsed_symbolgraph.dart index e980107196..88684dc665 100644 --- a/pkgs/swift2objc/lib/src/parser/_core/parsed_symbolgraph.dart +++ b/pkgs/swift2objc/lib/src/parser/_core/parsed_symbolgraph.dart @@ -35,6 +35,10 @@ class ParsedRelation { } enum ParsedRelationKind { + requirementOf, + defaultImplementationOf, + optionalRequirementOf, + conformsTo, memberOf; static final _supportedRelationKindsMap = { diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart index 0940833db9..27ecfa3f4a 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import '../../../ast/_core/interfaces/compound_declaration.dart'; +import '../../../ast/_core/interfaces/declaration.dart'; import '../../../ast/_core/interfaces/nestable_declaration.dart'; import '../../../ast/declarations/compounds/class_declaration.dart'; import '../../../ast/declarations/compounds/members/initializer_declaration.dart'; @@ -111,9 +112,125 @@ StructDeclaration parseStructDeclaration( // This won't work as there's more for a protocol declaration // Placing this here as placeholder declaration +// TODO: Implement extensions before adding support for default implementations + // 5. protocol func with reimpl in extension -> requirementOf + // and defaultImplementationOf, swift.method + // 6. protocol var with reimpl in extension -> requirementOf + // and defaultImplementationOf, swift.property, +// TODO: Replace generics to associatedType and implement ProtocolDeclaration parseProtocolDeclaration( ParsedSymbol protocolSymbol, ParsedSymbolgraph symbolgraph ) { - return _parseCompoundDeclaration(protocolSymbol, ProtocolDeclaration.new, symbolgraph); + final compoundId = parseSymbolId(protocolSymbol.json); + final compoundRelations = symbolgraph.relations[compoundId] ?? []; + + // construct protocol + final protocol = ProtocolDeclaration( + id: compoundId, name: parseSymbolName(protocolSymbol.json), + properties: [], + methods: [], + initializers: [], + conformedProtocols: [], + typeParams: [] + ); + + // get optional member declarations if any + final optionalMemberDeclarations = compoundRelations.where((relation) { + final isOptionalRequirementRelation = + relation.kind == ParsedRelationKind.optionalRequirementOf; + final isMemberOfProtocol = relation.targetId == compoundId; + return isMemberOfProtocol && isOptionalRequirementRelation; + }).map((relation) { + final memberSymbol = symbolgraph.symbols[relation.sourceId]; + if (memberSymbol == null) { + return null; + } + return tryParseDeclaration(memberSymbol, symbolgraph); + }) + .nonNulls + .dedupeBy((decl) => decl.id) + .toList() + ; + + // get normal member declarations + final memberDeclarations = compoundRelations.where((relation) { + final isOptionalRequirementRelation = + relation.kind == ParsedRelationKind.requirementOf + && relation.kind != ParsedRelationKind.optionalRequirementOf; + final isMemberOfProtocol = relation.targetId == compoundId; + return isMemberOfProtocol && isOptionalRequirementRelation; + }).map((relation) { + final memberSymbol = symbolgraph.symbols[relation.sourceId]; + if (memberSymbol == null) { + return null; + } + return tryParseDeclaration(memberSymbol, symbolgraph); + }) + .nonNulls + .dedupeBy((decl) => decl.id) + .toList() + ; + + // get conformed protocols + final conformedProtocolDeclarations = compoundRelations.where((relation) { + final isOptionalRequirementRelation = + relation.kind == ParsedRelationKind.conformsTo; + final isMemberOfProtocol = relation.targetId == compoundId; + return isMemberOfProtocol && isOptionalRequirementRelation; + }).map((relation) { + final memberSymbol = symbolgraph.symbols[relation.sourceId]; + if (memberSymbol == null) { + return null; + } + var conformedDecl = tryParseDeclaration(memberSymbol, symbolgraph) as ProtocolDeclaration; + return conformedDecl.asDeclaredType; + }) + .nonNulls + .dedupeBy((decl) => decl.id) + .toList() + ; + + // If the protocol has optional members, it must be annotated with `@objc` + if (optionalMemberDeclarations.isNotEmpty) { + protocol.hasObjCAnnotation = true; + } + + protocol.methods.addAll( + memberDeclarations + .whereType() + .dedupeBy((m) => m.fullName), + ); + + protocol.properties.addAll( + memberDeclarations.whereType(), + ); + + protocol.optionalMethods.addAll( + optionalMemberDeclarations + .whereType() + .dedupeBy((m) => m.fullName), + ); + + protocol.optionalProperties.addAll( + optionalMemberDeclarations.whereType(), + ); + + protocol.conformedProtocols.addAll( + conformedProtocolDeclarations + ); + + protocol.initializers.addAll( + memberDeclarations + .whereType() + .dedupeBy((m) => m.fullName), + ); + + protocol.nestedDeclarations.addAll( + memberDeclarations.whereType(), + ); + + protocol.nestedDeclarations.fillNestingParents(protocol); + + return protocol; } \ No newline at end of file From fa00ec49c089c38fe92f8a360703b7c0017ebd7b Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Sat, 18 Jan 2025 22:16:45 -0600 Subject: [PATCH 03/14] added support for associated type --- .../src/ast/_core/shared/referred_type.dart | 27 +++++++++++++++++++ .../members/associated_type_declaration.dart | 25 +++++++++++++++++ .../compounds/protocol_declaration.dart | 7 +++++ .../parse_associated_type_declaration.dart | 15 +++++++++++ .../parse_compound_declaration.dart | 10 +++++++ .../parser/parsers/parse_declarations.dart | 5 ++++ .../lib/src/parser/parsers/parse_type.dart | 1 + 7 files changed, 90 insertions(+) create mode 100644 pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart create mode 100644 pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_associated_type_declaration.dart diff --git a/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart b/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart index 9bbd4080b4..9cedb8f4a3 100644 --- a/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart +++ b/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import '../../ast_node.dart'; +import '../../declarations/compounds/protocol_declaration.dart'; import '../interfaces/declaration.dart'; import '../interfaces/nestable_declaration.dart'; import '../interfaces/objc_annotatable.dart'; @@ -71,6 +72,7 @@ class DeclaredType extends AstNode /// Describes a reference of a generic type /// (e.g a method return type `T` within a generic class). +/// TODO(): Add Type Constrains and extend to support associated types class GenericType extends AstNode implements ReferredType { final String id; @@ -97,6 +99,31 @@ class GenericType extends AstNode implements ReferredType { void visit(Visitation visitation) => visitation.visitGenericType(this); } +class AssociatedType extends AstNode implements ReferredType { + final String id; + + final String name; + + + @override + bool get isObjCRepresentable => false; + + @override + String get swiftType => name; + + @override + bool sameAs(ReferredType other) => other is AssociatedType && other.id == id; + + AssociatedType({ + required this.id, + required this.name, + }); + + @override + String toString() => name; +} + + /// An optional type, like Dart's nullable types. Eg `String?`. class OptionalType extends AstNode implements ReferredType { final ReferredType child; diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart new file mode 100644 index 0000000000..58cf08d727 --- /dev/null +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart @@ -0,0 +1,25 @@ + +import '../../../_core/interfaces/declaration.dart'; +import '../../../_core/shared/referred_type.dart'; +import '../../../ast_node.dart'; +import '../protocol_declaration.dart'; + + +class AssociatedTypeDeclaration extends AstNode implements Declaration { + @override + String id; + + @override + String name; + + AssociatedTypeDeclaration({ + required this.id, + required this.name, + }); +} + +extension AsAssociatedType on T { + AssociatedType asType() => AssociatedType( + id: id, name: name + ); +} \ No newline at end of file diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart index ce2b16d160..5276d33856 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart @@ -7,6 +7,7 @@ import '../../_core/interfaces/nestable_declaration.dart'; import '../../_core/interfaces/objc_annotatable.dart'; import '../../_core/shared/referred_type.dart'; import '../../ast_node.dart'; +import 'members/associated_type_declaration.dart'; import 'members/initializer_declaration.dart'; import 'members/method_declaration.dart'; import 'members/property_declaration.dart'; @@ -29,6 +30,11 @@ class ProtocolDeclaration extends AstNode implements CompoundDeclaration, ObjCAn @override List optionalProperties; + /// Associated types used with this declaration + /// They are similar to generic types + /// but only designated for protocol declarations + List associatedTypes; + /// Only present if indicated with `@objc` @override List optionalMethods; @@ -59,6 +65,7 @@ class ProtocolDeclaration extends AstNode implements CompoundDeclaration, ObjCAn required this.initializers, required this.conformedProtocols, required this.typeParams, + this.associatedTypes = const [], this.hasObjCAnnotation = false, this.nestingParent, this.nestedDeclarations = const [], diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_associated_type_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_associated_type_declaration.dart new file mode 100644 index 0000000000..8b191af360 --- /dev/null +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_associated_type_declaration.dart @@ -0,0 +1,15 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../../../ast/declarations/compounds/members/associated_type_declaration.dart'; +import '../../_core/json.dart'; +import '../../_core/parsed_symbolgraph.dart'; +import '../../_core/utils.dart'; + +AssociatedTypeDeclaration parseAssociatedTypeDeclaration(Json symbolJson, ParsedSymbolgraph symbolGraph) { + final id = parseSymbolId(symbolJson); + final name = parseSymbolName(symbolJson); + + return AssociatedTypeDeclaration(id: id, name: name); +} diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart index 27ecfa3f4a..bb5de27453 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart @@ -6,6 +6,7 @@ import '../../../ast/_core/interfaces/compound_declaration.dart'; import '../../../ast/_core/interfaces/declaration.dart'; import '../../../ast/_core/interfaces/nestable_declaration.dart'; import '../../../ast/declarations/compounds/class_declaration.dart'; +import '../../../ast/declarations/compounds/members/associated_type_declaration.dart'; import '../../../ast/declarations/compounds/members/initializer_declaration.dart'; import '../../../ast/declarations/compounds/members/method_declaration.dart'; import '../../../ast/declarations/compounds/members/property_declaration.dart'; @@ -196,6 +197,13 @@ ProtocolDeclaration parseProtocolDeclaration( protocol.hasObjCAnnotation = true; } + protocol.associatedTypes.addAll( + memberDeclarations + .whereType() + .map((decl) => decl.asType()) + .dedupeBy((m) => m.name) + ); + protocol.methods.addAll( memberDeclarations .whereType() @@ -232,5 +240,7 @@ ProtocolDeclaration parseProtocolDeclaration( protocol.nestedDeclarations.fillNestingParents(protocol); + + return protocol; } \ No newline at end of file diff --git a/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart b/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart index 6a7bbca3eb..6a9d268f63 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart @@ -5,8 +5,12 @@ import 'package:logging/logging.dart'; import '../../ast/_core/interfaces/declaration.dart'; +import '../../ast/_core/shared/referred_type.dart'; +import '../../ast/declarations/compounds/members/associated_type_declaration.dart'; +import '../_core/json.dart'; import '../_core/parsed_symbolgraph.dart'; import '../_core/utils.dart'; +import 'declaration_parsers/parse_associated_type_declaration.dart'; import 'declaration_parsers/parse_compound_declaration.dart'; import 'declaration_parsers/parse_function_declaration.dart'; import 'declaration_parsers/parse_initializer_declaration.dart'; @@ -57,6 +61,7 @@ Declaration parseDeclaration( 'swift.func' => parseGlobalFunctionDeclaration(symbolJson, symbolgraph), 'swift.var' => parseGlobalVariableDeclaration(symbolJson, symbolgraph), 'swift.protocol' => parseProtocolDeclaration(parsedSymbol, symbolgraph), + 'swift.associatedtype' => parseAssociatedTypeDeclaration(symbolJson, symbolgraph), _ => throw Exception( 'Symbol of type $symbolType is not implemented yet.', ), diff --git a/pkgs/swift2objc/lib/src/parser/parsers/parse_type.dart b/pkgs/swift2objc/lib/src/parser/parsers/parse_type.dart index 6e7a4231f3..1efa4b3cc1 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/parse_type.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/parse_type.dart @@ -10,6 +10,7 @@ import '../_core/parsed_symbolgraph.dart'; import '../_core/token_list.dart'; import 'parse_declarations.dart'; + /// Parse a type from a list of Json fragments. /// /// Returns the parsed type, and a Json slice of the remaining fragments that From be6b8c83b04d0c6e1402fdb9e09377c87e668d71 Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Wed, 22 Jan 2025 22:35:46 -0600 Subject: [PATCH 04/14] completed Protocol Declaration parsing --- .../members/associated_type_declaration.dart | 2 -- .../declarations/compounds/protocol_declaration.dart | 9 +++------ .../parse_compound_declaration.dart | 11 +---------- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart index 58cf08d727..e9054b7198 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart @@ -2,8 +2,6 @@ import '../../../_core/interfaces/declaration.dart'; import '../../../_core/shared/referred_type.dart'; import '../../../ast_node.dart'; -import '../protocol_declaration.dart'; - class AssociatedTypeDeclaration extends AstNode implements Declaration { @override diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart index 5276d33856..bb9770cbf7 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart @@ -7,7 +7,6 @@ import '../../_core/interfaces/nestable_declaration.dart'; import '../../_core/interfaces/objc_annotatable.dart'; import '../../_core/shared/referred_type.dart'; import '../../ast_node.dart'; -import 'members/associated_type_declaration.dart'; import 'members/initializer_declaration.dart'; import 'members/method_declaration.dart'; import 'members/property_declaration.dart'; @@ -27,18 +26,16 @@ class ProtocolDeclaration extends AstNode implements CompoundDeclaration, ObjCAn covariant List methods; /// Only present if indicated with `@objc` - @override List optionalProperties; + /// Only present if indicated with `@objc` + List optionalMethods; + /// Associated types used with this declaration /// They are similar to generic types /// but only designated for protocol declarations List associatedTypes; - /// Only present if indicated with `@objc` - @override - List optionalMethods; - @override List> conformedProtocols; diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart index bb5de27453..74276051de 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart @@ -111,14 +111,7 @@ StructDeclaration parseStructDeclaration( ); } -// This won't work as there's more for a protocol declaration -// Placing this here as placeholder declaration -// TODO: Implement extensions before adding support for default implementations - // 5. protocol func with reimpl in extension -> requirementOf - // and defaultImplementationOf, swift.method - // 6. protocol var with reimpl in extension -> requirementOf - // and defaultImplementationOf, swift.property, -// TODO: Replace generics to associatedType and implement +// TODO(https://github.com/dart-lang/native/issues/1815): Implement extensions before adding support for default implementations ProtocolDeclaration parseProtocolDeclaration( ParsedSymbol protocolSymbol, ParsedSymbolgraph symbolgraph @@ -240,7 +233,5 @@ ProtocolDeclaration parseProtocolDeclaration( protocol.nestedDeclarations.fillNestingParents(protocol); - - return protocol; } \ No newline at end of file From 1e2f8559384057bbc5bc69d9c6c3d293319d8595 Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Wed, 22 Jan 2025 23:59:04 -0600 Subject: [PATCH 05/14] completed setting up tests Tests succeed and necessary TODOs have been placed --- .../src/ast/_core/shared/referred_type.dart | 10 +- .../members/associated_type_declaration.dart | 15 +- .../compounds/protocol_declaration.dart | 14 +- .../parse_associated_type_declaration.dart | 55 +- .../parse_compound_declaration.dart | 136 +- .../parse_function_declaration.dart | 3 + .../parse_variable_declaration.dart | 1 + .../parser/parsers/parse_declarations.dart | 6 +- .../lib/src/parser/parsers/parse_type.dart | 1 - .../test/unit/json/parse_protocol_symbol.json | 2128 +++++++++++++++++ .../test/unit/parse_protocol_test.dart | 100 + 11 files changed, 2372 insertions(+), 97 deletions(-) create mode 100644 pkgs/swift2objc/test/unit/json/parse_protocol_symbol.json create mode 100644 pkgs/swift2objc/test/unit/parse_protocol_test.dart diff --git a/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart b/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart index 9cedb8f4a3..8adf8d17b8 100644 --- a/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart +++ b/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart @@ -104,26 +104,24 @@ class AssociatedType extends AstNode implements ReferredType { final String name; - @override bool get isObjCRepresentable => false; @override String get swiftType => name; + List> conformedProtocols; + @override bool sameAs(ReferredType other) => other is AssociatedType && other.id == id; - AssociatedType({ - required this.id, - required this.name, - }); + AssociatedType( + {required this.id, required this.name, required this.conformedProtocols}); @override String toString() => name; } - /// An optional type, like Dart's nullable types. Eg `String?`. class OptionalType extends AstNode implements ReferredType { final ReferredType child; diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart index e9054b7198..555ec9c2ca 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/associated_type_declaration.dart @@ -1,7 +1,7 @@ - import '../../../_core/interfaces/declaration.dart'; import '../../../_core/shared/referred_type.dart'; import '../../../ast_node.dart'; +import '../protocol_declaration.dart'; class AssociatedTypeDeclaration extends AstNode implements Declaration { @override @@ -10,14 +10,13 @@ class AssociatedTypeDeclaration extends AstNode implements Declaration { @override String name; - AssociatedTypeDeclaration({ - required this.id, - required this.name, - }); + List> conformedProtocols; + + AssociatedTypeDeclaration( + {required this.id, required this.name, required this.conformedProtocols}); } extension AsAssociatedType on T { AssociatedType asType() => AssociatedType( - id: id, name: name - ); -} \ No newline at end of file + id: id, name: name, conformedProtocols: conformedProtocols); +} diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart index bb9770cbf7..23e14a5d14 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart @@ -12,7 +12,8 @@ import 'members/method_declaration.dart'; import 'members/property_declaration.dart'; /// Describes the declaration of a Swift protocol. -class ProtocolDeclaration extends AstNode implements CompoundDeclaration, ObjCAnnotatable { +class ProtocolDeclaration extends AstNode + implements CompoundDeclaration, ObjCAnnotatable { @override String id; @@ -32,7 +33,7 @@ class ProtocolDeclaration extends AstNode implements CompoundDeclaration, ObjCAn List optionalMethods; /// Associated types used with this declaration - /// They are similar to generic types + /// They are similar to generic types /// but only designated for protocol declarations List associatedTypes; @@ -62,13 +63,12 @@ class ProtocolDeclaration extends AstNode implements CompoundDeclaration, ObjCAn required this.initializers, required this.conformedProtocols, required this.typeParams, - this.associatedTypes = const [], this.hasObjCAnnotation = false, this.nestingParent, - this.nestedDeclarations = const [], - this.optionalMethods = const [], - this.optionalProperties = const [], - }); + }) : associatedTypes = [], + nestedDeclarations = [], + optionalMethods = [], + optionalProperties = []; @override void visit(Visitation visitation) => diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_associated_type_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_associated_type_declaration.dart index 8b191af360..9309ba8cd0 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_associated_type_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_associated_type_declaration.dart @@ -2,14 +2,63 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import '../../../ast/_core/interfaces/declaration.dart'; +import '../../../ast/_core/shared/referred_type.dart'; import '../../../ast/declarations/compounds/members/associated_type_declaration.dart'; +import '../../../ast/declarations/compounds/protocol_declaration.dart'; import '../../_core/json.dart'; import '../../_core/parsed_symbolgraph.dart'; import '../../_core/utils.dart'; +import '../parse_declarations.dart'; -AssociatedTypeDeclaration parseAssociatedTypeDeclaration(Json symbolJson, ParsedSymbolgraph symbolGraph) { +AssociatedTypeDeclaration parseAssociatedTypeDeclaration( + Json symbolJson, ParsedSymbolgraph symbolGraph) { final id = parseSymbolId(symbolJson); - final name = parseSymbolName(symbolJson); + final name = parseSymbolName(symbolJson); - return AssociatedTypeDeclaration(id: id, name: name); + final conformedProtocols = _parseConformedProtocols(symbolJson, symbolGraph); + + return AssociatedTypeDeclaration( + id: id, name: name, conformedProtocols: conformedProtocols); +} + +List> _parseConformedProtocols( + Json symbolJson, ParsedSymbolgraph symbolGraph) { + final conformDecls = >[]; + + final identifierIndex = symbolJson['declarationFragments'] + .toList() + .indexWhere((t) => + t['kind'].get() == 'identifier' && + t['spelling'].get() == 'Element'); + + if (symbolJson['declarationFragments'].length - 1 > identifierIndex && + symbolJson['declarationFragments'][identifierIndex + 1]['spelling'] + .get() + .trim() == + ':') { + // the associated type contains + final conformList = symbolJson['declarationFragments'] + .toList() + .sublist(identifierIndex + 2); + conformList.removeWhere((t) => t['spelling'].get().trim() == ','); + + // go through and find, then add + for (final proto in conformList) { + final protoId = proto['preciseIdentifier'].get(); + + final protoSymbol = symbolGraph.symbols[protoId]; + + if (protoSymbol == null) { + // return null; + continue; + } + + conformDecls.add( + (tryParseDeclaration(protoSymbol, symbolGraph) as ProtocolDeclaration) + .asDeclaredType); + } + } + + return conformDecls; } diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart index 74276051de..e06cddf8c8 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart @@ -113,89 +113,91 @@ StructDeclaration parseStructDeclaration( // TODO(https://github.com/dart-lang/native/issues/1815): Implement extensions before adding support for default implementations ProtocolDeclaration parseProtocolDeclaration( - ParsedSymbol protocolSymbol, - ParsedSymbolgraph symbolgraph -) { + ParsedSymbol protocolSymbol, ParsedSymbolgraph symbolgraph) { final compoundId = parseSymbolId(protocolSymbol.json); final compoundRelations = symbolgraph.relations[compoundId] ?? []; // construct protocol final protocol = ProtocolDeclaration( - id: compoundId, name: parseSymbolName(protocolSymbol.json), - properties: [], - methods: [], - initializers: [], - conformedProtocols: [], - typeParams: [] - ); + id: compoundId, + name: parseSymbolName(protocolSymbol.json), + properties: [], + methods: [], + initializers: [], + conformedProtocols: [], + typeParams: []); // get optional member declarations if any - final optionalMemberDeclarations = compoundRelations.where((relation) { - final isOptionalRequirementRelation = - relation.kind == ParsedRelationKind.optionalRequirementOf; - final isMemberOfProtocol = relation.targetId == compoundId; - return isMemberOfProtocol && isOptionalRequirementRelation; - }).map((relation) { - final memberSymbol = symbolgraph.symbols[relation.sourceId]; - if (memberSymbol == null) { - return null; - } - return tryParseDeclaration(memberSymbol, symbolgraph); - }) - .nonNulls - .dedupeBy((decl) => decl.id) - .toList() - ; + final optionalMemberDeclarations = compoundRelations + .where((relation) { + final isOptionalRequirementRelation = + relation.kind == ParsedRelationKind.optionalRequirementOf; + final isMemberOfProtocol = relation.targetId == compoundId; + return isMemberOfProtocol && isOptionalRequirementRelation; + }) + .map((relation) { + final memberSymbol = symbolgraph.symbols[relation.sourceId]; + if (memberSymbol == null) { + return null; + } + return tryParseDeclaration(memberSymbol, symbolgraph); + }) + .nonNulls + .dedupeBy((decl) => decl.id) + .toList(); // get normal member declarations - final memberDeclarations = compoundRelations.where((relation) { - final isOptionalRequirementRelation = - relation.kind == ParsedRelationKind.requirementOf - && relation.kind != ParsedRelationKind.optionalRequirementOf; - final isMemberOfProtocol = relation.targetId == compoundId; - return isMemberOfProtocol && isOptionalRequirementRelation; - }).map((relation) { - final memberSymbol = symbolgraph.symbols[relation.sourceId]; - if (memberSymbol == null) { - return null; - } - return tryParseDeclaration(memberSymbol, symbolgraph); - }) - .nonNulls - .dedupeBy((decl) => decl.id) - .toList() - ; + final memberDeclarations = compoundRelations + .where((relation) { + final isOptionalRequirementRelation = + relation.kind == ParsedRelationKind.requirementOf && + relation.kind != ParsedRelationKind.optionalRequirementOf; + final isMemberOfProtocol = relation.targetId == compoundId; + return isMemberOfProtocol && isOptionalRequirementRelation; + }) + .map((relation) { + final memberSymbol = symbolgraph.symbols[relation.sourceId]; + + if (memberSymbol == null) { + return null; + } + + return tryParseDeclaration(memberSymbol, symbolgraph); + }) + .nonNulls + .dedupeBy((decl) => decl.id) + .toList(); // get conformed protocols - final conformedProtocolDeclarations = compoundRelations.where((relation) { - final isOptionalRequirementRelation = - relation.kind == ParsedRelationKind.conformsTo; - final isMemberOfProtocol = relation.targetId == compoundId; - return isMemberOfProtocol && isOptionalRequirementRelation; - }).map((relation) { - final memberSymbol = symbolgraph.symbols[relation.sourceId]; - if (memberSymbol == null) { - return null; - } - var conformedDecl = tryParseDeclaration(memberSymbol, symbolgraph) as ProtocolDeclaration; - return conformedDecl.asDeclaredType; - }) - .nonNulls - .dedupeBy((decl) => decl.id) - .toList() - ; + final conformedProtocolDeclarations = compoundRelations + .where((relation) { + final isOptionalRequirementRelation = + relation.kind == ParsedRelationKind.conformsTo; + final isMemberOfProtocol = relation.sourceId == compoundId; + return isMemberOfProtocol && isOptionalRequirementRelation; + }) + .map((relation) { + final memberSymbol = symbolgraph.symbols[relation.targetId]; + if (memberSymbol == null) { + return null; + } + var conformedDecl = tryParseDeclaration(memberSymbol, symbolgraph) + as ProtocolDeclaration; + return conformedDecl.asDeclaredType; + }) + .nonNulls + .dedupeBy((decl) => decl.id) + .toList(); // If the protocol has optional members, it must be annotated with `@objc` if (optionalMemberDeclarations.isNotEmpty) { protocol.hasObjCAnnotation = true; } - protocol.associatedTypes.addAll( - memberDeclarations + protocol.associatedTypes.addAll(memberDeclarations .whereType() .map((decl) => decl.asType()) - .dedupeBy((m) => m.name) - ); + .dedupeBy((m) => m.name)); protocol.methods.addAll( memberDeclarations @@ -217,9 +219,7 @@ ProtocolDeclaration parseProtocolDeclaration( optionalMemberDeclarations.whereType(), ); - protocol.conformedProtocols.addAll( - conformedProtocolDeclarations - ); + protocol.conformedProtocols.addAll(conformedProtocolDeclarations); protocol.initializers.addAll( memberDeclarations @@ -234,4 +234,4 @@ ProtocolDeclaration parseProtocolDeclaration( protocol.nestedDeclarations.fillNestingParents(protocol); return protocol; -} \ No newline at end of file +} diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart index 02d705d220..f80c51e5b5 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart @@ -142,6 +142,9 @@ ParsedFunctionInfo parseFunctionInfo( ); } +// TODO(): Function Return Type does not support nested types +// (e.g String.UTF8, Self.Element +// (necessary when making use of protocol associated types)) ReferredType _parseFunctionReturnType( Json methodSymbolJson, ParsedSymbolgraph symbolgraph, diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart index 1877af6c18..4fad7313e2 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart @@ -10,6 +10,7 @@ import '../../_core/parsed_symbolgraph.dart'; import '../../_core/token_list.dart'; import '../../_core/utils.dart'; +// TODO(): Add support for parsing getters and setters in property declarations PropertyDeclaration parsePropertyDeclaration( Json propertySymbolJson, ParsedSymbolgraph symbolgraph, { diff --git a/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart b/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart index 6a9d268f63..b4728bcf9f 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart @@ -5,9 +5,6 @@ import 'package:logging/logging.dart'; import '../../ast/_core/interfaces/declaration.dart'; -import '../../ast/_core/shared/referred_type.dart'; -import '../../ast/declarations/compounds/members/associated_type_declaration.dart'; -import '../_core/json.dart'; import '../_core/parsed_symbolgraph.dart'; import '../_core/utils.dart'; import 'declaration_parsers/parse_associated_type_declaration.dart'; @@ -61,7 +58,8 @@ Declaration parseDeclaration( 'swift.func' => parseGlobalFunctionDeclaration(symbolJson, symbolgraph), 'swift.var' => parseGlobalVariableDeclaration(symbolJson, symbolgraph), 'swift.protocol' => parseProtocolDeclaration(parsedSymbol, symbolgraph), - 'swift.associatedtype' => parseAssociatedTypeDeclaration(symbolJson, symbolgraph), + 'swift.associatedtype' => + parseAssociatedTypeDeclaration(symbolJson, symbolgraph), _ => throw Exception( 'Symbol of type $symbolType is not implemented yet.', ), diff --git a/pkgs/swift2objc/lib/src/parser/parsers/parse_type.dart b/pkgs/swift2objc/lib/src/parser/parsers/parse_type.dart index 1efa4b3cc1..6e7a4231f3 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/parse_type.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/parse_type.dart @@ -10,7 +10,6 @@ import '../_core/parsed_symbolgraph.dart'; import '../_core/token_list.dart'; import 'parse_declarations.dart'; - /// Parse a type from a list of Json fragments. /// /// Returns the parsed type, and a Json slice of the remaining fragments that diff --git a/pkgs/swift2objc/test/unit/json/parse_protocol_symbol.json b/pkgs/swift2objc/test/unit/json/parse_protocol_symbol.json new file mode 100644 index 0000000000..0e67c36a3c --- /dev/null +++ b/pkgs/swift2objc/test/unit/json/parse_protocol_symbol.json @@ -0,0 +1,2128 @@ +{ + "metadata": { + "formatVersion": { + "major": 0, + "minor": 6, + "patch": 0 + }, + "generator": "Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)" + }, + "module": { + "name": "proto", + "platform": { + "architecture": "arm64", + "vendor": "apple", + "operatingSystem": { + "name": "macosx", + "minimumVersion": { + "major": 15, + "minor": 0 + } + } + } + }, + "symbols": [ + { + "kind": { + "identifier": "swift.protocol", + "displayName": "Protocol" + }, + "identifier": { + "precise": "s:5proto12IdentifiableP", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "Identifiable" + ], + "names": { + "title": "Identifiable", + "navigator": [ + { + "kind": "identifier", + "spelling": "Identifiable" + } + ], + "subHeading": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Identifiable" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Identifiable" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 15, + "character": 16 + } + } + }, + { + "kind": { + "identifier": "swift.property", + "displayName": "Instance Property" + }, + "identifier": { + "precise": "s:5proto12IdentifiableP2idSSvp", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "Identifiable", + "id" + ], + "names": { + "title": "id", + "subHeading": [ + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "id" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "id" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + }, + { + "kind": "text", + "spelling": " { " + }, + { + "kind": "keyword", + "spelling": "get" + }, + { + "kind": "text", + "spelling": " }" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 16, + "character": 8 + } + } + }, + { + "kind": { + "identifier": "swift.property", + "displayName": "Instance Property" + }, + "identifier": { + "precise": "s:5proto4UserP5emailSSvp", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "User", + "email" + ], + "names": { + "title": "email", + "subHeading": [ + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "email" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "email" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + }, + { + "kind": "text", + "spelling": " { " + }, + { + "kind": "keyword", + "spelling": "get" + }, + { + "kind": "text", + "spelling": " }" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 24, + "character": 8 + } + } + }, + { + "kind": { + "identifier": "swift.protocol", + "displayName": "Protocol" + }, + "identifier": { + "precise": "c:@M@proto@objc(pl)OptionallyResponds", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "OptionallyResponds" + ], + "names": { + "title": "OptionallyResponds", + "navigator": [ + { + "kind": "identifier", + "spelling": "OptionallyResponds" + } + ], + "subHeading": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "OptionallyResponds" + } + ] + }, + "declarationFragments": [ + { + "kind": "attribute", + "spelling": "@objc" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "OptionallyResponds" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 28, + "character": 22 + } + } + }, + { + "kind": { + "identifier": "swift.property", + "displayName": "Instance Property" + }, + "identifier": { + "precise": "s:5proto9GreetableP4nameSSvp", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "Greetable", + "name" + ], + "names": { + "title": "name", + "subHeading": [ + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "name" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "name" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + }, + { + "kind": "text", + "spelling": " { " + }, + { + "kind": "keyword", + "spelling": "get" + }, + { + "kind": "text", + "spelling": " }" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 3, + "character": 8 + } + } + }, + { + "kind": { + "identifier": "swift.method", + "displayName": "Instance Method" + }, + "identifier": { + "precise": "s:5proto18PrintableStackableP3pop7ElementQzSgyF", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "PrintableStackable", + "pop()" + ], + "names": { + "title": "pop()", + "subHeading": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "pop" + }, + { + "kind": "text", + "spelling": "() -> " + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto18PrintableStackableP7ElementQa" + }, + { + "kind": "text", + "spelling": "?" + } + ] + }, + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "spelling": "Self" + }, + { + "kind": "text", + "spelling": "." + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto18PrintableStackableP7ElementQa" + }, + { + "kind": "text", + "spelling": "?" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "mutating" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "pop" + }, + { + "kind": "text", + "spelling": "() -> " + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto18PrintableStackableP7ElementQa" + }, + { + "kind": "text", + "spelling": "?" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 38, + "character": 18 + } + } + }, + { + "kind": { + "identifier": "swift.protocol", + "displayName": "Protocol" + }, + "identifier": { + "precise": "s:5proto18PrintableStackableP", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "PrintableStackable" + ], + "names": { + "title": "PrintableStackable", + "navigator": [ + { + "kind": "identifier", + "spelling": "PrintableStackable" + } + ], + "subHeading": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "PrintableStackable" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "PrintableStackable" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 35, + "character": 16 + } + } + }, + { + "kind": { + "identifier": "swift.method", + "displayName": "Instance Method" + }, + "identifier": { + "precise": "c:@M@proto@objc(pl)OptionallyResponds(im)optionalMethod", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "OptionallyResponds", + "optionalMethod()" + ], + "names": { + "title": "optionalMethod()", + "subHeading": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "optionalMethod" + }, + { + "kind": "text", + "spelling": "()" + } + ] + }, + "functionSignature": { + "returns": [ + { + "kind": "text", + "spelling": "()" + } + ] + }, + "declarationFragments": [ + { + "kind": "attribute", + "spelling": "@objc" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "optional" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "optionalMethod" + }, + { + "kind": "text", + "spelling": "()" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 29, + "character": 24 + } + } + }, + { + "kind": { + "identifier": "swift.property", + "displayName": "Instance Property" + }, + "identifier": { + "precise": "c:@M@proto@objc(pl)OptionallyResponds(py)response", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "OptionallyResponds", + "response" + ], + "names": { + "title": "response", + "subHeading": [ + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "response" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ] + }, + "declarationFragments": [ + { + "kind": "attribute", + "spelling": "@objc" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "optional" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "response" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + }, + { + "kind": "text", + "spelling": " { " + }, + { + "kind": "keyword", + "spelling": "get" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "set" + }, + { + "kind": "text", + "spelling": " }" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 30, + "character": 23 + } + } + }, + { + "kind": { + "identifier": "swift.method", + "displayName": "Instance Method" + }, + "identifier": { + "precise": "s:5proto18PrintableStackableP4pushyy7ElementQzF", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "PrintableStackable", + "push(_:)" + ], + "names": { + "title": "push(_:)", + "subHeading": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "push" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto18PrintableStackableP7ElementQa" + }, + { + "kind": "text", + "spelling": ")" + } + ] + }, + "functionSignature": { + "parameters": [ + { + "name": "element", + "declarationFragments": [ + { + "kind": "identifier", + "spelling": "element" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto18PrintableStackableP7ElementQa" + } + ] + } + ], + "returns": [ + { + "kind": "text", + "spelling": "()" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "mutating" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "push" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "externalParam", + "spelling": "_" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "element" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto18PrintableStackableP7ElementQa" + }, + { + "kind": "text", + "spelling": ")" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 37, + "character": 18 + } + } + }, + { + "kind": { + "identifier": "swift.method", + "displayName": "Instance Method" + }, + "identifier": { + "precise": "c:@M@proto@objc(pl)OptionallyResponds(im)requiredMethod", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "OptionallyResponds", + "requiredMethod()" + ], + "names": { + "title": "requiredMethod()", + "subHeading": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "requiredMethod" + }, + { + "kind": "text", + "spelling": "()" + } + ] + }, + "functionSignature": { + "returns": [ + { + "kind": "text", + "spelling": "()" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "requiredMethod" + }, + { + "kind": "text", + "spelling": "()" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 31, + "character": 9 + } + } + }, + { + "kind": { + "identifier": "swift.protocol", + "displayName": "Protocol" + }, + "identifier": { + "precise": "s:5proto9GreetableP", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "Greetable" + ], + "names": { + "title": "Greetable", + "navigator": [ + { + "kind": "identifier", + "spelling": "Greetable" + } + ], + "subHeading": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Greetable" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Greetable" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 2, + "character": 16 + } + } + }, + { + "kind": { + "identifier": "swift.method", + "displayName": "Instance Method" + }, + "identifier": { + "precise": "s:5proto9StackableP4pushyy7ElementQzF", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "Stackable", + "push(_:)" + ], + "names": { + "title": "push(_:)", + "subHeading": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "push" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto9StackableP7ElementQa" + }, + { + "kind": "text", + "spelling": ")" + } + ] + }, + "functionSignature": { + "parameters": [ + { + "name": "element", + "declarationFragments": [ + { + "kind": "identifier", + "spelling": "element" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto9StackableP7ElementQa" + } + ] + } + ], + "returns": [ + { + "kind": "text", + "spelling": "()" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "mutating" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "push" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "externalParam", + "spelling": "_" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "element" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto9StackableP7ElementQa" + }, + { + "kind": "text", + "spelling": ")" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 10, + "character": 18 + } + } + }, + { + "kind": { + "identifier": "swift.method", + "displayName": "Instance Method" + }, + "identifier": { + "precise": "s:5proto4UserP11displayInfoSSyF", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "User", + "displayInfo()" + ], + "names": { + "title": "displayInfo()", + "subHeading": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "displayInfo" + }, + { + "kind": "text", + "spelling": "() -> " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ] + }, + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "displayInfo" + }, + { + "kind": "text", + "spelling": "() -> " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 25, + "character": 9 + } + } + }, + { + "kind": { + "identifier": "swift.protocol", + "displayName": "Protocol" + }, + "identifier": { + "precise": "s:5proto9StackableP", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "Stackable" + ], + "names": { + "title": "Stackable", + "navigator": [ + { + "kind": "identifier", + "spelling": "Stackable" + } + ], + "subHeading": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Stackable" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Stackable" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 8, + "character": 16 + } + } + }, + { + "kind": { + "identifier": "swift.protocol", + "displayName": "Protocol" + }, + "identifier": { + "precise": "s:5proto4UserP", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "User" + ], + "names": { + "title": "User", + "navigator": [ + { + "kind": "identifier", + "spelling": "User" + } + ], + "subHeading": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "User" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "User" + }, + { + "kind": "text", + "spelling": " : " + }, + { + "kind": "typeIdentifier", + "spelling": "Identifiable", + "preciseIdentifier": "s:5proto12IdentifiableP" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 19, + "character": 16 + } + } + }, + { + "kind": { + "identifier": "swift.method", + "displayName": "Instance Method" + }, + "identifier": { + "precise": "s:5proto9GreetableP5greetSSyF", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "Greetable", + "greet()" + ], + "names": { + "title": "greet()", + "subHeading": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "greet" + }, + { + "kind": "text", + "spelling": "() -> " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ] + }, + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "greet" + }, + { + "kind": "text", + "spelling": "() -> " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 4, + "character": 9 + } + } + }, + { + "kind": { + "identifier": "swift.type.method", + "displayName": "Type Method" + }, + "identifier": { + "precise": "s:5proto4UserP9configureyyFZ", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "User", + "configure()" + ], + "names": { + "title": "configure()", + "subHeading": [ + { + "kind": "keyword", + "spelling": "static" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "configure" + }, + { + "kind": "text", + "spelling": "()" + } + ] + }, + "functionSignature": { + "returns": [ + { + "kind": "text", + "spelling": "()" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "static" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "configure" + }, + { + "kind": "text", + "spelling": "()" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 21, + "character": 16 + } + } + }, + { + "kind": { + "identifier": "swift.associatedtype", + "displayName": "Associated Type" + }, + "identifier": { + "precise": "s:5proto18PrintableStackableP7ElementQa", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "PrintableStackable", + "Element" + ], + "names": { + "title": "Element", + "subHeading": [ + { + "kind": "keyword", + "spelling": "associatedtype" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Element" + }, + { + "kind": "text", + "spelling": " : " + }, + { + "kind": "typeIdentifier", + "spelling": "Identifiable", + "preciseIdentifier": "s:5proto12IdentifiableP" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "associatedtype" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Element" + }, + { + "kind": "text", + "spelling": " : " + }, + { + "kind": "typeIdentifier", + "spelling": "Identifiable", + "preciseIdentifier": "s:5proto12IdentifiableP" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 36, + "character": 19 + } + } + }, + { + "kind": { + "identifier": "swift.associatedtype", + "displayName": "Associated Type" + }, + "identifier": { + "precise": "s:5proto9StackableP7ElementQa", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "Stackable", + "Element" + ], + "names": { + "title": "Element", + "subHeading": [ + { + "kind": "keyword", + "spelling": "associatedtype" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Element" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "associatedtype" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Element" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 9, + "character": 19 + } + } + }, + { + "kind": { + "identifier": "swift.method", + "displayName": "Instance Method" + }, + "identifier": { + "precise": "s:5proto9StackableP3pop7ElementQzSgyF", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "Stackable", + "pop()" + ], + "names": { + "title": "pop()", + "subHeading": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "pop" + }, + { + "kind": "text", + "spelling": "() -> " + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto9StackableP7ElementQa" + }, + { + "kind": "text", + "spelling": "?" + } + ] + }, + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "spelling": "Self" + }, + { + "kind": "text", + "spelling": "." + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto9StackableP7ElementQa" + }, + { + "kind": "text", + "spelling": "?" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "mutating" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "pop" + }, + { + "kind": "text", + "spelling": "() -> " + }, + { + "kind": "typeIdentifier", + "spelling": "Element", + "preciseIdentifier": "s:5proto9StackableP7ElementQa" + }, + { + "kind": "text", + "spelling": "?" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 11, + "character": 18 + } + } + }, + { + "kind": { + "identifier": "swift.type.property", + "displayName": "Type Property" + }, + "identifier": { + "precise": "s:5proto4UserP17configurationNameSSvpZ", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "User", + "configurationName" + ], + "names": { + "title": "configurationName", + "subHeading": [ + { + "kind": "keyword", + "spelling": "static" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "configurationName" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "static" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "configurationName" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + }, + { + "kind": "text", + "spelling": " { " + }, + { + "kind": "keyword", + "spelling": "get" + }, + { + "kind": "text", + "spelling": " }" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 20, + "character": 15 + } + } + }, + { + "kind": { + "identifier": "swift.property", + "displayName": "Instance Property" + }, + "identifier": { + "precise": "s:5proto4UserP8isActiveSbvp", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "User", + "isActive" + ], + "names": { + "title": "isActive", + "subHeading": [ + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "isActive" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "Bool", + "preciseIdentifier": "s:Sb" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "isActive" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "Bool", + "preciseIdentifier": "s:Sb" + }, + { + "kind": "text", + "spelling": " { " + }, + { + "kind": "keyword", + "spelling": "get" + }, + { + "kind": "text", + "spelling": " }" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 23, + "character": 8 + } + } + }, + { + "kind": { + "identifier": "swift.property", + "displayName": "Instance Property" + }, + "identifier": { + "precise": "s:5proto4UserP12currentStateSSvp", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "User", + "currentState" + ], + "names": { + "title": "currentState", + "subHeading": [ + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "currentState" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "var" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "currentState" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "String", + "preciseIdentifier": "s:SS" + }, + { + "kind": "text", + "spelling": " { " + }, + { + "kind": "keyword", + "spelling": "get" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "set" + }, + { + "kind": "text", + "spelling": " }" + } + ], + "accessLevel": "public", + "location": { + "uri": "file://protocol.swift", + "position": { + "line": 22, + "character": 8 + } + } + } + ], + "relationships": [ + { + "kind": "requirementOf", + "source": "s:5proto12IdentifiableP2idSSvp", + "target": "s:5proto12IdentifiableP" + }, + { + "kind": "requirementOf", + "source": "s:5proto18PrintableStackableP4pushyy7ElementQzF", + "target": "s:5proto18PrintableStackableP" + }, + { + "kind": "optionalRequirementOf", + "source": "c:@M@proto@objc(pl)OptionallyResponds(im)optionalMethod", + "target": "c:@M@proto@objc(pl)OptionallyResponds" + }, + { + "kind": "optionalRequirementOf", + "source": "c:@M@proto@objc(pl)OptionallyResponds(py)response", + "target": "c:@M@proto@objc(pl)OptionallyResponds" + }, + { + "kind": "requirementOf", + "source": "s:5proto4UserP9configureyyFZ", + "target": "s:5proto4UserP" + }, + { + "kind": "requirementOf", + "source": "s:5proto18PrintableStackableP3pop7ElementQzSgyF", + "target": "s:5proto18PrintableStackableP" + }, + { + "kind": "requirementOf", + "source": "c:@M@proto@objc(pl)OptionallyResponds(im)optionalMethod", + "target": "c:@M@proto@objc(pl)OptionallyResponds" + }, + { + "kind": "requirementOf", + "source": "c:@M@proto@objc(pl)OptionallyResponds(py)response", + "target": "c:@M@proto@objc(pl)OptionallyResponds" + }, + { + "kind": "requirementOf", + "source": "s:5proto4UserP12currentStateSSvp", + "target": "s:5proto4UserP" + }, + { + "kind": "requirementOf", + "source": "s:5proto9StackableP7ElementQa", + "target": "s:5proto9StackableP" + }, + { + "kind": "requirementOf", + "source": "s:5proto9GreetableP4nameSSvp", + "target": "s:5proto9GreetableP" + }, + { + "kind": "requirementOf", + "source": "s:5proto4UserP17configurationNameSSvpZ", + "target": "s:5proto4UserP" + }, + { + "kind": "requirementOf", + "source": "s:5proto9StackableP3pop7ElementQzSgyF", + "target": "s:5proto9StackableP" + }, + { + "kind": "requirementOf", + "source": "s:5proto4UserP8isActiveSbvp", + "target": "s:5proto4UserP" + }, + { + "kind": "requirementOf", + "source": "c:@M@proto@objc(pl)OptionallyResponds(im)requiredMethod", + "target": "c:@M@proto@objc(pl)OptionallyResponds" + }, + { + "kind": "requirementOf", + "source": "s:5proto4UserP5emailSSvp", + "target": "s:5proto4UserP" + }, + { + "kind": "requirementOf", + "source": "s:5proto18PrintableStackableP7ElementQa", + "target": "s:5proto18PrintableStackableP" + }, + { + "kind": "requirementOf", + "source": "s:5proto9StackableP4pushyy7ElementQzF", + "target": "s:5proto9StackableP" + }, + { + "kind": "conformsTo", + "source": "s:5proto4UserP", + "target": "s:5proto12IdentifiableP" + }, + { + "kind": "requirementOf", + "source": "s:5proto4UserP11displayInfoSSyF", + "target": "s:5proto4UserP" + }, + { + "kind": "requirementOf", + "source": "s:5proto9GreetableP5greetSSyF", + "target": "s:5proto9GreetableP" + } + ] +} \ No newline at end of file diff --git a/pkgs/swift2objc/test/unit/parse_protocol_test.dart b/pkgs/swift2objc/test/unit/parse_protocol_test.dart new file mode 100644 index 0000000000..d9fe73f003 --- /dev/null +++ b/pkgs/swift2objc/test/unit/parse_protocol_test.dart @@ -0,0 +1,100 @@ +import 'package:path/path.dart' as p; +import 'package:swift2objc/src/ast/declarations/compounds/protocol_declaration.dart'; +import 'package:swift2objc/src/parser/_core/parsed_symbolgraph.dart'; +import 'package:swift2objc/src/parser/_core/utils.dart'; +import 'package:swift2objc/src/parser/parsers/parse_declarations.dart'; +import 'package:swift2objc/src/parser/parsers/parse_relations_map.dart'; +import 'package:swift2objc/src/parser/parsers/parse_symbols_map.dart'; +import 'package:test/test.dart'; + +void main() { + group('Protocol Testing', () { + final jsonFile = + p.join('test', 'unit', 'json', 'parse_protocol_symbol.json'); + final inputJson = readJsonFile(jsonFile); + final symbolgraph = ParsedSymbolgraph( + parseSymbolsMap(inputJson), + parseRelationsMap(inputJson), + ); + final declarations = parseDeclarations(symbolgraph); + + test('Basic Protocols', () { + final declOne = declarations.firstWhere((t) => t.name == 'Greetable') + as ProtocolDeclaration; + + expect(declOne.properties, hasLength(1)); + expect(declOne.methods, hasLength(1)); + + expect(declOne.properties.single.name, equalsIgnoringCase('name')); + + var declMethod = declOne.methods.single; + expect(declMethod.name, equalsIgnoringCase('greet')); + expect(declMethod.returnType.swiftType, equalsIgnoringCase('String')); + }); + + test('Protocols with Static Properties and Methods', () { + final testDecl = declarations.firstWhere((t) => t.name == 'User') + as ProtocolDeclaration; + + expect(testDecl.properties, hasLength(4)); + expect(testDecl.methods, hasLength(2)); + + expect(testDecl.methods.where((m) => m.isStatic), hasLength(1)); + expect(testDecl.properties.where((m) => m.isStatic), hasLength(1)); + + final declProp = testDecl.properties.where((m) => m.isStatic).single; + final declMethod = testDecl.methods.where((m) => m.isStatic).single; + + expect(declProp.name, equalsIgnoringCase('configurationName')); + }); + + test('Nested Protocols', () { + final testDecl = declarations.firstWhere((t) => t.name == 'User') + as ProtocolDeclaration; + + expect(testDecl.conformedProtocols, hasLength(1)); + + final conformedProtocol = testDecl.conformedProtocols.single.declaration; + + expect(conformedProtocol.name, equalsIgnoringCase('Identifiable')); + expect(conformedProtocol.properties, hasLength(1)); + + var conformedProtocolProp = conformedProtocol.properties.single; + expect(conformedProtocolProp.name, equalsIgnoringCase('id')); + }); + + test('Protocols with associated types', () { + final testDecl = declarations.firstWhere((t) => t.name == 'Stackable') + as ProtocolDeclaration; + + expect(testDecl.associatedTypes, hasLength(1)); + expect(testDecl.methods.map((m) => m.name), contains('push')); + + expect( + testDecl.methods + .firstWhere((m) => m.name == 'push') + .returnType + .swiftType, + equalsIgnoringCase('Void')); + }); + + test('Protocols with associated types that conform', () { + final testDecl = + declarations.firstWhere((t) => t.name == 'PrintableStackable') + as ProtocolDeclaration; + + expect(testDecl.associatedTypes, hasLength(1)); + + final associatedType = testDecl.associatedTypes.single; + + expect(associatedType.name, equalsIgnoringCase('Element')); + expect(associatedType.conformedProtocols, hasLength(1)); + + final associatedTypeConformedProtocol = + associatedType.conformedProtocols.single.declaration; + + expect(associatedTypeConformedProtocol.name, + equalsIgnoringCase('Identifiable')); + }); + }); +} From c2c4c6d2354c7b80ca9551389011ef28d40284ee Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Thu, 23 Jan 2025 00:00:52 -0600 Subject: [PATCH 06/14] removed redundant/completed TODO --- pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart b/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart index 8adf8d17b8..e1a16f0b5e 100644 --- a/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart +++ b/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart @@ -72,7 +72,6 @@ class DeclaredType extends AstNode /// Describes a reference of a generic type /// (e.g a method return type `T` within a generic class). -/// TODO(): Add Type Constrains and extend to support associated types class GenericType extends AstNode implements ReferredType { final String id; From 354bb50d15b80b14974ecfc0a6398d969c942f31 Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Thu, 23 Jan 2025 00:15:03 -0600 Subject: [PATCH 07/14] Added related issues for dangling TODOs --- .../parsers/declaration_parsers/parse_function_declaration.dart | 2 +- .../parsers/declaration_parsers/parse_variable_declaration.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart index f80c51e5b5..5357ae032b 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart @@ -142,7 +142,7 @@ ParsedFunctionInfo parseFunctionInfo( ); } -// TODO(): Function Return Type does not support nested types +// TODO(https://github.com/dart-lang/native/issues/1931): Function Return Type does not support nested types // (e.g String.UTF8, Self.Element // (necessary when making use of protocol associated types)) ReferredType _parseFunctionReturnType( diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart index 4fad7313e2..bf1e575e34 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart @@ -10,7 +10,7 @@ import '../../_core/parsed_symbolgraph.dart'; import '../../_core/token_list.dart'; import '../../_core/utils.dart'; -// TODO(): Add support for parsing getters and setters in property declarations +// TODO(https://github.com/dart-lang/native/issues/1932): Add support for parsing getters and setters in property declarations PropertyDeclaration parsePropertyDeclaration( Json propertySymbolJson, ParsedSymbolgraph symbolgraph, { From d75dc8b189a42fc8b1abd425a0302cced3915736 Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Sun, 2 Mar 2025 01:12:06 -0600 Subject: [PATCH 08/14] Search for superclass and inherit, fallback on NSObject if no superclass --- .../swift2objc/lib/src/transformer/transform.dart | 15 +++++++++++++++ .../transformers/transform_compound.dart | 9 ++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/pkgs/swift2objc/lib/src/transformer/transform.dart b/pkgs/swift2objc/lib/src/transformer/transform.dart index 409252c524..1f18cac808 100644 --- a/pkgs/swift2objc/lib/src/transformer/transform.dart +++ b/pkgs/swift2objc/lib/src/transformer/transform.dart @@ -6,16 +6,25 @@ import '../ast/_core/interfaces/compound_declaration.dart'; import '../ast/_core/interfaces/declaration.dart'; import '../ast/_core/interfaces/nestable_declaration.dart'; import '../ast/declarations/compounds/class_declaration.dart'; +import '../ast/declarations/compounds/protocol_declaration.dart'; import '../ast/declarations/compounds/struct_declaration.dart'; import '../ast/declarations/globals/globals.dart'; import '../ast/visitor.dart'; +import '../parser/_core/utils.dart'; import '_core/dependencies.dart'; import '_core/unique_namer.dart'; import 'transformers/transform_compound.dart'; import 'transformers/transform_globals.dart'; +import 'transformers/transform_protocol.dart'; typedef TransformationMap = Map; +extension TransformationMapUtils on TransformationMap { + Declaration? findByOriginalName(String name) { + return this[keys.where((k) => k.name == name).firstOrNull]; + } +} + Set generateDependencies(Iterable decls) => visit(DependencyVisitation(), decls).topLevelDeclarations; @@ -77,6 +86,12 @@ Declaration transformDeclaration( parentNamer, transformationMap, ), + ProtocolDeclaration() => transformProtocol( + declaration, + parentNamer, + transformationMap + ), _ => throw UnimplementedError(), }; } + diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart index 3e079f0f2d..06a17c6d8f 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart @@ -10,6 +10,7 @@ import '../../ast/declarations/built_in/built_in_declaration.dart'; import '../../ast/declarations/compounds/class_declaration.dart'; import '../../ast/declarations/compounds/members/initializer_declaration.dart'; import '../../ast/declarations/compounds/members/property_declaration.dart'; +import '../../ast/declarations/compounds/struct_declaration.dart'; import '../../parser/_core/utils.dart'; import '../_core/unique_namer.dart'; import '../transform.dart'; @@ -30,11 +31,17 @@ ClassDeclaration transformCompound( type: originalCompound.asDeclaredType, ); + final superClass = originalCompound is ClassDeclaration ? + (originalCompound.superClass == null ? null : + transformationMap.findByOriginalName(originalCompound.superClass!.name)) + : null; + final transformedCompound = ClassDeclaration( id: originalCompound.id.addIdSuffix('wrapper'), name: parentNamer.makeUnique('${originalCompound.name}Wrapper'), hasObjCAnnotation: true, - superClass: objectType, + // TODO: superclass can be previous superclass since it will already inherit + superClass: superClass?.asDeclaredType ?? objectType, isWrapper: true, wrappedInstance: wrappedCompoundInstance, wrapperInitializer: _buildWrapperInitializer(wrappedCompoundInstance), From d441639ae9dd6d3641f4f06a391575b3f2ab1966 Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Sun, 2 Mar 2025 01:25:08 -0600 Subject: [PATCH 09/14] Added Protocol Transformation and Generation --- .../members/initializer_declaration.dart | 1 + .../compounds/members/method_declaration.dart | 4 + .../compounds/protocol_declaration.dart | 12 +- .../lib/src/generator/generator.dart | 4 + .../generator/generators/class_generator.dart | 2 + .../generators/protocol_generator.dart | 128 ++++++++++++++++++ .../parse_compound_declaration.dart | 3 +- .../lib/src/transformer/transform.dart | 5 +- .../transformers/transform_compound.dart | 14 +- .../transformers/transform_protocol.dart | 43 ++++++ .../test/integration/protocol_input.swift | 26 ++++ .../test/integration/protocol_output.swift | 28 ++++ .../test/unit/parse_protocol_test.dart | 4 + 13 files changed, 262 insertions(+), 12 deletions(-) create mode 100644 pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart create mode 100644 pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart create mode 100644 pkgs/swift2objc/test/integration/protocol_input.swift create mode 100644 pkgs/swift2objc/test/integration/protocol_output.swift diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/initializer_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/initializer_declaration.dart index ce4bf5685f..94b1fc453a 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/initializer_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/initializer_declaration.dart @@ -13,6 +13,7 @@ import '../../../_core/shared/parameter.dart'; import '../../../ast_node.dart'; /// Describes an initializer for a Swift compound entity (e.g, class, structs) +/// TODO(https://github.com/dart-lang/native/issues/2048): Convenience and Required Initializers class InitializerDeclaration extends AstNode implements Declaration, diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/method_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/method_declaration.dart index 604b313508..a3e9cdbdf2 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/method_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/method_declaration.dart @@ -11,6 +11,7 @@ import '../../../ast_node.dart'; /// Describes a method declaration for a Swift compound entity /// (e.g, class, structs) +/// TODO(https://github.com/dart-lang/native/issues/2049): Add support for private(set) functions class MethodDeclaration extends AstNode implements FunctionDeclaration, ObjCAnnotatable, Overridable { @override @@ -45,6 +46,8 @@ class MethodDeclaration extends AstNode bool isStatic; + bool public; + String get fullName => [ name, for (final p in params) p.name, @@ -55,6 +58,7 @@ class MethodDeclaration extends AstNode required this.name, required this.returnType, required this.params, + this.public = true, this.typeParams = const [], this.hasObjCAnnotation = false, this.statements = const [], diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart index 23e14a5d14..07af645e7e 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart @@ -43,9 +43,6 @@ class ProtocolDeclaration extends AstNode @override bool hasObjCAnnotation; - @override - List typeParams; - @override List initializers; @@ -62,7 +59,6 @@ class ProtocolDeclaration extends AstNode required this.methods, required this.initializers, required this.conformedProtocols, - required this.typeParams, this.hasObjCAnnotation = false, this.nestingParent, }) : associatedTypes = [], @@ -80,9 +76,15 @@ class ProtocolDeclaration extends AstNode visitor.visitAll(properties); visitor.visitAll(methods); visitor.visitAll(conformedProtocols); - visitor.visitAll(typeParams); visitor.visitAll(initializers); visitor.visit(nestingParent); visitor.visitAll(nestedDeclarations); } + + @override + List get typeParams => + throw Exception( + 'Protocols do not have type params: ' + 'Did you mean to use `associatedTypes` instead?' + ); } diff --git a/pkgs/swift2objc/lib/src/generator/generator.dart b/pkgs/swift2objc/lib/src/generator/generator.dart index 86f6a5454a..e6e9f442bf 100644 --- a/pkgs/swift2objc/lib/src/generator/generator.dart +++ b/pkgs/swift2objc/lib/src/generator/generator.dart @@ -1,6 +1,8 @@ import '../ast/_core/interfaces/declaration.dart'; import '../ast/declarations/compounds/class_declaration.dart'; +import '../ast/declarations/compounds/protocol_declaration.dart'; import 'generators/class_generator.dart'; +import 'generators/protocol_generator.dart'; String generate( List declarations, { @@ -19,8 +21,10 @@ String generate( List generateDeclaration(Declaration declaration) { return switch (declaration) { ClassDeclaration() => generateClass(declaration), + ProtocolDeclaration() => generateProtocol(declaration), _ => throw UnimplementedError( "$declaration generation isn't implemented yet", ), }; } + diff --git a/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart b/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart index b5161bfb2c..cd62451ddb 100644 --- a/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart +++ b/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart @@ -97,6 +97,7 @@ List _generateInitializer(InitializerDeclaration initializer) { List _generateClassMethods(ClassDeclaration declaration) => [for (final method in declaration.methods) ..._generateClassMethod(method)]; + List _generateClassMethod(MethodDeclaration method) { final header = StringBuffer(); @@ -134,6 +135,7 @@ List _generateClassProperties(ClassDeclaration declaration) => [ ..._generateClassProperty(property), ]; +// TODO: Generate Class properties for constants (i.e let) List _generateClassProperty(PropertyDeclaration property) { final header = StringBuffer(); diff --git a/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart b/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart new file mode 100644 index 0000000000..d7b0071144 --- /dev/null +++ b/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart @@ -0,0 +1,128 @@ +import '../../ast/declarations/built_in/built_in_declaration.dart'; +import '../../ast/declarations/compounds/members/initializer_declaration.dart'; +import '../../ast/declarations/compounds/members/method_declaration.dart'; +import '../../ast/declarations/compounds/members/property_declaration.dart'; +import '../../ast/declarations/compounds/protocol_declaration.dart'; +import '../_core/utils.dart'; + +List generateProtocol(ProtocolDeclaration declaration) { + return [ + '${_generateProtocolHeader(declaration)} {', + ...[ + ..._generateProtocolProperties(declaration), + ..._generateInitializers(declaration), + ..._generateProtocolMethods(declaration) + ].nonNulls.indent(), + '}\n', + ]; +} + +String _generateProtocolHeader(ProtocolDeclaration declaration) { + final header = StringBuffer(); + + if (declaration.hasObjCAnnotation) { + header.write('@objc '); + } + + header.write('public protocol ${declaration.name}'); + + final superClassAndProtocols = [ + ...declaration.conformedProtocols + .map((protocol) => protocol.declaration.name), + ].nonNulls; + + if (superClassAndProtocols.isNotEmpty) { + header.write(': ${superClassAndProtocols.join(", ")}'); + } + + return header.toString(); +} + +List _generateProtocolMethods(ProtocolDeclaration declaration) => + [for (final method in declaration.methods) ..._generateProtocolMethod(method)]; + + +List _generateProtocolMethod(MethodDeclaration method) { + final header = StringBuffer(); + + if (method.hasObjCAnnotation) { + header.write('@objc '); + } + + if (method.isStatic) { + header.write('static '); + } + + // if (method.isOverriding) { + // header.write('override '); + // } + + header.write( + 'func ${method.name}(${generateParameters(method.params)}) ', + ); + + header.write(generateAnnotations(method)); + + if (!method.returnType.sameAs(voidType)) { + header.write('-> ${method.returnType.swiftType} '); + } + + return [ + '$header' + ]; +} + +List _generateProtocolProperties(ProtocolDeclaration declaration) => [ + for (final property in declaration.properties) + ..._generateProtocolProperty(property), + ]; + +List _generateProtocolProperty(PropertyDeclaration property) { + final header = StringBuffer(); + + if (property.hasObjCAnnotation) { + header.write('@objc '); + } + + if (property.isStatic) { + header.write('static '); + } + + // TODO: Getters work differently + header.write(property.isConstant ? 'let' : 'var'); + header.write(' ${property.name}: ${property.type.swiftType}'); + header.write(' { ${[ + if (property.getter != null) 'get', if (property.setter != null) 'set'] + .join(' ')} }'); + + return [ + header.toString(), + ]; +} + +List _generateInitializers(ProtocolDeclaration declaration) { + final initializers = [ + ...declaration.initializers, + ].nonNulls; + return [for (final init in initializers) ..._generateInitializer(init)]; +} + +List _generateInitializer(InitializerDeclaration initializer) { + final header = StringBuffer(); + + if (initializer.hasObjCAnnotation) { + header.write('@objc '); + } + + header.write('init'); + + if (initializer.isFailable) { + header.write('?'); + } + + header.write('(${generateParameters(initializer.params)})'); + + return [ + '$header ${generateAnnotations(initializer)}', + ]; +} \ No newline at end of file diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart index e06cddf8c8..aba046a49b 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_compound_declaration.dart @@ -124,8 +124,7 @@ ProtocolDeclaration parseProtocolDeclaration( properties: [], methods: [], initializers: [], - conformedProtocols: [], - typeParams: []); + conformedProtocols: []); // get optional member declarations if any final optionalMemberDeclarations = compoundRelations diff --git a/pkgs/swift2objc/lib/src/transformer/transform.dart b/pkgs/swift2objc/lib/src/transformer/transform.dart index 1f18cac808..1c2a0db23c 100644 --- a/pkgs/swift2objc/lib/src/transformer/transform.dart +++ b/pkgs/swift2objc/lib/src/transformer/transform.dart @@ -20,8 +20,9 @@ import 'transformers/transform_protocol.dart'; typedef TransformationMap = Map; extension TransformationMapUtils on TransformationMap { - Declaration? findByOriginalName(String name) { - return this[keys.where((k) => k.name == name).firstOrNull]; + Declaration? findByOriginalId(String id) { + print(this.entries.map((e) => (e.key.name, e.value.name))); + return this[keys.where((k) => k.id == id).firstOrNull]; } } diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart index 06a17c6d8f..5f2589db01 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart @@ -10,6 +10,7 @@ import '../../ast/declarations/built_in/built_in_declaration.dart'; import '../../ast/declarations/compounds/class_declaration.dart'; import '../../ast/declarations/compounds/members/initializer_declaration.dart'; import '../../ast/declarations/compounds/members/property_declaration.dart'; +import '../../ast/declarations/compounds/protocol_declaration.dart'; import '../../ast/declarations/compounds/struct_declaration.dart'; import '../../parser/_core/utils.dart'; import '../_core/unique_namer.dart'; @@ -33,21 +34,25 @@ ClassDeclaration transformCompound( final superClass = originalCompound is ClassDeclaration ? (originalCompound.superClass == null ? null : - transformationMap.findByOriginalName(originalCompound.superClass!.name)) + transformationMap.findByOriginalId(originalCompound.superClass!.id)) : null; final transformedCompound = ClassDeclaration( id: originalCompound.id.addIdSuffix('wrapper'), name: parentNamer.makeUnique('${originalCompound.name}Wrapper'), hasObjCAnnotation: true, - // TODO: superclass can be previous superclass since it will already inherit superClass: superClass?.asDeclaredType ?? objectType, isWrapper: true, wrappedInstance: wrappedCompoundInstance, wrapperInitializer: _buildWrapperInitializer(wrappedCompoundInstance), ); - transformationMap[originalCompound] = transformedCompound; + // transformedCompound.conformedProtocols.addAll( + // originalCompound.conformedProtocols.map((p) { + // return (transformationMap.findByOriginalId(p.id) as ProtocolDeclaration) + // .asDeclaredType; + // }) + // ); transformedCompound.nestedDeclarations = originalCompound.nestedDeclarations .map((nested) => transformDeclaration( @@ -90,6 +95,9 @@ ClassDeclaration transformCompound( .toList() ..sort((Declaration a, Declaration b) => a.id.compareTo(b.id)); + + transformationMap[originalCompound] = transformedCompound; + return transformedCompound; } diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart new file mode 100644 index 0000000000..67445f18a9 --- /dev/null +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart @@ -0,0 +1,43 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../../ast/_core/interfaces/declaration.dart'; +import '../../ast/declarations/compounds/protocol_declaration.dart'; +import '../../parser/_core/utils.dart'; +import '../_core/unique_namer.dart'; +import '../transform.dart'; + +/// NOTES: +/// 1. Protocols with `associatedTypes` are not allowed +/// TODO: Update TransformationMap to make referencing types easy. Would want to just add wrapper suffix but due to unique naming, can't take chances +ProtocolDeclaration transformProtocol(ProtocolDeclaration originalProtocol, + UniqueNamer parentNamer, TransformationMap transformationMap) { + final compoundNamer = UniqueNamer.inCompound(originalProtocol); + + if (originalProtocol.associatedTypes.isNotEmpty) { + throw Exception('Associated types are not exportable to Objective-C'); + } + + final transformedProtocol = ProtocolDeclaration( + id: originalProtocol.id.addIdSuffix('wrapper'), + name: parentNamer.makeUnique('${originalProtocol.name}Wrapper'), + properties: originalProtocol.properties, + methods: originalProtocol.methods, + initializers: originalProtocol.initializers, + conformedProtocols: [], + hasObjCAnnotation: true, + nestingParent: originalProtocol.nestingParent + ); + + // transformedProtocol.conformedProtocols.addAll( + // originalProtocol.conformedProtocols.map((p) { + // return (transformationMap.findByOriginalId(p.id) as ProtocolDeclaration) + // .asDeclaredType; + // }) + // ); + + transformationMap[originalProtocol] = transformedProtocol; + + return transformedProtocol; +} diff --git a/pkgs/swift2objc/test/integration/protocol_input.swift b/pkgs/swift2objc/test/integration/protocol_input.swift new file mode 100644 index 0000000000..9aa30bdd57 --- /dev/null +++ b/pkgs/swift2objc/test/integration/protocol_input.swift @@ -0,0 +1,26 @@ +import Foundation + +public protocol Greetable { + var name: String { get } + func greet() -> String +} + + +public protocol Identifiable { + var id: String { get } +} + +public protocol User: Identifiable { + static var configurationName: String { get } + static func configure() + var currentState: String { get set } + var isActive: Bool { get } + var email: String { get } + func displayInfo() -> String +} + +@objc public protocol OptionallyResponds { + @objc optional func optionalMethod() + @objc optional var response: String { get set } + func requiredMethod() +} \ No newline at end of file diff --git a/pkgs/swift2objc/test/integration/protocol_output.swift b/pkgs/swift2objc/test/integration/protocol_output.swift new file mode 100644 index 0000000000..e1645510ee --- /dev/null +++ b/pkgs/swift2objc/test/integration/protocol_output.swift @@ -0,0 +1,28 @@ +// Test preamble text + +import Foundation + +@objc public protocol OptionallyRespondsWrapper { + @objc var response: String { } + @objc func optionalMethod() + func requiredMethod() +} + +@objc public protocol IdentifiableWrapper { + var id: String { } +} + +@objc public protocol UserWrapper { + var email: String { } + var currentState: String { } + static var configurationName: String { } + var isActive: Bool { } + static func configure() + func displayInfo() -> String +} + +@objc public protocol GreetableWrapper { + var name: String { } + func greet() -> String +} + diff --git a/pkgs/swift2objc/test/unit/parse_protocol_test.dart b/pkgs/swift2objc/test/unit/parse_protocol_test.dart index d9fe73f003..883e4b7bd0 100644 --- a/pkgs/swift2objc/test/unit/parse_protocol_test.dart +++ b/pkgs/swift2objc/test/unit/parse_protocol_test.dart @@ -1,5 +1,9 @@ +import 'dart:io'; + import 'package:path/path.dart' as p; import 'package:swift2objc/src/ast/declarations/compounds/protocol_declaration.dart'; +import 'package:swift2objc/src/config.dart'; +import 'package:swift2objc/src/generate_wrapper.dart'; import 'package:swift2objc/src/parser/_core/parsed_symbolgraph.dart'; import 'package:swift2objc/src/parser/_core/utils.dart'; import 'package:swift2objc/src/parser/parsers/parse_declarations.dart'; From a312c769f1f59460b7e29d698e95ce2442a505c0 Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Sun, 2 Mar 2025 01:27:20 -0600 Subject: [PATCH 10/14] Formatting and Fixing --- .../compounds/protocol_declaration.dart | 10 +++---- .../lib/src/generator/generator.dart | 1 - .../generator/generators/class_generator.dart | 1 - .../generators/protocol_generator.dart | 18 +++++------ .../lib/src/transformer/transform.dart | 11 ++----- .../transformers/transform_compound.dart | 14 ++++----- .../transformers/transform_protocol.dart | 30 +++++++++---------- .../test/unit/parse_protocol_test.dart | 5 +--- 8 files changed, 38 insertions(+), 52 deletions(-) diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart index 07af645e7e..189013c72c 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart @@ -80,11 +80,9 @@ class ProtocolDeclaration extends AstNode visitor.visit(nestingParent); visitor.visitAll(nestedDeclarations); } - + @override - List get typeParams => - throw Exception( - 'Protocols do not have type params: ' - 'Did you mean to use `associatedTypes` instead?' - ); + List get typeParams => + throw Exception('Protocols do not have type params: ' + 'Did you mean to use `associatedTypes` instead?'); } diff --git a/pkgs/swift2objc/lib/src/generator/generator.dart b/pkgs/swift2objc/lib/src/generator/generator.dart index e6e9f442bf..789ac321d6 100644 --- a/pkgs/swift2objc/lib/src/generator/generator.dart +++ b/pkgs/swift2objc/lib/src/generator/generator.dart @@ -27,4 +27,3 @@ List generateDeclaration(Declaration declaration) { ), }; } - diff --git a/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart b/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart index cd62451ddb..42a1e7ebfa 100644 --- a/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart +++ b/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart @@ -97,7 +97,6 @@ List _generateInitializer(InitializerDeclaration initializer) { List _generateClassMethods(ClassDeclaration declaration) => [for (final method in declaration.methods) ..._generateClassMethod(method)]; - List _generateClassMethod(MethodDeclaration method) { final header = StringBuffer(); diff --git a/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart b/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart index d7b0071144..35ecf81b3e 100644 --- a/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart +++ b/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart @@ -38,9 +38,10 @@ String _generateProtocolHeader(ProtocolDeclaration declaration) { return header.toString(); } -List _generateProtocolMethods(ProtocolDeclaration declaration) => - [for (final method in declaration.methods) ..._generateProtocolMethod(method)]; - +List _generateProtocolMethods(ProtocolDeclaration declaration) => [ + for (final method in declaration.methods) + ..._generateProtocolMethod(method) + ]; List _generateProtocolMethod(MethodDeclaration method) { final header = StringBuffer(); @@ -67,9 +68,7 @@ List _generateProtocolMethod(MethodDeclaration method) { header.write('-> ${method.returnType.swiftType} '); } - return [ - '$header' - ]; + return ['$header']; } List _generateProtocolProperties(ProtocolDeclaration declaration) => [ @@ -92,8 +91,9 @@ List _generateProtocolProperty(PropertyDeclaration property) { header.write(property.isConstant ? 'let' : 'var'); header.write(' ${property.name}: ${property.type.swiftType}'); header.write(' { ${[ - if (property.getter != null) 'get', if (property.setter != null) 'set'] - .join(' ')} }'); + if (property.getter != null) 'get', + if (property.setter != null) 'set' + ].join(' ')} }'); return [ header.toString(), @@ -125,4 +125,4 @@ List _generateInitializer(InitializerDeclaration initializer) { return [ '$header ${generateAnnotations(initializer)}', ]; -} \ No newline at end of file +} diff --git a/pkgs/swift2objc/lib/src/transformer/transform.dart b/pkgs/swift2objc/lib/src/transformer/transform.dart index 1c2a0db23c..2077e04622 100644 --- a/pkgs/swift2objc/lib/src/transformer/transform.dart +++ b/pkgs/swift2objc/lib/src/transformer/transform.dart @@ -10,7 +10,6 @@ import '../ast/declarations/compounds/protocol_declaration.dart'; import '../ast/declarations/compounds/struct_declaration.dart'; import '../ast/declarations/globals/globals.dart'; import '../ast/visitor.dart'; -import '../parser/_core/utils.dart'; import '_core/dependencies.dart'; import '_core/unique_namer.dart'; import 'transformers/transform_compound.dart'; @@ -21,7 +20,7 @@ typedef TransformationMap = Map; extension TransformationMapUtils on TransformationMap { Declaration? findByOriginalId(String id) { - print(this.entries.map((e) => (e.key.name, e.value.name))); + print(entries.map((e) => (e.key.name, e.value.name))); return this[keys.where((k) => k.id == id).firstOrNull]; } } @@ -87,12 +86,8 @@ Declaration transformDeclaration( parentNamer, transformationMap, ), - ProtocolDeclaration() => transformProtocol( - declaration, - parentNamer, - transformationMap - ), + ProtocolDeclaration() => + transformProtocol(declaration, parentNamer, transformationMap), _ => throw UnimplementedError(), }; } - diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart index 5f2589db01..7355b3cb26 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart @@ -10,8 +10,6 @@ import '../../ast/declarations/built_in/built_in_declaration.dart'; import '../../ast/declarations/compounds/class_declaration.dart'; import '../../ast/declarations/compounds/members/initializer_declaration.dart'; import '../../ast/declarations/compounds/members/property_declaration.dart'; -import '../../ast/declarations/compounds/protocol_declaration.dart'; -import '../../ast/declarations/compounds/struct_declaration.dart'; import '../../parser/_core/utils.dart'; import '../_core/unique_namer.dart'; import '../transform.dart'; @@ -32,10 +30,11 @@ ClassDeclaration transformCompound( type: originalCompound.asDeclaredType, ); - final superClass = originalCompound is ClassDeclaration ? - (originalCompound.superClass == null ? null : - transformationMap.findByOriginalId(originalCompound.superClass!.id)) - : null; + final superClass = originalCompound is ClassDeclaration + ? (originalCompound.superClass == null + ? null + : transformationMap.findByOriginalId(originalCompound.superClass!.id)) + : null; final transformedCompound = ClassDeclaration( id: originalCompound.id.addIdSuffix('wrapper'), @@ -49,7 +48,7 @@ ClassDeclaration transformCompound( // transformedCompound.conformedProtocols.addAll( // originalCompound.conformedProtocols.map((p) { - // return (transformationMap.findByOriginalId(p.id) as ProtocolDeclaration) + // return (transformationMap.findByOriginalId(p.id) as ProtocolDeclaration) // .asDeclaredType; // }) // ); @@ -95,7 +94,6 @@ ClassDeclaration transformCompound( .toList() ..sort((Declaration a, Declaration b) => a.id.compareTo(b.id)); - transformationMap[originalCompound] = transformedCompound; return transformedCompound; diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart index 67445f18a9..96aac6ff8f 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart @@ -2,7 +2,6 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -import '../../ast/_core/interfaces/declaration.dart'; import '../../ast/declarations/compounds/protocol_declaration.dart'; import '../../parser/_core/utils.dart'; import '../_core/unique_namer.dart'; @@ -10,29 +9,30 @@ import '../transform.dart'; /// NOTES: /// 1. Protocols with `associatedTypes` are not allowed -/// TODO: Update TransformationMap to make referencing types easy. Would want to just add wrapper suffix but due to unique naming, can't take chances -ProtocolDeclaration transformProtocol(ProtocolDeclaration originalProtocol, - UniqueNamer parentNamer, TransformationMap transformationMap) { - final compoundNamer = UniqueNamer.inCompound(originalProtocol); +// TODO: Update TransformationMap to make referencing types easy. +// Would want to just add wrapper suffix but due to unique naming, +// can't take chances +ProtocolDeclaration transformProtocol(ProtocolDeclaration originalProtocol, + UniqueNamer parentNamer, TransformationMap transformationMap) { + // final compoundNamer = UniqueNamer.inCompound(originalProtocol); if (originalProtocol.associatedTypes.isNotEmpty) { throw Exception('Associated types are not exportable to Objective-C'); } final transformedProtocol = ProtocolDeclaration( - id: originalProtocol.id.addIdSuffix('wrapper'), - name: parentNamer.makeUnique('${originalProtocol.name}Wrapper'), - properties: originalProtocol.properties, - methods: originalProtocol.methods, - initializers: originalProtocol.initializers, - conformedProtocols: [], - hasObjCAnnotation: true, - nestingParent: originalProtocol.nestingParent - ); + id: originalProtocol.id.addIdSuffix('wrapper'), + name: parentNamer.makeUnique('${originalProtocol.name}Wrapper'), + properties: originalProtocol.properties, + methods: originalProtocol.methods, + initializers: originalProtocol.initializers, + conformedProtocols: [], + hasObjCAnnotation: true, + nestingParent: originalProtocol.nestingParent); // transformedProtocol.conformedProtocols.addAll( // originalProtocol.conformedProtocols.map((p) { - // return (transformationMap.findByOriginalId(p.id) as ProtocolDeclaration) + // return (transformationMap.findByOriginalId(p.id) as ProtocolDeclaration) // .asDeclaredType; // }) // ); diff --git a/pkgs/swift2objc/test/unit/parse_protocol_test.dart b/pkgs/swift2objc/test/unit/parse_protocol_test.dart index 883e4b7bd0..b1c58b0a08 100644 --- a/pkgs/swift2objc/test/unit/parse_protocol_test.dart +++ b/pkgs/swift2objc/test/unit/parse_protocol_test.dart @@ -1,9 +1,6 @@ -import 'dart:io'; import 'package:path/path.dart' as p; import 'package:swift2objc/src/ast/declarations/compounds/protocol_declaration.dart'; -import 'package:swift2objc/src/config.dart'; -import 'package:swift2objc/src/generate_wrapper.dart'; import 'package:swift2objc/src/parser/_core/parsed_symbolgraph.dart'; import 'package:swift2objc/src/parser/_core/utils.dart'; import 'package:swift2objc/src/parser/parsers/parse_declarations.dart'; @@ -47,7 +44,7 @@ void main() { expect(testDecl.properties.where((m) => m.isStatic), hasLength(1)); final declProp = testDecl.properties.where((m) => m.isStatic).single; - final declMethod = testDecl.methods.where((m) => m.isStatic).single; + // final declMethod = testDecl.methods.where((m) => m.isStatic).single; expect(declProp.name, equalsIgnoringCase('configurationName')); }); From 9b5c264142c15b7e0054234ad9c519d0e9c997b2 Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Sun, 2 Mar 2025 01:29:42 -0600 Subject: [PATCH 11/14] Removed dangling TODO --- .../lib/src/generator/generators/protocol_generator.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart b/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart index 35ecf81b3e..bbf865231e 100644 --- a/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart +++ b/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart @@ -87,7 +87,6 @@ List _generateProtocolProperty(PropertyDeclaration property) { header.write('static '); } - // TODO: Getters work differently header.write(property.isConstant ? 'let' : 'var'); header.write(' ${property.name}: ${property.type.swiftType}'); header.write(' { ${[ From ecd7bfd0a493785e079330625e88f62876b6db4c Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Sun, 2 Mar 2025 22:23:34 -0600 Subject: [PATCH 12/14] Formatted files --- .../lib/src/transformer/transformers/transform_compound.dart | 3 +-- .../lib/src/transformer/transformers/transform_protocol.dart | 4 ++-- pkgs/swift2objc/test/unit/parse_protocol_test.dart | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart index 711de5185d..38ff67f447 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart @@ -97,9 +97,8 @@ ClassDeclaration transformCompound( .toList() ..sort((Declaration a, Declaration b) => a.id.compareTo(b.id)); - transformationMap[originalCompound] = transformedCompound; - + transformedCompound.initializers = transformedInitializers .whereType() .toList() diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart index 96aac6ff8f..e188c265e9 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart @@ -9,8 +9,8 @@ import '../transform.dart'; /// NOTES: /// 1. Protocols with `associatedTypes` are not allowed -// TODO: Update TransformationMap to make referencing types easy. -// Would want to just add wrapper suffix but due to unique naming, +// TODO: Update TransformationMap to make referencing types easy. +// Would want to just add wrapper suffix but due to unique naming, // can't take chances ProtocolDeclaration transformProtocol(ProtocolDeclaration originalProtocol, UniqueNamer parentNamer, TransformationMap transformationMap) { diff --git a/pkgs/swift2objc/test/unit/parse_protocol_test.dart b/pkgs/swift2objc/test/unit/parse_protocol_test.dart index b1c58b0a08..5eed76e7df 100644 --- a/pkgs/swift2objc/test/unit/parse_protocol_test.dart +++ b/pkgs/swift2objc/test/unit/parse_protocol_test.dart @@ -1,4 +1,3 @@ - import 'package:path/path.dart' as p; import 'package:swift2objc/src/ast/declarations/compounds/protocol_declaration.dart'; import 'package:swift2objc/src/parser/_core/parsed_symbolgraph.dart'; From 4db39a7fca971ca1af897c4f43ff9a435134111f Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Sun, 2 Mar 2025 22:31:31 -0600 Subject: [PATCH 13/14] Updated TODOs, referencing a pull request --- .../lib/src/generator/generators/class_generator.dart | 2 +- .../lib/src/transformer/transformers/transform_protocol.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart b/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart index 42a1e7ebfa..83e58f96b9 100644 --- a/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart +++ b/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart @@ -134,7 +134,7 @@ List _generateClassProperties(ClassDeclaration declaration) => [ ..._generateClassProperty(property), ]; -// TODO: Generate Class properties for constants (i.e let) +// TODO(https://github.com/dart-lang/native/pull/2056): Generate Class properties for constants (i.e let) List _generateClassProperty(PropertyDeclaration property) { final header = StringBuffer(); diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart index e188c265e9..b84269b65e 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart @@ -9,7 +9,7 @@ import '../transform.dart'; /// NOTES: /// 1. Protocols with `associatedTypes` are not allowed -// TODO: Update TransformationMap to make referencing types easy. +// TODO(https://github.com/dart-lang/native/pull/2056): Update TransformationMap to make referencing types easy. // Would want to just add wrapper suffix but due to unique naming, // can't take chances ProtocolDeclaration transformProtocol(ProtocolDeclaration originalProtocol, From 478d543b24978bc7ff6bf0cb4308b20b2821f8f5 Mon Sep 17 00:00:00 2001 From: Nike Okoronkwo Date: Mon, 10 Mar 2025 23:22:03 -0400 Subject: [PATCH 14/14] Made changes to protocol --- .../src/ast/_core/shared/referred_type.dart | 4 ++++ .../compounds/protocol_declaration.dart | 5 ++--- .../generators/protocol_generator.dart | 4 ---- .../lib/src/transformer/transform.dart | 1 - .../transformers/transform_compound.dart | 16 +++++++++------ .../transformers/transform_protocol.dart | 20 ++++++++++--------- 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart b/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart index e1a16f0b5e..24d913efa4 100644 --- a/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart +++ b/pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart @@ -98,6 +98,10 @@ class GenericType extends AstNode implements ReferredType { void visit(Visitation visitation) => visitation.visitGenericType(this); } +/// Associated Types are similar to Generics, but in the context of protocols. +/// They are declared with an `associatedType` keyword inside a protocol. +/// +/// For more information: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/generics/#Associated-Types class AssociatedType extends AstNode implements ReferredType { final String id; diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart index 189013c72c..15ce6d252d 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/protocol_declaration.dart @@ -32,9 +32,8 @@ class ProtocolDeclaration extends AstNode /// Only present if indicated with `@objc` List optionalMethods; - /// Associated types used with this declaration - /// They are similar to generic types - /// but only designated for protocol declarations + /// Associated types used with this declaration. They are similar to generic + /// types, but only designated for protocol declarations. List associatedTypes; @override diff --git a/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart b/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart index bbf865231e..5dd195d8fd 100644 --- a/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart +++ b/pkgs/swift2objc/lib/src/generator/generators/protocol_generator.dart @@ -54,10 +54,6 @@ List _generateProtocolMethod(MethodDeclaration method) { header.write('static '); } - // if (method.isOverriding) { - // header.write('override '); - // } - header.write( 'func ${method.name}(${generateParameters(method.params)}) ', ); diff --git a/pkgs/swift2objc/lib/src/transformer/transform.dart b/pkgs/swift2objc/lib/src/transformer/transform.dart index 2077e04622..ce9fa1d20f 100644 --- a/pkgs/swift2objc/lib/src/transformer/transform.dart +++ b/pkgs/swift2objc/lib/src/transformer/transform.dart @@ -20,7 +20,6 @@ typedef TransformationMap = Map; extension TransformationMapUtils on TransformationMap { Declaration? findByOriginalId(String id) { - print(entries.map((e) => (e.key.name, e.value.name))); return this[keys.where((k) => k.id == id).firstOrNull]; } } diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart index 38ff67f447..27942bc6d3 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart @@ -11,6 +11,7 @@ import '../../ast/declarations/compounds/class_declaration.dart'; import '../../ast/declarations/compounds/members/initializer_declaration.dart'; import '../../ast/declarations/compounds/members/method_declaration.dart'; import '../../ast/declarations/compounds/members/property_declaration.dart'; +import '../../ast/declarations/compounds/protocol_declaration.dart'; import '../../parser/_core/utils.dart'; import '../_core/unique_namer.dart'; import '../transform.dart'; @@ -47,12 +48,15 @@ ClassDeclaration transformCompound( wrapperInitializer: _buildWrapperInitializer(wrappedCompoundInstance), ); - // transformedCompound.conformedProtocols.addAll( - // originalCompound.conformedProtocols.map((p) { - // return (transformationMap.findByOriginalId(p.id) as ProtocolDeclaration) - // .asDeclaredType; - // }) - // ); + transformedCompound.conformedProtocols.addAll( + originalCompound.conformedProtocols.map((p) { + return ( + transformDeclaration(p.declaration, compoundNamer, transformationMap) + as ProtocolDeclaration + ) + .asDeclaredType; + }) + ); transformedCompound.nestedDeclarations = originalCompound.nestedDeclarations .map((nested) => transformDeclaration( diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart index b84269b65e..c42b3704a5 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_protocol.dart @@ -2,19 +2,18 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import '../../ast/_core/interfaces/declaration.dart'; import '../../ast/declarations/compounds/protocol_declaration.dart'; import '../../parser/_core/utils.dart'; import '../_core/unique_namer.dart'; import '../transform.dart'; -/// NOTES: -/// 1. Protocols with `associatedTypes` are not allowed // TODO(https://github.com/dart-lang/native/pull/2056): Update TransformationMap to make referencing types easy. // Would want to just add wrapper suffix but due to unique naming, // can't take chances ProtocolDeclaration transformProtocol(ProtocolDeclaration originalProtocol, UniqueNamer parentNamer, TransformationMap transformationMap) { - // final compoundNamer = UniqueNamer.inCompound(originalProtocol); + final compoundNamer = UniqueNamer.inCompound(originalProtocol); if (originalProtocol.associatedTypes.isNotEmpty) { throw Exception('Associated types are not exportable to Objective-C'); @@ -30,12 +29,15 @@ ProtocolDeclaration transformProtocol(ProtocolDeclaration originalProtocol, hasObjCAnnotation: true, nestingParent: originalProtocol.nestingParent); - // transformedProtocol.conformedProtocols.addAll( - // originalProtocol.conformedProtocols.map((p) { - // return (transformationMap.findByOriginalId(p.id) as ProtocolDeclaration) - // .asDeclaredType; - // }) - // ); + transformedProtocol.conformedProtocols.addAll( + originalProtocol.conformedProtocols.map((p) { + return ( + transformDeclaration(p.declaration, compoundNamer, transformationMap) + as ProtocolDeclaration + ) + .asDeclaredType; + }) + ); transformationMap[originalProtocol] = transformedProtocol;