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 debugPerformance = 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 debugPerformance = 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);
    }
    final major = _currentBytecodeModule.read();
    final minor = _currentBytecodeModule.read();
    final patch = _currentBytecodeModule.readUint16();
    final preReleaseLength = _currentBytecodeModule.read();
    String? preRelease;
    for (var i = 0; i < preReleaseLength; ++i) {
      preRelease ??= '';
      preRelease += _currentBytecodeModule.readUtf8String();
    }
    final buildLength = _currentBytecodeModule.read();
    String? build;
    for (var i = 0; i < buildLength; ++i) {
      build ??= '';
      build += _currentBytecodeModule.readUtf8String();
    }
    _currentBytecodeModule.version =
        Version(major, minor, patch, pre: preRelease, build: build);
    _currentBytecodeModule.compiledAt =
        _currentBytecodeModule.readUtf8String();

    var incompatible = false;
    if (major > 0) {
      if (major != kHetuVersion.major) {
        incompatible = true;
      }
    } else {
      if (major != kHetuVersion.major ||
          minor != kHetuVersion.minor ||
          patch != kHetuVersion.patch) {
        incompatible = true;
      }
    }
    if (incompatible) {
      throw HTError.version('$major.$minor.$patch', '$kHetuVersion',
          filename: _currentFileName, line: _currentLine, column: _column);
    }
    _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.expressions[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 (debugPerformance) {
      print(
          'hetu: ${tok - tik}ms\tto load\t\t[${_currentBytecodeModule.id}] (version: \'${_currentBytecodeModule.version}\', compiled at: ${_currentBytecodeModule.compiledAt})');
    }
    stackTraceList.clear();
    return result;
  } catch (error, stackTrace) {
    if (config.processError) {
      processError(error, stackTrace);
    } else {
      rethrow;
    }
  }
}