KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > polyglot > frontend > Job


1 package polyglot.frontend;
2
3 import polyglot.ast.*;
4 import polyglot.types.*;
5 import polyglot.util.*;
6 import polyglot.frontend.Compiler;
7
8 import java.util.*;
9
10 /**
11  * A <code>Job</code> encapsulates work done by the compiler. <code>Job</code>s
12  * are typically associated either with a nested class (<code>InnerJob</code>s)
13  * or a source file (<code>SourceJob</code>s). A Job contains all information
14  * carried between phases of the compiler. A Job consists of a set of scheduled
15  * passes over the associated code.
16  */

17 public abstract class Job
18 {
19     /** Field used for storing extension-specific information. */
20     protected JobExt ext;
21
22     /** The language extension used for this job. */
23     protected ExtensionInfo lang;
24
25     /** The AST constructed from the source file. */
26     protected Node ast;
27
28     /** List of passes to be run on this job. */
29     protected ArrayList passes;
30
31     /** Index of the next pass to run. */
32     protected int nextPass;
33
34     /** The currently running pass, or null. */
35     protected Pass runningPass;
36
37     /** True if all passes run so far have been successful. */
38     protected boolean status;
39
40     /** Map from pass id to pass. */
41     protected Map passMap;
42
43     /** Initial count of errors before running the job. */
44     protected int initialErrorCount;
45
46     /** True if the the job has reported an error. */
47     protected boolean reportedErrors;
48
49     public Job(ExtensionInfo lang, JobExt ext, Node ast) {
50         this.lang = lang;
51         this.ext = ext;
52     this.ast = ast;
53
54     this.passes = null;
55         this.passMap = null;
56         this.nextPass = 0;
57         this.runningPass = null;
58         this.status = true;
59         this.initialErrorCount = 0;
60         this.reportedErrors = false;
61     }
62
63     public JobExt ext() {
64       return ext;
65     }
66
67     /**
68      * Return the last <code>BarrierPass</code> that this job completed;
69      * return <code>null</code> if no <code>BarrierPass</code>es have
70      * yet been completed
71      */

72     public BarrierPass lastBarrier() {
73         for (int i = nextPass - 1; i >= 0; i--) {
74             Pass pass = (Pass) passes.get(i);
75
76             if (pass instanceof BarrierPass) {
77                 return (BarrierPass)pass;
78             }
79         }
80
81         return null;
82     }
83
84     public void setRunningPass(Pass pass) {
85         // The pass is not-null iff the job is running
86
if (pass != null) {
87             // We're starting to run the pass.
88
// Record the initial error count.
89
this.initialErrorCount = compiler().errorQueue().errorCount();
90         }
91         else {
92             // We've stopped running a pass.
93
// Check if the error count changed.
94
int errorCount = compiler().errorQueue().errorCount();
95
96             if (errorCount > initialErrorCount) {
97                 reportedErrors = true;
98             }
99         }
100
101         runningPass = pass;
102     }
103
104     public boolean isRunning() {
105         return runningPass != null;
106     }
107
108     public Pass runningPass() {
109         return runningPass;
110     }
111
112     /** Get the state's AST. */
113     public Node ast() {
114     return ast;
115     }
116
117     /** Set the state's AST. */
118     public void ast(Node ast) {
119         this.ast = ast;
120     }
121
122     /** True if some pass reported an error. */
123     public boolean reportedErrors() {
124         return reportedErrors;
125     }
126
127     public void dump(CodeWriter cw) {
128     if (ast != null) {
129         ast.dump(cw);
130     }
131     }
132
133     /**
134      * By default, a <code>Job</code> does not have a context associated
135      * with it. Subclasses may override this method.
136      */

137     public Context context() {
138         return null;
139     }
140     
141     /**
142      * Get the <code>SourceJob</code> associated with this <code>Job</code>.
143      * If this <code>Job</code> is a <code>SourceJob</code>, then this
144      * object should be returned; otherwise the most suitable
145      * <code>SourceJob</code> should be returned. See subclasses' documentation
146      * for more details of what the most suitable <code>SourceJob</code> is.
147      */

148     public abstract SourceJob sourceJob();
149
150     /**
151      * Return the <code>Source</code> associated with the
152      * <code>SourceJob</code> returned by <code>sourceJob</code>.
153      */

154     public Source source() {
155         return this.sourceJob().source();
156     }
157     
158     /**
159      * Returns whether the source for this job was explicitly specified
160      * by the user, or if it was drawn into the compilation process due
161      * to some dependency.
162      */

163     public boolean userSpecified() {
164         return this.source().userSpecified();
165     }
166
167     /**
168      * Get the initial list of passes that this <code>Job</code> should go
169      * through.
170      * This method is called only once, from <code>init</code>.
171      */

172     protected abstract List getPasses();
173
174     /**
175      * Get the list of passes that this <code>Job</code> needs to go through.
176      * This list is initialized with the list returned by
177      * <code>getPasses</code>.
178      */

179     public final List passes() {
180         if (passes == null) {
181             init();
182     }
183
184         return passes;
185     }
186
187     private Map passMap() {
188         if (passMap == null) {
189             init();
190         }
191         return passMap;
192     }
193
194     /**
195      * Initialize the <code>passes</code> field and the
196      * <code>passMap</code> field.
197      */

198     protected void init() {
199         passes = new ArrayList(getPasses());
200         passMap = new HashMap();
201         for (int i = 0; i < passes.size(); i++) {
202             Pass pass = (Pass) passes.get(i);
203             passMap.put(pass.id(), new Integer JavaDoc(i));
204         }
205     }
206
207     /**
208      * Return true if all of the passes been completed.
209      */

210     public boolean completed() {
211         return pendingPasses().isEmpty();
212     }
213
214     /**
215      * Return a list of passes that have been completed so far.
216      * The list returned by <code>completedPasses</code> concatenated with the
217      * list returned by <code>pendingPasses</code> should be equivalent to the
218      * list returned by <code>passes</code>.
219      */

220     public List completedPasses() {
221     return passes().subList(0, nextPass);
222     }
223
224     /**
225      * Return a list of passes that still have to be performed.
226      * The list returned by <code>completedPasses</code> concatenated with the
227      * list returned by <code>pendingPasses</code> should be equivalent to the
228      * list returned by <code>passes</code>.
229      */

230     public List pendingPasses() {
231     return passes().subList(nextPass, passes.size());
232     }
233
234     /**
235      * Return true if the pass <code>id</code> has been completed.
236      */

237     public boolean completed(Pass.ID id) {
238         Integer JavaDoc i = (Integer JavaDoc) passMap().get(id);
239         return i != null && i.intValue() < nextPass;
240     }
241
242     /**
243      * Return true if the pass <code>id</code> is still pending.
244      */

245     public boolean pending(Pass.ID id) {
246         Integer JavaDoc i = (Integer JavaDoc) passMap().get(id);
247         return i != null && i.intValue() >= nextPass;
248     }
249
250     /**
251      * Get the pass identified by <code>id</code>.
252      */

253     public Pass passByID(Pass.ID id) {
254         Integer JavaDoc i = (Integer JavaDoc) passMap().get(id);
255
256         if (i != null) {
257             return (Pass) passes().get(i.intValue());
258         }
259
260         throw new InternalCompilerError("No pass named \"" + id + "\".");
261     }
262
263     /**
264      * Return the pass immediately before the pass identified by <code>id</code>.
265      * Return <code>null</code> if no such pass exists.
266      */

267     public Pass getPreviousTo(Pass.ID id) {
268         Integer JavaDoc i = (Integer JavaDoc) passMap().get(id);
269
270         if (i != null) {
271             if (i.intValue() == 0)
272                 return null;
273             return (Pass) passes().get(i.intValue() - 1);
274         }
275
276         throw new InternalCompilerError("No pass named \"" + id + "\".");
277     }
278     
279     /**
280      * Return the next pass to be performed. Return null if there are no
281      * passes left to be performed.
282      */

283     public Pass nextPass() {
284         if (nextPass < passes().size()) {
285             Pass pass = (Pass) passes().get(nextPass);
286             return pass;
287         }
288         else {
289             return null;
290         }
291     }
292
293     
294     public boolean status() {
295         return status;
296     }
297
298     /**
299      * Inform this <code>Job</code> that pass <code>p</code> has finished.
300      * If <code>okay</code> is <code>true</code>, then the pass
301      * was completed successfully; if it is <code>false</code> the pass was not
302      * completed successfully.
303      *
304      * Pass <code>p</code> may be any pending pass.
305      */

306     public void finishPass(Pass p, boolean okay) {
307         List passes = passes();
308
309         status &= okay;
310
311         for (int i = nextPass; i < passes.size(); i++) {
312         Pass pass = (Pass) passes.get(i);
313
314         if (pass == p) {
315                 nextPass = i + 1;
316             return;
317         }
318     }
319     
320         throw new InternalCompilerError("Pass " + p + " was not a pending " +
321                             "pass.");
322     }
323
324     public ExtensionInfo extensionInfo() {
325     return lang;
326     }
327
328     public Compiler JavaDoc compiler() {
329     return lang.compiler();
330     }
331
332     /**
333      * Spawn a new job. All passes between the pass <code>begin</code>
334      * and <code>end</code> inclusive will be performed immediately on
335      * the AST <code>ast</code>, and the resulting AST returned.
336      *
337      * Spawn a new job. All passes between the pass <code>begin</code>
338      * and <code>end</code> inclusive will be performed immediately on
339      * the AST <code>ast</code>.
340      *
341      * @param c the context that the AST occurs in
342      * @param ast the AST the new Job is for.
343      * @param begin the first pass to perform for this job.
344      * @param end the last pass to perform for this job.
345      * @return the new job. The caller can check the result with
346      * <code>j.status()</code> and get the ast with <code>j.ast()</code>.
347      */

348     public Job spawn(Context c, Node ast, Pass.ID begin, Pass.ID end) {
349         return lang.spawnJob(c, ast, this, begin, end);
350     }
351 }
352
Popular Tags