Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 40 additions & 8 deletions lib/src/eval/bindgen/bindgen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:dart_eval/src/eval/bindgen/bridge_declaration.dart';
import 'package:dart_eval/src/eval/bindgen/configure.dart';
import 'package:dart_eval/src/eval/bindgen/context.dart';
import 'package:dart_eval/src/eval/bindgen/enum.dart';
import 'package:dart_eval/src/eval/bindgen/function.dart';
import 'package:dart_eval/src/eval/bindgen/methods.dart';
import 'package:dart_eval/src/eval/bindgen/properties.dart';
import 'package:dart_eval/src/eval/bindgen/statics.dart';
Expand All @@ -29,6 +30,7 @@ class Bindgen implements BridgeDeclarationRegistry {
final _exportedLibMappings = <String, String>{};
final List<({String file, String uri, String name})> registerClasses = [];
final List<({String file, String uri, String name})> registerEnums = [];
final List<({String file, String uri, String name})> registerFunctions = [];

AnalysisContextCollection? _contextCollection;

Expand Down Expand Up @@ -159,11 +161,16 @@ class Bindgen implements BridgeDeclarationRegistry {
try {
resolved = units
.where((declaration) => declaration.declaredFragment != null)
.map((declaration) => declaration is ClassDeclaration
? _$instance(ctx, declaration.declaredFragment!.element)
: (declaration is EnumDeclaration
? _$enum(ctx, declaration.declaredFragment!.element)
: null))
.map((declaration) {
if (declaration is ClassDeclaration) {
return _$instance(ctx, declaration.declaredFragment!.element);
} else if (declaration is EnumDeclaration) {
return _$enum(ctx, declaration.declaredFragment!.element);
} else if (declaration is FunctionDeclaration) {
return _$function(ctx, declaration.declaredFragment!.element);
}
return null;
})
.toList()
.nonNulls;
} on Error {
Expand All @@ -188,7 +195,7 @@ class Bindgen implements BridgeDeclarationRegistry {
}

({bool process, bool isBridge}) _shouldProcess(
BindgenContext ctx, TypeDefiningElement2 element) {
BindgenContext ctx, Annotatable element) {
final metadata = element.metadata2;
final bindAnno = metadata.annotations
.firstWhereOrNull((element) => element.element2?.displayName == 'Bind');
Expand All @@ -201,10 +208,10 @@ class Bindgen implements BridgeDeclarationRegistry {
bindAnnoValue?.getField('implicitSupers')?.toBoolValue() ?? false;
ctx.implicitSupers = implicitSupers;
final override = bindAnnoValue?.getField('overrideLibrary');
if (override != null && !override.isNull) {
if (override != null && !override.isNull && element is Element2) {
final overrideUri = override.toStringValue();
if (overrideUri != null) {
ctx.libOverrides[element.name3!] = overrideUri;
ctx.libOverrides[(element as Element2).name3!] = overrideUri;
}
}

Expand Down Expand Up @@ -316,6 +323,31 @@ class \$${element.name3} implements \$Instance {
''';
}

String? _$function(BindgenContext ctx, ExecutableElement2 element) {
if (element is! TopLevelFunctionElement) return null;
final (:process, :isBridge) = _shouldProcess(ctx, element);
if (!process) {
return null;
}

registerFunctions.add((
file: ctx.filename,
uri: ctx.libOverrides[element.name3!] ?? ctx.uri,
name: element.name3!,
));

return '''
/// dart_eval function wrapper binding for [${element.name3}]
class \$${element.name3}Fn implements EvalCallable {
const \$${element.name3}Fn();

${bindConfigureFunctionForRuntime(ctx, element)}
${bindFunctionDeclaration(ctx, element)}
${$function(ctx, element)}
}
''';
}

String $superclassWrapper(BindgenContext ctx, InterfaceElement2 element) {
final supertype = element.supertype;
final objectWrapper = '\$Object(\$value)';
Expand Down
41 changes: 26 additions & 15 deletions lib/src/eval/bindgen/bridge_declaration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ String bindBridgeType(BindgenContext ctx, InterfaceElement2 element) {
''';
}

String bindFunctionDeclaration(
BindgenContext ctx, TopLevelFunctionElement element) {
final uri = ctx.libOverrides[element.name3] ?? ctx.uri;
return '''
static const \$declaration = BridgeFunctionDeclaration(
'$uri',
'${element.name3!.replaceAll(r'$', r'\$')}',
${bridgeFunctionDef(ctx, function: element)}
);
''';
}

String? bindBridgeDeclaration(BindgenContext ctx, InterfaceElement2 element,
{bool isBridge = false}) {
if (element is ClassElement2 && element.constructors2.isEmpty) {
Expand Down Expand Up @@ -188,14 +200,21 @@ String bridgeConstructorDef(BindgenContext ctx,
''';
}

String bridgeMethodDef(BindgenContext ctx, {required MethodElement2 method}) {
String bridgeFunctionDef(BindgenContext ctx,
{required ExecutableElement2 function}) {
return '''
'${method.name3}': BridgeMethodDef(
BridgeFunctionDef(
returns: ${bridgeTypeAnnotationFrom(ctx, method.returnType)},
namedParams: [${namedParameters(ctx, element: method)}],
params: [${positionalParameters(ctx, element: method)}],
returns: ${bridgeTypeAnnotationFrom(ctx, function.returnType)},
namedParams: [${namedParameters(ctx, element: function)}],
params: [${positionalParameters(ctx, element: function)}],
),
''';
}

String bridgeMethodDef(BindgenContext ctx, {required MethodElement2 method}) {
return '''
'${method.name3}': BridgeMethodDef(
${bridgeFunctionDef(ctx, function: method)}
${method.isStatic ? 'isStatic: true,' : ''}
),
''';
Expand All @@ -205,11 +224,7 @@ String bridgeGetterDef(BindgenContext ctx,
{required PropertyAccessorElement2 getter}) {
return '''
'${getter.name3}': BridgeMethodDef(
BridgeFunctionDef(
returns: ${bridgeTypeAnnotationFrom(ctx, getter.returnType)},
namedParams: [${namedParameters(ctx, element: getter)}],
params: [${positionalParameters(ctx, element: getter)}],
),
${bridgeFunctionDef(ctx, function: getter)}
${getter.isStatic ? 'isStatic: true,' : ''}
),
''';
Expand All @@ -219,11 +234,7 @@ String bridgeSetterDef(BindgenContext ctx,
{required PropertyAccessorElement2 setter}) {
return '''
'${setter.name3}': BridgeMethodDef(
BridgeFunctionDef(
returns: ${bridgeTypeAnnotationFrom(ctx, setter.returnType)},
namedParams: [${namedParameters(ctx, element: setter)}],
params: [${positionalParameters(ctx, element: setter)}],
),
${bridgeFunctionDef(ctx, function: setter)}
${setter.isStatic ? 'isStatic: true,' : ''}
),
''';
Expand Down
10 changes: 10 additions & 0 deletions lib/src/eval/bindgen/configure.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ static void configureForRuntime(Runtime runtime) {
}
''';

String bindConfigureFunctionForRuntime(
BindgenContext ctx, TopLevelFunctionElement element) {
final uri = ctx.libOverrides[element.name3] ?? ctx.uri;
return '''
static void configureForRuntime(Runtime runtime) {
return runtime.registerBridgeFunc('$uri', '${element.name3!.replaceAll(r'$', r'\$')}', const \$${element.name3}Fn().call);
}
''';
}

String enumValuesForRuntime(BindgenContext ctx, EnumElement2 element) {
final uri = ctx.libOverrides[element.name3] ?? ctx.uri;
return '''
Expand Down
16 changes: 16 additions & 0 deletions lib/src/eval/bindgen/function.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:dart_eval/src/eval/bindgen/context.dart';
import 'package:dart_eval/src/eval/bindgen/parameters.dart';
import 'package:dart_eval/src/eval/bindgen/type.dart';

String $function(BindgenContext ctx, ExecutableElement2 element) {
final returnsValue =
element.returnType is! VoidType && !element.returnType.isDartCoreNull;
return '''
@override
\$Value? call(Runtime runtime, \$Value? target, List<\$Value?> args) {
${returnsValue ? 'final result = ' : ''}${element.displayName}(${argumentAccessors(ctx, element.formalParameters).join(', ')});
return ${wrapVar(ctx, element.returnType, 'result')};
}''';
}
2 changes: 2 additions & 0 deletions lib/src/eval/cli/bind.dart
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,14 @@ class ${packageName.toPascalCase()}Plugin implements EvalPlugin {
void configureForCompile(BridgeDeclarationRegistry registry) {
${bindgen.registerClasses.map((e) => 'registry.defineBridgeClass(\$${e.name}.\$declaration);').join('\n')}
${bindgen.registerEnums.map((e) => 'registry.defineBridgeEnum(\$${e.name}.\$declaration);').join('\n')}
${bindgen.registerFunctions.map((e) => 'registry.defineBridgeTopLevelFunction(\$${e.name}Fn.\$declaration);').join('\n')}
}

@override
void configureForRuntime(Runtime runtime) {
${bindgen.registerClasses.map((e) => '\$${e.name}.configureForRuntime(runtime);').join('\n')}
${bindgen.registerEnums.map((e) => '\$${e.name}.configureForRuntime(runtime);').join('\n')}
${bindgen.registerFunctions.map((e) => '\$${e.name}Fn.configureForRuntime(runtime);').join('\n')}
}
}
''';
Expand Down
3 changes: 2 additions & 1 deletion lib/src/eval/compiler/reference.dart
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,8 @@ Variable _declarationToVariable(
final type = ctx.topLevelVariableInferredTypes[decOrBridge.sourceLib]![
decl.name.lexeme];
if (type == null) {
throw CompileError('Cannot resolve top level variable ${decl.name.lexeme}', source);
throw CompileError(
'Cannot resolve top level variable ${decl.name.lexeme}', source);
}
final gIndex =
ctx.topLevelGlobalIndices[decOrBridge.sourceLib]![decl.name.lexeme]!;
Expand Down