callExternalFunction method

void callExternalFunction(
  1. String funcName,
  2. int numberOfArguments
)

Implementation

void callExternalFunction(String funcName, int numberOfArguments) {
  ExternalFunctionDef? funcDef;
  Container? fallbackFunctionContainer;

  var foundExternal = _externals.containsKey(funcName);
  if (foundExternal) {
    funcDef = _externals[funcName];
  }

  if (foundExternal &&
      funcDef?.lookaheadSafe == false &&
      _stateSnapshotAtLastNewline != null) {
    _sawLookaheadUnsafeFunctionAfterNewline = true;
    return;
  }

  // Try to use fallback function?
  if (!foundExternal) {
    if (allowExternalFunctionFallbacks) {
      fallbackFunctionContainer = knotContainerWithName(funcName);
      assert(
          fallbackFunctionContainer != null,
          "Trying to call EXTERNAL function '" +
              funcName +
              "' which has not been bound, and fallback ink function could not be found.");

      // Divert direct into fallback function and we're done
      state.callStack.push(PushPopType.Function,
          outputStreamLengthWithPushed: state.outputStream.length);
      state.divertedPointer = Pointer.startOf(fallbackFunctionContainer);
      return;
    } else {
      assert(
          false,
          "Trying to call EXTERNAL function '" +
              funcName +
              "' which has not been bound (and ink fallbacks disabled).");
    }
  }

  // Pop arguments
  var arguments = <Object>[];
  for (var i = 0; i < numberOfArguments; ++i) {
    var poppedObj = state.popEvaluationStack() as Value;
    var valueObj = poppedObj.valueObject;
    arguments.add(valueObj);
  }

  // Reverse arguments from the order they were popped,
  // so they're the right way round again.
  arguments = arguments.reversed.toList();

  // Run the function!
  var funcResult = funcDef!.function?.call(arguments.toList());

  // Convert return value (if any) to the a type that the ink engine can use
  RuntimeObject? returnObj;
  if (funcResult != null) {
    returnObj = Value.create(funcResult);
    assert(
        returnObj != null,
        'Could not create ink value from returned object of type ' +
            funcResult.runtimeType.toString());
  } else {
    returnObj = RuntimeVoid();
  }

  state.pushEvaluationStack(returnObj!);
}