668 lines
17 KiB
Plaintext
668 lines
17 KiB
Plaintext
Debug = {};
|
|
|
|
fn Debug.encodeString(raw, islua51) {
|
|
var out = '"';
|
|
|
|
for (var i = 1; i <= #raw; i += 1;) {
|
|
var ch = raw:sub(i,i);
|
|
|
|
var code = string.byte(ch);
|
|
if (ch == '\') {
|
|
out ..= '\\';
|
|
} elseif (ch == '"') {
|
|
out ..= '\"';
|
|
} elseif (code >= 32 && code <= 126) {
|
|
out ..= ch;
|
|
} else {
|
|
if (islua51)
|
|
out ..= '\' .. DecEncode(code, 3);
|
|
else
|
|
out ..= '\x' .. HexEncode(code, 2);
|
|
}
|
|
}
|
|
|
|
out ..= '"';
|
|
return out;
|
|
}
|
|
|
|
fn Debug.encodeNumber(n) {
|
|
var num = '';
|
|
var isneg = false;
|
|
|
|
if (n < 0) {
|
|
n *= -1;
|
|
isneg = true;
|
|
}
|
|
|
|
var whole = math.floor(n);
|
|
|
|
if (whole == 0) {
|
|
num ..= '0';
|
|
}
|
|
|
|
while (whole > 0) {
|
|
var digit = whole % 10;
|
|
num = string.char(string.byte('0') + digit) .. num;
|
|
whole = math.floor(whole / 10);
|
|
}
|
|
|
|
var dec = n % 1;
|
|
|
|
if (dec > 0) {
|
|
num ..= '.';
|
|
|
|
while (dec > 0) {
|
|
dec *= 10;
|
|
|
|
var digit = math.floor(dec);
|
|
num ..= string.char(string.byte('0') + digit);
|
|
|
|
dec %= 1;
|
|
}
|
|
}
|
|
|
|
if (isneg) num = '-' .. num;
|
|
|
|
return num;
|
|
}
|
|
|
|
fn Debug.convertBinaryOperator(lakeop) {
|
|
if (lakeop == '+') {
|
|
return '+';
|
|
} elseif (lakeop == "-" ) {
|
|
return "-";
|
|
} elseif ( lakeop == "*" ) {
|
|
return "*";
|
|
} elseif ( lakeop == "/" ) {
|
|
return "/";
|
|
} elseif ( lakeop == "%" ) {
|
|
return "%";
|
|
} elseif ( lakeop == "^" ) {
|
|
return "^";
|
|
} elseif ( lakeop == ".." ) {
|
|
return "..";
|
|
} elseif ( lakeop == "<" ) {
|
|
return "<";
|
|
} elseif ( lakeop == ">" ) {
|
|
return ">";
|
|
} elseif ( lakeop == "<=" ) {
|
|
return "<=";
|
|
} elseif ( lakeop == ">=" ) {
|
|
return ">=";
|
|
} elseif ( lakeop == "!=" ) {
|
|
return "~=";
|
|
} elseif ( lakeop == "==" ) {
|
|
return "==";
|
|
} elseif ( lakeop == "&&" ) {
|
|
return "and";
|
|
} elseif ( lakeop == "||" ) {
|
|
return "or";
|
|
}
|
|
}
|
|
|
|
fn Debug.convertUnaryOperator(op) {
|
|
if (op == '#') return '#';
|
|
elseif (op == '-') return '-';
|
|
elseif (op == '!') return 'not';
|
|
}
|
|
|
|
fn Debug.output(outp, ast) {
|
|
Debug.outputStatement(outp, ast);
|
|
}
|
|
|
|
fn Debug.outputStatement(outp, node) {
|
|
if (node.kind == 'Program') {
|
|
outp:addLine('do', node.location:format());
|
|
|
|
for (var i = 1; i <= #node.content; i += 1;) {
|
|
var stmt = node.content[i];
|
|
|
|
Debug.outputStatement(outp, stmt);
|
|
}
|
|
|
|
outp:addLine('end;', node.location:format());
|
|
} elseif (node.kind == 'VariableDeclaration') {
|
|
outp:addLine('local', node.location:format());
|
|
var varnames = node.content[1];
|
|
|
|
for (var i = 1; i <= #varnames; i += 1;) {
|
|
var vname = varnames[i];
|
|
|
|
outp:addLine(vname[1], vname[2]:format());
|
|
|
|
if (i != #varnames) {
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
}
|
|
|
|
var values = node.content[2];
|
|
if (#values > 0) {
|
|
outp:addLine('=', node.location:format());
|
|
|
|
for (var i = 1; i <= #values; i += 1;) {
|
|
var val = values[i];
|
|
|
|
Debug.outputExpression(outp, val);
|
|
|
|
if (i != #values) {
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
}
|
|
}
|
|
|
|
outp:addLine(';', node.location:format());
|
|
} elseif (node.kind == "Block") {
|
|
outp:addLine('do', node.location:format());
|
|
|
|
for (var i = 1; i <= #node.content; i += 1;) {
|
|
var stmt = node.content[i];
|
|
|
|
Debug.outputStatement(outp, stmt);
|
|
}
|
|
|
|
outp:addLine('end;', node.location:format());
|
|
} elseif (node.kind == 'IfStatement') {
|
|
outp:addLine('if', node.location:format());
|
|
|
|
Debug.outputExpression(outp, node.content[1][1][1]);
|
|
|
|
outp:addLine('then', node.location:format());
|
|
|
|
Debug.outputStatement(outp, node.content[1][1][2]);
|
|
|
|
for (var i = 2; i <= #node.content[1]; i += 1;) {
|
|
var item = node.content[1][i];
|
|
|
|
outp:addLine('elseif', node.location:format());
|
|
|
|
Debug.outputExpression(outp, item[1]);
|
|
|
|
outp:addLine('then', node.location:format());
|
|
|
|
Debug.outputStatement(outp, item[2]);
|
|
}
|
|
|
|
if (node.content[2]) {
|
|
outp:addLine('else', node.location:format());
|
|
|
|
Debug.outputStatement(outp, node.content[2]);
|
|
}
|
|
|
|
outp:addLine('end;', node.location:format());
|
|
} elseif (node.kind == "FunctionDeclaration") {
|
|
outp:addLine('function', node.location:format());
|
|
|
|
Debug.outputFunctionName(outp, node.content[1]);
|
|
|
|
outp:addLine('(', node.location:format());
|
|
|
|
for (var i = 1; i <= #node.content[2]; i += 1;) {
|
|
var part = node.content[2][i];
|
|
|
|
outp:addLine(part, node.location:format());
|
|
|
|
if (i != #node.content[2]) {
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine(')', node.location:format());
|
|
|
|
Debug.outputStatement(outp, node.content[3]);
|
|
|
|
outp:addLine('end;', node.location:format());
|
|
} elseif (node.kind == 'LocalFunctionDeclaration') {
|
|
outp:addLine('local function', node.location:format());
|
|
|
|
outp:addLine(node.content[1].content, node.content[1].location:format());
|
|
|
|
outp:addLine('(', node.location:format());
|
|
|
|
for (var i = 1; i <= #node.content[2]; i += 1;) {
|
|
var part = node.content[2][i];
|
|
|
|
outp:addLine(part, node.location:format());
|
|
|
|
if (i != #node.content[2]) {
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine(')', node.location:format());
|
|
|
|
Debug.outputStatement(outp, node.content[3]);
|
|
|
|
outp:addLine('end;', node.location:format());
|
|
} elseif (node.kind == 'Return') {
|
|
outp:addLine('return', node.location:format()); // if true because it has to be at the end of a block in lua, but not here.
|
|
|
|
for (var i = 1; i <= #node.content; i += 1;) {
|
|
var expr = node.content[i];
|
|
|
|
Debug.outputExpression(outp, expr);
|
|
|
|
if (i != #node.content) {
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine(';', node.location:format());
|
|
} elseif (node.kind == 'Assignment') {
|
|
var vars = node.content[1];
|
|
var vals = node.content[2];
|
|
|
|
for (var i = 1; i <= #vars; i += 1;) {
|
|
var vari = vars[i];
|
|
|
|
Debug.outputVariable(outp, vari);
|
|
|
|
if (i != #vars) {
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine('=', node.location:format());
|
|
|
|
for (var i = 1; i <= #vals; i += 1;) {
|
|
var val = vals[i];
|
|
|
|
Debug.outputExpression(outp, val);
|
|
|
|
if (i != #vals) {
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine(';', node.location:format());
|
|
} elseif (node.kind == 'Call') {
|
|
outp:addLine('(', node.location:format());
|
|
Debug.outputExpression(outp, node.content[1]);
|
|
outp:addLine(')(', node.location:format());
|
|
|
|
var args = node.content[2];
|
|
for (var i = 1; i <= #args; i += 1;) {
|
|
var arg = args[i];
|
|
|
|
Debug.outputExpression(outp, arg);
|
|
|
|
if (i != #args) {
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine(');', node.location:format());
|
|
} elseif (node.kind == 'MethodCall') {
|
|
outp:addLine('(', node.location:format());
|
|
Debug.outputExpression(outp, node.content[1]);
|
|
outp:addLine('):', node.location:format());
|
|
outp:addLine(node.content[2] .. '(', node.location:format());
|
|
|
|
var args = node.content[3];
|
|
for (var i = 1; i <= #args; i += 1;) {
|
|
var arg = args[i];
|
|
|
|
Debug.outputExpression(outp, arg);
|
|
|
|
if (i != #args) {
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine(');', node.location:format());
|
|
} elseif (node.kind == 'While') {
|
|
outp:addLine('while', node.location:format());
|
|
|
|
Debug.outputExpression(outp, node.content[1]);
|
|
|
|
outp:addLine('do', node.location:format());
|
|
|
|
Debug.outputStatement(outp, node.content[2]);
|
|
|
|
outp:addLine('end;', node.location:format());
|
|
} elseif (node.kind == 'For') {
|
|
outp:addLine('do', node.location:format());
|
|
Debug.outputStatement(outp, node.content[1]);
|
|
|
|
outp:addLine('while', node.location:format());
|
|
Debug.outputExpression(outp, node.content[2]);
|
|
outp:addLine('do', node.location:format());
|
|
|
|
outp:addLine('do', node.location:format());
|
|
Debug.outputStatement(outp, node.content[4]);
|
|
outp:addLine('end;', node.location:format());
|
|
|
|
Debug.outputStatement(outp, node.content[3]);
|
|
|
|
outp:addLine('end;', node.location:format());
|
|
outp:addLine('end;', node.location:format());
|
|
} elseif (node.kind == 'OperatorAssignment') {
|
|
var lakeop = node.content[2];
|
|
var op = Debug.convertBinaryOperator(lakeop);
|
|
|
|
var lhs = node.content[1];
|
|
var rhs = node.content[3];
|
|
|
|
if (lhs.kind == 'Variable') {
|
|
var varname = lhs.content;
|
|
|
|
outp:addLine(varname, node.location:format());
|
|
outp:addLine('=', node.location:format());
|
|
|
|
outp:addLine('(', node.location:format());
|
|
outp:addLine(varname, node.location:format());
|
|
outp:addLine(op, node.location:format());
|
|
outp:addLine('(', node.location:format());
|
|
Debug.outputExpression(outp, rhs);
|
|
outp:addLine('));', node.location:format());
|
|
} elseif (lhs.kind == 'Field') {
|
|
outp:addLine('do', node.location:format());
|
|
|
|
outp:addLine('local _lake_operator_assignment_tmp =', node.location:format());
|
|
Debug.outputExpression(outp, lhs.content[1]);
|
|
outp:addLine(';', node.location:format());
|
|
|
|
outp:addLine('(_lake_operator_assignment_tmp).', node.location:format());
|
|
outp:addLine(lhs.content[2], node.location:format());
|
|
|
|
outp:addLine('=', node.location:format());
|
|
|
|
outp:addLine('(', node.location:format());
|
|
outp:addLine('(_lake_operator_assignment_tmp).', node.location:format());
|
|
outp:addLine(lhs.content[2], node.location:format());
|
|
outp:addLine(op, node.location:format());
|
|
outp:addLine('(', node.location:format());
|
|
Debug.outputExpression(outp, rhs);
|
|
outp:addLine('));', node.location:format());
|
|
|
|
outp:addLine('end;', node.location:format());
|
|
} elseif (lhs.kind == 'Index') {
|
|
outp:addLine('do', node.location:format());
|
|
|
|
outp:addLine('local _lake_operator_assignment_tmp =', node.location:format());
|
|
Debug.outputExpression(outp, lhs.content[1]);
|
|
outp:addLine(';', node.location:format());
|
|
|
|
outp:addLine('(_lake_operator_assignment_tmp)[', node.location:format());
|
|
Debug.outputExpression(outp, lhs.content[2]);
|
|
outp:addLine(']', node.location:format());
|
|
|
|
outp:addLine('=', node.location:format());
|
|
|
|
outp:addLine('(', node.location:format());
|
|
outp:addLine('(_lake_operator_assignment_tmp)[', node.location:format());
|
|
Debug.outputExpression(outp, lhs.content[2]);
|
|
outp:addLine(']', node.location:format());
|
|
outp:addLine(op, node.location:format());
|
|
outp:addLine('(', node.location:format());
|
|
Debug.outputExpression(outp, rhs);
|
|
outp:addLine('));', node.location:format());
|
|
|
|
outp:addLine('end;', node.location:format());
|
|
}
|
|
} elseif (node.kind == 'Break') {
|
|
outp:addLine('break;', node.location:format());
|
|
} elseif (node.kind == 'Foreach') {
|
|
outp:addLine("for", node.location:format());
|
|
|
|
var varlist,exprlist,block = node.content[1],node.content[2],node.content[3];
|
|
|
|
for (var i = 1; i <= #varlist; i += 1;) {
|
|
outp:addLine(varlist[i], node.location:format());
|
|
if (i != #varlist) {
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine("in", node.location:format());
|
|
|
|
for (var i = 1; i <= #exprlist; i += 1;) {
|
|
Debug.outputExpression(outp, exprlist[i]);
|
|
|
|
if (i != #exprlist) {
|
|
outp:addLine(",", node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine('do', node.location:format());
|
|
|
|
Debug.outputStatement(outp, block);
|
|
|
|
outp:addLine('end;', node.location:format());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn Debug.outputExpression(outp, node) {
|
|
if (node.kind == 'StringLiteral') {
|
|
var lakestr = node.content;
|
|
var raw = Lower.decodeString(lakestr);
|
|
var enc = Debug.encodeString(raw, outp.target == 'lua51');
|
|
|
|
outp:addLine(enc, node.location:format());
|
|
} elseif (node.kind == 'CompiledStringLiteral') {
|
|
var raw = node.content;
|
|
var enc = Debug.encodeString(raw, outp.target == 'lua51');
|
|
|
|
outp:addLine(enc, node.location:format());
|
|
} elseif (node.kind == 'ParenthesizedExpression') {
|
|
outp:addLine("(", node.location:format());
|
|
Debug.outputExpression(outp, node.content);
|
|
outp:addLine(")", node.location:format());
|
|
} elseif (node.kind == 'NumberLiteral') {
|
|
var lakenum = node.content;
|
|
|
|
var raw = Lower.decodeNumber(lakenum);
|
|
|
|
var enc = Debug.encodeNumber(raw);
|
|
|
|
outp:addLine("(", node.location:format());
|
|
outp:addLine(enc, node.location:format());
|
|
outp:addLine(")", node.location:format());
|
|
} elseif (node.kind == 'CompiledNumberLiteral') { // usually generated by optimizer doing math
|
|
var raw = node.content;
|
|
|
|
var enc = Debug.encodeNumber(raw);
|
|
|
|
outp:addLine("(", node.location:format());
|
|
outp:addLine(enc, node.location:format());
|
|
outp:addLine(")", node.location:format());
|
|
} elseif (node.kind == 'TableLiteral') {
|
|
outp:addLine('{', node.location:format());
|
|
var listpart = node.content[1];
|
|
var tablepart = node.content[2];
|
|
|
|
for (var i = 1; i <= #listpart; i += 1;) {
|
|
var item = listpart[i];
|
|
|
|
Debug.outputExpression(outp, item);
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
|
|
for (var i = 1; i <= #tablepart; i += 1;) {
|
|
var item = tablepart[i];
|
|
|
|
outp:addLine('[', node.location:format());
|
|
Debug.outputExpression(outp, item[1]);
|
|
outp:addLine(']', node.location:format());
|
|
outp:addLine('=', node.location:format());
|
|
Debug.outputExpression(outp, item[2]);
|
|
outp:addLine(',', node.location:format());
|
|
}
|
|
outp:addLine('}', node.location:format());
|
|
} elseif (node.kind == 'LambdaFunctionLiteral') {
|
|
outp:addLine('function(', node.location:format());
|
|
|
|
for (var i = 1; i <= #node.content[1]; i += 1;) {
|
|
var part = node.content[1][i];
|
|
|
|
outp:addLine(part, node.location:format());
|
|
|
|
if (i != #node.content[1]) {
|
|
outp:addLine(",", node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine(")", node.location:format());
|
|
|
|
Debug.outputStatement(outp, node.content[2]);
|
|
|
|
outp:addLine("end", node.location:format());
|
|
} elseif (node.kind == 'BinaryOperator') {
|
|
var op = node.content[1];
|
|
var lhs = node.content[2];
|
|
var rhs = node.content[3];
|
|
|
|
outp:addLine("((", node.location:format());
|
|
|
|
Debug.outputExpression(outp,lhs);
|
|
|
|
outp:addLine(")", node.location:format());
|
|
|
|
var luaop = Debug.convertBinaryOperator(op);
|
|
|
|
outp:addLine(luaop, node.location:format());
|
|
|
|
outp:addLine("(", node.location:format());
|
|
|
|
Debug.outputExpression(outp,rhs);
|
|
|
|
outp:addLine("))", node.location:format());
|
|
} elseif (node.kind == 'UnaryOperator') {
|
|
var op = node.content[1];
|
|
var val = node.content[2];
|
|
|
|
outp:addLine("(", node.location:format());
|
|
|
|
var luaop = Debug.convertUnaryOperator(op);
|
|
outp:addLine(luaop, node.location:format());
|
|
|
|
|
|
outp:addLine("(", node.location:format());
|
|
|
|
Debug.outputExpression(outp,val);
|
|
|
|
outp:addLine("))", node.location:format());
|
|
} elseif (node.kind == 'Field') {
|
|
var left = node.content[1];
|
|
var right = node.content[2];
|
|
|
|
outp:addLine("((", node.location:format());
|
|
Debug.outputExpression(outp, left);
|
|
outp:addLine(").", node.location:format());
|
|
outp:addLine(right, node.location:format());
|
|
outp:addLine(")", node.location:format());
|
|
} elseif (node.kind == 'Index') {
|
|
var left = node.content[1];
|
|
var right = node.content[2];
|
|
|
|
outp:addLine("((", node.location:format());
|
|
Debug.outputExpression(outp, left);
|
|
outp:addLine(")", node.location:format());
|
|
outp:addLine("[", node.location:format());
|
|
Debug.outputExpression(outp, right);
|
|
outp:addLine("]", node.location:format());
|
|
outp:addLine(")", node.location:format());
|
|
} elseif (node.kind == 'Variable') {
|
|
outp:addLine("(", node.location:format());
|
|
outp:addLine(node.content, node.location:format());
|
|
outp:addLine(")", node.location:format());
|
|
} elseif (node.kind == 'BooleanLiteral') {
|
|
outp:addLine("(", node.location:format());
|
|
outp:addLine(node.content, node.location:format());
|
|
outp:addLine(")", node.location:format());
|
|
} elseif (node.kind == 'NullLiteral') {
|
|
outp:addLine("(nil)", node.location:format());
|
|
} elseif (node.kind == 'Call') {
|
|
outp:addLine("(", node.location:format());
|
|
Debug.outputExpression(outp, node.content[1]);
|
|
outp:addLine(")(", node.location:format());
|
|
|
|
var args = node.content[2];
|
|
for (var i = 1; i <= #args; i += 1;) {
|
|
var arg = args[i];
|
|
|
|
Debug.outputExpression(outp, arg);
|
|
|
|
if (i != #args) {
|
|
outp:addLine(",", node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine(")", node.location:format());
|
|
} elseif (node.kind == 'MethodCall') {
|
|
outp:addLine("(", node.location:format());
|
|
Debug.outputExpression(outp, node.content[1]);
|
|
outp:addLine("):", node.location:format());
|
|
outp:addLine(node.content[2] .. "(", node.location:format());
|
|
|
|
var args = node.content[3];
|
|
for (var i = 1; i <= #args; i += 1;) {
|
|
var arg = args[i];
|
|
|
|
Debug.outputExpression(outp, arg);
|
|
|
|
if (i != #args) {
|
|
outp:addLine(",", node.location:format());
|
|
}
|
|
}
|
|
|
|
outp:addLine(")", node.location:format());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn Debug.outputFunctionName(outp, node) {
|
|
if (node.kind == 'Field') {
|
|
var left = node.content[1];
|
|
var right = node.content[2];
|
|
|
|
Debug.outputFunctionName(outp, left);
|
|
outp:addLine(".", node.location:format());
|
|
outp:addLine(right, node.location:format());
|
|
} elseif (node.kind == 'Index') {
|
|
var left = node.content[1];
|
|
var right = node.content[2];
|
|
|
|
Debug.outputFunctionName(outp, left);
|
|
outp:addLine("[", node.location:format());
|
|
Debug.outputExpression(outp, right);
|
|
outp:addLine("]", node.location:format());
|
|
} elseif (node.kind == 'Variable') {
|
|
outp:addLine(node.content, node.location:format());
|
|
} elseif (node.kind == 'Method') {
|
|
var left = node.content[1];
|
|
var right = node.content[2];
|
|
|
|
Debug.outputFunctionName(outp, left);
|
|
outp:addLine(":", node.location:format());
|
|
outp:addLine(right, node.location:format());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn Debug.outputVariable(outp, node) {
|
|
if (node.kind == 'Field') {
|
|
var left = node.content[1];
|
|
var right = node.content[2];
|
|
|
|
Debug.outputExpression(outp, left);
|
|
outp:addLine(".", node.location:format());
|
|
outp:addLine(right, node.location:format());
|
|
} elseif (node.kind == 'Index') {
|
|
var left = node.content[1];
|
|
var right = node.content[2];
|
|
|
|
Debug.outputExpression(outp, left);
|
|
outp:addLine("[", node.location:format());
|
|
Debug.outputExpression(outp, right);
|
|
outp:addLine("]", node.location:format());
|
|
} elseif (node.kind == 'Variable') {
|
|
outp:addLine(node.content, node.location:format());
|
|
}
|
|
}
|
|
|
|
RegisterOutMethod("debug", Debug);
|