init method

void init({
  1. bool useDefaultModuleAndBinding = true,
  2. Map<String, Function> externalFunctions = const {},
  3. Map<String, HTExternalMethod> externalMethods = const {},
  4. Map<String, HTExternalFunctionTypedef> externalFunctionTypedef = const {},
  5. List<HTExternalClass> externalClasses = const [],
  6. List<HTExternalTypeReflection> externalTypeReflections = const [],
})

Initialize the interpreter, prepare it with preincluded modules, bind it with HTExternalFunction, HTExternalFunctionTypedef, HTExternalClass, etc.

A uninitted Hetu can still eval certain script, it cannot use any of the pre-included functions like print and the Dart apis on number & string, etc.

Implementation

void init({
  bool useDefaultModuleAndBinding = true,
  Map<String, Function> externalFunctions = const {},
  Map<String, HTExternalMethod> externalMethods = const {},
  Map<String, HTExternalFunctionTypedef> externalFunctionTypedef = const {},
  List<HTExternalClass> externalClasses = const [],
  List<HTExternalTypeReflection> externalTypeReflections = const [],
}) {
  if (_isInitted) return;

  if (useDefaultModuleAndBinding) {
    final numBinding = HTNumberClassBinding();
    final iterableBinding = HTIterableClassBinding();
    interpreter.bindExternalClass(numBinding);
    interpreter
        .bindExternalClass(HTIntegerClassBinding(superClass: numBinding));
    interpreter
        .bindExternalClass(HTFloatClassBinding(superClass: numBinding));
    interpreter.bindExternalClass(HTBigIntClassBinding());
    interpreter.bindExternalClass(HTBooleanClassBinding());
    interpreter.bindExternalClass(HTStringClassBinding());
    interpreter.bindExternalClass(HTIteratorClassBinding());
    interpreter.bindExternalClass(iterableBinding);
    interpreter
        .bindExternalClass(HTListClassBinding(superClass: iterableBinding));
    interpreter
        .bindExternalClass(HTSetClassBinding(superClass: iterableBinding));
    interpreter.bindExternalClass(HTMapClassBinding());
    interpreter.bindExternalClass(HTRandomClassBinding());
    interpreter.bindExternalClass(HTFutureClassBinding());
    interpreter.bindExternalClass(HTCryptoClassBinding());
    interpreter.bindExternalClass(HTConsoleClassBinding(console: console));
    interpreter.bindExternalClass(HTJSONClassBinding(lexicon: lexicon));

    // bind dynamic external functions or static method
    interpreter.bindExternalFunction('print',
        ({positionalArgs, namedArgs}) => console.log(positionalArgs));
    interpreter.bindExternalFunction(
        'eval', ({positionalArgs, namedArgs}) => eval(positionalArgs.first));
    interpreter.bindExternalFunction('require',
        ({positionalArgs, namedArgs}) => require(positionalArgs.first));
    interpreter.bindExternalFunction(
        'help', ({positionalArgs, namedArgs}) => help(positionalArgs.first));
    interpreter.bindExternalFunction('Object.fromJSON', (
        {positionalArgs, namedArgs}) {
      final jsonData = positionalArgs.first as Map<dynamic, dynamic>;
      return interpreter.createStructfromJSON(jsonData);
    });
    interpreter.bindExternalFunction('Object.assign', (
        {positionalArgs, namedArgs}) {
      final target = positionalArgs[0] as HTStruct;
      final source = positionalArgs[1] as HTStruct;
      target.assign(source);
    });
    interpreter.bindExternalFunction('Object.merge', (
        {positionalArgs, namedArgs}) {
      final target = positionalArgs[0] as HTStruct;
      final source = positionalArgs[1] as HTStruct;
      target.merge(source);
    });

    // bind dynamic external method
    interpreter.bindExternalMethod('ClassRoot::toString', (
        {object, positionalArgs, namedArgs}) {
      return lexicon.stringify(object);
    });
    interpreter.bindExternalMethod('Object::iterator', (
        {object, positionalArgs, namedArgs}) {
      final struct = object as HTStruct;
      return struct.keys.iterator;
    });
    interpreter.bindExternalMethod('Object::keys', (
        {object, positionalArgs, namedArgs}) {
      final struct = object as HTStruct;
      return struct.keys;
    });
    interpreter.bindExternalMethod('Object::values', (
        {object, positionalArgs, namedArgs}) {
      final struct = object as HTStruct;
      return struct.values;
    });
    interpreter.bindExternalMethod('Object::contains', (
        {object, positionalArgs, namedArgs}) {
      final struct = object as HTStruct;
      return struct.contains(positionalArgs.first);
    });
    interpreter.bindExternalMethod('Object::containsKey', (
        {object, positionalArgs, namedArgs}) {
      final struct = object as HTStruct;
      return struct.containsKey(positionalArgs.first);
    });
    interpreter.bindExternalMethod('Object::isEmpty', (
        {object, positionalArgs, namedArgs}) {
      final struct = object as HTStruct;
      return struct.isEmpty;
    });
    interpreter.bindExternalMethod('Object::isNotEmpty', (
        {object, positionalArgs, namedArgs}) {
      final struct = object as HTStruct;
      return struct.isNotEmpty;
    });
    interpreter.bindExternalMethod('Object::length', (
        {object, positionalArgs, namedArgs}) {
      final struct = object as HTStruct;
      return struct.length;
    });
    interpreter.bindExternalMethod('Object::remove', (
        {object, positionalArgs, namedArgs}) {
      final struct = object as HTStruct;
      struct.remove(positionalArgs.first);
    });
    interpreter.bindExternalMethod('Object::clone', (
        {object, positionalArgs, namedArgs}) {
      final struct = object as HTStruct;
      return struct.clone();
    });
    interpreter.bindExternalMethod('Object::assign', (
        {object, positionalArgs, namedArgs}) {
      final struct = object as HTStruct;
      final other = positionalArgs.first as HTStruct;
      struct.assign(other);
    });

    // must convert the return type to let dart know its return value type.
    interpreter.bindExternalFunctionType(
      'VoidCallback',
      (HTFunction function) {
        return () {
          return function.call();
        };
      },
    );

    interpreter.bindExternalFunctionType(
      'ValueCallback',
      (HTFunction function) {
        return (value) {
          return function.call(positionalArgs: [value]);
        };
      },
    );

    // bind non-dynamic external functions
    for (var key in preincludeFunctions.keys) {
      interpreter.bindExternalFunction(key, preincludeFunctions[key]!);
    }

    // load precompiled core module.
    final coreModule = Uint8List.fromList(hetuCoreModule);
    interpreter.loadBytecode(
      bytes: coreModule,
      module: 'hetu',
      globallyImport: true,
    );

    interpreter.define(
      'kHetuVersion',
      HTValueBinding(
        id: 'kHetuVersion',
        value: kHetuVersion.toString(),
        isMutable: false,
      ),
    );
    interpreter.define(
      lexicon.kThis,
      HTValueBinding(
        id: lexicon.kThis,
        value: interpreter.globalNamespace,
        isMutable: false,
      ),
    );
    interpreter.define(
      lexicon.idGlobal,
      HTValueBinding(
        id: lexicon.idGlobal,
        value: interpreter.globalNamespace,
        isMutable: false,
      ),
    );

    // interpreter.assign('console', console);

    HTInterpreter.classRoot = interpreter.globalNamespace
        .memberGet(lexicon.idGlobalObject, isRecursive: true);
    HTInterpreter.structRoot = interpreter.globalNamespace
        .memberGet(lexicon.idGlobalPrototype, isRecursive: true);
  }

  for (final key in externalFunctions.keys) {
    interpreter.bindExternalFunction(key, externalFunctions[key]!);
  }
  for (final key in externalMethods.keys) {
    interpreter.bindExternalMethod(key, externalMethods[key]!);
  }
  for (final key in externalFunctionTypedef.keys) {
    interpreter.bindExternalFunctionType(key, externalFunctionTypedef[key]!);
  }
  for (final value in externalClasses) {
    interpreter.bindExternalClass(value);
  }
  for (final value in externalTypeReflections) {
    interpreter.bindExternalReflection(value);
  }

  interpreter.currentNamespace = interpreter.globalNamespace;

  _isInitted = true;
}