PageRenderTime 61ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/antlr-2.7.5/antlr/ASTFactory.java

https://github.com/boo/boo-lang
Java | 410 lines | 239 code | 34 blank | 137 comment | 47 complexity | 50b164d77206bcdbb94f2ca9b20c1822 MD5 | raw file
Possible License(s): GPL-2.0
  1. package antlr;
  2. /* ANTLR Translator Generator
  3. * Project led by Terence Parr at http://www.jGuru.com
  4. * Software rights: http://www.antlr.org/license.html
  5. *
  6. * $Id: //depot/code/org.antlr/release/antlr-2.7.5/antlr/ASTFactory.java#1 $
  7. */
  8. import antlr.collections.AST;
  9. import antlr.collections.impl.ASTArray;
  10. import java.util.Hashtable;
  11. import java.lang.reflect.Constructor;
  12. /** AST Support code shared by TreeParser and Parser.
  13. * We use delegation to share code (and have only one
  14. * bit of code to maintain) rather than subclassing
  15. * or superclassing (forces AST support code to be
  16. * loaded even when you don't want to do AST stuff).
  17. *
  18. * Typically, setASTNodeType is used to specify the
  19. * homogeneous type of node to create, but you can override
  20. * create to make heterogeneous nodes etc...
  21. */
  22. public class ASTFactory {
  23. /** Name of AST class to create during tree construction.
  24. * Null implies that the create method should create
  25. * a default AST type such as CommonAST. This is for
  26. * homogeneous nodes.
  27. */
  28. protected String theASTNodeType = null;
  29. protected Class theASTNodeTypeClass = null;
  30. /** How to specify the classname to create for a particular
  31. * token type. Note that ANTLR allows you to say, for example,
  32. *
  33. tokens {
  34. PLUS<AST=PLUSNode>;
  35. ...
  36. }
  37. *
  38. * and it tracks everything statically. #[PLUS] will make you
  39. * a PLUSNode w/o use of this table.
  40. *
  41. * For tokens that ANTLR cannot track statically like #[i],
  42. * you can use this table to map PLUS (Integer) -> PLUSNode (Class)
  43. * etc... ANTLR sets the class map from the tokens {...} section
  44. * via the ASTFactory(Hashtable) ctor in antlr.Parser.
  45. */
  46. protected Hashtable tokenTypeToASTClassMap = null;
  47. public ASTFactory() {
  48. }
  49. /** Create factory with a specific mapping from token type
  50. * to Java AST node type. Your subclasses of ASTFactory
  51. * can override and reuse the map stuff.
  52. */
  53. public ASTFactory(Hashtable tokenTypeToClassMap) {
  54. setTokenTypeToASTClassMap(tokenTypeToClassMap);
  55. }
  56. /** Specify an "override" for the Java AST object created for a
  57. * specific token. It is provided as a convenience so
  58. * you can specify node types dynamically. ANTLR sets
  59. * the token type mapping automatically from the tokens{...}
  60. * section, but you can change that mapping with this method.
  61. * ANTLR does it's best to statically determine the node
  62. * type for generating parsers, but it cannot deal with
  63. * dynamic values like #[LT(1)]. In this case, it relies
  64. * on the mapping. Beware differences in the tokens{...}
  65. * section and what you set via this method. Make sure
  66. * they are the same.
  67. *
  68. * Set className to null to remove the mapping.
  69. *
  70. * @since 2.7.2
  71. */
  72. public void setTokenTypeASTNodeType(int tokenType, String className)
  73. throws IllegalArgumentException
  74. {
  75. if ( tokenTypeToASTClassMap==null ) {
  76. tokenTypeToASTClassMap = new Hashtable();
  77. }
  78. if ( className==null ) {
  79. tokenTypeToASTClassMap.remove(new Integer(tokenType));
  80. return;
  81. }
  82. Class c = null;
  83. try {
  84. c = Class.forName(className);
  85. tokenTypeToASTClassMap.put(new Integer(tokenType), c);
  86. }
  87. catch (Exception e) {
  88. throw new IllegalArgumentException("Invalid class, "+className);
  89. }
  90. }
  91. /** For a given token type, what is the AST node object type to create
  92. * for it?
  93. * @since 2.7.2
  94. */
  95. public Class getASTNodeType(int tokenType) {
  96. // try node specific class
  97. if ( tokenTypeToASTClassMap!=null ) {
  98. Class c = (Class)tokenTypeToASTClassMap.get(new Integer(tokenType));
  99. if ( c!=null ) {
  100. return c;
  101. }
  102. }
  103. // try a global specified class
  104. if (theASTNodeTypeClass != null) {
  105. return theASTNodeTypeClass;
  106. }
  107. // default to the common type
  108. return CommonAST.class;
  109. }
  110. /** Add a child to the current AST */
  111. public void addASTChild(ASTPair currentAST, AST child) {
  112. if (child != null) {
  113. if (currentAST.root == null) {
  114. // Make new child the current root
  115. currentAST.root = child;
  116. }
  117. else {
  118. if (currentAST.child == null) {
  119. // Add new child to current root
  120. currentAST.root.setFirstChild(child);
  121. }
  122. else {
  123. currentAST.child.setNextSibling(child);
  124. }
  125. }
  126. // Make new child the current child
  127. currentAST.child = child;
  128. currentAST.advanceChildToEnd();
  129. }
  130. }
  131. /** Create a new empty AST node; if the user did not specify
  132. * an AST node type, then create a default one: CommonAST.
  133. */
  134. public AST create() {
  135. return create(Token.INVALID_TYPE);
  136. }
  137. public AST create(int type) {
  138. Class c = getASTNodeType(type);
  139. AST t = create(c);
  140. if ( t!=null ) {
  141. t.initialize(type, "");
  142. }
  143. return t;
  144. }
  145. public AST create(int type, String txt) {
  146. AST t = create(type);
  147. if ( t!=null ) {
  148. t.initialize(type, txt);
  149. }
  150. return t;
  151. }
  152. /** Create an AST node with the token type and text passed in, but
  153. * with a specific Java object type. Typically called when you
  154. * say @[PLUS,"+",PLUSNode] in an antlr action.
  155. * @since 2.7.2
  156. */
  157. public AST create(int type, String txt, String className) {
  158. AST t = create(className);
  159. if ( t!=null ) {
  160. t.initialize(type, txt);
  161. }
  162. return t;
  163. }
  164. /** Create a new empty AST node; if the user did not specify
  165. * an AST node type, then create a default one: CommonAST.
  166. */
  167. public AST create(AST tr) {
  168. if (tr == null) return null; // create(null) == null
  169. AST t = create(tr.getType());
  170. if ( t!=null ) {
  171. t.initialize(tr);
  172. }
  173. return t;
  174. }
  175. public AST create(Token tok) {
  176. AST t = create(tok.getType());
  177. if ( t!=null ) {
  178. t.initialize(tok);
  179. }
  180. return t;
  181. }
  182. /** ANTLR generates reference to this when you reference a token
  183. * that has a specified heterogeneous AST node type. This is
  184. * also a special case node creation routine for backward
  185. * compatibility. Before, ANTLR generated "new T(tokenObject)"
  186. * and so I must call the appropriate constructor not T().
  187. *
  188. * @since 2.7.2
  189. */
  190. public AST create(Token tok, String className) {
  191. AST t = createUsingCtor(tok,className);
  192. return t;
  193. }
  194. /**
  195. * @since 2.7.2
  196. */
  197. public AST create(String className) {
  198. Class c = null;
  199. try {
  200. c = Class.forName(className);
  201. }
  202. catch (Exception e) {
  203. throw new IllegalArgumentException("Invalid class, "+className);
  204. }
  205. return create(c);
  206. }
  207. /**
  208. * @since 2.7.2
  209. */
  210. protected AST createUsingCtor(Token token, String className) {
  211. Class c = null;
  212. AST t = null;
  213. try {
  214. c = Class.forName(className);
  215. Class[] tokenArgType = new Class[] { antlr.Token.class };
  216. try {
  217. Constructor ctor = c.getConstructor(tokenArgType);
  218. t = (AST)ctor.newInstance(new Object[]{token}); // make a new one
  219. }
  220. catch (NoSuchMethodException e){
  221. // just do the regular thing if you can't find the ctor
  222. // Your AST must have default ctor to use this.
  223. t = create(c);
  224. if ( t!=null ) {
  225. t.initialize(token);
  226. }
  227. }
  228. }
  229. catch (Exception e) {
  230. throw new IllegalArgumentException("Invalid class or can't make instance, "+className);
  231. }
  232. return t;
  233. }
  234. /**
  235. * @since 2.7.2
  236. */
  237. protected AST create(Class c) {
  238. AST t = null;
  239. try {
  240. t = (AST)c.newInstance(); // make a new one
  241. }
  242. catch (Exception e) {
  243. error("Can't create AST Node " + c.getName());
  244. return null;
  245. }
  246. return t;
  247. }
  248. /** Copy a single node with same Java AST objec type.
  249. * Ignore the tokenType->Class mapping since you know
  250. * the type of the node, t.getClass(), and doing a dup.
  251. *
  252. * clone() is not used because we want all AST creation
  253. * to go thru the factory so creation can be
  254. * tracked. Returns null if t is null.
  255. */
  256. public AST dup(AST t) {
  257. if ( t==null ) {
  258. return null;
  259. }
  260. AST dup_t = create(t.getClass());
  261. dup_t.initialize(t);
  262. return dup_t;
  263. }
  264. /** Duplicate tree including siblings of root. */
  265. public AST dupList(AST t) {
  266. AST result = dupTree(t); // if t == null, then result==null
  267. AST nt = result;
  268. while (t != null) { // for each sibling of the root
  269. t = t.getNextSibling();
  270. nt.setNextSibling(dupTree(t)); // dup each subtree, building new tree
  271. nt = nt.getNextSibling();
  272. }
  273. return result;
  274. }
  275. /**Duplicate a tree, assuming this is a root node of a tree--
  276. * duplicate that node and what's below; ignore siblings of root node.
  277. */
  278. public AST dupTree(AST t) {
  279. AST result = dup(t); // make copy of root
  280. // copy all children of root.
  281. if (t != null) {
  282. result.setFirstChild(dupList(t.getFirstChild()));
  283. }
  284. return result;
  285. }
  286. /** Make a tree from a list of nodes. The first element in the
  287. * array is the root. If the root is null, then the tree is
  288. * a simple list not a tree. Handles null children nodes correctly.
  289. * For example, build(a, b, null, c) yields tree (a b c). build(null,a,b)
  290. * yields tree (nil a b).
  291. */
  292. public AST make(AST[] nodes) {
  293. if (nodes == null || nodes.length == 0) return null;
  294. AST root = nodes[0];
  295. AST tail = null;
  296. if (root != null) {
  297. root.setFirstChild(null); // don't leave any old pointers set
  298. }
  299. // link in children;
  300. for (int i = 1; i < nodes.length; i++) {
  301. if (nodes[i] == null) continue; // ignore null nodes
  302. if (root == null) {
  303. // Set the root and set it up for a flat list
  304. root = tail = nodes[i];
  305. }
  306. else if (tail == null) {
  307. root.setFirstChild(nodes[i]);
  308. tail = root.getFirstChild();
  309. }
  310. else {
  311. tail.setNextSibling(nodes[i]);
  312. tail = tail.getNextSibling();
  313. }
  314. // Chase tail to last sibling
  315. while (tail.getNextSibling() != null) {
  316. tail = tail.getNextSibling();
  317. }
  318. }
  319. return root;
  320. }
  321. /** Make a tree from a list of nodes, where the nodes are contained
  322. * in an ASTArray object
  323. */
  324. public AST make(ASTArray nodes) {
  325. return make(nodes.array);
  326. }
  327. /** Make an AST the root of current AST */
  328. public void makeASTRoot(ASTPair currentAST, AST root) {
  329. if (root != null) {
  330. // Add the current root as a child of new root
  331. root.addChild(currentAST.root);
  332. // The new current child is the last sibling of the old root
  333. currentAST.child = currentAST.root;
  334. currentAST.advanceChildToEnd();
  335. // Set the new root
  336. currentAST.root = root;
  337. }
  338. }
  339. public void setASTNodeClass(Class c) {
  340. if ( c!=null ) {
  341. theASTNodeTypeClass = c;
  342. theASTNodeType = c.getName();
  343. }
  344. }
  345. public void setASTNodeClass(String t) {
  346. theASTNodeType = t;
  347. try {
  348. theASTNodeTypeClass = Class.forName(t); // get class def
  349. }
  350. catch (Exception e) {
  351. // either class not found,
  352. // class is interface/abstract, or
  353. // class or initializer is not accessible.
  354. error("Can't find/access AST Node type" + t);
  355. }
  356. }
  357. /** Specify the type of node to create during tree building.
  358. * @deprecated since 2.7.1
  359. */
  360. public void setASTNodeType(String t) {
  361. setASTNodeClass(t);
  362. }
  363. public Hashtable getTokenTypeToASTClassMap() {
  364. return tokenTypeToASTClassMap;
  365. }
  366. public void setTokenTypeToASTClassMap(Hashtable tokenTypeToClassMap) {
  367. this.tokenTypeToASTClassMap = tokenTypeToClassMap;
  368. }
  369. /** To change where error messages go, can subclass/override this method
  370. * and then setASTFactory in Parser and TreeParser. This method removes
  371. * a prior dependency on class antlr.Tool.
  372. */
  373. public void error(String e) {
  374. System.err.println(e);
  375. }
  376. }