diff options
-rw-r--r-- | server-beta/src/vm/getValue.lua | 262 | ||||
-rw-r--r-- | server-beta/test/type_inference/init.lua | 2 |
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 |