Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

LowLevel & dynamic code


  • Please log in to reply
173 replies to this topic
Pil
  • Members
  • 55 posts
  • Last active: Mar 25 2014 05:00 AM
  • Joined: 26 Feb 2006
What about writing code that permits use of ASM code in script using __mcode(FuncName, Hex). Not that I don´t like C, but most of languages I saw use Asm to speed up things. I am reading the GoAsm manual, seems to suit perfectly.

Lexikos
  • Administrators
  • 9397 posts
  • Last active:
  • Joined: 17 Oct 2006
ASM can be used as the source language for __mcode just as easily as C. Either way the code must be compiled/assembled first.

Pil
  • Members
  • 55 posts
  • Last active: Mar 25 2014 05:00 AM
  • Joined: 26 Feb 2006
That´s what I meant.
Writing code that reads permitted asm line code in source script, then makes an .obj file with GoAsm, links it with GoLink,disassambles the exe with disassem, and takes machinecode out of produced txt file to put it in as an __mcode function on compile time.
Or another way?

Lexikos
  • Administrators
  • 9397 posts
  • Last active:
  • Joined: 17 Oct 2006
Since "mcode" is short for "machine code," the function you describe would have to be __asm. ;)

I've never even heard of GoAsm before you mentioned it. You seem to have a reasonable understanding of how it might work, so why not try it yourself?

It is also feasible to write a basic assembler in AutoHotkey, using the Intel documentation as reference.

(If anyone has wondered what I've been working on the last few weekends...)

Pil
  • Members
  • 55 posts
  • Last active: Mar 25 2014 05:00 AM
  • Joined: 26 Feb 2006
BITMAP example by SKAN with __mcode funcion by Lexikos.
ATC:=A_TickCount
SetBatchLines -1
DetectHiddenWindows, On
#include lowlevel.ahk
; Creating a 256x256 24bit bitmap file in memory
Id:="BM",Hdr:=54,W:=256,H:=256,Bit:=24,Byt:=W*H*(Bit/8),  VarSetCapacity(BMP,Hdr+Byt,0)
NumPut( NumGet( Id,0,"UShort" ),BMP,0,"UShort" ), NumPut( Hdr+Byt,BMP,2 )
NumPut( Hdr,BMP,10 ), NumPut( 40,BMP,14 ), NumPut( W,BMP,18 ), NumPut( H,BMP,22 )
NumPut( 1,BMP,26,"UShort" ), NumPut( Bit,BMP,28,"UShort" ), NumPut( Byt,BMP,34 )

Gui, 99:+AlwaysOnTop +ToolWindow +LastFound 
Gui99:=WinExist(), hDC:=DllCall("GetDC",UInt,Gui99)
Gui, 99:Add, Text, w256 h256 0x120E hWndhPic gSelColor
;LowLevel.ahk required. 
prepare_bitmap(bmp){ 
}LowLevel_init(),__mcode("prepare_bitmap" 
, "8B4424088B088B118B0283C03633D29033C988104088084" 
. "0C60000414081F9000100007CED4281FA000100007CE2C3") 
prepare_bitmap(BMP)
hBMP := DllCall( "CreateDIBitmap", UInt,hDC, UInt,&BMP+14, Int,4, UInt,&BMP+NumGet(BMP,10)
              , UInt,&BMP+14, UInt,1 )       
SendMessage, (STM_SETIMAGE:=0x172), (IMAGE_BITMAP:=0x0), hBMP,, ahk_id %hPic%
Gui, 99:Show,, % "ColorPicker [ " (A_TickCount-ATC) "ms ]"
Return

SelColor:
 MouseGetPos, X, Y
 PixelGetColor,Color, X, Y, RGB
 Tooltip % SubStr(Color,-5)
 SetTimer, TooltipOff, -2000
Return

ToolTipOff:
 ToolTip
Return

GuiClose:
 ExitApp
Lightning fast... giving me the enthousiam trying to write an "automation script" making possible to write simple asm code in AHK script.
However:

It is also feasible to write a basic assembler in AutoHotkey, using the Intel documentation as reference.
(If anyone has wondered what I've been working on the last few weekends...)

Are you saying that that´s where you are working on?
PS. Above script gives an error using beta version.

tinku99
  • Members
  • 560 posts
  • Last active: Nov 18 2013 02:43 AM
  • Joined: 03 Aug 2007
I am able to keep the temp function created by __expr
as follows:
__expr(expr, pScopeFunc=0, function = "__expr_sub")
{
    static pThisFunc
        pFunc:=__getFuncUDF(function), pThisFunc:=__getFuncUDF(A_ThisFunc), __init()
    
    nInst := NumGet(pThisFunc+40)
    VarSetCapacity(Line%nInst%,44,0), __static(Line%nInst%), pLine:=&Line%nInst%

    if ! __ParseExpressionArg(expr, pArg:=&Line%nInst%+32, pScopeFunc)
        return
    
    NumPut(pArg,NumPut(1,NumPut(102,pLine+0,0,"char"),0,"char"),2)
    , NumPut(pLine,NumPut(pLine,pLine+16))
    , NumPut(pLine,pFunc+4)
    , ret := %function%()
    return ret
}
However, all the functions i create seem to point to the last function created.

setq(ByRef var, val){
var = %val%
}

myMsg(msg)
{
Msgbox % msg
}
function1() {
    global
    ; Contents replaced at run-time by __expr.
}
function2() {
    global
    ; Contents replaced at run-time by __expr.
}

F11::  ;; test various dynamic functions

setq(x, 5)
setq(y, 7)
__expr("myMsg(y)", 0, "function2")
__expr("myMsg(x)", 0, "function1")
function1()
function2()
return


Lexikos
  • Administrators
  • 9397 posts
  • Last active:
  • Joined: 17 Oct 2006

Are you saying that that´s where you are working on?

Yes. You give the script basic assembly source, and it spits out a hexadecimal string. It is at a "functional but not useful" state. When it gets far enough to at least implement the simple function I wrote for SKAN's example, I'll start a thread. (Please save any further discussion until then.)

PS. Above script gives an error using beta version.

I likely won't write a fix until after the next official (non-beta) release of AutoHotkey.

I am able to keep the temp function created by __expr as follows:

__expr reuses the same structures for each call, except when a previous call is still running. Below is an alternative which replaces the function's body, but does not call it. It should not be used on a given function more than once as it does not free the memory used by the text and derefs.
x=Ex.
y=Why?
LowLevel_init()
__expr_("function2", "myMsg(y)")
__expr_("function1", "myMsg(x)")
function1()
function2()

__expr_(function, expr, pScopeFunc=0)
{
    __init()
    pFunc:=__getFuncUDF(function)
    VarSetCapacity(Line%function%,44,0), __static(Line%function%), pLine:=&Line%function%
    if ! __ParseExpressionArg(expr, pArg:=&Line%function%+32, pScopeFunc)
        return false
    NumPut(pArg,NumPut(1,NumPut(102,pLine+0,0,"char"),0,"char"),2)
    , NumPut(pLine,NumPut(pLine,pLine+16))
    , NumPut(pLine,pFunc+4)
    return true
}


myMsg(msg)
{
Msgbox % msg
}
function1() {
    global
    ; Contents replaced at run-time by __expr.
}
function2() {
    global
    ; Contents replaced at run-time by __expr.
}
If you have a practical use for this, would you mind posting a demonstration?

tinku99
  • Members
  • 560 posts
  • Last active: Nov 18 2013 02:43 AM
  • Joined: 03 Aug 2007

If you have a practical use for this, would you mind posting a demonstration?


Thanks Lexikos. That works.

I was just playing around with it.

No specific use for it yet.

Lexikos
  • Administrators
  • 9397 posts
  • Last active:
  • Joined: 17 Oct 2006
I recently realised that __expr cannot easily be made to work with the pre-v1.0.48 beta, since all expressions must be pre-tokenized before evaluation. In other words, it would need to implement a full expression parser, which is simply something I will not do. (If Line::ExpressionToPostfix() were exposed to script it would be possible, but permanent memory would be allocated for each expression evaluated.)

This makes easier my decision to stop development on LowLevel indefinitely, instead focusing my efforts on AutoHotkey_L. I intend to eventually introduce similar functionality.

That aside, some of you may find the following script interesting, especially those that know what the uses of an anonymous function are (since my example is not useful):
private=no
FuncA()

FuncA()
{
    static _T,_F ; Generate the exression function only once.
    if !_T
        LowLevel_init(),_T:=__findFunc(A_ThisFunc)
    
    private=yep
    
    ; Demonstrate that FuncB cannot access 'private' directly.
    MsgBox % FuncB("private")
    ; Demonstrate that via _T, functions created by __function CAN access our local variables.
    MsgBox % FuncB(__function(_F,"private '!'",_T) "()")
}

FuncB(x)
{
    if SubStr(x,-1)="()"
    {
        F := SubStr(x,1,-2)
        return %F%()
    }
    else
        return (%x%)
}

; Builds a function from a given expression, and returns its name.
; DO NOT CALL if func_buf has been assigned contents or given
;   non-zero capacity by anything other than this function.
; IT IS NOT SAFE to simply clear func_buf since it will not release
;   resources allocated by __ParseExpressionArg.
__function(ByRef func_buf, expr="", pScopeFunc=0)
{
    static ACT_RETURN:=102, VAR_ASSUME_LOCAL:=1
        , SIZE_FUNC:=52, SIZE_LINE:=32, SIZE_ARGSTRUCT:=12
        , func_index:=0
    LowLevel_init()
    if !(first_func:=__getFirstFunc())
        return ; FATAL ERROR.
    
    ; Recommended usage is to use 'func' to conveniently cache the result.
    ; func MUST have capacity=0 unless set by a previous call to this function.
    if VarSetCapacity(func_buf)
        return __str(NumGet(func_buf))
    if expr =
        return ; OOPS!
    
    ; Function name can be anything since AutoHotkey won't be validating it.
    func_index += 1
    
    VarSetCapacity(func_buf, SIZE_FUNC + SIZE_LINE + SIZE_ARGSTRUCT + StrLen(func_index) + 1, 0)
    
    ptr_func := &func_buf
    ptr_line := ptr_func + SIZE_FUNC
    ptr_arg  := ptr_line + SIZE_LINE
    ptr_name := ptr_arg  + SIZE_ARGSTRUCT
    
    DllCall("lstrcpy","uint",ptr_name,"str",func_index) ; Copy name into buffer.
    
    NumPut(ptr_name, ptr_func + 0) ; Func->Name
    NumPut(ptr_line, ptr_func + 4) ; Func->JumpToLine
    NumPut(VAR_ASSUME_LOCAL, ptr_func + 48, 0, "char") ; Func->DefaultVarType
    
    NumPut(ACT_RETURN | 1<<8, ptr_line + 0, 0, "short") ; Line->{ActionType,Argc}
    NumPut(ptr_arg, ptr_line + 4) ; Line->Arg
    
    ; ArgStruct will be initialised by the following call:
    __ParseExpressionArg(expr, ptr_arg, pScopeFunc)
    
    ; Now that Func, Line and ArgStruct are valid, insert function into list.
    NumPut(NumGet(first_func + 44), ptr_func + 44)
    NumPut(ptr_func, first_func + 44)
    
    return func_index ; Name, not address.
}
It has similar functionality to __expr_ in my previous post, but creates an entirely new function rather than overwriting an existing one.

A more useful function would support something like:
MyFunc(myparam) {
    ...
    Foreach(list, __function(_F
        , "(f, i) => mylocal .= f + myparam * i . ','"
    ,_T))
}

Foreach(list, func, delim=",") {
    Loop, Parse, list, %delim%
        %func%(A_LoopField, A_Index)
}
Entirely untested and probably useless pseudo-code. Yes, it is entirely feasible.

polyethene
  • Administrators
  • 5511 posts
  • Last active: Apr 23 2014 11:38 PM
  • Joined: 26 Oct 2012

(f, i) => mylocal .= f + myparam * i . ',

I see what you're doing there. While syntax sugar like delegates and reflection can be useful to fluent programmers, the typical AutoHotkey user would probably never get the hang of them. You could end up with feature bloat as py3k has taught us, not to mention the massive waste of time for the developer. Keep us updated on your new ideas though, it'll help me decide what to work into the IA lexer when I do it the first time round - like arrays for example.

Lexikos
  • Administrators
  • 9397 posts
  • Last active:
  • Joined: 17 Oct 2006

You could end up with feature bloat as py3k has taught us,

It's a hypothetical script, not a proposal for a built-in feature.

not to mention the massive waste of time for the developer.

Given its dependence on __expr, it would be only a small waste of time. Not small enough, I think.

While syntax sugar like delegates and reflection can be useful to fluent programmers,

What I was suggesting was merely an extension of the function to allow a list of parameter names without requiring an extra parameter. As it is, the generated function cannot have parameters.

What does reflection have to do with syntax sugar?

the typical AutoHotkey user

...has nothing to do with this thread. :p

polyethene
  • Administrators
  • 5511 posts
  • Last active: Apr 23 2014 11:38 PM
  • Joined: 26 Oct 2012

It's a hypothetical script, not a proposal for a built-in feature.

My statement was a hypothetical response.

some of you may find the following script interesting, especially those that know what the uses of an anonymous function are

an extension of the function to allow a list of parameter names without requiring an extra parameter.

In some languages there are anonymous delegates and object initializers. What you're describing is a mix of both, can you be more clear?

What does reflection have to do with syntax sugar?

In the low level (pun intended) sense that here it would cause a conversion to an intermediate form, or "pre-tokenized before evaluation [Line]." Anyway the point is not to discuss the definition of syntax sugar, I don't want to hijack this thread with another debate over semantics.

the typical AutoHotkey user

...has nothing to do with this thread.

I probably haven't understood who the target audience for your AutoHotkey fork exactly is. Going by your response I would assume the proficient few programmers, correct?

Lexikos
  • Administrators
  • 9397 posts
  • Last active:
  • Joined: 17 Oct 2006

In some languages there are anonymous delegates and object initializers. What you're describing is a mix of both, can you be more clear?

I was a bit vague, speaking only in the context of __function.

__function creates a "Func" structure which can be dynamically called by AutoHotkey to evaluate an expression and return its result. My "idea" was strictly limited to allowing __function to add parameters to the "Func" it creates, for use in the expression.

In the low level (pun intended) sense that here it would cause a conversion to an intermediate form, or "pre-tokenized before evaluation [Line]."

Thanks for the explanation. I now see what reflection has to do with the script, but my original point remains: Syntax defines how a functionality is accessed, but is not itself functional.

The way I see it now, dynamic function calls provide the capability for delegation, and LowLevel provides the capability for reflection. Neither are syntax, but the former is represented by such: %func%(). This you could say is syntax sugar, as there are longer ways to achieve similar results without having syntax specifically for it.

This brings me to __function("(params)=>expression") - syntax sugar for __function("params","expression"). (Just one way of placing less importance on the "params" param.)

I don't want to hijack this thread with another debate over semantics.

By debating semantics, I come to a better understanding of what you really mean, rather than what I would mean if I spoke those words.

While the script I posted uses "reflection" to allow a function to be defined in-line, if it were a built-in feature as in C#, "reflection" would not be necessary. From a user's perspective, they are not using reflection, but using functionality made feasible by it.

I probably haven't understood who the target audience for your AutoHotkey fork exactly is.

What I meant was that this thread, LowLevel, is absolutely not intended for typical AutoHotkey users - i.e. those that "would probably never get the hang of" its functionality.

polyethene
  • Administrators
  • 5511 posts
  • Last active: Apr 23 2014 11:38 PM
  • Joined: 26 Oct 2012
It was misleading of me to suggest that dynamic code or reflection is syntax sugar, with the same logic one could argue looping is no different as it can be done with conditional gotos. What I meant to refer to was the added stages in the lexer such that if "(params)=>expression" were to be converted to "params","expression" then reparsed and evaluated no new functionality has been added as far as the parser is concerned, hence low level syntactic sugar.

By debating semantics, I come to a better understanding of what you really mean, rather than what I would mean if I spoke those words.

As I see it there can only be a single definition. I am not a professional programmer so if my understanding is incorrect please let me know.

What I meant was that this thread, LowLevel, is absolutely not intended for typical AutoHotkey users

This makes easier my decision to stop development on LowLevel indefinitely, instead focusing my efforts on AutoHotkey_L.

My posts were in fact directed towards your AutoHotkey fork and the concepts you're taking over from this script. Here seemed like the right place to discuss it.

Lexikos
  • Administrators
  • 9397 posts
  • Last active:
  • Joined: 17 Oct 2006

My posts were in fact directed towards your AutoHotkey fork and the concepts you're taking over from this script. Here seemed like the right place to discuss it.

I should have qualified "similar functionality" by saying I intend to implement only a few key functionalities, like "reflection" and __expr.