Sign in to follow this  
Followers 0
SmOke_N

Nested functions

12 posts in this topic

When we nest functions, AutoIt will fire the functions off right to left.

In this string example (from GUIListView.au3, (I added an extra parenthesis in there so I could account for erroneous issues)):

BitShift(((_SendMessage($hwnd, $LVM_APPROXIMATEVIEWRECT, $icount, BitOR(BitShift($icy, -16), BitAND($icx, 0xFFFF))))), 16)

Can any of you come up with a band of regex's or simple "efficient" function that will strip the functions out right to left?

Example output:

$a_strip_func[0] = BitAND($icx, 0xFFFF)
$a_strip_func[1] = BitShift($icy, -16)
$a_strip_func[2] = BitOr(a_strip_func[2], $a_strip_func[1])
$a_strip_func[3] = _SendMessage($hwnd, $LVM_APPROXIMATEVIEWRECT, $icount, $a_strip_func[2])
$a_strip_func[4] = BitShift($a_strip_func[3], -16)

Or, maybe even a personal preference output:

$a_strip_func[0] = BitAND($icx, 0xFFFF)
$a_strip_func[1] = BitShift($icy, -16)
$a_strip_func[2] = BitOr(BitShift($icy, -16), BitAND($icx, 0xFFFF))
$a_strip_func[3] = _SendMessage($hwnd, $LVM_APPROXIMATEVIEWRECT, $icount, BitOr(BitShift($icy, -16), BitAND($icx, 0xFFFF)))
$a_strip_func[4] = BitShift(_SendMessage($hwnd, $LVM_APPROXIMATEVIEWRECT, $icount, BitOr(BitShift($icy, -16), BitAND($icx, 0xFFFF))), -16)

I am not going to post what I have, because what I have is failing, and I don't want ya'll going down this dead path with me if you are going to attempt it, I'd rather see a fresh outlook and maybe build on that.

*Keep in mind that some params may be strings, so if you're thinking of using StringSplit(), it very well could fail.

* This expression should give you the functions names:

"(\w+)\s*\("

If I get it working properly before anyone posts a viable solution, I'll post what I did.


Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

#include <Array.au3>
#include <String.au3>

Dim $sTxt = 'BitShift(((_SendMessage($hwnd, $LVM_APPROXIMATEVIEWRECT,' & _
            '$icount, BitOR(BitShift($icy, -16), BitAND($icx, 0xFFFF))))), 16)'

Dim $sPatt = '(\)(?:[^()]*|(?R))\(\w+\b)'
Dim $aFuncs[1], $aMatches
$sTxt = _StringReverse($sTxt)
ConsoleWrite($sTxt & @LF)

While 1
    $aMatches = StringRegExp($sTxt, $sPatt, 3)
    If IsArray($aMatches) Then _ArrayDisplay($aMatches)

    If IsArray($aMatches) Then
        For $i = 0 To UBound($aMatches)-1
            ReDim $aFuncs[UBound($aFuncs)+1]
            $aFuncs[UBound($aFuncs)-1] = $aMatches[$i]
            $sTxt = StringRegExpReplace($sTxt, '\Q' & $aMatches[$i] & '\E', '', 1)
            ConsoleWrite($aMatches[$i] & @TAB)
            ConsoleWrite($sTxt & @LF)
        Next
    Else
        ExitLoop
    EndIf
WEnd

ReDim $aFuncs[UBound($aFuncs)+1]
$aFuncs[UBound($aFuncs)-1] = $sTxt

$aFuncs[0] = UBound($aFuncs)-1
For $i = 1 To $aFuncs[0]
    $aFuncs[$i] = _StringReverse($aFuncs[$i])
Next

If IsArray($aFuncs) Then _ArrayDisplay($aFuncs)

I think it's possible to do it without reversing the string but with a cost of much complicated RegExp.

Edited by Authenticity

Share this post


Link to post
Share on other sites

Why index 3 and 5 have only () and ((())). It should be the full function, not?


When the words fail... music speaks

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

#include <Array.au3>
#include <String.au3>

Dim $sTxt = 'BitShift(((_SendMessage($hwnd, $LVM_APPROXIMATEVIEWRECT,' & _
            '$icount, BitOR(BitShift($icy, -16), BitAND($icx, 0xFFFF))))), 16)'

Dim $sPatt = '(\)(?:[^()]*|(?R))\(\w+\b)', $sPattRepl = Chr(0xFC) & '\1' & Chr(0xFD), $sFunc
Dim $aFuncs[1], $aMatches
$sTxt = _StringReverse($sTxt)

While 1
    $aMatches = StringRegExp($sTxt, $sPatt, 3)

    If IsArray($aMatches) Then
        For $i = 0 To UBound($aMatches)-1
            ReDim $aFuncs[UBound($aFuncs)+1]
            
            $aFuncs[UBound($aFuncs)-1] = $aMatches[$i]
            $aFuncs[UBound($aFuncs)-1] = StringRegExpReplace($aFuncs[UBound($aFuncs)-1], '\xfc', ')')
            $aFuncs[UBound($aFuncs)-1] = StringRegExpReplace($aFuncs[UBound($aFuncs)-1], '\xfd', '(')

            $sFunc = StringRegExpReplace($aMatches[$i], '\)([^(]*)\(.*', '\1', 1)
            $sTxt = StringRegExpReplace($sTxt, '\)(\Q' & $sFunc & '\E)\(', $sPattRepl, 1)
            Next
    Else
        ExitLoop
    EndIf
WEnd

ReDim $aFuncs[UBound($aFuncs)+1]
$aFuncs[UBound($aFuncs)-1] = $sTxt
$aFuncs[UBound($aFuncs)-1] = StringRegExpReplace($aFuncs[UBound($aFuncs)-1], '\xfc', ')')
$aFuncs[UBound($aFuncs)-1] = StringRegExpReplace($aFuncs[UBound($aFuncs)-1], '\xfd', '(')

$aFuncs[0] = UBound($aFuncs)-1
For $i = 1 To $aFuncs[0]
    $aFuncs[$i] = _StringReverse($aFuncs[$i])
Next

If IsArray($aFuncs) Then _ArrayDisplay($aFuncs)

Respecting the array elements. It's only the concept so it's clumsy and probably not efficient by any mean but it can get better in my opinion.

Edited by Authenticity

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

When we nest functions, AutoIt will fire the functions off right to left.

I don't think that's true. They are interpreted left-to-right, and also checked for additional nesting in that order:
; First test
Global $sTest = ""
ConsoleWrite(_MyFunc1(_MyFuncA()) & " :: " & _MyFunc2(_MyFuncB()) & " :: " & _MyFunc3(_MyFuncC()) & @LF)
ConsoleWrite("First Test:  $sTest = " & $sTest & @LF)

; Second test
Global $sTest = ""
_MyFuncX(_MyFunc1(_MyFuncA()), _MyFunc2(_MyFuncB()), _MyFunc3(_MyFuncC()))
ConsoleWrite("Second Test:  $sTest = " & $sTest & @LF)

; Functions
Func _MyFunc1($vInput = "")
    $sTest &= "_MyFunc1()" & @CRLF
    Return 1
EndFunc

Func _MyFunc2($vInput = "")
    $sTest &= "_MyFunc2()" & @CRLF
    Return 2
EndFunc

Func _MyFunc3($vInput = "")
    $sTest &= "_MyFunc3()" & @CRLF
    Return 3
EndFunc

Func _MyFuncA($vInput = "")
    $sTest &= "_MyFuncA()" & @CRLF
    Return "A"
EndFunc

Func _MyFuncB($vInput = "")
    $sTest &= "_MyFuncB()" & @CRLF
    Return "B"
EndFunc

Func _MyFuncC($vInput = "")
    $sTest &= "_MyFuncC()" & @CRLF
    Return "C"
EndFunc

Func _MyFuncX($vInput1 = "", $vInput2 = "", $vInput3 = "")
    $sTest &= "_MyFuncX()"
    Return "X"
EndFunc

Output:

1 :: 2 :: 3
First Test:  $sTest = _MyFuncA()
_MyFunc1()
_MyFuncB()
_MyFunc2()
_MyFuncC()
_MyFunc3()

Second Test:  $sTest = _MyFuncA()
_MyFunc1()
_MyFuncB()
_MyFunc2()
_MyFuncC()
_MyFunc3()
_MyFuncX()

:D

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

I fail to see what your test is supposed to prove. You have the output in a constant order.

Anyway, think about this. If you're using SendMessage API and you use BitAnd() etc as a LPARAM, And you fire off the function left to right... Then you're sending a string with the "BitAnd()" in it, not the Ptr/Integer that you should be sending.

Regardless, the right-left/left-right really has nothing to do with the request.

Edit:

My argument example isn't a very good one. And I think I proved my ownself wrong. ... but it still doesn't matter lol.

Edited by SmOke_N

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Share this post


Link to post
Share on other sites

I fail to see what your test is supposed to prove. You have the output in a constant order.

The output shows the order they were executed in, which is the order the nested operations were performed in.

Anyway, think about this. If you're using SendMessage API and you use BitAnd() etc as a LPARAM, And you fire off the function left to right... Then you're sending a string with the "BitAnd()" in it, not the Ptr/Integer that you should be sending.

Regardless, the right-left/left-right really has nothing to do with the request.

You're right that it probably doesn't matter = just a matter of technical language. What I meant was that your example would be interpreted in this order:
Original:  BitShift(((_SendMessage($hwnd, $LVM_APPROXIMATEVIEWRECT, $icount, BitOR(BitShift($icy, -16), BitAND($icx, 0xFFFF))))), 16)

1:  BitShift($icy, -16)
2:  BitAND($icx, 0xFFFF)
3:  _SendMessage($hwnd, $LVM_APPROXIMATEVIEWRECT, {result of 1}, {result of 2})
4:  BitShift( {$result of 3}, 16)

Because the BitShift() at 1 happens before the BitAnd() at 2, it is left-to-right. It could become significant if the two operations changed some global state that would effect the other's operation.

But as you said, this does not address your real question. Sorry for the digression.

:D


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

@Authenticity

Kind of funny really, I thought about doing reverse as well. I have taken a different approach myself which I never did iron out yet. I will have a look at what yours is doing and see if maybe do a little of both and see how efficient they may be.

Thanks


Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Share this post


Link to post
Share on other sites

Regarding the discussion you had with PsaltyDS about the nested being actually evaluated from the most inner, left most, function call toward outside, right most function call. It may be necessary to preform the loop, instead of this:

For $i = 0 To UBound($aMatches)-1

like this:

For $i = UBound($aMatches)-1 To 0 Step -1.

This way it's evaluated from the left most, inner most to the outside right most. ;]

Share this post


Link to post
Share on other sites

Regarding the discussion you had with PsaltyDS about the nested being actually evaluated from the most inner, left most, function call toward outside, right most function call. It may be necessary to preform the loop, instead of this:

For $i = 0 To UBound($aMatches)-1

like this:

For $i = UBound($aMatches)-1 To 0 Step -1.

This way it's evaluated from the left most, inner most to the outside right most. ;]

Understood thanks...

You did something in your expression that I actually had to look up (recursive), been a while since I had to do that! :D


Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

This was the original path I was taking:

#include <array.au3>
Dim $s_txt = "BitShift(((_SendMessage($hwnd, $LVM_APPROXIMATEVIEWRECT," & _
            "$icount, BitOR(BitShift($icy, -16), BitAND($icx, 0xFFFF))))), 16)"
$a_1 = _Func_GetNested($s_txt)
$a_2 = _Func_GetNested($s_txt, 0)
_ArrayDisplay($a_1, "one")
_ArrayDisplay($a_2, "two")

Func _Func_GetNested($s_text, $f_inorder = True)
    Local $a_funcs = StringRegExp($s_text, "(\w+)\s*\(", 3)
    If @error Then Return SetError(1, 0, 0)
    
    Local $a_func_list[UBound($a_funcs)]
    Local $s_temp = $s_text, $a_temp, $a_split
    Local $i_parenth_left = 0, $i_parenth_right = 0
    
    For $i = 0 To UBound($a_funcs) - 1
        $a_temp = StringRegExp($s_temp, $a_funcs[$i] & ".+\)\s*\z", 1)
        If @error Then ContinueLoop
        
        $a_func_list[$i] = $a_temp[0]
        $s_temp = StringRegExpReplace($s_temp, "\s*" & $a_funcs[$i] & "\s*\(\s*", "", 1)
        
        $a_split = StringSplit($a_func_list[$i], "")
        $i_parenth_left = 0
        $i_parenth_right = 0
        
        For $j = 1 To $a_split[0]
            If $a_split[$j] = "(" Then
                If StringRegExp($a_split[$j - 1], "\s|\w") Then $i_parenth_left += 1
            EndIf
            
            If $a_split[$j] = ")" Then
                If StringRegExp($a_split[$j - 1], "[\s\w\(]") Then $i_parenth_right += 1
            EndIf
            
            If $i_parenth_left And $i_parenth_left = $i_parenth_right Then
                $a_func_list[$i] = StringLeft($a_func_list[$i], $j)
                ExitLoop
            EndIf
        Next                
    Next
    
    If $f_inorder Then Return $a_func_list
    
    Local $i_ub = UBound($a_func_list), $i_enum = 0
    Local $a_ret_temp[$i_ub]
    For $i = $i_ub - 1 To 0 Step -1
        $a_ret_temp[$i_enum] = $a_func_list[$i]
        $i_enum += 1
    Next
    Return $a_ret_temp
EndFunc

Edited by SmOke_N

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Share this post


Link to post
Share on other sites

Yeah, it seems like an efficient way. I think that it'd be safe to exclude in both examples anything between " or ' as this is also valid but is not considered a function call

ConsoleWrite("Use ConsoleWrite($sArgument) to out put to the console")

So both paths don't eliminate this possibility.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0