3 – Язык
В этом разделе описываются лексика, синтаксис и семантика Lua. Иными словами, в этом разделе описывается, какие токены допустимы, как их можно комбинировать и что означают их комбинации.
Конструкции языка объясняются с использованием обычной расширенной нотации BNF, в которой {a} означает 0 или более a, а [a] означает необязательное a. Нетерминалы показываются как non-terminal, ключевые слова показываются как kword, а другие терминальные символы показываются как ‘=’. Полный синтаксис Lua можно найти в §9 в конце этого руководства.
3.1 – Лексические соглашения
Lua — язык со свободным форматированием. Он игнорирует пробелы и комментарии между лексическими элементами (токенами), кроме случаев, когда они служат разделителями между двумя токенами. В исходном коде Lua распознаёт как пробелы стандартные ASCII-символы пробела: пробел, подачу страницы, перевод строки, возврат каретки, горизонтальную табуляцию и вертикальную табуляцию.
Имена (также называемые идентификаторами) в Lua могут быть любой строкой из латинских букв, арабо-индийских цифр и символов подчёркивания, не начинающейся с цифры и не являющейся зарезервированным словом. Идентификаторы используются для именования переменных, полей таблиц и меток.
Следующие ключевые слова зарезервированы и не могут использоваться как имена:
and break do else elseif end
false for function global goto if
in local nil not or repeat
return then true until while
Lua — язык, чувствительный к регистру:
and является зарезервированным словом, но And и AND
— два разных допустимых имени.
По соглашению
программы должны избегать создания
имён, которые начинаются с символа подчёркивания, за которым следуют
одна или более заглавных букв (например, _VERSION).
Следующие строки обозначают другие токены:
+ - * / % ^ #
& ~ | << >> //
== ~= <= >= < > =
( ) { } [ ] ::
; : , . .. ...
Короткая литеральная строка
может быть ограничена парными одинарными или двойными кавычками
и может содержать следующие escape-последовательности, подобные используемым в C:
'\a' (звонок),
'\b' (забой),
'\f' (подача страницы),
'\n' (перевод строки),
'\r' (возврат каретки),
'\t' (горизонтальная табуляция),
'\v' (вертикальная табуляция),
'\\' (обратная косая черта),
'\"' (кавычка [двойная кавычка])
и '\'' (апостроф [одинарная кавычка]).
Обратная косая черта, за которой следует разрыв строки,
приводит к появлению в строке перевода строки.
Escape-последовательность '\z' пропускает следующий участок
пробельных символов,
включая разрывы строк;
она особенно полезна для разбиения и отступов длинной литеральной строки
на несколько строк без добавления переводов строк и пробелов
в содержимое строки.
Короткая литеральная строка не может содержать неэкранированные разрывы строк
или escape-последовательности, не образующие допустимой escape-последовательности.
Любой байт в короткой литеральной строке,
включая встроенные нули,
можно задать его числовым значением.
Это можно сделать
с помощью escape-последовательности \xXX,
где XX — последовательность ровно из двух шестнадцатеричных цифр,
или с помощью escape-последовательности \ddd,
где ddd — последовательность из не более чем трёх десятичных цифр.
(Обратите внимание, что если за десятичной escape-последовательностью
должна следовать цифра,
её нужно записывать ровно тремя цифрами.)
UTF-8-кодировку символа Unicode
можно вставить в литеральную строку
с помощью escape-последовательности \u{XXX}
(с обязательными заключающими фигурными скобками),
где XXX — последовательность из одной или более шестнадцатеричных цифр,
представляющая кодовую точку символа.
Эта кодовая точка может быть любым значением меньше 231.
(Здесь Lua использует исходную спецификацию UTF-8,
которая не ограничена допустимыми кодовыми точками Unicode.)
Литеральные строки также можно определять с использованием длинного формата,
заключённого в длинные скобки.
Мы определяем открывающую длинную скобку уровня n как открывающую
квадратную скобку, за которой следуют n знаков равенства, а затем ещё одна
открывающая квадратная скобка.
Так, открывающая длинная скобка уровня 0 записывается как [[,
открывающая длинная скобка уровня 1 записывается как [=[,
и так далее.
Закрывающая длинная скобка определяется аналогично;
например,
закрывающая длинная скобка уровня 4 записывается как ]====].
Длинный литерал начинается с открывающей длинной скобки любого уровня и
заканчивается на первой закрывающей длинной скобке того же уровня.
Он может содержать любой текст, кроме закрывающей скобки того же уровня.
Литералы в такой форме со скобками могут занимать несколько строк,
не интерпретируют никакие escape-последовательности
и игнорируют длинные скобки любого другого уровня.
Любой вид последовательности конца строки
(возврат каретки, перевод строки, возврат каретки с последующим переводом строки
или перевод строки с последующим возвратом каретки)
преобразуется в обычный перевод строки.
Когда за открывающей длинной скобкой сразу следует перевод строки,
этот перевод строки не включается в строку.
В качестве примера, в системе, использующей ASCII
(в которой 'a' кодируется как 97,
перевод строки кодируется как 10, а '1' кодируется как 49),
пять литеральных строк ниже обозначают одну и ту же строку:
a = 'alo\n123"'
a = "alo\n123\""
a = '\97lo\10\04923"'
a = [[alo
123"]]
a = [==[
alo
123"]==]
Любой байт в литеральной строке, явно не затронутый предыдущими правилами, представляет сам себя. Однако Lua открывает файлы для разбора в текстовом режиме, и файловые функции системы могут иметь проблемы с некоторыми управляющими символами. Поэтому безопаснее представлять двоичные данные как литерал в кавычках с явными escape-последовательностями для символов, не являющихся текстовыми.
Числовая константа (или числовой литерал)
может быть записана с необязательной дробной частью
и необязательной десятичной экспонентой,
обозначаемой буквой 'e' или 'E'.
Lua также принимает шестнадцатеричные константы,
которые начинаются с 0x или 0X.
Шестнадцатеричные константы также принимают необязательную дробную часть
и необязательную двоичную экспоненту,
обозначаемую буквой 'p' или 'P' и записываемую в десятичном виде.
(Например, 0x1.fp10 обозначает 1984,
что равно 0x1f / 16, умноженному на 210.)
Числовая константа с разделителем целой и дробной части или с экспонентой обозначает число с плавающей точкой; в противном случае, если её значение помещается в целое число или она является шестнадцатеричной константой, она обозначает целое число; в противном случае (то есть десятичный целочисленный литерал, который переполняется) она обозначает число с плавающей точкой. Шестнадцатеричные числовые литералы без разделителя целой и дробной части и без экспоненты всегда обозначают целочисленное значение; если значение переполняется, оно циклически переполняется, чтобы поместиться в допустимое целое число.
Примеры допустимых целочисленных констант:
3 345 0xff 0xBEBADA
Примеры допустимых констант с плавающей точкой:
3.0 3.1416 314.16e-2 0.31416E1 34e1
0x0.1E 0xA23p-4 0X1.921FB54442D18P+1
Комментарий начинается с двойного дефиса (--)
в любом месте вне строки.
Если текст непосредственно после -- не является открывающей длинной скобкой,
комментарий является коротким комментарием,
который продолжается до конца строки.
В противном случае это длинный комментарий,
который продолжается до соответствующей закрывающей длинной скобки.
3.2 – Переменные
Переменные — это места, хранящие значения. В Lua существует три вида переменных: глобальные переменные, локальные переменные и поля таблиц.
Одно имя может обозначать глобальную переменную или локальную переменную (или формальный параметр функции, который является особым видом локальной переменной) (см. §2.2):
var ::= Name
Name обозначает идентификаторы (см. §3.1).
Поскольку переменные имеют лексическую область видимости, к локальным переменным могут свободно обращаться функции, определённые внутри их области видимости (см. §2.2).
До первого присваивания переменной её значение равно nil.
Квадратные скобки используются для индексирования таблицы:
var ::= prefixexp ‘[’ exp ‘]’
Семантика обращений к полям таблиц может быть изменена с помощью метатаблиц (см. §2.4).
Синтаксис var.Name — это просто синтаксический сахар для
var["Name"]:
var ::= prefixexp ‘.’ Name
Обращение к глобальной переменной x
эквивалентно _ENV.x.
3.3 – Операторы
Lua поддерживает почти традиционный набор операторов, аналогичный наборам в других традиционных языках. Этот набор включает блоки, присваивания, управляющие конструкции, вызовы функций и объявления переменных.
3.3.1 – Блоки
Блок — это список операторов, которые выполняются последовательно:
block ::= {stat}
В Lua есть пустые операторы, которые позволяют разделять операторы точками с запятой, начинать блок с точки с запятой или записывать две точки с запятой подряд:
stat ::= ‘;’
Как вызовы функций, так и присваивания могут начинаться с открывающей круглой скобки. Эта возможность приводит к неоднозначности в грамматике Lua. Рассмотрим следующий фрагмент:
a = b + c
(print or io.write)('done')
Грамматика может интерпретировать этот фрагмент двумя способами:
a = b + c(print or io.write)('done')
a = b + c; (print or io.write)('done')
Текущий синтаксический анализатор всегда интерпретирует такие конструкции первым способом, считая открывающую круглую скобку началом аргументов вызова. Чтобы избежать этой неоднозначности, рекомендуется всегда ставить точку с запятой перед операторами, начинающимися с круглой скобки:
;(print or io.write)('done')
Блок можно явно ограничить, чтобы получить отдельный оператор:
stat ::= do block end
Явные блоки полезны для управления областью действия объявлений переменных. Явные блоки также иногда используются, чтобы добавить оператор return в середину другого блока (см. §3.3.4).
3.3.2 – Фрагменты
Единица компиляции Lua называется фрагментом. Синтаксически фрагмент — это просто блок:
chunk ::= block
Lua обрабатывает фрагмент как тело анонимной функции
с переменным числом аргументов
(см. §3.4.11).
Таким образом, фрагменты могут определять локальные переменные,
принимать аргументы и возвращать значения.
Более того, такая анонимная функция компилируется так, как если бы она находилась
в области действия внешней локальной переменной с именем _ENV (см. §2.2).
Полученная функция всегда имеет _ENV в качестве своей единственной внешней переменной,
даже если она не использует эту переменную.
Фрагмент может храниться в файле или в строке внутри хост-программы. Чтобы выполнить фрагмент, Lua сначала загружает его, предкомпилируя код фрагмента в инструкции виртуальной машины, а затем Lua выполняет скомпилированный код с помощью интерпретатора виртуальной машины.
Фрагменты также могут быть предкомпилированы в двоичную форму;
подробности см. в программе luac и функции string.dump.
Программы в исходной и скомпилированной формах взаимозаменяемы;
Lua автоматически определяет тип файла и действует соответствующим образом (см. load).
Учтите, что, в отличие от исходного кода,
злонамеренно созданные двоичные фрагменты могут вызвать сбой интерпретатора.
3.3.3 – Присваивание
Lua допускает множественные присваивания. Поэтому синтаксис присваивания определяет список переменных в левой части и список выражений в правой части. Элементы обоих списков разделяются запятыми:
stat ::= varlist ‘=’ explist
varlist ::= var {‘,’ var}
explist ::= exp {‘,’ exp}
Выражения рассматриваются в §3.4.
Перед присваиванием список значений приводится к длине списка переменных (см. §3.4.12).
Если переменная как присваивается, так и читается внутри множественного присваивания, Lua гарантирует, что все чтения получат значение переменной до присваивания. Таким образом, код
i = 3
i, a[i] = i+1, 20
присваивает a[3] значение 20, не затрагивая a[4],
поскольку i в a[i] вычисляется (как 3)
до того, как ему присваивается 4.
Аналогично, строка
x, y = y, x
обменивает значения x и y,
а
x, y, z = y, z, x
циклически переставляет значения x, y и z.
Обратите внимание, что эта гарантия охватывает только обращения, синтаксически находящиеся внутри оператора присваивания. Если функция или метаметод, вызванные во время присваивания, изменяют значение переменной, Lua не даёт никаких гарантий относительно порядка такого обращения.
Присваивание глобальному имени x = val
эквивалентно присваиванию
_ENV.x = val (см. §2.2).
Смысл присваиваний полям таблиц и глобальным переменным (которые на самом деле тоже являются полями таблиц) может изменяться посредством метатаблиц (см. §2.4).
3.3.4 – Управляющие конструкции
Управляющие конструкции if, while и repeat имеют обычное значение и привычный синтаксис:
stat ::= while exp do block end
stat ::= repeat block until exp
stat ::= if exp then block {elseif exp then block} [else block] end
В Lua также есть оператор for в двух разновидностях (см. §3.3.5).
Условное выражение управляющей конструкции может возвращать любое значение. И false, и nil считаются ложными. Все значения, отличные от nil и false, считаются истинными. В частности, число 0 и пустая строка также считаются истинными.
В цикле repeat–until внутренний блок заканчивается не на ключевом слове until, а только после условия. Поэтому условие может обращаться к локальным переменным, объявленным внутри блока цикла.
Оператор goto передаёт управление программой на метку. По синтаксическим причинам метки в Lua также считаются операторами:
stat ::= goto Name stat ::= label label ::= ‘::’ Name ‘::’
Метка видима во всём блоке, где она определена, кроме вложенных функций. goto может переходить на любую видимую метку при условии, что он не входит в область действия объявления переменной. Метку не следует объявлять там, где видима предыдущая метка с тем же именем, даже если эта другая метка была объявлена во включающем блоке.
Оператор break завершает выполнение цикла while, repeat или for, переходя к следующему оператору после цикла:
stat ::= break
break завершает ближайший охватывающий цикл.
Оператор return используется для возврата значений из функции или фрагмента (который обрабатывается как анонимная функция). Функции могут возвращать более одного значения, поэтому синтаксис оператора return таков:
stat ::= return [explist] [‘;’]
Оператор return может быть записан только
как последний оператор блока.
Если необходимо выполнить return в середине блока,
можно использовать явный внутренний блок,
как в идиоме do return end,
поскольку теперь return является последним оператором своего (внутреннего) блока.
3.3.5 – Оператор for
Оператор for имеет две формы: численную и обобщённую.
Численный цикл for
Численный цикл for повторяет блок кода, пока управляющая переменная изменяется в соответствии с арифметической прогрессией. Он имеет следующий синтаксис:
stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end
Заданный идентификатор (Name) определяет управляющую переменную,
которая является новой локальной для тела цикла (блока)
переменной только для чтения (const).
Цикл начинается с однократного вычисления трёх управляющих выражений. Их значения называются соответственно начальным значением, пределом и шагом. Если шаг отсутствует, по умолчанию он равен 1.
Если и начальное значение, и шаг являются целыми числами, цикл выполняется с целыми числами; обратите внимание, что предел может не быть целым числом. В противном случае три значения преобразуются в числа с плавающей запятой, и цикл выполняется с плавающей запятой. В этом случае учитывайте точность чисел с плавающей запятой.
После этой инициализации тело цикла повторяется, а значение управляющей переменной изменяется по арифметической прогрессии, начиная с начального значения, с разностью, задаваемой шагом. Отрицательный шаг создаёт убывающую последовательность; шаг, равный нулю, вызывает ошибку. Цикл продолжается, пока значение меньше или равно пределу (больше или равно при отрицательном шаге). Если начальное значение уже больше предела (или меньше, если шаг отрицательный), тело не выполняется.
В целочисленных циклах управляющая переменная никогда не переполняется с заворачиванием; вместо этого цикл завершается в случае переполнения.
Обобщённый цикл for
Обобщённый оператор for работает с функциями, называемыми итераторами. На каждой итерации вызывается функция-итератор для получения нового значения; выполнение прекращается, когда это новое значение равно nil. Обобщённый цикл for имеет следующий синтаксис:
stat ::= for namelist in explist do block end
namelist ::= Name {‘,’ Name}
Оператор for вида
for var_1, ···, var_n in explist do body end
работает следующим образом.
Имена var_i объявляют переменные цикла, локальные для тела цикла.
Первая из этих переменных является управляющей переменной,
которая представляет собой переменную только для чтения (const).
Цикл начинается с вычисления explist, в результате чего получаются четыре значения: функция-итератор, состояние, начальное значение для управляющей переменной и закрывающее значение.
Затем на каждой итерации Lua вызывает функцию-итератор с двумя аргументами: состоянием и управляющей переменной. Полученные в результате этого вызова значения затем присваиваются переменным цикла по правилам множественного присваивания (см. §3.3.3). Если управляющая переменная становится nil, цикл завершается. В противном случае выполняется тело, и цикл переходит к следующей итерации.
Закрывающее значение ведёт себя как переменная, подлежащая закрытию (см. §3.3.8), и может использоваться для освобождения ресурсов при завершении цикла. В остальном оно не влияет на цикл.
3.3.6 – Вызовы функций как операторы
Чтобы допустить возможные побочные эффекты, вызовы функций можно выполнять как операторы:
stat ::= functioncall
В этом случае все возвращённые значения отбрасываются. Вызовы функций объясняются в §3.4.10.
3.3.7 – Объявления переменных
Локальные и глобальные переменные можно объявлять в любом месте внутри блока. Объявление может включать инициализацию:
stat ::= local attnamelist [‘=’ explist] stat ::= global attnamelist [‘=’ explist]
Если инициализация отсутствует, локальные переменные инициализируются значением nil; глобальные переменные остаются без изменений. В противном случае инициализация подвергается такому же согласованию, как при множественном присваивании (см. §3.3.3). Кроме того, для глобальных переменных инициализация вызовет ошибку времени выполнения, если переменная уже определена, то есть имеет значение, отличное от nil.
Список имён может иметь префиксный атрибут (имя в угловых скобках), и каждое имя переменной может иметь постфиксный атрибут:
attnamelist ::= [attrib] Name [attrib] {‘,’ Name [attrib]}
attrib ::= ‘<’ Name ‘>’
Префиксный атрибут применяется ко всем именам в списке;
постфиксный атрибут применяется к соответствующему имени.
Возможны два атрибута:
const, который объявляет константную или доступную только для чтения переменную,
то есть переменную, которую нельзя использовать в качестве левой части
присваивания,
и close, который объявляет переменную, подлежащую закрытию (см. §3.3.8).
Только локальные переменные могут иметь атрибут close.
Список переменных может содержать не более одной переменной, подлежащей закрытию.
Lua также предлагает коллективное объявление для глобальных переменных:
stat ::= global [attrib] ‘*’
Эта специальная форма неявно объявляет
глобальными все имена, которые ранее не были явно объявлены.
В частности,
global<const> * неявно объявляет
глобальными только для чтения все имена, которые ранее не были явно объявлены;
см. следующий пример:
global X
global<const> *
print(math.pi) -- Ok, 'print' and 'math' are read-only
X = 1 -- Ok, declared as read-write
Y = 1 -- Error, Y is read-only
Как отмечено в §2.2,
все фрагменты начинаются с неявного объявления global *,
но это вступительное объявление становится недействительным внутри
области действия любого другого объявления global.
Поэтому программа, которая не использует объявления глобальных переменных
и не начинается с global *,
имеет свободный доступ на чтение и запись к любой глобальной переменной;
программа, которая начинается с global<const> *,
имеет свободный доступ только для чтения к любой глобальной переменной;
а программа, которая начинается с любого другого объявления глобальных переменных
(например, global none), может обращаться только к объявленным переменным.
Обратите внимание, что для глобальных переменных эффект любого объявления является только синтаксическим (за исключением необязательного присваивания):
global X <const>, _G
X = 1 -- ERROR
_ENV.X = 1 -- Ok
_G.print(X) -- Ok
foo() -- 'foo' can freely change any global
Фрагмент также является блоком (см. §3.3.2), поэтому переменные можно объявлять во фрагменте вне любого явного блока.
Правила видимости для объявлений переменных объясняются в §2.2.
3.3.8 – Переменные, подлежащие закрытию
Переменная, подлежащая закрытию, ведёт себя как локальная константа, за исключением того, что её значение закрывается всякий раз, когда переменная выходит из области действия, включая нормальное завершение блока, выход из её блока посредством break/goto/return или выход из-за ошибки.
Здесь закрыть значение означает
вызвать его метаметод __close.
При вызове метаметода
само значение передаётся в качестве первого аргумента.
Если произошла ошибка,
объект ошибки, вызвавшей выход,
передаётся в качестве второго аргумента;
в противном случае второго аргумента нет.
Значение, присваиваемое переменной, подлежащей закрытию,
должно иметь метаметод __close
или быть ложным значением.
(nil и false игнорируются как значения, подлежащие закрытию.)
Если несколько переменных, подлежащих закрытию, выходят из области действия при одном и том же событии, они закрываются в порядке, обратном порядку их объявления.
Если при выполнении метода закрытия возникает какая-либо ошибка, эта ошибка обрабатывается как ошибка в обычном коде, где была определена переменная. После ошибки остальные ожидающие методы закрытия всё равно будут вызваны.
Если сопрограмма уступает управление и больше никогда не возобновляется,
некоторые переменные могут так и не выйти из области действия,
и поэтому они никогда не будут закрыты.
(Это переменные, созданные внутри сопрограммы
и находящиеся в области действия в точке, где сопрограмма уступила управление.)
Аналогично, если сопрограмма завершается с ошибкой,
она не разворачивает свой стек,
поэтому она не закрывает ни одной переменной.
В обоих случаях
можно либо использовать финализаторы,
либо вызвать coroutine.close, чтобы закрыть переменные.
Однако если сопрограмма была создана
посредством coroutine.wrap,
то соответствующая ей функция закроет сопрограмму
в случае ошибок.
3.4 – Выражения
Базовые выражения в Lua следующие:
exp ::= prefixexp exp ::= nil | false | true exp ::= Numeral exp ::= LiteralString exp ::= functiondef exp ::= tableconstructor exp ::= ‘...’ exp ::= exp binop exp exp ::= unop exp prefixexp ::= var | functioncall | ‘(’ exp ‘)’
Числовые литералы и строковые литералы объясняются в §3.1;
переменные объясняются в §3.2;
определения функций объясняются в §3.4.11;
вызовы функций объясняются в §3.4.10;
конструкторы таблиц объясняются в §3.4.9.
Выражения vararg,
обозначаемые тремя точками ('...'), могут использоваться только
непосредственно внутри вариативной функции;
они объясняются в §3.4.11.
Бинарные операторы включают арифметические операторы (см. §3.4.1), побитовые операторы (см. §3.4.2), операторы отношения (см. §3.4.4), логические операторы (см. §3.4.5) и оператор конкатенации (см. §3.4.6). Унарные операторы включают унарный минус (см. §3.4.1), унарное побитовое НЕ (см. §3.4.2), унарное логическое not (см. §3.4.5) и унарный оператор длины (см. §3.4.7).
3.4.1 – Арифметические операторы
Lua поддерживает следующие арифметические операторы:
+: сложение-: вычитание*: умножение/: деление с плавающей точкой//: деление с округлением вниз%: остаток от деления^: возведение в степень-: унарный минус
За исключением возведения в степень и деления с плавающей точкой, арифметические операторы работают следующим образом: если оба операнда являются целыми числами, операция выполняется над целыми числами, и результат является целым числом. В противном случае, если оба операнда являются числами, они преобразуются в числа с плавающей точкой, операция выполняется по правилам машины для арифметики с плавающей точкой (обычно стандарт IEEE 754), и результат является числом с плавающей точкой. (Библиотека string приводит строки к числам в арифметических операциях; подробности см. в §3.4.3.)
Возведение в степень и деление с плавающей точкой (/)
всегда преобразуют свои операнды в числа с плавающей точкой,
и результат всегда является числом с плавающей точкой.
Возведение в степень использует функцию ISO C pow,
поэтому оно работает и для нецелых показателей степени.
Деление с округлением вниз (//) — это деление,
которое округляет частное к минус бесконечности,
что даёт нижнюю границу деления его операндов.
Остаток от деления определяется как остаток от деления, которое округляет частное к минус бесконечности (деление с округлением вниз).
В случае переполнения в целочисленной арифметике все операции циклически переполняются.
3.4.2 – Побитовые операторы
Lua поддерживает следующие побитовые операторы:
&: побитовое И|: побитовое ИЛИ~: побитовое исключающее ИЛИ>>: сдвиг вправо<<: сдвиг влево~: унарное побитовое НЕ
Все побитовые операции преобразуют свои операнды в целые числа (см. §3.4.3), действуют на все биты этих целых чисел и дают в результате целое число.
Как правый, так и левый сдвиг заполняют освободившиеся биты нулями. Отрицательные смещения выполняют сдвиг в другую сторону; смещения с абсолютным значением, равным или превышающим число битов в целом числе, дают ноль (так как все биты сдвигаются за пределы).
3.4.3 – Приведения и преобразования
Lua предоставляет некоторые автоматические преобразования между некоторыми типами и представлениями во время выполнения. Побитовые операторы всегда преобразуют операнды с плавающей точкой в целые числа. Возведение в степень и деление с плавающей точкой всегда преобразуют целочисленные операнды в числа с плавающей точкой. Все остальные арифметические операции, применяемые к смешанным числам (целым и с плавающей точкой), преобразуют целочисленный операнд в число с плавающей точкой. C API также преобразует как целые числа в числа с плавающей точкой, так и числа с плавающей точкой в целые, по мере необходимости. Кроме того, конкатенация строк принимает в качестве аргументов числа, помимо строк.
При преобразовании целого числа в число с плавающей точкой, если целое значение имеет точное представление в виде числа с плавающей точкой, результатом является оно. В противном случае преобразование даёт ближайшее большее или ближайшее меньшее представимое значение. Преобразование такого рода никогда не завершается ошибкой.
Преобразование из числа с плавающей точкой в целое проверяет, имеет ли число с плавающей точкой точное представление в виде целого числа (то есть имеет целое значение и находится в диапазоне представления целых чисел). Если да, результатом является это представление. В противном случае преобразование завершается неудачей.
В нескольких местах Lua при необходимости приводит строки к числам. В частности, библиотека string устанавливает метаметоды, которые пытаются привести строки к числам во всех арифметических операциях. Если преобразование не удаётся, библиотека вызывает метаметод другого операнда (если он присутствует) или возбуждает ошибку. Обратите внимание, что побитовые операторы не выполняют такого приведения.
Всегда хорошей практикой является не полагаться на
неявные приведения строк к числам,
поскольку они применяются не всегда;
в частности, "1"==1 равно false, а "1"<1 возбуждает ошибку
(см. §3.4.4).
Эти приведения существуют главным образом для совместимости и могут быть удалены
в будущих версиях языка.
Строка преобразуется в целое число или число с плавающей точкой в соответствии с её синтаксисом и правилами лексического анализатора Lua. Строка также может содержать ведущие и завершающие пробельные символы и знак. Все преобразования из строк в числа принимают как точку, так и текущий символ локали в качестве символа основания. (Однако лексический анализатор Lua принимает только точку.) Если строка не является допустимым числовым литералом, преобразование завершается неудачей. При необходимости результат этого первого шага затем преобразуется в определённый подтип числа в соответствии с предыдущими правилами преобразования между числами с плавающей точкой и целыми числами.
Преобразование из чисел в строки использует
неуказанный удобочитаемый формат.
Чтобы преобразовать числа в строки каким-либо конкретным способом,
используйте функцию string.format.
3.4.4 – Операторы отношения
Lua поддерживает следующие операторы отношения:
==: равенство~=: неравенство<: меньше>: больше<=: меньше или равно>=: больше или равно
Эти операторы всегда дают в результате false или true.
Равенство (==) сначала сравнивает типы своих операндов.
Если типы различаются, результатом является false.
В противном случае сравниваются значения операндов.
Строки равны, если они имеют одинаковое байтовое содержимое.
Числа равны, если они обозначают одно и то же математическое значение.
Таблицы, userdata и потоки сравниваются по ссылке: два объекта считаются равными, только если это один и тот же объект. Каждый раз, когда вы создаёте новый объект (таблицу, userdata или поток), этот новый объект отличается от любого ранее существовавшего объекта. Функция всегда равна самой себе. Функции с любым обнаружимым различием (разное поведение, разное определение) всегда различны. Функции, созданные в разное время, но без обнаружимых различий, могут быть признаны равными или нет (в зависимости от деталей внутреннего кэширования).
Вы можете изменить способ, которым Lua сравнивает таблицы и userdata,
используя метаметод __eq (см. §2.4).
Сравнения на равенство не преобразуют строки в числа
и наоборот.
Таким образом, "0"==0 вычисляется как false,
а t[0] и t["0"] обозначают разные
записи в таблице.
Оператор ~= является в точности отрицанием равенства (==).
Операторы порядка работают следующим образом.
Если оба аргумента являются числами,
они сравниваются в соответствии со своими математическими значениями,
независимо от их подтипов.
В противном случае, если оба аргумента являются строками,
их значения сравниваются в соответствии с текущей локалью.
В противном случае Lua пытается вызвать метаметод __lt или __le
(см. §2.4).
Сравнение a > b переводится в b < a,
а a >= b переводится в b <= a.
Согласно стандарту IEEE 754, специальное значение NaN не считается ни меньшим, ни равным, ни большим любого значения, включая само себя.
3.4.5 – Логические операторы
Логические операторы в Lua — это and, or и not. Как и управляющие конструкции (см. §3.3.4), все логические операторы считают как false, так и nil ложью, а всё остальное — истиной.
Оператор отрицания not всегда возвращает false или true. Оператор конъюнкции and возвращает свой первый аргумент, если это значение равно false или nil; в противном случае and возвращает свой второй аргумент. Оператор дизъюнкции or возвращает свой первый аргумент, если это значение отлично от nil и false; в противном случае or возвращает свой второй аргумент. И and, и or используют вычисление по короткой схеме; то есть второй операнд вычисляется только при необходимости. Вот некоторые примеры:
10 or 20 --> 10
10 or error() --> 10
nil or "a" --> "a"
nil and 10 --> nil
false and error() --> false
false and nil --> false
false or nil --> nil
10 and 20 --> 20
3.4.6 – Конкатенация
Оператор конкатенации строк в Lua
обозначается двумя точками ('..').
Если оба операнда являются строками или числами,
числа преобразуются в строки
в неуказанном формате (см. §3.4.3).
В противном случае вызывается метаметод __concat (см. §2.4).
3.4.7 – Оператор длины
Оператор длины обозначается унарным префиксным оператором #.
Длина строки — это число её байтов. (Это обычное значение длины строки, когда каждый символ занимает один байт.)
Оператор длины, применённый к таблице,
возвращает границу в этой таблице.
Граница в таблице t — это любое неотрицательное целое число,
удовлетворяющее следующему условию:
(border == 0 or t[border] ~= nil) and
(t[border + 1] == nil or border == math.maxinteger)
Словами: граница — это любой присутствующий в таблице положительный целочисленный индекс, за которым следует отсутствующий индекс, плюс два предельных случая: ноль, когда индекс 1 отсутствует; и максимальное значение целого числа, когда этот индекс присутствует. Обратите внимание, что ключи, не являющиеся положительными целыми числами, не влияют на границы.
Таблица ровно с одной границей называется последовательностью.
Например, таблица {10,20,30,40,50} является последовательностью,
так как имеет только одну границу (5).
Таблица {10,20,30,nil,50} имеет две границы (3 и 5)
и поэтому не является последовательностью.
(nil с индексом 4 называется дырой.)
Таблица {nil,20,30,nil,nil,60,nil}
имеет три границы (0, 3 и 6),
поэтому она тоже не является последовательностью.
Таблица {} является последовательностью с границей 0.
Когда t является последовательностью,
#t возвращает её единственную границу,
что соответствует интуитивному представлению о длине последовательности.
Когда t не является последовательностью,
#t может возвращать любую из её границ.
(Конкретная зависит от деталей
внутреннего представления таблицы,
которые, в свою очередь, могут зависеть от того, как таблица была заполнена,
и от адресов памяти её нечисловых ключей.)
Вычисление длины таблицы имеет гарантированное худшее время O(log n), где n — наибольший целочисленный ключ в таблице.
Программа может изменить поведение оператора длины для
любого значения, кроме строк, с помощью метаметода __len (см. §2.4).
3.4.8 – Приоритет
Приоритет операторов в Lua следует таблице ниже, от низшего к высшему приоритету:
or
and
< > <= >= ~= ==
|
~
&
<< >>
..
+ -
* / // %
unary operators (not # - ~)
^
Как обычно,
вы можете использовать круглые скобки, чтобы изменить приоритеты выражения.
Операторы конкатенации ('..') и возведения в степень ('^')
правоассоциативны.
Все остальные бинарные операторы левоассоциативны.
3.4.9 – Конструкторы таблиц
Конструкторы таблиц — это выражения, создающие таблицы. Каждый раз, когда конструктор вычисляется, создаётся новая таблица. Конструктор может использоваться для создания пустой таблицы или для создания таблицы и инициализации некоторых её полей. Общий синтаксис конструкторов:
tableconstructor ::= ‘{’ [fieldlist] ‘}’
fieldlist ::= field {fieldsep field} [fieldsep]
field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
fieldsep ::= ‘,’ | ‘;’
Каждое поле вида [exp1] = exp2 добавляет в новую таблицу запись
с ключом exp1 и значением exp2.
Поле вида name = exp эквивалентно
["name"] = exp.
Поля вида exp эквивалентны
[i] = exp, где i — последовательные целые числа,
начиная с 1;
поля в других форматах не влияют на этот счёт.
Например,
a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
эквивалентно
do
local t = {}
t[f(1)] = g
t[1] = "x" -- 1st exp
t[2] = "y" -- 2nd exp
t.x = 1 -- t["x"] = 1
t[3] = f(x) -- 3rd exp
t[30] = 23
t[4] = 45 -- 4th exp
a = t
end
Порядок присваиваний в конструкторе не определён. (Этот порядок был бы важен только при наличии повторяющихся ключей.)
Если последнее поле в списке имеет вид exp
и это выражение является многорезультатным,
то все значения, возвращаемые этим выражением, последовательно входят в список
(см. §3.4.12).
Список полей может иметь необязательный завершающий разделитель для удобства машинно-сгенерированного кода.
3.4.10 – Вызовы функций
Вызов функции в Lua имеет следующий синтаксис:
functioncall ::= prefixexp args
При вызове функции
сначала вычисляются prefixexp и args.
Если значение prefixexp имеет тип function,
то эта функция вызывается
с заданными аргументами.
В противном случае, если он присутствует,
вызывается метаметод __call значения prefixexp:
его первым аргументом является значение prefixexp,
за которым следуют исходные аргументы вызова
(см. §2.4).
Форма
functioncall ::= prefixexp ‘:’ Name args
может использоваться для эмуляции методов.
Вызов v:name(args)
является синтаксическим сахаром для v.name(v, args),
за исключением того, что v вычисляется только один раз.
Аргументы имеют следующий синтаксис:
args ::= ‘(’ [explist] ‘)’ args ::= tableconstructor args ::= LiteralString
Все выражения аргументов вычисляются перед вызовом.
Вызов вида f{fields} является
синтаксическим сахаром для f({fields});
то есть список аргументов состоит из одной новой таблицы.
Вызов вида f'string'
(или f"string", или f[[string]])
является синтаксическим сахаром для f('string');
то есть список аргументов состоит из одного строкового литерала.
Вызов вида return functioncall вне
области действия переменной, подлежащей закрытию, называется хвостовым вызовом.
Lua реализует правильные хвостовые вызовы
(или правильную хвостовую рекурсию):
при хвостовом вызове
вызываемая функция повторно использует элемент стека вызывающей функции.
Поэтому нет ограничения на количество вложенных хвостовых вызовов,
которые может выполнить программа.
Однако хвостовой вызов стирает любую отладочную информацию о
вызывающей функции.
Обратите внимание, что хвостовой вызов происходит только при определённом синтаксисе,
когда return имеет в качестве аргумента один-единственный вызов функции
и находится вне области действия любой переменной, подлежащей закрытию.
Этот синтаксис заставляет вызывающую функцию возвращать в точности
то, что возвращает вызываемая функция,
без каких-либо промежуточных действий.
Таким образом, ни один из следующих примеров не является хвостовым вызовом:
return (f(x)) -- results adjusted to 1
return 2 * f(x) -- result multiplied by 2
return x, f(x) -- additional results
f(x); return -- results discarded
return x or f(x) -- results adjusted to 1
3.4.11 – Определения функций
Синтаксис определения функции:
functiondef ::= function funcbody funcbody ::= ‘(’ [parlist] ‘)’ block end
Следующий синтаксический сахар упрощает определения функций:
stat ::= function funcname funcbody
stat ::= local function Name funcbody
stat ::= global function Name funcbody
funcname ::= Name {‘.’ Name} [‘:’ Name]
Оператор
function f () body end
переводится в
f = function () body end
Оператор
function t.a.b.c.f () body end
переводится в
t.a.b.c.f = function () body end
Оператор
local function f () body end
переводится в
local f; f = function () body end
а не в
local f = function () body end
(Это имеет значение только тогда, когда тело функции
содержит рекурсивные ссылки на f.)
Аналогично, оператор
global function f () body end
переводится в
global f; global f = function () body end
Второе global делает присваивание инициализацией, которая вызовет ошибку, если эта глобальная переменная уже определена.
Двоеточие в синтаксисе
используется для эмуляции методов,
добавляя к функции неявный дополнительный параметр self.
Таким образом, оператор
function t.a.b.c:f (params) body end
является синтаксическим сахаром для
t.a.b.c.f = function (self, params) body end
Определение функции — это исполняемое выражение, значение которого имеет тип function. Когда Lua предкомпилирует блок, все его тела функций также предкомпилируются, но ещё не создаются. Затем, когда Lua выполняет определение функции, функция создаётся (или закрывается). Этот экземпляр функции, или замыкание, является конечным значением выражения.
Результаты возвращаются с помощью оператора return (см. §3.3.4). Если управление достигает конца функции, не встретив оператор return, функция возвращает без результатов.
Существует зависящее от системы ограничение на количество значений, которые функция может вернуть. Гарантируется, что это ограничение составляет не менее 1000.
Параметры
Параметры действуют как локальные переменные, которые инициализируются значениями аргументов:
parlist ::= namelist [‘,’ varargparam] | varargparam varargparam ::= ‘...’ [Name]
Когда вызывается функция Lua,
она подстраивает свой список аргументов до
длины своего списка параметров (см. §3.4.12),
если только функция не является вариативной функцией,
что обозначается тремя точками ('...')
в конце её списка параметров.
Вариативная функция не подстраивает свой список аргументов;
вместо этого она собирает все дополнительные аргументы и передаёт их
функции через таблицу vararg.
В этой таблице
значения с индексами 1, 2 и т. д. являются дополнительными аргументами,
а значение с индексом "n" — количество дополнительных аргументов.
В качестве примера рассмотрим следующие определения:
function f(a, b) end
function g(a, b, ...) end
function r() return 1,2,3 end
Тогда мы имеем следующее отображение аргументов в параметры и в таблицу vararg:
CALL PARAMETERS
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, va. table -> {n = 0}
g(3, 4) a=3, b=4, va. table -> {n = 0}
g(3, 4, 5, 8) a=3, b=4, va. table -> {5, 8, n = 2}
g(5, r()) a=5, b=1, va. table -> {2, 3, n = 2}
Таблица vararg в вариативной функции может иметь необязательное имя, задаваемое после трёх точек. Если оно присутствует, это имя обозначает доступную только для чтения локальную переменную, которая ссылается на таблицу vararg. Если таблица vararg не имеет имени, к ней можно получить доступ только через выражение vararg.
Выражение vararg также записывается как три точки,
и его значением является список значений в таблице vararg,
от 1 до целочисленного значения по индексу "n".
(Следовательно, если код не изменяет таблицу vararg,
этот список соответствует дополнительным аргументам в вызове функции.)
Этот список ведёт себя как результаты
функции с несколькими результатами (см. §3.4.12).
В качестве оптимизации,
если таблица vararg удовлетворяет некоторым условиям,
код не создаёт фактическую таблицу, а вместо этого переводит
выражения индексирования и выражения vararg
в обращения к внутренним данным vararg.
Условия следующие:
если таблица vararg имеет имя,
это имя не является внешней локальной переменной (upvalue) во вложенной функции
и используется только как базовая таблица
в синтаксических конструкциях t[exp] или t.id.
Обратите внимание, что анонимная таблица vararg всегда удовлетворяет этим условиям.
3.4.12 – Списки выражений, множественные результаты и подстройка
Как вызовы функций, так и выражения vararg могут давать несколько значений. Эти выражения называются многорезультатными выражениями.
Когда многорезультатное выражение используется как последний элемент списка выражений, все результаты этого выражения добавляются в список значений, производимых списком выражений. Обратите внимание, что единственное выражение в месте, где ожидается список выражений, является последним выражением в этом (одноэлементном) списке.
Вот места, где Lua ожидает список выражений:
- Оператор return,
например
return e1,e2,e3(см. §3.3.4). - Конструктор таблицы,
например
{e1,e2,e3}(см. §3.4.9). - Аргументы вызова функции,
например
foo(e1,e2,e3)(см. §3.4.10). - Множественное присваивание,
например
a,b,c = e1,e2,e3(см. §3.3.3). - Локальное или глобальное объявление, которое аналогично множественному присваиванию.
- Начальные значения в обобщённом цикле for,
например
for k in e1,e2,e3 do ... end(см. §3.3.5).
В последних четырёх случаях список значений из списка выражений должен быть подстроен до определённой длины: количества параметров при вызове невариативной функции (см. §3.4.11), количества переменных в множественном присваивании или объявлении и ровно четырёх значений для обобщённого цикла for. Подстройка следует этим правилам: если значений больше, чем нужно, лишние значения отбрасываются; если значений меньше, чем нужно, список дополняется nil. Когда список выражений заканчивается многорезультатным выражением, все результаты этого выражения входят в список значений перед подстройкой.
Когда многорезультатное выражение используется в списке выражений, не будучи последним элементом, или в месте, где синтаксис ожидает одно выражение, Lua подстраивает список результатов этого выражения к одному элементу. В частности, синтаксис ожидает одно выражение внутри выражения в круглых скобках; поэтому добавление круглых скобок вокруг многорезультатного выражения заставляет его выдать ровно один результат.
Нам редко требуется использовать выражение vararg в месте, где синтаксис ожидает одно выражение. (Обычно проще добавить обычный параметр перед вариативной частью и использовать этот параметр.) Когда такая необходимость возникает, мы рекомендуем присвоить выражение vararg одной переменной и использовать эту переменную вместо него.
Вот несколько примеров использования многорезультатных выражений. Во всех случаях, когда конструкции нужен "n-й результат", а такого результата нет, используется nil.
print(x, f()) -- prints x and all results from f().
print(x, (f())) -- prints x and the first result from f().
print(f(), x) -- prints the first result from f() and x.
print(1 + f()) -- prints 1 added to the first result from f().
local x = ... -- x gets the first vararg argument.
x,y = ... -- x gets the first vararg argument,
-- y gets the second vararg argument.
x,y,z = w, f() -- x gets w, y gets the first result from f(),
-- z gets the second result from f().
x,y,z = f() -- x gets the first result from f(),
-- y gets the second result from f(),
-- z gets the third result from f().
x,y,z = f(), g() -- x gets the first result from f(),
-- y gets the first result from g(),
-- z gets the second result from g().
x,y,z = (f()) -- x gets the first result from f(), y and z get nil.
return f() -- returns all results from f().
return x, ... -- returns x and all received vararg arguments.
return x,y,f() -- returns x, y, and all results from f().
{f()} -- creates a list with all results from f().
{...} -- creates a list with all vararg arguments.
{f(), 5} -- creates a list with the first result from f() and 5.