Skip to content
12 changes: 7 additions & 5 deletions pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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 '../interfaces/compound_declaration.dart';
import '../../ast_node.dart';
import '../interfaces/declaration.dart';
import '../interfaces/nestable_declaration.dart';
Expand Down Expand Up @@ -76,6 +77,9 @@ class GenericType extends AstNode implements ReferredType {

final String name;

/// type constraints the generic type might have
final List<DeclaredType<CompoundDeclaration>> constraints;

@override
bool get isObjCRepresentable => false;

Expand All @@ -84,11 +88,9 @@ class GenericType extends AstNode implements ReferredType {

@override
bool sameAs(ReferredType other) => other is GenericType && other.id == id;

const GenericType({
required this.id,
required this.name,
});

const GenericType(
{required this.id, required this.name, this.constraints = const []});

@override
String toString() => name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import '../../_core/interfaces/objc_annotatable.dart';
import '../../ast_node.dart';

/// Describes a built-in Swift type (e.g Int, String, etc).
/// TODO(https://github.com/dart-lang/native/issues/1827): Include builtin protocols like `Hashable`, `Numeric`
class BuiltInDeclaration extends AstNode
implements Declaration, ObjCAnnotatable {
@override
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/shared/referred_type.dart';
import '../../../ast/_core/interfaces/nestable_declaration.dart';
import '../../../ast/declarations/compounds/class_declaration.dart';
import '../../../ast/declarations/compounds/members/initializer_declaration.dart';
Expand All @@ -12,13 +13,15 @@ import '../../../ast/declarations/compounds/struct_declaration.dart';
import '../../_core/parsed_symbolgraph.dart';
import '../../_core/utils.dart';
import '../parse_declarations.dart';
import '../utils/parse_generics.dart';

typedef CompoundTearOff<T extends CompoundDeclaration> = T Function({
required String id,
required String name,
required List<PropertyDeclaration> properties,
required List<MethodDeclaration> methods,
required List<InitializerDeclaration> initializers,
required List<GenericType> typeParams,
required List<NestableDeclaration> nestedDeclarations,
});

Expand All @@ -37,11 +40,17 @@ T _parseCompoundDeclaration<T extends CompoundDeclaration>(
methods: [],
properties: [],
initializers: [],
typeParams: [],
nestedDeclarations: [],
);

compoundSymbol.declaration = compound;

final typeParams = parseTypeParams(compoundSymbol.json, symbolgraph);
compound.typeParams.addAll(
typeParams
);

final memberDeclarations = compoundRelations
.where(
(relation) {
Expand Down Expand Up @@ -77,6 +86,7 @@ T _parseCompoundDeclaration<T extends CompoundDeclaration>(
.whereType<InitializerDeclaration>()
.dedupeBy((m) => m.fullName),
);

compound.nestedDeclarations.addAll(
memberDeclarations.whereType<NestableDeclaration>(),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,36 @@
// 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/compound_declaration.dart';
import '../../../ast/_core/interfaces/declaration.dart';
import '../../../ast/_core/shared/parameter.dart';
import '../../../ast/_core/shared/referred_type.dart';
import '../../../ast/declarations/compounds/members/method_declaration.dart';
import '../../../ast/declarations/globals/globals.dart';
import '../../_core/json.dart';
import '../../_core/parsed_symbolgraph.dart';
import '../../_core/token_list.dart';
import '../../_core/utils.dart';
import '../parse_declarations.dart';
import '../utils/parse_generics.dart';
import '../../_core/token_list.dart';
import '../parse_type.dart';

GlobalFunctionDeclaration parseGlobalFunctionDeclaration(
Json globalFunctionSymbolJson,
ParsedSymbolgraph symbolgraph,
) {
final info = parseFunctionInfo(
globalFunctionSymbolJson['declarationFragments'], symbolgraph);
// final info = parseFunctionInfo(
// globalFunctionSymbolJson['declarationFragments'], symbolgraph);
return GlobalFunctionDeclaration(
id: parseSymbolId(globalFunctionSymbolJson),
name: parseSymbolName(globalFunctionSymbolJson),
returnType: _parseFunctionReturnType(globalFunctionSymbolJson, symbolgraph),
params: info.params,
throws: info.throws,
async: info.async,
// params: info.params,
// throws: info.throws,
// async: info.async,
params: _parseFunctionParams(globalFunctionSymbolJson, symbolgraph),
typeParams:
parseTypeParams(globalFunctionSymbolJson, symbolgraph)
);
}

Expand All @@ -33,18 +40,118 @@ MethodDeclaration parseMethodDeclaration(
ParsedSymbolgraph symbolgraph, {
bool isStatic = false,
}) {
final info =
parseFunctionInfo(methodSymbolJson['declarationFragments'], symbolgraph);
// final info =
// parseFunctionInfo(methodSymbolJson['declarationFragments'], symbolgraph);
return MethodDeclaration(
id: parseSymbolId(methodSymbolJson),
name: parseSymbolName(methodSymbolJson),
returnType: _parseFunctionReturnType(methodSymbolJson, symbolgraph),
params: info.params,
hasObjCAnnotation: parseSymbolHasObjcAnnotation(methodSymbolJson),
isStatic: isStatic,
throws: info.throws,
async: info.async,
mutating: info.mutating);
id: parseSymbolId(methodSymbolJson),
name: parseSymbolName(methodSymbolJson),
returnType: _parseFunctionReturnType(methodSymbolJson, symbolgraph),
params: _parseFunctionParams(methodSymbolJson, symbolgraph),
hasObjCAnnotation: parseSymbolHasObjcAnnotation(methodSymbolJson),
typeParams: parseTypeParams(methodSymbolJson, symbolgraph),
isStatic: isStatic,
// params: info.params,
// throws: info.throws,
// async: info.async,
// mutating: info.mutating
);
}

ReferredType _parseFunctionReturnType(
Json methodSymbolJson,
ParsedSymbolgraph symbolgraph,
) {
final returnJson = methodSymbolJson['functionSignature']['returns'][0];

// if it is a type generic it may not even have a spelling
if (returnJson['spelling'].get<String?>() == null) {
// check if the item is a generic registered
try {
final type = returnJson['spelling'].get<String>();
final generics = methodSymbolJson['swiftGenerics']['parameters'];
if (generics.map((e) => e['name'].get<String>()).contains(type)) {
// generic located
return parseDeclGenericType(methodSymbolJson['swiftGenerics'], type,
symbolgraph, methodSymbolJson);
}
} on Exception catch (e) {
// continue
}
} else if (returnJson['spelling'].get<String>() == '()') {
// This means there's no return type
return null;
}

// final returnTypeId = returnJson['preciseIdentifier'].get<String>();

// final returnTypeSymbol = symbolgraph.symbols[returnTypeId];

// if (returnTypeSymbol == null) {
// throw Exception(
// 'The method at path "${methodSymbolJson.path}" has a return type that '
// 'does not exist among parsed symbols.',
// );
// }

// final returnTypeDeclaration = parseDeclaration(
// returnTypeSymbol,
// symbolgraph,
// );

// return returnTypeDeclaration.asDeclaredType;
final returnJson =
TokenList(methodSymbolJson['functionSignature']['returns']);
final (returnType, unparsed) = parseType(symbolgraph, returnJson);
assert(unparsed.isEmpty, '$returnJson\n\n$returnType\n\n$unparsed\n');
return returnType;
}

List<Parameter> _parseFunctionParams(
Json methodSymbolJson,
ParsedSymbolgraph symbolgraph,
) {
final paramList = methodSymbolJson['functionSignature']['parameters'];

if (!paramList.exists) return [];

return paramList
.map(
// TODO: Add parameter type generic parsing
(param) => Parameter(
name: param['name'].get(),
internalName: param['internalName'].get(),
type: _parseParamType(param, symbolgraph, methodSymbolJson: methodSymbolJson),
),
)
.toList();
}

ReferredType _parseParamType(
Json paramSymbolJson,
ParsedSymbolgraph symbolgraph,
{Json? methodSymbolJson}
) {
final fragments = paramSymbolJson['declarationFragments'];

var typeDeclFragment = fragments
.firstJsonWhereKey('kind', 'typeIdentifier');

if (methodSymbolJson != null) {
if (methodSymbolJson['swiftGenerics'].get<Map<String, dynamic>?>() != null) {
if (methodSymbolJson['swiftGenerics']['parameters'].map(
(e) => e['name'].get<String>()
).contains(typeDeclFragment['spelling'].get<String>())) {
return parseDeclGenericType(methodSymbolJson['swiftGenerics'],
typeDeclFragment['spelling'].get<String>(), symbolgraph,
methodSymbolJson);
}
}
}

final paramTypeId = typeDeclFragment['preciseIdentifier']
.get<String>();

return parseTypeFromId(paramTypeId, symbolgraph);
}

typedef ParsedFunctionInfo = ({
Expand Down Expand Up @@ -162,14 +269,3 @@ ParsedFunctionInfo parseFunctionInfo(
mutating: prefixAnnotations.contains('mutating')
);
}

ReferredType _parseFunctionReturnType(
Json methodSymbolJson,
ParsedSymbolgraph symbolgraph,
) {
final returnJson =
TokenList(methodSymbolJson['functionSignature']['returns']);
final (returnType, unparsed) = parseType(symbolgraph, returnJson);
assert(unparsed.isEmpty, '$returnJson\n\n$returnType\n\n$unparsed\n');
return returnType;
}
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: Support for generic types: Requires larger scope
PropertyDeclaration parsePropertyDeclaration(
Json propertySymbolJson,
ParsedSymbolgraph symbolgraph, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Declaration parseDeclaration(

final symbolType = symbolJson['kind']['identifier'].get<String>();

// TODO(https://github.com/dart-lang/native/issues/1828): Support protocols
parsedSymbol.declaration = switch (symbolType) {
'swift.class' => parseClassDeclaration(parsedSymbol, symbolgraph),
'swift.struct' => parseStructDeclaration(parsedSymbol, symbolgraph),
Expand Down
60 changes: 60 additions & 0 deletions pkgs/swift2objc/lib/src/parser/parsers/utils/parse_generics.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import '../../../ast/_core/interfaces/compound_declaration.dart';
import '../../../ast/_core/interfaces/declaration.dart';
import '../../../ast/_core/shared/referred_type.dart';
import '../../_core/json.dart';
import '../../_core/parsed_symbolgraph.dart';
import '../parse_declarations.dart';


List<GenericType> parseTypeParams(
Json declarationSymbolJson,
ParsedSymbolgraph symbolgraph,
) {
// get type params
final genericInfo = declarationSymbolJson['swiftGenerics'];

final parameters = genericInfo['parameters'];

if (genericInfo.jsonWithKeyExists('constraints')) {
return parameters.map((e) {
return parseDeclGenericType(genericInfo, e['name'].get<String>(),
symbolgraph, declarationSymbolJson);
}).toList();
} else {
// how to make a good id for generic types
return parameters
.map((e) => GenericType(
id: e['name'].get<String>(), name: e['name'].get<String>()))
.toList();
}
}

GenericType parseDeclGenericType(Json genericInfo, String name,
ParsedSymbolgraph symbolgraph,
Json declSymbolJson, {String? id}) {
final constraintsDesc = genericInfo['constraints'].where(
(element) => element['lhs'].get<String>() == name);

return GenericType(
id: id ?? name,
name: name,
constraints: constraintsDesc.map((c) {
final constraintId = c['rhsPrecise'].get<String>();

final constraintTypeSymbol = symbolgraph.symbols[constraintId];

if (constraintTypeSymbol == null) {
throw Exception(
'The type constraint at path "${declSymbolJson.path}"'
' has a return type that does not exist among parsed symbols.',
);
}

final constraintDeclaration = parseDeclaration(
constraintTypeSymbol,
symbolgraph,
) as CompoundDeclaration;

return constraintDeclaration.asDeclaredType;
}).toList());
}
Loading