Skip to content

Commit 2b6151a

Browse files
committed
Add support for getmetatable
1 parent 759e8fb commit 2b6151a

File tree

3 files changed

+101
-2
lines changed

3 files changed

+101
-2
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<!-- Add all new changes here. They will be moved under a version at release -->
55
* `FIX` cannot debug in Linux due to lua-debug expecting host process to have lua54 symbols available
66
* `FIX` support hex color codes with `#` in `textDocument/documentColor`
7+
* `NEW` type reference from `getmetatable` is supported now
78

89
## 3.14.0
910
`2025-4-7`

script/parser/compile.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ local Specials = {
108108
['rawset'] = true,
109109
['rawget'] = true,
110110
['setmetatable'] = true,
111+
['getmetatable'] = true,
111112
['require'] = true,
112113
['dofile'] = true,
113114
['loadfile'] = true,

script/vm/compiler.lua

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -632,9 +632,21 @@ local function getReturnOfSetMetaTable(args)
632632
local mt = args[2]
633633
local node = vm.createNode()
634634
if tbl then
635-
node:merge(vm.compileNode(tbl))
635+
local tblNode = vm.compileNode(tbl)
636+
node:merge(tblNode)
637+
638+
-- 存储元表信息,将mt节点作为源节点的元表
639+
if mt then
640+
local mtNode = vm.compileNode(mt)
641+
-- 为节点添加metatable属性
642+
for n in tblNode:eachObject() do
643+
n.metatable = mtNode
644+
end
645+
end
636646
end
647+
637648
if mt then
649+
-- 合并__index属性到返回节点
638650
vm.compileByParentNodeAll(mt, '__index', function (src)
639651
for n in vm.compileNode(src):eachObject() do
640652
if n.type == 'global'
@@ -647,7 +659,85 @@ local function getReturnOfSetMetaTable(args)
647659
end)
648660
end
649661
--过滤nil
650-
node:remove 'nil'
662+
node:remove 'nil'
663+
return node
664+
end
665+
666+
---@param args parser.object[]
667+
---@return vm.node
668+
local function getReturnOfGetMetaTable(args)
669+
local obj = args[1]
670+
local node = vm.createNode()
671+
if not obj then
672+
return node
673+
end
674+
675+
local objNode = vm.compileNode(obj)
676+
local foundMetatable = false
677+
678+
-- 尝试遍历对象的所有可能类型
679+
for n in objNode:eachObject() do
680+
-- 检查是否有metatable属性
681+
if n.metatable then
682+
-- 先检查元表中是否有__metatable字段
683+
local hasMetaField = false
684+
for mt in n.metatable:eachObject() do
685+
if mt.type == 'table' then
686+
-- 尝试从元表中查找__metatable字段
687+
vm.compileByParentNodeAll(mt, '__metatable', function (src)
688+
hasMetaField = true
689+
-- 使用__metatable字段的值作为返回值
690+
for metaObj in vm.compileNode(src):eachObject() do
691+
node:merge(metaObj)
692+
end
693+
end)
694+
end
695+
end
696+
697+
-- 如果没有__metatable字段,则返回元表本身
698+
if not hasMetaField then
699+
node:merge(n.metatable)
700+
end
701+
702+
foundMetatable = true
703+
end
704+
705+
-- 检查是否有setmetatable调用
706+
if not foundMetatable and n.value and n.value.type == 'call' and n.value.node and n.value.node.special == 'setmetatable' and n.value.args and n.value.args[2] then
707+
local mtArg = n.value.args[2]
708+
local mtNode = vm.compileNode(mtArg)
709+
710+
-- 检查元表参数中是否有__metatable字段
711+
local hasMetaField = false
712+
-- 尝试从元表参数中查找__metatable字段
713+
vm.compileByParentNodeAll(mtArg, '__metatable', function (src)
714+
hasMetaField = true
715+
-- 使用__metatable字段的值作为返回值
716+
for metaObj in vm.compileNode(src):eachObject() do
717+
node:merge(metaObj)
718+
end
719+
end)
720+
721+
-- 如果没有__metatable字段,则返回元表本身
722+
if not hasMetaField then
723+
node:merge(mtNode)
724+
end
725+
726+
foundMetatable = true
727+
end
728+
end
729+
730+
-- 如果没有找到任何元表信息,创建一个空表类型
731+
if not foundMetatable then
732+
local tableObj = {
733+
type = 'table',
734+
start = obj.start or 0,
735+
finish = obj.finish or 0,
736+
}
737+
node:merge(tableObj)
738+
end
739+
740+
node:remove 'nil'
651741
return node
652742
end
653743

@@ -1865,6 +1955,13 @@ local compilerSwitch = util.switch()
18651955
vm.setNode(source, getReturnOfSetMetaTable(args))
18661956
return
18671957
end
1958+
if func.special == 'getmetatable' then
1959+
if not args then
1960+
return
1961+
end
1962+
vm.setNode(source, getReturnOfGetMetaTable(args))
1963+
return
1964+
end
18681965
if func.special == 'pcall' and index > 1 then
18691966
if not args then
18701967
return

0 commit comments

Comments
 (0)