HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

AdicHelper - A cJass parser

10-02-2009, 08:35 PM#1
ADOLF
I am proud to present AdicHelper — a cJass to vJass/Jass parser.

What is cJass?
cJass is an addition to Blizzard's JASS2 language, which is fully compatible with the popular vJass syntax. The goal of our team is to grant coders more possibilities to create high-quality and simple code. Core principles of cJass are:
  1. Macro facilities and standard library.
    They spare routine actions, letting you concentrate on implementing your ideas.
  2. Simplified syntax.
    We don't want to start over the argument about the verbosity of syntax, we just let you choose the way you like. Almost all cJass constructs can be written in JASS2-like notation.
  3. Map optimization.
    We keep all cJass additions away from complicating the resulting map's code, so using them won't hurt your map's performance. We are also working on embedded map optimizer.
You can read everything about the syntax in our online manual.

How can I use it?
NewGen WE is required to work comfortably with cJass syntax. You simply download the installer, run it and point to your NewGen folder. All required changes will be made automatically.

AdicHelper comes with an updater app, which will check for new versions and download them if needed.

There are two branches of program: stable, which is tested and generally error-free, but is updated not very often and development, which contains new features as they are created, but can also have errors.

Bugs and ideas
You suddenly encounter any bugs or have interesting ideas about implementing new features or extending standard library? Your reports and suggestions can be posted to this thread or our feedback section.
Files:
AdicHelper 1.4.1.5 — setup file. Contains stable version of the parser itself, updater, manual, standard library, some examples of usage and full source code. The installer includes Project Horus 0.4.6 a full rewrite of Scintilla lexer library, which is responsible for JASS code highlighting in TESH. Also highlights delimited comments. Also includes slightly modified TESH to highlight cJass keywords.
10-02-2009, 09:02 PM#2
Nestharus
Love your tool man : ) +rep. I've been using it for awhile now : O.

Still no method/function overloading tho in either vJASS or cJASS : (, but cJASS has global and private function overloading now, so that's a serious start ^^.
10-02-2009, 11:22 PM#3
midiway
plz, zip the file because there are some places where you can't download exe files
10-03-2009, 02:58 AM#4
Bobo_The_Kodo
Request: Can you make it possible to start variable names with _ and access internal struct members in it's methods without .
xD

Also one line if / while statements without needing braces, and inlined sets if possible while (integer(u = TempGroup.first) != 0)
And having the TESH update highlight break too
10-03-2009, 10:49 AM#5
Van Damm
Here's an archived installer if anyone needs it
Attached Files
File type: 7zcJassSetup.7z (1.1 MB)
10-03-2009, 05:08 PM#6
Troll-Brain
Fine, and all.
Let's ask some questions , bug/lack report :

Why do you remove comments inside war3map.j ?

It doesn't help me, sometimes i'm happy to look the map script, at least it would help the user to find eventual cJass compilation bugs.
I guess your point is to reduce the script size, but leave this part for wc3mapoptimizer, no ?
For me this kind of compression is absolutely negligible against the loss of comments, when i want to read the generated jass2 code :(
Same comment for the empty lines.

At least plz add an option to disable/enable it.

Bug report on AdicHelper v.1.4.0.2 :

TESH :

- the keyword endwhilenot isn't considered as a keyword.

I could use "endloop" but it doesn't really make sense, also i won't leave the end keywords. But if you implement the "end" keyword which work for all blocks (if , loops, function, and so one), it would be great for me, but you probably hate this idea.

Hmm i wonder if TESH can handle that (minimize/display blocks), if not i won't use it.
At least could you update TESH to handle cJass blocks like whilenot/endwhilenot ; define/enddefine plz ?

- the cJass documentation :

Quote:
If you want variable to be initialized where it is declared in code, you should initialize it on next line (see 2.6).
The link to 2.6 is wrong. And why 2.6 btw ?

- The title of the doncumentation is still 1.4.0.0, but maybe currently you didn't made it for 1.4.0.2.

-
Quote:
3.2 Visibility scopes

Macros can be defined as private inside of scopes, libraries, structs and modules using private keyword:
scope test { #define private FOOT = 'HBlm' }

In this case private defines will not conflict with other defines with same names in global scope of visibility:
#define msg = "X" nothing test () { BJDebugMsg("Global = " + msg) } library A { #define private msg = "A" nothing test () { BJDebugMsg("Library A = " + msg) } } scope B { #define private msg = "B" nothing test () { BJDebugMsg("Scope B = " + msg) } }

You forgot that we can't use the same function name several times :)

- the "while" keyword will exist or not ?
TESH highlight it but cJass doesn't handle it.
Hmm, i saw in the end of the doc, you used a define in one of your standard library
Code:
while = whilenot not
, so you won't add it :( ?

- 3.7 Predefined macros

Here is a typo :
Quote:
(see 4.1) to add sets of actions, whixh exist only in
and also in some other places inside the doc.

Now a question about cJass usage.

Imagine i use TimerUtils, but i want to define NewTimer -> CreateTimer , and ReleaseTimer -> CreateTimer.

So the way is to use a not private define for CreateTimer and DestroyTimer, and inside the library TimerUtils i use an undef, or maybe a setdef (natives functions) ?

Keep the good work.
10-03-2009, 06:12 PM#7
PurplePoot
++ and -- are terribly broken.

Collapse JASS:
nothing zomg() {
    integer x = 3;
    integer y = x++ + x++;
    //y should be 8 here. However, it will instead be 6.
    integer z = ++x + ++x;
    //z should be 9 here. It will instead be 10.
}

The list goes on.
10-03-2009, 06:59 PM#8
Nestharus
Quote:
Originally Posted by PurplePoot
++ and -- are terribly broken.

Collapse JASS:
nothing zomg() {
    integer x = 3;
    integer y = x++ + x++;
    //y should be 8 here. However, it will instead be 6.
    integer z = ++x + ++x;
    //z should be 9 here. It will instead be 10.
}

The list goes on.

Then help him out and point it out unless there isn't an actual list and there's only that one thing =P.
10-04-2009, 08:58 AM#9
Van Damm
@PurplePoot: all prefix operations are done before current line and all postfix ones - after the line.
And there is error in your example: "It will instead be 10." it will be 14.

Try this code in C++
Code:
#include <iostream>

void main() {
	int x = 3;
	int y = x++ + x++;
	int z = ++x + ++x;
	std::cout << y << std::endl << z;
} 
It will print 6 and 14 =)

And compare to the output of this code in cJass:
Collapse JASS:
include "cj_print.j"
include "cj_types.j"

library test initializer fx {
    void fx () 
        int x = 3;
        int y = x++ + x++;
        int z = ++x + ++x;

        printf("^i|n^i",y,z)
    
}
It will also print 6 and 14
10-04-2009, 10:45 AM#10
Van Damm
@Troll-Brain:
Quote:
Fine, and all.
Let's ask some questions , bug/lack report :

Why do you remove comments inside war3map.j ?

It doesn't help me, sometimes i'm happy to look the map script, at least it would help the user to find eventual cJass compilation bugs.
I guess your point is to reduce the script size, but leave this part for wc3mapoptimizer, no ?
For me this kind of compression is absolutely negligible against the loss of comments, when i want to read the generated jass2 code :(
Same comment for the empty lines.

At least plz add an option to disable/enable it.
That's for optimization. I'll ask ADOLF but don't think he'll do it.

Quote:
Bug report on AdicHelper v.1.4.0.2 :

TESH :

- the keyword endwhilenot isn't considered as a keyword.

I could use "endloop" but it doesn't really make sense, also i won't leave the end keywords. But if you implement the "end" keyword which work for all blocks (if , loops, function, and so one), it would be great for me, but you probably hate this idea.

Hmm i wonder if TESH can handle that (minimize/display blocks), if not i won't use it.
At least could you update TESH to handle cJass blocks like whilenot/endwhilenot ; define/enddefine plz ?
I'll tell ADOLF about endwhilenot and think myself about implementing fold on define/enddefine.

Quote:
The link to 2.6 is wrong. And why 2.6 btw ?
Fixed. This part was not changed since older versions, now it's different. The parser decides on itself what initialization to leave with the declaration.

Quote:
- The title of the doncumentation is still 1.4.0.0, but maybe currently you didn't made it for 1.4.0.2.
I've updated it. You can now run the updater and your local manual will get updated.

Quote:
You forgot that we can't use the same function name several times :)
Fixed

Quote:
- the "while" keyword will exist or not ?
TESH highlight it but cJass doesn't handle it.
Hmm, i saw in the end of the doc, you used a define in one of your standard library
Code:
while = whilenot not
, so you won't add it :( ?
ADOLF doesn't want to add it to core syntax, but i'll add it to "cj_types.j"

Quote:
- 3.7 Predefined macros

Here is a typo : and also in some other places inside the doc.
Tried to fix =)

Quote:
Now a question about cJass usage.

Imagine i use TimerUtils, but i want to define NewTimer -> CreateTimer , and ReleaseTimer -> CreateTimer.

So the way is to use a not private define for CreateTimer and DestroyTimer, and inside the library TimerUtils i use an undef, or maybe a setdef (natives functions) ?

Keep the good work.
Please repeat your question again, I don't quite understand why you want to define two different functions with the same alias =)
10-04-2009, 11:32 AM#11
Troll-Brain
Code:
library Main

    #define CreateTimer = NewTimer
    #define DestroyTimer = ReleaseTimer


endlibrary

library_once TimerUtils initializer redInit

        #define private CreateTimer = CreateTimer
        #define private DestroyTimer = DestroyTimer

    
//*********************************************************************
//* TimerUtils (Red flavo for 1.23b)
//* ----------
//*
//*  To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//*  To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass)   More scripts: htt://www.wc3campaigns.net
//*
//* For your timer needs:
//*  * Attaching
//*  * Recycling (with double-free protection)
//*
//* set t=NewTimer()      : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t)       : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2)     : Attach value 2 to timer
//* GetTimerData(t)       : Get the timer's value.
//*                         You can assume a timer's value is 0
//*                         after NewTimer.
//*
//* Red flavor: Fastest, method in existence for timer attaching,
//*             only takes an array lookup, GetHandleId and subtraction. 
//*             However, all the code in your map requires extra care
//*             not to forget to call ReleaseTimer. It also requires
//*             to preload a lot of timers at map init, they use
//*             memory and handle ids.
//*
//*             I recommend you run your map in debug mode the first
//* time after adding it, make sure you can see map init messages
//* if nothing appears, all is done, if an error appears, it might
//* suggest you a value with OFFSET, in that case, update that value
//* if it still does not work after updating (rare), try a bigger
//* OFFSET by 1000 for example. (Sounds hard? Then use blue or purple
//* timerutils that are friendlier though not as fast)
//*
//********************************************************************

//================================================================
    globals
        private constant integer OFFSET     = 0x100000
        private constant integer QUANTITY   = 256
        private constant integer ARRAY_SIZE = 8191 //changing this to a higher value would effectively
                                                   //cripple the performance making this thing irrelevant

    endglobals

    //==================================================================================================
    globals
        private integer array data[ARRAY_SIZE]
    endglobals

    //It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
    function SetTimerData takes timer t, integer value returns nothing
        debug if(GetHandleId(t)-OFFSET<0) then
        debug     call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
        debug endif
        set data[GetHandleId(t)-OFFSET]=value
    endfunction

    function GetTimerData takes timer t returns integer
        debug if(GetHandleId(t)-OFFSET<0) then
        debug     call BJDebugMsg("GetTimerData: Wrong handle id, only use GetTimerData on timers created by NewTimer")
        debug endif

        return data[GetHandleId(t)-OFFSET]
    endfunction

    //==========================================================================================
    globals
        private timer array tT
        private integer tN = 0
        private constant integer HELD=0x28829022
        //use a totally random number here, the more improbable someone uses it, the better.
    endglobals

    //==========================================================================================
    function NewTimer takes nothing returns timer
        if (tN==0) then
            //If this happens then the QUANTITY rule has already been broken, try to fix the
            // issue, else fail.
            debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, please increase it for your map, fix your map's timer leaks or switch to blue flavor when applicable")
            set tT[0]=CreateTimer()
            if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
                //all right, couldn't fix it
                call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably switch to the blue flavor or fix timer leaks.")
                return null
            endif
        else
            set tN=tN-1
        endif
        call SetTimerData(tT[tN],0)
     return tT[tN]
    endfunction

    //==========================================================================================
    function ReleaseTimer takes timer t returns nothing
        if(t==null) then
            debug call BJDebugMsg("Warning: attempt to release a null timer")
            return
        endif
        if (tN==8191) then
            debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")

            //stack is full, the map already has much more troubles than the chance of bug
            call DestroyTimer(t)
        else
            call PauseTimer(t)
            if(GetTimerData(t)==HELD) then
                debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
                return
            endif
            call SetTimerData(t,HELD)
            set tT[tN]=t
            set tN=tN+1
        endif    
    endfunction

    private function redInit takes nothing returns nothing
     local integer i=0
     local integer bestoffset=-1

        loop
            exitwhen (i==QUANTITY)
            set tT[i] = CreateTimer()
            if(i==0) then
                set bestoffset=GetHandleId(tT[i])
            endif
            if (GetHandleId(tT[i])-OFFSET>=ARRAY_SIZE) then
                debug call BJDebugMsg("TimerUtils_redInit: Failed a initializing attempt")
                debug call BJDebugMsg("The timer limit is "+I2S(i))
                debug call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low, to change OFFSET to "+I2S(bestoffset) )
                exitwhen true
            endif
            if (GetHandleId(tT[i])-OFFSET>=0)  then
                set i=i+1
            endif
        endloop

        set tN=i
    endfunction

endlibrary

So the idea is to use the native CreateTimer() and DestroyTimer(), but in fact it will call NewTimer(), ReleaseTimer(), ofc it mustn't be the case in the library TimerUtils, and yes ofc i still need to manage the order of libraries.

If you are wondering why a want a such thing, it's because for me it's neat.
I don't like the import of a common.j for tesh.
Anyway it would be for a personal use.

An other thing :

Collapse JASS:
function test takes integer i returns integer
    return i--
endfunction

Collapse JASS:
function test takes integer i returns integer
local integer cj_v666_r
set cj_v666_r=i
set i=i-1
return cj_v666_r
endfunction

Wouldn't be better if you use globals instead ?
10-04-2009, 02:14 PM#12
ADOLF
Quote:
Wouldn't be better if you use globals instead ?
No, then there will be errors in recursive functions.
10-04-2009, 02:23 PM#13
Troll-Brain
Hmm you are probably right, but could you post a concrete example plz ?
For me as long as you set it just before the decrement, nothing bad would happen.

I've already said it, but plz give an option to not remove comments / empty lines of the map script.
Currently, for me it's the only bad thing with cJass.
10-04-2009, 05:05 PM#14
PurplePoot
Quote:
Originally Posted by Van Damm
Try this code in C++

It will print 6 and 14 =)
No, it will be 10. not 14. 5 + 5 = 10.

In other news, I'm surprised at how C++ handles this (I was assuming it would be similar to the way Java handles it) as that is totally different from what the symbols actually mean (++x generally means increase x by 1 then return, while x++ means return then increase x by 1).

C++'s stupidity strikes again I guess.
10-04-2009, 05:17 PM#15
Van Damm
Quote:
No, it will be 10. not 14. 5 + 5 = 10.
I meant C++, and it's 14 there.

And why should it be 10? If consider your logic, then you're wrong again:
Collapse JASS:
nothing zomg() {
    integer x = 3;
    integer y = x++ /* returns 3, sets x to 4 */ + x++ /* retruns 4, sets x to 5 */;
    // so y should be 3+4 = 7, not 8
    integer z = ++x /* sets x to 6, returns 6 */ + ++x /* sets x to 7, returns 7 */;
    // so z should be 6 + 7 = 13, not 9 or 10
}