113 lines
2.4 KiB
Lua
113 lines
2.4 KiB
Lua
local util = require "core:bitwise/util"
|
|
|
|
local tokenizer = require "core:bitwise/tokenizer"
|
|
local parser = require "core:bitwise/parser"
|
|
|
|
local types = tokenizer.types
|
|
|
|
local operatorToFunctionName =
|
|
{
|
|
[types.lshift] = "bit.lshift",
|
|
[types.rshift] = "bit.rshift",
|
|
[types.bnot] = "bit.bnot",
|
|
[types.band] = "bit.band",
|
|
[types.bxor] = "bit.bxor",
|
|
[types.bor] = "bit.bor"
|
|
}
|
|
|
|
local function compile(str, args, asFunction)
|
|
if asFunction == nil then
|
|
asFunction = true
|
|
end
|
|
|
|
local tokens = parser(str)
|
|
|
|
local stack = { }
|
|
|
|
local ids = { }
|
|
|
|
for _, token in ipairs(tokens) do
|
|
if table.has(tokenizer.numTypes, token.type) or token.type == types.id then
|
|
if token.type == tokenizer.types.binNum then
|
|
util.stack.push(stack, tonumber(token.value, 2))
|
|
elseif token.type == tokenizer.types.hexNum then
|
|
util.stack.push(stack, "0x"..token.value)
|
|
else
|
|
util.stack.push(stack, token.value)
|
|
|
|
if token.type == types.id then
|
|
local add = true
|
|
|
|
for i = 1, #ids do
|
|
if ids[i].value == token.value then
|
|
add = false
|
|
break
|
|
end
|
|
end
|
|
|
|
if add then table.insert(ids, token) end
|
|
end
|
|
end
|
|
else
|
|
local fun = operatorToFunctionName[token.type]
|
|
|
|
local a = util.stack.pop(stack)
|
|
local b = token.type ~= types.bnot and util.stack.pop(stack)
|
|
|
|
if not b then
|
|
util.stack.push(stack, fun..'('..a..')')
|
|
else
|
|
util.stack.push(stack, fun..'('..b..','..a..')')
|
|
end
|
|
end
|
|
end
|
|
|
|
local strArgs = ""
|
|
|
|
if args then
|
|
for _, id in ipairs(ids) do
|
|
if not table.has(args, id.value) then
|
|
util.throw(id.column, "undefined identifier")
|
|
end
|
|
end
|
|
else
|
|
args = { }
|
|
|
|
table.sort(ids, function(a, b) return a.value:upper() < b.value:upper() end)
|
|
|
|
for _, id in ipairs(ids) do
|
|
table.insert(args, id.value)
|
|
end
|
|
end
|
|
|
|
for i = 1, #args do
|
|
local str = args[i]
|
|
|
|
for j = 1, #str do
|
|
local char = str:sub(j,j)
|
|
|
|
if
|
|
not string.find(tokenizer.idChars, char) or
|
|
(j == 1 and string.find(tokenizer.startingDigits, char))
|
|
then error("invalid argument name ("..i..")") end
|
|
end
|
|
|
|
strArgs = strArgs..str
|
|
|
|
if i ~= #args then
|
|
strArgs = strArgs..','
|
|
end
|
|
end
|
|
|
|
local code = stack[1]
|
|
|
|
code = "function("..strArgs..") return "..code.." end"
|
|
|
|
if asFunction then
|
|
return load("return "..code)()
|
|
else
|
|
return code
|
|
end
|
|
end
|
|
|
|
return compile |