7 – Lua как самостоятельное приложение

Использование интерпретатора Lua из командной строки, аргументы, интерактивный режим и переменные окружения.

Оглавление

  1. Использование интерпретатора
  2. Несовместимости с предыдущей версией
  3. Полный синтаксис Lua

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 | ‘#’ | ‘~’