Справочник по языку Monkey

Это руководство описывает синтаксис и общие концепции языка программирования Monkey.

О справочнике

Моноширинным шрифтом выделяются примеры программного кода, например:

Function Main() 
    Print "Hello World!" 
End 

Объяснения синтаксиса языка, как правило, отформатированы следующим образом:

  • Жирным шрифтом выделяются ключевые слова языка. Например: Function соответствует ключевому слову "Function".
  • Курсивом выделяется любой другой синтаксис. Например: Identifier означает любой текст, который допустим для обозначения идентификатора.
  • Все, что обозначено квадратными скобками [] является необязательным. Например: [ Step ] означает необязательный параметр Step.
  • Вертикальная черта | обозначает возможную альтернативу. Например: To | Until означает, что вы можете использовать либо To, либо Until - но не оба оператора одновременно.
  • Многоточие … используется для обозначения повторяющегося кода.
Эти правила не выполняются в случае если это имеет смысл. Так, синтаксис может быть значительно упрощен и дополнен пояснительными комментариями.

Программы и объявления

Программа Monkey состоит из одного или нескольких модулей, каждый из которых является отдельным файлом, состоящим из ряда объявлений.

Объявление связывает "некое" значение с идентификатором. Например, это объявление:

Global x:Int 

Оно указывает, что идентификатор "х" является глобальной переменной типа Int (целое).

Monkey поддерживает следующие виды объявлений:

  • Модули
  • Константы
  • Переменные: локальные, глобальные, поля классов
  • Классы
  • Функции
  • Методы
Сам по себе, модуль представляет собой одиночный файл исходного кода. Имя модуля берется из имени файла. Например, если ваш файл назван "particles.monkey", то модуль будет называться "particles".

Модули могут импортировать другие модули с помощью команды import, которые, в свою очередь, могут импортировать другие модули, и так далее.

Каждый проект Monkey имеет основной модуль, который должен содержать публичную функцию Main, которая не принимает параметров и возвращает целое. Например:

Function Main() 
    Print "That's all folks!" 
End 

Это точка входа в приложение, где начинается его выполнение.

Если вы используете фреймворк mojo, то вам необходимо создать новый класс (который расширяет базовый класс mojo.app) и создать экземпляр этого класса в функции Main. Для получения подробной информации о mojo.app — обратитесь к справочнику по модулям Monkey. В качестве примера, предлагаем вам взглянуть на код ниже:

Import mojo.app 
Import mojo.graphics 
 
Class MyApp Extends App 
    Method OnRender() 
        DrawText "Hello World!",0,0 
    End 
End 
 
Function Main() 
        New MyApp 
End 

Строгий режим интерпретирования кода

По умолчанию, Monkey позволяет опускать определенные моменты при написании кода.

Однако, Monkey также предлагает строгий режим интерпретации кода - "Strict". Этот режим подходит для разработчиков, предпочитающих более строгое написание кода.

Различия между строгим и нестрогим режимами следующие:

  • В не строгом режиме, тип переменной, тип возвращаемый функцией и типы параметров функции могут быть опущены. В этом случае, они, по умолчанию, будут целыми числами (Int). В строгом режиме вы всегда должны указывать тип всех переменных, тип возвращаемый функцией и всех ее параметров.
  • В нестрогом режиме, возвращение значения функцией можно опустить. В этом случае, значение возвращается автоматически и будет равняться соответствующему для возвращаемого типа значению по умолчанию. То есть, False — для булева типа, 0 — для целого числа и чисел с плавающей точкой, "" — для строк, [] — для массивов, и Null — для объектов. В строгом режиме, функция не возвращающая Void, обязательно должна явно возвращать значение с помощью оператора Return.
  • В нестрогом режиме, скобки, окружающие параметры функции, являются необязательными, если функция используется как оператор или может быть вызвана без параметров. В строгом режиме, за каждой функцией должны следовать скобки.
Чтобы начать использовать строгий режим, вы должны поместить директиву Strict в начало исходного кода вашего модуля.

Например:

Strict 
 
Function Main:Int()                     'в строгом режиме, определение типа :Int является обязательным
   Print"Strict mode is...strict!" )  'в строгом режиме, все вызовы функций требуют наличие скобок
   Return 0                             'в строгом режиме, мы обязательно должны вернуть значение
End 

Все последующие примеры в этом руководстве будут представлены без использования директивы Strict.

Комментарии

Вы можете добавить комментарий к строке вашего кода используя ' (апостроф). Все, что будет написано после него, до самого конца строки, будет игнорироваться компилятором.

Чтобы добавить блочный комментарий в код, используйте #rem и #end. Эти директивы должны размещаться в начале новой строки, но перед ними допустимы пробелы. Компилятор будет игнорировать все, написанное между #rem и #end. Блочные комментарии также могут быть вложены друг в друга.

Пример использования комментариев:

Print "Hello World"                 'Это строчный комментарий
 
#Rem 'начало блочного комментария
Print "The sound of silence!" 'содержимое блочного комментария
#End 'конец блочного комментария

Идентификаторы

Идентификаторы должны начинаться с буквы латинского алфавита или с единичного знака подчеркивания. Оставшиеся символы идентификатора могут содержать различные комбинации букв и цифр и/или подчеркиваний.

Идентификаторы чувствительны к регистру (за исключением ключевых слов языка - см. ниже). Например player, Player, PLAYER и PLayER — являются различными идентификаторами. Это позволяет многократно использовать одно имя для различных целей. Например, Actor может относится к классу, а actor - к объекту этого класса.

Некоторые примеры корректных идентификаторов Monkey:

score 
player1 
player_up 
_internal 
helloworld 
HelloWorld 

Ключевые слова и зарезервированные идентификаторы

Следующие идентификаторы являются ключевыми словами, зарезервированными для использования языком программирования Monkey:

Void Strict Public Private Property Bool Int Float String Array 
Object Mod Continue Exit Import Extern New Self Super Try Catch 
Eachin True False Not Extends Abstract Final Select Case Default 
Const Local Global Field Method Function Class And Or Shl Shr 
End If Then Else ElseIf EndIf While Wend Repeat Until Forever  
For To Step Next Return Module Interface Implements Inline Throw 

Ключевые слова нечувствительны к регистру. Например, чтобы объявить функцию, вы можете использовать такие ключевые слова, как function, Function, и даже fUNCTION (не рекомендуется).

Ключевые слова Module, Inline и Array в настоящее время не используются в языке Monkey, но зарезервированы для использования в будущем.

Присваивание имен в Monkey

В стандартных модулях Monkey используются следующие стандарты кодирования:

  • Верхний регистр (например: "ALLCAPS"): Константы
  • Регистр в стиле Pascal (например: "PascalCase"): Глобальные переменные, функции, классы, методы и свойства.
  • Верблюжий регистр (например: "camelCase"): Поля классов, локальные переменные и параметры функций
Конечно, вы можете использовать свой собственный стиль, но для целостности рекомендуется использовать перечисленные выше соглашения для открытых интерфейсов различных модулей, которые будут предназначены для использования сообществом Monkey.

Типы

Monkey является строго типизированным языком программирования, что означает, что все переменные, параметры функций, возвращаемые значения и выражения имеют строго определенный тип, который известен во время компиляции.

Поддерживаются следующие типы:

Булев
Целое
С плавающей точкой
Строка
Массив
Объект

Булев тип

Значения типа Bool — булевы значения, используются для представления результата условных выражений, таких как операторы сравнения, и для представления состояния true/false. Булево значение может быть только True или False.

Синтаксис, используемый для объявления переменных и значений булева типа - Bool. Например:

Local gamePaused:Bool = False 

Булевы значения также генерируются операторами сравнения, например:

If livesLeft<>0 
    doSomething() 
End 

Однако, в некоторых случаях, Monkey автоматически конвертирует не булев тип в булев. Это происходит при проверке выражения операторами If или While, Until (часть цикла Repeat и For), а также при проверке аргументов операторов Not, Or и And. Например:

If livesLeft 
    doSomething() 
End 

Подробную информацию о преобразованиях вы найдете в одноименном подразделе раздела Выражения.

Обратите внимание, что идентификаторы булева типа могут быть также объявлены с помощью символа ?. Обе эти строчки исходного кода действительны и синтаксически корректны:

Local myVariable:Bool = True 
Local myVariable? = True

Целое

Значения типа Int — это целочисленные значения, без дробной части. Диапазон поддерживаемых целочисленных значений зависит от целевой платформы, но составляет не менее 32-х бит. 32-х битный целый тип может представлять диапазон значений от: -2,147,483,648 до 2,147,483,647.

Синтаксис, используемый для объявления значений и переменных целого типа — Int. Например:

Local x:Int = 5 

Литерал целочисленного типа данных — это последовательность цифр без дробной части. Также поддерживаются шестнадцатеричные числа с префиксом $. Например, следующие значения являются корректными целочисленными значениями:

0 
1234 
$3D0DEAD 
$CAFEBABE 

Обратите внимание, что идентификаторы целочисленного типа могут быть также объявлены с помощью символа %. Обе данные строчки исходного кода действительны и синтаксически корректны:

Local myVariable:Int = 1024 
Local myVariable% = 1024

Число с плавающей точкой

Значения типа Float содержат как целую, так и с дробную части. Диапазон поддерживаемых значений с плавающей точкой зависит от целевой платформы, но составляет не менее 32-х бит.

Используемый синтаксис для объявления значений и переменных чисел с плавающей точкой — Float. Например:

Local gravity:Float = 9.81 

Литералом чисел с плавающей точкой является последовательность цифр, которая включает в себя дробную часть, например:

.0 
0.0 
.5 
0.5 
1.0 
1.5 
1.00001 
3.14159265 

Обратите внимание, что идентификаторы с плавающей точкой могут быть также объявлены с помощью символа #. Обе данные строчки исходного кода действительны и синтаксически корректны:

Local myVariable:Float = 3.141516 
Local myVariable# = 3.141516

Строка

Значения типа String используются для отображения последовательности символов, таких как текст. Размер каждого символа в строке зависит от цели, но составляет не менее 8-ми бит.

Для объявления переменных и значений типа строка, используется ключевое слово String. Например:

Local name:String = "John Smith" 

Строки - неизменяемый объект. Создав их однажды их невозможно изменить. Операции, которые модифицируют строку всегда будут возвращать новую строку.

Литерал строки — это последовательность символов, заключенных в кавычки. Строки могут также включать специальные последовательности символов, используемые для отображения непечатных знаков.

Вы можете использовать следующие специальные обозначения в строках:

Экранированная последовательностьКод символа
~q 34 (quotate mark ")
~n 10 (newline)
~r 13 (return)
~t 9 (tab)
~z 0 (null>
~~ 126 (tilde ~)

Несколько примеров строк:

"Hello World" 
"~qHello World~q" 
"~tIndented~n" 

Строки могут быть проиндексированы и разорваны.

Синтаксис для индексации строки: StringExpression [ IndexExpression ]

Индексация (доступ к элементу по индексу) строки возвращает код символа в IndexExpression. Индекс равный нулю — первый символ в строке.

IndexExpression должен быть больше или равен нулю и меньше, чем длина StringExpression, иначе произойдет ошибка.

Несколько примеров индексирования строки:

Print "ABC"[0]              'выведет 65 - код символа "A"
Print "ABC"[1]              'выведет 66 - код символа "B"
Print "Hi~n"[2]             'выведет 10 - код символа "~n"

Синтаксис для разрыва строки: StringExpression[ StartExpression..EndExpression ]

Разрыв строки возвращает новую строку, состоящую из символов внутри StringExpression, начиная с индекса StartExpression и заканчивая индексом EndExpression.

Индексы StartExpression и EndExpression являются необязательными. Если StartExpression опущен, то он по умолчанию будет равен нулю. Если EndExpression опущен, то он по умолчанию будет равен длине строки.

StartExpression и EndExpression также могут быть отрицательными. В этом случае, они относятся к смещению от конца строки.

Несколько примеров разрыва строки:

Print "Hello World"[4..7]   'выведет "o W"
Print "Hello World"[..5]    'выведет "Hello"
Print "Hello World"[5..]    'выведет "World"
Print "Hello World"[..]     'выведет "Hello World"

Строки также поддерживают ряд "псевдо" методов и функций:

Метод/ФункцияОписание
Method Length() Property Возвращает число символов в строке.
Method Compare( str:String ) Возвращает: значение < 0 - если текущая строка меньше, чем str; значение > 0 - если текущая строка больше str; значение равное 0, если строка равна str.
Method Find( subString:String ) Возвращает индекс первого вхождения subString в текущей строке.
Method Find( subString:String, startIndex ) Возвращает индекс первого вхождения subString в текущей строке, начиная с индекса startIndex.
Method FindLast( subString:String ) Возвращает индекс последнего вхождения subString в текущей строке.
Method FindLast( subString:String, startIndex ) Возвращает индекс последнего вхождения subString в текущей строке, начиная с индекса startIndex.
Method Contains( subString:String ) Возвращает true, если текущая строка содержит subString.
Method StartsWith( subString:String ) Возвращает true, если текущая строка начинается с subString.
Method EndsWith( subString:String ) Возвращает true, если текущая строка заканчивается subString.
Method ToLower:String() Возвращает текущую строку, преобразованную в нижний регистр.
Method ToUpper:String() Возвращает текущую строку, преобразованную в верхний регистр.
Method Trim:String() Возвращает текущую строку с удаленными начальными и конечными пробелами.
Method Split:String[]( separator:String ) Возвращает массив строк, полученный путем разделения строки разделителем separator.
Method ToChars:Int[]() Преобразует строку в массив кодов символов.
Method Join:String( pieces:String[] ) Возвращает строку, содержащую все элементы частей, соединенные с текущей строкой.
Function FromChar:String( char ) Возвращает строку единичной длины, состоящую из одного кода символа.
Function FromChars:String( chars:Int[] ) Создает строку из массива кодов символов.

Например:

Print "  Hello World  ~n".Trim()    'выведет "Hello World"
Print "Hello World".ToUpper()       'выведет "HELLO WORLD"

Обратите внимание, что идентификаторы строчного типа могут быть также объявлены с помощью символа $. Обе данные строчки исходного кода действительны и синтаксически корректны:

Local message:String = "Hello world" 
Local message$ = "Hello world" 

Массив

Массив — это линейная последовательность значений, доступ к которым осуществляется по целочисленному индексу.

Каждый массив связан с определенным типом — то есть, типом элемента, который содержится в массиве. В связи с особенностями Monkey, тип элемента массива является статическим. Тип должен быть известен во время компиляции, поэтому он не может быть преобразован во время выполнения.

Синтаксис для объявления переменных и значений типа массив: ElementType []

Например:

Local box:Int[]            'массив целых чисел
Local ratio:Float[]        'массив чисел с плавающей точкой
Local thing:Int[][]        'массив массивов целых чисел

Литерал массива — разделенная запятыми (возможно пустая) последовательность выражений, заключенных в [ ]. Выражения в записи массива должны быть одного типа. Например:

Local box:Int[]=[]                              'пустой массив
Local scores:Int[]=[10,20,30]                   'последовательность, разделенная запятой
Local text:String[]=["Hello","There","World"]   'последовательность, разделенная запятой

Синтаксис доступа к значению массива по индексу: ArrayExpression [ IndexExpression ]. Например:

Local score:Int[]=[10,20,30]    'последовательность, разделенная запятой
Print score[1]                  'выведет "20"

Индексирование (получение значения по индексу) массива генерирует псевдо-переменную типа элемента массива, которая может быть прочитана и записана.

IndexExpression должен быть целочисленным выражением, и быть больше или равен нулю, но меньше, чем длина массива, иначе произойдет ошибка.

Как и строки, массивы также могут быть разорваны. Синтаксис для разделения массива: ArrayExpression [ StartExpression .. EndExpression ].

Эта операция возвращает подмассив ArrayExpression, начиная с индекса StartExpression и заканчивая индексом EndExpression (не включается в результирующий массив).

Индексы StartExpression и EndExpression являются необязательными. Если StartExpression опущен, то он, по умолчанию, будет равен нулю. Если EndExpression опущен, то он, по умолчанию, будет равен длине массива.

StartExpression и EndExpression также могут быть отрицательными. В этом случае, они относятся к смещению от последнего элемента массива.

Пример разделения массива:

Local text:String[]=["Cruel","Hello","World","There"]    'последовательность, разделенная запятой
 
Local helloWorld:=text[1..3]                             'будет содержать ["Hello","World"]

Для массивов также доступны следующие псевдо-методы:

МетодОписание
Method Length() Property Количество элементов в массиве.
Method Resize:Array( newLength ) Копирует элементы текущего массива, начиная с первого, в новый массив длиной newLength, и возвращает его.

Например:

Local text:String[]=["Hello","There","World"]        'последовательность, разделенная запятой
 
Print text.Length                'выведет "3"
 
text=text.Resize2 ) 
 
Print text.Length                'выведет "2"

Объект

Объект — экземпляр класса, который содержит в себе ряд констант, переменных, методов и функций.

Синтаксис объявления значений и переменных типа объект: ClassIdentifier

Например:

Local mine:MyClass = New MyClass 

Подробную информацию об объявлении классов и создании объектов вы найдете в разделе Классы.

Переменные

Переменная — это именованное хранилище, используемое для хранения значений, которые могут изменяться во время выполнения программы.

Все переменные имеют идентификатор, тип, и (необязательно) инициализатор — выражение, задающее переменной первоначальное значение.

Тип переменной может быть объявлен в коде или получен из инициализатора переменной.

Локальные переменные

Локальные переменные — это временные переменные, которые исчезают, при уничтожении локальной области видимости, в которой они были объявлены.

Локальные переменные могут быть объявлены в любой локальной области видимости.

Ниже представлено все, что образует локальную область видимости:

  • Операторы внутри функции или метода
  • Операторы внутри If, Else If или блока If
  • Операторы внутри Case или блока Default
  • Операторы внутри While, Repeat и цикла For.
Синтаксис объявления локальных переменных:

Local Identifier : Type [ = Expression ]

Или...

Local Identifier := Expression

Например:

Local age:Int=10 
Local age:=10 

Глобальные переменные

Глобальные переменные — это переменные, которые существуют до тех пор, пока выполняется программа.

Глобальные переменные могут быть объявлены в области видимости модуля или внутри объявления класса.

Синтаксис объявления глобальных переменных:

Global Identifier : Type [ = Expression ]

Или...

Global Identifier := Expression

Например:

Global isPlayerAlive:Bool = True 

Поля классов

Поля классов — это переменные, которые существуют ровно столько, сколько существует объект, к которому они принадлежат.

Поля классов могут быть объявлены только внутри объявления класса.

Синтаксис объявления поля класса:

Field Identifier : Type [ = Expression ]

Или...

Field Identifier := Expression

Константы

Константа — это значение, вычисляемое при компиляции, и не меняющееся во время выполнения программы.

Константы могут быть объявлены в области видимости модуля, в области видимости класса или в пределах любой локальной области видимости.

Синтаксис объявления констант:

Const Identifier : Type = Expression

Или...

Const Identifier := Expression

Выражения

Выражения — это часть программы, которая выполняет вычисления, совершает логические операции и возвращает результат выполнения методов и функций.

Операции

Синтаксис операцииОписание
New ClassTypeСоздает новый Объект
NullНе инициализированный объект
TrueИстина (логический, булев тип)
FalseЛожь (логический, булев тип)
SelfСсылка на текущий объект класса
SuperОбращение к родительскому классу
LiteralЛитерал
IdentifierИдентификатор
 
. Identifierдоступ к элементу в пределах видимости
( ExpressionSeq )Вызов
[ Expression ]Индексация
 
+Унарный плюс
-Унарный минус
~Побитовое дополнение
NotЛогическое отрицание
 
*Умножение
/Деление
ModДеление по модулю
ShlПобитовый сдвиг влево
ShrПобитовый сдвиг вправо (знаковый)
 
+Сложение
-Вычитание
 
&Побитовое "и"
~Побитовое "исключающее ИЛИ"
 
|Побитовое "или"
 
=Равно
<Меньше, чем
>Больше, чем
<=Меньше, чем или равно
>=Больше, чем или равно
<>Не равно
 
AndЛогическое "и"
 
OrЛогическое "или"

Операторы сгруппированы по приоритету.

Балансировка типов аргумента

При выполнении арифметических операций с двумя переменными (*, /, Mod, +, -) или операций сравнения (=, <, >, ⇐, >=, <>), аргументы будут сбалансированы в соответствии со следующими правилами:

  • Если операнд не строка, не число с плавающей точкой или не целое, то будет сгенерирована ошибка;
  • Иначе, если операнд является строкой, тогда сбалансированный тип является строкой;
  • Иначе, если оператор является числом с плавающей точкой, то сбалансированный тип будет числом с плавающей точкой;
  • В противном случае, сбалансированный тип является целым числом.
В случае арифметических операций, аргументы, при необходимости, неявно преобразуются в сбалансированный тип, точно также, как и результат.

В случае выполнения операций сравнения, аргументы, при необходимости, неявно преобразуются в сбалансированный тип, а результат приводится к логическом (булеву) типу.

Единственная арифметическая операция, которая может быть применена к строкам — это сложение, которое выполнит объединение строк.

Логические операторы

Аргументы логических операторов (And, Or), при необходимости, сначала конвертируются, в булев тип. Соответственно результат также имеет логический тип.

В случае с оператором Or, если результат выражения в левой части является истиной (true), то выражение находящееся в правой части не вычисляется.

Например:

If car<>Null Or GetSpeed()>10 Then... 

В приведенном выше примере, если car не является Null, то выражение справа от Or не вычисляется: то есть функция GetSpeed никогда не будет вызвана.

В случае с оператором And, если результат выражения в левой части является ложью (false), то выражение, находящееся в правой части, не вычисляется.

Например:

If enemies.Count > 0 And HasEnemyInSight() Then ... 

В приведенном выше примере, если значение enemies.Count меньше или равно нулю, то выражение справа от And не вычисляется: то есть функция hasEnemyInSight никогда не будет вызвана.

Битовые операции

При выполнении битовых операций (Shl Shr & | ~), все аргументы, а также результат, при необходимости, приводятся к целочисленному типу прежде, чем операция будет совершена.

Неявные преобразования

Неявные преобразования — это автоматическое преобразование, происходящее при присвоении значения переменной, передаче параметров в функцию, возвращении значения из функции или при балансировке аргументов оператора.

Monkey поддерживает следующие неявные преобразования:

Перобразуемый типПреобразуется вПримечания
Булев типЦелоеРезультат равен 1, если булево значение истинно (true), 0 — если ложно (false)
ЦелоеЧисло с плавающей точкой
ЦелоеСтрока
Число с плавающей точкойЦелоеЗначение преобразуется путем отбрасывания дробной части
Число с плавающей точкойСтрокаПреобразование зависит от целевой платформы
Производный класс объектаИсходный класс объектаПриведение типа

Явные преобразования

Явные преобразования — это преобразования из одного типа в другой, которые могут быть выполнены разработчиком вручную.

Синтаксис для выполнения явного преобразования: TargetType ( Expression )

Например:

Local energyFloat:Float = 120.1000002001 
 
Local energyInt:Int = Int(energyFloat)         'Теперь 120

Вы можете выполнить следующие явные преобразования в Monkey:

Преобразуемый типПреобразуется вПримечания
ЦелоеБулев типРезультатом будет правда (true), если значение больше или меньше 0, иначе ложь (false)
Число с плавающей точкойБулев типРезультатом будет правда (true), если значение больше или меньше 0.0, иначе ложь (false)
МассивБулев типРезультатом будет правда (true), если значение свойства Length больше или меньше 0, иначе ложь (false)
ОбъектБулев типРезультатом будет правда (true), если значение больше или меньше Null, иначе ложь (false)
СтрокаБулев типРезультатом будет правда (true), если значение больше или меньше пустой строки, иначе ложь (false)
СтрокаЦелоеПреобразование зависит от целевой платформы
СтрокаЧисло с плавающей точкойПреобразование зависит от целевой платформы
Базовый класс объектаПроизводный класс объектаРезультатом будет Null, если источник не является подклассом производного класса

В некоторых случаях, Monkey будет автоматически выполнять явное преобразование в значение булева типа. Это будет происходить при вычислениях условий в выражениях If и While; части Until цикла Repeat и For; и при оценке аргументов для операторов Not, Or и And. Это позволит вам использовать сокращенные код, подобный этому: If x Then y без необходимости сравнивать x c 0, "", [] or nulll.

Упаковка и распаковка

Упакованный объект — объект, содержащий в себе одно значение примитивного типа: целое, число с плавающей точкой или строку. Упаковка — процесс помещения значения в объект, распаковка — процесс извлечения значения из объекта. Для удобства упаковки и распаковки значений, в Monkey предусмотрены некоторые простые функции:

  • Целое, число с плавающей точкой или строковое значение будут автоматически преобразованы в новый упакованный объект, если у объекта есть подходящий конструктор: New(Int), New(Float) или New(String).
  • Объект будет автоматически преобразован в целое, число с плавающей точкой или строковое значение, если у этого объекта есть подходящий метод: ToInt:Int(), ToFloat:Float() или ToString:String().
Пример упакованного класса, предназначенного для хранения целочисленного значения:

Class IntBox 
    Field value:Int 
 
    Method Newvalue:Int ) 
        Self.value=value 
    End 
 
    Method ToInt:Int() 
        Return value 
    End 
End 
 
Function Main() 
    Local box:IntBox 
    box=10 
 
    Local t:Int=box 
    Print t 
End 

Операторы

Операторы могут использоваться только внутри метода или функции.

Дополнительно, после оператора, может ставиться символ “;”. Операторы, отделенные друг от друга этим символом, могут размещаться на одной строке.

Оператор If

Оператор If позволяет выполнять блок операторов по условию, в зависимости от результата серии логических выражений.

Если первая серия выражений окажется истинной, вызовется соответствующий блок операторов, и остальные выражения будут проигнорированы.

Если ни одно логическое выражение не окажется истинным, то, при наличии, будет выполнен финальный блок Еlse.

Синтаксис оператора If::

If Expression [ Then ]
     Statements...
ElseIf Expression [ Then ]
     Statements...
Else
     Statements...
EndIf

Количество блоков ElseIf неограниченно, также их может и не быть вовсе. Конечный блок Else также является необязательным.

End или End If могут использоваться вместо EndIf, чтобы закрыть тело оператора If, а Else If может быть использован вместо ElseIf.

Кроме того, также поддерживается однострочная версия оператора If:

If Expression [ Then ] Statement [ Else statement ]

Оператор Select

Оператор Select позволяет выполнять блок операторов в зависимости от ряда сравнений.

Первое выражение, соответствующее входному выражению, выполнит соответствующий блок операторов.

Если ни одно из заданных выражений не подошло, то, при наличии, будет выполнен блок Default.

Синтаксис оператора Select:

Select Expression
Case Expression [ , Expression... ]
     Statements...
Default
     Statements...
End [ Select ]

Возможно любое количество блоков Case, как и полное их отсутствие. Конечный блок Default также является необязательным. Блок Default, при наличии, должен помещаться после всех блоков Case.

Цикл While

Цикл While позволяет многократно выполнять блок операторов, до тех пор, пока логическое выражение является истинным.

Следует учитывать, что цикл While может никогда не выполниться. Это происходит в случаях, когда выражение является ложным на входе в цикл.

Синтаксис цикла While:

While Expression
     Statements...
Wend

Для завершения блока оператора While можно использовать End или End While вместо Wend.

Exit и Continue могут быть использованы внутри цикла While, чтобы, соответственно, досрочно прекратить или продолжить его выполнение.

Цикл Repeat

Как и цикл While, цикл Repeat также позволяет многократно выполнять блок операторов, до тех пор, пока логическое выражение не станет истинным.

Однако, в отличие от цикла While, цикл Repeat гарантированно выполняется хотя бы один раз, поскольку логическое выражение проверяется в конце тела цикла.

Синтаксис цикла Repeat/Until:

Repeat
     Statements...
Until Expression

Или...

Repeat
     Statements...
Forever

Exit и Continue могут быть использованы внутри цикла Repeat, чтобы, соответственно, досрочно прекратить или продолжить его выполнение.

Цикл со счетчиком

Цикл со счетчиком For будет выполнятся до тех пор, пока значение числовой переменной не достигнет условия выхода из цикла.

Переменная счетчика автоматически обновляется при каждой итерации цикла, путем добавления постоянного значения шага цикла (Step).

Синтаксис цикла со счетчиком For:

For [ Local ] IndexVariable = FirstValue To | Until LastValue [ Step StepValue ]
     Statements...
Next

End или End For могут быть использованы вместо Next, чтобы закрыть тело цикла For.

При наличии ключевого слова Local, будет создана новая локальная переменная счетчика, которая будет существовать до завершения цикла. Кроме того, запись IndexVariable должна включать тип переменной. Также, может быть использован знак ":=" вместо "=", чтобы неявно задать тип переменной.

При отсутствии ключевого слова Local, переменная IndexVariable должна быть корректной, существующей переменной.

Использование To или Until определяет, будет ли значение LastValue включено или нет.

Если используется To, цикл завершится, как только переменная счетчика станет больше значения LastValue (или меньше, если шаг StepValue имеет отрицательное значение).

Если используется Until, то цикл завершится как только переменная счетчика будет больше или равна значению LastValue (меньше или равна, при отрицательном значении шага StepValue).

По умолчанию, StepValue равен 1.

Exit и Continue могут быть использованы внутри цикла For, чтобы, соответственно, досрочно прекратить или продолжить его выполнение.

Цикл по коллекции

Совместный цикл For EachIn позволяет перебирать элементы коллекции.

Коллекция может быть массивом, строкой или специально спроектированным объектом.

Синтаксис совместного цикла:

For [ Local ] IndexVariable = EachIn Collection
     Statements...
Next

End или End For могут быть использованы вместо Next.

Наличие ключевого слова Local означает, что будет создана новая локальная переменная объекта, которая будет существовать до завершения цикла. Кроме того, запись IndexVariable должна включать тип переменной. Также, может быть использован знак ":=" вместо "=", чтобы неявно задать тип переменной.

При отсутствии ключевого слова Local, переменная IndexVariable должна быть корректной, существующей переменной.

Если коллекция является массивом, то цикл перебирает каждый элемент массива. Тип переменной цикла должен совпадать с типом массива.

Если коллекция является строкой, то цикл перебирает каждый код символа строки, а тип переменной цикла должен быть целочисленным.

Если коллекция является объектом, она должна предоставить реализацию следующего метода:

Method ObjectEnumerator:Object() 

Объект, возвращаемый этим методом, должен иметь реализацию следующих методов:

Method HasNext:Bool() 
Method NextObject:Object() 

Это позволяет создавать объекты классов типа "коллекция", такие как List и Map, по которым можно перемещаться, используя совместный цикл For EachIn.

Exit и Continue

Exit может быть использован внутри циклов While, Repeat и For, чтобы досрочно прекратить выполнение цикла, прежде чем условия завершения цикла будут выполнены.

Continue может быть использован внутри циклов While, Repeat и For, чтобы принудительно заставить цикл перейти к следующей итерации, пропуская операторы, которые могут остаться в текущем теле цикла.

Оператор присваивания

Оператор присваивания изменяет значение переменной и имеет следующий синтаксис:

VarExpression Operator Expression

Где VarExpression это выражение, определяющее переменную, а Operator является одним из следующих операторов:

=
**=*
/=
Shl=
Shr=
Mod=
+=
-=
&=
~=
|=

Оператор = используется для простого присваивания, в то время, как остальные операторы — для обновления с присваиванием.

Операторы-выражения

Вы можете использовать некоторые выражения, как операторы. К ним относятся:

  • Выражения вызова функции или метода.
  • Выражения New.

Функции

Функция — это автономный блок операторов, который может быть вызван неоднократно из любого места программы. В функцию могут быть переданы параметры, также она может возвращать результат.

Синтаксис объявления функции:

Function Identifier : ReturnType ( Parameters )
     Statements...
End [ Function ]

Например:

Function Eat:Voidamount:Int ) 
    ... 
End 

Parameters — это, разделенная запятыми, последовательность параметров функции.

Identifier : Type [ = InitExpression ]

Или...

Identifier := InitExpression

Наличие InitExpression при объявлении параметра функции означает, что параметр имеет значение по умолчанию и может быть опущен при вызове функции.

Как только вы объявили функцию, она может быть вызвана при помощи следующего синтаксиса:

FunctionIdentifier ( Arguments )

где Arguments — это, разделенная запятыми, последовательность выражений

Например:

Function Sum:Intx:Int,y:Int ) 
    Return x+y 
End 
 
Function Main() 
    Print Sum10,20 ) 
End 

Пример использования параметров по умолчанию:

Function Sumx:Int=0,y:Int=0,z:Int=0 ) 
    Print x+y+z 
End 
 
Function Main() 
    Print Sum()         'то же самое, что вызвать Sum( 0,0,0 )
    Print Sum10,20 )  'то же самое, что вызвать Sum( 10,20,0 )
    Print Sum10,,30 ) 'то же самое, что вызвать Sum( 10,0,30 )
End 

Перегрузка функции

Функции могут быть перегружены. Это означает, что можно многократно использовать одно и тоже имя функции, если каждое из них имеет различные параметры. Методы могут быть перегружены точно так же, как и функции.

Когда вызывается функция, Monkey определяет количество и тип параметров, используемых при вызове и ищет версию, соответствующую перегруженной. Например:

Function Addvalue:Int ) 
End 
 
Function Addvalue:Float ) 
End 
 
Function Addvalue:String ) 
End 
 
Function Main() 
    Add10 )   'вызывается первая версия, поскольку 10 относится к типу Int
    Add10.0 ) 'вызывается вторая версия, поскольку 10.0 относится к типу Float
    Add"10" ) 'вызывается третья версия, поскольку "10" относится к типу String
End 

Количество параметров также может быть использовано, для перегрузки функции. Например:

Function Setx ) 
End 
 
Function Setxy ) 
End 
 
Function Main() 
    Set10 )    'вызывается первая версия
    Set10,20 ) 'вызывается вторая версия, поскольку она имеет два параметра
End 

При определении, какую версию перегруженной функции, нужно использовать, Monkey следует следующей логике:

  • Будет использоваться та перегруженная версия, которая полностью совпадает по числу и типу передаваемых функции параметров. Следует отметить, что если вызов функции включает в себя вариант с использованием значений всех параметров по умолчанию, это не будет считаться точным совпадением.
  • В противном случае, используется перегруженная версия, которую можно вызвать неявным преобразованием аргументов функции.
  • Иначе, выдается сообщение об ошибке. В этом случае, вам понадобиться вручную привести некоторые или все аргументы функции, чтобы получилось точное соответствие.
Например:

Function Addvalue:Int ) 
End 
 
Function Addvalue:String ) 
End 
 
Function Main() 
    Add10 )   'OK, вызывается первая версия
    Add"10" ) 'OK, вызывается вторая версия
    Add10.0 ) 'Ошибка, невозможно определить какую версию функции нужно использовать
End 

Эта ошибка вызвана тем, что параметр функции "10.0" — это значение с плавающей точкой, которое может быть неявно преобразовано в целое число или строку. Поэтому Monkey не может решить, какую версию функции использовать.

Чтобы решить эту проблему, вы должны явно привести параметр к строке или целому числу, чтобы дать понять Monkey, какую версию вы хотите использовать. Например:

    AddInt(10.0) )        'Приведение типа с плавающей точкой к целому числу, вызывается первая версия

Методы

Метод — это функция, принадлежащая классу. Метод имеет неявный доступ ко всем членам своего класса, таким как поля, глобальные переменные, другие методы и функции.

Синтаксис объявления метода аналогичен синтаксису объявления функции:

Method Identifier : ReturnType ( Parameters ) [ Property ]
     Statements...
End [ Method ]

Внутри метода также можно использовать специальные переменные Self и Super:

  • Self может быть использован внутри метода, чтобы получить доступ к объекту связанному с методом.
  • Super может быть использован внутри метода для вызова методов родительского класса.
Необязательное ключевое слово Property используется для объявления метода свойством.

Свойство без параметров, может быть вызвано без скобок. Свойство с одним параметром вызывается простым присвоением. Оно используется, в качестве левой стороны оператора присвоения. В этом случае, выражение, находящееся с правой стороны, присваивается свойству.

В следствии этого, можно создать методы, с поведением полей, но, с возможностью выполнить код в момент обращения к ним. Вы можете использовать перегрузку метода, чтобы обеспечить чтение и/или запись свойств.

Запрещено объявлять свойство с двумя или более параметрами.

Классы

Класс это своего рода "план" создания объектов во время выполнения.

Синтаксис объявления класса:

Class Identifier [ < Parameters > ] [ Extends Class ] [ Implements Interfaces ]
     Declarations...
End [ Class ]

Классы могут содержать поля, методы, константы, глобальные переменные и объявления функций.

Если не задан базовый класс, с помощью Extends, то по умолчанию такой класс наследует класс Object.

Ключевое слово Implements используется для реализации интерфейсов, и должен содержать, разделенный запятыми, список интерфейсов. Для получения подробной информации, обратитесь к разделу Интерфейсы.

Класс является также областью видимости, и любые константы, глобальные переменные и функции внутри класса могут быть доступны за пределами класса, используя оператор доступа ".". Например:

Class C 
   Global T 
End 
 
Function Main() 
    C.T=10 
End 

Как только класс будет объявлен, вы сможете создать объекты этого класса во время выполнения, используя оператор New. Например:

Class MyClass 
    Field x,y,z 
End 
 
Function Main() 
    Local myObject:=New MyClass 
    myObject.x=10 
    myObject.y=20 
    myObject.z=30 
End 

Конструкторы

Конструкторы — это специальные методы, которые вызываются каждый раз, когда объект создается используя оператор New.

Чтобы объявить конструктор, нужно объявить метод класса и назвать его New.

Конструкторы, также, могут принимать параметры и могут быть перегружены.

Чтобы вызвать конструктор класса в конструкторе, используйте специальную переменную Super.

Обобщенные классы

Обобщенные классы позволяют писать код, который относится к разным типам данных.

Обобщенный класс объявляется также, как и обычный класс, только с дополнительным набором параметров типов, заключенным в < и >.

Например:

Class Pointer<T
    Method Setdata:T ) 
        _data=data 
    End 
     
    Method Get:T() 
        Return _data 
    End 
     
    Private 
 
    Field _data:T 
 
End 

Параметрами типов могут быть любые допустимые идентификаторы. Здесь T — параметр типа.

Внутри объявления обобщенного класса, параметры типов могут быть использованы в любом месте, где предполагается тип: например при объявлении переменных и типов возврата функции, при создании новых объектов или массивов.

При использования обобщенного класса, вы должны предоставить типы, которые будут использоваться вместо параметров типов. Могут использоваться любые корректные типы, включая: целое, с плавающей точкой, строка или массив.

Например:

Class Actor 
End 
 
Function Main() 
    Local pointer:Pointer<Actor
    pointer=New Pointer<Actor
    pointer.Set New Actor 
    Local actor:=pointer.Get() 
End 

Синтаксис Pointer<Actor> указывает на экземпляр обобщенного класса Pointer<T>.

Этот класс сам по себе уникален, поэтому каждый раз при использовании класса Pointer<T> с другим типом для T, вы на самом деле создаете новый класс.

Обобщенные классы обычно используются для написания классов-контейнеров, такие как списки, стеки и т.д. Стандартные модули Monkey предоставляют небольшой набор обобщенных классов-контейнеров.

Интерфейсы

Интерфейс похож на класс, за исключением того, что он может содержать только константы и абстрактные методы.

Классы могут реализовывать интерфейс, используя ключевое слово Implements в объявлении класса.

Классы, которые реализуют интерфейс, должны объявить каждый метод, объявленный в интерфейсе.

Интерфейс может использоваться там, где ожидается класс. Например, при объявлении типов переменных, или типов возврата функции. Однако, интерфейс не может использоваться с оператором New.

Интерфейс, также, может расширять существующие интерфейсы, в этом случае все методы всех интерфейсов должны быть объявлены в реализующих их классах.

Интерфейсы не могут быть обобщенными.

Синтаксис объявления интерфейса:

Interface Identifier [ Extends Interfaces ]
     Declarations...
End [ Interface ]

Все методы, объявленные внутри интерфейса, автоматически рассматриваются как абстрактные, и поэтому не имеют тела.

Пример использования интерфейсов:

Interface Moveable 
    Method Move() 
End 
 
Interface Drawable 
    Method Draw() 
End 
 
Class Actor Implements Moveable,Drawable 
    Method Move() 
        Print "Actor.Move()" 
    End 
    Method Draw() 
        Print "Actor.Draw()" 
    End 
End 
 
Function Movemoveable:Moveable ) 
    moveable.Move 
End 
 
Function Drawdrawable:Drawable ) 
    drawable.Draw 
End 
 
Function Main() 
    Local actor:=New Actor 
 
    Move actor 
    Draw actor 
End 

Исключения

Исключения - это специальные объекты, которые могут быть "брошены", чтобы проинформировать программу о необычном или ненормальном поведении.

Размещая код внутри блока "try", вы можете поймать брошенные исключения с помощью соответствующего блока "catch". Например...

Function Main() 
    Try 
        Print "Hello World!" 
        Throw New Throwable 
        Print "Where am I?" 
    Catch ex:Throwable 
        Print "Caught a Throwable!" 
    End 
End 

Запустите этот код с учетом и без учета оператора "throw".

Операторы "Throw" могут находиться в любом месте в вашем приложении, а не только внутри блока "try". Объект выбрасывается в самый последний выполненный блок "try", способный его поймать.

Класс объектов, используемый с "throw" и "catch" должен расширять специальных встроенный класс "Throwable". Сам класс "Throwable" расширяет "Object" и не предоставляет никаких новых методов или полей. Поэтому вы можете расширить "Throwable", чтобы создавать собственные классы исключений с большей функциональностью.

Вы также можете ловить несколько классов объекта-исключения в каждом блоке "try", например:

Class Ex1 Extends Throwable 
End 
 
Class Ex2 Extends Throwable 
End 
 
Function Main() 
    For Local i:=1 To 10 
        Try 
            If (i & 1Throw New Ex1 Else Throw New Ex2 
        Catch ex:Ex1 
            Print "Пойман ex1!" 
        Catch ex:Ex2 
            Print "Пойман ex2!" 
        End 
    Next 
End 

Если блок "try" имеет несколько блоков "catch" и было выброшено исключение, выполняется первый блок "catch", способный обработать исключение. Если подходящего блока "catch" не найдено, исключение передается в следующий иерархии блок "try", и так далее.

Если подходящий для поимки исключения блок "catch" не найден, возникает ошибка выполнения и завершение работы приложения.

Модули

Модуль Monkey соответствует одному исходному файлу Monkey, и обеспечивает именованную область видимости для объявления констант, глобальных переменных, функций и классов. Каждый исходный файл кода на Monkey объявляет модуль, а каждый модуль имеет соответствующий исходный файл.

Название области видимости модуля то же, что и имя файла (без пути к директории и расширения файла), поэтому имена файлов исходного кода на Monkey должны быть допустимыми идентификаторами Monkey.

Настоятельно рекомендуется именовать файл/модуль полностью в нижнем регистре — чтобы предотвратить проблемы с регистрозависимыми/регистронезависимыми файловыми системами и обеспечить согласованность со стандартным набором модулей.

Один модуль может импортировать другой, используя оператор импорта. Все операторы импорта должны находится в верхней части модуля, до каких-либо объявлений. Синтаксис оператора импорта:

Import ModulePath

Где ModulePath описывает местоположение модуля Monkey, который необходимо импортировать. Оно состоит из последовательности идентификаторов, разделенных точками и рассматривается как путь в файловой системе, где точки — разделитель директорий. Последний компонент пути представляет собой либо существующий исходный файл .monkey, либо директорию, содержащую одноименный исходный файл .monkey внутри.

При заданном пути модуля, Monkey будет искать модуль для импорта в следующих местах (и в заданном порядке):

  • Текущая директория — т.е. директория, содержащая импортируемый файл.
  • Директория проекта — т.е. директория, содержащая основной исходный файл. Это тот исходный файл, который передан в транслятор и содержит точку входа Main().
  • Директория модулей — т.е. директория под названием "modules" в дистрибутиве Monkey.
Например, дана следующая директива импорта:

Import myutil.mycolor 

Monkey сначала будет искать файлы myutil/mycolor.monkey и myutil/mycolor/mycolor.monkey в текущей директории.

(Примечание: для удобства модули могут быть представлены либо как единичный файл .monkey, либо как файл .monkey внутри одноименной директории. Иногда удобно, когда модуль состоит из одного файла, но иногда бывает удобнее если модуль имеет свою, отдельную директорию).

Если по одному из путей файл найден, то он импортируется в текущий модуль, и поиск завершается.

Если файл найден по обоим путям, то генерируется сообщение об ошибке.

Если ничего не найдено, поиск продолжается в директории проекта, а в случае отсутствия файлов и там — в директории модулей.

Если модуль нигде не найден, генерируется сообщение об ошибке.

После успешного импорта, импортирующий модуль может получить доступ к любым объявлениям, сделанным в импортируемом модуле, используя имя модуля, как область видимости.

Простой пример импорта:

'----- file1.monkey -----
Import file2                'после этого, file2 может быть использован в качестве области видимости
 
Function Main() 
    Print file2.X        'доступ к глобальной переменной X в модуле file2
 
    file2.Test           'доступ к функции Test в модуле file2
End 
 
'---- file2.monkey ----
Global X:=1 
 
Function Test() 
    Print "file2.Test" 
End 

Для получения доступа к идентификаторам в импортируемых модулях, Monkey позволяет опускать область видимости модуля, до тех пор, пока отсутствуют конфликты между идентификаторами в модулях. Например:

'----- file1.monkey ----
Import file2 
Import file3 
 
Function Main() 
 
    Print X     'OK, доступ к file2.X
    Print Y     'OK, доступ к file3.Y
    Test        'Ошибка! Какой Test? file2.Test или file3.Test?
    file2.Test  'OK, теперь я знаю из какого модуля получить Test
 
End 
 
'----- file2.monkey -----
Global X:=1 
 
Function Test() 
    Print "file2.Test" 
End 
 
'----- file3.monkey -----
Global Y:=2 
 
Function Test() 
    Print "file3.Test" 
End 

По умолчанию, любой импорт, сделанный модулем, автоматически доступен для импортеров этого модуля. Если модуль X импортирует модуль Y, а модуль Y импортирует модуль Z, то фактически получается, что модуль X импортирует модуль Z.

Однако, если импорт объявлен как приватный, то такой импорт не будет доступным. Например:

'----- file1.monkey -----
Import file2 
Function Main() 
 
    Print X  'OK, доступ к file2.X
    Print Y  'OK, доступ к file3.Y
    Print Z  'Ошибка! Не вижу file.Z
 
End 
 
'----- file2.monkey -----
Import file3                'Публичный импорт: когда вы импортируете file2, вы также импортируете file3
 
Private 
Import file4                'Приватный — т.е: только внутренне использование. Только file2 может получить доступ к file4. file1 не имеет доступа к file4
 
Public 
Global X:=1 
 
'----- file3.monkey -----
Global Y:=2 
 
'----- file4.monkey -----
Global Z:=3 

Модули могут быть сохранены в иерархии каталогов и импортированы с использованием "точечного" пути модуля, например:

'----- file1.monkey -----
Import file2 
Import util.file3 
 
Function Main() 
    Print file2.X 
    Print file3.Y 
End 
 
 
'----- util/file2.monkey ----
Global X:=1 
 
'----- util/file3.monkey -----
Global Y:=2 

Отметим, что путь директории (в данном случае — 'util') используется только для определения местонахождения модуля. Имя модуля остается — 'file3', не 'util.file3'.

Директива Alias

Директива Alias позволяет присвоить локальное имя константе, глобальной переменной или классу, объявленному в другом модуле. Это можно использовать, чтобы создать “ярлыки” при конфликтах идентификаторов.

Синтаксис директивы Alias:

Alias Identifier = ModulePath . Identifier

Директива Alias должна размещаться в секции объявления импорта модуля, перед основным кодом. Например:

'----- file1.monkey -----
Import file2 
Import file3 
 
Alias T=file2.T                'Какую "T" использовать
 
Function Main() 
    Print T                   'Выводит "1"
End 
 
'----- file2.monkey -----
Global T:=1 
 
'----- file3.monkey -----
Global T:=2 

Public и Private

Директивы Public и Private используются для управления видимостью последующих объявлений в модуле или классе.

Если директива Public используется в основной части модуля, все последующие объявления будут публичными, и будут видны за пределами текущего модуля.

Если в основной части модуля используется директива Private, все последующие объявления буду приватными, и не будут видны за пределами текущего модуля.

Например:

Private 
Global x,y,z        'Являются приватными для текущего модуля
 
Public 
Global P,Q,R        'Могут использоваться любым модулем

При использовании внутри объявления класса, директивы Public и Private работают аналогично, контролируя видимость последующих объявлений. Например:

Class MyClass 
    Private 
    Field x,y,z        'Не видны за пределами этого модуля
     
    Public 
    Field P,Q,R        'Видны за пределами этого модуля
End 

Примечание: приватные элементы класса являются приватными для всего модуля, а не только для класса. Это значит, что код вне класса, но внутри того же модуля, может получить доступ к приватным элементам класса.

Внешние объявления

Директива Extern используется для подключения кода Monkey к коду, не относящемуся к Monkey. Это позволяет смешивать код Monkey (чтобы быть транслированным на язык целевой платформы) с нативным кодом целевой платформы.

При использовании директивы Extern в основной части модуля, все последующие объявления — глобальные переменные, функции и классы будут рассматриваться как внешний объявления.

Предполагается, что внешние объявления реализуются где-то в нативном коде, и как таковые не могут иметь "тела".

В случае внешних глобальных переменных, это означает, что глобальная переменная не может быть инициализирована — предполагается, что она была инициализирована нативным кодом.

В случае с внешними функциями, функция не может содержать код и должна завершаться директивой End.

В случае внешних классов, любые глобальные переменные или методы объявленные в классе, также не должны иметь "тела".

Внешние объявления однако могут быть присвоены символу "@" в форме строкового литерала. Это нативный символ, используемый транслятором Monkey, когда объявление ссылается на код Monkey.

По умолчанию, внешние объявления являются публичными. Чтобы исключить видимость внешних объявлений за пределами текущего модуля, можно использовать Extern Private.

Некоторые примеры использования Extern:

Extern 
 
Global ActiveDriver:Driver="xyzActiveDriver"  'Нативное имя этой глобальной — xyzActiveDriver
 
Class Driver="xyzDriver"   'Нативное имя этого класса — "xyzDriver".
 
    Method Method1()       'По умолчанию, нативное имя то же, что и у определения — в данном случае Method1.
    Method Method2()       'Нативное имя - Method2
End 
 
Public        'Возвращается к открытым определениям.

Управление памятью

Monkey — язык со сборкой мусора. Управление памятью зависит от языка целевой платформы.

Деструкторы не поддерживаются. Если вам нужен “уничтожаемый” объект, то нужно добавить метод типа “Destroy”.

Сборщик мусора способен автоматически собирать циклические структуры данных, например связанные списки.

В настоящее время, сборщик мусора C++ работает только тогда, когда управление передается операционной системе. В случае с C++ платформами mojo, такими как IOS и GLFW, это происходит после завершения любого On-метода (OnCreate, OnUpdate и т.д.)

Обобщая сказанное, лучший способ использовать сборщик мусора — это игнорировать мусор! Несмотря на то, что такой метод как “обнуление” ссылок на объект широко распространен, он на самом деле требуется не так часто.

Но все же, следует контролировать потребление памяти ваших приложений. Это позволит вам, рано или поздно, исключить любые проблемы с памятью.

Препроцессор

Monkey содержит простой встроенный препроцессор, основанный на синтаксисе оператора Monkey If, который позволяет включать и отключать блоки кода от генерирования и трансляции, в зависимости от определенных условий.

Поддерживаются следующие директивы препроцессора:

#If
#ElseIf
#Else
#End
#Rem
#Print
#Error

Директивы препроцессора должны быть первыми в строчке кода, но им может предшествовать дополнительный пробел.

Директивы #If и #Else If должны сопровождаться постоянным выражением Monkey. Если это выражение истинно, то генерация кода включена, если нет — отключена.

Следующие встроенные константы могут быть использованы в выражениях препроцессора:

КонстантаОписание
HOSTОперационная система хоста, одна из: winnt macos linux
LANGЦелевой язык, один из: js as cs cpp java
TARGETЦелевая система, одна из: ios android winrt glfw html5 flash xna psm
CONFIGЦелевая сборка конфигурации, одна из: debug release
CDОсновная директория приложения
MODPATHПуть до модуля

Директива #Rem, так же как и #If False — безоговорочно запрещает генерацию кода. Обратите внимание, что это позволяет блоку #Rem быть "вложенным".