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