Page 1 of 6
SUPER STRICT for LUA
Posted: Thu Dec 31, 2020 2:46 pm
by ivan
SUPER STRICT for LUA
SUPER STRICT finds undeclared variables and other mistakes in your Lua source code as soon as the file is loaded.
Code: Select all
local function myFunc()
a = 5 -- undefined variable 'a'
end
--myFunc() -- an error is detected without even calling myFunc!
Installation of SUPER STRICT is SUPER easy.
Include the "sstrict.lua" file and any subsequent calls to "require" will be checked through SUPER STRICT.
Repository:
https://github.com/2dengine/sstrict.lua
Re: SUPER STRICT for LUA
Posted: Sun Jan 10, 2021 3:53 pm
by ivan
Great news! SUPERSTRICT now detects unused variables in your Lua scripts:
Make sure to use the underscore symbol "_" to avoid this error.
Code: Select all
local list = {1,2,3}
local sum = 0
for i, v in ipairs(list) do -- unused variable 'i'
sum = sum + v
end
Also pushed an optimization update so that a 2 MB Lua file is parsed in about 12 seconds.
Re: SUPER STRICT for LUA
Posted: Mon Jan 11, 2021 12:18 am
by grump
Gave it a quick test.
It doesn't seem to respect package.path correctly.
Code: Select all
package.path = package.path .. ';?/init.lua'
require('sstrict')
require('test') -- should end up requiring ./test/init.lua
Code: Select all
Error: sstrict.lua:656: file not found:test
The test module exists and does work correctly without sstrict.lua.
If you want this to be 100% compatible with LÖVE, you have to respect love.filesystem.getRequirePath() as well.
C modules can't be required (file not found), nor can the built-in bit module, nor love modules.
Byte code is not accepted either, it should at least detect and ignore, or maybe warn about byte code.
Some valid LuaJIT syntax is not supported:
Code: Select all
local foo = 0x1ULL -- works
local foo = 0x1LL -- undefined variable 'LL'
local foo = 0x1ull -- undefined variable 'ull'
local foo = 0x1ll -- undefined variable 'll'
local foo = 1ULL -- undefined variable 'ULL'
local foo = 1LL -- undefined variable 'LL'
local foo = 0x1p1 -- undefined variable 'p1'
local foo = 12.5i -- undefined variable 'i'
Parser shits the bed sometimes with some edge cases:
Code: Select all
global1 = 'foo' -- sstrict complains correctly
--[[]] global2 = 'foo' -- not detected
Code: Select all
--[=[
nothing
]=]
-- (undefined variable 'nothing')
Code: Select all
#--[[ (first line of file)
-- rest of file is ignored
The first line in a file should be ignored if it starts with a # (
per specification)
A scenario that is unsolvable with your general approach:
Code: Select all
local function foo()
return baz
end
setfenv(foo, { baz = 'bar' })()
Basing a Lua parser in pattern matching is a nasty can of worms. Unless the subset you want to support is small enough to make it work, you might end up fixing edge cases until the end of times.
Re: SUPER STRICT for LUA
Posted: Mon Jan 11, 2021 1:50 pm
by ivan
Thanks for the feedback, grump. I have pushed a fix on BitBucket for the following bugs:
Code: Select all
local foo = 0x1ULL -- works
local foo = 0x1LL -- undefined variable 'LL'
local foo = 0x1ull -- undefined variable 'ull'
local foo = 0x1ll -- undefined variable 'll'
local foo = 1ULL -- undefined variable 'ULL'
local foo = 1LL -- undefined variable 'LL'
I need help/documentation regarding:
Code: Select all
local foo = 0x1p1 -- undefined variable 'p1'
local foo = 12.5i -- undefined variable 'i'
The comments thing is a little more complicated. It is possible to solve these bugs but yea I will have to think about this one.
I promise to look into the require path issue too.
A scenario that is unsolvable with your general approach:
Yes, "setfenv" is not supported. A partial solution could be to use the traditional "strict.lua" in conjunction with SUPERSTRICT. Note that loadstring is not supported either at the time of this post.
Basing a Lua parser in pattern matching is a nasty can of worms
You are correct. Parsing the entire Lua language is a big task. SUPERSTRICT is NOT perfect by any means and it's open source if you want to contribute. Generally speaking it does help in finding bugs that are missed completely by "strict.lua"
Re: SUPER STRICT for LUA
Posted: Mon Jan 11, 2021 4:27 pm
by grump
ivan wrote: ↑Mon Jan 11, 2021 1:50 pm
I need help/documentation regarding:
Code: Select all
local foo = 0x1p1 -- undefined variable 'p1'
local foo = 12.5i -- undefined variable 'i'
p/P is used for binary exponents. It's a
Lua 5.2 thing that's also supported in LuaJIT.
The i/I suffix is an
obscure LuaJIT feature (bottom of the page) to specify the imaginary part of complex numbers.
Allowing directives in the code to exclude chunks from checks would be helpful. Something like
Code: Select all
--!nostrict
local function foo()
return baz
end
--!strict
setfenv(foo, { baz = 'bar' })()
That would allow unsupported/problematic code in projects that want to use sstrict.
Re: SUPER STRICT for LUA
Posted: Mon Jan 11, 2021 5:16 pm
by pgimeno
Funny, for me, PUC Lua 5.1 accepts 0x1p3 but not 0x1.0p3.
Formally, hex floats are numbers of the form 0x{hex digits}[. [hex digits]]p[+/-]{dec digits}, or 0x{. hex digits}p[+/-]{dec digits} (case insensitive), where [] indicates optional and {} mandatory. They are always in mantissa-exponent notation, where the mantissa is a hex number and the exponent (the number after the p) is a power of 2 instead of 10.
Re: SUPER STRICT for LUA
Posted: Mon Jan 11, 2021 6:32 pm
by ivan
Thanks again for the feedback.
I have changed the following patterns:
Code: Select all
hexp = "0x%x+[Pp][%-%+]?%x"
float = "%d*%.%d+[Ii]?"
So I think this should handle most of these weird-looking numbers, but more testing wouldn't hurt.
Additionally the comment bugs should be fixed after the latest patch on Bitbucket.
I have added the love2d require path too. Can you please check that it works on your machine?
I have also added the following one-liner (no spaces) which toggles the error reporting on and off:
This one will need more work and testing because I'm NOT sure that you can disable SUPERSTRICT for
just a section of the file.
Re: SUPER STRICT for LUA
Posted: Mon Jan 11, 2021 8:21 pm
by grump
ivan wrote: ↑Mon Jan 11, 2021 6:32 pm
I have added the love2d require path too. Can you please check that it works on your machine?
Nice. package.path and love's require path are working for me now.
Note that [[double brackets]] can have
any number of [===]equal signs[===] inside them, but it's still considered a double bracket. There seems to be a parser issue left with that syntax:
Code: Select all
-- this code does not trigger any errors or warnings in sstrict
--[=[ i'm just a comment lol ]=]
global = 1
-- ...while this does
--[[ i'm just a comment lol ]]
global = 1
This one will need more work and testing because I'm NOT sure that you can disable SUPERSTRICT for just a section of the file.
Fair enough, but imo some kind of control is required, because making changes to correct code just to overcome the shortcomings of an analyzer is too much to ask. I think it's perfectly fine to provide an opt out with a fine level of granularity to help resolve the static analysis vs. dynamic runtime problem.
I tried using it with a larger project, but it really doesn't like C modules. And C modules exporting globals is probably double the trouble.
Re: SUPER STRICT for LUA
Posted: Mon Jan 11, 2021 8:50 pm
by ivan
Sorry about that, I have pushed another fix and the comment issue seems to be resolved now.
Note that [[double brackets]] can have any number of [===]equal signs[===] inside them
Thanks, I was not aware of this!
Fair enough, but imo some kind of control is required, because making changes to correct code just to overcome the shortcomings of an analyzer is too much to ask
Just put --!strict at the top of the file and that should disable all error messages
Re: SUPER STRICT for LUA
Posted: Mon Jan 11, 2021 9:01 pm
by ivan
I tried using it with a larger project, but it really doesn't like C modules. And C modules exporting globals is probably double the trouble.
I'll make if work if you show me a concrete example.