/** * This file is licensed under the terms of the Modified BSD License. */ package abs.backend.erlang; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import abs.backend.common.CodeStream; import abs.frontend.ast.ASTNode; import abs.frontend.ast.ClassDecl; import abs.frontend.ast.Model; import abs.frontend.ast.ModuleDecl; import abs.frontend.ast.ParamDecl; import abs.frontend.ast.PureExp; /** * Utility functions to mostly generate headers or parameter lists. * * @author Georg Göri * */ public class ErlUtil { public enum Mask { none, all, not_first }; public static final void functionHeaderParamsAsList(CodeStream ecs, String funName, String firstParameter, abs.frontend.ast.List<ParamDecl> args, Mask mask) { StringBuilder b = new StringBuilder("["); boolean first = true; for (ParamDecl p : args) { if (!first) b.append(','); else first = false; b.append("P_" + p.getName()); } if (args.hasChildren()) { b.append(','); } b.append("Stack]"); functionHeader(ecs, funName, mask, firstParameter, b.toString()); } // Not used when garbage collector pause points are added to functions // Consider removing public static final void functionHeader(CodeStream ecs, String funName, abs.frontend.ast.List<ParamDecl> args) { List<String> a = new ArrayList<String>(args.getNumChild()); for (ParamDecl p : args) a.add(p.getName()); functionHeader(ecs, funName, a, Mask.all); } public static final void functionHeader(CodeStream ecs, String funName, String firstParameter, abs.frontend.ast.List<ParamDecl> args) { List<String> a = new ArrayList<String>(args.getNumChild()); a.add(firstParameter); for (ParamDecl p : args) a.add(p.getName()); functionHeader(ecs, funName, a, Mask.not_first); } public static final void functionHeader(CodeStream ecs, String funName, String... args) { functionHeader(ecs, funName, Mask.all, args); } public static final void functionHeader(CodeStream ecs, String funName, Mask mask, String... args) { functionHeader(ecs, funName, Arrays.asList(args), mask); } public static final void functionHeader(CodeStream ecs, String funName, List<String> args, Mask mask) { ecs.format("'%s'(", funName); boolean first = true; for (String a : args) { if (!first) ecs.print(','); if (mask == Mask.all || mask == Mask.not_first && !first) { ecs.print(Vars.PREFIX); ecs.print(a + "_0"); } else ecs.print(a); if (first) first = false; } // Consider using a parameter for this // Any function/method callable in ABS, should take a representation of the execution stack // except the built-in functions. if (funName.startsWith("m_") || funName.startsWith("f_")) { if (!first) { ecs.print(','); } ecs.print("Stack"); } ecs.println(")->"); ecs.incIndent(); } public static final String getName(ClassDecl cd) { return "class_" + cd.getModuleDecl().getName().replace('.', '_') + "_" + cd.getName(); } public static final String getName(ModuleDecl cd) { return getModuleName(cd.getName()); } public static final String getModuleName(String name) { return "m_" + name.replace('.', '_'); } public static void buildParams(CodeStream ecs, abs.frontend.ast.List<PureExp> params, Vars vars, boolean emptyStack) { ecs.print("["); buildParamsWithOutBrackets(ecs, params, vars); if (params.hasChildren()) { ecs.print(','); } if (emptyStack) { ecs.print("[]"); } else { ecs.print(vars.toStack()); } ecs.print("]"); } public static void buildParamsWithOutBrackets(CodeStream ecs, abs.frontend.ast.List<PureExp> params, Vars vars) { boolean first = true; for (PureExp a : params) { if (!first) ecs.print(','); else first = false; a.generateErlangCode(ecs, vars); } } public static void argumentList(CodeStream ecs, PureExp callee, boolean builtin, boolean imperativeContext, abs.frontend.ast.List<PureExp> params, Vars vars) { ecs.print("("); if (callee != null) { callee.generateErlangCode(ecs, vars); if (params.hasChildren()) { ecs.print(","); } } else { ecs.print("Cog"); if (params.hasChildren()) { ecs.print(","); } } buildParamsWithOutBrackets(ecs, params, vars); if (!builtin) { ecs.print(','); if (imperativeContext) { ecs.print(vars.toStack()); } else { ecs.print("Stack"); } } ecs.print(")"); } public static void stopWorldPrelude(CodeStream ecs, Vars vars, boolean functional) { ecs.println("receive"); ecs.incIndent(); ecs.println("{stop_world, CogRef} ->"); ecs.incIndent(); ecs.println("cog:process_is_blocked_for_gc(Cog, self()),"); ecs.println("cog:process_is_runnable(Cog,self()),"); ecs.print("task:wait_for_token(Cog,"); if (functional) { ecs.print("lists:map(fun({_, X}) -> X end, maps:to_list(get(vars))) ++ Stack"); } else { ecs.print(vars.toStack()); } ecs.println(");"); ecs.decIndent().println("die_prematurely ->"); ecs.incIndent().println("task:send_notifications(killed_by_the_clock),"); ecs.println("exit(killed_by_the_clock)"); ecs.decIndent(); ecs.decIndent(); ecs.println("after 0 -> ok end,"); } public static void emitLocationInformation(CodeStream ecs, Model m, String filename, int start, int end) { if (m.generate_erlang_coverage) { ecs.pf("coverage:register(\"%s\", %s, %s),", new java.io.File(filename).getName(), start, end); } else { ecs.pf(" %%%% %s:%s--%s", filename, start, end); } } public static String absParamDeclToErlVarName(ParamDecl p) { return Vars.PREFIX + p.getName() + "_0"; } }