Описание платформы Gide — различия между версиями
(→Подключение внешних модулей) |
(→Формат байт-кода gide) |
||
Строка 177: | Строка 177: | ||
Кроме оператора '''throw''', исключения могут кидаться неуправляемыми модулями. Кроме того, существует механизм, при помощи которого ошибки, возникающие на уровне самой виртуальной машины, передаются в стандартную библиотеку, которая кидает исключение. | Кроме оператора '''throw''', исключения могут кидаться неуправляемыми модулями. Кроме того, существует механизм, при помощи которого ошибки, возникающие на уровне самой виртуальной машины, передаются в стандартную библиотеку, которая кидает исключение. | ||
− | + | Furrealz? That's marveolusly good to know. | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + |
Версия 15:27, 9 марта 2012
Содержание |
Синтаксис языка gide
Синтаксис языка Gide максимально упрощен - с рассчетом на то, что поверх него будут писаться реализации языков более высокого уровня.
Каждая непустая строка исходного кода gide - это некоторая инструкция, записанная в следующей форме:
ключевое_слово аргумент1, аргумент2, ..., аргументN
Некоторые инструкции допустимы только за пределами тела функции, некоторые, наоборот, допустимы только внутри тела функции.
Аргументы для инструкции - это произвольные текстовые строки. Если значение аргумента содержит управляющие символы (пробел, табуляция, перевод строки, запятая, символы # или ") - его необходимо заключить в двойные кавычки. Внутри таких кавычек также допустимы escape-последовательности \r, \n, \t, \" и \\.
ЗАМЕЧАНИЕ: вставка произвольных символов \xNN на данный момент не поддерживается, но запланирована на будущее.
Весь текст от символа # и до конца строки - комментарий, он игнорируется.
Внутри тела функции также возможно вставлять т.н. метки. Метка - это некоторая уникальная в пределах данной функции ссылка на инструкцию. Метка выглядит следующим образом:
имя_метки:
Она может быть записана как на отдельной строке, так и на строке с инструкцией.
If I were a Teenage Mutant Ninja Turtle, now I'd say "Kowbagnua, dude!"
Объявление классов
Для того, чтобы объявить класс, нужно написать следующую инструкцию:
class имя_класса
Имя класса - это произвольная строка. Данная инструкция объявляет класс, в котором еще нет ни одного метода.
Инструкция
inherit имя_класса, имя_родителя
добавляет класс имя_родителя в качестве родительского класса. Она должна быть записана после объявления класса. В этой инструкции, и класс имя_класса, и класс имя_родителя могут быть объявлены во внешнем модуле.
Существует также понятие родителя по-умолчанию. Они могут быть заданы только в неуправляемых модулях. Такие родители добавляются автоматически, если не указаны другие родительские классы.
Объявление глобальных переменных
Для того, чтобы объявить глобальную переменную - т.е. переменную, доступную из любой функции - нужно написать инструкцию
global имя_переменной
В качестве имени переменной, опять же, может выступать любая строка.
Глобальные переменные доступны только в пределах данного модуля. Для получения их значений из других модулей, следует использовать функции.
По-умолчанию все глобальные переменные инициализируются нулем.
Объявление функции
Функция объявляется следующим образом:
function имя_функции, аргумент1, аргумент2, ..., аргументN тело функции end
Имя функции - это произвольная текстовая строка. Если имя имеет вид
имя_класса:имя_метода
, метод имя_метода добавляется в класс имя_класса (этот класс должен быть предварительно объявлен, но не обязательно в текущем модуле). В противном случае, объявляется функция, а не метод.
Аргументы - это формальные параметры функции, они доступны в теле как локальные переменные.
Список аргументов в какой-то мере условен. При вызове функции всегда можно указывать произвольное число параметров, это нигде не проверяется. Если фактических параметров меньше, чем формальных - оставшиеся аргументы будут инициализированы нулем. Если фактических больше - некоторые из них не будут доступны напрямую, однако стандартная библиотека может предоставлять функции, открывающие к ним доступ.
Методы класса могут быть публичными (public), защищенными (protected) или частными (private). Публичные методы можно вызывать без ограничений, защищенные - только из данного класса и его потомков, частные - только из данного класса. Эти проверки делаются во время исполнения.
По-умолчанию, метод является публичным. Для объявления защищенных и частных методов, нужно заменить ключевое слово function в объявлении метода на func_protected и func_private соответственно.
Если метод/функция уже был объявлен ранее, он переобъявляется - т.е. данная реализация перекрывает предыдущую. Вызвать предыдущую реализацию можно при помощи оператора recall (см. ниже).
Функция со специальным именем @@module_init является конструктором модуля; она вызывается в момент загрузки данного модуля. В ней, в частности, можно инициализировать глобальные переменные модуля.
Метод @@init - конструктор класса. Он вызывается в момент создания объекта данного класса. Порядок вызова конструкторов таков: сначала рекурсивно вызываются конструкторы родительских классов в порядке объявления родителей, затем - конструктор данного класса. В конструкторе, в частности, можно инициализировать поля объекта.
Специальные переменные
Существует 6 зарезервированных имен переменных:
- 0 (число ноль) - означает отсутствие объекта;
- @true - указывает на специальный объект "истина". Этот объект не имеет полей и методов; он бывает полезен для написания логических конструкций;
- @false - то же, что и 0;
- @this - внутри функции-метода, указывает на текущий объект; внутри обычной функции равен 0;
- @result - результат последней вызванной функции или оператора access;
- @exception - объект исключения, которое требуется обработать.
Операторы функции
Операторы - это управляющие инструкции, составляющие тело функции.
Поскольку единственный существующий тип переменной - это указатель на объект, значительная часть операторов не требуется. Все операторы реализуются на уровне самих объектов в виде методов.
Существуют следующие операторы:
new переменная, имя_класса, строка
- создает новый объект класса имя_класса и записывает результат в указанную переменную. Если переменная была объявлена ранее - результат записывается в нее; если нет - создается новая локальная переменная (т.е. переменная, доступная только в пределах данной функции). Третий параметр - это некоторые данные для инициализации объекта. Они имеют значение только для некоторых классов в неуправляемых модулях. Кроме того, любой класс может быть инициализирован пустой строкой.
bless переменная, имя_класса
- эквивалент new без последнего параметра.
mov переменная, источник
- копирует в переменную переменная ссылку на существующий объект источник (аналогично, если переменная не была объявлена ранее - создается новая локальная переменная). Важно подчеркнуть, что при этой операции не создается нового объекта; две переменные будут указывать на один и тот же объект.
goto имя_метки
- осуществляет безусловный переход к оператору, помеченному меткой имя_метки.
if переменная, имя_метки
- осуществляет условный переход к оператору имя_метки: если управляющая переменная (первый параметр) имеет отличное от нуля значение, осуществляется переход; в противном случае этот оператор игнорируется и выполнение продолжается со следующей инструкции.
call переменная, имя_функции, аргумент1, ..., аргументN
- если переменная - 0, вызывает функцию имя_функции; в противном случае вызывает метод объекта, на который ссылается переменная. Как уже говорилось ранее, количество аргументов может быть любым вне зависимости от количества формальных параметров. Результат выполнения функции записывается в специальную переменную @result.
- имя_функции может быть задано в форме имя_класса:имя_метода. В этом случае осуществляется вызов метода конкретного класса, а не текущего (имя_класса должно либо совпадать с классом объекта, либо быть его родительским классом). Это позволяет вызывать методы родительских классов, несмотря на перекрытие в дочерних классах.
return переменная
- осуществляет выход из текущей функции с возвратом объекта, на который ссылается переменная. Если выполнение функции доходит до конца, функция возвращает 0.
access переменная, имя_поля
- получает значение поля имя_поля объекта, на который ссылается переменная. Значение записывается в специальную переменную @result. Если указанного поля в классе нет, в @result записывается 0.
mutate переменная, имя_поля, значение
- записывает объект, на который ссылается значение, в поле имя_поля объекта, на который ссылается переменная. Если такого поля ранее не существовало, оно создается.
recall
- вызывает замещенную функцию с теми же параметрами, которые были переданы данной функции; осуществляет выход из текущей функции с результатом, который вернула замещенная функция.
upgrade переменная, имя_класса
- расширяет объект, на который ссылается переменная, до класса имя_класса. Это делается путем вызова конструкторов классов, которые в дереве иерархии находятся между классом переменной и указанным классом. Очевидно, класс объекта должен быть родительским для класса имя_класса. После выполнения данной инструкции, класс объекта станет равным имя_класса, т.е. для него будут доступны все методы этого класса.
use_locals имя_функции
- открывает данной функции доступ к локальным переменным функции имя_функции. Этот оператор может быть указан только в самом начале тела функции и только единожды. имя_функции записывается как при объявлении: для обычной функции - просто ее имя, для метода класса - имя класса и имя метода, разделенные двоеточием. Для того, чтобы локальные переменные реально стали доступны, функция имя_функции должна вызвать текущую функцию специальным образом.
- ПРИМЕЧАНИЕ: такой специальный вызов на данный момент невозможно сделать напрямую. Класс Closure стандартной библиотеки позволяет создать указатель на метод, при вызове которого (через этот указатель) происходит требуемый тип вызова. В будущем планируется добавить оператор вызова ccall, выполняющий эту операцию.
- данная инструкция требуется для реализации замыканий.
Кроме перечисленных, существуют еще операторы для работы с исключениями; они рассмотрены в следующем подразделе.
Обработка исключений
Исключения - это специальный механизм, предназначенный для передачи информации об ошибках. Он заключается в следующем.
Любая функция может бросить исключение. Само исключение - это некоторый объект произвольного класса. Когда такое происходит, виртуальная машина начинает искать ближайший обработчик исключений. Если сама функция, бросившая исключение, может его обработать - исполнение передается соответствующей инструкции. В противном случае, начинается раскрутка стека вызовов до первой функции, которая может обработать исключение. Если ни одна функция этого сделать не может, выполнение программы прекращается, а вызвавшему модулю сообщается о необработанном исключении.
В функции может быть установлено несколько обработчиков исключений, которые формируют стек. Обработчик - это некоторая метка в пределах функции. Когда функции требуется обработать исключение, управление передается оператору, на который ссылается эта метка, а сама эта метка извлекается из стека обработчиков. Другими словами, в функции может быть установлено несколько обработчиков, которые, при необходимости, будут вызываться в порядке, обратном их установке. Если же возникает исключение, а в функции не установлено ни одного обработчика - происходит выход из функции, а исключение передается функции, которая вызвала данную функцию, и т.д.
Для работы с исключением существуют следующие четыре оператора:
throw переменная
- кидает исключение, передав в качестве параметра объект, на который ссылается переменная.
except_push имя_метки
- добавляет метку имя_метки в стек обработчиков исключений для данной функции. Когда возникает исключение, управление передается указанной метке, а объект исключения записывается в специальную переменную @exception.
except_pop
- изымает из стека обработчиков метку, находящуюся на вершине стека.
except_clr
- очищает стек обработчиков исключений для данной функции.
Кроме оператора throw, исключения могут кидаться неуправляемыми модулями. Кроме того, существует механизм, при помощи которого ошибки, возникающие на уровне самой виртуальной машины, передаются в стандартную библиотеку, которая кидает исключение.
Furrealz? That's marveolusly good to know.