Lua

Lua(лу́а, спорт.—«луна») —скриптовыйязык программирования, разработанный в подразделении Tecgraf (Computer Graphics Technology Group)Католического университета Рио-де-Жанейро(Бразилия). Интерпретатор языка являетсясвободно распространяемым, с открытым исходным кодом наязыке программирования Си.
По идеологии и реализации язык Lua ближе всего кJavaScript, в частности, он также реализуетпрототипнуюмодельООП, но отличается Паскале-подобным синтаксисом и более мощными и гибкими конструкциями. Характерной особенностью Lua является реализация большого числа программных сущностей минимумом синтаксических средств. Так, все составные пользовательские типы данных (массивы,структуры,множества,очереди,списки) реализуются через механизмтаблиц, а механизмыобъектно-ориентированного программирования, включаямножественное наследование— с использованиемметатаблиц, которые также отвечают заперегрузку операцийи ряд других возможностей.
Lua предназначен для пользователей, не являющихся профессиональными программистами, вследствие чего большое внимание уделено простоте дизайна и лёгкости обучения. Язык широко используется для создания тиражируемого программного обеспечения (например, на нём написан графический интерфейс пакетаAdobe Lightroom). Также получил известность как язык программирования уровней и расширений во многих играх, в том числеGarry’s Mod,Roblox,Minetest.
Язык разработан подразделением Tecgraf (группа технологий компьютерной графики) Католического университета Рио-де-Жанейро в Бразилии, история языка ведёт отсчёт с 1993 года. Авторы языка —Роберту Иерузалимски, Луиш Энрике ди Фигейреду (Luiz Henrique de Figueiredo) и Валдемар Селиш (Waldemar Celes). Lua распространяется свободно, с открытым исходным кодом наязыке Си.
Как отметил Луиш Энрике ди Фигейреду, Lua — единственный язык программирования, разработанный вразвивающейся странеи получивший всемирное признание, которое, в частности, выразилось в приглашении на конференциюHOPL.
Историческими родителями языка были языки конфигурирования и описания данныхSOL(Simple Object Language) иDEL(Data-Entry Language), они были независимо разработаны в Tecgraf в 1992—1993 годах для добавления некоторой гибкости в два отдельных проекта (оба были интерактивными графическими приложениями для конструкторских нужд в компанииPetrobras). В SOL и DEL отсутствовали какие-либо управляющие конструкции, и Petrobras чувствовал растущую необходимость в добавлении к ним полноценного программирования.
Как пишет автор языка вThe Evolution of Lua:
Lua 1.0 была спроектирован таким образом, что конструкторы объектов, тогда чуть отличавшиеся от текущего лёгкого и гибкого стиля, включали в себя синтаксис языка SOL (отсюда название Lua: по-португальскиsol— «солнце»,lua— «луна»). Управляющие конструкции Lua в основном заимствованы изМодулы-2(if, while, repeat/until), хотя на них также повлиялиКлу(параллельное присваивание, множественноевозвращаемое значение функциикак более простая альтернатива вместопередачи параметров по ссылкеили явныхуказателей),C++(«отличная идея объявлятьлокальные переменныелишь тогда, когда они нужны»),Сноболиawk(ассоциативные массивы). Создатели Lua также признают, что единый вездесущий механизм структурирования данных в Лиспе и Scheme (связный список) оказал большое влияние на их решение о выборе таблиц в качестве основной структуры данных для Lua.
Версии Lua вплоть до 5.0 выпускались под лицензией, подобнойлицензии BSD. Начиная с версии 5.0 и выше Lua распространяется подлицензией MIT. Обе лицензии являютсяразрешительнымии практически идентичны.
Язык предназначен для использования в качестве отдельного либо встроенного в приложение скриптового языка. Он изначально создавался достаточно простым и компактным, чтобы поместиться на различных платформах и обеспечить приемлемую производительность. Также при проектировании учитывались требования простоты обучения и возможности использования не профессиональными программистами.
Lua — этопроцедурныйдинамически типизированныймодульныйязык савтоматическим управлением памятью. Включает базовые элементы для поддержкифункциональногоиобъектногостилей программирования. Таким образом, язык можно cчитатьмультипарадигменным. Встроенные средства параллельного программирования позволяют писать многопоточные программы только средствами языка, не обращаясь к API операционной системы или внешним библиотекам. Так как основным назначением Lua является встраивание, он имеет эффективные средства межъязыкового взаимодействия, ориентированные, главным образом, на вызов библиотекСии на работу в Си-окружении.
Язык поддерживает небольшое количество встроенных типов данных: логические значения, числа, строки, функции, потоки. Типичные комбинированные структуры данных, такие какмассивы,наборы,спискиизаписи, отсутствуют, вместо всех их используется одна базовая структура Lua — таблица (см. ниже). Отдельный типuserdataпредназначен специально для низкоуровневого программирования и обмена данными с внешним кодом на других языках. Функции в Lua являются объектами первого класса, могут присваиваться и передаваться в параметрах. Поддерживаются замыкания, есть возможность создания функций высших порядков. Объектная система прототипная, отсутствует явная поддержканаследования, однако оно легко реализуется с помощьюметатаблиц.
Вообще, Lua стремится обеспечить гибкие метафункции, которые могут быть расширены по мере необходимости, а не поставлять набор функций, специфичных для конкретной парадигмы программирования. Как результат, основа языка проста и легко адаптируема к большинству приложений. Предоставляя минимальный набор базовых средств, Lua пытается найти баланс между мощностью и размером.
Синтаксис Lua в основном построен на основе поздних Паскале-подобных языков, таких какМодула-2илиОберон. Формат записи текста — свободный, команды в тексте программы разделяются любыми пробельными символами. Допускается, но не является обязательным применение точки с запятой для разделения операций.
В одном из интервью Роберту Иерузалимски заметил, что синтаксис Lua — это компромиссное решение, которое он был вынужден принять, чтобы упростить освоение языка непрофессиональными программистами. Он охарактеризовал этот синтаксис как «довольно многословный», отметив, что лично для себя предпочёл бы более краткуюнотацию.
Основным алфавитом языка является английский, и в строковых литералах допускаются знаки других языков, идентификаторы которых могут состоять из букв, цифр и знаков подчеркивания, но они не могут начинаться с цифры или совпадать с одним из ключевых слов. В языковом руководстве не рекомендуется использовать идентификаторы, начинающиеся со знака подчеркивания, поскольку такие идентификаторы используются в систематических целях.
Язык регистрозависимый, все ключевые слова пишутся в нижнем регистре, идентификаторы, различающиеся только регистром букв, считаются различными. Следующие 22 ключевых слова не могут быть использованы для имён:
Для комментариев используется синтаксис, аналогичный реализованному вАде,SQLиVHDL:
Lua представляет собой язык с неявнымдинамическимопределениемтипов данных.Переменнаяязыка может содержать значения любого типа. Все значения в Lua могут храниться в переменных, использоваться в качествеаргументовпри вызовефункцийи возвращаться в виде результата их выполнения.
В Lua восемь основных типов:
nil— это тип значения nil [пустое значение], главное свойство которого — отличаться от всех остальных значений и обозначать отсутствие пригодного значения.
К типуbooleanотносятся значения false (ложь) и true (истина).
К типуnumberотносятся обычно вещественные числа (double). В первых версиях Lua целые числа не выделялись в отдельный тип; такое решение мотивируется тем, что вещественное представление позволяет точно представить достаточно широкий диапазон целых чисел. Начиная с версии 5.3 добавлена возможность явного определения целого или вещественного формата числа. Внутреннее представление чисел можно изменить при сборке интерпретатора.
Типstringобозначает массивы символов. Строки Lua могут содержать любые 8-битные символы, включая ноль ('\0'). Строки неизменяемы. Строковые литералы могут записываться в одинарных или двойных кавычках, служебные символы помещаются в них в стандартной для C нотации с ведущим обратным слэшем. Многострочные литералы ограничиваются двумя подряд открывающимися и двумя подряд закрывающимися квадратными скобками.
Встроенная в язык поддержка Юникода отсутствует, хотя допускается использование символов UTF-8 в строковых литералах, а сама система представления UTF-8 позволяет вводить, выводить и частично обрабатывать строки в этой кодировке стандартными системными средствами. В последние версии Lua входит библиотека utf8, обеспечивающая более развитую поддержку UTF-8, существуют также библиотеки сторонних разработчиков, предоставляющие средства работы с Юникод-строками в различных кодировках.
Функции в Lua являются полноправными объектами, допускающими присваивание, передачу функции в параметре и возврат функции как одного из значений. Типthreadимеют сопрограммы, типuserdataпредназначен для представления внешних данных, полученных или предоставляемых из/в код на другом языке (главным образом, на C/C++).
Все арифметические операторы поддерживают вещественные операнды, давая предсказуемый результат. Так,x^0.5возвращает квадратный корень изx,x^(-1/3)— значение, обратное кубическому корню изx. Оператор%определяется выражением:a % b = a - math.floor(a / b) * b, где функцияmath.floor()вычисляет целую часть своего аргумента. Для целых аргументов его результат вполне обычен. Для вещественного делимого нужно учитывать, что операция не производит никаких дополнительных округлений или отбрасывания дробной части, поэтому результат сохранит дробную часть делимого. Например,math.pi % 2вернёт не1, а1.1415926535898. Такая реализация даёт некоторые дополнительные возможности. Например, для усеченияxдо трёх знаков после запятой достаточно взять выражениеx = x % 0.001
Таблица в Lua — этодинамическийгетерогенныйассоциативный массив, то есть множество пар «ключ-значение». Ключами могут быть значения любых типов Lua, кромеnil. Ключи также могут быть литералами (идентификаторами) Lua. Записьnilв элемент таблицы равносильна удалению данного элемента.
Таблицы являются единственным в Lua составным типом данных. Они являются фундаментом для всех пользовательских типов данных, таких какструктуры,массивы,множестваи другие:
Мультимножества (множества, которые могут содержать более одного экземпляра одного и того же элемента) реализуются аналогично последнему примеру, только в качестве значений используются не логические, а целые — счётчики числа соответствующих элементов в множестве. Связанные списки могут быть представлены как массивы двухэлементных массивов, хранящих значение и ссылку на следующий элемент. Многомерные массивы могут быть реализованы как массивы массивов. Более сложные структуры, такие как очереди, графы, сети также реализуются на основе таблиц, конкретный способ реализации определяется задачей.
Lua поддерживает концепциюзамыканий, например:
Каждый раз, когда вызываетсяmakeaddfunc, создаётся новое замыкание для переменнойx, так что каждая возвращаемая анонимная функция будет ссылаться на свой параметрx. Как и у любого другого объекта Lua, временем жизни замыкания управляет сборщик мусора.
Механизмметатаблицобеспечивает многие возможности, в других языках предоставляемые за счёт введения отдельных синтаксических механизмов. Метатаблицы по структуре являются обычными таблицами Luа, подчиняющимися всем правилам и ограничениям языка. Особенность их состоит в применении. Метатаблица хранит дополнительные метаданные типов и объектов, то есть информацию о параметрах и функциях, связанных с ними. Сведения, хранящиеся в метатаблицах, используются интерпретатором Lua, их использование позволяет изменить или расширить функциональность программных объектов.
Метатаблица в Lua может быть связана со значением любого типа. Скалярные типы данных (все, кроме userdata и таблиц) имеют общие метатаблицы для каждого типа. Таблицы и значения типаuserdataимеют индивидуальные ссылки на метатаблицы в каждом экземпляре. Изменять метатаблицы всех типов, кроме таблиц, можно только посредством внешнего кода на Си. Непосредственно из Lua доступны только метатаблицы таблиц.
Созданная «с нуля» таблица Lua не имеет метатаблицы (её ссылка на метатаблицу равна nil). Но метатаблица для неё может быть в любой момент создана либо получена от другой таблицы. Встроенная функцияgetmetatable(t)возвращает метатаблицу таблицы t, а функцияsetmetatable(t, m)устанавливает для таблицы t метатаблицу m.
Для метатаблиц документирован набор полей, которые могут использоваться интерпретатором языка. Для указания на особую роль этих полей для них принято специальное правило именования: их идентификаторы начинаются с двух подчёркиваний. Некоторые из таких полей содержат информацию о специфических свойствах объекта, к которому относится метатаблица. Например, параметр__mode, когда он задан, может превратить таблицу вслабую, то есть таблицу, все ссылки на объекты которой являютсяслабыми ссылками. Но значениями большинства возможных полей метатаблицы являются так называемыеметаметоды, то есть ссылки на функции, которые интерпретатор вызывает при определённых условиях. Общая логика использования метаметодов интерпретатором состоит в следующем: когда интерпретатор встречает в программе операцию, которая не определена для объекта-операнда, он обращается к связанной с операндом метатаблице, находит в ней соответствующий метаметод и вызывает его.
В Lua поддерживаются метаметоды для всех арифметических операций и операций сравнения, так что с их помощью можно реализовать арифметику для любых объектов, созданных программистом. Помимо стандартных, можно использовать так называемые «библиотечные» метаметоды, которые поддерживаются не ядром языка, а конкретными библиотеками. В примере выше это метаметод__tostring, поддерживаемый библиотекой string; этот метод выполняет конвертацию таблицы в строку.
Наибольший интерес представляет поле__index. Обращение к нему происходит тогда, когда интерпретатор пытается прочитать элемент таблицы, но не находит его. Поле__indexможет ссылаться либо на таблицу, либо на метод. В первом случае интерпретатор, не найдя искомого значения в основной таблице, будет искать его в таблице__index. Во втором вместо обращения к таблице будет происходить вызов этого метода. Задавая таблицы или метаметоды для данного поля, в Lua можно реализовать наследование, сокрытие данных объекта, отслеживание операций с данными таблицы и многое другое.
Основой для ООП в Lua являются таблицы. В принципе, таблица и есть объект в ООП-смысле, так как она может иметь поля, именованные с помощью идентификаторов, и хранить в этих полях произвольные значения (свойства объекта) и функции для реализации поведения объекта (методы объекта). Некоторый синтаксический сахар, предоставляемый Lua, делает описание и обращение с объектами более привычным для программистов, имеющих опыт работы с традиционными ООП-языками. Понятия «класса» в Lua нет, поэтому описывается отдельный объект и все поля и методы относятся именно к нему. Свойства описываются аналогично элементам таблицы с ключами-идентификаторами, методы — как поля-функции. Подобно классическому Оберону, описание методов включает явное указание в первом параметре так называемого «получателя» — параметра, который при вызове метода ссылается на объект, для которого он вызван. Но, помимо стандартного обращения к полю таблицы через точку, которое требует и в вызове метода явно указывать получателя, Lua поддерживает дополнительный синтаксис: когда в вызове или описании метода его заголовок записываются в виде «Объект:метод», то получатель не указывается. При этом в теле метода он всё равно доступен под именемself:
Наследование, в том числе множественное, реализуется с помощью метатаблиц и метаметодов. Также с помощью метаметодов можно реализовать сокрытие данных и контролируемый доступ к полям таблицы-объекта. Если сравнивать данный подход с другими языками, где всё вышеперечисленное реализуется с помощью специальных языковых средств, то можно заметить, что реализация Lua сложнее и требует более тщательного кодирования, но обеспечивает бо́льшую гибкость и упрощает интерпретатор.
Классическая программа «Hello, world!» на Lua выглядит так:
Факториал— примеррекурсивнойфункции:
Цикл со счётчиком:
Работа с функциями как собъектами первого классадемонстрируется в следующем примере, в котором модифицируется поведение функции print:
Любой будущий вызовprintтеперь будет перенаправлен к новой функции, и благодаря поддержке в Luaлексического контекстастарая функция print будет доступна только посредством новой, модифицированной функции print. Lua также поддерживаетзамыкания, как описано выше, в соответствующем разделе.
Ключевой особенностью Lua является расширяемая семантика, механизм метатаблиц даёт большие возможности по настройке уникального поведения для таблиц Lua. В следующем примере демонстрируется «бесконечная» таблица. Для любогоn{\displaystyle n}fibs[n]дастn{\displaystyle n}-ечисло Фибоначчис использованиеммемоизации.
Lua позволяет использовать логические операторыandиorдля вводатернарных конструкций, как, например, вC#, или обращение к одному из существующих объектов.
Обращение к существующей таблице и получение значения по первому индексу:
Вызов функции из одной из существующих таблиц:
Как и многиеинтерпретируемые языки программирования, реализацияLuaимеет отдельнокомпиляторс исходного языка в исполняемыйбайт-кодивиртуальную машинудля исполнения сгенерированного байт-кода. Причём байт-код — это не команды стековой машины, а команды некоего виртуального процессора с несколькими регистрами, что повышает эффективность исполнения. В стандартной виртуальной машинеLuaиспользуется распределение памяти со сборкой мусора (аналогично Java или .NET).
Luaиспользует единыйстроковый пул, что позволяет снизить расходы памяти на хранение строк.
Для задач, критичных по времени, имеетсяJIT-компиляторLua— LuaJIT. Также разработан компилятор llvm-lua, генерирующий код для виртуальной машиныLLVM, предоставляющей возможность последующей компиляции в очень эффективный машинный код для процессоров различной архитектуры.
В настоящее время используется в различных проектах, где требуется встроить достаточно быстрый и нетрудный в освоениискриптовый языкпрограммирования — например, в разработкеигр, гдеLuaчасто используется в качестве прослойки междуигровым движкоми данными для написания сценариев поведения и взаимодействия объектов. Благодаря компактности применим и в портативных устройствах, в частности, один из графических микрокалькуляторовTexas Instruments, а именно, TI-Nspire CX, использует язык LUA помимо традиционного для такого класса устройствБейсика.
Первыми в разработку компьютерных игр языкLuaвнедрила компанияLucasArtsначиная с игрыGrim Fandango. Авторы языка в своём докладе на конференцииHOPLвспоминают, что в январе 1997 они получили сообщение от Брета Могилефски, главного разработчика Grim Fandango, где он писал, что, прочитав о языке в статье 1996 года вDr. Dobb’s Journal, он планирует заменить используемый ими самодельный скриптовый языкSCUMMнаLua. В результате им был создан игровой движокGrimE, используемый также более поздним квестом от LucasArts —Escape from Monkey Island.
В 2003 году в результате опроса на сайтеGameDev.netLuaбыл признан самым популярным скриптовым языком для разработки игр.
Примером игры, программируемой с помощьюLua, являетсяWorld of Warcraft. На языкеLuaописываются уровни игры-головоломкиEnigma.
Доступен рядсвободныхигровых движков, программируемых на Lua, таких, какDefold,аркадныйдвижокLÖVE, игровой конструкторNovashellи ориентированный наквесты(преимущественно —текстовые)INSTEAD.
Также используется в авиасимуляторе X-Plane, в движкеX-RayдляS.T.A.L.K.E.R.
Для популярной игрыMinecraftсозданы модификации ComputerCraft и его более совершенный аналог OpenComputers, которые добавляют компьютеры, программируемые на языке Lua.
Известная играGarry's Modпрограммируется, а также поддерживает модификации, написанные на Lua.
КомандаCroteam(разработчикиSerious SamиThe Talos Principle) использует Lua в скриптах начиная с версии Serious Engine 3.5.
Для игрыGTA: San Andreasсоздаются модификации, написанные на языке Lua и поддерживаемые плагином Moonloader.Также играMulti Theft Autoподдерживает программирование скриптов на языке Lua.
Игровая платформаRobloxиспользует Lua в качестве языка кодирования игр и управления игровой средой.
Сообществом игрыSatisfactoryсоздан мод Ficsit-Networks, дающий возможность программировать какие-либо действия на языке Lua.
В игреFactorioиспользуется Lua для создания модов.
В игре Dual Universe используется для внутри игровой механики и программирования игровых блоков
Программа компьютерной вёрсткиLuaTeX, расширенная версияpdfTeX, использует Lua как встроенный скриптовый язык.
Пакетный менеджерRPMсодержит встроенный интерпретатор Lua.
Существует как минимум две «родные»среды разработкидля Lua:
Кроме того, Lua поддерживается некоторыми универсальными IDE, в частности:
Существовал модуль поддержки Lua для средыNetBeans, но его развитие прекратилось в 2013 году и он доступен только для версии NetBeans 7.4 и более ранних. В NetBeans 8 плагин не поддерживается.
История языка
Переводы руководств
Статьи и обзоры