Мало и для
vanilla Lua
и для LuaJIT
Хорошо в
игростроении
Отсутствие
тулинга >
ограничивает
доступную
экспертизу
Мало тулинга в
экосистеме Луа
• Поддержка синтаксиса, навигации и рефакторинг в редакторе;
• Пакетный менеджер и живое сообщество вокруг него;
• Отладчик, желательно в интегрированной среде;
• Инструменты для анализа производительности, желательно -
доступные из редактора;
• Тестирование, желательно из редактора;
• Статический анализатор;
• Фаззинг.
• Lua 5.2/5.3/5.4
• LuaJIT 2.1
• Moonscript, Terra, Nelua, Ravi, MetaLua,
MoonSharp, Luau etc.
• Очень быстрая NoSQL СУБД с сервером приложений
• Открытый код ядра, есть компоненты closed source (в
коммерческой версии)
• Способность обрабатывать огромное кол-во одновременных
подключений
• Соответствие ACID
• Отказоустойчивость и масштабируемость (репликация,
шардинг)
• Кооперативная многозадачность, неблокирующие операции
IO (включая работу с внешними сервисами и файловой
системой)
Файбер (fiber) – он как сопрограмма
(coroutine) только файбер 
• Файбер (fiber)
• Легковесная нить исполнения, реализующая
кооперативную многозадачность
• Кооперативная многозадачность
• Следующая задача выполняется после того, как
текущая объявит о передаче управления
Goto Definition
Diagnostics
Auto Completion
Возможно посредством
формата EmmyLua/Sumneko
Возможно посредством
формата EmmyLua/Sumneko
$HOME/.vscode-server/extensions/sumneko.lua-
2.6.0/server/meta/LuaJIT en-us utf8/ffi.lua
---@meta
---@class ffi.namespace*: table
---@class ffi.cdecl*: string
---@class ffi.ctype*: userdata
local ctype
---@class ffi.cdata*: userdata
---@alias ffi.ct* ffi.cdecl*|ffi.ctype*|ffi.cdata*
---@class ffi.cb*: userdata
local cb
---@class ffi.VLA*: userdata
---@class ffi.VLS*: userdata
---@version JIT
---@class ffilib
---@field C ffi.namespace*
---@field os string
---@field arch string
local ffi = {}
---@param def string
function ffi.cdef(def) end
---@param name string
---@param global? boolean
---@return ffi.namespace* clib
---@nodiscard
function ffi.load(name, global) end
---@param ct ffi.ct*
---@param nelem? integer
---@param init? any
---@return ffi.cdata* cdata
---@nodiscard
Tarantool Tarantool
describe('Busted unit testing framework', function()
describe('should be awesome', function()
it('should be easy to use', function()
assert.truthy('Yup.')
end)
it('should have lots of features', function()
-- deep check comparisons!
assert.same({ table = 'great'}, { table = 'great' })
-- or check by reference!
assert.is_not.equals({ table = 'great'}, { table = 'great'})
assert.falsy(nil)
assert.error(function() error('Wat') end)
end)
it('should provide some shortcuts to common functions', function()
assert.unique({{ thing = 1 }, { thing = 2 }, { thing = 3 }})
end)
it('should have mocks and spies for functional tests', function()
local thing = require('thing_module')
spy.spy_on(thing, 'greet')
thing.greet('Hi!')
http://olivinelabs.com/busted/
#!/usr/bin/tarantool
local tap = require('tap')
test = tap.test("my test name")
test:plan(2)
test:ok(2 * 2 == 4, "2 * 2 is 4")
test:test("some subtests for test2", function(test)
test:plan(2)
test:is(2 + 2, 4, "2 + 2 is 4")
test:isnt(2 + 3, 4, "2 + 3 is not 4")
end)
test:check()
Tarantool
https://www.tarantool.io/ru/d
oc/latest/reference/reference
_lua/tap/
-- test/feature_test.lua
local t = require('luatest')
local g = t.group('feature')
-- Tests. All properties with name staring with `test` are treated as
test cases.
g.test_example_1 = function() ... end
g.test_example_n = function() ... End
-- Define parametrized groups
local pg = t.group('pgroup', {{engine = 'memtx'}, {engine = 'vinyl'}})
pg.test_example_3 = function(cg)
-- Use cg.params here
box.schema.space.create('test', {
engine = cg.params.engine,
})
end
-- Hooks can be specified for one parameter
pg.before_all({engine = 'memtx'}, function() ... end)
pg.before_each({engine = 'memtx'}, function() ... end)
Tarantool
https://github.com/tarantool/l
uatest/
local function sum_up_to(n)
local sum = 0
for i = 1, n do
sum = sum + i
end
return sum
end
property 'sum of numbers is equal to (n + 1) * n / 2' {
generators = { int(100) },
check = function(n)
return sum_up_to(n) == (n + 1) * n / 2
end
}
https://github.com/luc-tielen/lua-quickcheck
Lua ---@alias hookmask string
---|+'"c"' # Calls hook when Lua calls a function.
---|+'"r"' # Calls hook when Lua returns from a function.
---|+'"l"' # Calls hook when Lua enters a new line of
code.
---
---Sets the given function as a hook.
---
---[View documents](command:extension.lua.doc?["en-
us/51/manual.html/pdf-debug.sethook"])
---
---@overload fun(hook: function, mask: hookmask, count?:
integer)
---@param thread thread
---@param hook async fun()
---@param mask hookmask
---@param count? Integer
function debug.sethook(thread, hook, mask, count) end
Lua ---@param co? thread
---@return function hook
---@return string mask
---@return integer count
---@nodiscard
function debug.gethook(co) end
---@alias infowhat string
---|+'"n"' # `name` and `namewhat`
---|+'"S"' # `source`, `short_src`, `linedefined`,
`lastlinedefined`, and `what`
---|+'"l"' # `currentline`
---|+'"t"' # `istailcall`
---|+'"u"' # `nups`, `nparams`, and `isvararg`
---|+'"f"' # `func`
---|+'"L"' # `activelines`
Lua ---
---Returns a table with information about a function.
---
---[View documents](command:extension.lua.doc?["en-
us/51/manual.html/pdf-debug.getinfo"])
---
---@overload fun(f: integer|function, what?:
infowhat):debuginfo
---@param thread thread
---@param f integer|async fun()
---@param what? infowhat
---@return debuginfo
---@nodiscard
function debug.getinfo(thread, f, what) end
Lua ---
---Assigns the `value` to the local variable with index
`local` of the function at `level` of the stack.
---
---[View documents](command:extension.lua.doc?["en-
us/51/manual.html/pdf-debug.setlocal"])
---
---@overload fun(level: integer, index: integer, value:
any):string
---@param thread thread
---@param level integer
---@param index integer
---@param value any
---@return string name
function debug.setlocal(thread, level, index, value) end
Lua ---
---Returns the name and the value of the local variable
with index `local` of the function at level `f` of the
stack.
---
---[View documents](command:extension.lua.doc?["en-
us/51/manual.html/pdf-debug.getlocal"])
---
---@overload fun(f: integer|async fun(), index:
integer):string, any
---@param thread thread
---@param f integer|async fun()
---@param index integer
---@return string name
---@return any value
---@nodiscard
function debug.getlocal(thread, f, index) end
Lua
---
---Returns the name and the value of the upvalue with
index `up` of the function.
---
---[View documents](command:extension.lua.doc?["en-
us/51/manual.html/pdf-debug.getupvalue"])
---
---@param f async fun()
---@param up integer
---@return string name
---@return any value
---@nodiscard
function debug.getupvalue(f, up) end
Lua ---
---Returns a string with a traceback of the call stack.
The optional message string is appended at the beginning
of the traceback.
---
---[View documents](command:extension.lua.doc?["en-
us/51/manual.html/pdf-debug.traceback"])
---
---@overload fun(message?: any, level?: integer): string
---@param thread thread
---@param message? any
---@param level? integer
---@return string message
---@nodiscard
function debug.traceback(thread, message, level) end
Debug API:
local loadFunct = assert( loadfile(fileToExec) )
debug.sethook(covHandler, "l" )
-- Workaround: coroutines require us to sethook again.
local oldCreate = coroutine.create
coroutine.create = function( coFunct )
return oldCreate( function(...)
debug.sethook(covHandler, "l" )
return coFunct(unpack(arg))
end)
end
loadFunct() -- run the main program
M.stop()
function M.stop()
debug.sethook()
…
end
end
Debug API: function traceback ()
local level = 1
while true do
local info = debug.getinfo(level, "Sl")
if not info then break end
if info.what == "C" then -- is a C function?
print(level, "C function")
else -- a Lua function
print(string.format("[%s]:%d",
info.short_src,
info.currentline))
end
level = level + 1
end
end
`n´ selects fields name and namewhat
`f´ selects field func
`S´ selects fields source, short_src,
what, and linedefined
`l´ selects field currentline
`u´ selects field nup
• gperftools, callgrind покажут граф
вызовов на уровне Си
• jit.p позволит собрать граф вызовов
в LuaJIT
• Но никто не соберёт всё вместе
• Строчный хук позволяет собрать профиль исполнения
• Тайминги будут неверные…
• … но счетчикам строк верить можно
• Luacov - https://github.com/keplerproject/luacov
****0 local interval_mt = {
new = interval_new,
}
****0 return setmetatable(
{
new = datetime_new,
interval = setmetatable(interval_mt, interval_mt),
now = datetime_now,
is_datetime = is_datetime,
****0 }, {}
)
====================================================================
Summary
====================================================================
File Hits Missed Coverage
-----------------------------------------
builtin/datetime.lua 515 76 87.14%
-----------------------------------------
Total 515 76 87.14%
https://github.com/tarantool/tarantool/
wiki/How-to-generate-Lua-coverage-
report-for-built-in-module%3F
• Luatrace - https://github.com/geoffleyland/luatrace
“luatrace is a Lua module that collects information about
what your code is doing and how long it takes, and can
analyse that information to generate profile and coverage
reports.
luatrace adds a layer on top of Lua's debug hooks to make
it easier to collect information for profiling and coverage
analysis. luatrace traces of every line executed, not just
calls.
luatrace can trace through coroutine resumes and yields,
and through xpcalls, pcalls and errors. On some platforms it
uses high resolution timers to collect times of the order of
nanoseconds.”
https://github.com/tarantool/luajit/tree/fckxor
g/gh-5688-cli-for-memprof-parse
https://github.com/tarantool/luajit/tree/shishqa
/gh-781-platform-and-lua-profiler
Lua – язык, с динамической типизацией
Нет проверок времени компиляции
Но можно использовать внешний линтер
для статического анализа кода
std = "luajit"
globals = {"box", "_TARANTOOL", "tonumber64"}
ignore = {
-- Accessing an undefined field of a global variable
<debug>.
"143/debug",
-- Accessing an undefined field of a global variable
<string>.
"143/string",
-- Accessing an undefined field of a global variable
<table>.
"143/table",
-- Unused argument <self>.
"212/self",
-- Redefining a local variable.
"411",
-- Redefining an argument.
"412",
-- line contains only whitespace
"611",
}
include_files = {
"**/*.lua",
}
exclude_files = {
"build*/**/*.lua",
-- Third-party source code.
"test-run/**/*.lua",
".rocks/**/*.lua",
".git/**/*.lua",
}
std = "tarantool"
include_files = {
'**/*.lua',
'*.luacheckrc',
'*.rockspec'
}
exclude_files = {
'.rocks/',
'tmp/'
}
max_line_length = 120
https://github.com/tarantool/tarantool/wiki/How-to-verify-all-modified-lua-files-via-luachecks%3F
require('checks')
local function get_stat(uri, opts)
checks('string', {timeout =
'?number'})
end
get_stat()
-- error: bad argument #1 to get_stat
(string expected, got nil)
get_stat('localhost', {timeuot = 1})
-- error: unexpected argument opts.timeuot
to get_stat
13
get_stat('localhost', {timeuot = 1})
-- ^^ typo
-- No error, but does not work as expected
-- Still bad
https://github.com/tarantool/checks
• https://teal-playground.netlify.app/
• https://github.com/teal-language/teal-
types/tree/master/types/penlight/pl
• https://github.com/teal-language/vscode-teal
• https://github.com/teal-language/vim-teal
Teal –
local ltn12 = require("ltn12")
local Sink = ltn12.Sink
local Source = ltn12.Source
local record socket
record TCP
-- master methods
bind: function(TCP, string, integer)
connect: function(TCP, string, integer): integer, string
listen: function(TCP, integer): integer, string
-- client methods
getpeername: function(TCP): string, integer
enum TCPReceivePattern
"*l"
"*a"
end
enum TCPReceiveError
"closed"
"timeout"
end
receive: function(TCP, TCPReceivePattern|integer, string):
string, TCPReceiveError
https://github.com/teal-language/teal-
types/blob/master/types/luasocket/socket.d.tl
• Нет готового решения с удобным отладчиком
• Есть отладчик в Redis как артефакт поддержки в
ZeroBrane Studio Павла Ключенко
• Есть популярный модуль Mobdebug того же Павла
Ключенко
• Развитие RemDebug;
• Mobdebug можно поднять почти везде, где есть LuaSocket;
• Есть надежды зайти через VSCode Debug Adapter
API
• https://github.com/devcat-studio/VSCodeLuaDebug
• форк https://github.com/microsoft/vscode-mono-debug
• https://github.com/BeamNG/VSCodeLuaDebug
https://luarocks.org/modules/3scale/debugger
Basically Vscode-debuggee.lua drops the speed of running Lua
programs because it implements the breakpoint mechanism
using debug.sethook.
This performance degradation can be overcome by applying a
simple patch to the Lua VM.
Download:
lua 5.1.5 : Patch, Code
lua 5.3.4 : Patch, Code
https://marketplace.visualstudio.com/items?itemName=devCAT.lua-debug
Тимур Сафин

Инструменты для з̶а̶х̶в̶а̶т̶а̶ ̶м̶и̶р̶а̶ отладки в Tarantool

  • 4.
    Мало и для vanillaLua и для LuaJIT Хорошо в игростроении Отсутствие тулинга > ограничивает доступную экспертизу Мало тулинга в экосистеме Луа
  • 5.
    • Поддержка синтаксиса,навигации и рефакторинг в редакторе; • Пакетный менеджер и живое сообщество вокруг него; • Отладчик, желательно в интегрированной среде; • Инструменты для анализа производительности, желательно - доступные из редактора; • Тестирование, желательно из редактора; • Статический анализатор; • Фаззинг.
  • 6.
    • Lua 5.2/5.3/5.4 •LuaJIT 2.1 • Moonscript, Terra, Nelua, Ravi, MetaLua, MoonSharp, Luau etc.
  • 8.
    • Очень быстраяNoSQL СУБД с сервером приложений • Открытый код ядра, есть компоненты closed source (в коммерческой версии) • Способность обрабатывать огромное кол-во одновременных подключений • Соответствие ACID • Отказоустойчивость и масштабируемость (репликация, шардинг) • Кооперативная многозадачность, неблокирующие операции IO (включая работу с внешними сервисами и файловой системой)
  • 10.
    Файбер (fiber) –он как сопрограмма (coroutine) только файбер  • Файбер (fiber) • Легковесная нить исполнения, реализующая кооперативную многозадачность • Кооперативная многозадачность • Следующая задача выполняется после того, как текущая объявит о передаче управления
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
    Возможно посредством формата EmmyLua/Sumneko $HOME/.vscode-server/extensions/sumneko.lua- 2.6.0/server/meta/LuaJITen-us utf8/ffi.lua ---@meta ---@class ffi.namespace*: table ---@class ffi.cdecl*: string ---@class ffi.ctype*: userdata local ctype ---@class ffi.cdata*: userdata ---@alias ffi.ct* ffi.cdecl*|ffi.ctype*|ffi.cdata* ---@class ffi.cb*: userdata local cb ---@class ffi.VLA*: userdata ---@class ffi.VLS*: userdata ---@version JIT ---@class ffilib ---@field C ffi.namespace* ---@field os string ---@field arch string local ffi = {} ---@param def string function ffi.cdef(def) end ---@param name string ---@param global? boolean ---@return ffi.namespace* clib ---@nodiscard function ffi.load(name, global) end ---@param ct ffi.ct* ---@param nelem? integer ---@param init? any ---@return ffi.cdata* cdata ---@nodiscard
  • 24.
  • 25.
    describe('Busted unit testingframework', function() describe('should be awesome', function() it('should be easy to use', function() assert.truthy('Yup.') end) it('should have lots of features', function() -- deep check comparisons! assert.same({ table = 'great'}, { table = 'great' }) -- or check by reference! assert.is_not.equals({ table = 'great'}, { table = 'great'}) assert.falsy(nil) assert.error(function() error('Wat') end) end) it('should provide some shortcuts to common functions', function() assert.unique({{ thing = 1 }, { thing = 2 }, { thing = 3 }}) end) it('should have mocks and spies for functional tests', function() local thing = require('thing_module') spy.spy_on(thing, 'greet') thing.greet('Hi!') http://olivinelabs.com/busted/
  • 26.
    #!/usr/bin/tarantool local tap =require('tap') test = tap.test("my test name") test:plan(2) test:ok(2 * 2 == 4, "2 * 2 is 4") test:test("some subtests for test2", function(test) test:plan(2) test:is(2 + 2, 4, "2 + 2 is 4") test:isnt(2 + 3, 4, "2 + 3 is not 4") end) test:check() Tarantool https://www.tarantool.io/ru/d oc/latest/reference/reference _lua/tap/
  • 27.
    -- test/feature_test.lua local t= require('luatest') local g = t.group('feature') -- Tests. All properties with name staring with `test` are treated as test cases. g.test_example_1 = function() ... end g.test_example_n = function() ... End -- Define parametrized groups local pg = t.group('pgroup', {{engine = 'memtx'}, {engine = 'vinyl'}}) pg.test_example_3 = function(cg) -- Use cg.params here box.schema.space.create('test', { engine = cg.params.engine, }) end -- Hooks can be specified for one parameter pg.before_all({engine = 'memtx'}, function() ... end) pg.before_each({engine = 'memtx'}, function() ... end) Tarantool https://github.com/tarantool/l uatest/
  • 30.
    local function sum_up_to(n) localsum = 0 for i = 1, n do sum = sum + i end return sum end property 'sum of numbers is equal to (n + 1) * n / 2' { generators = { int(100) }, check = function(n) return sum_up_to(n) == (n + 1) * n / 2 end } https://github.com/luc-tielen/lua-quickcheck
  • 32.
    Lua ---@alias hookmaskstring ---|+'"c"' # Calls hook when Lua calls a function. ---|+'"r"' # Calls hook when Lua returns from a function. ---|+'"l"' # Calls hook when Lua enters a new line of code. --- ---Sets the given function as a hook. --- ---[View documents](command:extension.lua.doc?["en- us/51/manual.html/pdf-debug.sethook"]) --- ---@overload fun(hook: function, mask: hookmask, count?: integer) ---@param thread thread ---@param hook async fun() ---@param mask hookmask ---@param count? Integer function debug.sethook(thread, hook, mask, count) end
  • 33.
    Lua ---@param co?thread ---@return function hook ---@return string mask ---@return integer count ---@nodiscard function debug.gethook(co) end ---@alias infowhat string ---|+'"n"' # `name` and `namewhat` ---|+'"S"' # `source`, `short_src`, `linedefined`, `lastlinedefined`, and `what` ---|+'"l"' # `currentline` ---|+'"t"' # `istailcall` ---|+'"u"' # `nups`, `nparams`, and `isvararg` ---|+'"f"' # `func` ---|+'"L"' # `activelines`
  • 34.
    Lua --- ---Returns atable with information about a function. --- ---[View documents](command:extension.lua.doc?["en- us/51/manual.html/pdf-debug.getinfo"]) --- ---@overload fun(f: integer|function, what?: infowhat):debuginfo ---@param thread thread ---@param f integer|async fun() ---@param what? infowhat ---@return debuginfo ---@nodiscard function debug.getinfo(thread, f, what) end
  • 35.
    Lua --- ---Assigns the`value` to the local variable with index `local` of the function at `level` of the stack. --- ---[View documents](command:extension.lua.doc?["en- us/51/manual.html/pdf-debug.setlocal"]) --- ---@overload fun(level: integer, index: integer, value: any):string ---@param thread thread ---@param level integer ---@param index integer ---@param value any ---@return string name function debug.setlocal(thread, level, index, value) end
  • 36.
    Lua --- ---Returns thename and the value of the local variable with index `local` of the function at level `f` of the stack. --- ---[View documents](command:extension.lua.doc?["en- us/51/manual.html/pdf-debug.getlocal"]) --- ---@overload fun(f: integer|async fun(), index: integer):string, any ---@param thread thread ---@param f integer|async fun() ---@param index integer ---@return string name ---@return any value ---@nodiscard function debug.getlocal(thread, f, index) end
  • 37.
    Lua --- ---Returns the nameand the value of the upvalue with index `up` of the function. --- ---[View documents](command:extension.lua.doc?["en- us/51/manual.html/pdf-debug.getupvalue"]) --- ---@param f async fun() ---@param up integer ---@return string name ---@return any value ---@nodiscard function debug.getupvalue(f, up) end
  • 38.
    Lua --- ---Returns astring with a traceback of the call stack. The optional message string is appended at the beginning of the traceback. --- ---[View documents](command:extension.lua.doc?["en- us/51/manual.html/pdf-debug.traceback"]) --- ---@overload fun(message?: any, level?: integer): string ---@param thread thread ---@param message? any ---@param level? integer ---@return string message ---@nodiscard function debug.traceback(thread, message, level) end
  • 39.
    Debug API: local loadFunct= assert( loadfile(fileToExec) ) debug.sethook(covHandler, "l" ) -- Workaround: coroutines require us to sethook again. local oldCreate = coroutine.create coroutine.create = function( coFunct ) return oldCreate( function(...) debug.sethook(covHandler, "l" ) return coFunct(unpack(arg)) end) end loadFunct() -- run the main program M.stop() function M.stop() debug.sethook() … end end
  • 40.
    Debug API: functiontraceback () local level = 1 while true do local info = debug.getinfo(level, "Sl") if not info then break end if info.what == "C" then -- is a C function? print(level, "C function") else -- a Lua function print(string.format("[%s]:%d", info.short_src, info.currentline)) end level = level + 1 end end `n´ selects fields name and namewhat `f´ selects field func `S´ selects fields source, short_src, what, and linedefined `l´ selects field currentline `u´ selects field nup
  • 42.
    • gperftools, callgrindпокажут граф вызовов на уровне Си • jit.p позволит собрать граф вызовов в LuaJIT • Но никто не соберёт всё вместе
  • 43.
    • Строчный хукпозволяет собрать профиль исполнения • Тайминги будут неверные… • … но счетчикам строк верить можно • Luacov - https://github.com/keplerproject/luacov
  • 44.
    ****0 local interval_mt= { new = interval_new, } ****0 return setmetatable( { new = datetime_new, interval = setmetatable(interval_mt, interval_mt), now = datetime_now, is_datetime = is_datetime, ****0 }, {} ) ==================================================================== Summary ==================================================================== File Hits Missed Coverage ----------------------------------------- builtin/datetime.lua 515 76 87.14% ----------------------------------------- Total 515 76 87.14% https://github.com/tarantool/tarantool/ wiki/How-to-generate-Lua-coverage- report-for-built-in-module%3F
  • 45.
    • Luatrace -https://github.com/geoffleyland/luatrace “luatrace is a Lua module that collects information about what your code is doing and how long it takes, and can analyse that information to generate profile and coverage reports. luatrace adds a layer on top of Lua's debug hooks to make it easier to collect information for profiling and coverage analysis. luatrace traces of every line executed, not just calls. luatrace can trace through coroutine resumes and yields, and through xpcalls, pcalls and errors. On some platforms it uses high resolution timers to collect times of the order of nanoseconds.”
  • 46.
  • 47.
  • 49.
    Lua – язык,с динамической типизацией Нет проверок времени компиляции Но можно использовать внешний линтер для статического анализа кода
  • 50.
    std = "luajit" globals= {"box", "_TARANTOOL", "tonumber64"} ignore = { -- Accessing an undefined field of a global variable <debug>. "143/debug", -- Accessing an undefined field of a global variable <string>. "143/string", -- Accessing an undefined field of a global variable <table>. "143/table", -- Unused argument <self>. "212/self", -- Redefining a local variable. "411", -- Redefining an argument. "412", -- line contains only whitespace "611", } include_files = { "**/*.lua", } exclude_files = { "build*/**/*.lua", -- Third-party source code. "test-run/**/*.lua", ".rocks/**/*.lua", ".git/**/*.lua", }
  • 51.
    std = "tarantool" include_files= { '**/*.lua', '*.luacheckrc', '*.rockspec' } exclude_files = { '.rocks/', 'tmp/' } max_line_length = 120
  • 53.
  • 55.
    require('checks') local function get_stat(uri,opts) checks('string', {timeout = '?number'}) end get_stat() -- error: bad argument #1 to get_stat (string expected, got nil) get_stat('localhost', {timeuot = 1}) -- error: unexpected argument opts.timeuot to get_stat 13 get_stat('localhost', {timeuot = 1}) -- ^^ typo -- No error, but does not work as expected -- Still bad https://github.com/tarantool/checks
  • 56.
    • https://teal-playground.netlify.app/ • https://github.com/teal-language/teal- types/tree/master/types/penlight/pl •https://github.com/teal-language/vscode-teal • https://github.com/teal-language/vim-teal
  • 57.
    Teal – local ltn12= require("ltn12") local Sink = ltn12.Sink local Source = ltn12.Source local record socket record TCP -- master methods bind: function(TCP, string, integer) connect: function(TCP, string, integer): integer, string listen: function(TCP, integer): integer, string -- client methods getpeername: function(TCP): string, integer enum TCPReceivePattern "*l" "*a" end enum TCPReceiveError "closed" "timeout" end receive: function(TCP, TCPReceivePattern|integer, string): string, TCPReceiveError https://github.com/teal-language/teal- types/blob/master/types/luasocket/socket.d.tl
  • 59.
    • Нет готовогорешения с удобным отладчиком • Есть отладчик в Redis как артефакт поддержки в ZeroBrane Studio Павла Ключенко • Есть популярный модуль Mobdebug того же Павла Ключенко • Развитие RemDebug; • Mobdebug можно поднять почти везде, где есть LuaSocket; • Есть надежды зайти через VSCode Debug Adapter API
  • 63.
    • https://github.com/devcat-studio/VSCodeLuaDebug • форкhttps://github.com/microsoft/vscode-mono-debug • https://github.com/BeamNG/VSCodeLuaDebug
  • 65.
  • 66.
    Basically Vscode-debuggee.lua dropsthe speed of running Lua programs because it implements the breakpoint mechanism using debug.sethook. This performance degradation can be overcome by applying a simple patch to the Lua VM. Download: lua 5.1.5 : Patch, Code lua 5.3.4 : Patch, Code https://marketplace.visualstudio.com/items?itemName=devCAT.lua-debug
  • 68.