From 0d6861aa2067c0af7e7f9ab30e9a11b1c637ed30 Mon Sep 17 00:00:00 2001 From: Ethan Date: Sun, 17 Mar 2024 17:01:05 -0600 Subject: [PATCH] v0.7.9 --- CHANGELOG.md | 15 +++ README.md | 8 ++ lib/dart_eval_bridge.dart | 1 + lib/src/eval/bindgen/bridge_declaration.dart | 1 + lib/src/eval/bindgen/configure.dart | 3 +- lib/src/eval/bridge/runtime_bridge.dart | 3 +- lib/src/eval/cli/run.dart | 1 - lib/src/eval/compiler/compiler.dart | 1 - .../compiler/declaration/constructor.dart | 7 +- lib/src/eval/compiler/declaration/field.dart | 14 ++- .../eval/compiler/expression/assignment.dart | 3 +- .../eval/compiler/expression/expression.dart | 4 +- .../eval/compiler/expression/function.dart | 61 +++++++-- .../expression/method_invocation.dart | 2 +- .../expression/string_interpolation.dart | 7 +- .../eval/compiler/model/function_type.dart | 95 ++++++++++++++ lib/src/eval/compiler/offset_tracker.dart | 12 ++ lib/src/eval/compiler/type.dart | 11 +- lib/src/eval/compiler/variable.dart | 10 ++ lib/src/eval/runtime/class.dart | 48 +++++++- lib/src/eval/runtime/declaration.dart | 6 +- lib/src/eval/runtime/function.dart | 76 +++++++++++- lib/src/eval/runtime/ops/objects.dart | 9 +- lib/src/eval/runtime/override.dart | 1 - lib/src/eval/runtime/runtime.dart | 62 +++++++--- lib/src/eval/shared/stdlib/async.dart | 7 +- lib/src/eval/shared/stdlib/async/future.dart | 1 - lib/src/eval/shared/stdlib/async/stream.dart | 1 - .../stdlib/async/stream_controller.dart | 1 - lib/src/eval/shared/stdlib/async/timer.dart | 116 ++++++++++++++++++ lib/src/eval/shared/stdlib/async/zone.dart | 1 - lib/src/eval/shared/stdlib/collection.dart | 1 - .../stdlib/collection/linked_hash_map.dart | 1 - lib/src/eval/shared/stdlib/convert.dart | 1 - .../eval/shared/stdlib/convert/base64.dart | 1 - lib/src/eval/shared/stdlib/convert/codec.dart | 3 +- .../eval/shared/stdlib/convert/converter.dart | 1 - .../eval/shared/stdlib/convert/encoding.dart | 1 - lib/src/eval/shared/stdlib/convert/json.dart | 23 ++-- lib/src/eval/shared/stdlib/convert/utf.dart | 1 - lib/src/eval/shared/stdlib/core.dart | 1 - lib/src/eval/shared/stdlib/core/base.dart | 1 - .../eval/shared/stdlib/core/collection.dart | 1 - .../eval/shared/stdlib/core/comparable.dart | 1 - .../eval/shared/stdlib/core/date_time.dart | 1 - lib/src/eval/shared/stdlib/core/duration.dart | 1 - lib/src/eval/shared/stdlib/core/errors.dart | 1 - .../eval/shared/stdlib/core/exceptions.dart | 1 - lib/src/eval/shared/stdlib/core/future.dart | 4 +- .../eval/shared/stdlib/core/identical.dart | 1 - lib/src/eval/shared/stdlib/core/iterator.dart | 1 - lib/src/eval/shared/stdlib/core/num.dart | 1 - lib/src/eval/shared/stdlib/core/object.dart | 1 - lib/src/eval/shared/stdlib/core/pattern.dart | 1 - lib/src/eval/shared/stdlib/core/print.dart | 1 - lib/src/eval/shared/stdlib/core/regexp.dart | 1 - .../eval/shared/stdlib/core/stack_trace.dart | 1 - .../shared/stdlib/core/string_buffer.dart | 1 - lib/src/eval/shared/stdlib/core/symbol.dart | 1 - lib/src/eval/shared/stdlib/core/type.dart | 1 - lib/src/eval/shared/stdlib/core/uri.dart | 1 - lib/src/eval/shared/stdlib/io.dart | 1 - lib/src/eval/shared/stdlib/io/directory.dart | 1 - lib/src/eval/shared/stdlib/io/file.dart | 1 - .../shared/stdlib/io/file_system_entity.dart | 1 - lib/src/eval/shared/stdlib/io/http.dart | 1 - lib/src/eval/shared/stdlib/io/io_sink.dart | 1 - lib/src/eval/shared/stdlib/io/socket.dart | 1 - .../eval/shared/stdlib/io/string_sink.dart | 1 - lib/src/eval/shared/stdlib/math.dart | 1 - lib/src/eval/shared/stdlib/typed_data.dart | 1 - .../shared/stdlib/typed_data/typed_data.dart | 1 - lib/src/eval/shared/types.dart | 3 + pubspec.yaml | 2 +- test/async_test.dart | 2 +- test/bridge_lib.dart | 1 - test/class_test.dart | 42 +++++++ test/collection_test.dart | 18 +++ test/function_test.dart | 78 +++++++++--- 79 files changed, 673 insertions(+), 129 deletions(-) create mode 100644 lib/src/eval/compiler/model/function_type.dart create mode 100644 lib/src/eval/shared/stdlib/async/timer.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 9778890..3633142 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +## 0.7.9 +- Expose base `Object` properties (eg toString, hashCode) for classes + declared inside dart_eval +- Type autowrappers can now be added to the runtime to expose any type + for automatic wrapping using `runtime.wrap()`. +- Support for testing function equality +- Deprecated `runtime.wrapRecursive()`. Use `runtime.wrap(recursive: true)` + instead. +- Optimized generated bytecode for string interpolation +- Fixed $Future.$reified to unwrap its value +- Fix error when accessing or setting nullable static class fields without an + initializer +- Support for factory constructors in the binding generator +- Add $runtime Runtime getter to $Bridge mixin + ## 0.7.8 - Support for runtime methods, static setters, type parameters, class inheritance, anonymous function types, and typedefs in the binding generator diff --git a/README.md b/README.md index e8b1ff5..f6ab441 100644 --- a/README.md +++ b/README.md @@ -624,6 +624,14 @@ dart_eval VM, and not any code it interacts with. For example, most Flutter apps the vast majority of their performance budget in the Flutter framework itself, so the speed impact of dart_eval is usually negligible. +### Is this allowed in the App Store? + +Though Apple's official guidelines are unclear, many popular apps use similar +techniques to dynamically update their code. For example, apps built on +React Native often use its custom Hermes JavaScript engine to enable dynamic +code updates. Note that Apple is likely to remove apps if they introduce policy +violations in updates, regardless of the technology used. + ## Language feature support table The following table details the language features supported by dart_eval with native Dart code. Feature support diff --git a/lib/dart_eval_bridge.dart b/lib/dart_eval_bridge.dart index 1ac7c12..7d50234 100644 --- a/lib/dart_eval_bridge.dart +++ b/lib/dart_eval_bridge.dart @@ -1,6 +1,7 @@ library dart_eval.bridge; export 'package:pub_semver/pub_semver.dart' show Version; +export 'src/eval/runtime/runtime.dart' show Runtime; export 'src/eval/runtime/class.dart' hide $InstanceImpl; export 'src/eval/runtime/declaration.dart' hide EvalClassClass; export 'src/eval/bridge/declaration/class.dart'; diff --git a/lib/src/eval/bindgen/bridge_declaration.dart b/lib/src/eval/bindgen/bridge_declaration.dart index 7afe58c..e6723e5 100644 --- a/lib/src/eval/bindgen/bridge_declaration.dart +++ b/lib/src/eval/bindgen/bridge_declaration.dart @@ -125,6 +125,7 @@ String bridgeConstructorDef({required ConstructorElement constructor}) { namedParams: [${namedParameters(element: constructor)}], params: [${positionalParameters(element: constructor)}], ), + isFactory: ${constructor.isFactory}, ), '''; } diff --git a/lib/src/eval/bindgen/configure.dart b/lib/src/eval/bindgen/configure.dart index b00aea4..f9b90f3 100644 --- a/lib/src/eval/bindgen/configure.dart +++ b/lib/src/eval/bindgen/configure.dart @@ -12,7 +12,8 @@ static void configureForRuntime(Runtime runtime) { String constructorsForRuntime(BindgenContext ctx, ClassElement element) { return element.constructors - .where((cstr) => !element.isAbstract && !cstr.isPrivate) + .where( + (cstr) => (!element.isAbstract || cstr.isFactory) && !cstr.isPrivate) .map((e) => constructorForRuntime(ctx, element, e)) .join('\n'); } diff --git a/lib/src/eval/bridge/runtime_bridge.dart b/lib/src/eval/bridge/runtime_bridge.dart index acbf2c0..e90d063 100644 --- a/lib/src/eval/bridge/runtime_bridge.dart +++ b/lib/src/eval/bridge/runtime_bridge.dart @@ -1,7 +1,6 @@ // ignore_for_file: non_constant_identifier_names import 'package:dart_eval/dart_eval_bridge.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; /// A bridge class can be extended inside the dart_eval VM and used both in /// and outside of it. @@ -52,6 +51,8 @@ mixin $Bridge on Object implements $Value, $Instance { @override T get $reified => this as T; + Runtime get $runtime => Runtime.bridgeData[this]!.runtime; + @override int $getRuntimeType(Runtime runtime) { final data = Runtime.bridgeData[this]!; diff --git a/lib/src/eval/cli/run.dart b/lib/src/eval/cli/run.dart index 1d26bd7..dfd7938 100644 --- a/lib/src/eval/cli/run.dart +++ b/lib/src/eval/cli/run.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; void cliRun(String path, String library, String function) { diff --git a/lib/src/eval/compiler/compiler.dart b/lib/src/eval/compiler/compiler.dart index 3e0d3a2..f9091fb 100644 --- a/lib/src/eval/compiler/compiler.dart +++ b/lib/src/eval/compiler/compiler.dart @@ -15,7 +15,6 @@ import 'package:dart_eval/src/eval/compiler/util/custom_crawler.dart'; import 'package:dart_eval/src/eval/compiler/util/graph.dart'; import 'package:dart_eval/src/eval/compiler/util/library_graph.dart'; import 'package:dart_eval/src/eval/compiler/util/tree_shake.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/src/eval/shared/stdlib/async.dart'; import 'package:dart_eval/src/eval/shared/stdlib/collection.dart'; import 'package:dart_eval/src/eval/shared/stdlib/convert.dart'; diff --git a/lib/src/eval/compiler/declaration/constructor.dart b/lib/src/eval/compiler/declaration/constructor.dart index c658a46..5fc7551 100644 --- a/lib/src/eval/compiler/declaration/constructor.dart +++ b/lib/src/eval/compiler/declaration/constructor.dart @@ -288,7 +288,12 @@ void compileConstructorDeclaration( for (final init in otherInitializers) { if (init is ConstructorFieldInitializer) { - final V = compileExpression(init.expression, ctx).boxIfNeeded(ctx); + final fType = TypeRef.lookupFieldType( + ctx, + TypeRef.lookupDeclaration(ctx, ctx.library, parent), + init.fieldName.name, + source: init); + final V = compileExpression(init.expression, ctx, fType).boxIfNeeded(ctx); ctx.pushOp( SetObjectPropertyImpl.make(instOffset, fieldIndices[init.fieldName.name]!, V.scopeFrameOffset), diff --git a/lib/src/eval/compiler/declaration/field.dart b/lib/src/eval/compiler/declaration/field.dart index 65e15dd..b0fccb0 100644 --- a/lib/src/eval/compiler/declaration/field.dart +++ b/lib/src/eval/compiler/declaration/field.dart @@ -1,4 +1,5 @@ import 'package:analyzer/dart/ast/ast.dart'; +import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/compiler/context.dart'; import 'package:dart_eval/src/eval/compiler/errors.dart'; import 'package:dart_eval/src/eval/compiler/expression/expression.dart'; @@ -14,14 +15,14 @@ void compileFieldDeclaration(int fieldIndex, FieldDeclaration d, final fieldName = field.name.lexeme; if (d.isStatic) { final initializer = field.initializer; + TypeRef? type; + final specifiedType = d.fields.type; + if (specifiedType != null) { + type = TypeRef.fromAnnotation(ctx, ctx.library, specifiedType); + } if (initializer != null) { final pos = beginMethod(ctx, field, field.offset, '$fieldName*i'); ctx.beginAllocScope(); - TypeRef? type; - final specifiedType = d.fields.type; - if (specifiedType != null) { - type = TypeRef.fromAnnotation(ctx, ctx.library, specifiedType); - } var V = compileExpression(initializer, ctx, type); if (type != null) { if (!V.type.isAssignableTo(ctx, type)) { @@ -47,6 +48,9 @@ void compileFieldDeclaration(int fieldIndex, FieldDeclaration d, ctx.runtimeGlobalInitializerMap[_index] = pos; ctx.pushOp(Return.make(V.scopeFrameOffset), Return.LEN); ctx.endAllocScope(popValues: false); + } else { + ctx.topLevelVariableInferredTypes[ctx.library]![ + '$parentName.$fieldName'] = type ?? CoreTypes.dynamic.ref(ctx); } } else { final pos = beginMethod(ctx, d, d.offset, '$parentName.$fieldName (get)'); diff --git a/lib/src/eval/compiler/expression/assignment.dart b/lib/src/eval/compiler/expression/assignment.dart index 740fbad..f2d7895 100644 --- a/lib/src/eval/compiler/expression/assignment.dart +++ b/lib/src/eval/compiler/expression/assignment.dart @@ -10,7 +10,8 @@ import 'package:dart_eval/src/eval/compiler/variable.dart'; Variable compileAssignmentExpression( AssignmentExpression e, CompilerContext ctx) { final L = compileExpressionAsReference(e.leftHandSide, ctx); - final R = compileExpression(e.rightHandSide, ctx); + final R = + compileExpression(e.rightHandSide, ctx, L.resolveType(ctx, forSet: true)); if (e.operator.type == TokenType.EQ) { final set = diff --git a/lib/src/eval/compiler/expression/expression.dart b/lib/src/eval/compiler/expression/expression.dart index 8b0e255..0898b74 100644 --- a/lib/src/eval/compiler/expression/expression.dart +++ b/lib/src/eval/compiler/expression/expression.dart @@ -35,7 +35,7 @@ Variable compileExpression(Expression e, CompilerContext ctx, } else if (e is Identifier) { return compileIdentifier(e, ctx); } else if (e is MethodInvocation) { - return compileMethodInvocation(ctx, e); + return compileMethodInvocation(ctx, e, bound: bound); } else if (e is BinaryExpression) { return compileBinaryExpression(ctx, e, bound); } else if (e is PrefixExpression) { @@ -51,7 +51,7 @@ Variable compileExpression(Expression e, CompilerContext ctx, } else if (e is IndexExpression) { return compileIndexExpression(e, ctx); } else if (e is FunctionExpression) { - return compileFunctionExpression(e, ctx); + return compileFunctionExpression(e, ctx, bound); } else if (e is FunctionExpressionInvocation) { return compileFunctionExpressionInvocation(e, ctx); } else if (e is AwaitExpression) { diff --git a/lib/src/eval/compiler/expression/function.dart b/lib/src/eval/compiler/expression/function.dart index e3b5207..f3879d0 100644 --- a/lib/src/eval/compiler/expression/function.dart +++ b/lib/src/eval/compiler/expression/function.dart @@ -1,4 +1,5 @@ import 'package:analyzer/dart/ast/ast.dart'; +import 'package:collection/collection.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/compiler/builtins.dart'; import 'package:dart_eval/src/eval/compiler/context.dart'; @@ -6,6 +7,7 @@ import 'package:dart_eval/src/eval/compiler/errors.dart'; import 'package:dart_eval/src/eval/compiler/expression/expression.dart'; import 'package:dart_eval/src/eval/compiler/helpers/fpl.dart'; import 'package:dart_eval/src/eval/compiler/helpers/return.dart'; +import 'package:dart_eval/src/eval/compiler/model/function_type.dart'; import 'package:dart_eval/src/eval/compiler/offset_tracker.dart'; import 'package:dart_eval/src/eval/compiler/scope.dart'; import 'package:dart_eval/src/eval/compiler/statement/block.dart'; @@ -17,7 +19,8 @@ import 'package:dart_eval/src/eval/runtime/runtime.dart'; enum CallingConvention { static, dynamic } -Variable compileFunctionExpression(FunctionExpression e, CompilerContext ctx) { +Variable compileFunctionExpression(FunctionExpression e, CompilerContext ctx, + [TypeRef? bound]) { final jumpOver = ctx.pushOp(JumpConstant.make(-1), JumpConstant.LEN); final fnOffset = ctx.out.length; @@ -38,7 +41,24 @@ Variable compileFunctionExpression(FunctionExpression e, CompilerContext ctx) { final resolvedParams = resolveFPLDefaults(ctx, e.parameters, false, allowUnboxed: false, sortNamed: true); - var i = 1; + List boundNormalParams = []; + List boundOptionalParams = []; + List boundNamedParams = []; + if (bound != null) { + final functionType = bound.functionType; + if (functionType != null) { + boundNormalParams = functionType.normalParameters; + boundOptionalParams = functionType.optionalParameters; + boundNamedParams = functionType.namedParameters.entries + .map((e) => e.value) + .sorted((a, b) => a.name!.compareTo(b.name!)); + } + } + + final boundPositionalParams = [...boundNormalParams, ...boundOptionalParams]; + final inorderBoundParams = [...boundPositionalParams, ...boundNamedParams]; + + var i = 0; for (final param in resolvedParams) { final p = param.parameter; @@ -48,8 +68,13 @@ Variable compileFunctionExpression(FunctionExpression e, CompilerContext ctx) { var type = CoreTypes.dynamic.ref(ctx); if (p.type != null) { type = TypeRef.fromAnnotation(ctx, ctx.library, p.type!); + } else if (i < inorderBoundParams.length) { + final fType = inorderBoundParams[i].type; + if (fType.type != null) { + type = fType.type!; + } } - vRep = Variable(i, type.copyWith(boxed: true))..name = p.name!.lexeme; + vRep = Variable(i + 1, type.copyWith(boxed: true))..name = p.name!.lexeme; ctx.setLocal(vRep.name!, vRep); @@ -106,9 +131,18 @@ Variable compileFunctionExpression(FunctionExpression e, CompilerContext ctx) { ? a : (a as DefaultFormalParameter).parameter) .cast() - .map((a) => a.type == null - ? CoreTypes.dynamic.ref(ctx) - : TypeRef.fromAnnotation(ctx, ctx.library, a.type!)) + .mapIndexed((i, a) { + if (a.type != null) { + return TypeRef.fromAnnotation(ctx, ctx.library, a.type!); + } + if (i < boundPositionalParams.length) { + final fType = boundPositionalParams[i].type; + if (fType.type != null) { + return fType.type!; + } + } + return CoreTypes.dynamic.ref(ctx); + }) .map((t) => t.toRuntimeType(ctx)) .map((rt) => rt.toJson()) .toList(); @@ -123,9 +157,18 @@ Variable compileFunctionExpression(FunctionExpression e, CompilerContext ctx) { final sortedNamedArgTypes = sortedNamedArgs .map((e) => e is DefaultFormalParameter ? e.parameter : e) .cast() - .map((a) => a.type == null - ? CoreTypes.dynamic.ref(ctx) - : TypeRef.fromAnnotation(ctx, ctx.library, a.type!)) + .mapIndexed((i, a) { + if (a.type != null) { + return TypeRef.fromAnnotation(ctx, ctx.library, a.type!); + } + if (i < boundNamedParams.length) { + final fType = boundNamedParams[i].type; + if (fType.type != null) { + return fType.type!; + } + } + return CoreTypes.dynamic.ref(ctx); + }) .map((t) => t.toRuntimeType(ctx)) .map((rt) => rt.toJson()) .toList(); diff --git a/lib/src/eval/compiler/expression/method_invocation.dart b/lib/src/eval/compiler/expression/method_invocation.dart index 8f6358d..1618562 100644 --- a/lib/src/eval/compiler/expression/method_invocation.dart +++ b/lib/src/eval/compiler/expression/method_invocation.dart @@ -21,7 +21,7 @@ import 'expression.dart'; import 'identifier.dart'; Variable compileMethodInvocation(CompilerContext ctx, MethodInvocation e, - {Variable? cascadeTarget}) { + {TypeRef? bound, Variable? cascadeTarget}) { Variable? L = cascadeTarget; var isPrefix = false; if (e.target != null && cascadeTarget == null) { diff --git a/lib/src/eval/compiler/expression/string_interpolation.dart b/lib/src/eval/compiler/expression/string_interpolation.dart index 900e2e8..70772d5 100644 --- a/lib/src/eval/compiler/expression/string_interpolation.dart +++ b/lib/src/eval/compiler/expression/string_interpolation.dart @@ -11,8 +11,11 @@ Variable compileStringInterpolation( Variable? build; for (final element in str.elements) { if (element is InterpolationString) { - final _el = BuiltinValue(stringval: element.value).push(ctx); - build = build == null ? _el : build.invoke(ctx, '+', [_el]).result; + final sval = element.value; + if (sval.isNotEmpty) { + final _el = BuiltinValue(stringval: element.value).push(ctx); + build = build == null ? _el : build.invoke(ctx, '+', [_el]).result; + } } else if (element is InterpolationExpression) { final V = compileExpression(element.expression, ctx); Variable vStr; diff --git a/lib/src/eval/compiler/model/function_type.dart b/lib/src/eval/compiler/model/function_type.dart new file mode 100644 index 0000000..4b3af70 --- /dev/null +++ b/lib/src/eval/compiler/model/function_type.dart @@ -0,0 +1,95 @@ +import 'package:dart_eval/dart_eval_bridge.dart'; +import 'package:dart_eval/src/eval/compiler/context.dart'; +import 'package:dart_eval/src/eval/compiler/type.dart'; + +/// Represents either a real [TypeRef] or an unresolved type name e.g. +class FunctionTypeAnnotation { + final TypeRef? type; + final String? name; + + const FunctionTypeAnnotation.type(this.type) : name = null; + + const FunctionTypeAnnotation.name(this.name) : type = null; + + factory FunctionTypeAnnotation.fromBridgeAnnotation( + CompilerContext ctx, BridgeTypeAnnotation annotation) { + final _type = annotation.type; + if (_type.ref != null) { + return FunctionTypeAnnotation.name(_type.ref!); + } else { + return FunctionTypeAnnotation.type( + TypeRef.fromBridgeAnnotation(ctx, annotation)); + } + } + + factory FunctionTypeAnnotation.fromBridgeTypeRef( + CompilerContext ctx, BridgeTypeRef ref) { + return FunctionTypeAnnotation.type(TypeRef.fromBridgeTypeRef(ctx, ref)); + } +} + +class FunctionFormalParameter { + final String? name; + final FunctionTypeAnnotation type; + final bool isRequired; + + const FunctionFormalParameter(this.name, this.type, this.isRequired); +} + +class FunctionGenericParam { + final String name; + final FunctionTypeAnnotation? bound; + + const FunctionGenericParam(this.name, {this.bound}); +} + +class EvalFunctionType { + final List normalParameters; + final List optionalParameters; + final Map namedParameters; + final FunctionTypeAnnotation returnType; + final List generics; + + const EvalFunctionType(this.normalParameters, this.optionalParameters, + this.namedParameters, this.returnType, this.generics); + + factory EvalFunctionType.fromBridgeFunctionDef( + CompilerContext ctx, BridgeFunctionDef def) { + final fReturnType = + FunctionTypeAnnotation.fromBridgeAnnotation(ctx, def.returns); + + final fNormalParameters = []; + final fOptionalParameters = []; + final fNamedParameters = {}; + + for (final param in def.params) { + final fType = + FunctionTypeAnnotation.fromBridgeAnnotation(ctx, param.type); + final fParam = + FunctionFormalParameter(param.name, fType, !param.optional); + if (param.optional) { + fOptionalParameters.add(fParam); + } else { + fNormalParameters.add(fParam); + } + } + + for (final param in def.namedParams) { + final fType = + FunctionTypeAnnotation.fromBridgeAnnotation(ctx, param.type); + final fParam = + FunctionFormalParameter(param.name, fType, !param.optional); + fNamedParameters[param.name] = fParam; + } + + final fGenerics = def.generics.entries.map((entry) => FunctionGenericParam( + entry.key, + bound: entry.value.$extends != null + ? FunctionTypeAnnotation.fromBridgeTypeRef( + ctx, entry.value.$extends!) + : null)); + + return EvalFunctionType(fNormalParameters, fOptionalParameters, + fNamedParameters, fReturnType, fGenerics.toList()); + } +} diff --git a/lib/src/eval/compiler/offset_tracker.dart b/lib/src/eval/compiler/offset_tracker.dart index 46a8764..e50db89 100644 --- a/lib/src/eval/compiler/offset_tracker.dart +++ b/lib/src/eval/compiler/offset_tracker.dart @@ -75,4 +75,16 @@ class DeferredOrOffset { String toString() { return 'DeferredOrOffset{offset: $offset, file: $file, name: $name}'; } + + @override + bool operator ==(Object other) => + other is DeferredOrOffset && + other.offset == offset && + other.file == file && + other.className == className && + other.name == name; + + @override + int get hashCode => + offset.hashCode ^ className.hashCode ^ file.hashCode ^ name.hashCode; } diff --git a/lib/src/eval/compiler/type.dart b/lib/src/eval/compiler/type.dart index 1420b6a..6802d01 100644 --- a/lib/src/eval/compiler/type.dart +++ b/lib/src/eval/compiler/type.dart @@ -4,6 +4,7 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/compiler/expression/method_invocation.dart'; +import 'package:dart_eval/src/eval/compiler/model/function_type.dart'; import 'package:dart_eval/src/eval/runtime/type.dart'; import 'builtins.dart'; @@ -22,6 +23,7 @@ class TypeRef { this.genericParams = const [], this.specifiedTypeArgs = const [], this.resolved = false, + this.functionType = null, this.boxed = true, this.nullable = false}); @@ -38,6 +40,7 @@ class TypeRef { final List withType; final List genericParams; final List specifiedTypeArgs; + final EvalFunctionType? functionType; final bool resolved; final bool boxed; final bool nullable; @@ -173,7 +176,8 @@ class TypeRef { CompilerContext ctx, BridgeTypeAnnotation typeAnnotation, {TypeRef? specifyingType, TypeRef? specifiedType}) { return TypeRef.fromBridgeTypeRef(ctx, typeAnnotation.type, - specifyingType: specifyingType, specifiedType: specifiedType); + specifyingType: specifyingType, specifiedType: specifiedType) + .copyWith(nullable: typeAnnotation.nullable); } factory TypeRef.fromBridgeTypeRef( @@ -265,7 +269,8 @@ class TypeRef { } final gft = typeReference.gft; if (gft != null) { - return CoreTypes.function.ref(ctx); + return CoreTypes.function.ref(ctx).copyWith( + functionType: EvalFunctionType.fromBridgeFunctionDef(ctx, gft)); } throw CompileError( 'No support for looking up types by other bridge annotation types'); @@ -714,6 +719,7 @@ class TypeRef { List? withType, List? genericParams, List? specifiedTypeArgs, + EvalFunctionType? functionType, bool? boxed, bool? resolved, bool? nullable}) { @@ -723,6 +729,7 @@ class TypeRef { withType: withType ?? this.withType, genericParams: genericParams ?? this.genericParams, specifiedTypeArgs: specifiedTypeArgs ?? this.specifiedTypeArgs, + functionType: functionType ?? this.functionType, boxed: boxed ?? this.boxed, resolved: resolved ?? this.resolved, nullable: nullable ?? this.nullable); diff --git a/lib/src/eval/compiler/variable.dart b/lib/src/eval/compiler/variable.dart index 5636429..401ae24 100644 --- a/lib/src/eval/compiler/variable.dart +++ b/lib/src/eval/compiler/variable.dart @@ -4,6 +4,7 @@ import 'package:dart_eval/src/eval/compiler/builtins.dart'; import 'package:dart_eval/src/eval/compiler/collection/list.dart'; import 'package:dart_eval/src/eval/compiler/context.dart'; import 'package:dart_eval/src/eval/compiler/expression/function.dart'; +import 'package:dart_eval/src/eval/compiler/helpers/tearoff.dart'; import 'package:dart_eval/src/eval/compiler/type.dart'; import 'package:dart_eval/src/eval/runtime/runtime.dart'; @@ -254,6 +255,15 @@ class Variable { final checkEq = method == '==' && _args.length == 1; final checkNotEq = method == '!=' && _args.length == 1; if (checkEq || checkNotEq) { + if ($this.scopeFrameOffset == -1 && _args[0].scopeFrameOffset == -1) { + final result = $this.methodOffset! == _args[0].methodOffset!; + final rV = BuiltinValue(boolval: result).push(ctx); + return InvokeResult($this, rV, _args); + } else if ($this.scopeFrameOffset == -1) { + $this = $this.tearOff(ctx); + } else if (_args[0].scopeFrameOffset == -1) { + _args[0] = _args[0].tearOff(ctx); + } ctx.pushOp( CheckEq.make($this.scopeFrameOffset, _args[0].scopeFrameOffset), CheckEq.LEN); diff --git a/lib/src/eval/runtime/class.dart b/lib/src/eval/runtime/class.dart index b5c47c7..7f198d2 100644 --- a/lib/src/eval/runtime/class.dart +++ b/lib/src/eval/runtime/class.dart @@ -1,7 +1,9 @@ import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/runtime/exception.dart'; import 'package:dart_eval/src/eval/runtime/function.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; +import 'package:dart_eval/src/eval/shared/stdlib/core/base.dart'; +import 'package:dart_eval/src/eval/shared/stdlib/core/num.dart'; +import 'package:dart_eval/src/eval/shared/stdlib/core/type.dart'; /// Interface for objects with a backing value abstract class $Value { @@ -41,7 +43,10 @@ class $InstanceImpl implements $Instance { if (getter == null) { final method = evalClass.methods[identifier]; if (method == null) { - return evalSuperclass?.$getProperty(runtime, identifier); + if (evalSuperclass == null) { + return getCoreObjectProperty(identifier); + } + return evalSuperclass!.$getProperty(runtime, identifier); } return EvalStaticFunctionPtr(this, method); } @@ -66,6 +71,45 @@ class $InstanceImpl implements $Instance { runtime.bridgeCall(setter); } + $Value? getCoreObjectProperty(String identifier) { + switch (identifier) { + case 'hashCode': + return $int(hashCode); + case 'toString': + return __toString; + case '==': + return __equals; + case '!=': + return __notEquals; + case 'runtimeType': + return $TypeImpl(evalClass.delegatedType); + default: + throw EvalUnknownPropertyException(identifier); + } + } + + static const $Function __equals = $Function(_equals); + + static $Value? _equals(Runtime runtime, $Value? target, List<$Value?> args) { + final other = args[0]; + return $bool(target == other); + } + + static const $Function __notEquals = $Function(_notEquals); + + static $Value? _notEquals( + Runtime runtime, $Value? target, List<$Value?> args) { + final other = args[0]; + return $bool(target != other); + } + + static const $Function __toString = $Function(_toString); + + static $Value? _toString( + Runtime runtime, $Value? target, List<$Value?> args) { + return $String('object Object'); + } + @override Never get $reified => throw UnimplementedError(); diff --git a/lib/src/eval/runtime/declaration.dart b/lib/src/eval/runtime/declaration.dart index ef3d940..6a7b8fd 100644 --- a/lib/src/eval/runtime/declaration.dart +++ b/lib/src/eval/runtime/declaration.dart @@ -1,6 +1,5 @@ import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/runtime/class.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; /// A class is an instance of [Type] class EvalClass extends $InstanceImpl { @@ -81,4 +80,9 @@ class EvalClassClass implements EvalClass { @override int get delegatedType => throw UnimplementedError(); + + @override + $Value? getCoreObjectProperty(String identifier) { + throw UnimplementedError(); + } } diff --git a/lib/src/eval/runtime/function.dart b/lib/src/eval/runtime/function.dart index dd4851d..cbeeba5 100644 --- a/lib/src/eval/runtime/function.dart +++ b/lib/src/eval/runtime/function.dart @@ -1,6 +1,7 @@ import 'package:dart_eval/src/eval/runtime/exception.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/src/eval/runtime/type.dart'; +import 'package:dart_eval/src/eval/shared/stdlib/core/base.dart'; +import 'package:dart_eval/src/eval/shared/stdlib/core/num.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/object.dart'; import '../../../dart_eval_bridge.dart'; @@ -61,6 +62,31 @@ class EvalFunctionPtr extends EvalFunction { return runtime.returnValue as $Value?; } + @override + $Value? $getProperty(Runtime runtime, String identifier) { + switch (identifier) { + case '==': + return $Function((runtime, target, args) { + if (args.length != 1) { + throw ArgumentError('Expected 1 argument, got ${args.length}'); + } + final other = args[0]; + return $bool(other is EvalFunctionPtr && other.offset == offset); + }); + case '!=': + return $Function((runtime, target, args) { + if (args.length != 1) { + throw ArgumentError('Expected 1 argument, got ${args.length}'); + } + final other = args[0]; + return $bool(other is EvalFunctionPtr && other.offset != offset); + }); + case 'hashCode': + return $int(hashCode ^ offset.hashCode); + } + return super.$getProperty(runtime, identifier); + } + @override int $getRuntimeType(Runtime runtime) => runtime.lookupType(CoreTypes.function); @@ -91,6 +117,33 @@ class EvalStaticFunctionPtr extends EvalFunction { @override int $getRuntimeType(Runtime runtime) => runtime.lookupType(CoreTypes.function); + + @override + $Value? $getProperty(Runtime runtime, String identifier) { + switch (identifier) { + case '==': + return $Function((runtime, target, args) { + if (args.length != 1) { + throw ArgumentError('Expected 1 argument, got ${args.length}'); + } + final other = args[0]; + return $bool( + other is EvalStaticFunctionPtr && other.offset == offset); + }); + case '!=': + return $Function((runtime, target, args) { + if (args.length != 1) { + throw ArgumentError('Expected 1 argument, got ${args.length}'); + } + final other = args[0]; + return $bool( + other is EvalStaticFunctionPtr && other.offset != offset); + }); + case 'hashCode': + return $int(hashCode ^ offset.hashCode); + } + return super.$getProperty(runtime, identifier); + } } /// An implementation of [EvalFunction] that wraps an existing Dart function for @@ -118,12 +171,18 @@ class $Function extends EvalFunction { final EvalCallableFunc func; + get $value => func; + + get $reified => func; + @override $Value? $getProperty(Runtime runtime, String identifier) { try { return super.$getProperty(runtime, identifier); + } on UnimplementedError { + return $Object(this).$getProperty(runtime, identifier); } on EvalUnknownPropertyException { - return $Object($value).$getProperty(runtime, identifier); + return $Object(this).$getProperty(runtime, identifier); } } @@ -135,6 +194,11 @@ class $Function extends EvalFunction { @override int $getRuntimeType(Runtime runtime) => runtime.lookupType(CoreTypes.function); + + @override + String toString() { + return 'Function{func: $func}'; + } } /// Variant of [$Function] for use in a dynamic invocation / closure context, @@ -145,12 +209,18 @@ class $Closure extends EvalFunction { final EvalCallableFunc func; final $Instance? $this; + get $value => func; + + get $reified => func; + @override $Value? $getProperty(Runtime runtime, String identifier) { try { return super.$getProperty(runtime, identifier); + } on UnimplementedError { + return $Object(this).$getProperty(runtime, identifier); } on EvalUnknownPropertyException { - return $Object($value).$getProperty(runtime, identifier); + return $Object(this).$getProperty(runtime, identifier); } } diff --git a/lib/src/eval/runtime/ops/objects.dart b/lib/src/eval/runtime/ops/objects.dart index 3e4bf54..d48233a 100644 --- a/lib/src/eval/runtime/ops/objects.dart +++ b/lib/src/eval/runtime/ops/objects.dart @@ -250,16 +250,23 @@ class PushObjectProperty implements EvcOp { @override void run(Runtime runtime) { final _property = runtime.constantPool[_propertyIdx] as String; - var object = runtime.frame[_location]; + var base = runtime.frame[_location]; + var object = base; while (true) { if (object is $InstanceImpl) { + base = object; final evalClass = object.evalClass; final _offset = evalClass.getters[_property]; if (_offset == null) { final method = evalClass.methods[_property]; if (method == null) { object = object.evalSuperclass; + if (object == null) { + runtime.returnValue = + (base as $InstanceImpl).getCoreObjectProperty(_property); + return; + } continue; } runtime.returnValue = EvalStaticFunctionPtr(object, method); diff --git a/lib/src/eval/runtime/override.dart b/lib/src/eval/runtime/override.dart index 70a445c..438d834 100644 --- a/lib/src/eval/runtime/override.dart +++ b/lib/src/eval/runtime/override.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/compiler/model/override_spec.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/runtime/runtime.dart b/lib/src/eval/runtime/runtime.dart index 2607edb..6f77880 100644 --- a/lib/src/eval/runtime/runtime.dart +++ b/lib/src/eval/runtime/runtime.dart @@ -35,6 +35,8 @@ part 'ops/objects.dart'; part 'ops/bridge.dart'; +typedef TypeAutowrapper = $Value? Function(dynamic); + class ScopeFrame { const ScopeFrame(this.stackOffset, this.scopeStackOffset, [this.entrypoint = false]); @@ -84,7 +86,7 @@ class _UnloadedEnumValues { /// class Runtime { /// The current runtime version code - static const int versionCode = 75; + static const int versionCode = 79; /// Construct a runtime from EVC bytecode. When possible, use the /// [Runtime.ofProgram] constructor instead to reduce loading time. @@ -341,30 +343,61 @@ class Runtime { return null; } - /// Attempt to wrap a Dart value into a [$Value], and throw if unsuccessful. - $Value? wrap(dynamic value) { - if (value is $Value) { - return value; - } - return wrapPrimitive(value) ?? (throw Exception('Cannot wrap $value')); + /// Add a type autowrapper to the runtime. Type autowrappers are used to + /// automatically wrap values of a certain type into a [$Value]. They should + /// be used sparingly due to their high performance overhead. + /// + /// Type autowrappers should implement the code pattern: + /// ```dart + /// $Value? myTypeAutowrapper(dynamic value) { + /// if (value is MyType) { + /// return $MyType.wrap(value); + /// } else if (value is MyOtherType) { + /// return $MyOtherType.wrap(value); + /// } + /// return null; + /// } + /// ``` + void addTypeAutowrapper(TypeAutowrapper wrapper) { + _typeAutowrappers.add(wrapper); } - $Value? wrapRecursive(dynamic value) { + /// Attempt to wrap a Dart value into a [$Value], and throw if unsuccessful. + $Value wrap(dynamic value, {bool recursive = false}) { if (value is $Value) { return value; } if (value is List) { - return $List.wrap(value.map(wrapRecursive).toList()); + return recursive + ? $List.wrap(value.map((v) => wrap(v, recursive: true)).toList()) + : $List.wrap(value); } else if (value is Map) { - return $Map.wrap(value.map( - (key, value) => MapEntry(wrapRecursive(key), wrapRecursive(value)))); + return recursive + ? $Map.wrap(value.map((key, value) => MapEntry( + wrap(key, recursive: true), wrap(value, recursive: true)))) + : $Map.wrap(value); + } + for (final wrapper in _typeAutowrappers) { + final wrapped = wrapper(value); + if (wrapped != null) { + return wrapped; + } } - return wrapPrimitive(value) ?? (throw Exception('Cannot wrap $value')); + return wrapPrimitive(value) ?? + (throw Exception('Cannot wrap $value (${value.runtimeType}).' + 'If the type is known explicitly, use \${TypeName}.wrap(value); ' + 'otherwise, try adding a type autowrapper with ' + 'runtime.addTypeAutowrapper().')); } - $Value? wrapAlways(dynamic value) { + @Deprecated("Use runtime.wrap() with recursive:true instead") + $Value wrapRecursive(dynamic value) => wrap(value, recursive: true); + + /// Attempt to wrap a Dart value into a [$Value], falling back to wrapping + /// in an [$Object] + $Value wrapAlways(dynamic value, {bool recursive = false}) { try { - return wrapRecursive(value); + return wrap(value, recursive: recursive); } catch (e) { return $Object(value); } @@ -401,6 +434,7 @@ class Runtime { var globalInitializers = []; var overrideMap = {}; final _permissions = >{}; + final _typeAutowrappers = []; /// Write an [EvcOp] bytecode to a list of bytes. static List opcodeFrom(EvcOp op) { diff --git a/lib/src/eval/shared/stdlib/async.dart b/lib/src/eval/shared/stdlib/async.dart index 59fca81..0201023 100644 --- a/lib/src/eval/shared/stdlib/async.dart +++ b/lib/src/eval/shared/stdlib/async.dart @@ -1,7 +1,7 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/async/stream.dart'; import 'package:dart_eval/src/eval/shared/stdlib/async/stream_controller.dart'; +import 'package:dart_eval/src/eval/shared/stdlib/async/timer.dart'; import 'package:dart_eval/src/eval/shared/stdlib/async/zone.dart'; import 'async/future.dart'; @@ -18,6 +18,7 @@ class DartAsyncPlugin implements EvalPlugin { registry.defineBridgeClass($StreamController.$declaration); registry.defineBridgeClass($Zone.$declaration); registry.defineBridgeClass($StreamView.$declaration); + registry.defineBridgeClass($Timer.$declaration); } @override @@ -29,5 +30,9 @@ class DartAsyncPlugin implements EvalPlugin { runtime.registerBridgeFunc('dart:async', 'Zone.current*g', $Zone.$current); runtime.registerBridgeFunc('dart:async', 'Zone.root*g', $Zone.$root); runtime.registerBridgeFunc('dart:async', 'StreamView.', $StreamView.$new); + runtime.registerBridgeFunc('dart:async', 'Timer.', $Timer.$new); + runtime.registerBridgeFunc( + 'dart:async', 'Timer.periodic', $Timer.$periodic); + runtime.registerBridgeFunc('dart:async', 'Timer.run', $Timer.$run); } } diff --git a/lib/src/eval/shared/stdlib/async/future.dart b/lib/src/eval/shared/stdlib/async/future.dart index 451339d..fb16db7 100644 --- a/lib/src/eval/shared/stdlib/async/future.dart +++ b/lib/src/eval/shared/stdlib/async/future.dart @@ -2,7 +2,6 @@ import 'dart:async'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/future.dart'; diff --git a/lib/src/eval/shared/stdlib/async/stream.dart b/lib/src/eval/shared/stdlib/async/stream.dart index 2bab57a..c4d2ba0 100644 --- a/lib/src/eval/shared/stdlib/async/stream.dart +++ b/lib/src/eval/shared/stdlib/async/stream.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:dart_eval/dart_eval_bridge.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/stdlib/core.dart'; /// dart_eval wrapper for [StreamSubscription] diff --git a/lib/src/eval/shared/stdlib/async/stream_controller.dart b/lib/src/eval/shared/stdlib/async/stream_controller.dart index c10548f..e44f60a 100644 --- a/lib/src/eval/shared/stdlib/async/stream_controller.dart +++ b/lib/src/eval/shared/stdlib/async/stream_controller.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/async/stream.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/async/timer.dart b/lib/src/eval/shared/stdlib/async/timer.dart new file mode 100644 index 0000000..0c9a600 --- /dev/null +++ b/lib/src/eval/shared/stdlib/async/timer.dart @@ -0,0 +1,116 @@ +import 'dart:async'; +import 'package:dart_eval/dart_eval_bridge.dart'; +import 'package:dart_eval/stdlib/core.dart'; + +/// dart_eval wrapper for [Timer] +class $Timer implements $Instance { + static const _$type = BridgeTypeRef(AsyncTypes.timer); + + static const $declaration = BridgeClassDef(BridgeClassType(_$type), + constructors: { + '': BridgeConstructorDef( + BridgeFunctionDef(returns: BridgeTypeAnnotation(_$type), params: [ + BridgeParameter( + 'duration', + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.duration)), + false), + BridgeParameter( + 'callback', + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.function)), + false) + ], namedParams: []), + isFactory: true), + 'periodic': BridgeConstructorDef( + BridgeFunctionDef(returns: BridgeTypeAnnotation(_$type), params: [ + BridgeParameter('duration', + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.duration)), false), + BridgeParameter('callback', + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.function)), false) + ], namedParams: [])), + }, + methods: { + 'run': BridgeMethodDef( + BridgeFunctionDef( + returns: + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.voidType)), + params: [ + BridgeParameter( + 'callback', + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.function)), + false) + ], + namedParams: []), + isStatic: true), + 'cancel': BridgeMethodDef(BridgeFunctionDef( + returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.voidType)))), + }, + getters: { + 'tick': BridgeMethodDef(BridgeFunctionDef( + returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)))), + 'isActive': BridgeMethodDef(BridgeFunctionDef( + returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)))), + }, + setters: {}, + fields: {}, + wrap: true); + + /// Create a new [Timer] with [args] + static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) { + return $Timer.wrap(Timer(Duration(milliseconds: args[0]!.$value as int), + () => (args[1]!.$value as EvalFunction).call(runtime, null, []))); + } + + /// Create a new [Timer.periodic] with [args] + static $Value? $periodic( + Runtime runtime, $Value? target, List<$Value?> args) { + return $Timer.wrap(Timer.periodic( + Duration(milliseconds: args[0]!.$value as int), + (timer) => (args[1]!.$value as EvalFunction) + .call(runtime, null, [$Timer.wrap(timer)]))); + } + + /// Run a [Timer] with [args] + static $Value? $run(Runtime runtime, $Value? target, List<$Value?> args) { + Timer.run(() => (args[0]!.$value as EvalFunction).call(runtime, null, [])); + return null; + } + + final $Instance _superclass; + + /// Wrap a [Timer] in a [$Timer] + $Timer.wrap(this.$value) : _superclass = $Object($value); + + @override + final Timer $value; + + @override + Timer get $reified => $value; + + @override + int $getRuntimeType(Runtime runtime) => throw UnimplementedError(); + + @override + $Value? $getProperty(Runtime runtime, String identifier) { + switch (identifier) { + case 'tick': + return $int($value.tick); + case 'isActive': + return $bool($value.isActive); + case 'cancel': + return __$cancel; + } + return _superclass.$getProperty(runtime, identifier); + } + + static const $Function __$cancel = $Function(_$cancel); + + static $Value? _$cancel(Runtime runtime, $Value? target, List<$Value?> args) { + (target!.$value as Timer).cancel(); + return null; + } + + @override + void $setProperty(Runtime runtime, String identifier, $Value value) { + return _superclass.$setProperty(runtime, identifier, value); + } +} diff --git a/lib/src/eval/shared/stdlib/async/zone.dart b/lib/src/eval/shared/stdlib/async/zone.dart index 7fa49a1..06df84b 100644 --- a/lib/src/eval/shared/stdlib/async/zone.dart +++ b/lib/src/eval/shared/stdlib/async/zone.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/collection.dart b/lib/src/eval/shared/stdlib/collection.dart index e26cd3c..fcb8706 100644 --- a/lib/src/eval/shared/stdlib/collection.dart +++ b/lib/src/eval/shared/stdlib/collection.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/collection/linked_hash_map.dart'; diff --git a/lib/src/eval/shared/stdlib/collection/linked_hash_map.dart b/lib/src/eval/shared/stdlib/collection/linked_hash_map.dart index 1241a26..dbc137e 100644 --- a/lib/src/eval/shared/stdlib/collection/linked_hash_map.dart +++ b/lib/src/eval/shared/stdlib/collection/linked_hash_map.dart @@ -1,6 +1,5 @@ import 'dart:collection'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/collection.dart'; diff --git a/lib/src/eval/shared/stdlib/convert.dart b/lib/src/eval/shared/stdlib/convert.dart index ec85771..666ae85 100644 --- a/lib/src/eval/shared/stdlib/convert.dart +++ b/lib/src/eval/shared/stdlib/convert.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/convert/base64.dart'; import 'package:dart_eval/src/eval/shared/stdlib/convert/codec.dart'; diff --git a/lib/src/eval/shared/stdlib/convert/base64.dart b/lib/src/eval/shared/stdlib/convert/base64.dart index 91edca1..4a10ab0 100644 --- a/lib/src/eval/shared/stdlib/convert/base64.dart +++ b/lib/src/eval/shared/stdlib/convert/base64.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/convert/codec.dart'; import 'package:dart_eval/src/eval/shared/stdlib/convert/converter.dart'; diff --git a/lib/src/eval/shared/stdlib/convert/codec.dart b/lib/src/eval/shared/stdlib/convert/codec.dart index 7b0a468..303e88e 100644 --- a/lib/src/eval/shared/stdlib/convert/codec.dart +++ b/lib/src/eval/shared/stdlib/convert/codec.dart @@ -1,6 +1,5 @@ import 'dart:convert'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/convert/converter.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/object.dart'; @@ -83,7 +82,7 @@ class $Codec implements $Instance { static $Value? _decode(Runtime runtime, $Value? target, List<$Value?> args) { final encoded = args[0]!.$value; final result = (target!.$value as Codec).decode(encoded); - return runtime.wrapRecursive(result); + return runtime.wrap(result, recursive: true); } @override diff --git a/lib/src/eval/shared/stdlib/convert/converter.dart b/lib/src/eval/shared/stdlib/convert/converter.dart index ac70b39..a1fb28c 100644 --- a/lib/src/eval/shared/stdlib/convert/converter.dart +++ b/lib/src/eval/shared/stdlib/convert/converter.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:convert'; import 'package:dart_eval/dart_eval_bridge.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/src/eval/shared/stdlib/async/stream.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/object.dart'; diff --git a/lib/src/eval/shared/stdlib/convert/encoding.dart b/lib/src/eval/shared/stdlib/convert/encoding.dart index dea821a..e4fabed 100644 --- a/lib/src/eval/shared/stdlib/convert/encoding.dart +++ b/lib/src/eval/shared/stdlib/convert/encoding.dart @@ -1,6 +1,5 @@ import 'dart:convert'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/convert/codec.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/base.dart'; diff --git a/lib/src/eval/shared/stdlib/convert/json.dart b/lib/src/eval/shared/stdlib/convert/json.dart index f882b33..a48361c 100644 --- a/lib/src/eval/shared/stdlib/convert/json.dart +++ b/lib/src/eval/shared/stdlib/convert/json.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/convert/codec.dart'; import 'package:dart_eval/src/eval/shared/stdlib/convert/converter.dart'; @@ -310,16 +309,16 @@ class $JsonEncodeAndDecode { static const __$jsonDecode = $Function(_$decode); static $Value? _$decode(Runtime runtime, $Value? target, List<$Value?> args) { final reviver = args[1]?.$value as EvalCallable?; - return runtime.wrapRecursive( - jsonDecode(args[0]?.$value, - reviver: reviver == null - ? null - : (key, value) { - return reviver.call(runtime, null, [ - runtime.wrapPrimitive(key) ?? key as $Value?, - runtime.wrapPrimitive(value) ?? value as $Value? - ])?.$value; - }), - ); + return runtime.wrap( + jsonDecode(args[0]?.$value, + reviver: reviver == null + ? null + : (key, value) { + return reviver.call(runtime, null, [ + runtime.wrapPrimitive(key) ?? key as $Value?, + runtime.wrapPrimitive(value) ?? value as $Value? + ])?.$value; + }), + recursive: true); } } diff --git a/lib/src/eval/shared/stdlib/convert/utf.dart b/lib/src/eval/shared/stdlib/convert/utf.dart index 4cd80b2..8fd9663 100644 --- a/lib/src/eval/shared/stdlib/convert/utf.dart +++ b/lib/src/eval/shared/stdlib/convert/utf.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/convert/converter.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/core.dart b/lib/src/eval/shared/stdlib/core.dart index fb59b4a..504b1c9 100644 --- a/lib/src/eval/shared/stdlib/core.dart +++ b/lib/src/eval/shared/stdlib/core.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/async/stream.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/base.dart'; diff --git a/lib/src/eval/shared/stdlib/core/base.dart b/lib/src/eval/shared/stdlib/core/base.dart index cac73d3..c352ce9 100644 --- a/lib/src/eval/shared/stdlib/core/base.dart +++ b/lib/src/eval/shared/stdlib/core/base.dart @@ -1,6 +1,5 @@ import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/runtime/exception.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/collection.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/object.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/pattern.dart'; diff --git a/lib/src/eval/shared/stdlib/core/collection.dart b/lib/src/eval/shared/stdlib/core/collection.dart index fb30901..f7cf0f0 100644 --- a/lib/src/eval/shared/stdlib/core/collection.dart +++ b/lib/src/eval/shared/stdlib/core/collection.dart @@ -1,6 +1,5 @@ import 'dart:math'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/iterator.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/core/comparable.dart b/lib/src/eval/shared/stdlib/core/comparable.dart index 264032b..a9fcb29 100644 --- a/lib/src/eval/shared/stdlib/core/comparable.dart +++ b/lib/src/eval/shared/stdlib/core/comparable.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/num.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/object.dart'; diff --git a/lib/src/eval/shared/stdlib/core/date_time.dart b/lib/src/eval/shared/stdlib/core/date_time.dart index 549cf99..0ed21ad 100644 --- a/lib/src/eval/shared/stdlib/core/date_time.dart +++ b/lib/src/eval/shared/stdlib/core/date_time.dart @@ -1,6 +1,5 @@ // ignore_for_file: body_might_complete_normally_nullable -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/core/duration.dart b/lib/src/eval/shared/stdlib/core/duration.dart index d16617d..3aae870 100644 --- a/lib/src/eval/shared/stdlib/core/duration.dart +++ b/lib/src/eval/shared/stdlib/core/duration.dart @@ -1,7 +1,6 @@ // ignore_for_file: camel_case_types import 'package:dart_eval/dart_eval_bridge.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/base.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/num.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/object.dart'; diff --git a/lib/src/eval/shared/stdlib/core/errors.dart b/lib/src/eval/shared/stdlib/core/errors.dart index acb89fa..434c07c 100644 --- a/lib/src/eval/shared/stdlib/core/errors.dart +++ b/lib/src/eval/shared/stdlib/core/errors.dart @@ -1,6 +1,5 @@ // ignore_for_file: non_constant_identifier_names -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/base.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/num.dart'; diff --git a/lib/src/eval/shared/stdlib/core/exceptions.dart b/lib/src/eval/shared/stdlib/core/exceptions.dart index 07607df..cafd722 100644 --- a/lib/src/eval/shared/stdlib/core/exceptions.dart +++ b/lib/src/eval/shared/stdlib/core/exceptions.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/object.dart'; diff --git a/lib/src/eval/shared/stdlib/core/future.dart b/lib/src/eval/shared/stdlib/core/future.dart index 137e0b6..679ee0b 100644 --- a/lib/src/eval/shared/stdlib/core/future.dart +++ b/lib/src/eval/shared/stdlib/core/future.dart @@ -2,7 +2,6 @@ import 'dart:async'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; @@ -47,7 +46,8 @@ class $Future implements Future, $Instance { final Future $value; @override - Future get $reified => $value; + Future get $reified => + $value.then((value) => value is $Value ? value.$value : value); final $Instance _superclass; diff --git a/lib/src/eval/shared/stdlib/core/identical.dart b/lib/src/eval/shared/stdlib/core/identical.dart index 8d592ad..d7825ab 100644 --- a/lib/src/eval/shared/stdlib/core/identical.dart +++ b/lib/src/eval/shared/stdlib/core/identical.dart @@ -1,5 +1,4 @@ import 'package:dart_eval/dart_eval_bridge.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/base.dart'; void configureIdenticalForCompile(BridgeDeclarationRegistry registry) { diff --git a/lib/src/eval/shared/stdlib/core/iterator.dart b/lib/src/eval/shared/stdlib/core/iterator.dart index 070d101..ca97f83 100644 --- a/lib/src/eval/shared/stdlib/core/iterator.dart +++ b/lib/src/eval/shared/stdlib/core/iterator.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/core/num.dart b/lib/src/eval/shared/stdlib/core/num.dart index ef82d73..5f7bade 100644 --- a/lib/src/eval/shared/stdlib/core/num.dart +++ b/lib/src/eval/shared/stdlib/core/num.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/core/object.dart b/lib/src/eval/shared/stdlib/core/object.dart index f3b337b..7e3bca3 100644 --- a/lib/src/eval/shared/stdlib/core/object.dart +++ b/lib/src/eval/shared/stdlib/core/object.dart @@ -1,6 +1,5 @@ // ignore_for_file: non_constant_identifier_names -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/core/pattern.dart b/lib/src/eval/shared/stdlib/core/pattern.dart index fdbc0d9..b6c408a 100644 --- a/lib/src/eval/shared/stdlib/core/pattern.dart +++ b/lib/src/eval/shared/stdlib/core/pattern.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/core/print.dart b/lib/src/eval/shared/stdlib/core/print.dart index b1283e1..85be660 100644 --- a/lib/src/eval/shared/stdlib/core/print.dart +++ b/lib/src/eval/shared/stdlib/core/print.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; void configurePrintForCompile(BridgeDeclarationRegistry registry) { diff --git a/lib/src/eval/shared/stdlib/core/regexp.dart b/lib/src/eval/shared/stdlib/core/regexp.dart index 11b600f..6ab119a 100644 --- a/lib/src/eval/shared/stdlib/core/regexp.dart +++ b/lib/src/eval/shared/stdlib/core/regexp.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/core/stack_trace.dart b/lib/src/eval/shared/stdlib/core/stack_trace.dart index 1d6cf35..b77de67 100644 --- a/lib/src/eval/shared/stdlib/core/stack_trace.dart +++ b/lib/src/eval/shared/stdlib/core/stack_trace.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/object.dart'; diff --git a/lib/src/eval/shared/stdlib/core/string_buffer.dart b/lib/src/eval/shared/stdlib/core/string_buffer.dart index f36bcff..2bfc59a 100644 --- a/lib/src/eval/shared/stdlib/core/string_buffer.dart +++ b/lib/src/eval/shared/stdlib/core/string_buffer.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/num.dart'; import 'package:dart_eval/src/eval/shared/stdlib/io/string_sink.dart'; diff --git a/lib/src/eval/shared/stdlib/core/symbol.dart b/lib/src/eval/shared/stdlib/core/symbol.dart index 636af31..ead60a0 100644 --- a/lib/src/eval/shared/stdlib/core/symbol.dart +++ b/lib/src/eval/shared/stdlib/core/symbol.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/core/type.dart b/lib/src/eval/shared/stdlib/core/type.dart index 0b256a5..42efc56 100644 --- a/lib/src/eval/shared/stdlib/core/type.dart +++ b/lib/src/eval/shared/stdlib/core/type.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/core/uri.dart b/lib/src/eval/shared/stdlib/core/uri.dart index 1cd6c60..0187e5e 100644 --- a/lib/src/eval/shared/stdlib/core/uri.dart +++ b/lib/src/eval/shared/stdlib/core/uri.dart @@ -1,6 +1,5 @@ import 'dart:convert'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/utils/wap_helper.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/io.dart b/lib/src/eval/shared/stdlib/io.dart index e17d8cb..056443c 100644 --- a/lib/src/eval/shared/stdlib/io.dart +++ b/lib/src/eval/shared/stdlib/io.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/io/directory.dart'; import 'package:dart_eval/src/eval/shared/stdlib/io/file.dart'; diff --git a/lib/src/eval/shared/stdlib/io/directory.dart b/lib/src/eval/shared/stdlib/io/directory.dart index 060030f..1ea23cd 100644 --- a/lib/src/eval/shared/stdlib/io/directory.dart +++ b/lib/src/eval/shared/stdlib/io/directory.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/async/stream.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/collection.dart'; diff --git a/lib/src/eval/shared/stdlib/io/file.dart b/lib/src/eval/shared/stdlib/io/file.dart index b30b2ab..de59801 100644 --- a/lib/src/eval/shared/stdlib/io/file.dart +++ b/lib/src/eval/shared/stdlib/io/file.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/base.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/collection.dart'; diff --git a/lib/src/eval/shared/stdlib/io/file_system_entity.dart b/lib/src/eval/shared/stdlib/io/file_system_entity.dart index c524713..07f94cb 100644 --- a/lib/src/eval/shared/stdlib/io/file_system_entity.dart +++ b/lib/src/eval/shared/stdlib/io/file_system_entity.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:dart_eval/dart_eval_bridge.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/src/eval/shared/stdlib/io/directory.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/io/http.dart b/lib/src/eval/shared/stdlib/io/http.dart index ebd0c52..c048e1b 100644 --- a/lib/src/eval/shared/stdlib/io/http.dart +++ b/lib/src/eval/shared/stdlib/io/http.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:dart_eval/dart_eval_bridge.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/src/eval/shared/stdlib/async/stream.dart'; import 'package:dart_eval/src/eval/shared/stdlib/io/io_sink.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/io/io_sink.dart b/lib/src/eval/shared/stdlib/io/io_sink.dart index 1618c4c..0b53149 100644 --- a/lib/src/eval/shared/stdlib/io/io_sink.dart +++ b/lib/src/eval/shared/stdlib/io/io_sink.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:dart_eval/dart_eval_bridge.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/src/eval/shared/stdlib/async/stream.dart'; import 'package:dart_eval/src/eval/shared/stdlib/io/string_sink.dart'; diff --git a/lib/src/eval/shared/stdlib/io/socket.dart b/lib/src/eval/shared/stdlib/io/socket.dart index 712d070..e4ca838 100644 --- a/lib/src/eval/shared/stdlib/io/socket.dart +++ b/lib/src/eval/shared/stdlib/io/socket.dart @@ -2,7 +2,6 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:dart_eval/dart_eval_bridge.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/src/eval/shared/stdlib/typed_data/typed_data.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/stdlib/io/string_sink.dart b/lib/src/eval/shared/stdlib/io/string_sink.dart index efcde4e..af7d904 100644 --- a/lib/src/eval/shared/stdlib/io/string_sink.dart +++ b/lib/src/eval/shared/stdlib/io/string_sink.dart @@ -1,5 +1,4 @@ import 'package:dart_eval/dart_eval_bridge.dart'; -import 'package:dart_eval/src/eval/runtime/runtime.dart'; import 'package:dart_eval/stdlib/core.dart'; /// dart_eval wrapper for [StringSink] diff --git a/lib/src/eval/shared/stdlib/math.dart b/lib/src/eval/shared/stdlib/math.dart index 89f8ace..be1c956 100644 --- a/lib/src/eval/shared/stdlib/math.dart +++ b/lib/src/eval/shared/stdlib/math.dart @@ -1,5 +1,4 @@ import 'dart:math' as math; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/core/num.dart'; import 'math/point.dart'; diff --git a/lib/src/eval/shared/stdlib/typed_data.dart b/lib/src/eval/shared/stdlib/typed_data.dart index 110462c..25f4482 100644 --- a/lib/src/eval/shared/stdlib/typed_data.dart +++ b/lib/src/eval/shared/stdlib/typed_data.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/src/eval/shared/stdlib/typed_data/typed_data.dart'; diff --git a/lib/src/eval/shared/stdlib/typed_data/typed_data.dart b/lib/src/eval/shared/stdlib/typed_data/typed_data.dart index 6956ff4..0c74e9c 100644 --- a/lib/src/eval/shared/stdlib/typed_data/typed_data.dart +++ b/lib/src/eval/shared/stdlib/typed_data/typed_data.dart @@ -1,5 +1,4 @@ import 'dart:typed_data'; -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/lib/src/eval/shared/types.dart b/lib/src/eval/shared/types.dart index e6b8d4f..b99d90a 100644 --- a/lib/src/eval/shared/types.dart +++ b/lib/src/eval/shared/types.dart @@ -151,6 +151,9 @@ class AsyncTypes { /// Bridge type spec for [$StreamView] static const streamView = BridgeTypeSpec('dart:async', 'StreamView'); + /// Bridge type spec for [$Timer] + static const timer = BridgeTypeSpec('dart:async', 'Timer'); + /// Bridge type spec for [$Zone] static const zone = BridgeTypeSpec('dart:async', 'Zone'); } diff --git a/pubspec.yaml b/pubspec.yaml index 7da96b8..610a001 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: dart_eval description: A flexible Dart bytecode compiler and interpreter written in Dart, enabling dynamic execution and code push for AOT Dart apps. -version: 0.7.8 +version: 0.7.9 homepage: https://github.com/ethanblake4/dart_eval platforms: android: diff --git a/test/async_test.dart b/test/async_test.dart index 4e1c48c..1692c2a 100644 --- a/test/async_test.dart +++ b/test/async_test.dart @@ -28,7 +28,7 @@ void main() { await expectLater(future, completion($int(3))); final endTime = DateTime.now().millisecondsSinceEpoch; expect(endTime - startTime, greaterThan(80)); - expect(endTime - startTime, lessThan(300)); + expect(endTime - startTime, lessThan(350)); }); test('Chained async/await', () async { diff --git a/test/bridge_lib.dart b/test/bridge_lib.dart index da65841..17fcc93 100644 --- a/test/bridge_lib.dart +++ b/test/bridge_lib.dart @@ -1,4 +1,3 @@ -import 'package:dart_eval/dart_eval.dart'; import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; diff --git a/test/class_test.dart b/test/class_test.dart index 3286608..418b543 100644 --- a/test/class_test.dart +++ b/test/class_test.dart @@ -493,6 +493,48 @@ void main() { expect(runtime.executeLib('package:example/main.dart', 'main'), 15); }); + test('Nullable static value', () { + final runtime = compiler.compileWriteAndLoad({ + 'example': { + 'main.dart': ''' + class TestA { + static int? value; + } + + int? main() { + TestA.value = 22; + return TestA.value; + } + ''' + } + }); + + expect(runtime.executeLib('package:example/main.dart', 'main'), $int(22)); + }); + + test('Using set value', () { + final runtime = compiler.compileWriteAndLoad({ + 'example': { + 'main.dart': ''' + class TestClass { + int tempValue = 0; + } + + bool main() { + final testClass = TestClass(); + testClass.tempValue = testClass.hashCode; + print('hashCode \${testClass.tempValue}'); + return true; + } + ''' + } + }); + + expect(() { + runtime.executeLib('package:example/main.dart', 'main'); + }, prints(startsWith('hashCode '))); + }); + /* test('Super parameter multi-level indirection', () { final runtime = compiler.compileWriteAndLoad({ 'example': { diff --git a/test/collection_test.dart b/test/collection_test.dart index 1d6c141..8bf35f2 100644 --- a/test/collection_test.dart +++ b/test/collection_test.dart @@ -187,5 +187,23 @@ void main() { expect(runtime.executeLib('package:eval_test/main.dart', 'main'), true); }); + + test('Map null values == null', () { + final runtime = compiler.compileWriteAndLoad({ + 'eval_test': { + 'main.dart': ''' + bool main() { + final e = [{'name': null}]; + for (var item in e) { + bool ifNull = item['name'] == null; + return ifNull; + } + } + ''' + } + }); + + expect(runtime.executeLib('package:eval_test/main.dart', 'main'), true); + }); }); } diff --git a/test/function_test.dart b/test/function_test.dart index 4328b4a..dbcb68d 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -1,4 +1,5 @@ import 'package:dart_eval/dart_eval.dart'; +import 'package:dart_eval/dart_eval_bridge.dart'; import 'package:dart_eval/stdlib/core.dart'; import 'package:test/test.dart'; @@ -47,24 +48,6 @@ void main() { expect(runtime.executeLib('package:eval_test/main.dart', 'main'), 7); }); - test('idk', () { - final runtime = compiler.compileWriteAndLoad({ - 'eval_test': { - 'main.dart': ''' - int main() { - return test(); - } - int test({bool bigger = true}) { - final num = (bigger) ? 10 : 5; - return num; - } - ''' - } - }); - - expect(runtime.executeLib('package:eval_test/main.dart', 'main'), 10); - }); - test('Recursion (fibonacci)', () { final runtime = compiler.compileWriteAndLoad({ 'example': { @@ -232,6 +215,25 @@ void main() { expect(runtime.executeLib('package:example/main.dart', 'main'), $int(3)); }); + test('Anonymous function with many unordered named args', () { + final runtime = compiler.compileWriteAndLoad({ + 'example': { + 'main.dart': ''' + num main () { + var myfunc = ({d, a, b, c, e}) { + return d * e + a / c + b; + }; + + return myfunc(a: 2, b: 4, c: 2, d: 3, e: 4); + } + ''' + } + }); + + expect( + runtime.executeLib('package:example/main.dart', 'main'), $double(17)); + }); + test('Closure with arg', () { final runtime = compiler.compileWriteAndLoad({ 'example': { @@ -373,5 +375,45 @@ void main() { expect(runtime.executeLib('package:example/main.dart', 'main'), 3); }); + + test('Function equality test', () { + final runtime = compiler.compileWriteAndLoad({ + 'example': { + 'main.dart': ''' + class TestClass { + static TestClass instance = TestClass(); + + Function? _callback; + + void init(Function callback) { + _callback = callback; + } + + void runFunction() { + _callback!('Hello'); + } + } + + void main(Function callback) { + TestClass.instance.init(callback); + TestClass.instance.runFunction(callback); + print(fun == fun); + print(fun == callback); + } + + int fun() => 1; + ''' + } + }); + + expect( + () => runtime.executeLib('package:example/main.dart', 'main', [ + $Closure((runtime, target, args) { + print(args[0]!.$value + '!'); + return null; + }) + ]), + prints('Hello!\ntrue\nfalse\n')); + }); }); }