Jump to content

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

[AHK_L] OOP preprocessor v1.1a


  • This topic is locked This topic is locked
22 replies to this topic
fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
Hi,
This is an idea I've had for awhile. This program takes scripts with non-existing OOP constructs and converts them to the AHK_L syntax.

Download (version 1.1a)

Demo:
useless := [new Useless]
useless.AmIUseless()

useful := [new EvenMoreUseful]
msgbox % "2 + 2 = " useful.AddNums(2, 2)
useful.AmIUseless()

class Useless
	method AmIUseless
	{
		type := [typeof this]
		MsgBox % (type = "Useless" ? "Yeah" : "No") ", I'm " type "..."
	}
endclass

class Useful inherits Useless
	.constructor
	{
		MsgBox % [typeof this] " object instantiated!"
	}
endclass

class EvenMoreUseful inherits Useful
	method AddNums(a, b)
	{
		return a + b
	}
endclass


IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007
Very interesting.

:)

Thougt - I'm a bit afraid of all these user defined new syntaxes. It may be cool to discuss out AHK OOP Syntax and then it could be implemented and used more in common sense. Talking about a native IA/AHK_L implementation, or common accepted precompiler for IA/AHK_L.
This may result in some system defined keywords/key functions - typeof()/new/this and so on.

What do you think?


btw:
Typesafety could be implemented too:


class Person
	Name := "unknown"
	
	construcor(uname){
		this.Name := uname
	}
endclass

class Car
	Enter(Person person){
		MsgBox % person.Name  " entered the car."
	}
endclass

resulting in:

	Enter(uperson){
[color=red]		if(typeof(uperson) != "Person"){
			--> type error
		}[/color]
		MsgBox % person.Name  " entered the car."
	}


fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
Interesting. Perhaps I'll implement strong typing when I get to improve the parameter handling code (currently params are copied straight from the script).
BTW, your examples don't quite follow the current syntax:
class Person
   [color=red]; outside variable declarations not yet suppported[/color]
   [color=red].[/color]constructor(uname="unknown"){
      this.Name := uname
   }
endclass

class Car
   [color=red]method[/color] Enter(Person person){
      MsgBox % person.Name  " entered the car."
   }
endclass
[color=red]method[/color] Enter(uperson){
      if([color=red][[/color]typeof uperson[color=red]][/color] != "Person"){
         ; --> type error
      }
      MsgBox % person.Name  " entered the car."
   }
The reason why I chose to use keywords is to ease parsing of the ambiguous AHK syntax.

fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
Allright, new version up that adds properties and strong typing:
gen := [new Random]
Loop, 3
	msgbox % gen.Number
gen.Min := 1
gen.Max := 10
Loop, 3
	msgbox % gen.Number

class Random
	.constructor
	{
		this.l1 := 0, this.l2 := 2147483647
	}
	property Number
		get
		{
			Random, v, % this.l1, % this.l2
			return v
		}
	endprop
	property Min
		set	v
		{
			if v is number
				return this.l1 := v
		}
		get
		{
			return this.l1
		}
	endprop
	property Max
		set v
		{
			if v is number
				return this.l2 := v
		}
		get
		{
			return this.l2
		}
	endprop
endclass
MsgBox % "2 + 3 = " Add(2, 3)
; MsgBox % Add("in", "valid")

strong Add(num a, num b)
{
	return a + b
}

val1 := [new Value]
val1.val := "Hello"

val2 := [new Value]
val2.val := "World"

val3 := [new Value]
val3.val := "Hello"

msgbox % val1.CompareTo(val2)
msgbox % val1.CompareTo(val3)
msgbox % val1.CompareTo("wewww")

class Value
	property val
		set v
		{
			return this._val := v
		}
		get
		{
			return this._val
		}
	endprop
	method CompareTo(Value o)
	{
		return this._val = o._val
	}
endclass


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Why the "end" keywords? It's not very consistent...

fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007

Why the "end" keywords? It's not very consistent...

Yes. Read this:

The reason why I chose to use keywords is to ease parsing of the ambiguous AHK syntax.

If you know of a better method, tell me.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
I wouldn't say nested braces are ambiguous. So is there no reason other than "ease of parsing"? No doubt you've otherwise done a good job, but the syntax seems alien to me.

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007

No doubt you've otherwise done a good job, but the syntax seems alien to me.

This was the reason why in my "strong typing example" the syntax didn't exactly follow fincs definition.


fincs, in the class area you can interpret any standard Function definition as Method;

class Car

	OpenDoor(){

	}
	
EndClass

Further, what I dont understand is, why you choose "endclass" instead of AHKs bracket syntax? (* Guys how know what classes are shouldnt be afraid of brackets - in case you choosen this for better newbiew readability)


typeof should be a key method - you dont even have to parse any typeof expressions -

if(typeof(obj) = "Car"){

}


--> Just add a plain AHK Method typeof(object) which returns a string to the code and handle your checking code there ;)

fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007

fincs, in the class area you can interpret any standard Function definition as Method

There's no simple way to detect function definitions without having a full-blown AHK parser.
Here would be an example (ignoring leading and trailing whitespace, comments (both kinds) and continuation sections, which are anyway filtered)
^[#_@\w\$]+\(.*\)\s*{?$
False positives:
if(whatever){
myFunc(a, b, c) ; function call, must look ahead to confirm there is no opening brace
False negative:
myFunc(a
,b ,c, d
,e ,f ,g){
As for using brackets, there are ambiguities too:
; brackets or not?
if var = {
if(var){
if Func(whatever) = 3 {
IfInString, var, {
if !var || !var2 {
if var1 + var2 = var3 {
; A possible candidate would be:
; if RegExMatch(line, "i)^if(\s|\().*{$") && !RegExMatch(line, "i)^if\s+[#_@\w\$]+\s*=\s*")

typeof should be a key method - you dont even have to parse any typeof expressions
--> Just add a plain AHK Method typeof(object) which returns a string to the code and handle your checking code there ;)

I've considered it (& will distribute a stdlib file). In fact, it would be this short:
typeof(obj)
{
    return obj.__Type
}
Problem is, if I just embed it in each generated file there will be duplicates. As hinted before, I'm putting this function in a stdlib file in order to allow non-OOP scripts check the type of instances of OOP classes.
What checking code is there to handle? If you mean strong typing, functions are already shimmed.

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007
Long time ago, I worked on a AHK Syntax Parser - <!-- m -->http://de.autohotkey...opic.php?t=3946<!-- m -->

It's really not perfect and code could be improved, but some things are solved - as function definitions with brackets on same or next line.

if(x){

}

-->

i)([\w]+)(?<!If)\((.*?)\)[\n]*{

If I find some time I may update the code (as my ahk skills are growed :-P ) and add some more Methods. - There are still some parsing errors.

Mainproblem here is that the following matches:
aaa     sert(){

}
and it shouldn't. I don't get the negative look behind assertion to work.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006
I like it.

I don't like too verbose syntax tho but I understand your reasons.
How about making some syntax sugars for arrays ? I.E. automatic array making

x := [ 1.. 100 ]  ;  make x.1, ... x.100
for each i in [1..100] ; this can work too
x.y := z;           ;  make  x to be array, no new or whatsover required.

Then, you could add meaning to objects in different context by letting operator specification:
x + ojb 
obj . x

should be replaced with
x + ojb.OperatorPlus()
 obj.ToString() . x

ToString and OperatorXXXX is user defined function ofc but you can also implement some. For instance, you can return class type in ToString() if not implemented. I believe this will not be easy, but hey, thats another way to improve yourself :)

BTW, you could fix your verbose syntax by requiring "function" keyword in front of functions for instance or changing the syntax in any recognizable manner. Since you are createing OOP based on AHK I don't see any problem with it.
Posted Image

fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007

How about making some syntax sugars for arrays [perhaps you meant ranges?] ? I.E. automatic array making

Nice idea, I might even implement it (ranges). Anyway, Lexikos has also expressed interest in implementing {key: value} and [value] array notation.

x.y := z;           ;  make  x to be array, no new or whatsover required.

That can already be done with the default base (link, scroll down to "Default base", Lexikos forgot to tag that section).

Then, you could add meaning to objects in different context by letting operator specification:

I'm afraid this does require built-in support & can't be faked/preprocessed like classes.

BTW, you could fix your verbose syntax by requiring "function" keyword in front of functions for instance or changing the syntax in any recognizable manner. Since you are createing OOP based on AHK I don't see any problem with it.

I'll try implementing this in v2:
class MyClass
{
    property MyProp
    {
        ; etc
    }
    method Whatever
    {
        MsgBox etc
        ; ...
    }
}

EDIT: I've uploaded a new version that contains a fix for a nasty bug.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006

I'm afraid this does require built-in support & can't be faked/preprocessed like classes.

It can be done but not for every scenario possible. Its problem, for instance, when function returns object... On the other hand, if you mark objects you created yourself you can recognize them in expressions and fix them.

Btw, nice update, now it looks much better :)

That can already be done with the default base (link, scroll down to "Default base", Lexikos forgot to tag that section).

I know but it requires set-up.

BTW, is this the answer to nubAHK (or inevitable universe balancing) ?
Perhaps you should make a wiki or something :D

BTW2, it would be easier if you would specify grammar.
Posted Image

fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007

It can be done but not for every scenario possible. Its problem, for instance, when function returns object... On the other hand, if you mark objects you created yourself you can recognize them in expressions and fix them.

That still requires parsing. Current [pseudo-operator] syntax is implemented via RegExReplace.

BTW, is this the answer to nubAHK (or inevitable universe balancing)? Perhaps you should make a wiki or something.

No, but I've been thinking of giving my parsing framework to derRaphael for use in nubAHK. I already have ideas on how to make it extensible, just like der wants :twisted:

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006
LOL

Well anyway, you have all you need for proper parsing (RegExp).
You probably know what is the basic thing in yaml and friends...
Posted Image