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