initial commit

This commit is contained in:
2026-04-25 16:50:59 +02:00
commit 47c84ae3c8
11 changed files with 3484 additions and 0 deletions

689
src/methods/small.lake Normal file
View File

@@ -0,0 +1,689 @@
Small = {};
fn Small.isDigit(ch) {
var n = string.byte(ch);
if (!n) return false;
return n >= 48 && n <= 57;
}
fn Small.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 (ch == "\n") out ..= '\n';
elseif (ch == "\r") out ..= '\r';
elseif (ch == "\x07") out ..= '\a';
elseif (ch == "\x08") out ..= '\b';
elseif (ch == "\x0c") out ..= '\f';
elseif (ch == "\t") out ..= '\t';
elseif (code >= 32 && code <= 126) out ..= ch;
else {
var nextchar = raw:sub(i+1,i+1);
if (Small.isDigit(nextchar))
out ..= '\' .. DecEncode(code, 3);
else
out ..= '\' .. DecEncode(code, 1);
}
}
out ..= '"';
return out;
}
fn Small.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 Small.convertBinaryOperator(lakeop, spacer) {
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 == "&&" ) {
if (spacer) return " and ";
else return "and";
} elseif ( lakeop == "||" ) {
if (spacer) return " or ";
else return 'or';
}
}
fn Small.convertUnaryOperator(op) {
if (op == '#') return '#';
elseif (op == '-') return '-';
elseif (op == '!') return 'not';
}
fn Small.output(outp, ast) {
return Small.outputStatement(outp, ast);
}
fn Small.outputStatement(outp, node, noblock) {
if (node.kind == 'Program') {
outp:appendLine('do ', '');
for (var i = 1; i <= #node.content; i += 1;) {
var stmt = node.content[i];
Small.outputStatement(outp, stmt, #node.content == 1);
}
outp:appendLine('end;', '');
} elseif (node.kind == 'VariableDeclaration') {
outp:appendLine('local ', '');
var varnames = node.content[1];
for (var i = 1; i <= #varnames; i += 1;) {
var vname = varnames[i];
outp:appendLine(vname[1], '');
if (i != #varnames) {
outp:appendLine(',', '');
}
}
var values = node.content[2];
if (#values > 0) {
outp:appendLine('=', '');
for (var i = 1; i <= #values; i += 1;) {
var val = values[i];
Small.outputExpression(outp, val, false);
if (i != #values) {
outp:appendLine(',', '');
}
}
}
outp:appendLine(';', '');
} elseif (node.kind == 'Block') {
if (!noblock) outp:appendLine('do ', '');
for (var i = 1; i <= #node.content; i += 1;) {
var stmt = node.content[i];
Small.outputStatement(outp, stmt, i == #node.content);
}
if (!noblock) outp:appendLine('end;', '');
} elseif (node.kind == 'IfStatement') {
outp:appendLine("if ", '');
Small.outputExpression(outp, node.content[1][1][1]);
outp:appendLine("then ", '');
Small.outputStatement(outp, node.content[1][1][2], true);
for (var i = 2; i <= #node.content[1]; i += 1;) {
var item = node.content[1][i];
outp:appendLine("elseif ", '');
Small.outputExpression(outp,item[1]);
outp:appendLine("then ", '');
Small.outputStatement(outp,item[2], true);
}
if (node.content[2]) {
outp:appendLine("else ", '');
Small.outputStatement(outp, node.content[2], true);
}
outp:appendLine("end;", '');
} elseif (node.kind == 'FunctionDeclaration') {
outp:appendLine("function ", '');
Small.outputFunctionName(outp, node.content[1]);
outp:appendLine("(", '');
for (var i = 1; i <= #node.content[2]; i += 1;) {
var part = node.content[2][i];
outp:appendLine(part, '');
if (i != #node.content[2]) {
outp:appendLine(",", '');
}
}
outp:appendLine(")", '');
Small.outputStatement(outp, node.content[3], true);
outp:appendLine("end;", '');
} elseif (node.kind == 'LocalFunctionDeclaration') {
outp:appendLine("local function ", '');
outp:appendLine(node.content[1].content, '');
outp:appendLine("(", '');
for (var i = 1; i <= #node.content[2]; i += 1;) {
var part = node.content[2][i];
outp:appendLine(part, '');
if (i != #node.content[2]) {
outp:appendLine(",", '');
}
}
outp:appendLine(")", '');
Small.outputStatement(outp, node.content[3], true);
outp:appendLine("end;", '');
} elseif (node.kind == 'Return') {
if (!noblock) {
outp:appendLine("if''then ");
}
if (#node.content > 0) {
outp:appendLine("return ", '');
} else {
outp:appendLine('return', '');
}
for (var i = 1; i <= #node.content; i += 1;) {
var expr = node.content[i];
Small.outputExpression(outp, expr, false);
if (i != #node.content) {
outp:appendLine(",", '');
}
}
outp:appendLine(";", '');
if (!noblock) {
outp:appendLine("end;");
}
} 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];
Small.outputVariable(outp, vari);
if (i != #vars) {
outp:appendLine(",", '');
}
}
outp:appendLine("=", '');
for (var i = 1; i <= #vals; i += 1;) {
var val = vals[i];
Small.outputExpression(outp, val, false);
if (i != #vals) {
outp:appendLine(",", '');
}
}
outp:appendLine(";", '');
} elseif (node.kind == 'Call') {
outp:appendLine("(", '');
Small.outputExpression(outp, node.content[1], false);
outp:appendLine(")", '');
outp:appendLine("(", '');
var args = node.content[2];
for (var i = 1; i <= #args; i += 1;) {
var arg = args[i];
Small.outputExpression(outp, arg, false);
if (i != #args) {
outp:appendLine(",", '');
}
}
outp:appendLine(")", '');
outp:appendLine(";", '');
} elseif (node.kind == 'MethodCall') {
outp:appendLine("(", '');
Small.outputExpression(outp, node.content[1], false);
outp:appendLine("):", '');
outp:appendLine(node.content[2], '');
outp:appendLine("(", '');
var args = node.content[3];
for (var i = 1; i <= #args; i += 1;) {
var arg = args[i];
Small.outputExpression(outp, arg, false);
if (i != #args) {
outp:appendLine(",", '');
}
}
outp:appendLine(")", '');
outp:appendLine(";", '');
} elseif (node.kind == 'While') {
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') {
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') {
var lakeop = node.content[2];
var op = Small.convertBinaryOperator(lakeop, true);
var lhs = node.content[1];
var rhs = node.content[3];
if (lhs.kind == "Variable") {
var 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") {
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") {
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;', '');
}
} elseif (node.kind == 'Break') {
outp:appendLine('break;', '');
} elseif (node.kind == 'Foreach') {
outp:appendLine("for ", '');
var varlist,exprlist,block = node.content[1],node.content[2],node.content[3];
for (var i = 1; i <= #varlist; i += 1;) {
outp:appendLine(varlist[i], '');
if (i != #varlist) {
outp:appendLine(',', '');
}
}
outp:appendLine(" in ", '');
for (var i = 1; i <= #exprlist; i += 1;) {
Small.outputExpression(outp, exprlist[i], i == #exprlist);
if (i != #exprlist) {
outp:appendLine(",", '');
}
}
outp:appendLine('do ', '');
Small.outputStatement(outp, block, true);
outp:appendLine('end;', '');
}
}
fn Small.outputExpression(outp, node, needsp) {
if (needsp == null) needsp = true;
if (node.kind == 'StringLiteral') {
var lakestr = node.content;
var raw = Lower.decodeString(lakestr);
var enc = Small.encodeString(raw, outp.target == "lua51");
outp:appendLine(enc, '');
} elseif (node.kind == 'CompiledStringLiteral') {
var raw = node.content;
var enc = Small.encodeString(raw, outp.target == "lua51");
outp:appendLine(enc, '');
} elseif (node.kind == 'ParenthesizedExpression') {
outp:appendLine("(", '');
Small.outputExpression(outp, node.content, false);
outp:appendLine(")", '');
} elseif (node.kind == 'NumberLiteral') {
var lakenum = node.content;
var raw = Lower.decodeNumber(lakenum);
var enc = Small.encodeNumber(raw);
outp:appendLine(enc, '');
if (needsp) outp:appendLine(' ', '');
} elseif (node.kind == 'CompiledNumberLiteral') {
var raw = node.content;
var enc = Small.encodeNumber(raw);
outp:appendLine(enc, '');
if (needsp) outp:appendLine(' ', '');
} elseif (node.kind == 'TableLiteral') {
outp:appendLine('{', '');
var listpart = node.content[1];
var tablepart = node.content[2];
for (var i = 1; i <= #listpart; i += 1;) {
var item = listpart[i];
Small.outputExpression(outp, item, false);
if ((#tablepart > 0) || (i < #listpart)) {
outp:appendLine(',', '');
}
}
for (var i = 1; i <= #tablepart; i += 1;) {
var item = tablepart[i];
outp:appendLine('[', '');
Small.outputExpression(outp, item[1], false);
outp:appendLine(']', '');
outp:appendLine('=', '');
Small.outputExpression(outp, item[2], false);
if (i < #tablepart) {
outp:appendLine(',', '');
}
}
outp:appendLine('}', '');
} elseif (node.kind == 'LambdaFunctionLiteral') {
outp:appendLine('function(', '');
for (var i = 1; i <= #node.content[1]; i += 1;) {
var part = node.content[1][i];
outp:appendLine(part, '');
if (i != #node.content[1]) {
outp:appendLine(",", '');
}
}
outp:appendLine(")", '');
Small.outputStatement(outp, node.content[2], true);
outp:appendLine("end", '');
if (needsp) outp:appendLine(' ', '');
} elseif (node.kind == 'BinaryOperator') {
var op = node.content[1];
var lhs = node.content[2];
var rhs = node.content[3];
outp:appendLine("((", '');
Small.outputExpression(outp,lhs, false);
outp:appendLine(")", '');
var luaop = Small.convertBinaryOperator(op);
outp:appendLine(luaop, '');
outp:appendLine("(", '');
Small.outputExpression(outp,rhs,false);
outp:appendLine("))", '');
} elseif (node.kind == 'UnaryOperator') {
var op = node.content[1];
var val = node.content[2];
outp:appendLine("(", '');
var luaop = Small.convertUnaryOperator(op);
outp:appendLine(luaop, '');
outp:appendLine("(", '');
Small.outputExpression(outp,val,false);
outp:appendLine("))", '');
} elseif (node.kind == 'Field') {
var left = node.content[1];
var right = node.content[2];
outp:appendLine("(", '');
Small.outputExpression(outp, left, false);
outp:appendLine(").", '');
outp:appendLine(right, '');
if (needsp) outp:appendLine(' ', '');
} elseif (node.kind == 'Index') {
var left = node.content[1];
var 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') {
outp:appendLine(node.content, '');
if (needsp) outp:appendLine(' ', '');
} elseif (node.kind == 'BooleanLiteral') {
outp:appendLine(node.content, '');
if (needsp) outp:appendLine(' ', '');
} elseif (node.kind == 'NullLiteral') {
outp:appendLine("nil", '');
if (needsp) outp:appendLine(' ', '');
} elseif (node.kind == 'Call') {
outp:appendLine("(", '');
Small.outputExpression(outp, node.content[1], false);
outp:appendLine(")", '');
outp:appendLine("(", '');
var args = node.content[2];
for (var i = 1; i <= #args; i += 1;) {
var arg = args[i];
Small.outputExpression(outp, arg, false);
if (i != #args) {
outp:appendLine(",", '');
}
}
outp:appendLine(")", '');
} elseif (node.kind == 'MethodCall') {
outp:appendLine("(", '');
Small.outputExpression(outp, node.content[1], false);
outp:appendLine("):", '');
outp:appendLine(node.content[2], '');
outp:appendLine("(", '');
var args = node.content[3];
for (var i = 1; i <= #args; i += 1;) {
var arg = args[i];
Small.outputExpression(outp, arg, false);
if (i != #args) {
outp:appendLine(",", '');
}
}
outp:appendLine(")", '');
}
}
fn Small.outputFunctionName(outp, node) {
if (node.kind == "Field") {
var left = node.content[1];
var right = node.content[2];
Small.outputFunctionName(outp, left);
outp:appendLine(".", '');
outp:appendLine(right, '');
} elseif (node.kind == "Index") {
var left = node.content[1];
var right = node.content[2];
Small.outputFunctionName(outp, left);
outp:appendLine("[", '');
Small.outputExpression(outp, right, false);
outp:appendLine("]", '');
} elseif (node.kind == "Variable") {
outp:appendLine(node.content, '');
} elseif (node.kind == "Method") {
var left = node.content[1];
var right = node.content[2];
Small.outputFunctionName(outp, left);
outp:appendLine(":", '');
outp:appendLine(right, '');
}
}
fn Small.outputVariable(outp, node) {
if (node.kind == "Field") {
var left = node.content[1];
var right = node.content[2];
Small.outputExpression(outp, left, false);
outp:appendLine(".", '');
outp:appendLine(right, '');
} elseif (node.kind == "Index") {
var left = node.content[1];
var right = node.content[2];
Small.outputExpression(outp, left, false);
outp:appendLine("[", '');
Small.outputExpression(outp, right, false);
outp:appendLine("]", '');
} elseif (node.kind == "Variable") {
outp:appendLine(node.content, '');
}
}
RegisterOutMethod('small', Small);