AutoHotkey Community

It is currently May 25th, 2012, 10:36 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 173 posts ]  Go to page 1, 2, 3, 4, 5 ... 12  Next
Author Message
 Post subject: LowLevel & dynamic code
PostPosted: December 6th, 2007, 2:13 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
Quote:
This script is not being actively maintained and therefore may not work correctly on current versions of AutoHotkey. AutoHotkey.dll implements some or all of its functionality.



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: A compatible version of AutoHotkey (depends on the version of LowLevel downloaded).

Known 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.

    AutoHotkey v1.0.47.06:
  • 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.

    AutoHotkey v1.0.48:
  • Dynamic expressions are not supported. AutoHotkey requires expressions to be fully parsed and converted to a postfix-order array of tokens before execution. It is technically feasible but entirely impractical to form an expression using VarSetCapacity and NumPut or similar while referring to the LowLevel documentation and/or AutoHotkey source code.
  • All enum_act values listed after ACT_LOOP in the LowLevel documentation are off by one since the introduction of ACT_WHILE (105).

    AutoHotkey_L Revision 14+
  • See v1.0.48 above.

    AutoHotkey_L Revision 28+
  • Some functions of LowLevel.ahk and code.ahk are not supported. Use at your own risk.

Downloads
LowLevel for AutoHotkey v1.0.47.06
LowLevel for AutoHotkey v1.0.48
Covered by Lexikos' default copyright license.


Last edited by Lexikos on November 29th, 2010, 9:13 am, edited 30 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 6th, 2007, 2:22 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
:shock: :shock: :shock: :shock:

You are crazy.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 6th, 2007, 2:33 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
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

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 6th, 2007, 4:06 pm 
Offline

Joined: November 23rd, 2007, 10:23 am
Posts: 841
Location: ~/.
@lexikos
:D :D :D :D :D
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


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 6th, 2007, 4:10 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
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. :x

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? :lol: I lost much sleep in the aftermath of high-speed idea collision. :shock:
DerRaphael wrote:
@lexikos
:D :D :D :D :D
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." :lol:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 6th, 2007, 4:30 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
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

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 6th, 2007, 4:49 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
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...

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 6th, 2007, 5:40 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
Amazing! We have been waiting for these for years! Now dynamic expression evaluation works from compiled scripts, and without temporary files. :D

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 December 8th, 2007, 2:25 am, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 6th, 2007, 6:26 pm 
Offline
User avatar

Joined: August 30th, 2005, 8:43 pm
Posts: 8666
Location: Salem, MA
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.

_________________
Image
(Common Answers) - New Tutorials Forum - Humongous FAQ


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 7th, 2007, 12:12 am 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
I think it should be __.ahk :)

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 7th, 2007, 1:19 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
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 "?"... :x 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". :x

Edit: Script updated.


Last edited by Lexikos on December 7th, 2007, 1:25 am, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 7th, 2007, 1:30 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
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. :)
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? :?


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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 7th, 2007, 4:00 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
lexikos wrote:
Edit: Script updated.
Thanks! The ternary op works now in the calculator example!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 7th, 2007, 7:56 am 
Offline
User avatar

Joined: December 29th, 2004, 1:28 pm
Posts: 2541
Cool :!: Thanks :D


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 8th, 2007, 8:57 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
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} :x

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.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 173 posts ]  Go to page 1, 2, 3, 4, 5 ... 12  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Bing [Bot], tidbit, toddintr and 9 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group