Skip to content

Commit

Permalink
implemented parsing basic protocols with inheritance (conformance)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikeokoronkwo committed Dec 18, 2024
1 parent b0c806f commit 6f6d50f
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -23,9 +24,20 @@ class ProtocolDeclaration implements CompoundDeclaration {
@override
covariant List<MethodDeclaration> methods;

/// Only present if indicated with `@objc`
@override
List<PropertyDeclaration> optionalProperties;

/// Only present if indicated with `@objc`
@override
List<MethodDeclaration> optionalMethods;

@override
List<DeclaredType<ProtocolDeclaration>> conformedProtocols;

@override
bool hasObjCAnnotation;

@override
List<GenericType> typeParams;

Expand All @@ -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 [],
});
}
4 changes: 4 additions & 0 deletions pkgs/swift2objc/lib/src/parser/_core/parsed_symbolgraph.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ class ParsedRelation {
}

enum ParsedRelationKind {
requirementOf,
defaultImplementationOf,
optionalRequirementOf,
conformsTo,
memberOf;

static final _supportedRelationKindsMap = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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<MethodDeclaration>()
.dedupeBy((m) => m.fullName),
);

protocol.properties.addAll(
memberDeclarations.whereType<PropertyDeclaration>(),
);

protocol.optionalMethods.addAll(
optionalMemberDeclarations
.whereType<MethodDeclaration>()
.dedupeBy((m) => m.fullName),
);

protocol.optionalProperties.addAll(
optionalMemberDeclarations.whereType<PropertyDeclaration>(),
);

protocol.conformedProtocols.addAll(
conformedProtocolDeclarations
);

protocol.initializers.addAll(
memberDeclarations
.whereType<InitializerDeclaration>()
.dedupeBy((m) => m.fullName),
);

protocol.nestedDeclarations.addAll(
memberDeclarations.whereType<NestableDeclaration>(),
);

protocol.nestedDeclarations.fillNestingParents(protocol);

return protocol;
}

0 comments on commit 6f6d50f

Please sign in to comment.