Skip to content

Commit

Permalink
completed setting up tests
Browse files Browse the repository at this point in the history
Tests succeed and necessary TODOs have been placed
  • Loading branch information
nikeokoronkwo committed Jan 23, 2025
1 parent be6b8c8 commit 1e2f855
Show file tree
Hide file tree
Showing 11 changed files with 2,372 additions and 97 deletions.
10 changes: 4 additions & 6 deletions pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,26 +104,24 @@ class AssociatedType extends AstNode implements ReferredType {

final String name;


@override
bool get isObjCRepresentable => false;

@override
String get swiftType => name;

List<DeclaredType<ProtocolDeclaration>> 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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -10,14 +10,13 @@ class AssociatedTypeDeclaration extends AstNode implements Declaration {
@override
String name;

AssociatedTypeDeclaration({
required this.id,
required this.name,
});
List<DeclaredType<ProtocolDeclaration>> conformedProtocols;

AssociatedTypeDeclaration(
{required this.id, required this.name, required this.conformedProtocols});
}

extension AsAssociatedType<T extends AssociatedTypeDeclaration> on T {
AssociatedType asType() => AssociatedType(
id: id, name: name
);
}
id: id, name: name, conformedProtocols: conformedProtocols);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -32,7 +33,7 @@ class ProtocolDeclaration extends AstNode implements CompoundDeclaration, ObjCAn
List<MethodDeclaration> 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<AssociatedType> associatedTypes;

Expand Down Expand Up @@ -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) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<DeclaredType<ProtocolDeclaration>> _parseConformedProtocols(
Json symbolJson, ParsedSymbolgraph symbolGraph) {
final conformDecls = <DeclaredType<ProtocolDeclaration>>[];

final identifierIndex = symbolJson['declarationFragments']
.toList()
.indexWhere((t) =>
t['kind'].get<String>() == 'identifier' &&
t['spelling'].get<String>() == 'Element');

if (symbolJson['declarationFragments'].length - 1 > identifierIndex &&
symbolJson['declarationFragments'][identifierIndex + 1]['spelling']
.get<String>()
.trim() ==
':') {
// the associated type contains
final conformList = symbolJson['declarationFragments']
.toList()
.sublist(identifierIndex + 2);
conformList.removeWhere((t) => t['spelling'].get<String>().trim() == ',');

// go through and find, then add
for (final proto in conformList) {
final protoId = proto['preciseIdentifier'].get<String>();

final protoSymbol = symbolGraph.symbols[protoId];

if (protoSymbol == null) {
// return null;
continue;
}

conformDecls.add(
(tryParseDeclaration(protoSymbol, symbolGraph) as ProtocolDeclaration)
.asDeclaredType);
}
}

return conformDecls;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<AssociatedTypeDeclaration>()
.map((decl) => decl.asType())
.dedupeBy((m) => m.name)
);
.dedupeBy((m) => m.name));

protocol.methods.addAll(
memberDeclarations
Expand All @@ -217,9 +219,7 @@ ProtocolDeclaration parseProtocolDeclaration(
optionalMemberDeclarations.whereType<PropertyDeclaration>(),
);

protocol.conformedProtocols.addAll(
conformedProtocolDeclarations
);
protocol.conformedProtocols.addAll(conformedProtocolDeclarations);

protocol.initializers.addAll(
memberDeclarations
Expand All @@ -234,4 +234,4 @@ ProtocolDeclaration parseProtocolDeclaration(
protocol.nestedDeclarations.fillNestingParents(protocol);

return protocol;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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.',
),
Expand Down
1 change: 0 additions & 1 deletion pkgs/swift2objc/lib/src/parser/parsers/parse_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 1e2f855

Please sign in to comment.