PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-1-pre5/org/gjt/sp/jedit/syntax/XModeHandler.java

#
Java | 694 lines | 566 code | 53 blank | 75 comment | 167 complexity | b8043e7c1a48e6f1de5043faac8b0a39 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. * XModeHandler.java - XML handler for mode files
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999 mike dillon
  7. * Portions copyright (C) 2000, 2001 Slava Pestov
  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 com.microstar.xml.*;
  26. import gnu.regexp.*;
  27. import java.io.*;
  28. import java.net.URL;
  29. import java.util.*;
  30. import org.gjt.sp.jedit.search.RESearchMatcher;
  31. import org.gjt.sp.jedit.*;
  32. import org.gjt.sp.util.Log;
  33. //}}}
  34. public class XModeHandler extends HandlerBase
  35. {
  36. //{{{ XModeHandler constructor
  37. public XModeHandler (XmlParser parser, String modeName, String path)
  38. {
  39. this.modeName = modeName;
  40. this.parser = parser;
  41. this.path = path;
  42. stateStack = new Stack();
  43. // default value
  44. lastNoWordSep = "_";
  45. } //}}}
  46. //{{{ resolveEntity() method
  47. public Object resolveEntity(String publicId, String systemId)
  48. {
  49. if("xmode.dtd".equals(systemId))
  50. {
  51. // this will result in a slight speed up, since we
  52. // don't need to read the DTD anyway, as AElfred is
  53. // non-validating
  54. return new StringReader("<!-- -->");
  55. /* try
  56. {
  57. return new BufferedReader(new InputStreamReader(
  58. getClass().getResourceAsStream(
  59. "/org/gjt/sp/jedit/xmode.dtd")));
  60. }
  61. catch(Exception e)
  62. {
  63. error("dtd",e);
  64. } */
  65. }
  66. return null;
  67. } //}}}
  68. //{{{ attribute() method
  69. public void attribute(String aname, String value, boolean isSpecified)
  70. {
  71. String tag = peekElement();
  72. aname = (aname == null) ? null : aname.intern();
  73. if (aname == "NAME")
  74. {
  75. propName = value;
  76. }
  77. else if (aname == "VALUE")
  78. {
  79. propValue = value;
  80. }
  81. else if (aname == "TYPE")
  82. {
  83. lastTokenID = Token.stringToToken(value);
  84. if(lastTokenID == -1)
  85. error("token-invalid",value);
  86. }
  87. else if (aname == "AT_LINE_START")
  88. {
  89. lastAtLineStart = (isSpecified) ? (value.equals("TRUE")) :
  90. false;
  91. }
  92. else if (aname == "AT_WHITESPACE_END")
  93. {
  94. lastAtWhitespaceEnd = (isSpecified) ? (value.equals("TRUE")) :
  95. false;
  96. }
  97. else if (aname == "AT_WORD_START")
  98. {
  99. lastAtWordStart = (isSpecified) ? (value.equals("TRUE")) :
  100. false;
  101. }
  102. else if (aname == "NO_LINE_BREAK")
  103. {
  104. lastNoLineBreak = (isSpecified) ? (value.equals("TRUE")) :
  105. false;
  106. }
  107. else if (aname == "NO_WORD_BREAK")
  108. {
  109. lastNoWordBreak = (isSpecified) ? (value.equals("TRUE")) :
  110. false;
  111. }
  112. else if (aname == "EXCLUDE_MATCH")
  113. {
  114. lastExcludeMatch = (isSpecified) ? (value.equals("TRUE")) :
  115. false;
  116. }
  117. else if (aname == "IGNORE_CASE")
  118. {
  119. lastIgnoreCase = (isSpecified) ? (value.equals("TRUE")) :
  120. true;
  121. }
  122. else if (aname == "HIGHLIGHT_DIGITS")
  123. {
  124. lastHighlightDigits = (isSpecified) ? (value.equals("TRUE")) :
  125. false;
  126. }
  127. else if (aname == "DIGIT_RE")
  128. {
  129. lastDigitRE = value;
  130. }
  131. else if (aname == "NO_WORD_SEP")
  132. {
  133. if(isSpecified)
  134. lastNoWordSep = value;
  135. }
  136. else if (aname == "AT_CHAR")
  137. {
  138. try
  139. {
  140. if (isSpecified) termChar =
  141. Integer.parseInt(value);
  142. }
  143. catch (NumberFormatException e)
  144. {
  145. error("termchar-invalid",value);
  146. termChar = -1;
  147. }
  148. }
  149. else if (aname == "ESCAPE")
  150. {
  151. lastEscape = value;
  152. }
  153. else if (aname == "SET")
  154. {
  155. lastSetName = value;
  156. }
  157. else if (aname == "DELEGATE")
  158. {
  159. lastDelegateSet = value;
  160. if (lastDelegateSet != null
  161. && lastDelegateSet.indexOf("::") == -1)
  162. {
  163. lastDelegateSet = modeName + "::" + lastDelegateSet;
  164. }
  165. }
  166. else if (aname == "DEFAULT")
  167. {
  168. lastDefaultID = Token.stringToToken(value);
  169. if(lastDefaultID == -1)
  170. {
  171. error("token-invalid",value);
  172. lastDefaultID = Token.NULL;
  173. }
  174. }
  175. else if (aname == "HASH_CHAR")
  176. {
  177. if(value.length() != 1)
  178. {
  179. error("hash-char-invalid",value);
  180. lastDefaultID = Token.NULL;
  181. }
  182. else
  183. lastHashChar = value.charAt(0);
  184. }
  185. } //}}}
  186. //{{{ doctypeDecl() method
  187. public void doctypeDecl(String name, String publicId,
  188. String systemId) throws Exception
  189. {
  190. if ("MODE".equalsIgnoreCase(name)) return;
  191. error("doctype-invalid",name);
  192. } //}}}
  193. //{{{ charData() method
  194. public void charData(char[] c, int off, int len)
  195. {
  196. String tag = peekElement();
  197. String text = new String(c, off, len);
  198. if (tag == "EOL_SPAN" ||
  199. tag == "MARK_PREVIOUS" ||
  200. tag == "MARK_FOLLOWING" ||
  201. tag == "SEQ" ||
  202. tag == "SEQ_REGEXP" ||
  203. tag == "BEGIN"
  204. )
  205. {
  206. lastStart = text;
  207. }
  208. else if (tag == "END")
  209. {
  210. lastEnd = text;
  211. }
  212. else
  213. {
  214. lastKeyword = text;
  215. }
  216. } //}}}
  217. //{{{ startElement() method
  218. public void startElement (String tag)
  219. {
  220. tag = pushElement(tag);
  221. if (tag == "WHITESPACE")
  222. {
  223. Log.log(Log.WARNING,this,path + ": WHITESPACE rule "
  224. + "no longer needed");
  225. }
  226. else if (tag == "MODE")
  227. {
  228. mode = jEdit.getMode(modeName);
  229. if (mode == null)
  230. {
  231. mode = new Mode(modeName);
  232. jEdit.addMode(mode);
  233. }
  234. }
  235. else if (tag == "KEYWORDS")
  236. {
  237. keywords = new KeywordMap(rules.getIgnoreCase());
  238. }
  239. else if (tag == "RULES")
  240. {
  241. rules = new ParserRuleSet(lastSetName,mode);
  242. rules.setIgnoreCase(lastIgnoreCase);
  243. rules.setHighlightDigits(lastHighlightDigits);
  244. if(lastDigitRE != null)
  245. {
  246. try
  247. {
  248. rules.setDigitRegexp(new RE(lastDigitRE,
  249. lastIgnoreCase
  250. ? RE.REG_ICASE : 0,
  251. RESearchMatcher.RE_SYNTAX_JEDIT));
  252. }
  253. catch(REException e)
  254. {
  255. error("regexp",e);
  256. }
  257. }
  258. if(lastEscape != null)
  259. rules.setEscapeRule(ParserRule.createEscapeRule(lastEscape));
  260. rules.setDefault(lastDefaultID);
  261. rules.setNoWordSep(lastNoWordSep);
  262. }
  263. } //}}}
  264. //{{{ endElement() method
  265. public void endElement (String name)
  266. {
  267. if (name == null) return;
  268. String tag = popElement();
  269. if (name.equalsIgnoreCase(tag))
  270. {
  271. //{{{ MODE
  272. if (tag == "MODE")
  273. {
  274. // no need for this anymore
  275. //mode.init();
  276. mode.setTokenMarker(marker);
  277. } //}}}
  278. //{{{ PROPERTY
  279. else if (tag == "PROPERTY")
  280. {
  281. props.put(propName,propValue);
  282. } //}}}
  283. //{{{ PROPS
  284. else if (tag == "PROPS")
  285. {
  286. if(peekElement().equals("RULES"))
  287. rules.setProperties(props);
  288. else
  289. mode.setProperties(props);
  290. props = new Hashtable();
  291. } //}}}
  292. //{{{ RULES
  293. else if (tag == "RULES")
  294. {
  295. rules.setKeywords(keywords);
  296. marker.addRuleSet(lastSetName, rules);
  297. keywords = null;
  298. lastSetName = null;
  299. lastEscape = null;
  300. lastIgnoreCase = true;
  301. lastHighlightDigits = false;
  302. lastDigitRE = null;
  303. lastDefaultID = Token.NULL;
  304. lastNoWordSep = "_";
  305. rules = null;
  306. } //}}}
  307. //{{{ TERMINATE
  308. else if (tag == "TERMINATE")
  309. {
  310. rules.setTerminateChar(termChar);
  311. termChar = -1;
  312. } //}}}
  313. //{{{ SEQ
  314. else if (tag == "SEQ")
  315. {
  316. if(lastStart == null)
  317. {
  318. error("empty-tag","SEQ");
  319. return;
  320. }
  321. rules.addRule(ParserRule.createSequenceRule(
  322. lastStart,lastDelegateSet,lastTokenID,
  323. lastAtLineStart,lastAtWhitespaceEnd,
  324. lastAtWordStart));
  325. lastStart = null;
  326. lastEnd = null;
  327. lastDelegateSet = null;
  328. lastTokenID = Token.NULL;
  329. lastAtLineStart = false;
  330. lastAtWordStart = false;
  331. lastAtWhitespaceEnd = false;
  332. } //}}}
  333. //{{{ SEQ_REGEXP
  334. else if (tag == "SEQ_REGEXP")
  335. {
  336. if(lastStart == null)
  337. {
  338. error("empty-tag","SEQ_REGEXP");
  339. return;
  340. }
  341. try
  342. {
  343. rules.addRule(ParserRule.createRegexpSequenceRule(
  344. lastHashChar,
  345. lastStart,lastDelegateSet,lastTokenID,
  346. lastAtLineStart,lastAtWhitespaceEnd,
  347. lastAtWordStart,lastIgnoreCase));
  348. }
  349. catch(REException re)
  350. {
  351. error("regexp",re);
  352. }
  353. lastHashChar = '\0';
  354. lastStart = null;
  355. lastEnd = null;
  356. lastDelegateSet = null;
  357. lastTokenID = Token.NULL;
  358. lastAtLineStart = false;
  359. lastAtWordStart = false;
  360. lastAtWhitespaceEnd = false;
  361. } //}}}
  362. //{{{ SPAN
  363. else if (tag == "SPAN")
  364. {
  365. if(lastStart == null)
  366. {
  367. error("empty-tag","START");
  368. return;
  369. }
  370. if(lastEnd == null)
  371. {
  372. error("empty-tag","END");
  373. return;
  374. }
  375. rules.addRule(ParserRule
  376. .createSpanRule(
  377. lastStart,lastEnd,
  378. lastDelegateSet,
  379. lastTokenID,lastNoLineBreak,
  380. lastAtLineStart,
  381. lastAtWhitespaceEnd,
  382. lastAtWordStart,
  383. lastExcludeMatch,
  384. lastNoWordBreak));
  385. lastStart = null;
  386. lastEnd = null;
  387. lastTokenID = Token.NULL;
  388. lastAtLineStart = false;
  389. lastAtWordStart = false;
  390. lastNoLineBreak = false;
  391. lastAtWhitespaceEnd = false;
  392. lastExcludeMatch = false;
  393. lastNoWordBreak = false;
  394. lastDelegateSet = null;
  395. } //}}}
  396. //{{{ SPAN_REGEXP
  397. else if (tag == "SPAN_REGEXP")
  398. {
  399. if(lastStart == null)
  400. {
  401. error("empty-tag","START");
  402. return;
  403. }
  404. if(lastEnd == null)
  405. {
  406. error("empty-tag","END");
  407. return;
  408. }
  409. try
  410. {
  411. rules.addRule(ParserRule
  412. .createRegexpSpanRule(
  413. lastHashChar,
  414. lastStart,lastEnd,
  415. lastDelegateSet,
  416. lastTokenID,lastNoLineBreak,
  417. lastAtLineStart,
  418. lastAtWhitespaceEnd,
  419. lastAtWordStart,
  420. lastExcludeMatch,
  421. lastNoWordBreak,
  422. lastIgnoreCase));
  423. }
  424. catch(REException re)
  425. {
  426. error("regexp",re);
  427. }
  428. lastHashChar = '\0';
  429. lastStart = null;
  430. lastEnd = null;
  431. lastTokenID = Token.NULL;
  432. lastAtLineStart = false;
  433. lastAtWordStart = false;
  434. lastNoLineBreak = false;
  435. lastAtWhitespaceEnd = false;
  436. lastExcludeMatch = false;
  437. lastNoWordBreak = false;
  438. lastDelegateSet = null;
  439. } //}}}
  440. //{{{ EOL_SPAN
  441. else if (tag == "EOL_SPAN")
  442. {
  443. if(lastStart == null)
  444. {
  445. error("empty-tag","EOL_SPAN");
  446. return;
  447. }
  448. rules.addRule(ParserRule.createEOLSpanRule(
  449. lastStart,lastDelegateSet,lastTokenID,
  450. lastAtLineStart,lastAtWhitespaceEnd,
  451. lastAtWordStart,lastExcludeMatch));
  452. lastStart = null;
  453. lastEnd = null;
  454. lastDelegateSet = null;
  455. lastTokenID = Token.NULL;
  456. lastAtLineStart = false;
  457. lastAtWordStart = false;
  458. lastAtWhitespaceEnd = false;
  459. lastExcludeMatch = false;
  460. } //}}}
  461. //{{{ EOL_SPAN_REGEXP
  462. else if (tag == "EOL_SPAN_REGEXP")
  463. {
  464. if(lastStart == null)
  465. {
  466. error("empty-tag","EOL_SPAN_REGEXP");
  467. return;
  468. }
  469. try
  470. {
  471. rules.addRule(ParserRule.createRegexpEOLSpanRule(
  472. lastHashChar,lastStart,lastDelegateSet,
  473. lastTokenID,lastAtLineStart,
  474. lastAtWhitespaceEnd,lastAtWordStart,
  475. lastExcludeMatch,lastIgnoreCase));
  476. }
  477. catch(REException re)
  478. {
  479. error("regexp",re);
  480. }
  481. lastHashChar = '\0';
  482. lastStart = null;
  483. lastEnd = null;
  484. lastDelegateSet = null;
  485. lastTokenID = Token.NULL;
  486. lastAtLineStart = false;
  487. lastAtWordStart = false;
  488. lastAtWhitespaceEnd = false;
  489. lastExcludeMatch = false;
  490. } //}}}
  491. //{{{ MARK_FOLLOWING
  492. else if (tag == "MARK_FOLLOWING")
  493. {
  494. if(lastStart == null)
  495. {
  496. error("empty-tag","MARK_FOLLOWING");
  497. return;
  498. }
  499. rules.addRule(ParserRule
  500. .createMarkFollowingRule(lastStart,
  501. lastTokenID,lastAtLineStart,
  502. lastAtWhitespaceEnd,lastAtWordStart,
  503. lastExcludeMatch));
  504. lastStart = null;
  505. lastEnd = null;
  506. lastTokenID = Token.NULL;
  507. lastAtLineStart = false;
  508. lastAtWordStart = false;
  509. lastAtWhitespaceEnd = false;
  510. lastExcludeMatch = false;
  511. } //}}}
  512. //{{{ MARK_PREVIOUS
  513. else if (tag == "MARK_PREVIOUS")
  514. {
  515. if(lastStart == null)
  516. {
  517. error("empty-tag","MARK_PREVIOUS");
  518. return;
  519. }
  520. rules.addRule(ParserRule
  521. .createMarkPreviousRule(lastStart,
  522. lastTokenID,lastAtLineStart,
  523. lastAtWhitespaceEnd,lastAtWordStart,
  524. lastExcludeMatch));
  525. lastStart = null;
  526. lastEnd = null;
  527. lastTokenID = Token.NULL;
  528. lastAtLineStart = false;
  529. lastAtWordStart = false;
  530. lastAtWhitespaceEnd = false;
  531. lastExcludeMatch = false;
  532. } //}}}
  533. //{{{ Keywords
  534. else
  535. {
  536. byte token = Token.stringToToken(tag);
  537. if(token != -1)
  538. addKeyword(lastKeyword,token);
  539. } //}}}
  540. }
  541. else
  542. {
  543. // can't happen
  544. throw new InternalError();
  545. }
  546. } //}}}
  547. //{{{ startDocument() method
  548. public void startDocument()
  549. {
  550. marker = new TokenMarker();
  551. marker.setName(modeName);
  552. props = new Hashtable();
  553. pushElement(null);
  554. } //}}}
  555. //{{{ Private members
  556. //{{{ Instance variables
  557. private XmlParser parser;
  558. private String modeName;
  559. private String path;
  560. private TokenMarker marker;
  561. private KeywordMap keywords;
  562. private Mode mode;
  563. private Stack stateStack;
  564. private String propName;
  565. private String propValue;
  566. private Hashtable props;
  567. private String lastStart;
  568. private String lastEnd;
  569. private String lastKeyword;
  570. private String lastSetName;
  571. private String lastEscape;
  572. private String lastDelegateSet;
  573. private String lastNoWordSep;
  574. private ParserRuleSet rules;
  575. private byte lastDefaultID = Token.NULL;
  576. private byte lastTokenID;
  577. private int termChar = -1;
  578. private boolean lastNoLineBreak;
  579. private boolean lastNoWordBreak;
  580. private boolean lastAtLineStart;
  581. private boolean lastAtWhitespaceEnd;
  582. private boolean lastAtWordStart;
  583. private boolean lastExcludeMatch;
  584. private boolean lastIgnoreCase = true;
  585. private boolean lastHighlightDigits;
  586. private String lastDigitRE;
  587. private char lastHashChar;
  588. //}}}
  589. //{{{ addKeyword() method
  590. private void addKeyword(String k, byte id)
  591. {
  592. if(k == null)
  593. {
  594. error("empty-keyword");
  595. return;
  596. }
  597. if (keywords == null) return;
  598. keywords.add(k,id);
  599. } //}}}
  600. //{{{ pushElement() method
  601. private String pushElement(String name)
  602. {
  603. name = (name == null) ? null : name.intern();
  604. stateStack.push(name);
  605. return name;
  606. } //}}}
  607. //{{{ peekElement() method
  608. private String peekElement()
  609. {
  610. return (String) stateStack.peek();
  611. } //}}}
  612. //{{{ popElement() method
  613. private String popElement()
  614. {
  615. return (String) stateStack.pop();
  616. } //}}}
  617. //{{{ error() method
  618. private void error(String msg)
  619. {
  620. _error(jEdit.getProperty("xmode-error." + msg));
  621. } //}}}
  622. //{{{ error() method
  623. private void error(String msg, String subst)
  624. {
  625. _error(jEdit.getProperty("xmode-error." + msg,new String[] { subst }));
  626. } //}}}
  627. //{{{ error() method
  628. private void error(String msg, Throwable t)
  629. {
  630. _error(jEdit.getProperty("xmode-error." + msg,new String[] { t.toString() }));
  631. Log.log(Log.ERROR,this,t);
  632. } //}}}
  633. //{{{ _error() method
  634. private void _error(String msg)
  635. {
  636. Object[] args = { path, new Integer(parser.getLineNumber()),
  637. new Integer(parser.getColumnNumber()), msg };
  638. GUIUtilities.error(null,"xmode-error",args);
  639. } //}}}
  640. //}}}
  641. }