PageRenderTime 95ms CodeModel.GetById 58ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/SideKick/sidekick/enhanced/SourceParser.java

#
Java | 372 lines | 240 code | 43 blank | 89 comment | 27 complexity | 3f8b6168f09ca08c8b977122672f3615 MD5 | raw file
  1/*
  2 * SourceParser.java
  3 * :folding=explicit:collapseFolds=1:
  4 *
  5 * Copyright (C) 2005 by Martin Raspe
  6 * (hertzhaft@biblhertz.it)
  7 *
  8 * This program is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU General Public License
 10 * as published by the Free Software Foundation; either version 2
 11 * of the License, or any later version.
 12 *
 13 * This program is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 * GNU General Public License for more details.
 17 *
 18 * You should have received a copy of the GNU General Public License
 19 * along with this program; if not, write to the Free Software
 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 21 */
 22package sidekick.enhanced;
 23
 24import javax.swing.tree.*;
 25import javax.swing.text.Position;
 26import javax.swing.ImageIcon;
 27import java.util.*;
 28import java.util.regex.*;
 29
 30import java.net.URL;
 31
 32import org.gjt.sp.jedit.*;
 33import org.gjt.sp.util.*;
 34import org.gjt.sp.util.Log;
 35
 36import sidekick.SideKickParsedData;
 37import sidekick.SideKickParser;
 38
 39import errorlist.*;
 40
 41
 42/**
 43 * SourceParser: parses source and builds a sidekick structure tree
 44 * Parsers are based on regular expressions and will therefore
 45 * not able to correctly parse irregular source
 46 *
 47 * @author     Martin Raspe
 48 * @created    Oct 15, 2005
 49 * @modified   $Id: SourceParser.java 13298 2008-08-14 05:05:06Z daleanson $
 50 * @version    $Revision: 13298 $
 51 */
 52public class SourceParser extends SideKickParser implements PartialParser {
 53	//{{{ Icons
 54	public ImageIcon PACKAGE_ICON;
 55	public ImageIcon USE_ICON;
 56	public ImageIcon SUB_ICON;
 57	public ImageIcon PACKAGE_INVALID_ICON;
 58	public ImageIcon USE_INVALID_ICON;
 59	public ImageIcon SUB_INVALID_ICON;
 60	public ImageIcon COMMENT_ICON;
 61	//}}}
 62
 63	//{{{ vars
 64	public String LINE_COMMENT;
 65	public String COMMENT;	// title for block comments
 66	public String MAIN;	// title for default package
 67	public String USE;	// title for import modules
 68
 69	public String USE_KEY   = "---use---";
 70	public String SUB_KEY   = "---sub---";
 71	public String PKG_KEY   = "---pkg---";
 72
 73	protected SideKickParsedData data;
 74	protected PackageMap packages;
 75	protected ArrayList commentList;
 76	protected SourceAsset _asset;
 77	protected SourceAsset _pkgAsset;
 78
 79	protected Position _start;
 80	protected Position _end;
 81    protected int _lastLineNumber = 0;
 82
 83    protected int startLine = 0;
 84
 85	//}}}
 86
 87/**	 * Constructs a new SourceParser object
 88	 *
 89	 * @param name See sidekick.SidekickParser.
 90	 */
 91	public SourceParser(String name) {
 92		super(name);
 93		loadIcons(name, getClass());
 94	}
 95
 96	public SourceParser(String name, Class cls) {
 97		super(name);
 98		loadIcons(name, cls);
 99	}
100/**	 * Parses the given text and returns a tree model.
101	 *
102	 * @param buffer The buffer to parse.
103	 * @param errorSource An error source to add errors to.
104	 *
105	 * @return A new instance of the <code>SourceParsedData</code> class.
106	 */
107	public SideKickParsedData parse(Buffer buffer, DefaultErrorSource errorSource) {
108		data = new SideKickParsedData(buffer.getName());
109		packages = new PackageMap(new PackageComparator());
110		commentList = new ArrayList();
111		parseBuffer(buffer, errorSource);
112		completePackageAsset(_end, _lastLineNumber);
113		Log.log(Log.DEBUG, this, "parsing completed");
114		buildTrees();
115		Log.log(Log.DEBUG, this, "tree built");
116		return data;
117	}
118
119    /**
120     * Parse the contents of the given text.  This is the entry point to use when
121     * only a portion of the buffer text is to be parsed.  Note that <code>setLineOffset</code>
122     * should be called prior to calling this method, otherwise, tree node positions
123     * may be off.
124     * <p>
125     * This default implementation simply delegates to <code>parse(Buffer, DefaultErrorSource)</code>.
126     * Subclasses should override to actually parse appropriately.
127     *
128     * @param buffer       the buffer containing the text to parse
129     * @param text         the text to parse
130     * @param errorSource  where to send errors
131     * @return             the parsed buffer as a tree
132     */
133     public SideKickParsedData parse( Buffer buffer, String text, DefaultErrorSource errorSource ) {
134        return parse(buffer, errorSource);
135     }
136
137    /**
138     * If called by another parser to parse part of a file (for example, to parse
139     * a script tag in an html document), this can be set to the offset of the
140     * text to be parsed so that the node locations can be set correctly.
141     *
142     * @param startLine the starting line in the buffer of the text that is to
143     * be parsed.
144     */
145     public void setStartLine(int startLine) {
146        this.startLine = startLine;
147     }
148
149	protected void parseBuffer(Buffer buffer, DefaultErrorSource errorSource) {
150		}
151
152	protected void loadIcons(String name, Class cls) {
153		PACKAGE_ICON		= loadIcon(name, cls, "package-icon");
154		USE_ICON		= loadIcon(name, cls, "use-icon");
155		SUB_ICON		= loadIcon(name, cls, "sub-icon");
156		PACKAGE_INVALID_ICON	= loadIcon(name, cls, "package_invalid-icon");
157		USE_INVALID_ICON	= loadIcon(name, cls, "use-invalid-icon");
158		SUB_INVALID_ICON	= loadIcon(name, cls, "sub-invalid-icon");
159		COMMENT_ICON		= loadIcon(name, cls, "comment-icon");
160	}
161
162	protected ImageIcon loadIcon(String name, Class cls, String icon) {
163		String iconfile = jEdit.getProperty("sidekick.parser." + name + "." + icon);
164		URL res = cls.getResource("/icons/" + iconfile);
165		if (res == null) return null;
166		return new ImageIcon(res);
167	}
168
169	// Sets the end position of the most recently created asset.
170	protected void completeAsset(Position end) {
171		if (_asset != null) _asset.setEnd(end);
172		_asset = null;
173		}
174
175	// Sets the end position of the most recently created asset.
176	protected void completeAsset(Position end, String desc) {
177		if (_asset != null)
178			_asset.setLongDescription(desc);
179		completeAsset(end);
180		}
181
182	// Sets the end position of the most recently created asset.
183	protected void completeAsset(Position end, int lineNo) {
184		if (_asset != null)
185			_asset.setLongDescription(
186                		_asset.getLongDescription()+ "-" + lineNo
187				);
188		_lastLineNumber = lineNo;
189		completeAsset(end);
190		}
191
192	// Sets the end position of the most recently created package asset.
193	protected void completePackageAsset(Position end, int lineNo) {
194		completeAsset(end, lineNo);
195		_asset = _pkgAsset;
196		completeAsset(end, lineNo);
197        }
198
199    // Adds a multi-line asset to the list of its package
200	protected void addAsset(String typ, String p, String name, int lineNo, Position start) {
201		completeAsset(start, lineNo);
202		_asset = new SourceAsset(name, lineNo, start);
203		packages.addToList(typ, p, _asset);
204		}
205
206	// Adds a one-line asset (don't complete the current _asset yet)
207	protected void addLineAsset(String typ, String p, String name, int lineNo, Position start, Position end) {
208		SourceAsset a = new SourceAsset(name, lineNo, start);
209		a.setEnd(end);
210		packages.addToList(typ, p, a);
211		}
212
213	//Adds an asset to the pod list
214	protected void addCommentAsset(String name, int lineNo, Position start) {
215		completeAsset(start, lineNo);
216		_asset = new SourceAsset(name, lineNo, start);
217		commentList.add(_asset);
218		}
219
220	// Adds a new package to the "packages" TreeMap.
221	protected void addPackageAsset(String name, int lineNo, Position start) {
222		completePackageAsset(start, lineNo);
223		SourceAsset a = new SourceAsset(name, lineNo, start);
224		_pkgAsset = a;
225        packages.addPackage(name, a);
226		}
227
228	// Builds the sidekick tree from the "packages" TreeMap
229	protected void buildTrees() {
230		Set list = packages.keySet();
231		Iterator i = list.iterator();
232		while(i.hasNext()) {
233			String name = (String) i.next();
234			HashMap h = (HashMap) packages.get(name);
235			SourceAsset a = (SourceAsset) h.get(PKG_KEY);
236			a.setIcon(PACKAGE_ICON);
237			DefaultMutableTreeNode t = new DefaultMutableTreeNode(a);
238			newTree(t, USE, (ArrayList) h.get(USE_KEY), USE_ICON);
239			addList(t, (ArrayList) h.get(SUB_KEY), SUB_ICON);
240			data.root.add(t);
241			}
242		newTree(data.root, COMMENT, commentList, COMMENT_ICON);
243		}
244
245	// Builds a tree from asset list "list" and adds it to tree node "n".
246	protected void newTree(DefaultMutableTreeNode n, String name, ArrayList list, ImageIcon icon) {
247		if (list.size() == 0) return;
248		SourceAsset first = (SourceAsset) list.get(0);
249		SourceAsset branch = new SourceAsset(name, first.getLineNo(), first.getStart());
250		branch.setIcon(icon);
251		DefaultMutableTreeNode t = new DefaultMutableTreeNode(branch);
252		addList(t, list, null);
253		n.add(t);
254		}
255
256	//Adds an Asset list "list" to a tree node "n"
257	protected void addList(DefaultMutableTreeNode t, ArrayList list, ImageIcon icon) {
258		Collections.sort(list, new AssetComparator());
259		Iterator i = list.iterator();
260		while(i.hasNext()) {
261			SourceAsset a = (SourceAsset) i.next();
262			a.setIcon(icon);
263			t.add(new DefaultMutableTreeNode(a));
264			}
265		}
266
267	// match a line and return the specified group if found
268	protected String find(String line, Pattern p, int g) {
269		Matcher m = p.matcher(line);
270		return m.find() ? m.group(g) : null;
271		}
272
273	// match a line and return package and subname if found
274	protected String[] find2(String line, Pattern p) {
275		String[] res = new String[2];
276		Matcher m = p.matcher(line);
277		if (m.find()) {
278			res[0] = m.group(1);
279			res[1] = m.group(2);
280			}
281		else res = null;
282		return res;
283		}
284
285	// compare strings, ignore case
286	protected class AssetComparator implements Comparator {
287		public int compare(Object o1, Object o2) {
288			String s1 = ((SourceAsset) o1).toString();
289			String s2 = ((SourceAsset) o2).toString();
290			return s1.toLowerCase().compareTo(s2.toLowerCase());
291			}
292		}
293
294	// sort package names
295	public class PackageComparator implements Comparator{
296		public int compare(Object o1, Object o2) {
297			String s1 = (String)o1;
298			String s2 = (String)o2;
299			int comp = s1.toLowerCase().compareTo(s2.toLowerCase());
300			if (comp == 0) return comp;
301			// pull up module MAIN
302			if (s1.equals(MAIN)) return -1;
303			if (s2.equals(MAIN)) return 1;
304			return comp;
305			}
306		}
307
308	// reflects perl script structure
309	public class PackageMap extends TreeMap {
310		public PackageMap() {
311			super();
312			}
313
314		public PackageMap(PackageComparator pc) {
315			super(pc);
316			}
317
318		// add a HashMap for a new package name
319		public HashMap addPackage(String p, SourceAsset a) {
320			if (this.containsKey(p))
321                return (HashMap) this.get(p);
322			HashMap h = new HashMap();
323			h.put(PKG_KEY, a);
324			h.put(USE_KEY, new ArrayList());
325			h.put(SUB_KEY, new ArrayList());
326			this.put(p, h);
327			return h;
328			}
329
330		// get the package asset by name
331		public SourceAsset getPackageAsset(String p) {
332			if (! this.containsKey(p))
333				return null;
334			HashMap h = (HashMap) this.get(p);
335			return (SourceAsset) h.get(PKG_KEY);
336			}
337
338		// set the end position for a package asset
339		public void completePackageAsset(String p, Position end) {
340			SourceAsset a = getPackageAsset(p);
341			if (a != null) a.setEnd(end);
342			}
343
344		public void completePackageAsset(String p, Position end, String desc) {
345			SourceAsset a = getPackageAsset(p);
346			if (a == null)
347			return;
348			a.setLongDescription(desc);
349			a.setEnd(end);
350			}
351
352		public void completePackageAsset(String p, Position end, int lineNo) {
353			SourceAsset a = getPackageAsset(p);
354			if (a == null)
355			return;
356			a.setLongDescription(a.getLongDescription() + "-" + lineNo);
357			a.setEnd(end);
358			}
359
360		// add an Asset of type "typ" to the TreeMap for package "p"
361		public void addToList(String typ, String p, SourceAsset a) {
362			SourceAsset pkg = new SourceAsset(p, a.getLineNo(), a.getStart());
363			HashMap h = addPackage(p, pkg);
364			ArrayList list = (ArrayList) h.get(typ);
365			if (list != null)
366			list.add(a);
367			else Log.log(Log.DEBUG, SourceParser.class,
368			"Entry " + typ + " not in PackageMap"
369			);
370			}
371		}
372}