7 – Lua как самостоятельное приложение
Categories:
Оглавление
7 – Lua как самостоятельное приложение
Хотя Lua был разработан как язык расширения для встраивания в хост-программу на C, он также часто используется как самостоятельный язык. Интерпретатор для Lua как самостоятельного языка, называемый просто lua, поставляется со стандартным дистрибутивом. Автономный интерпретатор включает все стандартные библиотеки. Его использование:
lua [options] [script [args]]
Опции следующие:
-e stat: выполнить строкуstat;-i: войти в интерактивный режим после выполнения скрипта;-l mod: выполнитьrequire "mod"и присвоить результат глобальной переменнойmod;-l g=mod: выполнитьrequire "mod"и присвоить результат глобальной переменнойg;-v: вывести информацию о версии;-E: игнорировать переменные окружения;-W: включить предупреждения;--: прекратить обработку опций;-: выполнить стандартный ввод (stdin) как файл и прекратить обработку опций.
После обработки своих опций lua запускает указанный скрипт. При вызове без аргументов lua ведет себя как lua -v -i, если стандартный ввод (stdin) является терминалом, и как lua - в противном случае.
При вызове без опции -E интерпретатор проверяет переменную окружения LUA_INIT_5_5 (или LUA_INIT, если версионированное имя не определено) перед выполнением любого аргумента. Если содержимое переменной имеет формат @filename, то lua выполняет этот файл. В противном случае lua выполняет саму строку.
При вызове с опцией -E Lua не проверяет никакие переменные окружения. В частности, значения package.path и package.cpath устанавливаются с путями по умолчанию, определенными в luaconf.h. Чтобы сигнализировать библиотекам, что эта опция включена, автономный интерпретатор устанавливает поле "LUA_NOENV" в реестре в истинное значение. Другие библиотеки могут проверять это поле с той же целью.
Опции -e, -l и -W обрабатываются в порядке их появления. Например, вызов вида
$ lua -e 'a=1' -llib1 script.lua
сначала установит a в 1, затем выполнит require для библиотеки lib1 и, наконец, запустит файл script.lua без аргументов. (Здесь $ — приглашение командной оболочки. Ваше приглашение может отличаться).
Перед выполнением любого кода lua собирает все аргументы командной строки в глобальную таблицу arg. Имя скрипта помещается в индекс 0, первый аргумент после имени скрипта — в индекс 1, и так далее. Любые аргументы перед именем скрипта (то есть имя интерпретатора плюс его опции) помещаются в отрицательные индексы. Например, в вызове
$ lua -la b.lua t1 t2
таблица выглядит так:
arg = { [-2] = "lua", [-1] = "-la",
[0] = "b.lua",
[1] = "t1", [2] = "t2" }
Если в вызове нет скрипта, имя интерпретатора помещается в индекс 0, за ним следуют остальные аргументы. Например, вызов
$ lua -e "print(arg[1])"
выведет "-e". Если есть скрипт, скрипт вызывается с аргументами arg[1], ···, arg[#arg]. Как и все чанки в Lua, скрипт компилируется как вариадическая функция.
В интерактивном режиме Lua многократно выводит приглашение и ожидает строку. После чтения строки Lua сначала пытается интерпретировать строку как выражение. Если это удается, он выводит его значение. В противном случае он интерпретирует строку как чанк. Если вы вводите незавершенный чанк, интерпретатор ожидает его завершения, выдавая другое приглашение.
Обратите внимание, что, поскольку каждая полная строка читается как новый чанк, локальные переменные не переживают строки. Чтобы избежать путаницы, интерпретатор выдает предупреждение, если строка начинается с зарезервированного слова local:
> x = 20 -- глобальная 'x'
> local x = 10; print(x)
--> warning: locals do not survive across lines in interactive mode
--> 10
> print(x) -- снова глобальная 'x'
--> 20
> do -- незавершенный чанк
>> local x = 10; print(x) -- '>>' приглашение для завершения строки
>> print(x)
>> end -- чанк завершен
--> 10
--> 10
Если глобальная переменная _PROMPT содержит строку, то ее значение используется в качестве приглашения. Аналогично, если глобальная переменная _PROMPT2 содержит строку, ее значение используется в качестве вторичного приглашения (выдаваемого во время незавершенных инструкций).
В случае незащищенных ошибок в скрипте интерпретатор сообщает об ошибке в стандартный поток ошибок. Если объект ошибки не является строкой, но имеет метаметод __tostring, интерпретатор вызывает этот метаметод для создания итогового сообщения. В противном случае интерпретатор преобразует объект ошибки в строку и добавляет к нему трассировку стека. Когда предупреждения включены, они просто выводятся в стандартный вывод ошибок.
При нормальном завершении интерпретатор закрывает свое главное состояние Lua (см. lua_close). Скрипт может избежать этого шага, вызвав os.exit для завершения.
Чтобы позволить использовать Lua в качестве интерпретатора скриптов в системах Unix, Lua пропускает первую строку файла чанка, если она начинается с #. Поэтому Lua-скрипты можно сделать исполняемыми программами, используя chmod +x и форму #!, как в
#!/usr/local/bin/lua
Конечно, расположение интерпретатора Lua на вашей машине может отличаться. Если lua находится в вашем PATH, то
#!/usr/bin/env lua
является более переносимым решением.
8 – Несовместимости с предыдущей версией
Здесь мы перечисляем несовместимости, с которыми вы можете столкнуться при переходе программы с Lua 5.4 на Lua 5.5.
Вы можете избежать некоторых несовместимостей, скомпилировав Lua с соответствующими опциями (см. файл luaconf.h). Однако все эти опции совместимости будут удалены в будущем. Чаще всего проблемы совместимости возникают именно при удалении этих опций. Поэтому, когда у вас есть возможность, старайтесь тестировать свой код с версией Lua, скомпилированной со всеми отключенными опциями совместимости. Это облегчит переходы на более новые версии Lua.
Версии Lua всегда могут изменять C API способами, которые не подразумевают изменений в исходном коде программы, например, числовые значения констант или реализацию функций в виде макросов. Поэтому никогда не следует предполагать, что двоичные файлы совместимы между разными версиями Lua. Всегда перекомпилируйте клиентов Lua API при использовании новой версии.
Аналогично, версии Lua всегда могут изменять внутреннее представление предварительно скомпилированных чанков; предкомпилированные чанки несовместимы между разными версиями Lua.
Стандартные пути в официальном дистрибутиве могут меняться между версиями.
8.1 – Несовместимости в языке
- Слово
globalявляется зарезервированным словом. Не используйте его как обычное имя. - Управляющая переменная в циклах
forдоступна только для чтения. Если вам нужно ее изменить, объявите локальную переменную с тем же именем в теле цикла. - Цепочка метаметодов
__callможет содержать не более 15 объектов. - При ошибке
nilв качестве объекта ошибки заменяется строковым сообщением.
8.2 – Несовместимости в библиотеках
- Параметры сборки мусора не устанавливаются опциями
"incremental"и"generational"; вместо этого для этой цели есть новая опция"param". Более того, были внесены некоторые изменения в сами параметры.
8.3 – Несовместимости в API
- В
lua_callи связанных функциях максимальное значение для количества требуемых результатов (nresults) составляет 250. Если вам действительно нужно большее значение, используйтеLUA_MULTRET, а затем настройте размер стека. Ранее этот предел не был указан. lua_newstateимеет третий параметр — начальное значение для хеширования строк.- Функция
lua_resetthreadустарела; она эквивалентнаlua_closethreadсfrom, равнымNULL. - Функция
lua_setcstacklimitустарела. Вызовы к ней можно просто удалить. - Функция
lua_dumpизменила способ сохранения стека при вызовах функции-писателя. (Это не было указано в предыдущих версиях). Кроме того, она вызывает функцию-писатель один дополнительный раз, чтобы сигнализировать о конце дампа. - Параметры сборки мусора не устанавливаются опциями
LUA_GCINCиLUA_GCGEN; вместо этого для этой цели есть новая опцияLUA_GCPARAM. Более того, были внесены некоторые изменения в сами параметры. - Функция
lua_pushvfstringтеперь сообщает об ошибках, а не возбуждает их.
9 – Полный синтаксис Lua
Здесь представлен полный синтаксис Lua в расширенной БНФ. Как обычно в расширенной БНФ, {A} означает 0 или более A, а [A] означает необязательное A. (Приоритеты операторов см. в §3.4.8; описание терминалов Name, Numeral и LiteralString см. в §3.1).
chunk ::= block
block ::= {stat} [retstat]
stat ::= ‘;’ |
varlist ‘=’ explist |
functioncall |
label |
break |
goto Name |
do block end |
while exp do block end |
repeat block until exp |
if exp then block {elseif exp then block} [else block] end |
for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end |
for namelist in explist do block end |
function funcname funcbody |
local function Name funcbody |
global function Name funcbody |
local attnamelist [‘=’ explist] |
global attnamelist |
global [attrib] ‘*’
attnamelist ::= [attrib] Name [attrib] {‘,’ Name [attrib]}
attrib ::= ‘<’ Name ‘>’
retstat ::= return [explist] [‘;’]
label ::= ‘::’ Name ‘::’
funcname ::= Name {‘.’ Name} [‘:’ Name]
varlist ::= var {‘,’ var}
var ::= Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name
namelist ::= Name {‘,’ Name}
explist ::= exp {‘,’ exp}
exp ::= nil | false | true | Numeral | LiteralString | ‘...’ | functiondef |
prefixexp | tableconstructor | exp binop exp | unop exp
prefixexp ::= var | functioncall | ‘(’ exp ‘)’
functioncall ::= prefixexp args | prefixexp ‘:’ Name args
args ::= ‘(’ [explist] ‘)’ | tableconstructor | LiteralString
functiondef ::= function funcbody
funcbody ::= ‘(’ [parlist] ‘)’ block end
parlist ::= namelist [‘,’ varargparam] | varargparam
varargparam ::= ‘...’ [Name]
tableconstructor ::= ‘{’ [fieldlist] ‘}’
fieldlist ::= field {fieldsep field} [fieldsep]
field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
fieldsep ::= ‘,’ | ‘;’
binop ::= ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘//’ | ‘^’ | ‘%’ |
‘&’ | ‘~’ | ‘|’ | ‘>>’ | ‘<<’ | ‘..’ |
‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ |
and | or
unop ::= ‘-’ | not | ‘#’ | ‘~’