GETTABUP 0  0 -1 ; _ENV "print"
LOADK    1 -2    ; "Hello, Lua"
CALL     0  2  1
RETURN   0  1

Я использую Lua уже несколько лет — я использовал его как кроссплатформенный язык сценариев, язык сценариев для игр, для создания приложений Linux, IRC-ботов, веб-серверов и всего остального, что только можно вообразить, но я продолжаю наблюдать одну постоянную тенденцию: Людям не нравится использовать Lua.

Почему люди не любят использовать Lua? Причин много, некоторые из них описаны в этой статье Тима Менша:

  1. LuaJIT сейчас находится в режиме обслуживания, никаких серьезных изменений выпущено не будет.
  2. У Lua есть несколько версий, которые имеют различия.
  3. Очевидно, у JavaScript лучшая экосистема.
  4. Lua Coroutines больше не монополия.
  5. По-видимому, требуются аннотации типов.

Теперь, риторически, почему любой из них является причиной покинуть Lua? Программа, которая не хочет выпускать какие-либо основные версии, может быть разветвлена ​​любым, кто захочет ее улучшить — к тому же такие проекты, как Ravi и LLVM-Lua, создают компиляторы Lua, оптимизированные для LLVM, так в чем же проблема? Что касается второй версии, многие языки имеют разные версии, которые не имеют обратной совместимости. Python имеет разницу между 2 и 3; JavaScript (на который вы часто будете слышать, как я жалуюсь) даже имеет транспилятор, чтобы сделать исходный код обратно совместимым. Что касается третьего пункта, у JavaScript гораздо больше пакетов, но это потому, что у JavaScript есть «ощущение», которое требует большого количества программных зависимостей. Для одного программного обеспечения (например, Polymer) нужно было бы установить десятки пакетов всего для нескольких элементов. Lua с меньшим количеством элементов, которые нужно поддерживать, никогда не было проблемой, потому что программное обеспечение работает и делает то, что нужно.

Я не считаю, что последние два пункта, перечисленные в списке, являются какими-либо проблемами. Тот факт, что одно программное обеспечение использует определенную технологию, не означает, что другое программное обеспечение не может иметь эту технологию и, следовательно, делает первое программное обеспечение менее ценным. Что касается последнего элемента, аннотации типов существуют в таких форматах, как Typed Lua и Ravi — первый из них компилируется с помощью Lua, а второй является специальным дополнением к виртуальной машине Lua 5.3. TypeScript действует так же, как Typed Lua, где Ravi на самом деле работает быстрее из-за соединений типов, выполняемых на стороне C. Ни один из этих пунктов не должен быть определяющим фактором языка, если оба языка имеют эти особенности.

Я начал эту статью со слов «Привет, Луа». Я хотел бы представить некоторые вещи, которые делают Lua языком, который, я считаю, делает его не имеющим аналогов среди других языков:

Луа это просто

Вы когда-нибудь смотрели на программу и думали: «Черт, это почти похоже на псевдокод или что-то, что я мог бы произнести вслух»? Если да, то вы, вероятно, использовали Lua раньше. Lua — один из самых читаемых языков программирования благодаря упрощенным правилам грамматики. Когда я пишу приложение на Lua, мне кажется, что я пишу документ. Большую часть времени я не документирую большую часть своего кода, потому что мне кажется, что он документирует сам себя из-за простоты. Англоподобная природа Lua делает его чрезвычайно удобочитаемым и простым для написания языком.

Луа быстрый

По сравнению со многими другими языками Lua и особенно LuaJIT оставляют эти языки далеко позади. Lua — очень простой язык, как и C, и из-за этого все делается с чрезвычайно высокой скоростью. Иногда LuaJIT работает даже быстрее, чем C. Из-за JIT-компиляции и простоты Lua является одним из самых быстрых языков, ноздря в ноздрю с JavaScript и C.

Связать ОЧЕНЬ легко

Допустим, у вас есть функция на C, но вы хотите вызвать ее в своем приложении Lua. В качестве примера мы будем использовать функцию POSIX fork(). Сначала мы вызываем функцию и сохраняем возвращаемое значение — целое число. Затем мы помещаем это целое число в стек Lua, чтобы его можно было вернуть из функции. Затем мы возвращаемся из функции, и виртуальная машина Lua возобновляет выполнение кода Lua.

int lua_fork(lua_State *L) {
  int fork_result = fork();
  lua_pushinteger(L, (lua_Integer)fork_result);
  return 1;
}

Создание библиотеки Lua также чрезвычайно простой процесс. Вы связываете имена с функциями, а затем вызываете функцию, которая помещает результат в стек Lua, после чего библиотека становится доступной через виртуальную машину Lua.

static const struct luaL_Reg fork_lib[] = {
  {"fork", lua_fork},
  {NULL, NULL}
}
int luaopen_util(lua_State *L) {
  luaL_newlib(L, fork_lib);
  return 1;
}

В Lua вы можете запросить эту библиотеку как «util» и вызвать функцию fork().

Интерфейс внешней функции

Если вы не являетесь поклонником функций привязки или не хотите компилировать библиотеку, вы также можете использовать стороннюю библиотеку интерфейса функций, например, встроенную в LuaJIT и внешнюю, портированную Facebook, luaffifb. . В качестве примера мы свяжем функцию fork(), как показано в предыдущем примере.

local ffi = require("ffi")
ffi.cdef[[int fork();]]
ffi.C.fork()

Используя этот базовый пример, вы теперь имеете системный вызов fork() на Lua с выполнением всего трех строк кода.

Несколько языковых «форков»

Одним из преимуществ JavaScript является использование нескольких транспиляторов и компиляторов. Некоторые люди предпочитают CoffeeScript, в то время как другие предпочитают TypeScript. Другие просто используют обычный JavaScript и используют Babel, чтобы сделать его обратно совместимым.

Аналогичным образом Lua предлагает несколько транспиляторов и языковых дистрибутивов. Одним из самых популярных транспиляторов является MoonScript — язык, вдохновленный CoffeeScript. Некоторые другие среды выполнения включают Ravi, опционально со статической типизацией и LLVM-компилируемой Lua, и Terra, смесь Lua и C.

Теперь, когда у меня есть несколько простых причин, почему Lua — хороший язык, я хотел бы поделиться некоторыми вещами, которые легко выполнимы в Lua:

Системные служебные команды

Раньше написание системных команд выполнялось только на одном языке: C. Теперь мы можем использовать другие языки, такие как Perl, Python и (как вы уже догадались) Lua. Системные команды можно легко запрограммировать на Lua. В качестве примера я напишу пример команды `echo`:

#!/usr/bin/env lua
local has_end_of_line
if arg[1] == "-n" then
  has_end_of_line = true
  table.remove(arg[1])
end
io.write(table.concat(arg, " "), has_end_of_line and "\n" or "")

Поздравляем! Это системная команда, написанная на Lua! С большей сложностью вы, вероятно, могли бы заменить все пакеты coreutils Linux программами Lua.

IRC-боты

Если бы я стрелял каждый раз, когда запрограммирован IRC-бот, я был бы мертв. Это все, что я скажу по теме. Однако, если хотите, вот IRC-бот, который я сделал.

Программное обеспечение для работы с текстом

Существует множество способов использования Lua для управления текстом. Однако в этом документе мы продемонстрируем только язык конфигурации, использующий только шаблоны Lua — язык, подобный INI.

local function read(input)
  local output = {}
  local current = output
  while true do
    local line = coroutine.resume(input)
    if not line then
      break
    end
    if line:match("^%[[^%]]+%]") then -- [x]
      key = line:match("^%[([^%]]+)%]")
      output[key] = output[key] or {}
      current = output[key]
    elseif line:match("^[^=]+=.+") then -- key=value
      local key, value = line:match("^([^=]+)=(.-)%s*$")
      current[key] = value
    end
  end
  return output
end

Теперь все, что вам нужно сделать, это вызвать read() с сопрограммой, и ваш INI будет проанализирован в таблицу Lua.

Я бы добавил синтаксический анализатор JSON, но этот документ уже достаточно длинный. Извините, JSONers. Может быть, в следующий раз.

В дополнение к настройке шаблоны Lua могут быть полезны для сопоставления абстрактных шаблонов, таких как этот парсер тегов IRCv3 daurnimator, который я сделал:

parse_tags = (tag_message)=>
  local cur_name
  tags = {}
  charbuf = {}
  pos = 1
  while pos < #tag_message do
    if tag_message\match '^\\', pos
      lookahead = tag_message\sub pos+1, pos+1
      charbuf[charbuf+1] = escapers[lookahead] or lookahead
      pos += 2
    elseif cur_name
      if tag_message\match "^;", pos
        tags[cur_name] = table.concat charbuf
        cur_name = nil
        charbuf = {}
        pos += 1
      else
        charbuf[#charbuf + 1], pos = tag_message\match "([^\\;]+)()", pos
    else
      if tag_message\match "^=", pos
        if #charbuf > 0
          cur_name = table.concat charbuf
          charbuf = {}
      pos += 1
    elseif tag_message\match "^;", pos
      if #charbuf > 0
        tags[table.concat charbuf] = true
        charbuf = {}
      pos += 1
    else
      charbuf[#charbuf + 1], pos = tag_message\match "([^\\=;]+)()", pos
  return tags

Это довольно сложный шаблон, но он выполняет свою работу.

Веб-серверы

Так много бога проклятых веб-серверов. Очевидно, что-то должно идти правильно, если их так много. Я имею в виду, что Lua быстр, эффективен и идеально подходит для облегченных сценариев, а также, по-видимому, хорош в качестве основного бэкенда для веб-сервера. Я не эксперт, но скажу, что Lua явно сделал что-то правильное, чтобы привлечь внимание создателей веб-серверов.

Это лишь некоторые примеры того, что было сделано и может быть сделано в Lua. Я призываю других людей дополнять этот список и демонстрировать возможности Lua.

Сноска

Пожалуйста, ради любви к Lua, не присылайте мне гневные письма, потому что я «оскорбляю другие языки». Я не пытаюсь сказать, что Python или Perl — отстой, или что JavaScript — отстой из-за ужасной экосистемы (о, подождите, да, но только отчасти). Мне нравится использовать Python и раньше, а также поддерживать программное обеспечение, которое использует Python в настоящее время. Я немного поработал с Perl и C++. Я до сих пор использую C, а также Lua. Я также иногда использую JavaScript для одного или двух веб-приложений. Пожалуйста, не принимайте это за то, что я ругаю другие языки. Я просто пытаюсь указать на некоторые положительные стороны Lua.