Денис
Читай книгу, PATH - это вроде ?.lua, а CPATH это в твоём случае вроде ?.dll при чём эти переменные - это список путей, более того если правильно помню, то с помощью package можно менять значения этих переменных из интерпретатора, собственно можно было бы вполне забить на внешние переменные, если управлять ими из сценария
Не, про package я в курсе... Я не знал, что его так варварски можно менять. И, кстати, как показала практика, можно хакать даже те имплементации, где смена Package вообще невозможна...
Александр
Не, про package я в курсе... Я не знал, что его так варварски можно менять. И, кстати, как показала практика, можно хакать даже те имплементации, где смена Package вообще невозможна...
Не варварски, а системно - например можно тупо через переменные настраивать среду, это +- универсально, тогда как в случае ручной настройки вы будете жестко привязаны к библиотекам которые носите с собой, что черевато тем, что в системе будет куча версий одинаковых библиотек
Александр
Другими словами, через переменные можно получить унификацию среды, ручной настройкой эту гибкость вы теряете и тут собственно логика такова, что переменные правильно использовать в случае хорошо настроенной среды, руками - в случае если нужно таскать с собой кастомные библиотеки
Денис
В общем, если кому-то, как мне, понадобится собирать свою песочницу для приложения, делюсь пусковым VBS. Мне его в начале очень не хватало, поэтому кидаю сюда:
' Initialization parameters
AppContainer = "YourApp.luac" ' Either the pre-compiled LuaC app container or app startup source file
ContainerPlace = "app\" ' The Lua files where your application placed
Sandbox = "sandbox\" ' The interpreter environment folder where it is placed by per every architecture
LuaVersion = "53" ' The Lua version which it should search in every library or interpreter startup executable app.
' =========='
' Main body script
Set WshShell = CreateObject("WScript.Shell")
if right(WshShell.environment("system").item("processor_architecture"), 2) = "64" then
Architecture = "x64"
else
Architecture = "x86"
end if
Set procEnv = WshShell.environment("PROCESS")
procEnv("LUA_CPATH") = WshShell.CurrentDirectory & "\" & sandbox & "\" & Architecture & "\?.dll;" & WshShell.CurrentDirectory & "\" & sandbox & "\" & Architecture & "\?" & LuaVersion & ".dll"
procEnv("LUA_PATH") = WshShell.CurrentDirectory & "\" & sandbox & "\modules\?.lua;" & WshShell.CurrentDirectory & "\" & sandbox & "\modules\?\init.lua"
WshShell.Run(WshShell.CurrentDirectory & "\" & Sandbox & Architecture & "\wlua" & LuaVersion & ".exe" & Chr(32) & Chr(34) & ContainerPlace & AppContainer & Chr(34))
Set WshShell = Nothing
Может не совсем логичная структура, но тут уже каждый поправит под себя. Главное - есть толчок. И да, все это запускается без промежуточных консолей. Структура же папок следующая:
app : папка с вашим приложением на Lua
sandbox : Песочница интерпретатора. Должна содержать следующую структуру:
x64 : все необходимое для 64-разрядной ОС, включая интерпретатор и C-библиотеки
x86 : все то же самое, только для 32-разрядных ОС
modules : shared-модули, написанные на lua, которые будут подключаться отдельно в вашем приложении (можно конечно собирать в пре-компилированный luac)
Название папок разумеется можно менять легким движением руки (вверху в переменных).
Может всем покажется такое не нужно, но я вот такой лаунчер писал вполне себе долго, не зная VBS и объекта WScript.Shell, и, если бы нашел что-то вроде этого, моя жизнь бы сильно упростилась. К тому же, данный лаунчер учитывает ошибки прошлых дней и задает свои параметры package, которые дальше, чем для этого процесса, никуда не пойдут.
Денис
В общем, если кому-то, как мне, понадобится собирать свою песочницу для приложения, делюсь пусковым VBS. Мне его в начале очень не хватало, поэтому кидаю сюда:
' Initialization parameters
AppContainer = "YourApp.luac" ' Either the pre-compiled LuaC app container or app startup source file
ContainerPlace = "app\" ' The Lua files where your application placed
Sandbox = "sandbox\" ' The interpreter environment folder where it is placed by per every architecture
LuaVersion = "53" ' The Lua version which it should search in every library or interpreter startup executable app.
' =========='
' Main body script
Set WshShell = CreateObject("WScript.Shell")
if right(WshShell.environment("system").item("processor_architecture"), 2) = "64" then
Architecture = "x64"
else
Architecture = "x86"
end if
Set procEnv = WshShell.environment("PROCESS")
procEnv("LUA_CPATH") = WshShell.CurrentDirectory & "\" & sandbox & "\" & Architecture & "\?.dll;" & WshShell.CurrentDirectory & "\" & sandbox & "\" & Architecture & "\?" & LuaVersion & ".dll"
procEnv("LUA_PATH") = WshShell.CurrentDirectory & "\" & sandbox & "\modules\?.lua;" & WshShell.CurrentDirectory & "\" & sandbox & "\modules\?\init.lua"
WshShell.Run(WshShell.CurrentDirectory & "\" & Sandbox & Architecture & "\wlua" & LuaVersion & ".exe" & Chr(32) & Chr(34) & ContainerPlace & AppContainer & Chr(34))
Set WshShell = Nothing
Может не совсем логичная структура, но тут уже каждый поправит под себя. Главное - есть толчок. И да, все это запускается без промежуточных консолей. Структура же папок следующая:
app : папка с вашим приложением на Lua
sandbox : Песочница интерпретатора. Должна содержать следующую структуру:
x64 : все необходимое для 64-разрядной ОС, включая интерпретатор и C-библиотеки
x86 : все то же самое, только для 32-разрядных ОС
modules : shared-модули, написанные на lua, которые будут подключаться отдельно в вашем приложении (можно конечно собирать в пре-компилированный luac)
Название папок разумеется можно менять легким движением руки (вверху в переменных).
Может всем покажется такое не нужно, но я вот такой лаунчер писал вполне себе долго, не зная VBS и объекта WScript.Shell, и, если бы нашел что-то вроде этого, моя жизнь бы сильно упростилась. К тому же, данный лаунчер учитывает ошибки прошлых дней и задает свои параметры package, которые дальше, чем для этого процесса, никуда не пойдут.
И да, замечания и улучшения приветствуются. 🙂
Денис
Чото соседний чат подвергся нападению ботов...
Snusmumriken
Это бывает.
Snusmumriken
Луа входит в кейворд "бизнеса".
Денис
Та ну его, тем более, что там ничего полезного
Snusmumriken
Ну, ссылка на этот чат некоторое количество раз мелькала на хабре, и это с одной стороны сделало его популярнее, с другой — сюда тоже время от времени налетают боты. Иногда пачками по 50 штук.
Денис
Денис
А порой даже не какой-то, а вполне себе веселый)))
Hell
Приветствую господа товарисчи, есть возможно кто работал над игрой World of Warcraft именно на lua. Есть заказ, нужно сфомировать запрос с отправкой на сервер, или переписать код близзов. Готов оплатить время и работу. Если есть такие - отпишите
Snusmumriken
Hell
чуть позже отпишу
Snusmumriken
Потому что я лишний раз напоминаю: близзы ничего не дадут отправлять на сервер. Ты не можешь просто взять и отправить что-то из игры на сторонний сервер.
Для отправки используют сторонние приложения, вроде raider_io/wowhead tracker, то есть аддон сбрасывает данные в файлик на диске, его подхватывает стороннее приложение и отправляет, и наоборот. Скорость приём-передачи в среднем около 1-2 запросов в сутки.
"Переписывать" же код близзов == нарушать соглашение и заниматься хакерским хакингом.
Поэтому ещё раз спрашиваю: что конкретно нужно?
jon
Всем привет, где можно почитать то, как работают всякие функции луа? На lua.org как-то куцо. Вот например
string.sub. Потыкавшись в дебаг, я вижу, что эта функция возвращает строку не больше, чем она есть. Т.е какой нибудь мусор не скушает, если укажу конец строки за пределами строки. И вот не могу понять, это и нормальное поведение или как повезёт
Igor
jon
Snusmumriken
Snusmumriken
Например, достаточно исчерпывающая информация по sub.
jon
Snusmumriken
Книжка Роберто как раскрытие этих функций и примерчики, но тут — основная инфа.
В своё время просто перебирал вообще всё и тут же ковырял, чтобы усвоить.
jon
Правильно ли я понимаю, что если я хочу обходить таблицу типа
table = {
{1,2,3},
{2,3,4}
}
В +- красивом виде типа
for a, b, c in...
То надо итератор свой писать?
Snusmumriken
Правильно ли я понимаю, что если я хочу обходить таблицу типа
table = {
{1,2,3},
{2,3,4}
}
В +- красивом виде типа
for a, b, c in...
То надо итератор свой писать?
Да. Или превратить в список. Или воспользоваться двумя итераторами:
for i, row in ipairs(table)
for j, column in ipairs(row) do
...
end
end
Это проще и надёжнее.
jon
Snusmumriken
Меня в своё время больше интересовали итераторы по определённым диапазонам таблиц
jon
Мне пока семантика итераторов луа как то не даётся, не могу понять, почему они работают так как работают
Snusmumriken
Работают очень просто.
for i, v in ipairs(tbl) do
...
end
==
local iter, tbl, i = ipairs(tbl)
local i, v = iter(tbl, i)
while i do
...
i, v = iter(tbl, i)
end
То есть буквально так, конструкция in это сахар для этого.
И в пределах этой конструкции ты можешь делать что хочешь — мутить лямбды-итераторы-генераторы я ля питоновый range, делать stateless-итераторы которые не создают новых функций но используют существующие и т.д.
Денис
Мне пока семантика итераторов луа как то не даётся, не могу понять, почему они работают так как работают
Я тоже долгое время их не понимал, просто использовал. Потом задался целью понять и пописать свои. В общем, это выглядит примерно так:
for значения, из, итерирующей_функции in итерирующая_функция, объект_итерации do
end
А фабрика итераторов как раз и возвращает итерирующую функцию и объект, то есть
for значения, из, итерирующей_функции in фабрика_итераторов(объект_итерации) do
end
jon
Ну как их использовать понимаю) но вот как итерирующая функция внутри выглядит, и почему она такая, я до конца понять не могу, в тех же плюсах все понятнее в этом плане
Snusmumriken
К сожалению тут есть некоторое количество ограничений например на количество аргументов из функции-итератора, поэтому чтобы сделать что-то сложное и "stateles", приходится пилить таблицу-хранилище для множества аргументов, и пользоваться примерно так:
for itble, value in slice(tbl, i, j) do
print(itble.i) --> 1, 2, 3 и т.д.
print(itble.max) --> j
end
Потому что генерировать новые функции с замыканиями для таких задач выглядит дороговато. Делать таблицу-хранилище на самом деле тоже, и от этого несколько неприятно.
Денис
То есть, та же самая функция фабрики итераторов pairs() возвращает два параллельных значения: какбэ указатель на функцию next (стандартно есть в Lua, возвращает следующий элемент таблицы) и саму таблицу. В свою очередьь next() возвращает параллельные значения - ключ, значение.
Денис
К сожалению тут есть некоторое количество ограничений например на количество аргументов из функции-итератора, поэтому чтобы сделать что-то сложное и "stateles", приходится пилить таблицу-хранилище для множества аргументов, и пользоваться примерно так:
for itble, value in slice(tbl, i, j) do
print(itble.i) --> 1, 2, 3 и т.д.
print(itble.max) --> j
end
Потому что генерировать новые функции с замыканиями для таких задач выглядит дороговато. Делать таблицу-хранилище на самом деле тоже, и от этого несколько неприятно.
А кстати, сколько ограничение?
Snusmumriken
Да, вместо pairs можно использовать next, но в чуть другой форме:
for k, v in next, tbl do
...
end
То есть next это функция-итератор а tbl — аргумент который in будет принимать.
Snusmumriken
А кстати, сколько ограничение?
На вход лямбде итератора приходит всего 2 аргумента включая таблицу, остаётся один свободный, и обычно это индекс из которого делается следующий индекс.
Если через функцию-генератор, то можно хоть
for i, j, k, m, n, v in myiter(tbl) do
end
Но myiter должна возвращать новую функцию с замыканием, или функция с замыканием должна генерировать выводную часть всего из двух аргументов tbl и i. И если i сделать таблицей для дополнительной инфы из которой можно генерить остальные аргументы, то можно и stateless.
Денис
На вход лямбде итератора приходит всего 2 аргумента включая таблицу, остаётся один свободный, и обычно это индекс из которого делается следующий индекс.
Если через функцию-генератор, то можно хоть
for i, j, k, m, n, v in myiter(tbl) do
end
Но myiter должна возвращать новую функцию с замыканием, или функция с замыканием должна генерировать выводную часть всего из двух аргументов tbl и i. И если i сделать таблицей для дополнительной инфы из которой можно генерить остальные аргументы, то можно и stateless.
А, ну это-то да. А если наша самописная фабрика итераторов возвращает самописный итератор, который в свою очередь возвращает нужное количество значений?
Snusmumriken
Snusmumriken
Например, вот прекрасный итератор по utf8-символам:
string.charpattern = "[\1-\x7F\xC2-\xF4][\x80-\xBF]*"
local cp = string.charpattern
function utf8_next(line, index)
local a, b = line:find(cp, index)
if not a then return end
return b + 1, line:sub(a, b)
end
function string:utf8chars()
return utf8_next, self, 1
end
У него в качестве индекса используется конец текущего utf8-символа + 1. Поэтому он малоюзабельный в итераторе и фактически указывает на длину до текущего куска строки в байтах.
Использовать индекс utf8-символа крайне невыгодно. Добавить его отдельно — проблематично из-за stateless.
Денис
Денис
По сути, ты же под капот не лезешь, пусть там хоть userdata приходит, главное, чтобы итератор смог ее обработать)))
Snusmumriken
Ну это то что будет первым возвращаемым аргументом, и желательно чтобы оно было юзабельным для пользователя.
Денис
Ну это то что будет первым возвращаемым аргументом, и желательно чтобы оно было юзабельным для пользователя.
Не, смотри: наша фабрика итераторов принимает на вход некое значение. Под капотом Формирует лямбду, а вторым параллельным значением возвращает новый объект, который юзеру видеть не надо, это чисто внутренний служебный. Наша же лямбда принимает этот служебный объект, в который мы можем вообще принять всего один аргумент (второй просто проигнорировать), а в этом объекте например сохранить переданный нам в фабрику объект и нужные значения. Ну а далее итератор возвращает значения, с которыми нужно взаимодействовать.
Snusmumriken
Смотри, лямбда принимает некоторый индекс и должна возвращать его же первым аргументом, потому что его ей передадут при следующем вызове.
Или лямбда должна быть именно лямбдой и хранить аргументы в замыкании, тогда ей вообще пофигу что в неё будут пропихивать, она сама будет генерить аргументы и возвращать, ибо замыкание. Служебный объект может сидеть там же и не высовываться.
Но если добавляем зависимость от аргумента при следующих вызовах, то его надо возвращать первым.
Денис
Snusmumriken
Да, который она возвращала
Snusmumriken
Например для next это имя предыдущего ключа, чтобы можно было получить следующий.
Snusmumriken
Ну это не очень красиво для юзера )
Snusmumriken
Так что проще кажется делать натуральную независящую лямбду с замыканием. Но только в тех итераторах которые редко вызываются и на которые пофигу.
Snusmumriken
Блин, я уже хотел нарисовать схемку, пока не вспомнил что с этим проблемсы )
Денис
А там что происходит под капотом - это уже юзеру видеть не надо. Ну а если он хочет посмотреть - ну что ж, флаг ему в руки, пусть смотрит, тут и так порой смотришь на код и у тебя мозг подрывается)))
Денис
Snusmumriken
Карочи, всегда где есть возможность, я предпочитаю делать stateless-итератор, который по-человечески принимает аргументы и делает всю работу из некоторого индекса.
Денис
Snusmumriken
local function ripairs_next(tbl, index)
index = index - 1
local v = tbl[index]
if not v then return end
return index, v
end
function M.ripairs(tbl, index)
assert(type(tbl) == "table", "Arg #1 error: table expected, got " .. type(src))
index = index or #tbl
index = index > 0 and index - 1 or index
return ripairs_next, tbl, index % #tbl + 2
end
Денис
Тиха тиха тиха!
Денис
Не сбивай)))
Snusmumriken
Лады, просто тут уже всё работает и отлажено и stateless и можно выбрать начальную точку итерации )
Денис
function ipairsstep(t, startFrom, step)
local startIteration = true
local lambda = function (obj, index)
local tbl = obj.origTable
local objstep = obj.step
index = index or obj.startFrom
if startIteration then
startIteration = false
else
index = index+tonumber(objstep)
end
if tbl[index] then
return index, tbl[index]
end
end
return lambda, {origTable=t,step=step, startFrom=startFrom}
end
-- Test
cts = {"One", "Two", "Three", "Four", "Five"}
for k, v in ipairsstep(cts, 1, 1) do
print("key: ", k, "value: ", v)
end
for k, v in ipairsstep(cts, #cts, -1) do
print("key: ", k, "value: ", v)
end
Денис
Разумеется, шаг можно было вынести и в локальные переменные фабрики, но такое решение чисто для наглядности.
Денис
Да и стартовый шаг тоже можно было вынести)))
Денис
У меня вот тут другая проблема... Я никак не соображу как в C-библиотеке сопоставить юзердату метатаблице типа...
Snusmumriken
Igor
Igor
А, кстати, для 5.1 нет этого метода, надо использовать lua_setmetatable
Денис
Igor
Что не есть хорошо, если объектов будет туева хуча
Igor
А, не, один раз. Всё нормально, я не увидел там luaL_newmetatable.
Igor
Ну а функции в метатаблицу (если их много) можно задать через luaL_Reg структуры и функцию регистрации, чтобы не писать кучу пушей самому
Денис
У меня тут вся проблема в том, что я пишу на языке, который крутится в Widechar, а Lua кушает исключительно MultiByte. Так что мне тут еще приходится мудрить с закрытиями памяти
Денис
А еще я писал создание самой метатаблицы в luaopen_, и теперь мне надо сообразить ккак уже созданную метатаблицу сопоставить, но докопаюсь
Igor
Igor
Какая версия Lua?
Денис
Igor
Отлично, тогда через luaL_getmetatable её в стек отправляй
Денис