Skip to content

Commit a50369c

Browse files
committed
getVariable
1 parent ad5a1ec commit a50369c

File tree

1 file changed

+142
-44
lines changed

1 file changed

+142
-44
lines changed

script/parser/compile.lua

Lines changed: 142 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -753,10 +753,43 @@ local function createLocal(obj, attrs)
753753
return obj
754754
end
755755

756+
---@param obj table
757+
local function createGlobal(obj, attrs)
758+
obj.type = 'global'
759+
760+
if attrs then
761+
obj.attrs = attrs
762+
attrs.parent = obj
763+
end
764+
765+
local chunk = Chunk[#Chunk]
766+
if chunk then
767+
local globals = chunk.globals
768+
if not globals then
769+
globals = {}
770+
chunk.globals = globals
771+
end
772+
globals[#globals+1] = obj
773+
end
774+
return obj
775+
end
776+
756777
local function pushChunk(chunk)
757778
Chunk[#Chunk+1] = chunk
758779
end
759780

781+
local function hasAttr(attrs, attrName)
782+
if not attrs then
783+
return false
784+
end
785+
for i = 1, #attrs do
786+
if attrs[i][1] == attrName then
787+
return true
788+
end
789+
end
790+
return false
791+
end
792+
760793
local function resolveLable(label, obj)
761794
if not label.ref then
762795
label.ref = {}
@@ -2102,23 +2135,77 @@ local function getLocal(name, pos)
21022135
end
21032136
end
21042137

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+
return nil
2189+
end
2190+
21052191
local function resolveName(node)
21062192
if not node then
21072193
return nil
21082194
end
2109-
local loc = getLocal(node[1], node.start)
2110-
if loc then
2195+
local var = getVariable(node[1], node.start)
2196+
if var and var.type == 'local' then
21112197
node.type = 'getlocal'
2112-
node.node = loc
2113-
if not loc.ref then
2114-
loc.ref = {}
2198+
node.node = var
2199+
if not var.ref then
2200+
var.ref = {}
21152201
end
2116-
loc.ref[#loc.ref+1] = node
2117-
if loc.special then
2118-
addSpecial(loc.special, node)
2202+
var.ref[#var.ref+1] = node
2203+
if var.special then
2204+
addSpecial(var.special, node)
21192205
end
21202206
else
21212207
node.type = 'getglobal'
2208+
node.var = var
21222209
local env = getLocal(State.ENVMode, node.start)
21232210
if env then
21242211
node.node = env
@@ -2905,19 +2992,45 @@ local function bindValue(n, v, index, lastValue, isLocal, isSet)
29052992
end
29062993
end
29072994
if n.type == 'setglobal' then
2908-
local gi = State.globalInfo
29092995
local nameKey = n[1]
2910-
-- assignment / definition in strict global scope
2911-
if gi.active then
2912-
local info = gi.names[nameKey]
2913-
if not gi.hasAll and not info then
2996+
-- check if in strict global scope (any chunk has globals declared)
2997+
local hasGlobalDecl = false
2998+
local hasGlobalAll = false
2999+
local globalAllConst = false
3000+
local declaredGlobal = nil
3001+
3002+
for i = #Chunk, 1, -1 do
3003+
local chunk = Chunk[i]
3004+
if chunk.globals then
3005+
hasGlobalDecl = true
3006+
for j = 1, #chunk.globals do
3007+
if chunk.globals[j][1] == nameKey then
3008+
declaredGlobal = chunk.globals[j]
3009+
break
3010+
end
3011+
end
3012+
end
3013+
if chunk.hasGlobalAll then
3014+
hasGlobalAll = true
3015+
if chunk.globalAllConst then
3016+
globalAllConst = true
3017+
end
3018+
end
3019+
if declaredGlobal or hasGlobalAll then
3020+
break
3021+
end
3022+
end
3023+
3024+
-- assignment in strict global scope
3025+
if hasGlobalDecl or hasGlobalAll then
3026+
if not hasGlobalAll and not declaredGlobal then
29143027
pushError {
29153028
type = 'UNDEFINED_IN_GLOBAL_SCOPE',
29163029
start = n.start,
29173030
finish = n.finish,
29183031
}
29193032
end
2920-
local isConst = (info and info.const) or gi.allConst
3033+
local isConst = (declaredGlobal and declaredGlobal.attrs and hasAttr(declaredGlobal.attrs, 'const')) or globalAllConst
29213034
if isConst then
29223035
pushError {
29233036
type = 'ASSIGN_CONST_GLOBAL',
@@ -3205,10 +3318,7 @@ local function parseGlobal()
32053318
name.vstart = func.start
32063319
name.range = func.finish
32073320
func.parent = name
3208-
local gi = State.globalInfo
3209-
gi.active = true
3210-
local nameKey = name[1]
3211-
gi.names[nameKey] = gi.names[nameKey] or { declared = true, const = false }
3321+
createGlobal(name)
32123322
pushActionIntoCurrentChunk(name)
32133323
return name
32143324
else
@@ -3228,9 +3338,18 @@ local function parseGlobal()
32283338
finish = getPosition(Tokens[Index], 'right'),
32293339
attrs = attrs,
32303340
}
3231-
local gi = State.globalInfo
3232-
gi.active = true
3233-
gi.hasAll = true
3341+
local chunk = Chunk[#Chunk]
3342+
if chunk then
3343+
chunk.hasGlobalAll = true
3344+
if attrs then
3345+
for i = 1, #attrs do
3346+
if attrs[i][1] == 'const' then
3347+
chunk.globalAllConst = true
3348+
break
3349+
end
3350+
end
3351+
end
3352+
end
32343353
if attrs then
32353354
attrs.parent = action
32363355
for i = 1, #attrs do
@@ -3241,8 +3360,6 @@ local function parseGlobal()
32413360
start = a.start,
32423361
finish = a.finish,
32433362
}
3244-
elseif a[1] == 'const' then
3245-
gi.allConst = true
32463363
end
32473364
end
32483365
end
@@ -3259,14 +3376,10 @@ local function parseGlobal()
32593376
end
32603377

32613378
local glob = {
3262-
type = 'setglobal',
32633379
start = name.start,
32643380
finish = name.finish,
32653381
[1] = name[1],
32663382
}
3267-
local gi = State.globalInfo
3268-
gi.active = true
3269-
gi.names[glob[1]] = gi.names[glob[1]] or { declared = true, const = false }
32703383

32713384
if attrs then
32723385
glob.attrs = attrs
@@ -3279,8 +3392,6 @@ local function parseGlobal()
32793392
start = attrs[i].start,
32803393
finish = attrs[i].finish,
32813394
}
3282-
elseif attrs[i][1] == 'const' then
3283-
gi.names[glob[1]].const = true
32843395
end
32853396
end
32863397
else
@@ -3297,8 +3408,6 @@ local function parseGlobal()
32973408
start = attrsAfter[i].start,
32983409
finish = attrsAfter[i].finish,
32993410
}
3300-
elseif attrsAfter[i][1] == 'const' then
3301-
gi.names[glob[1]].const = true
33023411
end
33033412
end
33043413
if glob.attrs then
@@ -3312,6 +3421,7 @@ local function parseGlobal()
33123421
glob.finish = attrsAfter[#attrsAfter].finish
33133422
end
33143423

3424+
createGlobal(glob, glob.attrs)
33153425
pushActionIntoCurrentChunk(glob)
33163426
skipSpace()
33173427

@@ -3321,12 +3431,10 @@ local function parseGlobal()
33213431
local nameN = parseName(true)
33223432
if nameN then
33233433
local gN = {
3324-
type = 'setglobal',
33253434
start = attrsN and attrsN.start or nameN.start,
33263435
finish = nameN.finish,
33273436
[1] = nameN[1],
33283437
}
3329-
gi.names[gN[1]] = gi.names[gN[1]] or { declared = true, const = false }
33303438
if attrsN then
33313439
gN.attrs = attrsN
33323440
attrsN.parent = gN
@@ -3337,8 +3445,6 @@ local function parseGlobal()
33373445
start = attrsN[i].start,
33383446
finish = attrsN[i].finish,
33393447
}
3340-
elseif attrsN[i][1] == 'const' then
3341-
gi.names[gN[1]].const = true
33423448
end
33433449
end
33443450
end
@@ -3351,8 +3457,6 @@ local function parseGlobal()
33513457
start = attrsNAfter[i].start,
33523458
finish = attrsNAfter[i].finish,
33533459
}
3354-
elseif attrsNAfter[i][1] == 'const' then
3355-
gi.names[gN[1]].const = true
33563460
end
33573461
end
33583462
if gN.attrs then
@@ -3365,6 +3469,7 @@ local function parseGlobal()
33653469
end
33663470
gN.finish = attrsNAfter[#attrsNAfter].finish
33673471
end
3472+
createGlobal(gN, gN.attrs)
33683473
return gN
33693474
end
33703475
return nil
@@ -4373,13 +4478,6 @@ local function initState(lua, version, options)
43734478
errs[#errs+1] = err
43744479
return err
43754480
end
4376-
-- Lua 5.5 global keyword semantic tracking (syntax-level errors)
4377-
state.globalInfo = {
4378-
names = {}, -- map name -> { declared=true, const=bool }
4379-
hasAll = false, -- global * encountered
4380-
allConst = false, -- global <const> * encountered
4381-
active = false, -- any global declaration activates strict global scope
4382-
}
43834481
end
43844482

43854483
return function (lua, mode, version, options)

0 commit comments

Comments
 (0)