Предоставляет совершенно новый синтаксис, чем с одной стороны предлагает меньше писать руками. С другой усложняет переход из-за отсутствия конвертеров.
Установка
ZINC является альтернативным синтаксисом VJASS и соответственно повторяет его баги и способ установки.
zinc
Из-за синтаксиса несовместимого с VJASS все блоки должны быть обёрнуты в специальную директиву:
//! zinc
// Этот блок будет интерпретирован как ZINC
//! endzinc
import
Немного отличается от VJASS аналога тем, что позволяет явно указать как интерпретировать импортируемый файл:
//! zinc
// Будет интерпретирован как бог на душу положит
//! import "A.j"
// Будет интерпретирован как VJASS
//! import vjass "B.j"
// Будет интерпретирован как ZINC
//! import zinc "C.j"
//! endzinc
Наилучшим способом будет организовать структуру таким образом:
D:/MyMaps/MyAwesomeMap
└── map.w3x
├── main.zn
└── src
├── lib
| ├── libA.zn
| └── libB.zn
└── spell
├── spellA.zn
└── spellB.zn
Нестандартный код карты
//! zinc
//! import "main.zn"
//! endzinc
main.j
//! import "spell/spellA.zn"
//! import "spell/spellB.zn"
spellA.j
//! import "../lib/libA.zn"
spellB.j
//! import "../lib/libB.zn"
Теперь при сохранении карты в редакторе код будет собран из указанных файлов, которые можно просто редактировать и хранить на гитхабе.
Операторы
Приоритет | Ассоциативность | Оператор | Описание | Пример |
---|---|---|---|---|
1 | Левая | () | Оператор скобки | (a+b)*c |
2 | Левая | [] | Доступ к индексу | a[b] |
2 | Левая | () | Вызов функции | a(b) |
3 | Правая | ! | Логическое НЕ | !a |
3 | Правая | - | Математическая смена знака | -a |
4 | Левая | * | Умножение | a*b |
4 | Левая | / | Деление | a/b |
5 | Левая | + | Сложение | a+b |
5 | Левая | - | Вычитание | a-b |
6 | Левая | Меньше | a<b | |
6 | Левая | > | Больше | a>b |
6 | Левая | <= | Меньше или равно | a<=b |
6 | Левая | >= | Больше или равно | a>=b |
7 | Левая | == | Равно | a==b |
7 | Левая | != | Не равно | a!=b |
8 | Левая | && | Логическое И | a&&b |
9 | Левая | || | Логическое ИЛИ | a||b |
10 | Правая | = | Присваивание | a=b |
10 | Правая | *= | Присваивающее умножение | a*=b |
10 | Правая | /= | Присваивающее деление | a/=b |
10 | Правая | += | Присваивающее сложение | a+=b |
10 | Правая | -= | Присваивающее вычитание | a-=b |
11 | Левая | , | Перечисление | a,b |
library
Библиотеки основная структурная единица языка. Код вне библиотек недопустим.
library MyLib {
// Содержимое библиотеки
}
requires
Служит для явного указания зависимости одной библиотеки от другой:
library A requires B, C {}
library B {}
library C {}
При компиляции код библиотек, указанных в requires будет помещён выше исходной библиотеки.
Минутка рукожопости
Если вам лень писать сотни requires и вы решили просто импортировать библиотеки в правильно порядке, то спешу вас разочаровать - они будут отсортированы в в алфавитном порядке.
optional
Указывает компилятору, что отсутствие определённой библиотеки это штатная ситуация и если при компиляции библиотека не будет найдена, то ошибка не будет сгенерирована.
library A requires B, optional C {}
library B {}
onInit
Специально обученная функция, которая будет вызвана перед завершением функции main в war3map.j.
library A {
function onInit(){
// Этот блок будет вызван перед завершением функции main
}
}
Функции
Функции должны быть объявлены в корне библиотеки. В дальнейшем описании функций библиотека будет опущена для краткости.
library A {
function myFunc(){
// Код функции
}
}
Аргументы
Указываются внутри скобок:
function A(integer a, real b) {
// Код функции
}
Возврат значения
Для указания типа возвращаемого значения служит специально обученная стрелка:
function A(integer a, integer b) -> integer {
return a + b;
}
Вызов функции
function A(integer a, integer b) -> integer {
return a + b;
}
function B(){
A(1, A(2, 3));
}
Анонимные функции
Они же лямбды - очень удобная вещь, которая позволяет лишний раз не выдумывать шикарные имена передаваемым функциям:
function A(){
TimerStart(CreateTimer(), 1., false, function(){
// Этот код исполнится по истечению таймера
});
}
В JASS это скомпилится примерно таким образом:
function A_1 takes nothing returns nothing
// Этот код исполнится по истечению таймера
endfunction
function A takes nothing returns nothing
call TimerStart(CreateTimer(), 1., false, function A_1)
endfunction
Переменные
Для различия между глобальными и локальными переменными не определено дополнительного синтаксиса. Всё зависит от места, в котором они объявлены.
Глобальные переменные
Объявляются только в корне библиотеки:
library A {
integer B;
integer C = 2;
}
constant
Для запрета изменения значения в процессе исполнения код используется ключевое слово constant.
library A {
constant integer B = 1;
constant integer C = 2;
}
Переменные, объявленые как constant обязательно должны быть инициализированы при объявлении.
Локальные переменные
Объявляются только в функции до первого действия:
library A {
function B() {
integer C;
integer D = 2;
}
}
Короткая запись
Любые переменные одного типа могут быть объявлены одним выражением:
library A {
integer B, C = 1, D = 2;
function onInit(){
integer E, F = 3;
}
}
Массивы
Для объявления массива используются квадратные скобки:
library A {
integer B[], C = 1, D = 2;
function onInit(){
integer E[], F = 3;
}
}
Присваивание
library A {
integer B, C[];
function onInit(){
integer D[], E;
B = 1;
C[0] = 2;
D[0] = 3;
E = 4;
}
}
Модификаторы доступа
Определяют доступность содержимого библиотеки из других библиотек. По умолчанию все переменные и функции внутри библиотеки, тобишь невозможно вызвать функцию или получить значение переменной одной библиотеки из другой. Чтоб изменить это поведение используется ключевое слово public:
library A {
public integer C = 1;
public function D(){}
public {
integer E = 2;
function F(){};
}
}
library B() {
function onInit(){
C = 3;
D();
E = 3;
F();
}
}
Условия
Настоятельно рекомендую прочитать эту статью, здесь же приведу различия между синтаксисом:
ZINC
if (A) {
// этот блок выполнится, если A истинно
}
JASS
if A then
// этот блок выполнится, если A истинно
endif
ZINC
if (A) {
// этот блок выполнится если A истинно
} else {
// этот блок выполнится если A ложно
}
JASS
if A then
// этот блок выполнится если A истинно
else
// этот блок выполнится если A ложно
endif
ZINC
if (A) {
// этот блок выполнится если A истинно
} else if (B) {
// этот блок выполнится если A ложно и B истинно
} else if (C) {
// этот блок выполнится если A ложно, B ложно и C истинно
} else {
// этот блок выполнится если A ложно, B ложно и C ложно
}
JASS
if A then
// этот блок выполнится если A истинно
elseif B then
// этот блок выполнится если A ложно и B истинно
elseif C then
// этот блок выполнится если A ложно, B ложно и C истинно
else
// этот блок выполнится если A ложно, B ложно и C ложно
endif
Если условие содержит одно выражение, то скобки можно опустить. На этой особенности построен elseif, а так же удобно использовать в функциях подобного рода:
function MaxI(integer a, integer b) -> integer {
if (a > b) return a;
return b;
}
Циклы
Все циклы при компиляции будут превращены в loop.
while
ZINC
while(A){
// Этот блок будет исполняться пока A истинно
}
JASS
loop
exitwhen not A
// Этот блок будет исполняться пока A истинно
endloop
for
ZINC
i = 5;
for (0 < i <= 10){
// Этот блок будет выполняться пока i > 0 и i <= 10
// ...
// В конце итерации цикла произойдёт неявный инкримент i
}
JASS
set i = 5
loop
exitwhen i <= 0 or i > 10 // Этот блок будет выполняться пока i > 0 и i <= 10
// ...
set i = i + 1 // В конце итерации цикла произойдёт неявный инкримент i
endloop
ZINC
i = 5;
for (10 >= i > 0){
// Этот блок будет выполняться пока i > 0 и i <= 10
// ...
// В конце итерации цикла произойдёт неявный декримент i
}
JASS
set i = 5
loop
exitwhen i <= 0 or i > 10 // Этот блок будет выполняться пока i > 0 и i <= 10
// ...
set i = i - 1 // В конце итерации цикла произойдёт неявный декримент i
endloop
Минутка рукожопости
Для цикла for можно использовать только переменную. Хотя синтаксис позволяет использовать элемент массива.
break
Используется для остановки цикла:
ZINC
while(true){
if (!A) break; // Прерываем цикл если A ложно
}
JASS
loop
exitwhen not true
if not A then
exitwhen true // Прерываем цикл если A ложно
endif
endloop