cJass 1.4.0.2 |
The easiest way to start using the cJass parser is to download and install distribution. Please note, that you will need Jass New Gen Pack for correct installation of cJass. During the installation process, all required changes in NewGen files will be made automatically. All that you need to do after installation is to run World Editor and start getting benefits from using cJass syntax.
As you know, JASS2 scripting language was created by Blizzard Entertainment for usage in Warcraft III. Its syntax looks alo like Turing and is neither short nor laconic. You must use call
keyword for function calls, set
for variable setting and local
to declare local variables. You also have to isolate global variables to stand-alone block:
While using cJass, parser automatically determines the meaning of an expression depending on the context, so we can easily omit all these keywords to reach better code readability:
In JASS2 all local variables have to be declared at the beginning of the function. While using cJass, you can declare local variables anywhere inside the function.
The parser will move all local variable declarations to the beginning of the function. As in JASS2 variables can be initialized inside the declaration, cJass will also move the initialization if the variable is initialized with exact value:
After compilation it will become:
cJass syntax also lets you declare variables of the same type on the same line, separating them by commas. These variables can also be initialized here:
cJass syntax introduces new operators to make the life of programmers easier and to increase code readability.
Increment ++
(increasing by 1) and decrement --
(decreasing by 1) operators are unary (they have only one operand). They can be used alone on the line or be part of complex expression:
which will become:
These operators can be written either in prefix (when operator is before variable) or in postfix (when operator is after variable) notation. While using them alone, it doesn’t really matter, but they will behave differently as part of complex expression. Prefix operator changes the variable and then its new value is passed to the expression, postfix operator passes the value to the expression and then changes the variable.
which will be compiled as the following:
cJass syntax implements different assignment operators, which can help shorten code. For example,
can be shortened using the compound summation operator +=
:
Operator +=
adds the expression to the right to operand on the left. The same principle is used to form other compound operators: -=
, *=
and /=
.
is compiled as:
While using cJass syntax, all logical operators can be written in simplified way. You can either use it, or use default implementation - whatever you favor.
JASS2 syntax is rather verbose and uses block limiting using keywords. cJass introduces ligthweight block declaraions using curly brackets: now you can simply specify block name and surround its contents with curly brackets.
Such notation can be used with all JASS2 blocks (loop
, if
, else
and elseif
) and vJass extension blocks (library
, scope
, struct
, interface
and module
). While using short notation in if
and elseif
blocks, the following then
keyord can be omited:
which in plain jass will be:
Notice: this block syntax isn’t mandatory, so you can easily use default notation.
In cJass syntax, whilenot
loop is introduced as an analog of widely used loop with pre-condition. The way of using this loop is identical to the default one: after whilenot
operator the loop-ending condition is specified:
is same as the following:
There also is the form of this loop, that places the loop-ending condition afther the loop’s body:
will be compiled to:
You can also use do
keyword as a synonim to loop
.
For increased usability and code clarity, cJass syntax implements simplified notation of functions and vJass methods. In general, it looks like
Now let’s see, what all this means. At first, you have to indicate the return value type (in the above example it’s nothing
because the function returns nothing), which is followed by function name and arguments (please note, that the arguments should be enclosed in round braces, if a function takes nothing, these braces can be empty), and in the end goes the function body, enclosed in curly brackets. For example, here is the above code after compilation:
This notation also applies to vJass methods, the parser will determine if the declaration should become function or method.
cJass gives you the ability to freely manipulate line endings in your code. These symbols allow you to split one declaration into maly lines or write more than one command on a single line:
The ;
symbol will be replaced to the linebreak and \
symbol merges the lines.
Defines are one of the key cJass benefits. Macro processing is done completely on code parsing (on map save), which allows you to achieve high code readability and flexibility without its overcomplication.
At first look, you can imagine the processing of defines as a simple replace of macro names with their values (as if you used a Search’n’Replace in your favorite text editor).
Keyword define
is used when defining macros:
hereby FOOTMAN
is macro’s name, which you can use later in your code, and
is the value, to which all references will be replaced. For example,
'hfoo'
will compile to the following:
You can write multiple defines using define
and enclosing the block in curly brackets:
You can use either define
, or #
define
notation - it doesn’t matter.
For those, who prefer classic JASS2 syntax, there is another macro definition style:
Usually, macro names contain only letters, numbers and underscores. However, what should you do if you need to have some kinds of special symbols in the define’s name? In such cases you can use inequality signs:
If you need a multiline define, then simply enclose its body in curly brackets:
Macros can be defined as private inside of scopes, libraries, structs and modules using private
keyword:
In this case private defines will not conflict with other defines with same names in global scope of visibility:
After compilation we get:
If you define a macro with the name which is already used by another macro (this doesn’t apply to private defines in nested elements), cJass will show an error and stop compilation. If you want to change the value of an existing macrodefinition, you should use setdef
directive. To undo macro definitions, you can use the undef
directive, after which the macro will be undefined.
To widen the range of possible macrodefinition usages, defines, which take arguments were implemented. A macro can take arbitary number of arguments, which can be used in the macro’s body similiar to how the function’s arguments are used. The arguments can be of any type? parser does no type checks, so you should call macros with care, always checking the value types.
Attention! As parser doesn’t perform typechecks, all typesafety should be controlled by the coder.
You can define more than one macro with same names as soon as they take different number of arguments: such defines are called overloaded. Depending on the number of arguments passed, parder decides what macro to call.
will be compiled to the following:
Attention! If the group of overloaded defines has the one with no arguments, it should always be followed by empty parenthesis.
Sometimes you need to output one of the macro’s arguments as text (please note: not the argument’s value - if the argument is a variable, its name will be the result). For such cases there is ``
instruction, which represents its argument as string. You can also use concatenation operator ##
, which merges expressions on both sides of it (unlike the previous one, this operator can be used anytime, not only in defines).
which will become:
cJass introduces some predefined macros for usage by coders. All of them are replaced to their values at the compilation stage.
DATE
— returns current date in yyyy.mm.dd format.
TIME
— returns current time in hh:mm:ss format.
COUNTER
— returns integer starting from 0, every use increases this number by 1. Here’s an example of usage:
DEBUG
— returns 1 if "Debug mode" checkbox is checked, else returns 0. Is used in conditional compilation (see 4.1) to add sets of actions, which exist only in debug mode.
FUNCNAME
— returns the name of the function, where it’s used.
WAR3VER
— returns WAR3VER_23
or WAR3VER_24
depending on the position of the version switch in cJass menu. Can be used in conditional compilation blocks (see 4.1) to maintain two map versions: 1.23- and 1.24+ compatible. For example:
All predefined macros return non-string value. To represent them as string, you can use either stringizing operator or formatted output (see 6.2)
In this section there are some examples of macro usage for solving of non-trivial tasks.
The need to do some set of actions when calling native functions pops out sometimes. In such cases people create some wrapper functions and call them instead. Using cJass macrodefinitions, you can easily replace the calls of some function to the call to your own wrapper function, or to a set of actions.
which will be compiled to the following:
Now it’s time for some explanations. To replace the RemoveUnit
function to the set of actions, we simply define a macro with the same name, so all the calls to this function will be replaced to this macro’s contents. Please note that inside of this macro the name of hooked function is written using the concatenation operator. This is done to prevent the parser from trying to replace it to this macro’s contents as it has this name too. To replace the calls to SetUnitPosition
to our wrapper, we simply declare the wrapper function and replace all calls to the native with the calls to our wrapper.
Many programming languages allow you to assign default values to function’s arguments. In such cases these arguments can be easily omitted if you’re ok with their default values. Such behaviour can be emulated in cJass using overloaded macrodefinitions and concatenation operator.
I think, you already know, what you’ll see now:
Preprocessor directives are first to be parsed during map code processing. Because of this, you can use them to do some interesting things.
Sometimes it’s comfortable to keep parts of code (e.g. libraries, systems, spells, etc. which you use often) in external files. To include code from external files there’s include
directive, which should be followed by string with file name you want to include. If files are in the
subfolder or in the map folder, you can write file name without a path to it. Also it’s possible to include files from other folders, but you should write full path to it.
"..\AdicHelper\lib\"
The code within included files can be written using both cJass and vJass syntax.
Attention! Don’t forget about double backslash in file path: \\
Sometimes, things happen that one external file is included to the map several times (for example, by different libraries). In such cases inevitable errors happen because of code duplication, which we’d like to avoid. For such cases, cJass introduces the #
guard
ID
directive, which prevents files with same IDs to be included more than once. ID can be any word, composed from letters, numbers and underscores, but it’s good to use the file name with all extra symbols replaced to underscores. For example in
external file the ID can be "my-system.j"
#
guard
my_system_j
.
Attention! The #
guard
directive has to be the written on the first line of external file.
cJass syntax introduces useful conditional compilation commands. Using them you can include or exclude specified blocks of code during map parsing. Controlling elements of this construct can be values, defines or enums (see 5). Their syntax is the following:
Currently, only ==
and !=
comparison operations are supported.
In such conditional blocks you can write any code with one limitation: they shouldn’t contain identical define declarations:
If you try to save this code, parser will throw the define redeclaration error. If you want to use code, similar to above, you should declare the macrodefinition before conditional translation blocks and set its value in those blocks with setdef
directive:
Condiitonal compilation directives can also be triggered by a state of flag - macrodefinition with a special value.
The #
if
value
directive will work only if the compared macrodefinition has a value of true
or 1. You can use the DEBUG
predefined macro to write code, which is compiled only in debug mode.
Sometimes you need to stop compilation if some requirements are not met. In such cases the #
error
directive will help you. It stops the compilation, showing the defined message. Best used inside of conditional compilation blocks."MESSAGE"
This chapter describes some syntax constructions, that were not mentioned above, although not less important.
Enumeration is a type, that can contain values specified by coder. Integer constants can be declared as enumeration members. E.g.:
declares three named integer constants and sets values to them. Values are assigned atomatically starting from 0, in other words, enumeration is similar to the following:
Enumerations can also be named:
Named enumerations have their own internal counter - value of their elements will start from zero. Using several unnamed enumerations will continue the numeration of their values:
Enumerations also support default JASS2 syntax:
Enumerations can be used in conditional translation blocks:
Or instead of named integer constants as markers for some actions:
The cJass default package includes standard libraries, which can be used in your maps because they will definitely be on target computer if cJass is installed there. You can find them in "lib" subfolder of your "AdicHelper" directory. These files were created specially for ease of coding and some light optimizations. You simply include
the ones you need in your map. All standard included files have "cj_" prefix and ".j" extension.
These libraries contain macrodefinitions, aimed to make JASS2 type usage closer to C++. In the first one, aliases for main types and keywords are defined:
In the second, constructs like new
<
type
>
are defined for main handle types:
You can read the full list by opening "cj_typesEx.j" in any text editor.
There also are versions of these files for usage inside of libraries, where all defines are private so they won’t affect anything outside you library. They have "_priv" suffix in the filename.
These libraries aim for ease usage and slight map optimization on save.
First of them replaces all calls to order conversion functions like OrderId
(
"smart"
)
to corresponding integer values and implements defines like order_smart
for integer values of all existing orders.
The other one performs light optimization when functions and constants from "Blizzard.j" are used in the map. Constants are replaced to their values and many functions are replaced to their analogs from "common.j". Please note, that these optimizations also work for GUI triggers of your map.
By including this file, you gain access to output formatting functions. The templates, used for formatting, are defined by specially formatted string (format string). Arguments, passed to formatting functions, should follow the foemat string in exact order, stated in format string.
In function descriptions format string is declared as string
format
and arguments are ...
These functions can be used without arguments, in this case they will simply use given string as input.
The sprintf
function formats a string and returns it as a result. It’s compiled to a simple statement, not a function call.
The printf
function outputs the formatted string to local player. The output is done using DisplayTimedTextToPlayer
function.
The following function do same things, as their standard analogs, but take a format string and arguments list instead of their default string argument.
The formatting string is a template for arguments substitution. All the characters of this string excluding control sequences are copied to the resulting string without changes. Usually, control sequences start with %
symbol (to output the percent sign, you have to escape it using backslash symbol \%
). Control sequences also contain name of the type of substituted variable. By default, the following types are defined:
Furthermore, the user can define his own markup for any additional argument types. To do this, you have to redefine the cj_sprintf_argTyp_User
macro.
Let’s look into the type definition syntax by the exaple of %
i
type:
Attention! The %
symbol will lead the World Editor to strange behaviour if used in the Custom Script section. To use string formatting functions there, you should use the ^
symbol as a control sequence start marker.
This document was translated from LATEX by HEVEA.