PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre3/org/gjt/sp/jedit/syntax/XModeHandler.java

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