ethanblake4 / dart_eval

Extensible Dart interpreter for Dart with full interop
https://pub.dev/packages/dart_eval
BSD 3-Clause "New" or "Revised" License
334 stars 40 forks source link

[Question] cannot extends bridge class #126

Closed Noobware1 closed 1 year ago

Noobware1 commented 1 year ago

i am getting this error

Unhandled exception:
Null check operator used on a null value
#0      compileDefaultConstructor (package:dart_eval/src/eval/compiler/declaration/constructor.dart:286:94)
#1      compileClassDeclaration (package:dart_eval/src/eval/compiler/declaration/class.dart:30:5)
#2      compileDeclaration (package:dart_eval/src/eval/compiler/declaration/declaration.dart:17:5)
#3      Compiler.compileSources.<anonymous closure>.<anonymous closure> (package:dart_eval/src/eval/compiler/compiler.dart:427:11)
#4      _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:625:13)
#5      Compiler.compileSources.<anonymous closure> (package:dart_eval/src/eval/compiler/compiler.dart:416:15)
#6      _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:625:13)
#7      Compiler.compileSources (package:dart_eval/src/eval/compiler/compiler.dart:413:32)
#8      Compiler.compile (package:dart_eval/src/eval/compiler/compiler.dart:146:12)
#9      compilerEval (package:extenstions_test/extenstions_test.dart:41:28)
#10     main (package:extenstions_test/extenstions_test.dart:91:20)
<asynchronous suspension>

from this eval code

import 'package:bridge_lib/bridge_lib.dart';

class TestPlugin extends BasePluginApi {
  @override
  Future<List<String>> search(String query) async {
    return ['testPassed'];
  }
}

getPlugin() {
  return TestPlugin();
}

here is the implementation

import 'package:dart_eval/dart_eval_bridge.dart';
import 'package:dart_eval/src/eval/runtime/runtime.dart';
import 'package:dart_eval/stdlib/core.dart';
// import 'package:extenstions_test/bridge_models/search_response.dart';
import 'package:extenstions_test/constants/bridge.dart';
import 'package:extenstions_test/extenstions/iterable.dart';

abstract class BasePluginApi {
  Future<List<String>> search(String query);
}

class $BasePluginApi extends BasePluginApi with $Bridge<BasePluginApi> {
  $BasePluginApi() : super();

  static const $type =
      BridgeTypeRef(BridgeTypeSpec(bridgeLibary, 'BasePluginApi'));

  static const $declaration =
      BridgeClassDef(BridgeClassType($type, isAbstract: true),
          constructors: {
            '': BridgeConstructorDef(BridgeFunctionDef(
                returns: BridgeTypeAnnotation($type),
                namedParams: [],
                params: []))
          },
          methods: {
            'search': BridgeMethodDef(
              BridgeFunctionDef(
                  returns: BridgeTypeAnnotation(
                    BridgeTypeRef(CoreTypes.future, [
                      BridgeTypeRef(CoreTypes.list,
                          [BridgeTypeRef.type(RuntimeTypes.stringType)]),
                    ]),
                  ),
                  params: [
                    BridgeParameter(
                        'query',
                        BridgeTypeAnnotation(
                            BridgeTypeRef.type(RuntimeTypes.stringType)),
                        false)
                  ]),
            )
          },
          bridge: true);

  static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) {
    return $BasePluginApi();
  }

  static $Value? $search(Runtime runtime, $Value? target, List<$Value?> args) {
    return $Future.wrap((target?.$value as BasePluginApi)
        .search(args[0]?.$value)
        .then((value) => $List.wrap(value.mapAsList((it) => $String(it)))));
  }

  @override
  Future<List<String>> search(String query) =>
      $_invoke('search', [$String(query)]);

  @override
  $Value? $bridgeGet(String identifier) {
    switch (identifier) {
      case 'search':
        return $Function($search);
      default:
        return null;
    }
  }

  @override
  void $bridgeSet(String identifier, $Value value) {}
}

and here is how i am using it

import 'dart:io';
import 'dart:typed_data';

import 'package:dart_eval/dart_eval.dart';
import 'package:extenstions_test/bridge_models/plugin/base_plugin_api.dart';
import 'package:extenstions_test/constants/bridge.dart';

Uint8List compilerEval(String sourceCode) {
  final compiler = Compiler();

  compiler.defineBridgeClasses([
    $BasePluginApi.$declaration,
  ]);
  final program = compiler.compile({
    'extenstions_test': {'code.dart': sourceCode}
  });

  final bytecode = program.write();
  return bytecode;
}

Runtime runtimeEval(Uint8List bytecode) {
  final runtime = Runtime(bytecode.buffer.asByteData());

  runtime.registerBridgeFunc(
      bridgeLibary, 'BasePluginApi.', $BasePluginApi.$new,
      isBridge: true);

  runtime.setup();

  return runtime;
}

void main(List<String> args) async {
  final file =
      await File('E:/Projects/extenstions_test/lib/code.dart').readAsString();

  final compiled = compilerEval(file);

  final runtime = runtimeEval(compiled);

  final value = (await runtime.executeLib(
    'package:extenstions_test/code.dart',
    'getPlugin',
  ));

  print(value);
}
Noobware1 commented 1 year ago

fixed it by invoking the constructor of the subclass like TestPlugin()