KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > drjava > project > ProjectFileParser


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2005 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32  *END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.drjava.project;
35
36 import java.io.File JavaDoc;
37 import java.io.IOException JavaDoc;
38 import java.io.FileNotFoundException JavaDoc;
39 import java.util.List JavaDoc;
40 import java.util.ArrayList JavaDoc;
41 import java.util.Date JavaDoc;
42 import java.text.SimpleDateFormat JavaDoc;
43
44 import edu.rice.cs.drjava.config.FileOption;
45 import edu.rice.cs.plt.tuple.Pair;
46 import edu.rice.cs.util.sexp.*;
47 import edu.rice.cs.drjava.model.DocumentRegion;
48 import edu.rice.cs.drjava.model.SimpleDocumentRegion;
49 import edu.rice.cs.drjava.model.OpenDefinitionsDocument;
50 import edu.rice.cs.drjava.model.debug.DebugWatchData;
51 import edu.rice.cs.drjava.model.debug.DebugBreakpointData;
52 import edu.rice.cs.drjava.model.debug.DebugException;
53
54 /** This parser uses the s-expression parser defined in the util pacakge. The SExp tree given by the parser is
55  * interpreted into a ProjectFileIR that is given to the user. This class must also deal with different
56  * versions of the project file.
57  *
58  * <p> If at some point new information is to be stored in the project file, the following places in the code that need to
59  * changed: <menu> <li> If the new information pertains to a document, the DocFile class should be augmented to
60  * store the new info. <li> The interface for the DocumentInfoGetter should be expanded to allow for the new
61  * data to be retrieved. <li> Add a new clause to the else-if ladder in the FilePropertyVisitor. <li>
62  * Add the new information to the DocFile form the DocumentInfoGetter in the ProjectFileBuilder's
63  * addSourceDocument method.</p>
64  *
65  * <p> If the change is at the top level, you must modify the evaluateExpression method in this parser and add the
66  * corresponding methods to the ProjectFileIR, ProjectFileIRImpl, and ProjectFileBuilder</p>
67  */

68 public class ProjectFileParser {
69   /** Singleton instance of ProjectFileParser */
70   public static final ProjectFileParser ONLY = new ProjectFileParser();
71   
72   private File JavaDoc _projectFile;
73   private String JavaDoc _parent;
74   private String JavaDoc _srcFileBase;
75   
76   BreakpointListVisitor breakpointListVisitor = new BreakpointListVisitor();
77   BookmarkListVisitor bookmarkListVisitor = new BookmarkListVisitor();
78   
79   private ProjectFileParser() { }
80   
81   /* methods */
82   
83   /** @param projFile the file to parse
84    * @return the project file IR
85    */

86   public ProjectFileIR parse(File JavaDoc projFile) throws IOException JavaDoc, FileNotFoundException JavaDoc, MalformedProjectFileException {
87     
88     _projectFile = projFile;
89     _parent = projFile.getParent();
90     _srcFileBase = _parent; // oldest legacy file format may omit proj-root or proj-root-and-base node
91
// System.err.println("Parsing project file " + projFile + " with parent " + _parent);
92

93     List JavaDoc<SEList> forest = null;
94     try { forest = SExpParser.parse(projFile); }
95     catch(SExpParseException e) { throw new MalformedProjectFileException("Parse Error: " + e.getMessage()); }
96     
97     ProjectFileIR pfir = new ProjectProfile(projFile);
98
99     try { for (SEList exp : forest) evaluateExpression(exp, pfir, new DocFileListVisitor(_parent)); }
100     catch(PrivateProjectException e) { throw new MalformedProjectFileException("Parse Error: " + e.getMessage()); }
101     
102 // System.err.println("Parsed buildDir is " + pfir.getBuildDirectory());
103

104     return pfir;
105   }
106   
107   /** Given a top-level s-expression, this method checks the name of the node and configures the given pfir
108    * appropriately. If the expression is empty, it is ignored.
109    * @param e the top-level s-expression to check
110    * @param pfir the ProjectFileIR to update
111    */

112   private void evaluateExpression(SEList e, ProjectFileIR pfir, DocFileListVisitor flv) throws IOException JavaDoc {
113     if (e == Empty.ONLY) return;
114     Cons exp = (Cons) e; // If it's not empty, it's a cons
115

116     String JavaDoc name = exp.accept(NameVisitor.ONLY);
117     if ((name.compareToIgnoreCase("source") == 0) || (name.compareToIgnoreCase("source-files") == 0)) {
118       List JavaDoc<DocFile> dfList = exp.getRest().accept(new DocFileListVisitor(_srcFileBase));
119       pfir.setSourceFiles(dfList);
120     }
121     else if (name.compareToIgnoreCase("proj-root") == 0) { // legacy node form; all paths relative to project file
122
List JavaDoc<DocFile> fList = exp.getRest().accept(flv);
123       if (fList.size() > 1) throw new PrivateProjectException("Cannot have multiple source roots");
124       else if (fList.size() == 0) pfir.setProjectRoot(null); // can this ever happen?
125
pfir.setProjectRoot(fList.get(0));
126     }
127     else if (name.compareToIgnoreCase("proj-root-and-base") == 0) { // source file paths are relative to project root
128
List JavaDoc<DocFile> fList = exp.getRest().accept(flv);
129       if (fList.size() > 1) throw new PrivateProjectException("Cannot have multiple source roots");
130       File JavaDoc root = fList.get(0);
131       if (! root.exists()) throw new IOException JavaDoc("Project root " + root + " no longer exists");
132       pfir.setProjectRoot(root);
133       _srcFileBase = root.getCanonicalPath();
134     }
135     else if (name.compareToIgnoreCase("auxiliary") == 0) {
136       List JavaDoc<DocFile> dfList = exp.getRest().accept(flv);
137       pfir.setAuxiliaryFiles(dfList);
138     }
139     else if (name.compareToIgnoreCase("collapsed") == 0) {
140       List JavaDoc<String JavaDoc> sList = exp.getRest().accept(PathListVisitor.ONLY);
141       pfir.setCollapsedPaths(sList);
142     }
143     else if (name.compareToIgnoreCase("build-dir") == 0) {
144       List JavaDoc<DocFile> fList = exp.getRest().accept(flv);
145 // System.err.println("BuildDir fList = " + fList);
146
if (fList.size() > 1) throw new PrivateProjectException("Cannot have multiple build directories");
147       else if (fList.size() == 0) pfir.setBuildDirectory(null);
148       else pfir.setBuildDirectory(fList.get(0));
149     }
150     else if (name.compareToIgnoreCase("work-dir") == 0) {
151       List JavaDoc<DocFile> fList = exp.getRest().accept(flv);
152       if (fList.size() > 1) throw new PrivateProjectException("Cannot have multiple working directories");
153       else if (fList.size() == 0) pfir.setWorkingDirectory(null);
154       else pfir.setWorkingDirectory(fList.get(0));
155     }
156     else if (name.compareToIgnoreCase("classpaths") == 0) {
157       List JavaDoc<DocFile> fList = exp.getRest().accept(flv);
158       pfir.setClassPaths(fList);
159     }
160     else if (name.compareToIgnoreCase("main-class") == 0) {
161       List JavaDoc<DocFile> fList = exp.getRest().accept(flv);
162       if (fList.size() > 1) throw new PrivateProjectException("Cannot have multiple main classes");
163       else if (fList.size() == 0) pfir.setMainClass(null);
164       else pfir.setMainClass(fList.get(0));
165     }
166 // else if (name.compareToIgnoreCase("create-jar-file") == 0) {
167
// List<File> fList = exp.getRest().accept(fileListVisitor);
168
// if (fList.size() > 1) throw new PrivateProjectException("Cannot have more than one \"create jar\" file");
169
// else if (fList.size() == 0) pfir.setCreateJarFile(null);
170
// else pfir.setCreateJarFile(fList.get(0));
171
// }
172
// else if (name.compareToIgnoreCase("create-jar-flags") == 0) {
173
// Integer i = exp.getRest().accept(NumberVisitor.ONLY);
174
// pfir.setCreateJarFlags(i);
175
// }
176
else if (name.compareToIgnoreCase("breakpoints") == 0) {
177        List JavaDoc<DebugBreakpointData> bpList = exp.getRest().accept(breakpointListVisitor);
178        pfir.setBreakpoints(bpList);
179     }
180     else if (name.compareToIgnoreCase("watches") == 0) {
181       List JavaDoc<DebugWatchData> sList = exp.getRest().accept(WatchListVisitor.ONLY);
182       pfir.setWatches(sList);
183     }
184     else if (name.compareToIgnoreCase("bookmarks") == 0) {
185        List JavaDoc<DocumentRegion> bmList = exp.getRest().accept(bookmarkListVisitor);
186        pfir.setBookmarks(bmList);
187     }
188   }
189   
190   /** Parses out the labeled node (a non-empty list) into a DocFile. The node must have the "file" label on it.
191    * @param s the non-empty list expression
192    * @return the DocFile described by this s-expression
193    */

194   DocFile parseFile(SExp s, String JavaDoc pathRoot) {
195     String JavaDoc name = s.accept(NameVisitor.ONLY);
196     if (name.compareToIgnoreCase("file") != 0)
197       throw new PrivateProjectException("Expected a file tag, found: " + name);
198     if (! (s instanceof Cons))
199       throw new PrivateProjectException("Expected a labeled node, found a label: " + name);
200     SEList c = ((Cons)s).getRest(); // get parameter list
201

202     DocFilePropertyVisitor v = new DocFilePropertyVisitor(pathRoot);
203     return c.accept(v);
204   }
205   
206   private String JavaDoc parseFileName(SExp s) {
207     if (s instanceof Cons) {
208       SEList l = ((Cons)s).getRest();
209       if (l == Empty.ONLY)
210         throw new PrivateProjectException("expected filename, but nothing found");
211       else {
212         String JavaDoc name = l.accept(NameVisitor.ONLY);
213         name = edu.rice.cs.util.StringOps.replace(name,"\\","/");
214         return name;
215       }
216     }
217     else throw new PrivateProjectException("expected name tag, found string");
218   }
219   
220   private int parseInt(SExp s) {
221     if (s instanceof Cons) {
222       SEList l = ((Cons)s).getRest();
223       if (l == Empty.ONLY)
224         throw new PrivateProjectException("expected integer, but nothing found");
225       else {
226         int i = l.accept(NumberVisitor.ONLY);
227         return i;
228       }
229     }
230     else throw new PrivateProjectException("expected name tag, found string");
231   }
232   
233   private Pair<Integer JavaDoc,Integer JavaDoc> parseIntPair(SExp s) {
234     int row;
235     int col;
236     
237     /* we're getting in a "(select # #)" */
238     if (!(s instanceof Cons)) {
239       throw new PrivateProjectException("expected name tag, found string");
240     }
241     
242     // get rid of "select"
243
final List JavaDoc<Integer JavaDoc> intList = new ArrayList JavaDoc<Integer JavaDoc>();
244     SEList l = ((Cons)s).getRest();
245     List JavaDoc<Integer JavaDoc> li = l.accept(new SExpVisitor<List JavaDoc<Integer JavaDoc>>() {
246       public List JavaDoc<Integer JavaDoc> forEmpty(Empty e) { return intList; }
247   
248       public List JavaDoc<Integer JavaDoc> forCons(Cons c) {
249         c.getFirst().accept(this);
250         return c.getRest().accept(this);
251       }
252   
253       public List JavaDoc<Integer JavaDoc> forBoolAtom(BoolAtom b) {
254         throw new PrivateProjectException("unexpected boolean found, int expected");
255       }
256       
257       public List JavaDoc<Integer JavaDoc> forNumberAtom(NumberAtom n) {
258         intList.add(new Integer JavaDoc(n.intValue()));
259         return intList;
260       }
261       
262       public List JavaDoc<Integer JavaDoc> forTextAtom(TextAtom t) {
263         throw new PrivateProjectException("unexpected string found where number expected: " + t.getText());
264       }
265       
266     });
267     
268     if (li.size() == 2) return new Pair<Integer JavaDoc,Integer JavaDoc>(li.get(0), li.get(1));
269     else throw new PrivateProjectException("expected a list of 2 ints for select, found list of size " + li.size());
270   }
271
272     /** Takes input of form "(str str)" and returns the second string. */
273     private String JavaDoc parseStringNode(SExp n) {
274       if (n instanceof Cons)
275         return ((Cons)n).getRest().accept(NameVisitor.ONLY);
276       else throw new PrivateProjectException("List expected, but found text instead");
277     }
278   
279   /* nested/inner classes */
280   
281   /** Parses out a list of file nodes. */
282   private static class DocFileListVisitor implements SEListVisitor<List JavaDoc<DocFile>> {
283     /** Base directory for relative paths */
284     private String JavaDoc _base;
285     DocFileListVisitor(String JavaDoc base) { _base = base; }
286     public List JavaDoc<DocFile> forEmpty(Empty e) { return new ArrayList JavaDoc<DocFile>(); }
287     public List JavaDoc<DocFile> forCons(Cons c) {
288       List JavaDoc<DocFile> list = c.getRest().accept(this);
289       DocFile tmp = ProjectFileParser.ONLY.parseFile(c.getFirst(), _base);
290       list.add(0, tmp); // add to the end
291
return list;
292     }
293   };
294   
295   /** Traverses the list of expressions found after "file" tag and returns the DocFile described by those properties. */
296   private static class DocFilePropertyVisitor implements SEListVisitor<DocFile> {
297     private String JavaDoc fname = "";
298     private Pair<Integer JavaDoc,Integer JavaDoc> select = new Pair<Integer JavaDoc,Integer JavaDoc>(new Integer JavaDoc(0),new Integer JavaDoc(0));
299     private Pair<Integer JavaDoc,Integer JavaDoc> scroll = new Pair<Integer JavaDoc,Integer JavaDoc>(new Integer JavaDoc(0),new Integer JavaDoc(0));
300     private boolean active = false;
301     private String JavaDoc pack = "";
302     private Date JavaDoc modDate = null;
303     
304     private String JavaDoc pathRoot;
305     public DocFilePropertyVisitor(String JavaDoc pr) { pathRoot = pr; }
306     
307     public DocFile forCons(Cons c) {
308       String JavaDoc name = c.getFirst().accept(NameVisitor.ONLY);
309       if (name.compareToIgnoreCase("name") == 0) { fname = ProjectFileParser.ONLY.parseFileName(c.getFirst()); }
310       else if (name.compareToIgnoreCase("select") == 0) { select = ProjectFileParser.ONLY.parseIntPair(c.getFirst()); }
311       else if (name.compareToIgnoreCase("scroll") == 0) { scroll = ProjectFileParser.ONLY.parseIntPair(c.getFirst()); }
312       else if (name.compareToIgnoreCase("active") == 0) { active = true; }
313       else if (name.compareToIgnoreCase("package") == 0) {
314         pack = ProjectFileParser.ONLY.parseStringNode(c.getFirst());
315       }
316       else if (name.compareToIgnoreCase("mod-date") == 0) {
317         String JavaDoc tmp = ProjectFileParser.ONLY.parseStringNode(c.getFirst());
318         try { modDate = new SimpleDateFormat JavaDoc("dd-MMM-yyyy HH:mm:ss").parse(tmp); }
319         catch (java.text.ParseException JavaDoc e) { throw new PrivateProjectException("Bad mod-date: " + e.getMessage()); }
320       }
321         
322       return c.getRest().accept(this);
323     }
324     
325     public DocFile forEmpty(Empty c) {
326       if (pathRoot == null || new File JavaDoc(fname).isAbsolute()) {
327         return new DocFile(fname, select, scroll, active, pack);
328       }
329       else {
330         DocFile f = new DocFile(pathRoot, fname, select, scroll, active, pack);
331         if (modDate != null) f.setSavedModDate(modDate.getTime());
332         return f;
333       }
334     }
335   }
336   
337   /** Parses out a list of path nodes into a list of Strings. */
338   private static class PathListVisitor implements SEListVisitor<List JavaDoc<String JavaDoc>> {
339     public static final PathListVisitor ONLY = new PathListVisitor();
340     private PathListVisitor() { }
341     
342     public List JavaDoc<String JavaDoc> forEmpty(Empty e) { return new ArrayList JavaDoc<String JavaDoc>(); }
343     public List JavaDoc<String JavaDoc> forCons(Cons c) {
344       List JavaDoc<String JavaDoc> list = c.getRest().accept(this);
345       SExp first = c.getFirst();
346       String JavaDoc name = first.accept(NameVisitor.ONLY);
347       if (name.compareToIgnoreCase("path") == 0) {
348         String JavaDoc tmp = ProjectFileParser.ONLY.parseStringNode(c.getFirst());
349         list.add(0,tmp); // add to the end
350
}
351       return list;
352     }
353   };
354   
355   /** Retrieves the name of a node. The node should either be a list with its first element being a text atom,
356    * or a text atom itself.
357    */

358   private static class NameVisitor implements SExpVisitor<String JavaDoc> {
359     public static final NameVisitor ONLY = new NameVisitor();
360     private NameVisitor() { }
361     
362     public String JavaDoc forEmpty(Empty e) {
363       throw new PrivateProjectException("Found an empty node, expected a labeled node");
364     }
365     public String JavaDoc forCons(Cons c) { return c.getFirst().accept(this); }
366     public String JavaDoc forBoolAtom(BoolAtom b) {
367       throw new PrivateProjectException("Found a boolean, expected a label");
368     }
369     public String JavaDoc forNumberAtom(NumberAtom n) {
370       throw new PrivateProjectException("Found a number, expected a label");
371     }
372     public String JavaDoc forTextAtom(TextAtom t) { return t.getText(); }
373   };
374   
375   /** Retrieves the number of a node. The node should either be a list with its first element being a number atom,
376    * or a number atom itself.
377    */

378   private static class NumberVisitor implements SExpVisitor<Integer JavaDoc> {
379     public static final NumberVisitor ONLY = new NumberVisitor();
380     private NumberVisitor() { }
381     
382     public Integer JavaDoc forEmpty(Empty e) {
383       throw new PrivateProjectException("Found an empty node, expected an integer");
384     }
385     public Integer JavaDoc forCons(Cons c) { return c.getFirst().accept(this); }
386     public Integer JavaDoc forBoolAtom(BoolAtom b) {
387       throw new PrivateProjectException("Found a boolean, expected an integer");
388     }
389     public Integer JavaDoc forNumberAtom(NumberAtom n) { return n.intValue(); }
390     public Integer JavaDoc forTextAtom(TextAtom t) {
391       throw new PrivateProjectException("Found a string '"+t+"', expected an integer");
392     }
393   };
394
395   /** Parses out a list of watch names into a list of watches. */
396   private static class WatchListVisitor implements SEListVisitor<List JavaDoc<DebugWatchData>> {
397     public static final WatchListVisitor ONLY = new WatchListVisitor();
398     private WatchListVisitor() { }
399     
400     public List JavaDoc<DebugWatchData> forEmpty(Empty e) { return new ArrayList JavaDoc<DebugWatchData>(); }
401     public List JavaDoc<DebugWatchData> forCons(Cons c) {
402       List JavaDoc<DebugWatchData> list = c.getRest().accept(this);
403       SExp first = c.getFirst();
404       String JavaDoc name = first.accept(NameVisitor.ONLY);
405       if (name.compareToIgnoreCase("watch") == 0) {
406         String JavaDoc tmp = ProjectFileParser.ONLY.parseStringNode(c.getFirst());
407         list.add(0,new DebugWatchData(tmp)); // add to the end
408
}
409       return list;
410     }
411   };
412   
413   // === breakpoints ===
414

415   /** Parses out a list of breakpoint nodes. */
416   private class BreakpointListVisitor implements SEListVisitor<List JavaDoc<DebugBreakpointData>> {
417     public List JavaDoc<DebugBreakpointData> forEmpty(Empty e) { return new ArrayList JavaDoc<DebugBreakpointData>(); }
418     public List JavaDoc<DebugBreakpointData> forCons(Cons c) {
419       List JavaDoc<DebugBreakpointData> list = c.getRest().accept(this);
420       DebugBreakpointData tmp = ProjectFileParser.ONLY.parseBreakpoint(c.getFirst(), _srcFileBase);
421       list.add(0, tmp); // add to the end
422
return list;
423     }
424   };
425     
426   /** Parses out the labeled node (a non-empty list) into a breakpoint. The node must have the "breakpoint" label on it.
427    * @param s the non-empty list expression
428    * @return the breakpoint described by this s-expression
429    */

430   DebugBreakpointData parseBreakpoint(SExp s, String JavaDoc pathRoot) {
431     String JavaDoc name = s.accept(NameVisitor.ONLY);
432     if (name.compareToIgnoreCase("breakpoint") != 0)
433       throw new PrivateProjectException("Expected a breakpoint tag, found: " + name);
434     if (! (s instanceof Cons))
435       throw new PrivateProjectException("Expected a labeled node, found a label: " + name);
436     SEList c = ((Cons)s).getRest(); // get parameter list
437

438     BreakpointPropertyVisitor v = new BreakpointPropertyVisitor(pathRoot);
439     return c.accept(v);
440   }
441   
442   
443   /** Traverses the list of expressions found after "breakpoint" tag and returns the Breakpoint described by those properties. */
444   private static class BreakpointPropertyVisitor implements SEListVisitor<DebugBreakpointData> {
445     private String JavaDoc fname = null;
446     private Integer JavaDoc offset = null;
447     private Integer JavaDoc lineNumber = null;
448     private boolean isEnabled = false;
449     
450     private String JavaDoc pathRoot;
451     public BreakpointPropertyVisitor(String JavaDoc pr) { pathRoot = pr; }
452     
453     public DebugBreakpointData forCons(Cons c) {
454       String JavaDoc name = c.getFirst().accept(NameVisitor.ONLY);
455       if (name.compareToIgnoreCase("name") == 0) { fname = ProjectFileParser.ONLY.parseFileName(c.getFirst()); }
456       else if (name.compareToIgnoreCase("offset") == 0) { offset = ProjectFileParser.ONLY.parseInt(c.getFirst()); }
457       else if (name.compareToIgnoreCase("line") == 0) { lineNumber = ProjectFileParser.ONLY.parseInt(c.getFirst()); }
458       else if (name.compareToIgnoreCase("enabled") == 0) { isEnabled = true; }
459         
460       return c.getRest().accept(this);
461     }
462     
463     public DebugBreakpointData forEmpty(Empty c) {
464       if ((fname == null) || (offset == null) || (lineNumber == null)) {
465         throw new PrivateProjectException("Breakpoint information incomplete, need name, offset and line tags");
466       }
467       if (pathRoot == null || new File JavaDoc(fname).isAbsolute()) {
468         final File JavaDoc f = new File JavaDoc(fname);
469         return new DebugBreakpointData() {
470           public File JavaDoc getFile() { return f; }
471           public int getOffset() { return offset; }
472           public int getLineNumber() { return lineNumber; }
473           public boolean isEnabled() { return isEnabled; }
474         };
475       }
476       else {
477         final File JavaDoc f = new File JavaDoc(pathRoot, fname);
478         return new DebugBreakpointData() {
479           public File JavaDoc getFile() { return f; }
480           public int getOffset() { return offset; }
481           public int getLineNumber() { return lineNumber; }
482           public boolean isEnabled() { return isEnabled; }
483         };
484       }
485     }
486   }
487   
488   // === bookmarks ===
489

490   /** Parses out a list of bookmark nodes. */
491   private class BookmarkListVisitor implements SEListVisitor<List JavaDoc<DocumentRegion>> {
492     public List JavaDoc<DocumentRegion> forEmpty(Empty e) { return new ArrayList JavaDoc<DocumentRegion>(); }
493     public List JavaDoc<DocumentRegion> forCons(Cons c) {
494       List JavaDoc<DocumentRegion> list = c.getRest().accept(this);
495       DocumentRegion tmp = ProjectFileParser.ONLY.parseBookmark(c.getFirst(), _srcFileBase);
496       list.add(0, tmp); // add to the end
497
return list;
498     }
499   };
500     
501   /** Parses out the labeled node (a non-empty list) into a bookmark. The node must have the "bookmark" label on it.
502    * @param s the non-empty list expression
503    * @return the bookmark described by this s-expression
504    */

505   DocumentRegion parseBookmark(SExp s, String JavaDoc pathRoot) {
506     String JavaDoc name = s.accept(NameVisitor.ONLY);
507     if (name.compareToIgnoreCase("bookmark") != 0)
508       throw new PrivateProjectException("Expected a bookmark tag, found: " + name);
509     if (! (s instanceof Cons))
510       throw new PrivateProjectException("Expected a labeled node, found a label: " + name);
511     SEList c = ((Cons)s).getRest(); // get parameter list
512

513     BookmarkPropertyVisitor v = new BookmarkPropertyVisitor(pathRoot);
514     return c.accept(v);
515   }
516   
517   
518   /** Traverses the list of expressions found after "bookmark" tag and returns the DocumentRegion
519    * described by those properties. */

520   private static class BookmarkPropertyVisitor implements SEListVisitor<DocumentRegion> {
521     private String JavaDoc fname = null;
522     private Integer JavaDoc startOffset = null;
523     private Integer JavaDoc endOffset = null;
524     
525     private String JavaDoc pathRoot;
526     public BookmarkPropertyVisitor(String JavaDoc pr) { pathRoot = pr; }
527     
528     public DocumentRegion forCons(Cons c) {
529       String JavaDoc name = c.getFirst().accept(NameVisitor.ONLY);
530       if (name.compareToIgnoreCase("name") == 0) { fname = ProjectFileParser.ONLY.parseFileName(c.getFirst()); }
531       else if (name.compareToIgnoreCase("start") == 0) { startOffset = ProjectFileParser.ONLY.parseInt(c.getFirst()); }
532       else if (name.compareToIgnoreCase("end") == 0) { endOffset = ProjectFileParser.ONLY.parseInt(c.getFirst()); }
533         
534       return c.getRest().accept(this);
535     }
536     
537     public DocumentRegion forEmpty(Empty c) {
538       if ((fname == null) || (startOffset == null) || (endOffset == null)) {
539         throw new PrivateProjectException("Bookmark information incomplete, need name, start offset and end offset");
540       }
541       File JavaDoc f;
542       if (pathRoot == null || new File JavaDoc(fname).isAbsolute()) {
543         f = new File JavaDoc(fname);
544       }
545       else {
546         f = new File JavaDoc(pathRoot, fname);
547       }
548       return new SimpleDocumentRegion(null, f, startOffset, endOffset);
549     }
550   }
551   
552   private static class PrivateProjectException extends RuntimeException JavaDoc{
553     public PrivateProjectException(String JavaDoc message) { super(message); }
554   }
555 }
556
Popular Tags