ТОМ2: функции

Материал из IFВики
Перейти к навигации Перейти к поиску

Назначение

Функции используются в командной строке и в коде игры. В отличие от других языков, функции ТОМа не имеют имён и подбираются исключительно по аргументам.

Пример вызова фукции:

Дай мяч Маше

Строка кода может содержать несколько функций, вызываемых последовательно. При этом результат одной функции может являться аргументом для другой функции.

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

Синтаксис

fn_type ( arg_list ) { code }

Где:

  • fn_type - ключевое слово, определяющее тип функции: expression (выражение), action (действие), fact (факт);
  • arg_list - список аргументов;
  • code - код тела функции, разделённый на секции.

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

arg_list

Синтаксис:

arg_type [arg_name] [#arg_key] [, arg_type [arg_name] [#arg_key]] ...

Аргументы в списке разделяются запятой или точкой с запятой.

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

arg_type

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

  • Тип значения: bool, string, number, course, spcvalue, object, attribute, class, location, word, preposition, and-list, or-list.
  • Класс значения. Например, "предмет", "существо" и т.п.
  • Имя значения. Для значений, имеющих уникальные имена, в качестве типа можно указывать имя конкретного значения - имена объектов, локаций и т.д.
  • Произвольный литерал - должен в точности совпасть со словом, введенным игроком. Пример: "трах-тибидох"

arg_name

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

Если имя переменной не указано, значение в функцию не передаётся, но по-прежнему влияет на подбор функций.

arg_key

Ключ, которому должно соответствовать значение аргумента.

Пример: #ВпЕч - значение должно находиться в винительном падеже единственного числа.

В состав ключа могут входить шаблоны '!' и '*'.

  • * - подходит любое свойство ключа;
  •  ! - в ключе не должно быть указанного свойства.

Пример: #*п!е - у значения должен быть любой падеж, и не должно быть отрицания.

Если ключ не указан, проверка значения на соответствие ключу не проводится.

Типы функций

Существует три типа функций – выражения, факты, действия.

Строка кода или команды в ТОМе обрабатывается в 2 этапа:

  1. Парсинг
  2. Выполнение строки

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

Ели строка однозначно разобрана, она выполняется. Выполняется строка только один раз.

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

Зачем нужно деление функций на три типа:

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

Функции типа expression (выражение)

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

Выражения могут входить в состав других сложных выражений, фактов или действий.

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

Примеры выражений:

цвет стен
количество людей в комнате
некто, взявший 3 рубля
2 + 2
X + 3

Пример функции выражения:

expression(attribute Atr, object Ob) 
{ == parsing ==
  if :Ob.key != :Atr.key then fail, "несогласовано"
  Ok
  == execute ==
  if :Ob.:Atr then return :Ob
  fail, "тут такого нет"
}

Функции типа action (действие)

Действия изменяют состояние игры.

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

На этапе парсинга определяется необходимое действие и подготавливаются его аргументы.

Выполнение действий происходит после однозначного разбора строки.

Примеры действий:

покрась стены в зелёный цвет
возьми 3 рубля

Пример функции действия:

action(иди#Пф, location напр#Ап)
{ == check ==
  if loc = напр then fail, "ты уже здесь"
  if нельзя_пройти loc :напр then fail, "туда нет прохода"
  Ok
  == execute ==
  goto :напр
}

Функции типа fact (факт)

Факты применяются в качестве условий или вопросов, а так же как утверждения:

Если цвет стен зеленый, то … // условие
Цвет стен зеленый? // вопрос
Цвет стен зеленый. // утверждение

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

На этапе парсинга строки происходит проверка факта. Результат проверки - всегда логическое значение. Для условий результат проверки влияет на дальнейшее выполнение условной конструкции, для вопросов результат проверки является финальным результатом строки, для утверждений результат не важен.

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

Примеры фактов:

Цвет стен зеленый
в комнате 5 человек
X = 3

Пример функции факта:

fact(нельзя_пройти, локация, локация)
{ == check ==
  yes //по умолчанию никуда нельзя пройти
}

Секции в функциях

Код функции делится на секции. Каждая секция имеет своё имя и выполняется на определённом этапе парсинга.

Начало секции обозначается знаками ==, после которых идёт имя секции.

Пример:

== parsing ==
... код секции ...

Код, размещенный перед первой секцией, является общим и выполняется всегда.

Пример:

action(дай#Пф, Маша#Дп, мяч#Вп)
{ ...общий код...
  ==parsing==
  ...код парсинга...
  ==check==
  ...код проверки...
  ==execute==
  ...код выполнения...
}

Секции в выражениях

В выражениях используются секции parsing (парсинг) и execute (выполнение).

Секция parsing (парсинг) в выражениях

Эта секция вызывается на этапе синтаксического анализа строки кода или командной строки. Здесь нужно проверить синтаксическую правильность переданных аргументов, например то что прилагательное стоит перед существительным и согласуется с ним по роду, числу, падежу и одушевлённости.

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

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

Проверка позиций аргументов

описать!

Секция execute (выполнение) в выражениях

Секция вычисляет значение выражения.

В выражениях эта cекция исполняется на этапе парсинга, из чего следует:

  1. выполнение этой секции может происходить многократно;
  2. результат выражения может быть вариантным;
  3. в этой секции нельзя менять состояния объектов и переменных (за исключением переменных самой функции);
  4. результат выражения влияет на дальнейший парсинг команды.

Пример:

выражение (среднее, число А, число Б)
{
  ==выполнение==
  (А + Б)/2
}

В данном примере функция вычисляет среднее значение двух чисел.

Обращаться к функции из кода можно следующим образом. Пример:

var X = среднее 4 5;
var A = 2
var Б = 7
%{среднее А Б} //переменные А и Б должны содержать числа

Секции в фактах

В фактах используются секции parsing (парсинг), check (проверка), и execute (выполнение).

Секция parsing (парсинг) в фактах

Работает аналогично секции parsing в выражениях.

Секция check (проверка) в фактах

Эта секция проверяет факт на его соответствие действительности и возвращает логическое да или нет.

Секция исполняется на этапе парсинга, из чего следует:

  1. выполнение этой секции может происходить многократно;
  2. в этой секции нельзя менять состояния объектов и переменных (за исключением переменных самой функции);

Именно эта секция позволяет использовать факты в условных конструкциях и вопросах.

Пример:

факт (предмет А, весит, число Б, кг)
{
  ==проверка==
  А.вес = Б?
  ==выполнение==
  ... код выполнения ...
}

Пример условия:

если камень весит 100 кг то ...

Пример вопроса:

камень весит 100 кг?

Секция execute (выполнение) в фактах

В факте секция execute (выполнение) выполняется после однозначного разбора строки кода или команды.

Эта секция должна сделать так, чтобы факт стал истинным.

Пример:

факт (предмет А, весит, число Б, кг)
{
  ==проверка==
  А.вес = Б?
  ==выполнение==
  А.вес = Б
}

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

Пример:

камень весит 100 кг. //да будет так

В связи с этим, секция execute (выполнение) для фактов работает только в режиме 'вне игры' (см. раздел Режимы работы ТОМ), иначе игрок мог бы очень сильно изменить игровой мир.

Секции в действиях

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

Секция parsing (парсинг) в действиях

Работает аналогично секции parsing в выражениях.

Секция check (проверка) в действиях

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

Секция исполняется на этапе парсинга, из чего следует:

  1. выполнение этой секции может происходить многократно;
  2. в этой секции нельзя менять состояния объектов и переменных (за исключением переменных самой функции);

Если действие невозможно, секция должна вернуть ошибку.

Секция execute (выполнение) в действиях

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

Сообщения об ошибках выполнения функций

описать!