Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[swift2objc] Property Parsing and Generation Refactoring #2056

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,29 @@ class PropertyDeclaration extends AstNode
@override
bool async;

bool mutating;

bool hasSetter;

PropertyStatements? getter;
PropertyStatements? setter;

bool isStatic;

PropertyDeclaration({
required this.id,
required this.name,
required this.type,
this.hasSetter = false,
this.isConstant = false,
this.hasObjCAnnotation = false,
this.getter,
this.setter,
this.isStatic = false,
this.throws = false,
this.async = false,
}) : assert(!(isConstant && hasSetter)),
PropertyDeclaration(
{required this.id,
required this.name,
required this.type,
this.hasSetter = false,
this.isConstant = false,
this.hasObjCAnnotation = false,
this.getter,
this.setter,
this.isStatic = false,
this.throws = false,
this.async = false,
this.mutating = false})
: assert(!(isConstant && hasSetter)),
assert(!(hasSetter && throws));

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ PropertyDeclaration parsePropertyDeclaration(
ParsedSymbolgraph symbolgraph, {
bool isStatic = false,
}) {
final isConstant = _parseVariableIsConstant(propertySymbolJson);
final info = parsePropertyInfo(propertySymbolJson['declarationFragments']);
return PropertyDeclaration(
id: parseSymbolId(propertySymbolJson),
name: parseSymbolName(propertySymbolJson),
type: _parseVariableType(propertySymbolJson, symbolgraph),
hasObjCAnnotation: parseSymbolHasObjcAnnotation(propertySymbolJson),
isConstant: isConstant,
hasSetter: isConstant ? false : _parsePropertyHasSetter(propertySymbolJson),
isConstant: info.constant,
hasSetter: info.constant ? false : info.setter,
isStatic: isStatic,
throws: _parseVariableThrows(propertySymbolJson),
async: _parseVariableAsync(propertySymbolJson),
throws: info.throws,
async: info.async,
);
}

Expand All @@ -34,15 +34,14 @@ GlobalVariableDeclaration parseGlobalVariableDeclaration(
ParsedSymbolgraph symbolgraph, {
bool isStatic = false,
}) {
final isConstant = _parseVariableIsConstant(variableSymbolJson);
final hasSetter = _parsePropertyHasSetter(variableSymbolJson);
final info = parsePropertyInfo(variableSymbolJson['declarationFragments']);
return GlobalVariableDeclaration(
id: parseSymbolId(variableSymbolJson),
name: parseSymbolName(variableSymbolJson),
type: _parseVariableType(variableSymbolJson, symbolgraph),
isConstant: isConstant || !hasSetter,
throws: _parseVariableThrows(variableSymbolJson),
async: _parseVariableAsync(variableSymbolJson),
isConstant: info.constant || !info.setter,
throws: info.throws,
async: info.async,
);
}

Expand All @@ -53,9 +52,7 @@ ReferredType _parseVariableType(
parseTypeAfterSeparator(
TokenList(propertySymbolJson['names']['subHeading']), symbolgraph);

bool _parseVariableIsConstant(Json variableSymbolJson) {
final fragmentsJson = variableSymbolJson['declarationFragments'];

bool _parseVariableIsConstant(Json fragmentsJson) {
final declarationKeyword = fragmentsJson.firstWhere(
(json) =>
matchFragment(json, 'keyword', 'var') ||
Expand All @@ -65,24 +62,41 @@ bool _parseVariableIsConstant(Json variableSymbolJson) {
'Expected to find "var" or "let" as a keyword, found none',
),
);

return matchFragment(declarationKeyword, 'keyword', 'let');
}

bool _parseVariableThrows(Json json) {
final throws = json['declarationFragments']
.any((frag) => matchFragment(frag, 'keyword', 'throws'));
return throws;
bool _findKeywordInFragments(Json json, String keyword) {
final keywordIsPresent =
json.any((frag) => matchFragment(frag, 'keyword', keyword));
return keywordIsPresent;
}

bool _parseVariableAsync(Json json) {
final async = json['declarationFragments']
.any((frag) => matchFragment(frag, 'keyword', 'async'));
return async;
typedef ParsedPropertyInfo = ({
bool async,
bool throws,
bool constant,
bool getter,
bool setter,
bool mutating,
});

ParsedPropertyInfo parsePropertyInfo(Json json) {
final (getter, setter) = _parsePropertyGetandSet(json);
return (
constant: _parseVariableIsConstant(json),
async: _findKeywordInFragments(json, 'async'),
throws: _findKeywordInFragments(json, 'throws'),
getter: getter,
setter: setter,
mutating: _findKeywordInFragments(json, 'mutating')
);
}

bool _parsePropertyHasSetter(Json propertySymbolJson) {
final fragmentsJson = propertySymbolJson['declarationFragments'];
(bool, bool) _parsePropertyGetandSet(Json fragmentsJson, {String? path}) {
if (fragmentsJson.any((frag) => matchFragment(frag, 'text', ' { get }'))) {
// has explicit getter and no explicit setter
return (true, false);
}

final hasExplicitSetter =
fragmentsJson.any((frag) => matchFragment(frag, 'keyword', 'set'));
Expand All @@ -92,21 +106,21 @@ bool _parsePropertyHasSetter(Json propertySymbolJson) {
if (hasExplicitGetter) {
if (hasExplicitSetter) {
// has explicit getter and has explicit setter
return true;
return (true, true);
} else {
// has explicit getter and no explicit setter
return false;
return (true, false);
}
} else {
if (hasExplicitSetter) {
// has no explicit getter and but has explicit setter
throw Exception(
'Invalid property at ${propertySymbolJson.path}. '
'Invalid property${path != null ? ' at $path' : ''}. '
'Properties can not have a setter without a getter',
);
} else {
// has no explicit getter and no explicit setter
return true;
return (false, false);
}
}
}
3 changes: 3 additions & 0 deletions pkgs/swift2objc/lib/src/transformer/transform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import '_core/unique_namer.dart';
import 'transformers/transform_compound.dart';
import 'transformers/transform_globals.dart';

// TODO: Update TransformationMap to make referencing types easy.
// Would want to just add wrapper suffix but due to unique naming,
// can't take chances
typedef TransformationMap = Map<Declaration, Declaration>;

Set<Declaration> generateDependencies(Iterable<Declaration> decls) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Declaration? transformProperty(
originalProperty,
globalNamer,
transformationMap,
property: true,
wrapperPropertyName: originalProperty.name,
variableReferenceExpression: '$propertySource.${originalProperty.name}',
);
Expand Down Expand Up @@ -60,6 +61,7 @@ Declaration _transformVariable(
VariableDeclaration originalVariable,
UniqueNamer globalNamer,
TransformationMap transformationMap, {
bool property = false,
required String wrapperPropertyName,
required String variableReferenceExpression,
}) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ public struct MyStruct {

public let representableConstantProperty: Int

public var mutatingProperty: Int {
mutating get { 1 }
}


init(
customVariableProperty: MyOtherStruct,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ import Foundation
@objc public class MyStructWrapper: NSObject {
var wrappedInstance: MyStruct

@objc public var mutatingProperty: Int {
get {
wrappedInstance.mutatingProperty
}
}

@objc public var customGetterProperty: MyOtherStructWrapper {
get {
MyOtherStructWrapper(wrappedInstance.customGetterProperty)
Expand Down
Loading
Loading