1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-05-07 05:34:02 +02:00

Add bitwise functions

This commit is contained in:
Matt Ellis 2025-02-18 18:03:03 +00:00 committed by Alex Pláte
parent be86dc3c78
commit 23329cc522
8 changed files with 354 additions and 1 deletions
src
main/resources/messages
test/java/org/jetbrains/plugins/ideavim/ex/implementation/functions/bitwiseFunctions
vim-engine/src/main
kotlin/com/maddyhome/idea/vim/vimscript/model/functions/handlers/bitwiseFunctions
resources/ksp-generated

View File

@ -84,6 +84,7 @@ E546=E546: Illegal mode: {0}
E548=E548: Digit expected: {0}
E549=E549: Illegal percentage: {0}
E774=E774: 'operatorfunc' is empty
E805=E805: Using a Float as a Number
e841.reserved.name.cannot.be.used.for.user.defined.command=E841: Reserved name, cannot be used for user defined command
E939=E939: Positive count required
E1214=E1214: Digraph must be just two characters: {0}

View File

@ -0,0 +1,66 @@
/*
* Copyright 2003-2025 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package org.jetbrains.plugins.ideavim.ex.implementation.functions.bitwiseFunctions
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInfo
class AndFunctionTest : VimTestCase() {
@BeforeEach
override fun setUp(testInfo: TestInfo) {
super.setUp(testInfo)
configureByText("\n")
}
@Test
fun `test and function bitwise ANDs two numbers`() {
assertCommandOutput("echo and(2, 6)", "2")
}
@Test
fun `test and function bitwise ANDs two numbers with negative numbers`() {
assertCommandOutput("echo and(-2, -6)", "-6")
}
@Test
fun `test and function returns 0`() {
assertCommandOutput("echo and(2, 4)", "0")
}
@Test
fun `test and function coerces string to number`() {
assertCommandOutput("echo and('0xFF', '35')", "35")
}
@Test
fun `test and function with list causes error`() {
enterCommand("echo and([1, 2, 3], [2, 3, 4])")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E745: Using a List as a Number")
}
@Test
fun `test and function with dict causes error`() {
enterCommand("echo and({1: 2, 3: 4}, {3: 4, 5: 6})")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E728: Using a Dictionary as a Number")
}
@Test
fun `test and function with float causes error`() {
enterCommand("echo and(1.5, 2.5)")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E805: Using a Float as a Number")
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2003-2025 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package org.jetbrains.plugins.ideavim.ex.implementation.functions.bitwiseFunctions
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInfo
class InvertFunctionTest : VimTestCase() {
@BeforeEach
override fun setUp(testInfo: TestInfo) {
super.setUp(testInfo)
configureByText("\n")
}
@Test
fun `test invert function inverts bits`() {
// assertCommandOutput("echo invert(0b1010)", "-11")
assertCommandOutput("echo invert(10)", "-11")
}
@Test
fun `test invert function with list causes error`() {
enterCommand("echo invert([1, 2, 3])")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E745: Using a List as a Number")
}
@Test
fun `test invert function with dict causes error`() {
enterCommand("echo invert({1: 2, 3: 4})")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E728: Using a Dictionary as a Number")
}
@Test
fun `test invert function with float causes error`() {
enterCommand("echo invert(1.5)")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E805: Using a Float as a Number")
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright 2003-2025 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package org.jetbrains.plugins.ideavim.ex.implementation.functions.bitwiseFunctions
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInfo
class OrFunctionTest : VimTestCase() {
@BeforeEach
override fun setUp(testInfo: TestInfo) {
super.setUp(testInfo)
configureByText("\n")
}
@Test
fun `test or function bitwise ORs two numbers`() {
assertCommandOutput("echo or(2, 7)", "7")
}
@Test
fun `test or function bitwise ORs two numbers with negative numbers`() {
assertCommandOutput("echo or(-2, -6)", "-2")
}
@Test
fun `test or function returns 0`() {
assertCommandOutput("echo or(0, 0)", "0")
}
@Test
fun `test or function coerces string to number`() {
assertCommandOutput("echo or('0x07', '35')", "39")
}
@Test
fun `test or function with list causes error`() {
enterCommand("echo or([1, 2, 3], [2, 3, 4])")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E745: Using a List as a Number")
}
@Test
fun `test or function with dict causes error`() {
enterCommand("echo or({1: 2, 3: 4}, {3: 4, 5: 6})")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E728: Using a Dictionary as a Number")
}
@Test
fun `test or function with float causes error`() {
enterCommand("echo or(1.5, 2.5)")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E805: Using a Float as a Number")
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright 2003-2025 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package org.jetbrains.plugins.ideavim.ex.implementation.functions.bitwiseFunctions
import org.jetbrains.plugins.ideavim.VimTestCase
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInfo
class XorFunctionTest : VimTestCase() {
@BeforeEach
override fun setUp(testInfo: TestInfo) {
super.setUp(testInfo)
configureByText("\n")
}
@Test
fun `test xor function bitwise XORs two numbers`() {
assertCommandOutput("echo xor(2, 7)", "5")
}
@Test
fun `test xor function bitwise XORs two numbers with negative numbers`() {
assertCommandOutput("echo xor(-2, -6)", "4")
}
@Test
fun `test xor function returns 0`() {
assertCommandOutput("echo xor(2, 2)", "0")
}
@Test
fun `test xor function coerces string to number`() {
assertCommandOutput("echo xor('0x07', '35')", "36")
}
@Test
fun `test xor function with list causes error`() {
enterCommand("echo xor([1, 2, 3], [2, 3, 4])")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E745: Using a List as a Number")
}
@Test
fun `test xor function with dict causes error`() {
enterCommand("echo xor({1: 2, 3: 4}, {3: 4, 5: 6})")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E728: Using a Dictionary as a Number")
}
@Test
fun `test xor function with float causes error`() {
enterCommand("echo xor(1.5, 2.5)")
assertNoExOutput()
assertPluginError(true)
assertPluginErrorMessageContains("E805: Using a Float as a Number")
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2003-2025 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.vimscript.model.functions.handlers.bitwiseFunctions
import com.intellij.vim.annotations.VimscriptFunction
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.ex.exExceptionMessage
import com.maddyhome.idea.vim.vimscript.model.VimLContext
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFloat
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import com.maddyhome.idea.vim.vimscript.model.expressions.Expression
import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler
internal abstract class BinaryBitwiseFunctionHandlerBase : FunctionHandler() {
override val minimumNumberOfArguments = 2
override val maximumNumberOfArguments = 2
override fun doFunction(
argumentValues: List<Expression>,
editor: VimEditor,
context: ExecutionContext,
vimContext: VimLContext,
): VimDataType {
val arg1 = argumentValues[0].evaluate(editor, context, vimContext)
val arg2 = argumentValues[1].evaluate(editor, context, vimContext)
if (arg1 is VimFloat || arg2 is VimFloat) {
throw exExceptionMessage("E805") // E805: Using a Float as a Number
}
return VimInt(invoke(arg1.asDouble().toInt(), arg2.asDouble().toInt()))
}
abstract fun invoke(a: Int, b: Int): Int
}
@VimscriptFunction(name = "and")
internal class AndFunctionHandler : BinaryBitwiseFunctionHandlerBase() {
override fun invoke(a: Int, b: Int) = a and b
}
@VimscriptFunction(name = "or")
internal class OrFunctionHandler : BinaryBitwiseFunctionHandlerBase() {
override fun invoke(a: Int, b: Int) = a or b
}
@VimscriptFunction(name = "xor")
internal class XorFunctionHandler : BinaryBitwiseFunctionHandlerBase() {
override fun invoke(a: Int, b: Int) = a xor b
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2003-2025 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.vimscript.model.functions.handlers.bitwiseFunctions
import com.intellij.vim.annotations.VimscriptFunction
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.ex.exExceptionMessage
import com.maddyhome.idea.vim.vimscript.model.VimLContext
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFloat
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import com.maddyhome.idea.vim.vimscript.model.expressions.Expression
import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler
@VimscriptFunction(name = "invert")
internal class InvertFunctionHandler : FunctionHandler() {
override val minimumNumberOfArguments = 1
override val maximumNumberOfArguments = 1
override fun doFunction(
argumentValues: List<Expression>,
editor: VimEditor,
context: ExecutionContext,
vimContext: VimLContext,
): VimDataType {
val arg1 = argumentValues[0].evaluate(editor, context, vimContext)
if (arg1 is VimFloat) {
throw exExceptionMessage("E805") // E805: Using a Float as a Number
}
return VimInt(arg1.asDouble().toInt().inv())
}
}

View File

@ -1,5 +1,6 @@
{
"abs": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.AbsFunctionHandler",
"and": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.bitwiseFunctions.AndFunctionHandler",
"col": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.ColFunctionHandler",
"empty": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.EmptyFunctionHandler",
"escape": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.EscapeFunctionHandler",
@ -8,12 +9,15 @@
"function": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.FunctionFunctionHandler",
"get": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.GetFunctionHandler",
"getcmdtype": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.GetCmdTypeFunctionHandler",
"invert": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.bitwiseFunctions.InvertFunctionHandler",
"join": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.JoinFunctionHandler",
"len": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.LenFunctionHandler",
"line": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.LineFunctionHandler",
"or": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.bitwiseFunctions.OrFunctionHandler",
"sin": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.SinFunctionHandler",
"split": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.SplitFunctionHandler",
"submatch": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.SubmatchFunctionHandler",
"tolower": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.TolowerFunctionHandler",
"toupper": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.ToupperFunctionHandler"
"toupper": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.ToupperFunctionHandler",
"xor": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.bitwiseFunctions.XorFunctionHandler"
}