AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

LowLevel & dynamic code
Goto page 1, 2, 3, 4, 5  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Lexikos



Joined: 17 Oct 2006
Posts: 2472
Location: Australia, Qld

PostPosted: Thu Dec 06, 2007 2:13 pm    Post subject: LowLevel & dynamic code Reply with quote

LowLevel.ahk contains a collection of advanced functions for AutoHotkey scripts. The base functions allow a script to access the so-called "low-level" data structures which form it. Additional functions provide other functionality by accessing these data structures. See the included help file for a list of functions.

code.ahk provides functions to simplify generating code while the script is running. For a basic overview, see Generating Code in the included help file.

Requirements: AutoHotkey v1.0.47.06+

Known limitations and issues:
  • User-defined functions are only accessible if referenced in script or defined after a function which is referenced in script.
  • Since 'AND' and 'OR' are normally replaced at load-time with '&&' or '||', they are not supported by __expr or __ParseExpressionArg. Use '&&' and '||' instead.
  • Double-derefs in __expr always resolve to a global variable.
  • If a local variable is used as the base of an array for an array-creating function such as RegExMatch, the individual array variables are created local to __expr_sub - i.e. inaccessible to the script.

Download


Last edited by Lexikos on Mon Jun 09, 2008 2:50 am; edited 20 times in total
Back to top
View user's profile Send private message
majkinetor



Joined: 24 May 2006
Posts: 3589
Location: Belgrade

PostPosted: Thu Dec 06, 2007 2:22 pm    Post subject: Reply with quote

Shocked Shocked Shocked Shocked

You are crazy.
_________________
Back to top
View user's profile Send private message MSN Messenger
majkinetor



Joined: 24 May 2006
Posts: 3589
Location: Belgrade

PostPosted: Thu Dec 06, 2007 2:33 pm    Post subject: Reply with quote

This acctually works
Code:
#singleinstance, force
   Gui, Add, Text, Enter AHK code
   Gui, Add, Edit, w300 vCode
   Gui, Add, Button, Default gOnButton, Execute
   Gui, Add, Text, vRes x+50 w200
   Gui, Show, autosize
   __init()
return

OnButton:
   Gui, Submit, NoHide   
   res := __expr(code)
   GuiControl, , res, %res%
return


This expression doesn't work though:  1 ? 5 : 6
Hello(){
  return "Hi there"
}

Msg() {
  MsgBox Hi there
}

#include lowlevel.ahk

_________________
Back to top
View user's profile Send private message MSN Messenger
DerRaphael



Joined: 23 Nov 2007
Posts: 379
Location: Heidelberg, Germany

PostPosted: Thu Dec 06, 2007 4:06 pm    Post subject: Reply with quote

@lexikos
Very Happy Very Happy Very Happy Very Happy Very Happy
This is ...... actually i can't find words for it.

Let's call it great. Fantastic. Awesome.
Im still shaking my head, being so impressed.

btw i tried majkinetors lil example and it works fine (Version 1.0.47.5)

When you're still looking for a name, why not naming it:
AhkLowLevelAccess (ALLA)
AccessLowLevel (ALL)
Access_AhkLowLevel (A_ALL)

great job and many thanks for sharing it
derRaphael
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 2472
Location: Australia, Qld

PostPosted: Thu Dec 06, 2007 4:10 pm    Post subject: Reply with quote

majkinetor wrote:
This expression doesn't work though: 1 ? 5 : 6

Works for me.
Code:
MsgBox % __expr("1 ? 5 : 6")
I did, however, find and fix two bugs in function deref parsing. "func0()+1" would not work when func0 has no parameters because the ')' was skipped and "+1" was seen as a parameter. "func0()" worked because after the ')' is nothing. "func1(func0())" would not work because the inner ')' was skipped and the outer ')' was miscounted as a parameter. Mad

Btw, __expr doesn't do any expression evaluation. It constructs a Line and ArgStruct, and creates a DerefType for each var or func reference. It then assigns the Line to the __expr_sub function, and calls it.

Basically, it emulates the load-time processing of AutoHotkey.

If no var or func references are needed, it can be considerably simpler. The following is the third iteration of __expr (where the one in lowlevel.ahk is the fourth):
Code:
MsgBox % __expr("1 ? 5 : 6")

__expr(expr)
{
    static line, arg
    if !VarSetCapacity(line) {
        VarSetCapacity(line,32,0), VarSetCapacity(arg,12,0)
        NumPut(102,line,0,"char")           ; line.mActionType = ACT_RETURN
        NumPut(&arg,line,4)                 ; line.mArg = &arg
        ; Give mNextLine and mPrevLine non-NULL values in case the expression
        ; somehow causes a critical error, in which case AutoHotkey may try
        ; to use these to display the error line and the lines around it.
        NumPut(&line,NumPut(&line,line,16)) ; line.mNextLine = line.mPrevLine = &line
        NumPut(1,arg,1,"char")              ; arg.is_expression = true
        cb:=RegisterCallback("__expr_last")
        NumPut(&line,NumGet(cb+28),4)       ; cb->Func->mJumpToLine = &line
        DllCall("GlobalFree","uint",cb)
    }
    NumPut(1,line,1,"char")                 ; line.mArgc = 1
    NumPut(StrLen(expr)+1,arg,2,"short")    ; arg.length = StrLen(expr)+1
    NumPut(&expr,arg,4)                     ; arg.text = &expr
    ret := __expr_last()
    ; Reset mArgc to 0 so ListLines does not try to read 'expr', which will
    ; become invalid once __expr() returns.
    NumPut(0,line,1,"char")                 ; mArgc = 0
    return ret
}
__expr_last() {
}


I will eventually write a function to evaluate commands. (This is why I wrote __MakeExpressionArg separate from __expr.) The command names must be translated to ActionType codes, and derefs in non-expression args must also be parsed.

Once that's done, a little extra work must be done to link the lines together properly and form a working dynamic script (with If, Loop, etc.)
Quote:
You are crazy.
You noticed? Laughing I lost much sleep in the aftermath of high-speed idea collision. Shocked
DerRaphael wrote:
@lexikos
Very Happy Very Happy Very Happy Very Happy Very Happy
This is ...... actually i can't find words for it.

Let's call it great. Fantastic. Awesome.
Im still shaking my head, being so impressed.
I was in shock for a while after coming up with "the idea." Laughing
Back to top
View user's profile Send private message
majkinetor



Joined: 24 May 2006
Posts: 3589
Location: Belgrade

PostPosted: Thu Dec 06, 2007 4:30 pm    Post subject: Reply with quote

This accutally allows us to read internal function variables as this example shows (and so to change it, without calling the function):

Code:
ppFunc := __findFunc("Module_Globals")
ppvar  := __findVar("var1", ppFunc, 1)

mContents := NumGet(ppVar+0)

buf := "some new text"

DllCall("lstrcpyn", "uint", mContents, "uint", &buf, "int", StrLen(buf)+1)

Msgbox % __str( mContents , -1 )

return



Module_Globals(){
   static var1 := "this is some internal function text"
}

#include lowlevel.ahk

_________________
Back to top
View user's profile Send private message MSN Messenger
majkinetor



Joined: 24 May 2006
Posts: 3589
Location: Belgrade

PostPosted: Thu Dec 06, 2007 4:49 pm    Post subject: Reply with quote

I just benchmarked in optimal case, and it doesn't provide benefits comparing to using function call to return variable result. Check it out:

Code:
ppFunc := __findFunc("Module_Globals")
ppvar  := __findVar("var1", ppFunc, 1)
mContents := NumGet(ppVar+0)
hKernal :=  DllCall("LoadLibrary", "str", "Kernel32.dll")
pMulDiv :=  DllCall("GetProcAddress", "Uint", hKernal , "uint", 612)

t := A_TickCount

loop, 100000
   s := Module_Globals("var1")
t0 := A_tickCount - t

t := A_TickCount
loop, 100000
   s := DllCall(pMulDiv,"uint",mContents,"int",1,"int",1,"str")
t1 := A_tickCount - t

MsgBox %t0% %t1%

return

Module_Globals(name){
   static var1 := "this is some internal function text", var2 := 123
   val := %name%
   return val
}

#include lowlevel.ahk


Neverthe less, static local arrays are valuable thing.

Enough with that, I am impatiently waiting for full dynamic code. That will open metaprogramming dimension in AHK.

The only bad thing about this is that it is 100% AHK version dependent.
Perhaps Chris can use your work to implement dynamic code internaly...
_________________
Back to top
View user's profile Send private message MSN Messenger
Laszlo



Joined: 14 Feb 2005
Posts: 3941
Location: Pittsburgh

PostPosted: Thu Dec 06, 2007 5:40 pm    Post subject: Reply with quote

Amazing! We have been waiting for these for years! Now dynamic expression evaluation works from compiled scripts, and without temporary files. Very Happy

Ternary operators don’t work for me, either (return blank) with the downloaded lowlevel.ahk. Also, “1 ? 2” results in 12, which could indicate that the “?” is not treated properly.

As majkinetor showed, we can have a calculator with 9 AHK commands (after including lowlevel.ahk):
Code:
Gui Add, Edit, w300 vCode
Gui Add, Button, w0 Default gExec
Gui Add, Text, vRes x+0 w200, Result =
Gui Show, AutoSize, Evaluate AHK expression {Enter}
__init()

Exec:
   Gui Submit, NoHide
   GuiControl,,res, % "Result = " . __expr(code)
return


The double underscore prefix looks informative for me. How much lower level can a prefix be? Wink

Edit 20071207: Actually, 3 AHK commands are enough for a calculator.
Code:
Loop {
   InputBox code,Evaluate AHK expression,% "Result = " __expr(code),,300,120,,,,,%code%
   IfEqual ErrorLevel,1, Break
}
#include lowlevel.ahk
Assign it to a hotkey, and you have a fast simple, always available calculator.

Last edited by Laszlo on Sat Dec 08, 2007 2:25 am; edited 1 time in total
Back to top
View user's profile Send private message
engunneer



Joined: 30 Aug 2005
Posts: 6307
Location: Pacific Northwest, US

PostPosted: Thu Dec 06, 2007 6:26 pm    Post subject: Reply with quote

but can you call the script _.ahk and be stdlib compliant?

I think we need some prefix here so it can be added to the stdlib. This is obviously quite powerful.

edit:
_.ahk in my lib did not work.
_________________
Unless otherwise noted, all code is untested.
Common Answers: 1.(Loops, Viruses, etc.) 2. Search 3.RTFM
Back to top
View user's profile Send private message Visit poster's website
majkinetor



Joined: 24 May 2006
Posts: 3589
Location: Belgrade

PostPosted: Fri Dec 07, 2007 12:12 am    Post subject: Reply with quote

I think it should be __.ahk Smile
_________________
Back to top
View user's profile Send private message MSN Messenger
Lexikos



Joined: 17 Oct 2006
Posts: 2472
Location: Australia, Qld

PostPosted: Fri Dec 07, 2007 1:19 am    Post subject: Reply with quote

Laszlo wrote:
Ternary operators don’t work for me, either (return blank) with the downloaded lowlevel.ahk. Also, “1 ? 2” results in 12, which could indicate that the “?” is not treated properly.
As I pointed out, __expr doesn't evaluate the expression. It does, however, create a deref for "?"... Mad It worked in my previous test because I forgot to call __init().
Quote:
The double underscore prefix looks informative for me. How much lower level can a prefix be? Wink
Heh, that's priceless.
engunneer wrote:
but can you call the script _.ahk and be stdlib compliant?
As I said, the script is std-lib compliant if named ".ahk". AutoHotkey uses everything up to the first under-score (in this case nothing) as the prefix. Explorer won't let you give it "no name," but Firefox will. You can also use a command prompt (or AutoHotkey script!) to rename it. I only named the file lowlevel.ahk because Firefox would save ".ahk.html". Mad

Edit: Script updated.


Last edited by Lexikos on Fri Dec 07, 2007 1:25 am; edited 1 time in total
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 2472
Location: Australia, Qld

PostPosted: Fri Dec 07, 2007 1:30 am    Post subject: Reply with quote

Moderator! wrote:
this is amazing... thanks. while this opens many new opportunites, i am worried about the internals of AHK being discussed in public. IMHO, you could have opted the "appropriate section" of our forum. please consider. thanks again for your wonderful contribution. Smile
Come again? AutoHotkey is open source. Anyone that understands my script could most likely understand the AutoHotkey source. Anyway, how could any of this be exploited? The "entry point" is RegisterCallback, which must be called by the script itself. As for the "appropriate section," what would that be? Confused


majkinetor wrote:
The only bad thing about this is that it is 100% AHK version dependent.
Perhaps Chris can use your work to implement dynamic code internaly...

I don't imagine so. The main barrier to building in dynamic code functionality is that script objects (Line, ArgStruct, DerefType, etc.) use "persistent" memory (avoiding the overhead of dynamic memory allocations), so can't be deleted. Changing this behaviour would affect the performance (at least, memory usage) of all scripts. This isn't an issue with the script, since it allocates the structures itself. (Doing it this way in AutoHotkey itself would involve duplicating a considerable amount of code.)

Perhaps I'll take a crack at it some time, and see how it performs. For now I'm trying to focus on my many unfinished projects.
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 3941
Location: Pittsburgh

PostPosted: Fri Dec 07, 2007 4:00 am    Post subject: Reply with quote

lexikos wrote:
Edit: Script updated.
Thanks! The ternary op works now in the calculator example!
Back to top
View user's profile Send private message
corrupt



Joined: 29 Dec 2004
Posts: 2381

PostPosted: Fri Dec 07, 2007 7:56 am    Post subject: Reply with quote

Cool Exclamation Thanks Very Happy
Back to top
View user's profile Send private message Visit poster's website
Lexikos



Joined: 17 Oct 2006
Posts: 2472
Location: Australia, Qld

PostPosted: Sat Dec 08, 2007 8:57 am    Post subject: Reply with quote

This morning (it's nearly 6 PM here) I started working on __findVar, with the intention of adding support for creating local variables. It got up to 55 lines before I realised what a PAIN it would be to write code to insert a local variable into the (mVar or mLazyVar) array, since I'd potentially have to reallocate mVar and/or move Vars from mLazyVar into mVar, all the while preserving alphabetical order. {gasps for air} Mad

Luckily, I thought of a way to make __findVar smaller, more capable, and more efficient:
Instead of searching some function's local variable arrays, simply switch them with __findVar's arrays temporarily and perform a double-deref! Consequently, I have renamed __findVar to __getVarInContext.
Quote:
__getVarInContext( sVarName [, pScopeFunc ] )
    Retrieves the Var structure of a variable with the given name in the context of the specified function (or in global context if no function is specified), with the same semantics as a double-deref. pScopeFunc is a pointer to a Func, not a callback or function name.

Quote:
If a thread running __getVarInContext is interrupted between the second and last RtlMoveMemory calls and __getVarInContext is called again (causing recursion), the local variables in the first instance of __getVarInContext are overwritten. This should be very rare, considering the very small "window of inopportunity."

I have also removed the "LocalVarsOnly" parameter, since it is no longer applicable.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page 1, 2, 3, 4, 5  Next
Page 1 of 5

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group