summaryrefslogtreecommitdiff
path: root/script
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2022-07-06 17:34:21 +0800
committer最萌小汐 <sumneko@hotmail.com>2022-07-06 17:34:21 +0800
commit91ab8e7b4c3c17da0a1bcdfb02a38c23cc786910 (patch)
treeb8b9637292bf7656e9b3acefc11e71d98ffd6c9c /script
parentf407cb07ed559daf7a5a943d8896e849791ae5b7 (diff)
downloadlua-language-server-91ab8e7b4c3c17da0a1bcdfb02a38c23cc786910.zip
cleanup
Diffstat (limited to 'script')
-rw-r--r--script/parser/luadoc.lua39
-rw-r--r--script/vm/compiler.lua247
-rw-r--r--script/vm/init.lua1
-rw-r--r--script/vm/operator.lua269
4 files changed, 311 insertions, 245 deletions
diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua
index 2e0125c5..a94f89cd 100644
--- a/script/parser/luadoc.lua
+++ b/script/parser/luadoc.lua
@@ -1353,6 +1353,45 @@ local docSwitch = util.switch()
return result
end)
+ : case 'operator'
+ : call(function ()
+ local result = {
+ type = 'doc.operator',
+ start = getFinish(),
+ finish = getFinish(),
+ }
+
+ local op = parseName('doc.operator.name', result)
+ if not op then
+ pushWarning {
+ type = 'LUADOC_MISS_OPERATOR_NAME',
+ start = getFinish(),
+ finish = getFinish(),
+ }
+ return nil
+ end
+ result.op = op
+ result.finish = op.finish
+
+ if checkToken('symbol', '(', 1) then
+ local exp = parseType(result)
+ if exp then
+ result.exp = exp
+ result.finish = exp.finish
+ end
+ nextSymbolOrError ')'
+ end
+
+ nextSymbolOrError ':'
+
+ local ret = parseType(result)
+ if ret then
+ result.ret = ret
+ result.finish = ret.finish
+ end
+
+ return result
+ end)
local function convertTokens()
local tp, text = nextToken()
diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua
index 12cf102b..beb6e4e5 100644
--- a/script/vm/compiler.lua
+++ b/script/vm/compiler.lua
@@ -1022,193 +1022,6 @@ local function compileLocal(source)
vm.getNode(source):setData('hasDefined', hasMarkDoc or hasMarkParam or hasMarkValue)
end
-local binarySwich = util.switch()
- : case 'and'
- : call(function (source)
- local node1 = vm.compileNode(source[1])
- local node2 = vm.compileNode(source[2])
- local r1 = vm.testCondition(source[1])
- if r1 == true then
- vm.setNode(source, node2)
- elseif r1 == false then
- vm.setNode(source, node1)
- else
- local node = node1:copy():setFalsy():merge(node2)
- vm.setNode(source, node)
- end
- end)
- : case 'or'
- : call(function (source)
- local node1 = vm.compileNode(source[1])
- local node2 = vm.compileNode(source[2])
- local r1 = vm.testCondition(source[1])
- if r1 == true then
- vm.setNode(source, node1)
- elseif r1 == false then
- vm.setNode(source, node2)
- else
- local node = node1:copy():setTruthy():merge(node2)
- vm.setNode(source, node)
- end
- end)
- : case '=='
- : case '~='
- : call(function (source)
- local result = vm.equal(source[1], source[2])
- if result == nil then
- vm.setNode(source, vm.declareGlobal('type', 'boolean'))
- else
- if source.op.type == '~=' then
- result = not result
- end
- vm.setNode(source, {
- type = 'boolean',
- start = source.start,
- finish = source.finish,
- parent = source,
- [1] = result,
- })
- end
- end)
- : case '<<'
- : case '>>'
- : case '&'
- : case '|'
- : case '~'
- : call(function (source)
- local a = vm.getInteger(source[1])
- local b = vm.getInteger(source[2])
- if a and b then
- local op = source.op.type
- local result = op.type == '<<' and a << b
- or op.type == '>>' and a >> b
- or op.type == '&' and a & b
- or op.type == '|' and a | b
- or op.type == '~' and a ~ b
- vm.setNode(source, {
- type = 'integer',
- start = source.start,
- finish = source.finish,
- parent = source,
- [1] = result,
- })
- else
- vm.setNode(source, vm.declareGlobal('type', 'integer'))
- end
- end)
- : case '+'
- : case '-'
- : case '*'
- : case '/'
- : case '%'
- : case '//'
- : case '^'
- : call(function (source)
- local a = vm.getNumber(source[1])
- local b = vm.getNumber(source[2])
- local op = source.op.type
- local zero = b == 0
- and ( op == '%'
- or op == '/'
- or op == '//'
- )
- if a and b and not zero then
- local result = op == '+' and a + b
- or op == '-' and a - b
- or op == '*' and a * b
- or op == '/' and a / b
- or op == '%' and a % b
- or op == '//' and a // b
- or op == '^' and a ^ b
- vm.setNode(source, {
- type = math.type(result) == 'integer' and 'integer' or 'number',
- start = source.start,
- finish = source.finish,
- parent = source,
- [1] = result,
- })
- else
- if op == '+'
- or op == '-'
- or op == '*'
- or op == '//'
- or op == '%' then
- local uri = guide.getUri(source)
- local infer1 = vm.getInfer(source[1])
- local infer2 = vm.getInfer(source[2])
- if infer1:hasType(uri, 'integer')
- or infer2:hasType(uri, 'integer') then
- if not infer1:hasType(uri, 'number')
- and not infer2:hasType(uri, 'number') then
- vm.setNode(source, vm.declareGlobal('type', 'integer'))
- return
- end
- end
- end
- vm.setNode(source, vm.declareGlobal('type', 'number'))
- end
- end)
- : case '..'
- : call(function (source)
- local a = vm.getString(source[1])
- or vm.getNumber(source[1])
- local b = vm.getString(source[2])
- or vm.getNumber(source[2])
- if a and b then
- if type(a) == 'number' or type(b) == 'number' then
- local uri = guide.getUri(source)
- local version = config.get(uri, 'Lua.runtime.version')
- if math.tointeger(a) and math.type(a) == 'float' then
- if version == 'Lua 5.3' or version == 'Lua 5.4' then
- a = ('%.1f'):format(a)
- else
- a = ('%.0f'):format(a)
- end
- end
- if math.tointeger(b) and math.type(b) == 'float' then
- if version == 'Lua 5.3' or version == 'Lua 5.4' then
- b = ('%.1f'):format(b)
- else
- b = ('%.0f'):format(b)
- end
- end
- end
- vm.setNode(source, {
- type = 'string',
- start = source.start,
- finish = source.finish,
- parent = source,
- [1] = a .. b,
- })
- else
- vm.setNode(source, vm.declareGlobal('type', 'string'))
- end
- end)
- : case '>'
- : case '<'
- : case '>='
- : case '<='
- : call(function (source)
- local a = vm.getNumber(source[1])
- local b = vm.getNumber(source[2])
- if a and b then
- local op = source.op.type
- local result = op.type == '>' and a > b
- or op.type == '<' and a < b
- or op.type == '>=' and a >= b
- or op.type == '<=' and a <= b
- vm.setNode(source, {
- type = 'boolean',
- start = source.start,
- finish = source.finish,
- parent = source,
- [1] =result,
- })
- else
- vm.setNode(source, vm.declareGlobal('type', 'boolean'))
- end
- end)
-
local compilerSwitch = util.switch()
: case 'nil'
: case 'boolean'
@@ -1818,63 +1631,7 @@ local compilerSwitch = util.switch()
if not source[1] then
return
end
- if source.op.type == 'not' then
- local result = vm.testCondition(source[1])
- if result == nil then
- vm.setNode(source, vm.declareGlobal('type', 'boolean'))
- return
- else
- vm.setNode(source, {
- type = 'boolean',
- start = source.start,
- finish = source.finish,
- parent = source,
- [1] = not result,
- })
- return
- end
- end
- if source.op.type == '#' then
- vm.setNode(source, vm.declareGlobal('type', 'integer'))
- return
- end
- if source.op.type == '-' then
- local v = vm.getNumber(source[1])
- if v == nil then
- local infer = vm.getInfer(source[1])
- if infer:hasType(guide.getUri(source), 'integer') then
- vm.setNode(source, vm.declareGlobal('type', 'integer'))
- else
- vm.setNode(source, vm.declareGlobal('type', 'number'))
- end
- return
- else
- vm.setNode(source, {
- type = 'number',
- start = source.start,
- finish = source.finish,
- parent = source,
- [1] = -v,
- })
- return
- end
- end
- if source.op.type == '~' then
- local v = vm.getInteger(source[1])
- if v == nil then
- vm.setNode(source, vm.declareGlobal('type', 'integer'))
- return
- else
- vm.setNode(source, {
- type = 'integer',
- start = source.start,
- finish = source.finish,
- parent = source,
- [1] = ~v,
- })
- return
- end
- end
+ vm.unarySwich(source.op.type, source)
end)
: case 'binary'
: call(function (source)
@@ -1884,7 +1641,7 @@ local compilerSwitch = util.switch()
if not source[1] or not source[2] then
return
end
- binarySwich(source.op.type, source)
+ vm.binarySwitch(source.op.type, source)
end)
---@param source parser.object
diff --git a/script/vm/init.lua b/script/vm/init.lua
index 24e75f95..87c046f0 100644
--- a/script/vm/init.lua
+++ b/script/vm/init.lua
@@ -18,4 +18,5 @@ require 'vm.sign'
require 'vm.local-id'
require 'vm.global'
require 'vm.function'
+require 'vm.operator'
return vm
diff --git a/script/vm/operator.lua b/script/vm/operator.lua
new file mode 100644
index 00000000..0ed3ff1d
--- /dev/null
+++ b/script/vm/operator.lua
@@ -0,0 +1,269 @@
+---@class vm
+local vm = require 'vm.vm'
+local util = require 'utility'
+local guide = require 'parser.guide'
+local config = require 'config'
+
+vm.UNARY_OP = {
+ 'unm',
+ 'bnot',
+ 'len',
+}
+vm.BINARY_OP = {
+ 'add',
+ 'sub',
+ 'mul',
+ 'div',
+ 'mod',
+ 'pow',
+ 'idiv',
+ 'band',
+ 'bor',
+ 'bxor',
+ 'shl',
+ 'shr',
+ 'concat',
+}
+
+vm.unarySwich = util.switch()
+ : case 'not'
+ : call(function (source)
+ local result = vm.testCondition(source[1])
+ if result == nil then
+ vm.setNode(source, vm.declareGlobal('type', 'boolean'))
+ else
+ vm.setNode(source, {
+ type = 'boolean',
+ start = source.start,
+ finish = source.finish,
+ parent = source,
+ [1] = not result,
+ })
+ end
+ end)
+ : case '#'
+ : call(function (source)
+ vm.setNode(source, vm.declareGlobal('type', 'integer'))
+ end)
+ : case '-'
+ : call(function (source)
+ local v = vm.getNumber(source[1])
+ if v == nil then
+ local infer = vm.getInfer(source[1])
+ if infer:hasType(guide.getUri(source), 'integer') then
+ vm.setNode(source, vm.declareGlobal('type', 'integer'))
+ else
+ vm.setNode(source, vm.declareGlobal('type', 'number'))
+ end
+ else
+ vm.setNode(source, {
+ type = 'number',
+ start = source.start,
+ finish = source.finish,
+ parent = source,
+ [1] = -v,
+ })
+ end
+ end)
+ : case '~'
+ : call(function (source)
+ local v = vm.getInteger(source[1])
+ if v == nil then
+ vm.setNode(source, vm.declareGlobal('type', 'integer'))
+ else
+ vm.setNode(source, {
+ type = 'integer',
+ start = source.start,
+ finish = source.finish,
+ parent = source,
+ [1] = ~v,
+ })
+ end
+ end)
+
+vm.binarySwitch = util.switch()
+ : case 'and'
+ : call(function (source)
+ local node1 = vm.compileNode(source[1])
+ local node2 = vm.compileNode(source[2])
+ local r1 = vm.testCondition(source[1])
+ if r1 == true then
+ vm.setNode(source, node2)
+ elseif r1 == false then
+ vm.setNode(source, node1)
+ else
+ local node = node1:copy():setFalsy():merge(node2)
+ vm.setNode(source, node)
+ end
+ end)
+ : case 'or'
+ : call(function (source)
+ local node1 = vm.compileNode(source[1])
+ local node2 = vm.compileNode(source[2])
+ local r1 = vm.testCondition(source[1])
+ if r1 == true then
+ vm.setNode(source, node1)
+ elseif r1 == false then
+ vm.setNode(source, node2)
+ else
+ local node = node1:copy():setTruthy():merge(node2)
+ vm.setNode(source, node)
+ end
+ end)
+ : case '=='
+ : case '~='
+ : call(function (source)
+ local result = vm.equal(source[1], source[2])
+ if result == nil then
+ vm.setNode(source, vm.declareGlobal('type', 'boolean'))
+ else
+ if source.op.type == '~=' then
+ result = not result
+ end
+ vm.setNode(source, {
+ type = 'boolean',
+ start = source.start,
+ finish = source.finish,
+ parent = source,
+ [1] = result,
+ })
+ end
+ end)
+ : case '<<'
+ : case '>>'
+ : case '&'
+ : case '|'
+ : case '~'
+ : call(function (source)
+ local a = vm.getInteger(source[1])
+ local b = vm.getInteger(source[2])
+ if a and b then
+ local op = source.op.type
+ local result = op.type == '<<' and a << b
+ or op.type == '>>' and a >> b
+ or op.type == '&' and a & b
+ or op.type == '|' and a | b
+ or op.type == '~' and a ~ b
+ vm.setNode(source, {
+ type = 'integer',
+ start = source.start,
+ finish = source.finish,
+ parent = source,
+ [1] = result,
+ })
+ else
+ vm.setNode(source, vm.declareGlobal('type', 'integer'))
+ end
+ end)
+ : case '+'
+ : case '-'
+ : case '*'
+ : case '/'
+ : case '%'
+ : case '//'
+ : case '^'
+ : call(function (source)
+ local a = vm.getNumber(source[1])
+ local b = vm.getNumber(source[2])
+ local op = source.op.type
+ local zero = b == 0
+ and ( op == '%'
+ or op == '/'
+ or op == '//'
+ )
+ if a and b and not zero then
+ local result = op == '+' and a + b
+ or op == '-' and a - b
+ or op == '*' and a * b
+ or op == '/' and a / b
+ or op == '%' and a % b
+ or op == '//' and a // b
+ or op == '^' and a ^ b
+ vm.setNode(source, {
+ type = math.type(result) == 'integer' and 'integer' or 'number',
+ start = source.start,
+ finish = source.finish,
+ parent = source,
+ [1] = result,
+ })
+ else
+ if op == '+'
+ or op == '-'
+ or op == '*'
+ or op == '//'
+ or op == '%' then
+ local uri = guide.getUri(source)
+ local infer1 = vm.getInfer(source[1])
+ local infer2 = vm.getInfer(source[2])
+ if infer1:hasType(uri, 'integer')
+ or infer2:hasType(uri, 'integer') then
+ if not infer1:hasType(uri, 'number')
+ and not infer2:hasType(uri, 'number') then
+ vm.setNode(source, vm.declareGlobal('type', 'integer'))
+ return
+ end
+ end
+ end
+ vm.setNode(source, vm.declareGlobal('type', 'number'))
+ end
+ end)
+ : case '..'
+ : call(function (source)
+ local a = vm.getString(source[1])
+ or vm.getNumber(source[1])
+ local b = vm.getString(source[2])
+ or vm.getNumber(source[2])
+ if a and b then
+ if type(a) == 'number' or type(b) == 'number' then
+ local uri = guide.getUri(source)
+ local version = config.get(uri, 'Lua.runtime.version')
+ if math.tointeger(a) and math.type(a) == 'float' then
+ if version == 'Lua 5.3' or version == 'Lua 5.4' then
+ a = ('%.1f'):format(a)
+ else
+ a = ('%.0f'):format(a)
+ end
+ end
+ if math.tointeger(b) and math.type(b) == 'float' then
+ if version == 'Lua 5.3' or version == 'Lua 5.4' then
+ b = ('%.1f'):format(b)
+ else
+ b = ('%.0f'):format(b)
+ end
+ end
+ end
+ vm.setNode(source, {
+ type = 'string',
+ start = source.start,
+ finish = source.finish,
+ parent = source,
+ [1] = a .. b,
+ })
+ else
+ vm.setNode(source, vm.declareGlobal('type', 'string'))
+ end
+ end)
+ : case '>'
+ : case '<'
+ : case '>='
+ : case '<='
+ : call(function (source)
+ local a = vm.getNumber(source[1])
+ local b = vm.getNumber(source[2])
+ if a and b then
+ local op = source.op.type
+ local result = op.type == '>' and a > b
+ or op.type == '<' and a < b
+ or op.type == '>=' and a >= b
+ or op.type == '<=' and a <= b
+ vm.setNode(source, {
+ type = 'boolean',
+ start = source.start,
+ finish = source.finish,
+ parent = source,
+ [1] =result,
+ })
+ else
+ vm.setNode(source, vm.declareGlobal('type', 'boolean'))
+ end
+ end)