summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server-beta/src/vm/getValue.lua262
-rw-r--r--server-beta/test/type_inference/init.lua2
2 files changed, 231 insertions, 33 deletions
diff --git a/server-beta/src/vm/getValue.lua b/server-beta/src/vm/getValue.lua
index b13d822d..d5db880b 100644
--- a/server-beta/src/vm/getValue.lua
+++ b/server-beta/src/vm/getValue.lua
@@ -187,37 +187,235 @@ local function checkBinary(source)
source = source,
}
elseif op.type == '<=' then
- elseif op.type == '>='
- or op.type == '<'
- or op.type == '>' then
- return 'boolean'
- end
- if op.type == '|'
- or op.type == '~'
- or op.type == '&'
- or op.type == '<<'
- or op.type == '>>' then
- return 'integer'
- end
- if op.type == '..' then
- return 'string'
- end
- if op.type == '^'
- or op.type == '/' then
- return 'number'
- end
+ local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
+ local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
+ local v
+ if v1 and v2 then
+ v = v1 <= v2
+ end
+ return {
+ type = 'boolean',
+ value = v,
+ source = source,
+ }
+ elseif op.type == '>=' then
+ local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
+ local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
+ local v
+ if v1 and v2 then
+ v = v1 >= v2
+ end
+ return {
+ type = 'boolean',
+ value = v,
+ source = source,
+ }
+ elseif op.type == '<' then
+ local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
+ local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
+ local v
+ if v1 and v2 then
+ v = v1 < v2
+ end
+ return {
+ type = 'boolean',
+ value = v,
+ source = source,
+ }
+ elseif op.type == '>' then
+ local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
+ local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
+ local v
+ if v1 and v2 then
+ v = v1 > v2
+ end
+ return {
+ type = 'boolean',
+ value = v,
+ source = source,
+ }
+ elseif op.type == '|' then
+ local v1 = vm.getLiteral(source[1], 'integer')
+ local v2 = vm.getLiteral(source[2], 'integer')
+ local v
+ if v1 and v2 then
+ v = v1 | v2
+ end
+ return {
+ type = 'integer',
+ value = v,
+ source = source,
+ }
+ elseif op.type == '~' then
+ local v1 = vm.getLiteral(source[1], 'integer')
+ local v2 = vm.getLiteral(source[2], 'integer')
+ local v
+ if v1 and v2 then
+ v = v1 ~ v2
+ end
+ return {
+ type = 'integer',
+ value = v,
+ source = source,
+ }
+ elseif op.type == '&' then
+ local v1 = vm.getLiteral(source[1], 'integer')
+ local v2 = vm.getLiteral(source[2], 'integer')
+ local v
+ if v1 and v2 then
+ v = v1 & v2
+ end
+ return {
+ type = 'integer',
+ value = v,
+ source = source,
+ }
+ elseif op.type == '<<' then
+ local v1 = vm.getLiteral(source[1], 'integer')
+ local v2 = vm.getLiteral(source[2], 'integer')
+ local v
+ if v1 and v2 then
+ v = v1 << v2
+ end
+ return {
+ type = 'integer',
+ value = v,
+ source = source,
+ }
+ elseif op.type == '>>' then
+ local v1 = vm.getLiteral(source[1], 'integer')
+ local v2 = vm.getLiteral(source[2], 'integer')
+ local v
+ if v1 and v2 then
+ v = v1 >> v2
+ end
+ return {
+ type = 'integer',
+ value = v,
+ source = source,
+ }
+ elseif op.type == '..' then
+ local v1 = vm.getLiteral(source[1], 'string')
+ local v2 = vm.getLiteral(source[2], 'string')
+ local v
+ if v1 and v2 then
+ v = v1 .. v2
+ end
+ return {
+ type = 'string',
+ value = v,
+ source = source,
+ }
+ elseif op.type == '^' then
+ local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
+ local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
+ local v
+ if v1 and v2 then
+ v = v1 ^ v2
+ end
+ return {
+ type = 'number',
+ value = v,
+ source = source,
+ }
+ elseif op.type == '/' then
+ local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
+ local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
+ local v
+ if v1 and v2 then
+ v = v1 > v2
+ end
+ return {
+ type = 'number',
+ value = v,
+ source = source,
+ }
-- 其他数学运算根据2侧的值决定,当2侧的值均为整数时返回整数
- if op.type == '+'
- or op.type == '-'
- or op.type == '*'
- or op.type == '%'
- or op.type == '//' then
- if hasType('integer', vm.getValue(source[1]))
- and hasType('integer', vm.getValue(source[2])) then
- return 'integer'
- else
- return 'number'
+ elseif op.type == '+' then
+ local v1 = vm.getLiteral(source[1], 'integer')
+ local v2 = vm.getLiteral(source[2], 'integer')
+ if v1 and v2 then
+ return {
+ type = 'integer',
+ value = v1 + v2,
+ source = source,
+ }
+ end
+ v1 = v1 or vm.getLiteral(source[1], 'number')
+ v2 = v2 or vm.getLiteral(source[1], 'number')
+ return {
+ type = 'number',
+ value = (v1 and v2) and (v1 + v2) or nil,
+ source = source,
+ }
+ elseif op.type == '-' then
+ local v1 = vm.getLiteral(source[1], 'integer')
+ local v2 = vm.getLiteral(source[2], 'integer')
+ if v1 and v2 then
+ return {
+ type = 'integer',
+ value = v1 - v2,
+ source = source,
+ }
+ end
+ v1 = v1 or vm.getLiteral(source[1], 'number')
+ v2 = v2 or vm.getLiteral(source[1], 'number')
+ return {
+ type = 'number',
+ value = (v1 and v2) and (v1 - v2) or nil,
+ source = source,
+ }
+ elseif op.type == '*' then
+ local v1 = vm.getLiteral(source[1], 'integer')
+ local v2 = vm.getLiteral(source[2], 'integer')
+ if v1 and v2 then
+ return {
+ type = 'integer',
+ value = v1 * v2,
+ source = source,
+ }
+ end
+ v1 = v1 or vm.getLiteral(source[1], 'number')
+ v2 = v2 or vm.getLiteral(source[1], 'number')
+ return {
+ type = 'number',
+ value = (v1 and v2) and (v1 * v2) or nil,
+ source = source,
+ }
+ elseif op.type == '%' then
+ local v1 = vm.getLiteral(source[1], 'integer')
+ local v2 = vm.getLiteral(source[2], 'integer')
+ if v1 and v2 then
+ return {
+ type = 'integer',
+ value = v1 % v2,
+ source = source,
+ }
end
+ v1 = v1 or vm.getLiteral(source[1], 'number')
+ v2 = v2 or vm.getLiteral(source[1], 'number')
+ return {
+ type = 'number',
+ value = (v1 and v2) and (v1 % v2) or nil,
+ source = source,
+ }
+ elseif op.type == '//' then
+ local v1 = vm.getLiteral(source[1], 'integer')
+ local v2 = vm.getLiteral(source[2], 'integer')
+ if v1 and v2 then
+ return {
+ type = 'integer',
+ value = v1 // v2,
+ source = source,
+ }
+ end
+ v1 = v1 or vm.getLiteral(source[1], 'number')
+ v2 = v2 or vm.getLiteral(source[1], 'number')
+ return {
+ type = 'number',
+ value = (v1 and v2) and (v1 // v2) or nil,
+ source = source,
+ }
end
end
@@ -394,14 +592,14 @@ function vm.isSameValue(a, b)
return true
end
-function vm.typeInference(source)
+function vm.getType(source)
local values = vm.getValue(source)
if not values then
return 'any'
end
local types = {}
- for _ = 1, #values do
- local tp = values.type
+ for i = 1, #values do
+ local tp = values[i].type
if not types[tp] then
types[tp] = true
types[#types+1] = tp
diff --git a/server-beta/test/type_inference/init.lua b/server-beta/test/type_inference/init.lua
index d7c1e4f2..7187c298 100644
--- a/server-beta/test/type_inference/init.lua
+++ b/server-beta/test/type_inference/init.lua
@@ -30,7 +30,7 @@ function TEST(wanted)
files.setText('', newScript)
local source = getSource(pos)
assert(source)
- local result = vm.getValue(source) or 'any'
+ local result = vm.getType(source) or 'any'
assert(wanted == result)
end
end