Этот раздел описывает лексику, синтаксис и семантику Lua.
Идентификатором в Lua может быть любая строка символов, цифр и символов подчеркивания, не начинающаяся цифрой. Это совпадает с определением идентификаторов в большинстве языков, за исключением того, что определение символа зависит от текущего региона. Любой символ, который считается алфавитным в текущем языке, может использоваться в идентификаторе. То есть, алфавитные символы берутся из настроек текущей системной локали. Замечу, что для лучшей переносимости программ и их применения в разных регионах лучше все же ограничиться латинским алфавитом, цифрами и символом подчеркивания: они применимы везде. Следующие слова зарезервированы, и не могут использоваться как идентификаторы:
and break do else elseif return end for function if in then local nil not or repeat until while
Lua представляет собой язык, чувствительный к регистру символов: and
является зарезервированным словом, но And и AND (если
региональный язык разрешает) не одно и то же. Значит, приведенные варианты уже
можно использовать как имена переменных. Кроме того, идентификаторы,
начинающиеся с символа подчеркивания, сопровождаемого прописными буквами (типа
_INPUT
) зарезервированы для внутренних переменных. Их не стоит
применять в своих программах.
Следующие строки обозначают другие лексемы (tokens):
~= <= >= < > == = + - * ( ) { } [ ] ; , . .. ... /
Литеральные строки могут быть
разграничены одиночными или двойными кавычками, и могут содержать C-подобные
управляющие последовательности: \a
(bell), \b
(backspace), \f
(form feed), \n
(newline),
\r
(carriage return), \t
(horizontal tab),
\v
(vertical tab), \\
(backslash), \"
(double quote), \'
(single quote), и \
newline
(то есть, наклонная черта влево, сопровождаемая реальным newline, который
приводит к переводу строки). Символ в строке может также быть определен числовым
значением, через управляющую последовательность \
ddd, где
ddd последовательность до трех десятичных цифр. Строки в Lua
могут содержать любое 8-разрядное значение, включая вложенные нули, которые
могут быть определены как \000
.
Литеральные строки могут также быть разграничены парами [[
...
]]
. Литералы в этой форме в скобках могут занимать по несколько
строк, содержать вложенные пары скобок [[
... ]]
и не
интерпретировать управляющие последовательности. Эта форма особенно удобна для
записи строк, которые содержат части программы или другие цитируемые строки. Как
пример, в системе использующей ASCII-кодировку, следующие три литерала
эквивалентны:
1) "alo\n123\"" 2) '\97lo\10\04923"' 3) [[alo 123"]]
Комментарии начинаются с двойного тире
(--
) и выполняются до конца строки. Кроме того, первая строка
составной части всегда пропущена, если начинается с символа #
. Это
средство позволяет использование Lua как интерпретатора скриптов в
Unix-системах.
Числовые константы могут быть написаны с факультативной целой частью и тоже факультативным дробной частями. Допустимо применение экспоненциальной формы запитси. Примеры имеющих силу числовых констант:
3 3.0 3.1416 314.16e-2 0.31416E1
Lua обеспечивает некоторые автоматические преобразования между значениями во
время выполнения. Любая арифметическая операция, примененная к строке, пробует
преобразовывать эту строку в соответствующее число, следуя обычным правилам.
Наоборот, всякий раз, когда используется число, а ожидается строка, это число
будет преобразовано в строку в приемлемом формате. Формат выбран так, чтобы
преобразование из числа в строку было таким, чтобы обратное преобразование из
строки в число было точным. Таким образом, преобразование не
обязательно генерирует хороший текст для некоторых чисел. Для полного управления
тем, как числа будут преобразованы в строки, используйте функцию
format
(подробности в разделе 6.2).
Функции в Lua могут возвращать много значений. Потому, что не имеется никаких объявлений типа когда функция вызвана, система не знает, сколько значений вернется, или сколько параметры требуется. Следовательно, иногда список значений должен быть откорректирован во время выполнения к данной длине. Если имеется большее количество значений, чем необходимы, то лишние значения отбрасываются. Если имеется меньшее количество значений, чем необходимы, то список расширен добавлением потребного количества nil. Эта корректировка происходит в многократных назначениях (подробности в разделе 4.4.2) и в обращениях к функции (подробности в разделе 4.5.8).
Lua поддерживает почти стандартный набор инструкций, подобных таким же
наборам на Pascal или C. Стандартные команды включают присваивание, контроль
выполнения и вызовы процедур. Нестандартные команды включают конструкторы
таблицы и объявления локальных переменных.
Блоком является список инструкций.
4.4.1 Блоки
block ::= chunk
Блок может быть явно разграничен:
stat ::= do block endЯвные блоки полезны, чтобы управлять областью видимости (контекстом) локальных переменных. Явные блоки также иногда используются, чтобы добавить возврат или разрывать инструкцию в середине другого блока.
4.4.2 Присваивания
Lua поддерживает такую
удобную вещь, как многократные присваивания.
Следовательно, синтаксис определяет список переменных с левой стороны и список
выражений с правой сторона. Элементы в обоих списках отделяются запятыми:
stat ::= varlist1 `=' explist1 varlist1 ::= var {`,' var}Эта инструкция сначала оценивает все значения справа и возможные индексы слева, а затем делает примваивание. Так, код:
i = 3 i, a[i] = 4, 20установит
a[3]
в 20, но не воздействует на a[4]
потому, что i
в a[i]
оценен прежде, чем ему было
присвоено значение 4
. Многократное присваивание может
использоваться, чтобы поменять местами два значения, например: x, y = y, x
Два списка в многократном присваивании могут иметь различные длины. Перед собственно присваиванием, список значений будет откорректирован к длине списка имеющихся переменных.
Одиночное имя может обозначать глобальную переменную, локальную переменную или формальный параметр:
var ::= name
Квадратные скобки используются, чтобы индексировать таблицу:
var ::= varorfunc `[' exp1 `]' varorfunc ::= var | functioncallvarorfunc должен иметь в качестве результата значение из таблицы, где поле, индексированное значением выражения exp1, получает назначенное ему значение.
Синтаксис var.NAME
представляет собой только синтаксический
аналог для выражения var["NAME"]
:
var ::= varorfunc `.' name
Значение присваиваний, оценок глобальных переменных и индексированных
переменных может быть изменено методами тэгов. Фактически, назначение
x=val
, где x
представляет собой глобальную переменную,
является эквивалентным обращению setglobal("x",val)
, а присваивание
t[i]=val
эквивалентно settable_event(t,i,val)
. В
разделе 4.8
есть полное описание этих функций (setglobal
находится в
базисной библиотеке, settable_event используется только для
объяснительных целей).
4.4.3 Структуры управления
Структуры управления if,
while и repeat имеют обычное значение и знакомый синтаксис:
stat ::= while exp1 do block end stat ::= repeat block until exp1 stat ::= if exp1 then block {elseif exp1 then block} [else block] endВыражение exp1 условия структуры управления может возвращать любое значение. Все значения, отличные от nil, рассматриваются как истина, только nil считается ложью.
Инструкция return используется, чтобы возвратить значения из функции или из chunk. Поскольку функции или составные части могут возвращать больше, чем одно значение, синтаксис для инструкции return:
stat ::= return [explist1]
Инструкция break может использоваться, чтобы завершить выполнение цикла, переходя к следующей инструкции сразу после цикла:
stat ::= breakbreak заканчивает самый внутренний вложенный цикл (while, repeat или for).
По синтаксическим причинам инструкции return и break могут быть
написаны только как последние инструкции блока. Если действительно
необходимо вставить их в середину, надо применить явный внутренний блок,
например, do return end
потому, что теперь return в самом
деле последняя инструкция во внутреннем блоке.
4.4.4 Инструкция For
Инструкция for имеет две формы, по одной для чисел и таблиц. Числовая версия цикла for имеет следующий синтаксис:
stat ::= for name `=' exp1 `,' exp1 [`,' exp1] do block endИнструкция for, подобная:
for var = e1 ,e2, e3 do block endявляется заменителем кода:
do local var, _limit, _step = tonumber(e1), tonumber(e2), tonumber(e3) if not (var and _limit and _step) then error() end while (_step>0 and var<=_limit) or (_step<=0 and var>=_limit) do block var = var+_step end endОбратите внимание на следующее:
_limit
и _step
являются невидимыми переменными.
Имена здесь даны только для объяснительных целей.
var
внутри блока.
var
локальна для инструкции: Вы не можете
использовать ее значение после окончания работы for.
Таблица для инструкции for пересекает все пары (index,value) данной таблицы. Это имеет следующий синтаксис:
stat ::= for name `,' name in exp1 do block endИнструкция for, подобная:
for index, value in exp do block endравносильна такому коду:
do local _t = exp local index, value = next(t, nil) while index do block index, value = next(t, index) end endОбратите внимание на следующее:
_t
является невидимомй переменномй. Имя здесь дано только для
объяснительных целей.
index
внутри блока.
_t
при работе цикла.
index
и var
локальны для инструкции:
Вы не можете использовать их значения после окончания работы for.
index
или value
, присвойте их
другим переменным перед выходом.
stat ::= functioncallВ этом случае все возвращенные значения утрачены. Обращения к функции объясняются в разделе 4.5.8.
stat ::= local declist [init] declist ::= name {`,' name} init ::= `=' explist1Если представлено начальное назначение, то оно имеет ту же самую семантику многократного назначения. Иначе все переменные инициализированы nil.
Сhunk также блок, так что локальные переменные могут быть объявлены снаружи любого явного блока.
Область действия (контекст) локальных переменных начинается после объявления
и продолжается до конца блока. Таким образом, код local print=print
создает локальную переменную, названную print
, чье начальное
значение будет взято из глобальной переменной с тем же самым именем.
Базисные выражения в Lua такие:
exp ::= `(' exp `)' exp ::= nil exp ::= number exp ::= literal exp ::= var exp ::= upvalue exp ::= function exp ::= functioncall exp ::= tableconstructor
Доступ к глобальной переменной x
эквивалентен обращению
getglobal("x")
, а доступ к индексированной переменной
t[i]
эквивалентен обращению к gettable_event(t,i)
.
Подробности в разделе 4.8,
там есть описания этих функций (getglobal
находится в базисной
библиотеке).
Нетерминальный exp1 используется, чтобы указать, что значения, возвращенные выражением должны быть откорректированы к одному значению:
exp1 ::= exp
+
(сложение), -
(вычитание), *
(умножение), /
(деление),
^
(возведение в степень), а также унарный -
(обращение
знака числа). Если операнды числа или строки, которые могут быть преобразованы в
числа, (согласно правилам, данным в разделе 4.2),
то все операции за исключением возведения в степень имеют обычное значение.
Иначе будет вызван соответствующий метод тэга. Возведение в степень всегда
вызывает метод тэга. Стандартная математическая библиотека переопределяет этот
метод для чисел, давая ожидаемое значение (подробности в разделе
6.3).
== ~= < > <= >=Эти операторы возвращают nil как ложь, или любое другое значение (но не nil) в качестве истины.
Равенство (==
) сначала сравнивает тэги операндов. Если они
различны, то результатом будет nil. Иначе сравниваются их значения. Числа
и строки сравниваются обычным способом. Таблицы, userdata, и функции
сравниваются как ссылки, то есть две таблицы рассматриваются равными только,
если они реально та же самая таблица. Оператор ~=
прямо
противоположен оператору равенства (==
).
Правила преобразования из раздела 4.2
НЕ применяются к сравнениям равенства. Таким образом,
"0"==0
вернет false, а t[0]
и
t["0"]
обозначают различные записи в таблице.
Операторы порядка работают следующим образом. Если оба параметра числа, то
они сравниваются также. Иначе, если оба параметра строки, то их значения
сравниваются, используя лексикографический порядок. Во всех остальных ситуациях
будет вызван метод lt тэга (подробности в разделе 4.8).
4.5.4 Логические операторы
Логические
операторы в Lua:
and or notПодобно структурам управления, все логические операторы рассматривают nil как false (ложь), а все остальное как истину (true).
Оператор конъюнкции and
вернет nil, если первый параметр
nil, иначе это возвращает второй параметр. Оператор дизъюнкции
or
вернет первый параметр, если он отличается от nil, в
противном случае это возвращает второй параметр. Операторы and
и
or
используют краткое
вычисление, то есть второй операнд оценен только в случае необходимости.
Имеются две полезных идиомы в Lua, которые используют логические операторы.
Первая идиома:
x = x or vКоторая является эквивалентной:
if x == nil then x = v endЭта идиома устанавливает
x
к значению по умолчанию
v
, когда x
не установлен.
Вторая идиома такая:
x = a and b or cКоторая должна читаться как
x=(a and b) or c
. Эта идиома
эквивалентна: if a then x = b else x = c endПри условии, что
b
не nil.
and or < > <= >= ~= == .. + - * / not - (unary) ^Все двоичные операторы ассоциативны слева, кроме возведения в степень, который является ассоциативным справа. Прекомпилятор может перестраивать порядок оценки ассоциативных операторов (типа
..
или +
), пока
эти оптимизация не изменяют нормальные результаты. Однако, эти оптимизация могут
изменять некоторые результаты, если Вы определяете не ассоциативные методы тэгов
для этих операторов.
tableconstructor ::= `{' fieldlist `}' fieldlist ::= lfieldlist|ffieldlist|lfieldlist `;' ffieldlist|ffieldlist `;' lfieldlist lfieldlist ::= [lfieldlist1] ffieldlist ::= [ffieldlist1]
Форма lfieldlist1 используется, чтобы инициализировать списки:
lfieldlist1 ::= exp {`,' exp} [`,']Выражения в списке назначены последовательным числовым индексам, начиная с 1 (но не с 0!). Например, код:
a = {"v1", "v2", 34}является эквивалентным коду:
do local temp = {} temp[1] = "v1" temp[2] = "v2" temp[3] = 34 a = temp end
Форма ffieldlist1 инициализирует другие поля в таблице:
ffieldlist1 ::= ffield {`,' ffield} [`,'] ffield ::= `[' exp `]' `=' exp | name `=' expНапример такая запись:
a = {[f(k)] = g(y), x = 1, y = 3, [0] = b+c}эквивалентна такому коду:
do local temp = {} temp[f(k)] = g(y) temp.x = 1 -- or temp["x"] = 1 temp.y = 3 -- or temp["y"] = 3 temp[0] = b+c a = temp endВыражения, подобные
{x=1, y=4}
фактически синтаксический
аналог для выражения вида {["x"]=1, ["y"]=4}
.
Обе формы могут иметь факультативную конечную запятую и могут использоваться в том же самом конструкторе, разделенные точкой с запятой. Например, все формы ниже правильны:
x = {;} x = {"a", "b",} x = {type="list"; "a", "b"} x = {f(0), f(1), f(2),; n=3,}
functioncall ::= varorfunc argsСначала вычисляется varorfunc. Если значение имеет тип function, то эта функция будет вызвана с данными параметрами. Иначе вызывается метод function тэга, имея первым параметром значение varorfunc с перечисленными затем первоначальными параметрами обращения. Подробности в разделе 4.8.
Форма
functioncall ::= varorfunc `:' name argsМожет использоваться, чтобы вызвать methods. Обращение
v:name(...)
синтаксически аналогично v.name(v, ...)
,
за исключением того, что v
будет оценен только однажды. Параметры
имеют следующий синтаксис: args ::= `(' [explist1] `)' args ::= tableconstructor args ::= literal explist1 ::= {exp1 `,'} expВсе выражения параметра оценены перед обращением. Обращение в форме
f{...}
синтаксически аналогично f({...})
, то есть
список параметров представляет собой одиночную новую таблицу. Обращение в форме
f'...'
(f"..."
или f[[...]]
)
синтаксически аналогично f('...')
, то есть список параметров
представляет собой одиночную строку литералов.
Потому, что функция может возвращать любое число результатов, число результатов должно быть откорректировано прежде, чем они используются. Если функция вызвана как инструкция, то список возврата откорректирован к 0, таким образом отбрасывая все возвращенные значения. Если функция вызвана в месте, которое нуждается в одиночном значении (синтаксически обозначенном нетерминальным exp1), то список возврата откорректирован к 1, таким образом отбрасывая все возвращенные значения, но не первый. Если функция вызвана в месте, которое может использовать много значений (синтаксически обозначено нетерминальным exp), то никакая корректировка не будет сделана. Единственные места, которые могут обрабатывать много значений, это последние (или единственные) выражения в присваивании, в списке параметров или в инструкции return. Имеются примеры:
f() -- 0 результатов g(f(), x) -- f() 1 результат g(x, f()) -- g получает x и все значения, возвращенные f() a,b,c = f(), x -- f() скорректирован к 1 результату (и c получает nil) a,b,c = x, f() -- f() 2 результата a,b,c = f() -- f() 3 результата return f() -- возвращает все значения, возвращенные f() return x,y,f() -- вернет a, b и все, что вернет f()
Синтаксис для определения функций такой:
function ::= function `(' [parlist1] `)' block end stat ::= function funcname `(' [parlist1] `)' block end funcname ::= name | name `.' name | name `:' nameИнструкция
function f () ... endявляется только синтаксическим аналогом для
f = function () ... endа инструкция
function v.f () ... endявляется синтаксическим аналогом для
v.f = function () ... end
Функциональное определение представляет собой выполнимое выражение, чье значение имеет тип function. Когда Lua прекомпилирует chunk, все функциональные тела также прекомпилируются. Затем, всякий раз, когда Lua выполняет функциональное определение верхние переменные (upvalues) фиксируются, и функция выполняется. Этот функциональный образец (или замкнутое выражение) представляет собой конечное значение выражения. Различные образцы той же самой функции могут иметь различные верхние переменные.
Параметры действуют как локальные переменные, инициализированные со значениями параметра:
parlist1 ::= `...' parlist1 ::= name {`,' name} [`,' `...']Когда функция вызвана, список параметров будет откорректирован к длине списка параметров, если функция не vararg-функция, которая обозначена тремя точками (`
...
') в конце списка параметра. Функция vararg не
корректирует список параметров, вместо этого она собирает все лишние параметры в
неявный параметр, названный arg. Значением
arg
является таблицы из n
полей, чьим значением
является число параметров дополнительного пространства и сами эти параметры,
перечисленные в полях 1, 2, ..., n
.
Как пример, рассмотрите следующие определения:
function f(a, b) end function g(a, b, ...) end function r() return 1,2,3 endИмеем следующее отображение параметров:
ВЫЗОВ ПАРАМЕТРЫ f(3) a=3, b=nil f(3, 4) a=3, b=4 f(3, 4, 5) a=3, b=4 f(r(), 10) a=1, b=10 f(r()) a=1, b=2 g(3) a=3, b=nil, arg={n=0} g(3, 4) a=3, b=4, arg={n=0} g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2} g(5, r()) a=5, b=1, arg={2, 3; n=2}
Результаты возвращены, используя инструкцию return. Если управление достигает конца функции без того, чтобы столкнуться с инструкцией return, то функция будет завершена без результатов.
Синтаксис
funcname ::= name `:' nameиспользуется для определения методов, то есть функции, которые имеют неявный дополнительный параметр self .
Инструкция
function v:f (...) ... endявляется только синтаксическим аналогом для
v.f = function (self, ...) ... end
Обратите внимание, что функция получает дополнительный формальный параметр
self
.
Функциональное тело может обратиться к собственным локальным переменным (которые включают и параметры), а также к глобальным переменным, пока они не затенены локальными переменными с тем же самым именем. Функция не может обращаться к локальной переменной из функции включения, так как такие переменные больше не могут существовать, когда функция вызвана. Однако, функция может обращаться к значению локальной переменной из функции включения, используя upvalues, чей синтаксис:
upvalue ::= `%' name
upvalue подобен переменному выражению, но его значение закрепляется, когда функция, в которой он появляется запускается. Имя, используемое в upvalue, может быть именем любой переменной, видимой в том месте, где функция определена, то есть пригодны глобальные переменные и локальные переменные. Обратите внимание, что, когда upvalue таблица, только ссылка на эту таблицу (которая и является значением upvalue) закрепляется, а содержание самой таблицы может быть изменено по желанию. Использование значений таблицы как upvalues представляет собой методику для наличия перезаписываемого но частного состояния, приложенного к функциям.
Имеются некоторые примеры:
a,b,c = 1,2,3 -- глобальные переменные local d function f (x) local b = {} -- x и b локальны для f, b затеняет глобальную b local g = function (a) local y -- a и y локальны для g p = a -- OK, доступ к локальной a p = c -- OK, доступ к глобальной c p = b -- ERROR: невозможен доступ к переменной вне зоны видимости p = %b -- OK, доступ к замороженной b (локальная f) %b = 3 -- ERROR: нельзя менять upvalue %b.x = 3 -- OK, изменение содержимого таблицы p = %c -- OK, доступ к замороженному значению глобальной c p = %y -- ERROR: `y' невидима, где `g' определена p = %d -- ERROR: `d' невидима, где `g' определена end -- g end -- f
Поскольку Lua язык расширений, все действия Lua начинаются из C-кода в
ведущей программе, вызывающей функцию из Lua-библиотеки. Всякий раз, когда
ошибка происходит в течение Lua-трансляции или выполнения, вызывается функция
_ERRORMESSAGE
и затем соответствующая
функция из библиотеки (lua_dofile
, lua_dostring
,
lua_dobuffer
или lua_call
) завершена, возвращая
условие ошибки.
Ошибки распределения памяти представляют собой исключительную ситуацию из
предыдущего правила. Когда происходит сбой распределения памяти, Lua не может
выполнить функцию _ERRORMESSAGE
. Так что, для этого вида ошибки,
Lua не вызывает функцию _ERRORMESSAGE
. Вместо этого соответствующая
функция из библиотеки немедленно завершится со специальным кодом ошибки
(LUA_ERRMEM
). Это и другие коды ошибки определено в заголовочном
файле lua.h
, подробности в разделе 5.8.
Единственный параметр _ERRORMESSAGE
: строка, описывающая ошибку.
Заданное по умолчанию определение для этого: обращение к функции _ALERT
, которая печатает сообщение на
stderr
. Стандартная библиотека ввода-вывода переопределяет
_ERRORMESSAGE
и использует средства отладки, чтобы печатать
некоторую дополнительную информацию, типа расположения обращений в стеке.
Lua-код может явно генерировать ошибку, вызывая функцию error
(подробности в разделе 6.1).
Lua-код может перехватить ошибку, используя обращение к функции
call
(подробности в разделе 6.1).
Lua обеспечивает мощный механизм, чтобы расширить семантику, названный методами тэгов. Это определенная программистом функция, которая вызвана в специфических точках в течение выполнения программы Lua, позволяя программисту изменить стандартное поведение Lua в этих точках. Каждая из этих точек названа событием (event).
Метод тэга для некоего специфического события выбран согласно тэгу значения.
Функция settagmethod изменяет метод тэга,
связанный с данной парой (tag, event). Первый параметр представляет
собой тэг, второй строку (имя события), а третий параметр (функция) задает новый
метод или nil, чтобы восстановить заданное по умолчанию поведение для
пары. Функция settagmethod
возвращает предыдущий метод тэга для
этой пары. Функция-компаньон gettagmethod
получает тэг и имя события и возвращает текущий метод, связанный с парой.
Методы тэгов вызваны при соответствующих событиях, которые идентифицированы
данными именами. Семантика методов лучше объяснена функцией Lua, описывающей
поведение интерпретатора в каждом событии. Эта функция не только показывает,
когда метод вызван, но также параметры, результаты и заданное по умолчанию
поведение. Код, показанный здесь, только иллюстративен: реальное поведение
сложно закодировано в интерпретаторе и намного более эффективно, чем это
моделирование. Все функции, используемые в этих описаниях (rawget
,
tonumber
, call
и т.д.), описаны подробно в разделе
6.1.
+
применяется
к не числовым операндам.
Функция getbinmethod
ниже определяет, как Lua выбирает метод
для двоичной операции. Сначала Lua пробует первый операнд. Если тэг не
определяет метод для операции, то Lua пробует второй операнд. Если это также
терпит неудачу, то Lua получает метод из тэга 0.
function getbinmethod (op1, op2, event) return gettagmethod(tag(op1), event) or gettagmethod(tag(op2), event) or gettagmethod(0, event) endПри использовании этой функции, метод события ``add'' такой:
function add_event (op1, op2) local o1, o2 = tonumber(op1), tonumber(op2) if o1 and o2 then -- both operands are numeric return o1+o2 -- '+' here is the primitive 'add' else -- at least one of the operands is not numeric local tm = getbinmethod(op1, op2, "add") if tm then -- call the method with both operands and an extra -- argument with the event name return tm(op1, op2, "add") else -- no tag method available: default behavior error("unexpected type at arithmetic operation") end end end
-
применяется
к не числовым операндам. Поведение подобно событию ``add''.
*
применяется
к не числовым операндам. Поведение подобно событию ``add''.
/
применяется
к не числовым операндам. Поведение подобно событию ``add''.
^
(возведение
в степень) применяется к числовым операндам. function pow_event (op1, op2) local tm = getbinmethod(op1, op2, "pow") if tm then -- call the method with both operands and an extra -- argument with the event name return tm(op1, op2, "pow") else -- no tag method available: default behavior error("unexpected type at arithmetic operation") end end
-
применяется к не числовому операнду. function unm_event (op) local o = tonumber(op) if o then -- operand is numeric return -o -- '-' here is the primitive 'unm' else -- the operand is not numeric. -- Try to get a tag method from the operand; -- if it does not have one, try a "global" one (tag 0) local tm = gettagmethod(tag(op), "unm") or gettagmethod(0, "unm") if tm then -- call the method with the operand, nil, and an extra -- argument with the event name return tm(op, nil, "unm") else -- no tag method available: default behavior error("unexpected type at arithmetic operation") end end end
<
. function lt_event (op1, op2) if type(op1) == "number" and type(op2) == "number" then return op1 < op2 -- numeric comparison elseif type(op1) == "string" and type(op2) == "string" then return op1 < op2 -- lexicographic comparison else local tm = getbinmethod(op1, op2, "lt") if tm then return tm(op1, op2, "lt") else error("unexpected type at comparison"); end end endДругие операторы порядка используют этот метод согласно обычным эквивалентностям:
a>b <=> b<a a<=b <=> not (b<a) a>=b <=> not (a<b)
function concat_event (op1, op2) if (type(op1) == "string" or type(op1) == "number") and (type(op2) == "string" or type(op2) == "number") then return op1..op2 -- primitive string concatenation else local tm = getbinmethod(op1, op2, "concat") if tm then return tm(op1, op2, "concat") else error("unexpected type for concatenation") end end end
newtag
. Обратите
внимание, что тэг представляет собой текущее значение глобальной
переменной. function getglobal (varname) -- access the table of globals local value = rawget(globals(), varname) local tm = gettagmethod(tag(value), "getglobal") if not tm then return value else return tm(varname, value) end endФункция
getglobal
определена в базисной библиотеке.
function setglobal (varname, newvalue) local oldvalue = rawget(globals(), varname) local tm = gettagmethod(tag(oldvalue), "setglobal") if not tm then rawset(globals(), varname, newvalue) else tm(varname, oldvalue, newvalue) end endФункция
setglobal
определена в базисной библиотеке.
function gettable_event (table, index) local tm = gettagmethod(tag(table), "gettable") if tm then return tm(table, index) elseif type(table) ~= "table" then error("indexed expression not a table"); else local v = rawget(table, index) tm = gettagmethod(tag(table), "index") if v == nil and tm then return tm(table, index) else return v end end end
function settable_event (table, index, value) local tm = gettagmethod(tag(table), "settable") if tm then tm(table, index, value) elseif type(table) ~= "table" then error("indexed expression not a table") else rawset(table, index, value) end end
function function_event (func, ...) if type(func) == "function" then return call(func, arg) else local tm = gettagmethod(tag(func), "function") if tm then for i=arg.n,1,-1 do arg[i+1] = arg[i] end arg.n = arg.n+1 arg[1] = func return call(tm, arg) else error("call expression not a function") end end end
function gc_event (obj) local tm = gettagmethod(tag(obj), "gc") if tm then tm(obj) end endВ цикле уборки мусора методы тэгов для userdata вызываются в порядке, обратном созданию тэгов, то есть первые методы, которые будут вызваны, связаны с последним тэгом, созданным в программе. Кроме того, в конце цикла Lua делает эквивалент обращения
gc_event(nil)
.