Skip to content

Commit f63375d

Browse files
committed
more diagnostics for global
1 parent 76295c2 commit f63375d

File tree

9 files changed

+202
-152
lines changed

9 files changed

+202
-152
lines changed

script/core/diagnostics/lowercase-global.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ return function (uri, callback)
4343
local definedGlobalRegex = config.get(uri, 'Lua.diagnostics.globalsRegex')
4444

4545
guide.eachSourceType(ast.ast, 'setglobal', function (source)
46+
if source.declare then
47+
return
48+
end
4649
local name = guide.getKeyName(source)
4750
if not name or definedGlobal[name] then
4851
return

script/parser/compile.lua

Lines changed: 157 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -753,9 +753,156 @@ local function createLocal(obj, attrs)
753753
return obj
754754
end
755755

756+
local function getLocal(name, pos)
757+
for i = #Chunk, 1, -1 do
758+
local chunk = Chunk[i]
759+
local locals = chunk.locals
760+
if locals then
761+
local res
762+
for n = 1, #locals do
763+
local loc = locals[n]
764+
if loc.effect > pos then
765+
break
766+
end
767+
if loc[1] == name then
768+
if not res or res.effect < loc.effect then
769+
res = loc
770+
end
771+
end
772+
end
773+
if res then
774+
return res
775+
end
776+
end
777+
end
778+
end
779+
780+
local function getVariable(name, pos)
781+
for i = #Chunk, 1, -1 do
782+
local chunk = Chunk[i]
783+
local resLocal
784+
local resGlobal
785+
786+
-- Find most recent local in this chunk
787+
local locals = chunk.locals
788+
if locals then
789+
for n = 1, #locals do
790+
local loc = locals[n]
791+
if loc.effect > pos then
792+
break
793+
end
794+
if loc[1] == name then
795+
if not resLocal or resLocal.effect < loc.effect then
796+
resLocal = loc
797+
end
798+
end
799+
end
800+
end
801+
802+
-- Find global in this chunk (globals don't have effect time, just find the last one)
803+
local globals = chunk.globals
804+
if globals then
805+
for n = #globals, 1, -1 do
806+
local glob = globals[n]
807+
if glob[1] == name then
808+
resGlobal = glob
809+
break
810+
end
811+
end
812+
end
813+
814+
-- Return the one declared later (compare by start position)
815+
if resLocal and resGlobal then
816+
if resLocal.start > resGlobal.start then
817+
return resLocal
818+
else
819+
return resGlobal
820+
end
821+
end
822+
if resLocal then
823+
return resLocal
824+
end
825+
if resGlobal then
826+
return resGlobal
827+
end
828+
end
829+
830+
-- If not found, look for global *
831+
for i = #Chunk, 1, -1 do
832+
local chunk = Chunk[i]
833+
local globals = chunk.globals
834+
if globals then
835+
for n = #globals, 1, -1 do
836+
local glob = globals[n]
837+
if glob[1] == '*' then
838+
return glob
839+
end
840+
end
841+
end
842+
end
843+
844+
return nil
845+
end
846+
847+
local function linkGlobalToEnv(node, var)
848+
-- Lua 5.5: Check VARIABLE_NOT_DECLARED
849+
if State.version == 'Lua 5.5' and not var then
850+
-- Check if there's any global declaration in scope
851+
local hasAnyGlobal = false
852+
for i = #Chunk, 1, -1 do
853+
local chunk = Chunk[i]
854+
if chunk.globals and #chunk.globals > 0 then
855+
hasAnyGlobal = true
856+
break
857+
end
858+
end
859+
860+
if hasAnyGlobal then
861+
pushError {
862+
type = 'VARIABLE_NOT_DECLARED',
863+
start = node.start,
864+
finish = node.finish,
865+
}
866+
end
867+
end
868+
869+
-- Lua 5.5: Use getVariable to find _ENV, check if it's global
870+
local env
871+
if State.version == 'Lua 5.5' then
872+
env = getVariable(State.ENVMode, node.start)
873+
if env and env.type == 'global' then
874+
pushError {
875+
type = 'RUNTIME_ERROR',
876+
start = node.start,
877+
finish = node.finish,
878+
info = {
879+
message = '_ENV is global when accessing variable'
880+
}
881+
}
882+
end
883+
if env and env.type == 'local' then
884+
node.node = env
885+
if not env.ref then
886+
env.ref = {}
887+
end
888+
env.ref[#env.ref+1] = node
889+
end
890+
else
891+
env = getLocal(State.ENVMode, node.start)
892+
if env then
893+
node.node = env
894+
if not env.ref then
895+
env.ref = {}
896+
end
897+
env.ref[#env.ref+1] = node
898+
end
899+
end
900+
end
901+
756902
---@param obj table
757-
local function createGlobal(obj, attrs)
758-
obj.type = 'globaldeclare'
903+
local function createGlobalDeclare(obj, attrs)
904+
obj.type = 'setglobal'
905+
obj.declare = true
759906

760907
if attrs then
761908
obj.attrs = attrs
@@ -771,6 +918,9 @@ local function createGlobal(obj, attrs)
771918
end
772919
globals[#globals+1] = obj
773920
end
921+
922+
linkGlobalToEnv(obj, obj)
923+
774924
return obj
775925
end
776926

@@ -2111,97 +2261,6 @@ local function parseParen()
21112261
return paren
21122262
end
21132263

2114-
local function getLocal(name, pos)
2115-
for i = #Chunk, 1, -1 do
2116-
local chunk = Chunk[i]
2117-
local locals = chunk.locals
2118-
if locals then
2119-
local res
2120-
for n = 1, #locals do
2121-
local loc = locals[n]
2122-
if loc.effect > pos then
2123-
break
2124-
end
2125-
if loc[1] == name then
2126-
if not res or res.effect < loc.effect then
2127-
res = loc
2128-
end
2129-
end
2130-
end
2131-
if res then
2132-
return res
2133-
end
2134-
end
2135-
end
2136-
end
2137-
2138-
local function getVariable(name, pos)
2139-
for i = #Chunk, 1, -1 do
2140-
local chunk = Chunk[i]
2141-
local resLocal
2142-
local resGlobal
2143-
2144-
-- Find most recent local in this chunk
2145-
local locals = chunk.locals
2146-
if locals then
2147-
for n = 1, #locals do
2148-
local loc = locals[n]
2149-
if loc.effect > pos then
2150-
break
2151-
end
2152-
if loc[1] == name then
2153-
if not resLocal or resLocal.effect < loc.effect then
2154-
resLocal = loc
2155-
end
2156-
end
2157-
end
2158-
end
2159-
2160-
-- Find global in this chunk (globals don't have effect time, just find the last one)
2161-
local globals = chunk.globals
2162-
if globals then
2163-
for n = #globals, 1, -1 do
2164-
local glob = globals[n]
2165-
if glob[1] == name then
2166-
resGlobal = glob
2167-
break
2168-
end
2169-
end
2170-
end
2171-
2172-
-- Return the one declared later (compare by start position)
2173-
if resLocal and resGlobal then
2174-
if resLocal.start > resGlobal.start then
2175-
return resLocal
2176-
else
2177-
return resGlobal
2178-
end
2179-
end
2180-
if resLocal then
2181-
return resLocal
2182-
end
2183-
if resGlobal then
2184-
return resGlobal
2185-
end
2186-
end
2187-
2188-
-- If not found, look for global *
2189-
for i = #Chunk, 1, -1 do
2190-
local chunk = Chunk[i]
2191-
local globals = chunk.globals
2192-
if globals then
2193-
for n = #globals, 1, -1 do
2194-
local glob = globals[n]
2195-
if glob[1] == '*' then
2196-
return glob
2197-
end
2198-
end
2199-
end
2200-
end
2201-
2202-
return nil
2203-
end
2204-
22052264
local function resolveName(node)
22062265
if not node then
22072266
return nil
@@ -2221,58 +2280,7 @@ local function resolveName(node)
22212280
node.type = 'getglobal'
22222281
node.var = var
22232282

2224-
-- Lua 5.5: Check VARIABLE_NOT_DECLARED
2225-
if State.version == 'Lua 5.5' and not var then
2226-
-- Check if there's any global declaration in scope
2227-
local hasAnyGlobal = false
2228-
for i = #Chunk, 1, -1 do
2229-
local chunk = Chunk[i]
2230-
if chunk.globals and #chunk.globals > 0 then
2231-
hasAnyGlobal = true
2232-
break
2233-
end
2234-
end
2235-
2236-
if hasAnyGlobal then
2237-
pushError {
2238-
type = 'VARIABLE_NOT_DECLARED',
2239-
start = node.start,
2240-
finish = node.finish,
2241-
}
2242-
end
2243-
end
2244-
2245-
-- Lua 5.5: Use getVariable to find _ENV, check if it's global
2246-
local env
2247-
if State.version == 'Lua 5.5' then
2248-
env = getVariable(State.ENVMode, node.start)
2249-
if env and env.type == 'global' then
2250-
pushError {
2251-
type = 'RUNTIME_ERROR',
2252-
start = node.start,
2253-
finish = node.finish,
2254-
info = {
2255-
message = '_ENV is global when accessing variable'
2256-
}
2257-
}
2258-
end
2259-
if env and env.type == 'local' then
2260-
node.node = env
2261-
if not env.ref then
2262-
env.ref = {}
2263-
end
2264-
env.ref[#env.ref+1] = node
2265-
end
2266-
else
2267-
env = getLocal(State.ENVMode, node.start)
2268-
if env then
2269-
node.node = env
2270-
if not env.ref then
2271-
env.ref = {}
2272-
end
2273-
env.ref[#env.ref+1] = node
2274-
end
2275-
end
2283+
linkGlobalToEnv(node, var)
22762284
end
22772285
local name = node[1]
22782286
bindSpecial(node, name)
@@ -3344,7 +3352,7 @@ local function parseGlobal()
33443352
name.vstart = func.start
33453353
name.range = func.finish
33463354
func.parent = name
3347-
createGlobal(name)
3355+
createGlobalDeclare(name)
33483356
pushActionIntoCurrentChunk(name)
33493357
return name
33503358
else
@@ -3378,7 +3386,7 @@ local function parseGlobal()
33783386
end
33793387
end
33803388
end
3381-
createGlobal(action, attrs)
3389+
createGlobalDeclare(action, attrs)
33823390
Index = Index + 2
33833391
pushActionIntoCurrentChunk(action)
33843392
return action
@@ -3437,7 +3445,7 @@ local function parseGlobal()
34373445
glob.finish = attrsAfter[#attrsAfter].finish
34383446
end
34393447

3440-
createGlobal(glob, glob.attrs)
3448+
createGlobalDeclare(glob, glob.attrs)
34413449
pushActionIntoCurrentChunk(glob)
34423450
skipSpace()
34433451

@@ -3485,7 +3493,7 @@ local function parseGlobal()
34853493
end
34863494
gN.finish = attrsNAfter[#attrsNAfter].finish
34873495
end
3488-
createGlobal(gN, gN.attrs)
3496+
createGlobalDeclare(gN, gN.attrs)
34893497
return gN
34903498
end
34913499
return nil

script/parser/guide.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ local type = type
7777
---@field [integer] parser.object|any
7878
---@field dot { type: string, start: integer, finish: integer }
7979
---@field colon { type: string, start: integer, finish: integer }
80+
---@field declare? boolean
8081
---@field package _root parser.object
8182
---@field package _eachCache? parser.object[]
8283
---@field package _isGlobal? boolean

script/vm/compiler.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1694,7 +1694,7 @@ local compilerSwitch = util.switch()
16941694
if vm.bindDocs(source) then
16951695
return
16961696
end
1697-
if source.node[1] ~= '_ENV' then
1697+
if source.node and source.node[1] ~= '_ENV' then
16981698
return
16991699
end
17001700
if not source.value then

0 commit comments

Comments
 (0)