sclass ConvertLASToJava { replace Tk with GazelleV_LeftArrowScript. delegate Evaluable to Tk. O get(LASClassDef.FieldDef field) { ret field.type() + " " + field.name() + ";"; } O get(Tk.FunctionDef f) { ret "O " + f.name + "(" + joinWithComma(map(f.args, arg -> "O " + arg)) + ") {\n" + indentx(get(f.body, true)) + "}\n"; } O getInstruction(Evaluable o) { O inner = get(o); S space = null; var src = o.tokenRangeWithSrc(); if (src != null) space = src.endPtr().mapIdx(idx -> idx & ~1)!; bool needSemicolon = !o instanceof Tk.ClassDef; ret inner + (needSemicolon ? ";" : "") + or2(space, "\n"); } O get(Tk.Script script, bool returnLastResult) { var steps = asList(script.steps); if (returnLastResult) { if (empty(steps)) ret "return null;"; var last = last(steps); if (!last instanceof Tk.ReturnFromScript && !last instanceof Tk.ClassDef) setLast(steps, new Tk.ReturnFromScript(script, last)); } ret concatMapStrings(i -> str(getInstruction(i)), steps); } O get(Evaluable o, bool returnLastResult) { if (o cast Tk.Script) ret get(o, returnLastResult); ret get(o); } O get(Evaluable o) { if (o == null) null; // These are the properly implemented cases if (o cast Tk.GetVar) ret o.var; if (o cast Tk.Script) ret get(o, false); if (o cast Tk.ClassDef) { LASClassDef c = o.lasClass.classDef; ret "class " + c.userGivenName + " " + curly("\n" + indentx( joinNemptiesWithEmptyLines( lines_rtrim(map get(c.fields)), lines_rtrim(map get(c.methods))) )) + "\n}"; } if (o cast Tk.Assignment) ret o.var + " = " + get(o.expression); if (o cast Tk.CallMethod) { O target = o.target; S targetStr = null; if (target cast Class) if (eqOneOf(shortClassName(target), "main", "utils")) targetStr = ""; else targetStr = str(get(o.target)); ret (empty(targetStr) ? "" : targetStr + ".") + FunctionCall(o.methodName, map get(o.args)); } if (o cast Tk.SetField) ret get(o.target) + "." + o.name + " = " + get(o.expr); if (o cast Tk.CallMethodOrGetField) ret get(o.target) + "." + o.name + "()"; if (o cast Tk.NewObject) ret "new " + FunctionCall(shortClassName(o.c), map get(o.args)); if (o cast Tk.IfThen) ret "if (" + get(o.condition) + ") " + curlyIfScript(o.body) + (o.elseBranch == null ? "" : " else " + curlyIfScript(o.elseBranch)); if (o cast Tk.Const) { var c = o; try object c?.srcText(); pcall { ret toJava(o.value); } } if (o cast Tk.ForEach) ret "fOr (" + o.var + " : " + get(o.collection) + ") {\n" + indentx(get(o.body, true)) + "\n}"; if (o cast Tk.LambdaDef) ret roundBracketed(shortClassName(o.intrface)) + " " + joinNemptiesWithSpace(lambdaArgsToString_pureJava(o.args), "-> " + curlyIfScript(o.body)); if (o cast Tk.ReturnFromScript) ret "ret " + get(o.value); // end of explicitly handled cases warn("Can't convert to Java: " + className(o)); // Retain original script text as a default if (o cast Tk.Base) { var b = o; try object b?.srcText(); } // If that fails (it shouldn't), just return the toString warn("No source reference in script object: " + className(o)); ret str(o); } O curlyIfScript(Evaluable o) { if (o cast Tk.Script) ret "{\n" + indentx(get(o)) + "\n}"; ret get(o); } }