override fun doFunction()

in vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/functions/handlers/collectionFunctions/MapFunctionHandlers.kt [120:220]


  override fun doFunction(
    arguments: Arguments,
    editor: VimEditor,
    context: ExecutionContext,
    vimContext: VimLContext
  ): VimDataType {
    val expr1 = arguments[0]
    val expr2 = arguments[1]

    if (expr1 !is VimList && expr1 !is VimDictionary && expr1 !is VimString && expr1 !is VimBlob) {
      throw exExceptionMessage("E1250", "${name}()")
    }

    val funcref = expr2 as? VimFuncref
    val expression = if (funcref != null) {
      null
    } else if (expr2 is VimFloat) {
      // Vim doesn't normally convert Float to String
      SimpleExpression(expr2)
    } else {
      val string = expr2.toVimString()
      if (string.value.isEmpty()) {
        throw exExceptionMessage("E15", string.value)
      }
      injector.vimscriptParser.parseExpression(string.value)
    }
    if (funcref == null && expression == null) {
      throw exExceptionMessage("E1250", "${name}()")
    }

    when (expr1) {
      is VimList -> {
        val source = getSource(expr1)
        val target = getTarget(expr1)
        if (target.isLocked) {
          throw exExceptionMessage("E741", "${name}() argument")
        }

        var writeIndex = 0
        for ((index, value) in source.values.withIndex()) {
          val result = processItem(VimInt(index), value, funcref, expression, editor, context, vimContext)
          if (result != null) {
            if (target.values.size > index && target.values[index].isLocked) {
              throw exExceptionMessage("E741", "${name}() argument")
            }
            target.values[writeIndex++] = result
          }
          else {
            // TODO: Validate index values
            target.values.removeAt(writeIndex)
          }
        }

        return target
      }

      is VimDictionary -> {
        val source = getSource(expr1)
        val target = getTarget(expr1)
        if (target.isLocked) {
          throw exExceptionMessage("E741", "${name}() argument")
        }

        for ((k, v) in source.dictionary.entries) {
          val result = processItem(k, v, funcref, expression, editor, context, vimContext)
          if (result != null) {
            if (target.dictionary[k]?.isLocked == true) {
              throw exExceptionMessage("E741", "${name}() argument")
            }
            target.dictionary[k] = result
          }
          else {
            target.dictionary.remove(k)
          }
        }

        return target
      }

      is VimString -> {
        val string = buildString {
          // We don't need to use getSource here - we'll never modify expr1
          for ((index, ch) in expr1.value.withIndex()) {
            val result =
              processItem(VimInt(index), VimString(ch.toString()), funcref, expression, editor, context, vimContext)
            if (result != null) {
              if (result !is VimString) {
                throw exExceptionMessage("E928")
              }
              append(result.value)
            }
          }
        }

        return VimString(string)
      }

      is VimBlob -> TODO()
      else -> throw exExceptionMessage("E1250", "${name}()")
    }
  }