PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre5/org/gjt/sp/jedit/syntax/TokenMarker.java

#
Java | 896 lines | 647 code | 114 blank | 135 comment | 163 complexity | 8a7536a95426b58b02378857f94e2928 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. * TokenMarker.java - Tokenizes lines of text
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1998, 1999, 2000, 2001 Slava Pestov
  7. * Copyright (C) 1999, 2000 mike dillon
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. */
  23. package org.gjt.sp.jedit.syntax;
  24. //{{{ Imports
  25. import javax.swing.text.Segment;
  26. import java.util.*;
  27. import org.gjt.sp.jedit.*;
  28. import org.gjt.sp.util.Log;
  29. //}}}
  30. /**
  31. * A token marker splits lines of text into tokens. Each token carries
  32. * a length field and an identification tag that can be mapped to a color
  33. * or font style for painting that token.
  34. *
  35. * @author Slava Pestov, mike dillon
  36. * @version $Id: TokenMarker.java 3954 2001-12-30 07:35:03Z spestov $
  37. *
  38. * @see org.gjt.sp.jedit.syntax.Token
  39. */
  40. public class TokenMarker
  41. {
  42. //{{{ Major actions (total: 8)
  43. public static final int MAJOR_ACTIONS = 0x000000FF;
  44. public static final int WHITESPACE = 1 << 0;
  45. public static final int SPAN = 1 << 1;
  46. public static final int MARK_PREVIOUS = 1 << 2;
  47. public static final int MARK_FOLLOWING = 1 << 3;
  48. public static final int EOL_SPAN = 1 << 4;
  49. // public static final int MAJOR_ACTION_5 = 1 << 5;
  50. // public static final int MAJOR_ACTION_6 = 1 << 6;
  51. // public static final int MAJOR_ACTION_7 = 1 << 7;
  52. //}}}
  53. //{{{ Action hints (total: 8)
  54. public static final int ACTION_HINTS = 0x0000FF00;
  55. public static final int EXCLUDE_MATCH = 1 << 8;
  56. public static final int AT_LINE_START = 1 << 9;
  57. public static final int NO_LINE_BREAK = 1 << 10;
  58. public static final int NO_WORD_BREAK = 1 << 11;
  59. public static final int IS_ESCAPE = 1 << 12;
  60. public static final int DELEGATE = 1 << 13;
  61. // public static final int ACTION_HINT_14 = 1 << 14;
  62. // public static final int ACTION_HINT_15 = 1 << 15;
  63. //}}}
  64. //{{{ TokenMarker constructor
  65. public TokenMarker()
  66. {
  67. ruleSets = new Hashtable(64);
  68. } //}}}
  69. //{{{ addRuleSet() method
  70. public void addRuleSet(String setName, ParserRuleSet rules)
  71. {
  72. if (rules == null) return;
  73. if (setName == null) setName = "MAIN";
  74. ruleSets.put(rulePfx.concat(setName), rules);
  75. if (setName.equals("MAIN"))
  76. mainRuleSet = rules;
  77. } //}}}
  78. //{{{ getMainRuleSet() method
  79. public ParserRuleSet getMainRuleSet()
  80. {
  81. return mainRuleSet;
  82. } //}}}
  83. //{{{ getRuleSet() method
  84. public ParserRuleSet getRuleSet(String setName)
  85. {
  86. ParserRuleSet rules;
  87. rules = (ParserRuleSet) ruleSets.get(setName);
  88. if (rules == null && !setName.startsWith(rulePfx))
  89. {
  90. int delim = setName.indexOf("::");
  91. String modeName = setName.substring(0, delim);
  92. Mode mode = jEdit.getMode(modeName);
  93. if(mode == null)
  94. {
  95. Log.log(Log.ERROR,TokenMarker.class,
  96. "Unknown edit mode: " + modeName);
  97. rules = null;
  98. }
  99. else
  100. {
  101. TokenMarker marker = mode.getTokenMarker();
  102. rules = marker.getRuleSet(setName);
  103. }
  104. // store external ParserRuleSet in the local hashtable for
  105. // faster lookups later
  106. ruleSets.put(setName, rules);
  107. }
  108. if (rules == null)
  109. {
  110. Log.log(Log.ERROR,this,"Unresolved delegate target: " + setName);
  111. }
  112. return rules;
  113. } //}}}
  114. //{{{ getName() method
  115. public String getName()
  116. {
  117. return name;
  118. } //}}}
  119. //{{{ setName() method
  120. public void setName(String name)
  121. {
  122. if (name == null) throw new NullPointerException();
  123. this.name = name;
  124. rulePfx = name.concat("::");
  125. } //}}}
  126. //{{{ markTokens() method
  127. /**
  128. * Do not call this method directly; call Buffer.markTokens() instead.
  129. */
  130. public LineContext markTokens(LineContext prevContext,
  131. Buffer.TokenList tokenList, Segment line)
  132. {
  133. this.context = new LineContext();
  134. //{{{ Set up context
  135. if(prevContext == null)
  136. context.rules = getMainRuleSet();
  137. else
  138. {
  139. context.parent = prevContext.parent;
  140. context.inRule = prevContext.inRule;
  141. context.rules = prevContext.rules;
  142. } //}}}
  143. lastOffset = lastKeyword = line.offset;
  144. lineLength = line.count + line.offset;
  145. int terminateChar = context.rules.getTerminateChar();
  146. int searchLimit = (terminateChar >= 0 && terminateChar < line.count)
  147. ? line.offset + terminateChar : lineLength;
  148. escaped = false;
  149. boolean b;
  150. boolean tempEscaped;
  151. Segment tempPattern;
  152. ParserRule rule;
  153. LineContext tempContext;
  154. for(pos = line.offset; pos < searchLimit; pos++)
  155. {
  156. //{{{ if we are not in the top level context, we are delegated
  157. if (context.parent != null)
  158. {
  159. tempContext = context;
  160. context = context.parent;
  161. pattern.array = context.inRule.searchChars;
  162. pattern.count = context.inRule.sequenceLengths[1];
  163. pattern.offset = context.inRule.sequenceLengths[0];
  164. b = handleRule(tokenList, line, context.inRule);
  165. context = tempContext;
  166. if (!b)
  167. {
  168. if (escaped)
  169. {
  170. escaped = false;
  171. }
  172. else
  173. {
  174. if (pos != lastOffset)
  175. {
  176. if (context.inRule == null)
  177. {
  178. markKeyword(tokenList,line,lastKeyword,pos);
  179. tokenList.addToken(pos - lastOffset,
  180. context.rules.getDefault(),
  181. context.rules);
  182. }
  183. else if ((context.inRule.action & (NO_LINE_BREAK | NO_WORD_BREAK)) == 0)
  184. {
  185. tokenList.addToken(pos - lastOffset,
  186. context.inRule.token,
  187. context.rules);
  188. }
  189. else
  190. {
  191. tokenList.addToken(pos - lastOffset, Token.INVALID,
  192. context.rules);
  193. }
  194. }
  195. context = (LineContext)context.parent.clone();
  196. if ((context.inRule.action & EXCLUDE_MATCH) == EXCLUDE_MATCH)
  197. {
  198. tokenList.addToken(pattern.count,
  199. context.rules.getDefault(),
  200. context.rules);
  201. }
  202. else
  203. {
  204. tokenList.addToken(pattern.count,
  205. context.inRule.token,
  206. context.rules);
  207. }
  208. context.inRule = null;
  209. lastKeyword = lastOffset = pos + pattern.count;
  210. }
  211. pos += (pattern.count - 1); // move pos to last character of match sequence
  212. continue;
  213. }
  214. } //}}}
  215. //{{{ check the escape rule for the current context, if there is one
  216. if ((rule = context.rules.getEscapeRule()) != null)
  217. {
  218. // assign tempPattern to mutable "buffer" pattern
  219. tempPattern = pattern;
  220. // swap in the escape pattern
  221. pattern = context.rules.getEscapePattern();
  222. tempEscaped = escaped;
  223. b = handleRule(tokenList, line, rule);
  224. // swap back the buffer pattern
  225. pattern = tempPattern;
  226. if (!b)
  227. {
  228. if (tempEscaped) escaped = false;
  229. continue;
  230. }
  231. } //}}}
  232. //{{{ if we are inside a span, check for its end sequence
  233. rule = context.inRule;
  234. if(rule != null && (rule.action & SPAN) == SPAN)
  235. {
  236. pattern.array = rule.searchChars;
  237. pattern.count = rule.sequenceLengths[1];
  238. pattern.offset = rule.sequenceLengths[0];
  239. // if we match the end of the span, or if this is a "hard" span,
  240. // we continue to the next character; otherwise, we check all
  241. // applicable rules below
  242. if (!handleRule(tokenList,line,rule)
  243. || (rule.action & SOFT_SPAN) == 0)
  244. {
  245. escaped = false;
  246. continue;
  247. }
  248. } //}}}
  249. //{{{ now check every rule
  250. rule = context.rules.getRules(line.array[pos]);
  251. while(rule != null)
  252. {
  253. pattern.array = rule.searchChars;
  254. if (context.inRule == rule && (rule.action & SPAN) == SPAN)
  255. {
  256. pattern.count = rule.sequenceLengths[1];
  257. pattern.offset = rule.sequenceLengths[0];
  258. }
  259. else
  260. {
  261. pattern.count = rule.sequenceLengths[0];
  262. pattern.offset = 0;
  263. }
  264. // stop checking rules if there was a match and go to next pos
  265. if (!handleRule(tokenList,line,rule))
  266. break;
  267. rule = rule.next;
  268. } //}}}
  269. escaped = false;
  270. }
  271. //{{{ check for keywords at the line's end
  272. if(context.inRule == null)
  273. markKeyword(tokenList, line, lastKeyword, lineLength);
  274. //}}}
  275. //{{{ mark all remaining characters
  276. if(lastOffset != lineLength)
  277. {
  278. if (context.inRule == null)
  279. {
  280. tokenList.addToken(lineLength - lastOffset,
  281. context.rules.getDefault(),
  282. context.rules);
  283. }
  284. else if (
  285. (context.inRule.action & SPAN) == SPAN &&
  286. (context.inRule.action & (NO_LINE_BREAK | NO_WORD_BREAK)) != 0
  287. )
  288. {
  289. tokenList.addToken(lineLength - lastOffset,Token.INVALID,
  290. context.rules);
  291. context.inRule = null;
  292. }
  293. else
  294. {
  295. tokenList.addToken(lineLength - lastOffset,
  296. context.inRule.token,
  297. context.rules);
  298. if((context.inRule.action & MARK_FOLLOWING) == MARK_FOLLOWING)
  299. {
  300. context.inRule = null;
  301. }
  302. }
  303. } //}}}
  304. tokenList.addToken(0,Token.END,context.rules);
  305. return context.intern();
  306. } //}}}
  307. //{{{ Private members
  308. private static final int SOFT_SPAN = MARK_FOLLOWING | NO_WORD_BREAK;
  309. //{{{ Instance variables
  310. private String name;
  311. private String rulePfx;
  312. private Hashtable ruleSets;
  313. private ParserRuleSet mainRuleSet;
  314. private LineContext context;
  315. private Segment pattern = new Segment(new char[0],0,0);
  316. private int lastOffset;
  317. private int lastKeyword;
  318. private int lineLength;
  319. private int pos;
  320. private boolean escaped;
  321. //}}}
  322. //{{{ handleRule() method
  323. /**
  324. * Checks if the rule matches the line at the current position
  325. * and handles the rule if it does match
  326. * @param line Segment to check rule against
  327. * @param checkRule ParserRule to check against line
  328. * @return true, keep checking other rules
  329. * <br>false, stop checking other rules
  330. */
  331. private boolean handleRule(Buffer.TokenList tokenList, Segment line,
  332. ParserRule checkRule)
  333. {
  334. if (pattern.count == 0) return true;
  335. if (lineLength - pos < pattern.count) return true;
  336. char a, b;
  337. for (int k = 0; k < pattern.count; k++)
  338. {
  339. a = pattern.array[pattern.offset + k];
  340. b = line.array[pos + k];
  341. //{{{ break out and check the next rule if there is a mismatch
  342. if (
  343. !(
  344. a == b ||
  345. context.rules.getIgnoreCase() &&
  346. (
  347. Character.toLowerCase(a) == b ||
  348. a == Character.toLowerCase(b)
  349. )
  350. )
  351. ) return true;
  352. //}}}
  353. }
  354. if (escaped)
  355. {
  356. pos += pattern.count - 1;
  357. return false;
  358. }
  359. else if ((checkRule.action & IS_ESCAPE) == IS_ESCAPE)
  360. {
  361. escaped = true;
  362. pos += pattern.count - 1;
  363. return false;
  364. }
  365. //{{{ handle soft spans
  366. if (context.inRule != checkRule && context.inRule != null
  367. && (context.inRule.action & SOFT_SPAN) != 0)
  368. {
  369. if ((context.inRule.action & NO_WORD_BREAK) == NO_WORD_BREAK)
  370. {
  371. tokenList.addToken(pos - lastOffset, Token.INVALID,
  372. context.rules);
  373. }
  374. else
  375. {
  376. tokenList.addToken(pos - lastOffset,
  377. context.inRule.token,
  378. context.rules);
  379. }
  380. lastOffset = lastKeyword = pos;
  381. context.inRule = null;
  382. } //}}}
  383. //{{{ not inside a rule
  384. if (context.inRule == null)
  385. {
  386. if ((checkRule.action & AT_LINE_START) == AT_LINE_START)
  387. {
  388. if (
  389. (((checkRule.action & MARK_PREVIOUS) != 0) ?
  390. lastKeyword :
  391. pos) != line.offset
  392. )
  393. {
  394. return true;
  395. }
  396. }
  397. markKeyword(tokenList, line, lastKeyword, pos);
  398. if ((checkRule.action & MARK_PREVIOUS) != MARK_PREVIOUS)
  399. {
  400. lastKeyword = pos + pattern.count;
  401. if ((checkRule.action & WHITESPACE) == WHITESPACE)
  402. {
  403. return false; // break out of inner for loop to check next char
  404. }
  405. // mark previous sequence as NULL (plain text)
  406. if (lastOffset < pos)
  407. {
  408. tokenList.addToken(pos - lastOffset,
  409. context.rules.getDefault(),
  410. context.rules);
  411. }
  412. }
  413. switch(checkRule.action & MAJOR_ACTIONS)
  414. {
  415. //{{{ SEQ
  416. case 0:
  417. // this is a plain sequence rule
  418. tokenList.addToken(pattern.count,checkRule.token,
  419. context.rules);
  420. lastOffset = pos + pattern.count;
  421. break;
  422. //}}}
  423. //{{{ SPAN
  424. case SPAN:
  425. context.inRule = checkRule;
  426. //{{{ Non-delegated
  427. if ((checkRule.action & DELEGATE) != DELEGATE)
  428. {
  429. if ((checkRule.action & EXCLUDE_MATCH) == EXCLUDE_MATCH)
  430. {
  431. tokenList.addToken(pattern.count,
  432. context.rules.getDefault(),
  433. context.rules);
  434. lastOffset = pos + pattern.count;
  435. }
  436. else
  437. {
  438. lastOffset = pos;
  439. }
  440. } //}}}
  441. //{{{ Delegated
  442. else
  443. {
  444. String setName = new String(checkRule.searchChars,
  445. checkRule.sequenceLengths[0] + checkRule.sequenceLengths[1],
  446. checkRule.sequenceLengths[2]);
  447. ParserRuleSet delegateSet = getRuleSet(setName);
  448. if (delegateSet != null)
  449. {
  450. if ((checkRule.action & EXCLUDE_MATCH) == EXCLUDE_MATCH)
  451. {
  452. tokenList.addToken(pattern.count,
  453. context.rules.getDefault(),
  454. context.rules);
  455. }
  456. else
  457. {
  458. tokenList.addToken(pattern.count,
  459. checkRule.token,
  460. context.rules);
  461. }
  462. lastOffset = pos + pattern.count;
  463. context = new LineContext(delegateSet, context);
  464. }
  465. } //}}}
  466. break;
  467. //}}}
  468. //{{{ EOL_SPAN
  469. case EOL_SPAN:
  470. if ((checkRule.action & EXCLUDE_MATCH) == EXCLUDE_MATCH)
  471. {
  472. tokenList.addToken(pattern.count,
  473. context.rules.getDefault(),
  474. context.rules);
  475. tokenList.addToken(lineLength - (pos + pattern.count),
  476. checkRule.token,context.rules);
  477. }
  478. else
  479. {
  480. tokenList.addToken(lineLength - pos,
  481. checkRule.token,context.rules);
  482. }
  483. lastOffset = lineLength;
  484. lastKeyword = lineLength;
  485. pos = lineLength;
  486. return false;
  487. //}}}
  488. //{{{ MARK_PREVIOUS
  489. case MARK_PREVIOUS:
  490. if (lastKeyword > lastOffset)
  491. {
  492. tokenList.addToken(lastKeyword - lastOffset,
  493. context.rules.getDefault(),
  494. context.rules);
  495. lastOffset = lastKeyword;
  496. }
  497. if ((checkRule.action & EXCLUDE_MATCH) == EXCLUDE_MATCH)
  498. {
  499. tokenList.addToken(pos - lastOffset,
  500. checkRule.token,context.rules);
  501. tokenList.addToken(pattern.count,
  502. context.rules.getDefault(),
  503. context.rules);
  504. }
  505. else
  506. {
  507. tokenList.addToken(pos - lastOffset + pattern.count,
  508. checkRule.token,context.rules);
  509. }
  510. lastOffset = pos + pattern.count;
  511. break;
  512. //}}}
  513. //{{{ MARK_FOLLOWING
  514. case MARK_FOLLOWING:
  515. context.inRule = checkRule;
  516. if ((checkRule.action & EXCLUDE_MATCH) == EXCLUDE_MATCH)
  517. {
  518. tokenList.addToken(pattern.count,
  519. context.rules.getDefault(),
  520. context.rules);
  521. lastOffset = pos + pattern.count;
  522. }
  523. else
  524. {
  525. lastOffset = pos;
  526. }
  527. break;
  528. //}}}
  529. default:
  530. throw new InternalError("Unhandled major action");
  531. }
  532. lastKeyword = lastOffset;
  533. pos += (pattern.count - 1); // move pos to last character of match sequence
  534. return false; // break out of inner for loop to check next char
  535. }
  536. //}}}
  537. //{{{ inside a SPAN
  538. else if ((checkRule.action & SPAN) == SPAN)
  539. {
  540. if ((checkRule.action & DELEGATE) != DELEGATE)
  541. {
  542. context.inRule = null;
  543. if ((checkRule.action & EXCLUDE_MATCH) == EXCLUDE_MATCH)
  544. {
  545. tokenList.addToken(pos - lastOffset,
  546. checkRule.token,context.rules);
  547. tokenList.addToken(pattern.count,
  548. context.rules.getDefault(),
  549. context.rules);
  550. }
  551. else
  552. {
  553. tokenList.addToken((pos + pattern.count) - lastOffset,
  554. checkRule.token,context.rules);
  555. }
  556. lastKeyword = lastOffset = pos + pattern.count;
  557. pos += (pattern.count - 1); // move pos to last character of match sequence
  558. }
  559. return false; // break out of inner for loop to check next char
  560. }//}}}
  561. return true;
  562. } //}}}
  563. //{{{ markKeyword() method
  564. private void markKeyword(Buffer.TokenList tokenList, Segment line,
  565. int start, int end)
  566. {
  567. KeywordMap keywords = context.rules.getKeywords();
  568. int len = end - start;
  569. //{{{ do digits.
  570. /* right now, this is hardcoded to handle these cases:
  571. * 1234
  572. * 0x1234abcf
  573. * 1234l
  574. * 12.34f
  575. * 12.34d
  576. *
  577. * in the future, we need some sort of regexp mechanism. */
  578. if(context.rules.getHighlightDigits())
  579. {
  580. boolean digit = true;
  581. char[] array = line.array;
  582. boolean octal = false;
  583. boolean hex = false;
  584. boolean seenSomeDigits = false;
  585. loop: for(int i = 0; i < len; i++)
  586. {
  587. char ch = array[start+i];
  588. switch(ch)
  589. {
  590. case '0':
  591. if(i == 0)
  592. octal = true;
  593. seenSomeDigits = true;
  594. continue loop;
  595. case '1': case '2': case '3':
  596. case '4': case '5': case '6':
  597. case '7': case '8': case '9':
  598. seenSomeDigits = true;
  599. continue loop;
  600. case 'x': case 'X':
  601. if(octal && i == 1)
  602. {
  603. hex = true;
  604. continue loop;
  605. }
  606. else
  607. break;
  608. case 'd': case 'D':
  609. case 'f': case 'F':
  610. if(hex)
  611. continue loop;
  612. else if(i == len -1 && seenSomeDigits)
  613. continue loop;
  614. else
  615. break;
  616. case 'l': case 'L':
  617. if(i == len -1 && seenSomeDigits)
  618. continue loop;
  619. else
  620. break;
  621. case 'e': case 'E':
  622. if(seenSomeDigits)
  623. continue loop;
  624. else
  625. break;
  626. case 'a': case 'A': case 'b': case 'B':
  627. case 'c': case 'C':
  628. if(hex)
  629. continue loop;
  630. else
  631. break;
  632. case '.': case '-':
  633. // normally, this shouldn't be
  634. // necessary, because most modes
  635. // define '.' and '-' SEQs. However,
  636. // in props mode, we can't define
  637. // such a SEQ because it would
  638. // break the AT_LINE_START
  639. // MARK_PREVIOUS rule.
  640. continue loop;
  641. default:
  642. break;
  643. }
  644. // if we ended up here, then we have found a
  645. // non-digit character.
  646. digit = false;
  647. break loop;
  648. }
  649. // if we got this far with digit = true, then the keyword
  650. // consists of all digits. Add it as such.
  651. if(digit && seenSomeDigits)
  652. {
  653. if(start != lastOffset)
  654. {
  655. tokenList.addToken(start - lastOffset,
  656. context.rules.getDefault(),
  657. context.rules);
  658. }
  659. tokenList.addToken(len,Token.DIGIT,context.rules);
  660. lastKeyword = lastOffset = end;
  661. return;
  662. }
  663. } //}}}
  664. if(keywords != null)
  665. {
  666. byte id = keywords.lookup(line, start, len);
  667. if(id != Token.NULL)
  668. {
  669. if(start != lastOffset)
  670. {
  671. tokenList.addToken(start - lastOffset,
  672. context.rules.getDefault(),
  673. context.rules);
  674. }
  675. tokenList.addToken(len,id,context.rules);
  676. lastKeyword = lastOffset = end;
  677. }
  678. }
  679. } //}}}
  680. //}}}
  681. //{{{ LineContext class
  682. public static class LineContext
  683. {
  684. //{{{ Debug code
  685. static int count;
  686. static int countGC;
  687. public String getAllocationStatistics()
  688. {
  689. return "total: " + count + ", in core: " +
  690. (count - countGC)
  691. + ", interned: " + intern.size();
  692. } //}}}
  693. static Hashtable intern = new Hashtable();
  694. public LineContext parent;
  695. public ParserRule inRule;
  696. public ParserRuleSet rules;
  697. //{{{ LineContext constructor
  698. public LineContext(ParserRule r, ParserRuleSet rs)
  699. {
  700. this();
  701. inRule = r;
  702. rules = rs;
  703. } //}}}
  704. //{{{ LineContext constructor
  705. public LineContext(ParserRuleSet rs, LineContext lc)
  706. {
  707. this();
  708. rules = rs;
  709. parent = (lc == null ? null : (LineContext)lc.clone());
  710. } //}}}
  711. //{{{ LineContext constructor
  712. public LineContext(ParserRule r)
  713. {
  714. this();
  715. inRule = r;
  716. } //}}}
  717. //{{{ LineContext constructor
  718. public LineContext()
  719. {
  720. count++;
  721. } //}}}
  722. //{{{ intern() method
  723. public LineContext intern()
  724. {
  725. Object obj = intern.get(this);
  726. if(obj == null)
  727. {
  728. intern.put(this,this);
  729. return this;
  730. }
  731. else
  732. return (LineContext)obj;
  733. } //}}}
  734. //{{{ finalize() method
  735. public void finalize()
  736. {
  737. countGC++;
  738. } //}}}
  739. //{{{ hashCode() method
  740. public int hashCode()
  741. {
  742. if(inRule != null)
  743. return inRule.hashCode();
  744. else if(rules != null)
  745. return rules.hashCode();
  746. else
  747. return 0;
  748. } //}}}
  749. //{{{ equals() method
  750. public boolean equals(Object obj)
  751. {
  752. if(obj instanceof LineContext)
  753. {
  754. LineContext lc = (LineContext)obj;
  755. if(lc.parent == null)
  756. {
  757. if(parent != null)
  758. return false;
  759. }
  760. else //if(lc.parent != null)
  761. {
  762. if(parent == null)
  763. return false;
  764. else if(!lc.parent.equals(parent))
  765. return false;
  766. }
  767. return lc.inRule == inRule && lc.rules == rules;
  768. }
  769. else
  770. return false;
  771. } //}}}
  772. //{{{ clone() method
  773. public Object clone()
  774. {
  775. LineContext lc = new LineContext();
  776. lc.inRule = inRule;
  777. lc.rules = rules;
  778. lc.parent = (parent == null) ? null : (LineContext) parent.clone();
  779. return lc;
  780. } //}}}
  781. } //}}}
  782. }