Igor
luaL_getmetatable(L, "названте, которое ты ей дал в luaopen")
Денис
Отлично, тогда через luaL_getmetatable её в стек отправляй
ProcedureC.i L_LoadSound(*l.lua_State) Protected Filename.s = PeekS(luaL_checkstring(*l, 1), -1, #PB_UTF8) Protected IsStreaming.a If lua_isnoneornil(*l, 2) IsStreaming = #False Else IsStreaming = checkboolean(*l, 2) EndIf Protected *SObject.Long = lua_newuserdata(*l, SizeOf(Long)) If IsStreaming *SObject\l = LoadSound(#PB_Any, Filename, #PB_Sound_Streaming) Else *SObject\l = LoadSound(#PB_Any, Filename) EndIf lua_newtable(*l) luaL_getmetatable(*L, "luasound") lua_setfield(*L, -2, "__index") lua_pushcfunction(*l, @mtm_Destroy()) lua_setfield(*l, -2, "__gc") lua_setmetatable(*L, -2) ProcedureReturn 1 EndProcedure
Igor
Если нужно именно объетку её присвоить, тогда luaL_setmetatable(L, "название")
Денис
Денис
Без табов сложновато понять, что происходит
Мне-то оно носит исключительно наглядный характер, когда очень много вложенных проверок, а так...
Igor
Мне-то оно носит исключительно наглядный характер, когда очень много вложенных проверок, а так...
Конкретно сейчас у тебя таблице по много раз методы устанавливаются, это бесполезно, установщики __gc и __index можно в luaopen перенести
Денис
Хотя сейчас в VS Code насильно настроил автоотступы, чтобы привыкать
Денис
Конкретно сейчас у тебя таблице по много раз методы устанавливаются, это бесполезно, установщики __gc и __index можно в luaopen перенести
Да, это я перенесу. Проблема вся в том, что при одной инициализации он видит исключительно юзердату и при попытке обратиться к методу типа obj:method() выдает, что, мол, ты обратился к юзердате
Денис
Надо дальше копаться...
Igor
Надо дальше копаться...
Потому что сейчас lua_setmetatable вызывается с установкой меты на таблицу, которую создаёт lua_newtable
Igor
Я, если честно, не понимаю, зачем она там
Денис
Так разбираюсь же))) я просто смотрел по примеру исходников биндера LibUI
Igor
Так разбираюсь же))) я просто смотрел по примеру исходников биндера LibUI
lua_newtable вызов не нужен там совсем, lua_getmetatable и так её возвращает
Igor
по хорошему там надо вместо всего этого сделать luaL_setmetatable() после создания юзердаты
Igor
а в luaopen методы указываеть для меты
Igor
Так разбираюсь же))) я просто смотрел по примеру исходников биндера LibUI
https://github.com/igor725/cs-lua/blob/main/src/luascript.c#L89 https://github.com/igor725/cs-lua/blob/main/src/luaangle.c#L125 https://github.com/igor725/cs-lua/blob/main/src/luaangle.c#L12 Вот небольшой пример, как делал я. Вроде код не сильно замудрил, легко разобраться будет.
Igor
У меня только кросслуёвый код там, если что. Есть некоторые слои совместимости, чтобы работал со всеми версиями Lua начиная с 5.1 и заканчивая 5.4
Денис
https://github.com/igor725/cs-lua/blob/main/src/luascript.c#L89 https://github.com/igor725/cs-lua/blob/main/src/luaangle.c#L125 https://github.com/igor725/cs-lua/blob/main/src/luaangle.c#L12 Вот небольшой пример, как делал я. Вроде код не сильно замудрил, легко разобраться будет.
то есть: в luaopen_ мы делаем что-то вроде: luaL_newmetatable(*l, "luasound") luaL_setfuncs(*l, @Funcs(), 0) lua_pushcfunction(*l, @mtm_Destroy()) lua_setfield(*l, -2, "__gc") а в создании объекта делаем следующее: ``` Protected *SObject.Long = lua_newuserdata(*l, SizeOf(Long)) *SObject\l = LoadSound(#PB_Any, Filename) luaL_getmetatable(*L, "luasound") lua_setfield(*L, -2, "__index") lua_setmetatable(*L, -2)
Денис
Igor
а в luaopen ещё нужно после newmetatable добавить установку индекса как раз на ссылку таблицы
Igor
это в luaopen luaL_newmetatable(*l, "luasound") lua_pushvalue(*l, -1) lua_setfield(*l, -2, "__index")
Денис
а в luaopen ещё нужно после newmetatable добавить установку индекса как раз на ссылку таблицы
То есть, luaopen_: Global *ObjName = UTF8("luasound") luaL_newmetatable(*l, *ObjName) luaL_setfuncs(*l, @Funcs(), 0) Protected *TempString = UTF8("__index") lua_setfield(*l, -2, *TempString) FreeMemory(*TempString) lua_pushcfunction(*l, @mtm_Destroy()) *TempString = UTF8("__gc") lua_setfield(*l, -2, *TempString) FreeMemory(*TempString) загрузка: Protected *SObject.Long = lua_newuserdata(*l, SizeOf(Long)) *SObject\l = LoadSound(#PB_Any, Filename) lua_setmetatable(*L, -2, *ObjName)
Igor
Совершенно разные функции
Igor
А так в целом да, думаю так. По крайней мере быстрый взгляд говорит, что это похоже на правду.
Денис
Совершенно разные функции
Да, это автокомплит подвел)))
Денис
Ну щас проверим...
Денис
А так в целом да, думаю так. По крайней мере быстрый взгляд говорит, что это похоже на правду.
О! --------------------------- PureBasic --------------------------- Line 103: luaL_setmetatable(): Incorrect number of parameters. --------------------------- ОК ---------------------------
Денис
Щас полезу в инклуд
Igor
Стейт и название таблицы.
Igor
Таблицу она присваивает высшему объекту в стеке, ей его индекс не требуется
Денис
Тогда мне придется в стек положить метатаблицу...
Igor
Тогда мне придется в стек положить метатаблицу...
На момент вызова luaL_setmetatable у тебя в топе стека должна находиться юзердата
Igor
Тогда таблица присвоется ей. Юзердата в стеке останется нетронутой, у неё просто метатаблица появится.
Денис
Тогда таблица присвоется ей. Юзердата в стеке останется нетронутой, у неё просто метатаблица появится.
Так... PS D:\progworkspace\PB\LuaSound\tests> lua53 .\test.lua e:\lua\lua53.exe: attempt to index a string value stack traceback: [C]: in ? [C]: in function 'require' .\test.lua:2: in main chunk [C]: in ? разбираемся дальше)))
Денис
Тогда таблица присвоется ей. Юзердата в стеке останется нетронутой, у неё просто метатаблица появится.
Код такой: package.cpath = ".\\..\\build\\x64\\?53.dll" sound = require "luasound" f = sound.new("waiting2.ogg") f:play() io.read()
Igor
Так... PS D:\progworkspace\PB\LuaSound\tests> lua53 .\test.lua e:\lua\lua53.exe: attempt to index a string value stack traceback: [C]: in ? [C]: in function 'require' .\test.lua:2: in main chunk [C]: in ? разбираемся дальше)))
В sound.new проблемп со стеком, видимо ты пытаешься где-то строку проиндексировать, как таблицу
Igor
А, ну знаяит в luaopen что-то
Igor
Покажи итоговый код функции luaopen
Денис
Покажи итоговый код функции luaopen
Сейчас покажу Догадываюсь, что в нем как раз и проблемы...
Денис
А создание метатаблицы завершать никак не нужно? Она же ложится в стек, ее же надо каким-то образом завершить, чтобы продолжить создание основных функций (в данном случае, зарегистрировать функцию new)
Денис
Покажи итоговый код функции luaopen
ProcedureCDLL.i luaopen_luasound(*l.lua_State) If InitSound() UseOGGSoundDecoder() UseFLACSoundDecoder() Protected Dim Funcs.luaL_Reg(ListSize(MetaMethods())) ForEach MetaMethods() Funcs(ListIndex(MetaMethods())) = MetaMethods() Next luaL_newmetatable(*l, #ObjName) luaL_setfuncs(*l, @Funcs(), 0) ForEach MetaMethods() FreeMemory(MetaMethods()\name) Next FreeArray(Funcs()) FreeList(MetaMethods()) lua_setfield(*l, -2, "__index") lua_pushcfunction(*l, @mtm_Destroy()) lua_setfield(*l, -2, "__gc") Dim Funcs.luaL_Reg(ListSize(MainMethods())) ForEach MainMethods() Funcs(ListIndex(MainMethods())) = MainMethods() Next lua_createtable(*l,1,ArraySize(Funcs())) luaL_setfuncs(*l,@Funcs(),0) ForEach MainMethods() FreeMemory(MainMethods()\name) Next FreeArray(Funcs()) FreeList(MainMethods()) ProcedureReturn 1 EndIf ProcedureReturn 0 EndProcedure
Igor
перед lua_setfield(*l, -2, "__index") поставь lua_pushvalue(*l, -1)
Igor
lua_pushvalue отправляет в стек повторно значение с указанного индекса
Денис
Т.е., после регистрации функций мы должны как бы их туда отправить?
Igor
Т.е., после регистрации функций мы должны как бы их туда отправить?
Нет, lua_pushvalue(*l, -1) отправляет ещё раз в стек метатаблицу, lua_setfield эту таблицу записывает в саму себя с ключиком __index
Денис
Нет, lua_pushvalue(*l, -1) отправляет ещё раз в стек метатаблицу, lua_setfield эту таблицу записывает в саму себя с ключиком __index
Я просто спрашиваю, чтобы не просто накидать функции по совету, а понять логику...
Денис
Ну, плюс-минус, логику я понял. Осталось только живые поля добавить
Денис
Да не за что
А живые поля реализуются через функцию, которая вторым параметром получит ключ поля, и в соответствии с этим ключом я должен что-то сделать, то есть, ассоциировать таблицу с index мнне не нужно (аналогия с gc)
Денис
т.е., надо просто реализовать функцию __index, а в метатаблицу вместо текущей таблицы запушить адрес на нее
Денис
Ага
Ну, вроде в голове сошлось! Еще раз тебе спасибо!
Денис
Ага
А, не совсем сошлось... Я сейчас зарегистрировал массив обычных методов, затем сразу же начал пушить c-функции и устанавливать их на index, newindex и так далее, но при попытке обратиться к обычным методам, у меня attempt to call a string value.
Денис
Ага
luaL_setfuncs(*l, @Funcs(), 0) ... lua_pushcfunction(*l, @mtm_Index()) lua_setfield(*l, -2, "__index") lua_pushcfunction(*l, @mtm_NewIndex()) lua_setfield(*l, -2, "__newindex") lua_pushcfunction(*l, @mtm_Destroy()) lua_setfield(*l, -2, "__gc") lua_setmetatable(*l, -2)
Денис
я так подозреваю, что luaL_setfuncs чистит стек чтоли...
Igor
То, что она запушила, то и удаляет из стека, то есть после неё стек остается нетронутым
Денис
То, что она запушила, то и удаляет из стека, то есть после неё стек остается нетронутым
Тогда я пока имею ситуацию, что методы индексятся как строки названий... метаметоды index и newindex работают
Денис
Либо придется крепить методы на саму юзердату, а потом уже вызывать на нее метатаблицу...
Igor
Либо придется крепить методы на саму юзердату, а потом уже вызывать на нее метатаблицу...
На юзердату методы никак не повесить, они в метатаблице находиться должны
Денис
На юзердату методы никак не повесить, они в метатаблице находиться должны
Я уже понял в чем прикол. Дело в том, что я действовал по аналогии с Lua: индекс срабатывает только в случае, когда запрошенный ключ отсутствует в таблице. Здесь же индекс забирает полностью все. Осталось только понять как в случае если мне ничего делать не нужно, отправить на нужное значение по ключу...
Денис
Пока получилось вызвать Stack overflow)))
Igor
lua_isnil() -> lua_rawget() -> return
Igor
Пока получилось вызвать Stack overflow)))
getfield вызывает метаметод, так что лучше его не трогать, оно как раз и стало результатом stack overflow, думаю
Денис
то есть, я должен положить на стек метатаблицу как таблицу и rawget'ом положить значение?
Igor
можно и так
Денис
можно и так
В общем, работает вот так Default luaL_getmetatable(*l, #ObjName) lua_pushvalue(*l, 2) lua_rawget(*l, -2) EndSelect это в кейсселекте, когда другие случаи
Денис
А вообще, конечно, тут есть очень много неожиданных вещей, которые, оказывается, хорошо, что есть
Денис
Как вот с __index: ты вообще можешь переопределить все поведение таблицы!
Igor
Как вот с __index: ты вообще можешь переопределить все поведение таблицы!
Ну да, а через __newindex можно переопределить поведение при присвоении таблице значений
Денис
Ну да, а через __newindex можно переопределить поведение при присвоении таблице значений
Именно! Кстати, в моем случае, присвоение таких извратов делать не пришлось)))