Macro in Monkey

Monkey Forums/Monkey Programming/Macro in Monkey

Emil_halim(Posted 2014) [#1]
Hi all,

just i want to ask before thinking to implement it.

does Monkey has a Macro keyword ?

if not what do you think about implementing one.

i have 2 idea ,

1- first using CPP #define directive that will work in cpp compiling.
2- second make it with Preprocesser and work in Monkey stage.

thanks.


Gerry Quinn(Posted 2014) [#2]
I don't doubt that people have toyed with the idea. I could imagine an unofficial pre-processor getting built sometime...

There's no Macro command though, and the pre-processor options are limited. Possibly that's a good choice in terms of usability for all but a hard core of programmers.


nikoniko(Posted 2014) [#3]
Emil_halim wrote:
2- second make it with Preprocesser and work in Monkey stage.


It's more universal.


Emil_halim(Posted 2014) [#4]
ok ,

of cource if i will make any changing to monkey , it will be unofficial monkey version.

i will try implementing Macro in Preprocessor .


dragon(Posted 2014) [#5]
a gcc preprocessor work with every language...
also with java or monkey... or any other

you should run preprocessor before monkey compile...
so something need to change in monkey...


see this here:
If you use the -E option, nothing is done except preprocessing.

http://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html

example:
http://www.network-theory.co.uk/docs/gccintro/gccintro_36.html


Emil_halim(Posted 2014) [#6]
thanks dragon,

I am thinking in first implementing Macro that will work in monkey translator stage.

Also i have an idea , inline some c/c++ asm code within monkey source code itself, so using gcc preprocessor will help at this time.


nikoniko(Posted 2014) [#7]
Emil_halim wrote:
of cource if i will make any changing to monkey , it will be unofficial monkey version.


You may extend transcc(.monkey) or use any other tool to create preprocessor, set its name to transcc and call original transcc (under other name) when preprocessor ends work.


nikoniko(Posted 2014) [#8]
nikoniko wrote:
You may extend transcc(.monkey)


It's not even required. Call first preprocessor (better if it will be a part of MonkeyX distro), then call transcc to build.


Danilo(Posted 2014) [#9]
Would be nice to have in Monkey:
Macro abc ' replaces all occurences of 'abc' with 'x'
   x
End Macro

abc:Integer ' becomes 'x:Integer'

'----------------------------------

Macro DoIt(a,b)
   something(a)
   something(b)
   doSomething(a,b)
End

DoIt(1,2)
DoIt(1,"string")

'----------------------------------

Macro myMacro(_a_) ' '#'-operator within macros joins things
   x#_a_#z
End

myMacro(y) ' becomes 'xyz'


For embedding native code:
'!' operator on line start means native code. It get's inserted without modification.
So we could directly write C++, C#, Java, JavaScript. Depends on the target.
' Desktop/C++ target
!int func(int a) {
!  std::cout << a << std::endl;
!  doSomething(a);
!}

Import
   Function func(a:Int)
Public

func(1)


' JavaScript targets
!alert("alert");

'!' is used in PureBasic and PowerBasic to directly write ASM


Gerry Quinn(Posted 2014) [#10]
Macros could also be used for inlining Monkey code.


Emil_halim(Posted 2014) [#11]
@nikoniko

when i was working in c-- Extension , i was having no source code of c-- so i made c--Ext that translates my new extension stuff to c-- code then c-- made the remain stuff.
so here i have the source code of transcc so it is more easy to extend it, and i see that the best point to do a macro is after preprocessor. i mean in the end of PreProcess$ function.


@Danilo
that's exactly what i wes thinking , also i think in block of c , c++ or asm code with a kewword for each one.
and with asm block i will support heigh level asm , something like this

EAX = 10 -----> mov EAX,10

BTW BCX also uses ! for inlining c/c++ with basic code


@Gerry Quinn

of course that wright.


Emil_halim(Posted 2014) [#12]
Hi all,

I have successfully finished inline block to c/c++.

Example
Function Main:Int()

    Local kiro:Int = 20
     
    Print kiro
    inlineC 
       // Inline c source code
          t_kiro=200;
    endC   
    Print kiro
    Return 0
End


that will print
20
200
as you see i uesd inlineC--endC to send block to c/c++ compiler.
Note Well that the local variable kiro will be t_kiro in c/c++ phase.


Emil_halim(Posted 2014) [#13]
Hi all,

Also added inline symbol "!" to send the line to c/c++ compiler

the Previous Exm

Function Main:Int()

    Local kiro:Int = 20
     
    Print kiro
        

    inlineC 
       // Inline c source code
          t_kiro=200;
    endC
         
    ! // Inline Sym C
    ! bbPrint(String(t_kiro));
    
    Return 0
End


NoteWell tile now we can use inline only in Function Body.


Danilo(Posted 2014) [#14]
Sounds good. :)


Emil_halim(Posted 2014) [#15]
thanks Danilo,

now i can use ! symbol or inlinC in declaration area

Example
!DWORD put( String a ) {
!  bbPrint( a );
!}

inlineC
 // Inline c in declration area
endC

Extern
   Function put:Int(a:String)
Public
 
Function Main:Int()

    Local kiro:Int = 20
     
    Print kiro
       
    inlineC 
       // Inline c source code
          t_kiro=200;
    endC
         
    ! /* Inline Sym C */
    ! bbPrint(String(t_kiro));
    
    put("Monkey Ext is very good")
    
    Return 0
End


i will post the transcc Ext later.


k.o.g.(Posted 2014) [#16]
It would be cool to have a preprocessor variable like:
#transcc_ext



dragon(Posted 2014) [#17]
see how haxe handle this
http://haxe.org/doc/advanced/magic


Danilo(Posted 2014) [#18]
see how haxe handle this
http://haxe.org/doc/advanced/magic

Thanks for the link! Looks much more advanced, and has basic stuff I am wondering about in Monkey X, for example enums, macros, ...


Emil_halim(Posted 2014) [#19]
@Kog
if i got it well, #transcc_ext is a switch to on/of extension features. if so i will do it later.

@dragon
thanks again for your link, when i decided to change Transcc i put some roles to obay,which are
1- changes are done with a very little modification in monkey source code itself.
2- as possible as any changes will work for all targets.
3-try to collect changes and put then in one place and remark it for easy access.

@Danilo
with the monkey extension we can make what we want , for example , implementing Enum feature.
actually implementing it is very easy , the idea is change each term of Enum to a const and let monkey pares it.
started making it yesterday.


Emil_halim(Posted 2014) [#20]
Hi all,

Enum feature done.

Example
Enum
   ONE,TWO,THREE
EndEnum

Function Main:Int()
        
    Print ONE
    Print TWO
    Print THREE
    
    Return 0
End


will print 0 1 2


Nobuyuki(Posted 2014) [#21]
This enum has some problems; it is no different than an auto enumerated const scoped at the parent level. Many people use enums as a namespace... Furthermore, some people deliberately enumerate in different orders, for example to support bitwise flags. Your example doesn't seem to show this as possible.


Emil_halim(Posted 2014) [#22]
could you pleas feed some examples for enums as a namespace , deliberately enumerate in different orders , support bitwise flags.

any way , i have extend Enum to support that
Example
Enum 
   ONE,TWO,THREE
EndEnum

Enum 
   AA,BB=10,CC,PP=60,ZZ
EndEnum

Function Main:Int()
     
    Print ONE
    Print TWO
    Print THREE
    
    Print CC
    Print ZZ
    
    Return 0
End


print that 0 1 2 11 61


Danilo(Posted 2014) [#23]
Does this work?
Enum
   AA,BB=10,CC,PP=60,ZZ
   ENUM_1 = 1  ' restart at 1
   ENUM_2 = CC ' 11
   ENUM_3      ' 12
EndEnum

Enum 20
   ENUM_4 ' will start at 20
   ENUM_5 ' will be 21
End

Class ABC ' enum in class

    Enum 50 Step 5
       ENUM_6 ' will start at 50
       ENUM_7 ' will be 55
       ENUM_8 ' will be 60
    End

End

Enum
   ENUM_10 = 1 << 0
   ENUM_11 = 1 << 1
   ENUM_12 = 1 << 2
   ENUM_13 = 1 << 3
End Enum



Function Main:Int()
    
    Print AA
    Print BB
    Print CC
    Print PP
    Print ZZ
    
    Print ENUM_1
    Print ENUM_2
    Print ENUM_3
    
    Print ENUM_4
    Print ENUM_5
    
    Print ABC.ENUM_6
    Print ABC.ENUM_7
    Print ABC.ENUM_8
    
    Print ENUM_10
    Print ENUM_11
    Print ENUM_12
    Print ENUM_13
    Return 0
End



Nobuyuki(Posted 2014) [#24]
here is enum in class namespace example

Enum Option
  INVALID = -1
  NONE = 0
  A = 1
  B = 2
  C = 4
  D = 8
End Enum

Function Main()
  Print ( Option.B )  ' Prints 2
  Print ( Option.A | Option.B )  'Prints 3

  Local everything:Int = Option.A | Option.B | Option.C | Option.D
  Print ( everything )  'Prints 15

  Local currentOption:Option  'Declares as an Enum type
  currentOption = Option.C
  Print currentOption  'Prints 4

  If HasFlag(everything, Option.D) Then Print "True" Else Print "False"  'Prints True
End Function

Function HasFlag?(value:Int, flag:Int)
  Return (value & flag = flag)
 End Function


scope of Options is in global namespace. Other scopes must call Options.Whatever. Anything that can evaluate to an int constant should be supported, eg: A = "A"[0] should return 65 because it can be statically evaluated at compile time.

VB.NET has some pseudo-methods for Enums similar to how Monkey has pseudo-methods for Strings and Arrays. Enum.HasFlag() for example is a feature of .NET 4.0 and can easily be supported as in the above example.


Emil_halim(Posted 2014) [#25]
Hi all,

this is what done till now.
Example
Enum 
   ONE,TWO,THREE
EndEnum

Enum
   AA,BB=10+4,CC,PP=60,ZZ
   ENUM_1 = 1  ' restart at 1
   ENUM_2 = CC ' 11
   ENUM_3      ' ---------> still not supported
End

Enum 20
   ENUM_4 ' will start at 20
   ENUM_5 ' will be 21
End Enum

Enum 50*10 Step 5*10
       ENUM_6 ' will start at 500
       ENUM_7 ' will be 550
       ENUM_8 ' will be 600
EndEnum

Enum
   ENUM_10 = 1 Shl 0
   ENUM_11 = 1 Shl 1
   ENUM_12 = 1 Shl 2
   ENUM_13 = 1 Shl 3
EndEnum

Enum POINT
   TA,TB,TC
EndEnum

Function Main:Int()

    Print ONE
    Print TWO
    Print THREE
    
    Print AA
    Print BB
    Print CC
    Print PP
    Print ZZ
       
    Print ENUM_1
    Print ENUM_2
    Print ENUM_3
    
    Print ENUM_4
    Print ENUM_5
    
    Print ENUM_6
    Print ENUM_7
    Print ENUM_8
    
    Print ENUM_10
    Print ENUM_11
    Print ENUM_12
    Print ENUM_13
    
    Print POINT_TA   '  _ instead of . for scope stuff 
    Print POINT_TB
    Print POINT_TC
      
    Return 0
End


I will try to support other feature.


k.o.g.(Posted 2014) [#26]
Do you release a pre-alpha Version for testing?


Emil_halim(Posted 2014) [#27]
I will release it as soon as finishing Enum Keyword.

here is the new feature of Enum until now

Enum 
   ONE,TWO,THREE
EndEnum

Enum
   AA,BB=10+4,CC,PP=60,ZZ
   ENUM_1 = 1  ' restart at 1
   ENUM_2 = CC ' 15
   ENUM_3      ' ---------> still not supported
End

Enum 20
   ENUM_4 ' will start at 20
   ENUM_5 ' will be 21
End Enum

Enum 50*10 Step 5*10
       ENUM_6 ' will start at 500
       ENUM_7 ' will be 550
       ENUM_8 ' will be 600
EndEnum

Enum
   ENUM_10 = 1 Shl 0
   ENUM_11 = 1 Shl 1
   ENUM_12 = 1 Shl 2
   ENUM_13 = 1 Shl 3
EndEnum

Class ABC ' enum in class

    Enum 50 Step 5
       ENUM_14 ' will start at 50
       ENUM_15 ' will be 55
       ENUM_16 ' will be 60
    End

End


Enum POINT
   TA,TB,TC
EndEnum

Enum Option
  INVALID = -1
  NONE = 0
  A = 1
  B = 2
  C = 4
  D = 8
End Enum

Function Main:Int()

    Print ONE
    Print TWO
    Print THREE
    
    Print AA
    Print BB
    Print CC
    Print PP
    Print ZZ
       
    Print ENUM_1
    Print ENUM_2
    Print ENUM_3
    
    Print ENUM_4
    Print ENUM_5
    
    Print ENUM_6
    Print ENUM_7
    Print ENUM_8
    
    Print ENUM_10
    Print ENUM_11
    Print ENUM_12
    Print ENUM_13
    
    Print POINT_TA
    Print POINT_TB
    Print POINT_TC
    
    Print ( Option_A | Option_B )  'Prints 3
    Local everything:Int = Option_A | Option_B | Option_C | Option_D
    Print ( everything )  'Prints 15
    
    If HasFlag(everything, Option_D) Then Print "True" Else Print "False"  'Prints True
    
    Print ABC_ENUM_14 ' Enum in class 
           
    Return 0
End

Function HasFlag?(value:Int, flag:Int)
  Return (value & flag = flag)
End Function



Danilo(Posted 2014) [#28]
@Emil_halim:
Using underscore '_' instead dot '.' for named Enums in global space and within classes is not good IMO.

It should be like this:
' Enum in class
    Print ABC.ENUM_14
    Print ABC.ENUM_15
    Print ABC.ENUM_16

' Named Enum in global space
    Print POINT.TA
    Print POINT.TB
    Print POINT.TC

' Named Enum in Class
    Print MyClass.Option.INVALID
    Print MyClass.Option.NONE

Here is a run-able code that shows how generated code could look like:



Nobuyuki(Posted 2014) [#29]
by the way, if it wasn't clear in my earlier post, the primary advantage of declaring a variable to an enum type would be to hint the IDE. It would of course still be an Int, but the compiler could also optimize it based on the highest enum value available to a shorter type (like Short / unsigned char / Int8 / Int16), and more advanced IDE's like Jungle can auto-suggest an enumerated member.


Gerry Quinn(Posted 2014) [#30]
Pretty sure optimisation won't happen - any benefits would generally be insignificant, and Monkey is not about super-optimisation anyway.

[For everything except C++, Monkey is structurally close to the target language - that's why it generates reasonably fast code. And C++ has structures of every kind, including ones that are reasonably easy to translate Monkey into.]

Auto-suggestion, yes. But enums are mostly about giving names to magic numbers. They are mainly a handy alternative to consts when there is a long sequence of different values required.


Nobuyuki(Posted 2014) [#31]
I don't disagree, but namespaces can start to get long with enums, and it probably wouldn't hurt to have just a tiny bit more sugar to go with them. Auto-suggesting a value the moment an enum's data provider is determined would save some typing of the class name and reduce scope confusion for newbies as well.

And on a purely subjective personal preference note...Defining enums more like a class than some sort of static struct would be more in line with some the languages that seem to be the inspiration behind monkey's departure from bmax. C/C++ seem to me to be secondary design inspirations compared to newer languages like c#/vb.net and even java. While in the end they all compile to consts anyway, I'd rather see consistent scoping rules in line with the aforementioned expectation than something resembling a struct or union.


Danilo(Posted 2014) [#32]
@Nobuyuki:
I indeed overlooked that part in your example:
Enum Option
  INVALID = -1
  NONE = 0
  A = 1
  B = 2
  C = 4
  D = 8
End Enum

Function Main()
  ' ...
  Local everything:Int = Option.A | Option.B | Option.C | Option.D
  Print ( everything )  'Prints 15

  Local currentOption:Option  'Declares as an Enum type
  currentOption = Option.C
  Print currentOption  'Prints 4
  '..

I just recognized the first "everything:Int". I see now the second "currentOption:Option" declaration.
Thing is, making Enums a full type is more complicated, because you would also need to add some type checks.
It is the main reason I wrote my examples only to represent Int and Const values.

With a full type, the compiler should also check the values, whenever possible. And a full type would need to be
supported everywhere, for example in Function/Method arguments:
Class MyClass
    Enum Flags
        None
        Dithering
    End Enum

Function Main()

  Local f:MyClass.Flags
  f = MyClass.Flags.Dithering ' OK
  f = 1                       ' OK, same like Dithering
  f = 18                      ' clearly not a valid value for this Enum
  f = x                       ' not check-able most of the time, because Enums are compatible with Int

End

Function LoadBitmap(file:String, f:MyClass.Flags)
    If HasFlag(f, MyClass.Flags.Dithering)
        ' ...
    Else
        ' ...
    Endif
End

I agree, this would be very nice. I just think it could be too much for users to implement,
and Mark Sibly (who knows Monkey best) is silent and didn't say a word yet what he thinks
about enhancing the language itself. There is even more stuff missing in the language,
that other, similar cross-platform-tools (like Haxe), support. See Macros, the original
topic of the thread.
Would be nice to hear something from Mark about it, because it all doesn't make sense
if it does not find its way into Monkey X at the end. ;)

I'm also curious how Mark ticks. Maybe he thinks the core language is already finished?
Maybe he is open minded for new suggestions and improvements?
I would like to know, because that's also very important for the future of the language.
Do we need to do 45 forks, or will he integrate the good stuff into the main distribution, etc..?
Is it worth to invest time in Monkey X? Very much depends on the boss, that's why I'm curious
what he thinks about it. ;)
It is very clear that the users here want to enhance Monkey X to bring it forward...

There is just some stuff missing that is available with all other languages I know, and
I would like to know if it is possible Monkey X gets some of this stuff in the near future, or not.


Gerry Quinn(Posted 2014) [#33]
Valid point about using classes as scope - personally my enums always have a name with an underscore e.g. COLOUR_BLACK which I suppose is a kind of fake scoping.


Emil_halim(Posted 2014) [#34]
Okay , this is progress that done.

Enum 
   ONE,TWO,THREE
EndEnum

Enum
   AA,BB=10+4,CC,PP=60,ZZ
   ENUM_1 = 1  ' restart at 1
   ENUM_2 = CC ' 15
   ENUM_3      ' Err should print 16 
End

Enum 20
   ENUM_4 ' will start at 20
   ENUM_5 ' will be 21
End Enum

Enum 50*10 Step 5*10
       ENUM_6 ' will start at 500
       ENUM_7 ' will be 550
       ENUM_8 ' will be 600
EndEnum

Enum
   ENUM_10 = 1 Shl 0
   ENUM_11 = 1 Shl 1
   ENUM_12 = 1 Shl 2
   ENUM_13 = 1 Shl 3
EndEnum

Class ABC ' enum in class

    Enum 50 Step 5
       ENUM_14 ' will start at 50
       ENUM_15 ' will be 55
       ENUM_16 ' will be 60
    End
 
   Enum DEF 
       ENUM_17  
       ENUM_18 
       ENUM_19 
  End  
End

Enum POINT
   TA,TB,TC
EndEnum

Enum Option
  INVALID = -1
  NONE = 0
  A = 1
  B = 2
  C = 4
  D = 8
End Enum

Function Main:Int()

    Print ONE
    Print TWO
    Print THREE
    
    Print AA
    Print BB
    Print CC
    Print PP
    Print ZZ
       
    Print ENUM_1
    Print ENUM_2
    Print ENUM_3
    
    Print ENUM_4
    Print ENUM_5
    
    Print ENUM_6
    Print ENUM_7
    Print ENUM_8
    
    Print ENUM_10
    Print ENUM_11
    Print ENUM_12
    Print ENUM_13
    
    Print POINT.TA
    Print POINT.TB
    Print POINT.TC
    
    Print ( Option.A | Option.B )  'Prints 3
    Local everything:Int = Option.A | Option.B | Option.C | Option.D
    Print ( everything )  'Prints 15
    
    If HasFlag(everything, Option.D) Then Print "True" Else Print "False"  'Prints True
       
    Print ABC.ENUM_14 ' Enum in class 
    
    Print ABC.ENUM_19 ' Err must be  ABC.DEF.ENUM_19 
    
    Local currentOption:Option  'Declares as an Enum type
   ' currentOption = Option.C   ' Err connot convert from Int to Option 
   ' Print currentOption  'Prints 4
               
    Return 0
End

Function HasFlag?(value:Int, flag:Int)
  Return (value & flag = flag)
End Function



Danilo(Posted 2014) [#35]
Just to make sure this works, too:
Enum Option 50*10 Step 5*10
       ENUM_6 ' will start at 500
       ENUM_7 ' will be 550
       ENUM_8 ' will be 600
EndEnum

So Syntax would be:
Enum [ [Name] [StartValue [Step StepValue]] ]



Emil_halim(Posted 2014) [#36]
done ,
Enum OptionExt 50*10 Step 5*10
       ENUM_6 ' will start at 500
       ENUM_7 ' will be 550
       ENUM_8 ' will be 600
EndEnum

Function Main:Int()
    Print OptionExt.ENUM_8   'print 600
               
    Return 0
End


but still have 3 issues.
==========================
Enum
   AA,BB=10+4,CC,PP=60,ZZ
   ENUM_1 = 1  ' restart at 1
   ENUM_2 = CC ' 15
   ENUM_3      ' Err should print 16   <<<-------------------
End
========================== 
     Print ABC.ENUM_19 ' Err must be  ABC.DEF.ENUM_19 
==========================
     Local currentOption:Option  'Declares as an Enum type
     currentOption = Option.C   ' Err connot convert from Int to Option 



Emil_halim(Posted 2014) [#37]
Hi all,

just started to support float type Enum.
only simple stuff till now.

Example
Enum :Float
    F1,F2,F3   ' 0.0 ,1.0 , 2.0
End 

Function Main:Int()
     Print F1
     Print F2
     Print F3
               
   Return 0
End



Emil_halim(Posted 2014) [#38]
Hi all

while taking a rest of making Enum KeyWord , i created this


?Win32
     Const My_OS:String = "Win32"
?MacOS
     Const My_OS:String = "MacOS"
?Linux
     Const My_OS:String = "Linux"
?

Const My_Sys:String = "My system is "
 
Function Main:Int()

   Print My_Sys + My_OS
   
   Return 0
End


prints that "My system is Win32"


Emil_halim(Posted 2014) [#39]
Hi all ,

also this add
?Win32
     Const My_OS:String = "Win32"
?MacOS
     Const My_OS:String = "MacOS"
?Linux
     Const My_OS:String = "Linux"
?

Const My_Sys:String = "My system is "

?DeskTop
   Const My_target:String = "monkey game for win32,mac,lunix"
?CppTool
   Const My_target:String = "monkey tool"
?Html
   Const My_target:String = "monkey net browser"      
? 

Global my_var : Int = 10
  

Function Main:Int()

   Print My_Sys + My_OS
   
   Print "Target is " + My_target
   
   ?Release
     
   ?Debug
      Print my_var
   ? 
   
   Return 0
End


Here is the first release of MonkeyExt , please backup your old one please.
http://bcxdx.spoilerspace.com/Monkey/Tranc_EXT_02.zip


Emil_halim(Posted 2014) [#40]
Hi all,

I have found a small conflict with my last Ext.
i added "?" as a symbol so monkey toker will pares it as a token , and in box classes there is a function name "Equal?" , when toker pares this name will split it into two tokens "Equal" and "?".

so that i modified "?" to be "??" symbol.

here is the new release of MonkeyExt , included source code , for easy access search for '----Ext---- then you will find my code.

http://bcxdx.spoilerspace.com/Monkey/Tranc_EXT_02a.zip


Nobuyuki(Posted 2014) [#41]
The os module already has this functionality; if you're determining os in preprocessor then you should probably consider using existing preprocessor syntax..


Emil_halim(Posted 2014) [#42]
thanks Nobuyuki for your hint.
i was having no idea about os functions , i will remove mine.