diff options
Diffstat (limited to 'script/vm/compiler.lua')
-rw-r--r-- | script/vm/compiler.lua | 505 |
1 files changed, 171 insertions, 334 deletions
diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua index acb39432..5bdb1d3c 100644 --- a/script/vm/compiler.lua +++ b/script/vm/compiler.lua @@ -928,6 +928,176 @@ 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.test(source[1]) + if r1 == true then + vm.setNode(source, node2) + elseif r1 == false then + vm.setNode(source, node1) + else + vm.setNode(source, node2) + end + end) + : case 'or' + : call(function (source) + local node1 = vm.compileNode(source[1]) + local node2 = vm.compileNode(source[2]) + local r1 = vm.test(source[1]) + if r1 == true then + vm.setNode(source, node1) + elseif r1 == false then + vm.setNode(source, node2) + else + vm.getNode(source):merge(node1) + vm.getNode(source):setTruthy() + vm.getNode(source):merge(node2) + 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 + 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' @@ -1482,340 +1652,7 @@ local compilerSwitch = util.switch() if not source[1] or not source[2] then return end - if source.op.type == 'and' then - local node1 = vm.compileNode(source[1]) - local node2 = vm.compileNode(source[2]) - local r1 = vm.test(source[1]) - if r1 == true then - vm.setNode(source, node2) - elseif r1 == false then - vm.setNode(source, node1) - else - vm.setNode(source, node2) - end - end - if source.op.type == 'or' then - local node1 = vm.compileNode(source[1]) - local node2 = vm.compileNode(source[2]) - local r1 = vm.test(source[1]) - if r1 == true then - vm.setNode(source, node1) - elseif r1 == false then - vm.setNode(source, node2) - else - vm.getNode(source):merge(node1) - vm.getNode(source):setTruthy() - vm.getNode(source):merge(node2) - end - end - if source.op.type == '==' then - local result = vm.equal(source[1], source[2]) - 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] = result, - }) - return - end - end - if source.op.type == '~=' then - local result = vm.equal(source[1], source[2]) - 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 - local a = vm.getInteger(source[1]) - local b = vm.getInteger(source[2]) - if a and b then - vm.setNode(source, { - type = 'integer', - start = source.start, - finish = source.finish, - parent = source, - [1] = a << b, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'integer')) - return - end - end - if source.op.type == '>>' then - local a = vm.getInteger(source[1]) - local b = vm.getInteger(source[2]) - if a and b then - vm.setNode(source, { - type = 'integer', - start = source.start, - finish = source.finish, - parent = source, - [1] = a >> b, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'integer')) - return - end - end - if source.op.type == '&' then - local a = vm.getInteger(source[1]) - local b = vm.getInteger(source[2]) - if a and b then - vm.setNode(source, { - type = 'integer', - start = source.start, - finish = source.finish, - parent = source, - [1] = a & b, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'integer')) - return - end - end - if source.op.type == '|' then - local a = vm.getInteger(source[1]) - local b = vm.getInteger(source[2]) - if a and b then - vm.setNode(source, { - type = 'integer', - start = source.start, - finish = source.finish, - parent = source, - [1] = a | b, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'integer')) - return - end - end - if source.op.type == '~' then - local a = vm.getInteger(source[1]) - local b = vm.getInteger(source[2]) - if a and b then - vm.setNode(source, { - type = 'integer', - start = source.start, - finish = source.finish, - parent = source, - [1] = a ~ b, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'integer')) - return - end - end - if source.op.type == '+' then - local a = vm.getNumber(source[1]) - local b = vm.getNumber(source[2]) - if a and b then - local result = a + b - vm.setNode(source, { - type = math.type(result) == 'integer' and 'integer' or 'number', - start = source.start, - finish = source.finish, - parent = source, - [1] = result, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'number')) - return - end - end - if source.op.type == '-' then - local a = vm.getNumber(source[1]) - local b = vm.getNumber(source[2]) - if a and b then - local result = a - b - vm.setNode(source, { - type = math.type(result) == 'integer' and 'integer' or 'number', - start = source.start, - finish = source.finish, - parent = source, - [1] = result, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'number')) - return - end - end - if source.op.type == '*' then - local a = vm.getNumber(source[1]) - local b = vm.getNumber(source[2]) - if a and b then - local result = a * b - vm.setNode(source, { - type = math.type(result) == 'integer' and 'integer' or 'number', - start = source.start, - finish = source.finish, - parent = source, - [1] = result, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'number')) - return - end - end - if source.op.type == '/' then - local a = vm.getNumber(source[1]) - local b = vm.getNumber(source[2]) - if a and b then - vm.setNode(source, { - type = 'number', - start = source.start, - finish = source.finish, - parent = source, - [1] = a / b, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'number')) - return - end - end - if source.op.type == '%' then - local a = vm.getNumber(source[1]) - local b = vm.getNumber(source[2]) - if a and b and b ~= 0 then - local result = a % b - vm.setNode(source, { - type = math.type(result) == 'integer' and 'integer' or 'number', - start = source.start, - finish = source.finish, - parent = source, - [1] = result, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'number')) - return - end - end - if source.op.type == '^' then - local a = vm.getNumber(source[1]) - local b = vm.getNumber(source[2]) - if a and b then - vm.setNode(source, { - type = 'number', - start = source.start, - finish = source.finish, - parent = source, - [1] = a ^ b, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'number')) - return - end - end - if source.op.type == '//' then - local a = vm.getNumber(source[1]) - local b = vm.getNumber(source[2]) - if a and b and b ~= 0 then - local result = a // b - vm.setNode(source, { - type = math.type(result) == 'integer' and 'integer' or 'number', - start = source.start, - finish = source.finish, - parent = source, - [1] = result, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'number')) - return - end - end - if source.op.type == '..' then - 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, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'string')) - return - end - end - if source.op.type == '>' - or source.op.type == '<' - or source.op.type == '>=' - or source.op.type == '<=' then - local a = vm.getNumber(source[1]) - local b = vm.getNumber(source[2]) - if a and b then - local result - if source.op.type == '>' then - result = a > b - elseif source.op.type == '<' then - result = a < b - elseif source.op.type == '>=' then - result = a >= b - elseif source.op.type == '<=' then - result = a <= b - end - vm.setNode(source, { - type = 'boolean', - start = source.start, - finish = source.finish, - parent = source, - [1] = result, - }) - return - else - vm.setNode(source, vm.declareGlobal('type', 'boolean')) - return - end - end + binarySwich(source.op.type, source) end) ---@param source vm.object |