1 package gnu.expr; 2 import gnu.mapping.*; 3 import gnu.lists.*; 4 import gnu.kawa.reflect.ClassMemberLocation; 5 import gnu.kawa.io.OutPort; 6 import gnu.kawa.io.WriterManager; 7 import gnu.kawa.util.ExitCalled; 8 9 /** 10 * Class for the dummy top-level function of a module. 11 */ 12 13 public abstract class ModuleBody implements RunnableModule 14 { 15 protected boolean runDone; 16 checkRunDone(boolean value)17 public boolean checkRunDone(boolean value) { 18 boolean tmp = runDone; 19 runDone = value; 20 return tmp; 21 } 22 run(CallContext ctx)23 public void run (CallContext ctx) throws Throwable 24 { 25 } 26 run()27 public void run () 28 { 29 synchronized (this) 30 { 31 if (runDone) 32 return; 33 runDone = true; 34 } 35 run(this, VoidConsumer.instance); 36 } 37 runToVoid(RunnableModule mod)38 public static void runToVoid (RunnableModule mod) 39 {run(mod, VoidConsumer.instance); } 40 run(Consumer out)41 public void run (Consumer out) { run(this, out); } run(RunnableModule mod, Consumer out)42 public static void run (RunnableModule mod, Consumer out) 43 { 44 // This should match the "run" method generated in Compilation. 45 CallContext ctx = CallContext.getInstance(); 46 Consumer save = ctx.consumer; 47 ctx.consumer = out; 48 Throwable th; 49 try 50 { 51 mod.run(ctx); 52 th = null; 53 } 54 catch (Throwable ex) 55 { 56 th = ex; 57 } 58 runCleanup(ctx, th, save); 59 } 60 runCleanup(CallContext ctx, Throwable th, Consumer save)61 public static void runCleanup (CallContext ctx, Throwable th, Consumer save) 62 { 63 if (th == null) 64 { 65 try 66 { 67 ctx.runUntilDone(); 68 } 69 catch (Throwable ex) 70 { 71 th = ex; 72 } 73 } 74 ctx.consumer = save; 75 if (th != null) 76 { 77 WrappedException.rethrow(th); 78 } 79 } 80 81 private static boolean mainPrintValues; 82 83 /** True if runAsMain should print values (in top-level expressions). */ getMainPrintValues()84 public static boolean getMainPrintValues() 85 { 86 return mainPrintValues; 87 } 88 setMainPrintValues(boolean value)89 public static void setMainPrintValues(boolean value) 90 { 91 mainPrintValues = value; 92 } 93 94 /** Number of times exitDecrement calls before we exit. */ 95 private static int exitCounter; 96 /** See exitDecrement. */ exitIncrement()97 public static synchronized void exitIncrement() 98 { 99 if (exitCounter == 0) 100 exitCounter++; 101 exitCounter++; 102 } 103 104 /** Work around an AWT bug, where AWT threads are non-daemon. 105 * Thus if you start up AWT, the JVM will wait for the AWT to finish, 106 * even if there are no other non-daemon threads. 107 * So call exitIncrement() each time a Freme is created, 108 * and call exitDecrement() when a Frame is closed. */ exitDecrement()109 public static synchronized void exitDecrement() 110 { 111 int counter = exitCounter; 112 if (counter > 0) 113 { 114 counter--; 115 if (counter == 0) 116 { 117 System.exit(0); 118 } 119 else 120 exitCounter = counter; 121 } 122 } 123 124 /** This is invoked by main when ModuleBody is compiled with --main. */ runAsMain()125 public final void runAsMain () 126 { 127 runAsMain(this); 128 } 129 130 /** This is invoked by main when ModuleBody is compiled with --main. */ runAsMain(RunnableModule module)131 public static void runAsMain (RunnableModule module) 132 { 133 boolean registered = WriterManager.instance.registerShutdownHook(); 134 try 135 { 136 ExitCalled.push(); 137 CallContext ctx = CallContext.getInstance(); 138 if (getMainPrintValues()) 139 { 140 OutPort out = OutPort.outDefault(); 141 ctx.consumer = kawa.Shell.getOutputConsumer(out); 142 module.run(ctx); 143 ctx.runUntilDone(); 144 out.freshLine(); 145 } 146 else 147 { 148 ctx.consumer = VoidConsumer.instance; 149 module.run(ctx); 150 ctx.runUntilDone(); 151 } 152 if (! registered) 153 gnu.kawa.io.OutPort.runCleanups(); 154 exitDecrement(); 155 } 156 catch (ExitCalled ex) 157 { 158 throw ex; // handled by ExitCalled.pop below. 159 } 160 catch (Throwable ex) 161 { 162 ex.printStackTrace(); 163 gnu.kawa.io.OutPort.runCleanups(); 164 System.exit(-1); 165 } 166 finally 167 { 168 ExitCalled.pop(); 169 } 170 } 171 172 } 173