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
2 changes: 1 addition & 1 deletion lib/dart_eval.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// A library providing a Dart bytecode compiler and interpreter.
library dart_eval;
library;

export 'src/eval/eval.dart';
export 'src/eval/runtime/runtime.dart' show Runtime;
Expand Down
2 changes: 1 addition & 1 deletion lib/dart_eval_bridge.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
library dart_eval.bridge;
library;

export 'package:pub_semver/pub_semver.dart' show Version;
export 'src/eval/runtime/runtime.dart' show Runtime;
Expand Down
2 changes: 1 addition & 1 deletion lib/dart_eval_security.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
library dart_eval.security;
library;

export 'src/eval/runtime/security/permission.dart';
export 'src/eval/runtime/security/permissions/filesystem.dart';
Expand Down
24 changes: 15 additions & 9 deletions lib/src/eval/bindgen/bindgen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,21 @@ class Bindgen implements BridgeDeclarationRegistry {

final units = analysisResult.unit.declarations;

final 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))
.toList()
.nonNulls;
final Iterable<String> resolved;
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))
.toList()
.nonNulls;
} on Error {
print('Failed to resolve $filePath:');
rethrow;
}

if (resolved.isEmpty) {
return null;
Expand Down
9 changes: 6 additions & 3 deletions lib/src/eval/bindgen/bridge_declaration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ ${fields(ctx, element)}

String constructors(BindgenContext ctx, InterfaceElement2 element) {
return element.constructors2
.where((e) => !e.isPrivate)
.map((e) => bridgeConstructorDef(ctx, constructor: e))
.join('\n');
}
Expand All @@ -111,6 +112,7 @@ String methods(BindgenContext ctx, InterfaceElement2 element) {
return methods.values
.where(
(m) => !(const ['==', 'toString', 'noSuchMethod'].contains(m.name3)))
.where((m) => !m.isPrivate)
.map((m) => bridgeMethodDef(ctx, method: m))
.join('\n');
}
Expand All @@ -126,6 +128,7 @@ String getters(BindgenContext ctx, InterfaceElement2 element) {

return getters.values
.where((m) => !(const ['hashCode', 'runtimeType'].contains(m.name3)))
.where((element) => !element.isPrivate)
.where((element) =>
!element.isSynthetic ||
(element is EnumElement2 &&
Expand All @@ -145,7 +148,7 @@ String setters(BindgenContext ctx, InterfaceElement2 element) {
};

return setters.values
.where((element) => !element.isSynthetic)
.where((element) => !element.isSynthetic && !element.isPrivate)
.map((e) => bridgeSetterDef(ctx, setter: e))
.join('\n');
}
Expand All @@ -161,8 +164,8 @@ String fields(BindgenContext ctx, InterfaceElement2 element) {
for (final f in element.fields2) f.name3: f
};

final fields = allFields.values
.where((element) => !element.isSynthetic && !element.isEnumConstant);
final fields = allFields.values.where((element) =>
!element.isSynthetic && !element.isEnumConstant && !element.isPrivate);

return fields
.map(
Expand Down
8 changes: 5 additions & 3 deletions lib/src/eval/bindgen/methods.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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/operator.dart';
import 'package:dart_eval/src/eval/bindgen/parameters.dart';
import 'package:dart_eval/src/eval/bindgen/permission.dart';
import 'package:dart_eval/src/eval/bindgen/type.dart';
Expand All @@ -20,12 +21,13 @@ String $methods(BindgenContext ctx, InterfaceElement2 element) {
.map((e) {
final returnsValue =
e.returnType is! VoidType && !e.returnType.isDartCoreNull;
final op = resolveMethodOperator(e.displayName);
return '''
static const \$Function __${e.displayName} = \$Function(_${e.displayName});
static \$Value? _${e.displayName}(Runtime runtime, \$Value? target, List<\$Value?> args) {
static const \$Function __${op.name} = \$Function(_${op.name});
static \$Value? _${op.name}(Runtime runtime, \$Value? target, List<\$Value?> args) {
${assertMethodPermissions(e)}
final self = target! as \$${element.name3};
${returnsValue ? 'final result = ' : ''}self.\$value.${e.displayName}(${argumentAccessors(ctx, e.formalParameters)});
${returnsValue ? 'final result = ' : ''}${op.format('self.\$value', argumentAccessors(ctx, e.formalParameters))};
return ${wrapVar(ctx, e.returnType, 'result')};
}''';
}).join('\n');
Expand Down
95 changes: 95 additions & 0 deletions lib/src/eval/bindgen/operator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
abstract class OperatorMethod {
String get name;
String format(String obj, List<String> args);
}

class FunctionOperator implements OperatorMethod {
@override
final String name;

const FunctionOperator(this.name);

@override
String format(String obj, List<String> args) {
return '$obj.$name(${args.join(', ')})';
}
}

class BinaryOperator implements OperatorMethod {
final String op;

@override
final String name;

const BinaryOperator(this.op, this.name);

@override
String format(String obj, List<String> args) {
return '($obj $op ${args[0]})';
}
}

class UnaryOperator implements OperatorMethod {
final String op;

@override
final String name;

const UnaryOperator(this.op, this.name);

@override
String format(String obj, List<String> args) {
return '$op$obj';
}
}

class IndexGetOperator implements OperatorMethod {
@override
final String name;

const IndexGetOperator(this.name);

@override
String format(String obj, List<String> args) {
return '$obj[${args[0]}]';
}
}

class IndexSetOperator implements OperatorMethod {
@override
final String name;

const IndexSetOperator(this.name);

@override
String format(String obj, List<String> args) {
return '$obj[${args[0]}] = ${args[1]}';
}
}

OperatorMethod resolveMethodOperator(String name) =>
kOperatorNames[name] ?? FunctionOperator(name);

// https://dart.dev/language/methods#operators
final kOperatorNames = <String, OperatorMethod>{
'<': BinaryOperator('<', 'operatorLt'),
'>': BinaryOperator('>', 'operatorGt'),
'<=': BinaryOperator('<=', 'operatorLte'),
'>=': BinaryOperator('>=', 'operatorGte'),
'==': BinaryOperator('==', 'operatorEq'),
'~': UnaryOperator('~', 'operatorBitNot'),
'-': BinaryOperator('-', 'operatorMinus'),
'+': BinaryOperator('+', 'operatorPlus'),
'/': BinaryOperator('/', 'operatorDiv'),
'~/': BinaryOperator('~/', 'operatorIntDiv'),
'*': BinaryOperator('*', 'operatorMul'),
'%': BinaryOperator('%', 'operatorMod'),
'|': BinaryOperator('|', 'operatorBitOr'),
'^': BinaryOperator('^', 'operatorBitXor'),
'&': BinaryOperator('&', 'operatorBitAnd'),
'<<': BinaryOperator('<<', 'operatorShl'),
'>>': BinaryOperator('>>', 'operatorShr'),
'>>>': BinaryOperator('>>>', 'operatorUshr'),
'[]=': IndexSetOperator('operatorIndexSet'),
'[]': IndexGetOperator('operatorIndexGet'),
};
125 changes: 64 additions & 61 deletions lib/src/eval/bindgen/parameters.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:collection/collection.dart';
import 'package:dart_eval/src/eval/bindgen/bridge.dart';
import 'package:dart_eval/src/eval/bindgen/context.dart';
import 'package:dart_eval/src/eval/bindgen/type.dart';
Expand Down Expand Up @@ -39,79 +40,81 @@ String _parameterFrom(BindgenContext ctx, FormalParameterElement parameter) {
''';
}

String argumentAccessors(
BindgenContext ctx, List<FormalParameterElement> params,
String argumentAccessor(
BindgenContext ctx, int index, FormalParameterElement param,
{Map<String, String> paramMapping = const {},
bool isBridgeMethod = false}) {
final paramBuffer = StringBuffer();
for (var i = 0; i < params.length; i++) {
final idx = i + (isBridgeMethod ? 1 : 0);
final param = params[i];
if (param.isNamed) {
paramBuffer.write('${paramMapping[param.name3] ?? param.name3}: ');
final idx = index + (isBridgeMethod ? 1 : 0);
if (param.isNamed) {
paramBuffer.write('${paramMapping[param.name3] ?? param.name3}: ');
}
final type = param.type;
if (type.isDartCoreFunction || type is FunctionType) {
paramBuffer.write('(');
if (type is FunctionType) {
paramBuffer.write(parameterHeader(type.formalParameters));
}
final type = param.type;
if (type.isDartCoreFunction || type is FunctionType) {
paramBuffer.write('(');
if (type is FunctionType) {
paramBuffer.write(parameterHeader(type.formalParameters));
paramBuffer.write(') {\n');
if (type is FunctionType) {
if (type.returnType is! VoidType) {
paramBuffer.write('return ');
}
paramBuffer.write(') {\n');
if (type is FunctionType) {
if (type.returnType is! VoidType) {
paramBuffer.write('return ');
}
}
final q = (param.isRequired ? '' : '?');
final call = (param.isRequired ? '' : '?.call');
paramBuffer
.write('(args[$idx]! as EvalCallable$q)$call(runtime, null, [');
if (type is FunctionType) {
for (var j = 0; j < type.formalParameters.length; j++) {
final ftParam = type.formalParameters[j];
final name = ftParam.name3 == null || ftParam.name3!.isEmpty
? 'arg$j'
: ftParam.name3!;
paramBuffer
.write(wrapVar(ctx, ftParam.type, name, forCollection: true));
if (j < type.formalParameters.length - 1) {
paramBuffer.write(', ');
}
}
final q = (param.isRequired ? '' : '?');
final call = (param.isRequired ? '' : '?.call');
paramBuffer.write('(args[$idx]! as EvalCallable$q)$call(runtime, null, [');
if (type is FunctionType) {
for (var j = 0; j < type.formalParameters.length; j++) {
final ftParam = type.formalParameters[j];
final name = ftParam.name3 == null || ftParam.name3!.isEmpty
? 'arg$j'
: ftParam.name3!;
paramBuffer
.write(wrapVar(ctx, ftParam.type, name, forCollection: true));
if (j < type.formalParameters.length - 1) {
paramBuffer.write(', ');
}
}
paramBuffer.write('])');
if (type is FunctionType) {
if (type.returnType is! VoidType) {
paramBuffer.write('?.\$value');
}
}
paramBuffer.write('])');
if (type is FunctionType) {
if (type.returnType is! VoidType) {
paramBuffer.write('?.\$value');
}
paramBuffer.write(';\n}');
}
paramBuffer.write(';\n}');
} else {
final needsCast =
type.isDartCoreList || type.isDartCoreMap || type.isDartCoreSet;
if (needsCast) {
paramBuffer.write('(');
}
paramBuffer.write('args[$idx]');
final accessor = needsCast ? 'reified' : 'value';
if (param.isRequired) {
paramBuffer.write('!.\$$accessor');
} else {
final needsCast =
type.isDartCoreList || type.isDartCoreMap || type.isDartCoreSet;
if (needsCast) {
paramBuffer.write('(');
}
paramBuffer.write('args[$idx]');
final accessor = needsCast ? 'reified' : 'value';
if (param.isRequired) {
paramBuffer.write('!.\$$accessor');
} else {
paramBuffer.write('?.\$$accessor');
if (param.hasDefaultValue) {
paramBuffer.write(' ?? ${param.defaultValueCode}');
}
}
if (needsCast) {
final q = (param.isRequired ? '' : '?');
paramBuffer.write(' as ${type.element3!.name3}$q');
paramBuffer.write(')$q.cast()');
paramBuffer.write('?.\$$accessor');
if (param.hasDefaultValue) {
paramBuffer.write(' ?? ${param.defaultValueCode}');
}
}

if (i < params.length - 1) {
paramBuffer.write(', ');
if (needsCast) {
final q = (param.isRequired ? '' : '?');
paramBuffer.write(' as ${type.element3!.name3}$q');
paramBuffer.write(')$q.cast()');
}
}
return paramBuffer.toString();
}

List<String> argumentAccessors(
BindgenContext ctx, List<FormalParameterElement> params,
{Map<String, String> paramMapping = const {},
bool isBridgeMethod = false}) {
return params
.mapIndexed((i, p) => argumentAccessor(ctx, i, p,
paramMapping: paramMapping, isBridgeMethod: isBridgeMethod))
.toList();
}
6 changes: 4 additions & 2 deletions lib/src/eval/bindgen/properties.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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/operator.dart';
import 'package:dart_eval/src/eval/bindgen/parameters.dart';
import 'package:dart_eval/src/eval/bindgen/permission.dart';
import 'package:dart_eval/src/eval/bindgen/type.dart';
Expand Down Expand Up @@ -52,11 +53,12 @@ String propertyGetters(BindgenContext ctx, InterfaceElement2 element,
''').join('\n')}${methods0.map((e) {
final returnsValue =
e.returnType is! VoidType && !e.returnType.isDartCoreNull;
final op = resolveMethodOperator(e.displayName);
return '''
case '${e.displayName}':
return \$Function((runtime, target, args) {
${assertMethodPermissions(e)}
${returnsValue ? 'final result = ' : ''}super.${e.displayName}(${argumentAccessors(ctx, e.formalParameters, isBridgeMethod: true)});
${returnsValue ? 'final result = ' : ''}${op.format('super', argumentAccessors(ctx, e.formalParameters, isBridgeMethod: true))};
return ${wrapVar(ctx, e.returnType, 'result')};
});''';
}).join('\n')}\n}';
Expand All @@ -67,7 +69,7 @@ String propertyGetters(BindgenContext ctx, InterfaceElement2 element,
return ${wrapVar(ctx, e.type.returnType, '_${e.name3}', metadata: e.metadata2.annotations)};
''').join('\n')}${methods0.map((e) => '''
case '${e.name3}':
return __${e.name3};
return __${resolveMethodOperator(e.name3!).name};
''').join('\n')}\n}';
}

Expand Down
Loading