loadBytecode method

dynamic loadBytecode({
  1. required Uint8List bytes,
  2. required String moduleName,
  3. bool globallyImport = false,
  4. String? invokeFunc,
  5. List positionalArgs = const [],
  6. Map<String, dynamic> namedArgs = const {},
  7. List<HTType> typeArgs = const [],
  8. bool printPerformanceStatistics = false,
})

Load a pre-compiled bytecode file as a module. If invokeFunc is true, execute the bytecode immediately.

Implementation

dynamic loadBytecode({
  required Uint8List bytes,
  required String moduleName,
  bool globallyImport = false,
  String? invokeFunc,
  List<dynamic> positionalArgs = const [],
  Map<String, dynamic> namedArgs = const {},
  List<HTType> typeArgs = const [],
  bool printPerformanceStatistics = false,
}) {
  try {
    final tik = DateTime.now().millisecondsSinceEpoch;
    _currentBytecodeModule = HTBytecodeModule(id: moduleName, bytes: bytes);
    cachedModules[_currentBytecodeModule.id] = _currentBytecodeModule;
    final signature = _currentBytecodeModule.readUint32();
    if (signature != HTCompiler.hetuSignature) {
      throw HTError.bytecode(
          filename: _currentFileName, line: _currentLine, column: _column);
    }
    // compare the version of the compiler of the bytecode to my version.
    final compilerVersion = _handleVersion();
    var incompatible = false;
    if (compilerVersion.major > 0) {
      if (compilerVersion.major > kHetuVersion.major) {
        incompatible = true;
      }
    } else {
      if (compilerVersion != kHetuVersion) {
        incompatible = true;
      }
    }
    if (incompatible) {
      throw HTError.version(
        _currentBytecodeModule.version.toString(),
        kHetuVersion.toString(),
        filename: _currentFileName,
        line: _currentLine,
        column: _column,
      );
    }
    // read the version of the bytecode.
    final hasVersion = _currentBytecodeModule.readBool();
    if (hasVersion) {
      _currentBytecodeModule.version = _handleVersion();
    }
    _currentBytecodeModule.compiledAt =
        _currentBytecodeModule.readUtf8String();
    _currentFileName = _currentBytecodeModule.readUtf8String();
    final sourceType =
        HTResourceType.values.elementAt(_currentBytecodeModule.read());
    _isModuleEntryScript = sourceType == HTResourceType.hetuScript ||
        sourceType == HTResourceType.hetuLiteralCode ||
        sourceType == HTResourceType.hetuValue;
    if (sourceType == HTResourceType.hetuLiteralCode) {
      _currentNamespace = globalNamespace;
    }
    while (_currentBytecodeModule.ip < _currentBytecodeModule.bytes.length) {
      final result = execute(retractStackFrame: false);
      if (result is HTNamespace && result != globalNamespace) {
        _currentBytecodeModule.namespaces[result.id!] = result;
      } else if (result is HTValueSource) {
        _currentBytecodeModule.values[result.id] = result.value;
      } else {
        assert(result == globalNamespace);
      }
      // TODO: import binary bytes
    }
    if (!_isModuleEntryScript) {
      // handles imports
      for (final nsp in _currentBytecodeModule.namespaces.values) {
        for (final decl in nsp.imports.values) {
          _handleNamespaceImport(nsp, decl);
        }
      }
    }
    if (_currentBytecodeModule.namespaces.isNotEmpty) {
      _currentNamespace = _currentBytecodeModule.namespaces.values.last;
      if (globallyImport) {
        globalNamespace.import(_currentNamespace);
      }
    }
    // resolve each declaration after we get all declarations
    // if (!_isModuleEntryScript) {
    //   for (final namespace in _currentBytecodeModule.namespaces.values) {
    //     for (final decl in namespace.declarations.values) {
    //       decl.resolve();
    //     }
    //   }
    // }
    cachedModules[_currentBytecodeModule.id] = _currentBytecodeModule;
    dynamic result;
    if (invokeFunc != null) {
      result = invoke(invokeFunc,
          moduleName: _currentBytecodeModule.id,
          positionalArgs: positionalArgs,
          namedArgs: namedArgs);
    } else if (_isModuleEntryScript) {
      result = _stackFrames.last.first;
    }
    final tok = DateTime.now().millisecondsSinceEpoch;
    if (printPerformanceStatistics) {
      var message =
          'hetu: ${tok - tik}ms\tto load module\t${_currentBytecodeModule.id}';
      if (_currentBytecodeModule.version != null) {
        message += '@${_currentBytecodeModule.version}';
      }
      message +=
          ' (compiled at ${_currentBytecodeModule.compiledAt} UTC with hetu@$compilerVersion)';
      print(message);
    }
    stackTraceList.clear();
    return result;
  } catch (error, stackTrace) {
    if (config.processError) {
      processError(error, stackTrace);
    } else {
      rethrow;
    }
  }
}