Опубликована первая превью-версия Луа 5.2
Луа (Lua) — мощный, быстрый, лёгкий, расширяемый и встраиваемый скриптовый язык программирования. Луа удобно использовать для написания бизнес-логики приложений.
Несмотря на то, что исходный код Луа открыт, разработка новых версий языка — достаточно закрытый, консервативный и неспешный процесс (что, в случае с языком программирования, не так уж и плохо). Каждую новую версию языка в коммьюнити ждут с нетерпением и смакуют просачивающиеся на публику детали.
То, что выложено на публику даже не альфа — это просто снапшот рабочего кода. К релизу может измениться всё, что угодно.
Анонс здесь: http://article.gmane.org/gmane.comp.lang.lua.general/61229
Дополненный список изменений от авторов здесь: http://article.gmane.org/gmane.comp.lang.lua.general/61505
Скачать исходники можно здесь: http://www.lua.org/work/lua-5.2.0-work1.tar.gz
Сборка под Windows здесь: http://article.gmane.org/gmane.comp.lang.lua.general/61528
Посмотреть исходники в онлайне можно, например, здесь.
Update: Выложен 5.2.0-work2, анонс здесь.
Что изменилось
Официальной информации пока мало. Список изменений взят, в основном, из анализа diff-ов руководства пользователя. Детали можно найти там же. Изменения даны в произвольном порядке. Список, скорее всего, неполон и будет в меру сил уточняться.
Общие изменения
- ABI и байткод, как и ожидалось, несовместимы с 5.1.
- Почти все фичи, объявленные более неподдерживаемыми (deprecated) в 5.1 в новой версии удалены.
- Фичи, объявленные deprecated в 5.2 в этой версиии отключены по умолчанию. Для их включения нужно пересобирать интерпретатор.
Работа с окружениями из Lua
Это наиболее противоречивый набор изменений. Вокруг него в луашной рассылке сейчас ломается большая часть копий.
Lexical environments
Добавлены «лексические окружения» (lexical environments), позволяющие подменить для определённого куска кода глобальное окружение на указанную таблицу.
Новая функция loadin()
Добавлена новая функция loadin(), позволяющая загрузить код в заданное окружение:
Функции setfenv() и getfenv()
Функции setfenv() и getfenv() больше не поддерживаются. Вместо них предлагается использовать новые лексические окружения или новую функцию loadin().
Для страждущих оставлены debug.setfenv() и debug.getfenv().
У корутин больше нет отдельных окружений
Все корутины в стейте имеют одно общее фиксированное окружение.
Новые метаметоды
Метаметод __len работает для таблиц и строк
Код работы с таблицами и строками теперь обращает внимание на метаметод __len при определении длины данных.
Новые метаметоды __ipairs и __pairs
Теперь можно переопределять обход объекта при использовании ipairs и pairs.
Модуль debug
Модуль debug больше не подгружается по умолчанию
Если код его использует, нужно явно вызывать require(«debug»).
Новые функции для работы с upvalue
Добавлены debug.upvalueid(), debug.upvaluejoin() и соответствующие им lua_upvalueid() и lua_upvaluejoin(). (Часть из них пока не документирована.)
Теперь можно получить уникальный идентификатор upvalue (нужен, чтобы понять, указывают ли два upvalue на один и тот же объект).
При помощи upvaluejoin можно сделать, чтобы два разных upvalue указывали указывали на один объект. Это должно позволить делать сериализацию функций с upvalue без патчей кода Луа.
Расширена доступная отладочная информация
В записи, возвращаемой debug.getinfo() и lua_getinfo(), появились новые поля. Теперь о функции в стеке вызовов можно узнать следующее:
- была ли функция вызывана через tail call;
- число upvalue функции;
- число параметров функции;
- была ли функция объявлена как функция с переменным числом аргументов.
Прочие изменения в API Луа
Bitlib
Добавлена библиотека для выполнения бинарных операций.
Улучшено экранирование символов в %q
Теперь string.format("%q") экранирует все управляющие символы.
Frontier pattern
Шаблон поиска %f («frontier pattern») теперь документирован.
Изменено поведение ipairs()
Теперь при определении длины таблицы ipairs() следует общим правилам (раньше обход таблиц проводился строго до первой дырки).
Негативные числа в select()
Теперь select()-у можно передать в качестве номера первого аргумента выборки отрицательное число — будет возвращено соответствующее ему число аргументов с конца (в прямом порядке).
math.log10() больше не поддерживается
Теперь в math.log() можно указывать основание логарифма.
Функция table.maxn() больше не поддерживается
Если она вам и в самом деле нужна, напишите её сами.
Функции table.unpack() и table.pack()
Функция unpack() перенесена в модуль table. К ней в пару добавлена новая функция table.pack(), сохраняющая аргументы в новую таблицу (число аргументов сохраняется в поле «n» в этой таблице).
Фильтрация по типу чанка в load()
Функции load() теперь можно запретить загружать байт-код либо текстовые исходники.
Это полезно, поскольку, в отличие от текста, загружать байт-код из недоверенных источников не рекомендуется. Луа 5.2 больше не пытается валидировать корректность загружаемого байт-кода.
package.config теперь документирован
Теперь из Луа официально доступны настройки времени компиляции системы модулей:
- разделитель директорий в пути;
- разделитель путей в шаблоне поиска;
- символ для обозначения точек подстановки в шаблоне;
- символ для подстановки пути к исполнимому файлу, в котором выполняется скрипт (для Windows);
- символ границы значимой части имени файла для построения имени функции luaopen_* при открытии модуля.
Добавлена функция package.searchpath()
Функция, использующаяся для поиска файлов по заданному набору путей. (Та же, что используется в require.)
Аргументы в xpcall()
Теперь в xpcall() можно задавать аргументы для вызываемой функции, аналогично pcall().
Проверка аргументов в os.date()
Функция os.date() теперь проверяет переданную ей форматную строку с тем, чтобы обезопаситься от падучих реализаций strftime().
Улучшена поддержка пайпов
Если файл был открыт при помощи io.popen(), file:close() вернёт код завершения соответствующего ему процесса.
Улучшен интерфейс file:write()
Теперь file:write() возвращает file, что позволяет делать цепочку вызовов.
Сборщик мусора
Emergency GC
Луа форсирует полную сборку мусора если не может аллоцировать память.
Эфемерные таблицы
Сборщик мусора теперь корректно обрабатывает циклические ссылки между ключами и значениями в таблицах со слабыми ключами.
Скорректировано поведение инкрементального сборщика мусора
Попытка выполнения шага сборки мусора больше не перезапускает сборщик мусора если он был остановлен.
Остановлен ли GC?
Теперь можно узнать, остановлен ли GC. В Луа: collectgarbage(«isrunning»), в C: lua_gc(LUA_GCISRUNNING).
Прочие изменения в языке
Работа с локалью
Определение типа символа (ctype) при компиляции теперь полностью ведётся по внутренним фиксированным таблицам, не зависящим от текущей локали.
Идентификаторы могут использовать только символы, не зависящие от локали.
Шестнадцатиричные коды в строковых литералах
Теперь в строках можно писать, например, \xFF (раньше — только \255).
Упрощёна свёртка констант
Во избежание проблем с числами с плавающей точкой компилятор больше не делает свёртку констант (constant folding) для операторов деления и получения остатка от деления.
Улучшена поддержка нестроковых сообщений об ошибках
Если обработчику ошибок в интерпретаторе приходит вместо строки — сообщения об ошибке объект, он пытается вызвать метаметод __tostring перед выводом ошибки на экран.
Работа с окружениями из С API
Новые поля в реестре
В реестре (registry, специальная таблица, доступная только сишному коду) появились предустановленные поля, доступные по следующим целочисленным ключам:
- LUA_RIDX_MAINTHREAD — главная корутина текущего стейта (неявно создаётся вместе с ним);
- LUA_RIDX_GLOBALS — глобальное окружение луашного кода (таблица);
- LUA_RIDX_CPCALL — функция cpcall() для вызова сишных функций, работающих с Луа без создания для них замыканий (то есть для «незабинженных» функций). Функция lua_cpcall() была убрана из API.
Убран псевдоиндекс LUA_GLOBALSINDEX
Если окружение сишной функции не было изменено, вместо него можно использовать LUA_ENVIRONINDEX. Иначе нужно получить глобальное окружение из реестра.
Изменена логика работы макросов lua_getglobal(), lua_setglobal(), и lua_register()
Теперь они работают с окружением функций вместо глобального окружения стейта. Это больше соответствует тому, как Луа работает с глобальными переменными.
Прочие изменения в Lua C API
Переименована функция luaL_typerror()
Теперь она называется luaL_typeerror().
Добавлена функция lua_compare()
Её нужно использовать вместо более не поддерживаемых lua_equal() и lua_lessthan().
lua_arith()
Новая функция lua_arith() позволяет выполнять из C арифметические операции с луашными значениями по правилам Луа (с учётом метаметодов и проч.).
Определение длины объекта
Функция lua_objlen() переименована. Теперь она называется lua_rawlen(). Добавлена функция lua_len(), знающая про метаметод __len у таблиц.
Улучшена функция lua_checkstack()
Теперь гарантировано, что она не может вызвать ошибку выделения памяти.
Улучшены функции lua_pushstring() и lua_pushlstring()
Теперь они возвращают указатель на внутреннюю копию строки.
lua_copy()
Новая функция lua_copy() позволяет копировать значения на луашном стеке данных из одного слота в другой (при этом старое значение в другом слоте замещается копируемым).
Проверка версии рантайма
Теперь можно проверить версии рантайма Луа при помощи новых функций lua_version() и luaL_checkversion().
Больше того, поскольку эти функции возвращают указатели, можно проверить, что луашный стейт и выполняющийся сейчас код находятся в одном адресном пространстве. Это позволяет отловить ситуацию, когда Луа несколько раз слинкована с приложением.
Функция luaL_checkversion() выполняет такую проверку автоматически. Эту функцию вызывает luaL_register(), так что теперь соответствие рантаймов будет проверяться автоматически при подключении каждого модуля.
luaL_testudata()
Добавлена новая функция luaL_testudata() для теста userdata на принадлежность данному типу. (Раньше была доступна только валидация через luaL_checkudata(), вызывавшая ошибку при передаче userdata неверного типа.)
luaL_traceback()
Новая функция luaL_traceback(), чтобы делать стектрейсы из C, подобно debug.traceback() в Lua.
luaL_tolstring()
Функция luaL_tolstring() теперь документирована. Она позволяет конвертировать луашные значения аналогично функции tostring() в Луа. Реализовать свой собственный print() теперь проще чем когда бы то ни было!
Поддержка yield'ов через границу Луа—C
Добавлены новые методы API, позволяющие писать код на C, сквозь который можно было бы делать yield в Луа:
- lua_yieldk()
- lua_callk()
- lua_pcallk()
- lua_getctx()
Эти методы достаточно широко используются в самой реализации Луа 5.2, так что теперь можно будет делать yield через метаметоды, итераторы цикла for и функции pcall() и xpcall()!
Новый код ошибки LUA_ERRGCMM
Появился новый код ошибки LUA_ERRGCMM, означающий, что возникла ошибка при выполнении метаметода __gc при сборке мусора. (По понятным причинам, обычно не имеет отношения к коду на который указывает стектрейс.)
Для симметрии также добавлен код «ошибки» LUA_OK, означающий, что вызов был сделан успешно.
Улучшена загрузка динамических библиотек под никсами
Теперь loadlib корректно работает с библиотеками с глобальными символами (за счёт использования RTLD_GLOBAL).
Изменения в реализации
Увеличено максимальное число констант на функцию (чанк)
Теперь в одном чанке может быть до 226 констант (раньше было до 218). Превышение этого лимита вызывает ошибку времени компиляции «constant table overflow».
Теперь можно сохранять ещё более монструозные данные в виде луашных конструкторов таблиц, не заботясь о разбиении генерируемого кода на отдельные функции.
Оптимизирован парсер
Парсер теперь отъедает гораздо меньше сишного стека за счёт отказа от использования автоматических массивов (auto arrays).
Новая хэш-функция для чисел с плавающей запятой
Теперь хэширование выполняется корректно вне зависимости от размера lua_Number (раньше на некотрых 64-хбитных платформах возникали проблемы, если переопределить lua_Number в long double).
Известные проблемы в текущем снапшоте
- luac ещё не работает должным образом, в частности сломан дизассемблер байткода;
- код не собирается под Windows из-за конфликта с имёнем функции LoadString и проблем с макросом lua_number2uint() (в рассылке опубликованы неофициальные патчи);
- код пока не собирается как C++;
- в luaconf.h по умолчанию задан старый LUA_CPATH с «5.1» в пути;
- package.searchpath() пока ничего не знает про точки в имени модуля;
- документация пока в некотором беспорядке, поэтому не для всех новых функций понятно, будут ли они официальными, или останутся недокументированными.