720 lines
15 KiB
Lua
720 lines
15 KiB
Lua
Small = {}
|
|
|
|
function Small.isDigit(ch)
|
|
local n = string.byte(ch)
|
|
if not n then return false end
|
|
return n >= 48 and n <= 57
|
|
end
|
|
|
|
function Small.encodeString(raw, islua51)
|
|
local out = '"'
|
|
|
|
for i = 1,#raw do
|
|
local ch = raw:sub(i,i)
|
|
|
|
local code = string.byte(ch)
|
|
if ch == '\\' then
|
|
out = out .. "\\\\"
|
|
elseif ch == '"' then
|
|
out = out .. '\\"'
|
|
elseif ch == "\n" then
|
|
out = out .. "\\n"
|
|
elseif ch == '\r' then
|
|
out = out .. "\\r"
|
|
elseif ch == "\a" then
|
|
out = out .. "\\a"
|
|
elseif ch == "\b" then
|
|
out = out .. "\\b"
|
|
elseif ch == '\f' then
|
|
out = out .. "\\f"
|
|
elseif ch == "\t" then
|
|
out = out .. "\\t"
|
|
elseif code >= 32 and code <= 126 then
|
|
out = out .. ch
|
|
else
|
|
local nextchar = raw:sub(i+1,i+1)
|
|
if Small.isDigit(nextchar) then
|
|
out = out .. "\\" .. DecEncode(code, 3)
|
|
else
|
|
out = out .. "\\" .. DecEncode(code, 1)
|
|
end
|
|
end
|
|
end
|
|
|
|
out = out .. '"'
|
|
|
|
return out
|
|
end
|
|
|
|
function Small.encodeNumber(n)
|
|
local num = ''
|
|
local isneg = false
|
|
|
|
if n < 0 then
|
|
n = n * -1
|
|
isneg = true;
|
|
end
|
|
|
|
local whole = math.floor(n)
|
|
|
|
if whole == 0 then
|
|
num = num .. '0'
|
|
end
|
|
|
|
while whole > 0 do
|
|
local digit = whole % 10
|
|
num = string.char(string.byte'0' + digit) .. num
|
|
|
|
whole = math.floor(whole / 10)
|
|
end
|
|
|
|
local dec = n % 1
|
|
|
|
if dec > 0 then
|
|
num = num .. "."
|
|
|
|
while dec > 0 do
|
|
-- aw nah
|
|
dec = dec * 10
|
|
|
|
local digit = math.floor(dec)
|
|
|
|
num = num .. string.char(string.byte'0' + digit)
|
|
|
|
dec = dec % 1
|
|
end
|
|
end
|
|
|
|
if isneg then
|
|
num = '-' .. num
|
|
end
|
|
|
|
return num
|
|
end
|
|
|
|
function Small.convertBinaryOperator(lakeop, spacer)
|
|
if lakeop == "+" then
|
|
return "+"
|
|
elseif lakeop == "-" then
|
|
return "-"
|
|
elseif lakeop == "*" then
|
|
return "*"
|
|
elseif lakeop == "/" then
|
|
return "/"
|
|
elseif lakeop == "%" then
|
|
return "%"
|
|
elseif lakeop == "^" then
|
|
return "^"
|
|
elseif lakeop == ".." then
|
|
return ".."
|
|
elseif lakeop == "<" then
|
|
return "<"
|
|
elseif lakeop == ">" then
|
|
return ">"
|
|
elseif lakeop == "<=" then
|
|
return "<="
|
|
elseif lakeop == ">=" then
|
|
return ">="
|
|
elseif lakeop == "!=" then
|
|
return "~="
|
|
elseif lakeop == "==" then
|
|
return "=="
|
|
elseif lakeop == "&&" then
|
|
return spacer and ' and ' or "and"
|
|
elseif lakeop == "||" then
|
|
return spacer and ' or ' or "or"
|
|
end
|
|
end
|
|
|
|
function Small.convertUnaryOperator(op)
|
|
if op == "#" then
|
|
return "#"
|
|
elseif op == "-" then
|
|
return "-"
|
|
elseif op == "!" then
|
|
return "not"
|
|
end
|
|
end
|
|
|
|
function Small.output(outp, ast)
|
|
Small.outputStatement(outp, ast)
|
|
end
|
|
|
|
---@param outp Output
|
|
---@param node Node
|
|
function Small.outputStatement(outp, node, noblock)
|
|
if node.kind == "Program" then
|
|
outp:appendLine("do ", '')
|
|
|
|
for i = 1,#node.content do
|
|
local stmt = node.content[i]
|
|
|
|
Small.outputStatement(outp, stmt)
|
|
end
|
|
|
|
outp:appendLine("end;", '')
|
|
elseif node.kind == "VariableDeclaration" then
|
|
outp:appendLine("local ", '')
|
|
local varnames = node.content[1]
|
|
|
|
for i = 1,#varnames do
|
|
local vname = varnames[i]
|
|
|
|
outp:appendLine(vname[1], '')
|
|
|
|
if i ~= #varnames then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
local values = node.content[2]
|
|
if #values > 0 then
|
|
outp:appendLine("=", '')
|
|
|
|
for i = 1,#values do
|
|
local val = values[i]
|
|
|
|
Small.outputExpression(outp, val, false)
|
|
|
|
if i ~= #values then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
end
|
|
|
|
outp:appendLine(";", '')
|
|
elseif node.kind == "Block" then
|
|
if not noblock then
|
|
outp:appendLine("do ", '')
|
|
end
|
|
|
|
for i = 1,#node.content do
|
|
local stmt = node.content[i]
|
|
|
|
Small.outputStatement(outp, stmt, #node.content == 1)
|
|
end
|
|
|
|
if not noblock then
|
|
outp:appendLine("end;", '')
|
|
end
|
|
elseif node.kind == "IfStatement" then
|
|
outp:appendLine("if ", '')
|
|
|
|
Small.outputExpression(outp, node.content[1][1][1])
|
|
|
|
outp:appendLine("then ", '')
|
|
|
|
Small.outputStatement(outp, node.content[1][1][2], true)
|
|
|
|
for i = 2, #node.content[1] do
|
|
local item = node.content[1][i]
|
|
-- print(item, item[1], item[2])
|
|
outp:appendLine("elseif ", '')
|
|
|
|
Small.outputExpression(outp,item[1]);
|
|
|
|
outp:appendLine("then ", '')
|
|
|
|
Small.outputStatement(outp,item[2], true);
|
|
end
|
|
|
|
if node.content[2] then
|
|
outp:appendLine("else ", '')
|
|
|
|
Small.outputStatement(outp, node.content[2], true)
|
|
end
|
|
|
|
outp:appendLine("end;", '')
|
|
elseif node.kind == "FunctionDeclaration" then
|
|
outp:appendLine("function ", '')
|
|
|
|
Small.outputFunctionName(outp, node.content[1]);
|
|
|
|
outp:appendLine("(", '')
|
|
|
|
for i = 1,#node.content[2] do
|
|
local part = node.content[2][i]
|
|
|
|
outp:appendLine(part, '')
|
|
|
|
if i ~= #node.content[2] then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine(")", '')
|
|
|
|
Small.outputStatement(outp, node.content[3], true)
|
|
|
|
outp:appendLine("end;", '')
|
|
elseif node.kind == "LocalFunctionDeclaration" then
|
|
outp:appendLine("local function ", '')
|
|
|
|
outp:appendLine(node.content[1].content, '');
|
|
|
|
outp:appendLine("(", '')
|
|
|
|
for i = 1,#node.content[2] do
|
|
local part = node.content[2][i]
|
|
|
|
outp:appendLine(part, '')
|
|
|
|
if i ~= #node.content[2] then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine(")", '')
|
|
|
|
Small.outputStatement(outp, node.content[3], true)
|
|
|
|
outp:appendLine("end;", '')
|
|
elseif node.kind == "Return" then
|
|
if #node.content > 0 then
|
|
outp:appendLine("return ", '')
|
|
else
|
|
outp:appendLine('return', '')
|
|
end
|
|
|
|
for i = 1,#node.content do
|
|
local expr = node.content[i]
|
|
|
|
Small.outputExpression(outp, expr, false)
|
|
|
|
if i ~= #node.content then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine(";", '')
|
|
elseif node.kind == "Assignment" then
|
|
local vars = node.content[1]
|
|
local vals = node.content[2]
|
|
|
|
for i = 1,#vars do
|
|
local var = vars[i]
|
|
|
|
Small.outputVariable(outp, var)
|
|
|
|
if i ~= #vars then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine("=", '')
|
|
|
|
for i = 1,#vals do
|
|
local val = vals[i]
|
|
|
|
Small.outputExpression(outp, val, false)
|
|
|
|
if i ~= #vals then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine(";", '')
|
|
elseif node.kind == "Call" then
|
|
outp:appendLine("(", '')
|
|
Small.outputExpression(outp, node.content[1], false)
|
|
outp:appendLine(")", '')
|
|
|
|
outp:appendLine("(", '')
|
|
|
|
local args = node.content[2]
|
|
for i = 1,#args do
|
|
local arg = args[i]
|
|
|
|
Small.outputExpression(outp, arg, false)
|
|
|
|
if i ~= #args then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine(")", '')
|
|
outp:appendLine(";", '')
|
|
elseif node.kind == "MethodCall" then
|
|
outp:appendLine("(", '')
|
|
Small.outputExpression(outp, node.content[1], false)
|
|
outp:appendLine("):", '')
|
|
outp:appendLine(node.content[2], '')
|
|
outp:appendLine("(", '')
|
|
|
|
local args = node.content[3]
|
|
for i = 1,#args do
|
|
local arg = args[i]
|
|
|
|
Small.outputExpression(outp, arg, false)
|
|
|
|
if i ~= #args then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine(")", '')
|
|
outp:appendLine(";", '')
|
|
elseif node.kind == "While" then
|
|
outp:appendLine("while ", '')
|
|
|
|
Small.outputExpression(outp, node.content[1])
|
|
|
|
outp:appendLine("do ", '')
|
|
|
|
Small.outputStatement(outp, node.content[2], true)
|
|
|
|
outp:appendLine("end;", '')
|
|
elseif node.kind == "For" then
|
|
outp:appendLine("do ", '')
|
|
Small.outputStatement(outp,node.content[1]);
|
|
|
|
outp:appendLine("while ", '')
|
|
Small.outputExpression(outp,node.content[2]);
|
|
outp:appendLine("do ", '')
|
|
|
|
outp:appendLine("do ", '')
|
|
Small.outputStatement(outp,node.content[4], true);
|
|
outp:appendLine("end;", '')
|
|
|
|
Small.outputStatement(outp,node.content[3], true);
|
|
|
|
outp:appendLine("end;", '')
|
|
|
|
outp:appendLine("end;", '')
|
|
elseif node.kind == "OperatorAssignment" then
|
|
local lake_op = node.content[2]
|
|
local op = Small.convertBinaryOperator(lake_op, true)
|
|
|
|
local lhs = node.content[1]
|
|
local rhs = node.content[3]
|
|
|
|
if lhs.kind == "Variable" then
|
|
local varname = lhs.content
|
|
|
|
outp:appendLine(varname, '')
|
|
outp:appendLine('=', '')
|
|
outp:appendLine(varname, '')
|
|
outp:appendLine(op, '')
|
|
outp:appendLine('(', '')
|
|
Small.outputExpression(outp, rhs, false)
|
|
outp:appendLine(');', '')
|
|
elseif lhs.kind == "Field" then
|
|
outp:appendLine('do ', '')
|
|
|
|
outp:appendLine('local _lake_oat=', '')
|
|
Small.outputExpression(outp, lhs.content[1], false)
|
|
outp:appendLine(';', '');
|
|
|
|
outp:appendLine('_lake_oat.', '')
|
|
outp:appendLine(lhs.content[2], '')
|
|
|
|
outp:appendLine('=', '')
|
|
|
|
outp:appendLine('_lake_oat.', '')
|
|
outp:appendLine(lhs.content[2], '')
|
|
outp:appendLine(op, '')
|
|
outp:appendLine('(', '')
|
|
Small.outputExpression(outp, rhs, false)
|
|
outp:appendLine(');', '')
|
|
|
|
outp:appendLine('end;', '')
|
|
elseif lhs.kind == "Index" then
|
|
outp:appendLine('do ', '')
|
|
|
|
outp:appendLine('local _lake_oat=', '')
|
|
Small.outputExpression(outp, lhs.content[1], false)
|
|
outp:appendLine(';', '');
|
|
|
|
outp:appendLine('_lake_oat[', '')
|
|
Small.outputExpression(outp, lhs.content[2], false)
|
|
outp:appendLine(']', '')
|
|
|
|
outp:appendLine('=', '')
|
|
|
|
outp:appendLine('_lake_oat[', '')
|
|
Small.outputExpression(outp, lhs.content[2], false)
|
|
outp:appendLine(']', '')
|
|
outp:appendLine(op, '')
|
|
outp:appendLine('(', '')
|
|
Small.outputExpression(outp, rhs, false)
|
|
outp:appendLine(');', '')
|
|
|
|
outp:appendLine('end;', '')
|
|
end
|
|
elseif node.kind == "Break" then
|
|
outp:appendLine('break;', '')
|
|
elseif node.kind == "Foreach" then
|
|
outp:appendLine("for ", '')
|
|
|
|
local varlist,exprlist,block = node.content[1],node.content[2],node.content[3]
|
|
|
|
for i = 1,#varlist do
|
|
outp:appendLine(varlist[i], '')
|
|
if i ~= #varlist then
|
|
outp:appendLine(',', '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine(" in ", '')
|
|
|
|
for i = 1,#exprlist do
|
|
Small.outputExpression(outp, exprlist[i], i == #exprlist)
|
|
|
|
if i ~= #exprlist then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine('do ', '')
|
|
|
|
Small.outputStatement(outp, block, true);
|
|
|
|
outp:appendLine('end;', '')
|
|
end
|
|
end
|
|
|
|
---@param outp Output
|
|
---@param node Node
|
|
function Small.outputExpression(outp, node, needsp)
|
|
if needsp == nil then needsp = true end
|
|
if node.kind == "StringLiteral" then
|
|
local lakestr = node.content
|
|
|
|
local raw = Lower.decodeString(lakestr)
|
|
|
|
local enc = Small.encodeString(raw, outp.target == "lua51")
|
|
|
|
outp:appendLine(enc, '')
|
|
elseif node.kind == "ParenthesizedExpression" then
|
|
outp:appendLine("(", '')
|
|
Small.outputExpression(outp, node.content, false)
|
|
outp:appendLine(")", '')
|
|
elseif node.kind == "NumberLiteral" then
|
|
local lakenum = node.content
|
|
|
|
local raw = Lower.decodeNumber(lakenum)
|
|
|
|
-- print(raw, type(raw))
|
|
|
|
local enc = Small.encodeNumber(raw)
|
|
|
|
outp:appendLine(enc, '')
|
|
if needsp then
|
|
outp:appendLine(' ', '')
|
|
end
|
|
elseif node.kind == "TableLiteral" then
|
|
outp:appendLine('{', '')
|
|
local list_part = node.content[1]
|
|
local table_part = node.content[2]
|
|
|
|
for i = 1,#list_part do
|
|
local item = list_part[i]
|
|
|
|
Small.outputExpression(outp, item, false);
|
|
|
|
if (#table_part > 0) or (i < #list_part) then
|
|
outp:appendLine(',', '')
|
|
end
|
|
end
|
|
|
|
for i = 1,#table_part do
|
|
local item = table_part[i]
|
|
|
|
outp:appendLine('[', '')
|
|
Small.outputExpression(outp, item[1], false)
|
|
outp:appendLine(']', '')
|
|
outp:appendLine('=', '')
|
|
Small.outputExpression(outp, item[2], false)
|
|
if (i < #table_part) then
|
|
outp:appendLine(',', '')
|
|
end
|
|
end
|
|
outp:appendLine('}', '')
|
|
elseif node.kind == "LambdaFunctionLiteral" then
|
|
outp:appendLine('function(', '')
|
|
|
|
for i = 1,#node.content[1] do
|
|
local part = node.content[1][i]
|
|
|
|
outp:appendLine(part, '')
|
|
|
|
if i ~= #node.content[1] then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine(")", '')
|
|
|
|
Small.outputStatement(outp, node.content[2], true)
|
|
|
|
outp:appendLine("end", '')
|
|
if needsp then
|
|
outp:appendLine(' ', '')
|
|
end
|
|
elseif node.kind == "BinaryOperator" then
|
|
local op = node.content[1]
|
|
local lhs = node.content[2]
|
|
local rhs = node.content[3]
|
|
|
|
outp:appendLine("((", '')
|
|
|
|
Small.outputExpression(outp,lhs, false)
|
|
|
|
outp:appendLine(")", '')
|
|
|
|
local luaop = Small.convertBinaryOperator(op)
|
|
|
|
outp:appendLine(luaop, '')
|
|
|
|
outp:appendLine("(", '')
|
|
|
|
Small.outputExpression(outp,rhs,false)
|
|
|
|
outp:appendLine("))", '')
|
|
elseif node.kind == "UnaryOperator" then
|
|
local op = node.content[1]
|
|
local val = node.content[2]
|
|
|
|
outp:appendLine("(", '')
|
|
|
|
local luaop = Small.convertUnaryOperator(op)
|
|
outp:appendLine(luaop, '')
|
|
|
|
|
|
outp:appendLine("(", '')
|
|
|
|
Small.outputExpression(outp,val,false)
|
|
|
|
outp:appendLine("))", '')
|
|
elseif node.kind == "Field" then
|
|
local left = node.content[1]
|
|
local right = node.content[2]
|
|
|
|
outp:appendLine("(", '')
|
|
Small.outputExpression(outp, left, false)
|
|
outp:appendLine(").", '')
|
|
outp:appendLine(right, '')
|
|
if needsp then
|
|
outp:appendLine(' ', '')
|
|
end
|
|
elseif node.kind == "Index" then
|
|
local left = node.content[1]
|
|
local right = node.content[2]
|
|
|
|
outp:appendLine("(", '')
|
|
Small.outputExpression(outp, left, false)
|
|
outp:appendLine(")", '')
|
|
outp:appendLine("[", '')
|
|
Small.outputExpression(outp, right, false)
|
|
outp:appendLine("]", '')
|
|
elseif node.kind == "Variable" then
|
|
outp:appendLine(node.content, '')
|
|
if needsp then
|
|
outp:appendLine(' ', '')
|
|
end
|
|
elseif node.kind == "BooleanLiteral" then
|
|
outp:appendLine(node.content, '')
|
|
if needsp then
|
|
outp:appendLine(' ', '')
|
|
end
|
|
elseif node.kind == "NullLiteral" then
|
|
outp:appendLine("nil", '')
|
|
if needsp then
|
|
outp:appendLine(' ', '')
|
|
end
|
|
elseif node.kind == "Call" then
|
|
outp:appendLine("(", '')
|
|
Small.outputExpression(outp, node.content[1], false)
|
|
outp:appendLine(")", '')
|
|
|
|
outp:appendLine("(", '')
|
|
|
|
local args = node.content[2]
|
|
for i = 1,#args do
|
|
local arg = args[i]
|
|
|
|
Small.outputExpression(outp, arg, false)
|
|
|
|
if i ~= #args then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine(")", '')
|
|
elseif node.kind == "MethodCall" then
|
|
outp:appendLine("(", '')
|
|
Small.outputExpression(outp, node.content[1], false)
|
|
outp:appendLine("):", '')
|
|
outp:appendLine(node.content[2], '')
|
|
outp:appendLine("(", '')
|
|
|
|
local args = node.content[3]
|
|
for i = 1,#args do
|
|
local arg = args[i]
|
|
|
|
Small.outputExpression(outp, arg, false)
|
|
|
|
if i ~= #args then
|
|
outp:appendLine(",", '')
|
|
end
|
|
end
|
|
|
|
outp:appendLine(")", '')
|
|
end
|
|
end
|
|
|
|
---@param outp Output
|
|
---@param node Node
|
|
function Small.outputFunctionName(outp, node)
|
|
if node.kind == "Field" then
|
|
local left = node.content[1]
|
|
local right = node.content[2]
|
|
|
|
Small.outputFunctionName(outp, left)
|
|
outp:appendLine(".", '')
|
|
outp:appendLine(right, '')
|
|
elseif node.kind == "Index" then
|
|
local left = node.content[1]
|
|
local right = node.content[2]
|
|
|
|
Small.outputFunctionName(outp, left)
|
|
outp:appendLine("[", '')
|
|
Small.outputExpression(outp, right, false)
|
|
outp:appendLine("]", '')
|
|
elseif node.kind == "Variable" then
|
|
outp:appendLine(node.content, '')
|
|
elseif node.kind == "Method" then
|
|
local left = node.content[1]
|
|
local right = node.content[2]
|
|
|
|
Small.outputFunctionName(outp, left)
|
|
outp:appendLine(":", '')
|
|
outp:appendLine(right, '')
|
|
end
|
|
end
|
|
|
|
---@param outp Output
|
|
---@param node Node
|
|
function Small.outputVariable(outp, node)
|
|
if node.kind == "Field" then
|
|
local left = node.content[1]
|
|
local right = node.content[2]
|
|
|
|
Small.outputExpression(outp, left, false)
|
|
outp:appendLine(".", '')
|
|
outp:appendLine(right, '')
|
|
elseif node.kind == "Index" then
|
|
local left = node.content[1]
|
|
local right = node.content[2]
|
|
|
|
Small.outputExpression(outp, left, false)
|
|
outp:appendLine("[", '')
|
|
Small.outputExpression(outp, right, false)
|
|
outp:appendLine("]", '')
|
|
elseif node.kind == "Variable" then
|
|
outp:appendLine(node.content, '')
|
|
end
|
|
end
|
|
|
|
RegisterOutMethod("small", Small)
|