Convert Your Scripts to v2
This is a script for converting AutoHotkey v1 scripts to AutoHotkey v2 scripts. There are quite a few changes mainly based around the transition from traditional to expression syntax. Although at the moment `= is allowed in place of the past = for assignment, it may not be supported at some point. For this reason the converter will always change = assignment to :=.
Also, I don't know where style is going from here, or a number of possible changes that may be made (ex. deref characters). This script and its output may change greatly overtime if there is demand to keep it up.
I went for a simple approach to the conversion. I'm sure there are better, or more exact ways to convert scripts. Please let me know if you have ideas on how to improve it.
This is not complete even for the changes made thus far, so if anyone needs features I will add them on request.
Here is the main code. It runs on AHKv2 Alpha and needs format.ahk which Lexikos put in the Lib folder of the zip. To use:
- Run the script
- Chose the script to convert
- The new script will be in the same folder with "New" after the file name
- Enjoy!

Code:
; =============================================================================
; Script Converter
; for converting scripts from v1 AutoHotkey to v2
; Use:
; Run the script
; Chose the file you want to convert in the file select dialog
; A msgbox will popup telling you the script finished converting
; If you gave the file MyScript.ahk, the output file will be MyScriptNew.ahk
; Thats it, feel free to add to it and post changes here: http://www.autohotkey.com/forum/viewtopic.php?t=70266
; Uses format.ahk
; =============================================================================
Remove `=
(
#AllowSameLineComments
#MaxMem
SoundGetWaveVolume
SoundSetWaveVolume
#NoEnv
#Delimiter
SetFormat
A_FormatInteger
A_FormatFloat
)
Convert `=
(
EnvAdd,InputVar,Value,TimeUnits | *EnvAdd
EnvDiv,InputVar,Value | {1} /= {2}
EnvMult,InputVar,Valut | {1} *= {2}
EnvSub,InputVar,Value,TimeUnits | {1} -= {2}[, {3}]
IfEqual,InputVar,value | If {1} = {2}
IfNotEqual,InputVar,value | If {1} != {2}
IfGreater,InputVar,value | If {1} > {2}
IfGreaterOrEqual,InputVar,value | If {1} >= {2}
IfLess,InputVar,value | If {1} < {2}
IfLessOrEqual,InputVar,value | If {1} <= {2}
StringLen,OutputVar,InputVar | {1} := StrLen({2})
StringGetPos,OutputVar,InputVar,SearchText,Side, Offset | {1} := InStr({2}, {3}[][, false, {5}])
StringMid,OutputVar,InputVar,StartChar,Count,L | {1} := SubStr({2}, {3}[, {4}][])
StringLeft,OutputVar,InputVar,Count | {1} := SubStr({2}, 1, {3})
StringRight,OutputVar,InputVar,Count | {1} := SubStr({2}, -{3}+1, {3})
StringTrimLeft,OutputVar,InputVar,Count | {1} := SubStr({2}, 1, -{3})
StringTrimRight,OutputVar,InputVar,Count | {1} := SubStr({2}, {3}+1)
WinGetActiveStats,TitleVar,WidthVar,HeightVar,XVar,YVar | *ActiveStats
WinGetActiveTitle,OutputVar | WinGetTitle, {1}, A
DriveSpaceFree,OutputVar,PathVar | DriveGet, {1}, SpaceFree, {2}
)
Directives `=
(Join`r`n
#Warn UseUnsetLocal
#Warn UseUnsetGlobal
)
SubStrFunction `=
(Join`r`n
; This function may be removed if StartingPos is always > 0.
CheckStartingPos(p) {
return p - (p <= 0)
}
)
; =============================================================================
; Main Part of program
; Many changes can be made without altering this
; =============================================================================
if !Args
{
FileSelectFile, FN,, %A_MyDocuments%
If !FN
ExitApp
FNOut := SubStr(FN, 1, StrLen(FN)-4) . "_new.ahk"
}
else If Args.MaxIndex() = 1 ; Allow a command line param for the file name ex. Run Convert.ahk "MyInputFile.ahk"
{
FN := Trim(Args[1])
FNOut := SubStr(FN, 1, StrLen(FN)-4) . "_new.ahk"
}
else if Mod(Args.MaxIndex(), 2) = 0 ; Parse arguments with linux like syntax, ex. Run Convert.ahk --input "Inputfile.ahk" -o "OutputFile.ahk"
{
for i, P in Args
{
If Mod(i,2) ; Odd parameter, identifier
{
If (P = "-o") || (P = "--output")
Mode := 1
else If (P = "-i") || (P = "--input")
Mode := 2
else
Mode := 0
}
else if Mode != 0
{
If Mode = 1
FNOut := Trim(P)
else if Mode = 2
FN := Trim(P)
}
}
}
If !FN
{
Msgbox, 48, Conversion Error, The commandline parameters passed are invalid. Please make sure they are correct and try again. Now exiting.
ExitApp
}
If !FNOut
FNOut := SubStr(FN, 1, StrLen(FN)-4) . "_new.ahk"
Output := FileOpen(FNOut, "w")
Loop, Read, %FN%
{
Skip := false
Line := A_LoopReadLine
FirstChar := SubStr( Trim(Line), 1, 1 )
FirstTwo := SubStr(LTrim(Line), 1, 2)
CommandMatch := -1
If (Trim(Line) == "") || ( FirstChar == ";" )
{
; Do nothing, but we still want to add the line to the output file
}
else if FirstTwo == "/*"
InCommentBlock := true
else if FirstTwo == "*/"
InCommentBlock := false
else if InCommentBlock
{
; Do nothing, but skip all the following
}
else If InStr(Line, "SendMode") && InStr(Line, "Input")
Skip := true
else if ( FirstChar == "(" )
{
If RegExMatch(Line, "i)join(.+?)(LTrim|RTrim|Comment|%|,|``)?", Join)
JoinBy := Join1
else
JoinBy := "``n"
Cont := 1
If InStr(LastLine, ":= """"")
{
Output.Seek(-4, 1) ; Remove the newline characters and double quotes
}
else
{
Output.Seek(-2, 1)
Output.Write(" % ")
}
continue ; Don't add to the output file
}
else if ( FirstChar == ")" )
{
Cont := 0
continue
}
else if Cont
{
Line := ToExp(Line . JoinBy)
If Cont > 1
Line := ". " . Line
Cont++
}
; Replace = with := expression equivilents
else If RegExMatch(Line, "i)^([\s]*[a-z_][a-z_0-9]*[\s]*)=([^;]*)", Equation) ; Thanks Lexikos
Line := RTrim(Equation1) . " := " . ToExp(Equation2)
else If RegExMatch(Line, "i)^(\s*if\s+[a-z_][a-z_0-9]*[\s]*)=([^{;]*)(\s*{?)", Equation)
Line := format_v("{variable} = {equation}{otb}", {variable: RTrim(Equation1), equation: ToExp(Equation2), otb: Equation3} )
else ; Command replacing
; To add commands to be checked for, modify the list at the top of this file
{
CommandMatch := 0
Line := RegExReplace(Line, ",\s+", ",")
FirstDelim := RegExMatch(Line, "[,\s]")
Command := Trim( SubStr(Line, 1, FirstDelim-1) )
Params := SubStr(Line, FirstDelim+1)
; Now we format the parameters into their v2 equivilents
Loop, Parse, Convert, `n
{
StringSplit, Part, A_LoopField, |
ListDelim := RegExMatch(Part1, "[,\s]")
ListCommand := Trim( SubStr(Part1, 1, ListDelim-1) )
If (ListCommand = Command)
{
CommandMatch := 1
ListParams := RTrim( SubStr(Part1, ListDelim+1) )
ListParam := Array()
Param := Array() ; Parameters in expression form
Loop, Parse, ListParams, `,
ListParam[A_Index] := A_LoopField
Loop, Parse, Params, `,
If InStr(ListParam[A_Index], "var")
Param[A_Index] := A_LoopField
else
Param[A_Index] := ToExp(A_LoopField)
Part2 := Trim(Part2)
If ( SubStr(Part2, 1, 1) == "*" )
{
FuncName := SubStr(Part2, 2)
If IsFunc(FuncName)
Line := %FuncName%(Param)
}
else
{
If ParamDif := (ListParam.MaxIndex() - Param.MaxIndex() )
; Remove all unused optional parameters
Part2 := RegExReplace(Part2, "\[[^\]]*\]", "", Count, ParamDif, 1)
StringReplace, Part2, Part2, [,, All
StringReplace, Part2, Part2, ],, All
Line := format_v(Part2, Param)
}
}
}
}
; Remove lines we can't use
If CommandMatch = 0 && !InCommentBlock
Loop, Parse, Remove, `n, `r
If InStr(A_LoopReadLine, A_LoopField)
Skip := true
; TEMPORARY
If !FoundSubStr && !InCommentBlock && InStr(Line, "SubStr")
{
FoundSubStr := true
Line .= " `; WARNING: SubStr conversion may change in the near future"
}
; Put the directives after the first non-comment line
If !FoundNonComment && !InCommentBlock && A_Index != 1 && FirstChar != ";" && FirstTwo != "*/"
{
Output.Write(Directives . "`r`n")
FoundNonComment := true
}
If Skip
Line := format_v("; REMOVED: {line}", {line: Line})
Output.Write(Line . "`r`n")
LastLine := Line
}
; The following will be uncommented at a a later time
;If FoundSubStr
; Output.Write(SubStrFunction)
Output.Close()
If !Args.MaxIndex()
MsgBox, Done!
ExitApp
; =============================================================================
; Convert traditional statements to expressions
; Don't pass whole commands, instead pass one parameter at a time
; =============================================================================
ToExp(Text)
{
static qu := """" ; Constant for double quotes
Text := Trim(Text, " `t")
If Text = ""
TOut := (qu . qu) ; Two double quotes
else if InStr(Text, "%")
{
TOut := ""
Loop % StrLen(Text)
{
Symbol := Chr(NumGet(Text, (A_Index-1)*2, "UChar"))
If Symbol == "%"
{
If (DeRef := !DeRef) && (A_Index != 1)
TOut .= qu . " . "
else If (!DeRef) && (A_Index != StrLen(Text))
TOut .= " . " . qu
}
else
{
If A_Index = 1
TOut .= qu
TOut .= Symbol
}
}
If Symbol != "%"
TOut .= (qu) ; One double quote
}
else if type(Text+0) != "String"
{
TOut := Text+0
}
else
{
StringReplace, TOut, Text, % qu, % qu . qu, All
TOut := qu . TOut . qu
}
return (TOut)
}
; =============================================================================
; Formatting functions
; They all accept an array of parameters and return command(s) in text form
; These are only called in one place in the script and are called dynamicly
; =============================================================================
ActiveStats(p) {
If p[1]
Out .= format_v("WinGetTitle, {1}, A", p)
Count := p.MaxIndex()
loop 5
p[A_Index] := ( p[A_Index] ? " " . p[A_Index] : "" )
if Count > 1 ; Width and/or Height and/or X and/or Y but not Title
Out .= (p[1] ? "`r`n" : "") . format_v("WinGetPos{2},{3},{4},{5}, A", p)
return Out
}
EnvAdd(p) {
If p[3]
return format_v("{1} := DateAdd({1}, {2}, {3})", p)
else
return format_v("{1} += {2}", p)
}
Click here to see an example conversion