NumOp and StrOp: 'dynamic' operators

Post your working scripts, libraries and tools
User avatar
jeeswg
Posts: 6708
Joined: 19 Dec 2016, 01:58
Location: UK

NumOp and StrOp: 'dynamic' operators

18 Sep 2018, 06:37

- The idea of these functions is to be able to use an operator dynamically, and to be able to force a type comparison (numeric/alphabetical).
- Functions like these are useful when writing custom functions, to avoid using multiple if/else lines when multiple operators could be involved.
- The intention would be to use something like this for a quick script to submit to the forum. Of course the functions are so massive that this would only be useful if such functionality was built-in. Otherwise you're better off with a small(er) if/else ladder.
- It would also give a way to add in certain AHK v2 operator functionality into AHK v1 without breaking script compatibility.
- I've also thrown in a special ternary operator to do 'between'. While I would not recommend special syntax handling for a <= b <= c, for operators, there is no problem making this available for use with NumOp/StrOp functions. E.g. JEE_StrOp("a", "<=", "b", "<=", "c").
- This is more a proof of concept, the functions have not been thoroughly tested.

Code: Select all

q:: ;NumOp and StrOp
MsgBox, % (1 + 1) ;2
MsgBox, % JEE_NumOp(1, "+", 1) ;2

MsgBox, % JEE_NumOp("2", "<", "10") ;1
MsgBox, % JEE_StrOp(2, "<", 10) ;0

MsgBox, % JEE_StrOp("a", "<=", "b", "<=", "c") ;1
MsgBox, % JEE_StrOp("a", "<=", "d", "<=", "c") ;0
return

;==================================================

;doesn't handle: => (fat arrow functions)
;doesn't handle: , (multi-statement)
;vArg1 is ByRef in case we need ++ -- += -= etc
;vArg2 is ByRef in case we need ++ -- &vArg2
;accepts 2, 3 or 5 parameters

JEE_StrOp(ByRef vArg1, ByRef vArg2, oParams*)
{
	if !(oParams.Length() ~= "^(0|1|3)$")
		return

	if !oParams.Length() ;unary operators: new ++ -- - ! ~ & *
	{
		if else if (vArg1 = "new")
			return new %vArg2%
		else if (vArg1 = "!") || (vArg1 = "NOT")
			return !vArg2
		else if (vArg1 = "&")
			return &vArg2

		;ordinarily don't work with strings: ++ -- - ~ *
		else if (vArg1 = "++")
			++vArg2
		else if (vArg2 = "++")
			vArg1++
		else if (vArg1 = "--")
			--vArg2
		else if (vArg2 = "--")
			vArg1--
		else if (vArg1 = "-")
			return -vArg2
		else if (vArg1 = "~") ;AHK v2 style
			return vArg2 ^ -1
		else if (vArg1 = "*") ;not in AHK v2
			return NumGet(vArg2+0, 0, "UChar")
		return
	}

	vArg3 := oParams.1, vArg4 := oParams.2, vArg5 := oParams.3
	if (oParams.Length() = 3) ;ternary operators: ? :, < <, < <=, <= <, <= <=
	{
		if (vArg2 = "?") && (vArg4 = ":")
			return vArg1 ? vArg3 : vArg5
		else if (vArg2 = "<") && (vArg4 = "<")
			return ("" vArg1 < "" vArg3) && ("" vArg3 < "" vArg5)
		else if (vArg2 = "<") && (vArg4 = "<=")
			return ("" vArg1 < "" vArg3) && ("" vArg3 <= "" vArg5)
		else if (vArg2 = "<=") && (vArg4 = "<")
			return ("" vArg1 <= "" vArg3) && ("" vArg3 < "" vArg5)
		else if (vArg2 = "<=") && (vArg4 = "<=")
			return ("" vArg1 <= "" vArg3) && ("" vArg3 <= "" vArg5)
		return
	}

	;binary operators
	if (vArg2 = ".")
		return vArg1 . vArg3
	else if (vArg2 = "~=")
		return vArg1 ~= vArg3
	else if (vArg2 = ">")
		return "" vArg1 > "" vArg3
	else if (vArg2 = "<")
		return "" vArg1 < "" vArg3
	else if (vArg2 = ">=")
		return "" vArg1 >= "" vArg3
	else if (vArg2 = "<=")
		return "" vArg1 <= "" vArg3
	else if (vArg2 = "=") ;AHK v2 style
		return "" vArg1 = "" vArg3
	else if (vArg2 = "==") ;AHK v2 style
		return "" vArg1 == "" vArg3
	else if (vArg2 = "<>") ;may be removed in AHK v2
		return "" vArg1 <> "" vArg3
	else if (vArg2 = "!=") ;AHK v2 style
		return !("" vArg1 = "" vArg3)
	else if (vArg2 = "!==") ;AHK v2 style
		return !("" vArg1 == "" vArg3)
	else if (vArg2 = "&&") || (vArg2 = "AND") ;AHK v2 style
		return (vArg1 && vArg2) ? vArg2 : vArg1 ? vArg2 : vArg1
	else if (vArg2 = "||") || (vArg2 = "OR") ;AHK v2 style
		return vArg1 ? vArg1 : vArg3
	else if (vArg2 = ":=")
		vArg1 := vArg3
	else if (vArg2 = ".=")
		vArg1 .= vArg3

	;ordinarily don't work with strings:
	else if (vArg2 = "**")
		return vArg1 ** vArg3
	else if (vArg2 = "*")
		return vArg1 * vArg3
	else if (vArg2 = "/")
		return vArg1 / vArg3
	else if (vArg2 = "//")
		return vArg1 // vArg3
	else if (vArg2 = "+")
		return vArg1 + vArg3
	else if (vArg2 = "-")
		return vArg1 - vArg3
	else if (vArg2 = "<<")
		return vArg1 << vArg3
	else if (vArg2 = ">>")
		return vArg1 >> vArg3
	else if (vArg2 = "&")
		return !(vArg1 & vArg3)
	else if (vArg2 = "^")
		return vArg1 ^ vArg3
	else if (vArg2 = "|")
		return !(vArg1 | vArg3)
	else if (vArg2 = "+=")
		vArg1 += vArg3
	else if (vArg2 = "-=")
		vArg1 -= vArg3
	else if (vArg2 = "*=")
		vArg1 *= vArg3
	else if (vArg2 = "/=") ;AHK v2 style
		vArg1 := vArg1 / vArg3
	else if (vArg2 = "//=")
		vArg1 //= vArg3
	else if (vArg2 = "|=")
		vArg1 |= vArg3
	else if (vArg2 = "&=")
		vArg1 &= vArg3
	else if (vArg2 = "^=")
		vArg1 ^= vArg3
	else if (vArg2 = ">>=")
		vArg1 >>= vArg3
	else if (vArg2 = "<<=")
		vArg1 <<= vArg3

	if (vArg2 = "IS")
	{
		vType := vArg3
		%vType% := vType ;for AHK v2
		if vArg1 is %vType% ;[DO NOT CONVERT]
			return 1
		else
			return 0
	}

	;if object or a string without commas
	if (vArg2 = "CONTAINS" || vArg2 = "IN")
	&& !IsObject(vArg3) && !InStr(vArg3, ",")
		vArg3 := [vArg3]

	if (vArg2 = "CONTAINS") && IsObject(vArg3)
	{
		vText := vArg1, vNeedles := vArg3
		if !IsObject(vNeedles) && (vNeedles = "")
			return 1
		vCaseSen := (A_StringCaseSense = 1) || (A_StringCaseSense = "On")
		for vKey, vValue in (IsObject(vNeedles) ? vNeedles : StrSplit(vNeedles, ","))
			if InStr(vText, vValue, vCaseSen)
				return vKey
		return 0
	}

	if (vArg2 = "IN") && IsObject(vArg3)
	{
		vText := vArg1, vNeedles := vArg3
		if !IsObject(vNeedles) && (vNeedles = "") && (vText = "")
			return 1
		else if !(A_StringCaseSense = 1) && !(A_StringCaseSense = "On")
		{
			for vKey, vValue in (IsObject(vNeedles) ? vNeedles : StrSplit(vNeedles, ","))
				if ("" vText = "" vValue)
					return vKey
		}
		else
		{
			for vKey, vValue in (IsObject(vNeedles) ? vNeedles : StrSplit(vNeedles, ","))
				if ("" vText == "" vValue)
					return vKey
		}
		return 0
	}
}

;==================================================

;doesn't handle: => (fat arrow functions)
;doesn't handle: , (multi-statement)
;vArg1 is ByRef in case we need ++ -- += -= etc
;vArg2 is ByRef in case we need ++ -- &vArg2
;accepts 2, 3 or 5 parameters

JEE_NumOp(ByRef vArg1, ByRef vArg2, oParams*)
{
	if !(oParams.Length() ~= "^(0|1|3)$")
		return

	if !oParams.Length() ;unary operators: new ++ -- - ! ~ & *
	{
		if else if (vArg1 = "new")
			return new %vArg2%
		else if (vArg1 = "!") || (vArg1 = "NOT")
			return !vArg2
		else if (vArg1 = "&")
			return &vArg2

		;ordinarily don't work with strings: ++ -- - ~ *
		else if (vArg1 = "++")
			++vArg2
		else if (vArg2 = "++")
			vArg1++
		else if (vArg1 = "--")
			--vArg2
		else if (vArg2 = "--")
			vArg1--
		else if (vArg1 = "-")
			return -vArg2
		else if (vArg1 = "~") ;AHK v2 style
			return vArg2 ^ -1
		else if (vArg1 = "*") ;not in AHK v2
			return NumGet(vArg2+0, 0, "UChar")
		return
	}

	vArg3 := oParams.1, vArg4 := oParams.2, vArg5 := oParams.3
	if (oParams.Length() = 3) ;ternary operators: ? :, < <, < <=, <= <, <= <=
	{
		if (vArg2 = "?") && (vArg4 = ":")
			return vArg1 ? vArg3 : vArg5
		else if (vArg2 = "<") && (vArg4 = "<")
			return (vArg1 < vArg3) && (vArg3 < vArg5)
		else if (vArg2 = "<") && (vArg4 = "<=")
			return (vArg1 < vArg3) && (vArg3 <= vArg5)
		else if (vArg2 = "<=") && (vArg4 = "<")
			return (vArg1 <= vArg3) && (vArg3 < vArg5)
		else if (vArg2 = "<=") && (vArg4 = "<=")
			return (vArg1 <= vArg3) && (vArg3 <= vArg5)
		return
	}

	;binary operators
	if (vArg2 = ".")
		return vArg1 . vArg3
	else if (vArg2 = "~=")
		return vArg1 ~= vArg3
	else if (vArg2 = ">")
		return vArg1 > vArg3
	else if (vArg2 = "<")
		return vArg1 < vArg3
	else if (vArg2 = ">=")
		return vArg1 >= vArg3
	else if (vArg2 = "<=")
		return vArg1 <= vArg3
	else if (vArg2 = "=") ;AHK v2 style
		return vArg1 = vArg3
	else if (vArg2 = "==") ;AHK v2 style
		return vArg1 == vArg3
	else if (vArg2 = "<>") ;may be removed in AHK v2
		return vArg1 <> vArg3
	else if (vArg2 = "!=") ;AHK v2 style
		return !(vArg1 = vArg3)
	else if (vArg2 = "!==") ;AHK v2 style
		return !(vArg1 == vArg3)
	else if (vArg2 = "&&") || (vArg2 = "AND") ;AHK v2 style
		return (vArg1 && vArg2) ? vArg2 : vArg1 ? vArg2 : vArg1
	else if (vArg2 = "||") || (vArg2 = "OR") ;AHK v2 style
		return vArg1 ? vArg1 : vArg3
	else if (vArg2 = ":=")
		vArg1 := vArg3
	else if (vArg2 = ".=")
		vArg1 .= vArg3

	;ordinarily don't work with strings:
	else if (vArg2 = "**")
		return vArg1 ** vArg3
	else if (vArg2 = "*")
		return vArg1 * vArg3
	else if (vArg2 = "/")
		return vArg1 / vArg3
	else if (vArg2 = "//")
		return vArg1 // vArg3
	else if (vArg2 = "+")
		return vArg1 + vArg3
	else if (vArg2 = "-")
		return vArg1 - vArg3
	else if (vArg2 = "<<")
		return vArg1 << vArg3
	else if (vArg2 = ">>")
		return vArg1 >> vArg3
	else if (vArg2 = "&")
		return !(vArg1 & vArg3)
	else if (vArg2 = "^")
		return vArg1 ^ vArg3
	else if (vArg2 = "|")
		return !(vArg1 | vArg3)
	else if (vArg2 = "+=")
		vArg1 += vArg3
	else if (vArg2 = "-=")
		vArg1 -= vArg3
	else if (vArg2 = "*=")
		vArg1 *= vArg3
	else if (vArg2 = "/=") ;AHK v2 style
		vArg1 := vArg1 / vArg3
	else if (vArg2 = "//=")
		vArg1 //= vArg3
	else if (vArg2 = "|=")
		vArg1 |= vArg3
	else if (vArg2 = "&=")
		vArg1 &= vArg3
	else if (vArg2 = "^=")
		vArg1 ^= vArg3
	else if (vArg2 = ">>=")
		vArg1 >>= vArg3
	else if (vArg2 = "<<=")
		vArg1 <<= vArg3

	if (vArg2 = "IS")
	{
		vType := vArg3
		%vType% := vType ;for AHK v2
		if vArg1 is %vType% ;[DO NOT CONVERT]
			return 1
		else
			return 0
	}

	;if object or a string without commas
	if (vArg2 = "CONTAINS" || vArg2 = "IN")
	&& !IsObject(vArg3) && !InStr(vArg3, ",")
		vArg3 := [vArg3]

	if (vArg2 = "CONTAINS") && IsObject(vArg3)
	{
		vText := vArg1, vNeedles := vArg3
		if (vNeedles = "")
			return 1
		vCaseSen := (A_StringCaseSense = 1) || (A_StringCaseSense = "On")
		for vKey, vValue in (IsObject(vNeedles) ? vNeedles : StrSplit(vNeedles, ","))
			if InStr(vText, vValue, vCaseSen)
				return vKey
		return 0
	}

	if (vArg2 = "IN") && IsObject(vArg3)
	{
		vText := vArg1, vNeedles := vArg3
		if (vNeedles = "") && (vText = "")
			return 1
		else if !(A_StringCaseSense = 1) && !(A_StringCaseSense = "On")
		{
			for vKey, vValue in (IsObject(vNeedles) ? vNeedles : StrSplit(vNeedles, ","))
				if (vText = vValue)
					return vKey
		}
		else
		{
			for vKey, vValue in (IsObject(vNeedles) ? vNeedles : StrSplit(vNeedles, ","))
				if (vText == vValue)
					return vKey
		}
		return 0
	}
}

;==================================================
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Scripts and Functions”

Who is online

Users browsing this forum: hasantr and 32 guests