KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > syntax > XModeHandler


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
24 package org.gjt.sp.jedit.syntax;
25
26 //{{{ Imports
27
import java.util.*;
28 import java.util.regex.Pattern JavaDoc;
29 import java.util.regex.PatternSyntaxException JavaDoc;
30
31 import org.xml.sax.Attributes JavaDoc;
32 import org.xml.sax.InputSource JavaDoc;
33 import org.xml.sax.helpers.DefaultHandler JavaDoc;
34
35 import org.gjt.sp.util.Log;
36 import org.gjt.sp.util.XMLUtilities;
37 //}}}
38

39 /**
40  * XML handler for mode definition files.
41  * @version $Id: XModeHandler.java 8103 2006-11-21 00:03:41Z vampire0 $
42  */

43 public abstract class XModeHandler extends DefaultHandler JavaDoc
44 {
45     //{{{ XModeHandler constructor
46
public XModeHandler (String JavaDoc modeName)
47     {
48         this.modeName = modeName;
49         marker = new TokenMarker();
50         marker.addRuleSet(new ParserRuleSet(modeName,"MAIN"));
51         stateStack = new Stack<TagDecl>();
52     } //}}}
53

54     //{{{ resolveEntity() method
55
public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId)
56     {
57         return XMLUtilities.findEntity(systemId, "xmode.dtd", XModeHandler.class);
58     } //}}}
59

60     //{{{ characters() method
61
public void characters(char[] c, int off, int len)
62     {
63         peekElement().setText(c, off, len);
64     } //}}}
65

66     //{{{ startElement() method
67
public void startElement(String JavaDoc uri, String JavaDoc localName,
68                  String JavaDoc qName, Attributes JavaDoc attrs)
69     {
70         TagDecl tag = pushElement(qName, attrs);
71
72         if (qName.equals("WHITESPACE"))
73         {
74             Log.log(Log.WARNING,this,modeName + ": WHITESPACE rule "
75                 + "no longer needed");
76         }
77         else if (qName.equals("KEYWORDS"))
78         {
79             keywords = new KeywordMap(rules.getIgnoreCase());
80         }
81         else if (qName.equals("RULES"))
82         {
83             if(tag.lastSetName == null)
84                 tag.lastSetName = "MAIN";
85             rules = marker.getRuleSet(tag.lastSetName);
86             if(rules == null)
87             {
88                 rules = new ParserRuleSet(modeName,tag.lastSetName);
89                 marker.addRuleSet(rules);
90             }
91             rules.setIgnoreCase(tag.lastIgnoreCase);
92             rules.setHighlightDigits(tag.lastHighlightDigits);
93             if(tag.lastDigitRE != null)
94             {
95                 try
96                 {
97                     rules.setDigitRegexp(Pattern.compile(tag.lastDigitRE,
98                         tag.lastIgnoreCase
99                         ? Pattern.CASE_INSENSITIVE : 0));
100                 }
101                 catch(PatternSyntaxException JavaDoc e)
102                 {
103                     error("regexp",e);
104                 }
105             }
106
107             if(tag.lastEscape != null)
108                 rules.setEscapeRule(ParserRule.createEscapeRule(tag.lastEscape));
109             rules.setDefault(tag.lastDefaultID);
110             rules.setNoWordSep(tag.lastNoWordSep);
111         }
112     } //}}}
113

114     //{{{ endElement() method
115
public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc name)
116     {
117         TagDecl tag = popElement();
118         if (name.equals(tag.tagName))
119         {
120             //{{{ PROPERTY
121
if (tag.tagName.equals("PROPERTY"))
122             {
123                 props.put(propName,propValue);
124             } //}}}
125
//{{{ PROPS
126
else if (tag.tagName.equals("PROPS"))
127             {
128                 if(peekElement().tagName.equals("RULES"))
129                     rules.setProperties(props);
130                 else
131                     modeProps = props;
132
133                 props = new Hashtable<String JavaDoc, String JavaDoc>();
134             } //}}}
135
//{{{ RULES
136
else if (tag.tagName.equals("RULES"))
137             {
138                 rules.setKeywords(keywords);
139                 keywords = null;
140                 rules = null;
141             } //}}}
142
//{{{ IMPORT
143
else if (tag.tagName.equals("IMPORT"))
144             {
145                 // prevent lockups
146
if (!rules.getSetName().equals(tag.lastDelegateSet.getSetName()))
147                 {
148                     rules.addRuleSet(tag.lastDelegateSet);
149                 }
150             } //}}}
151
//{{{ TERMINATE
152
else if (tag.tagName.equals("TERMINATE"))
153             {
154                 rules.setTerminateChar(tag.termChar);
155             } //}}}
156
//{{{ SEQ
157
else if (tag.tagName.equals("SEQ"))
158             {
159                 if(tag.lastStart == null)
160                 {
161                     error("empty-tag","SEQ");
162                     return;
163                 }
164
165                 rules.addRule(ParserRule.createSequenceRule(
166                     tag.lastStartPosMatch,tag.lastStart.toString(),
167                     tag.lastDelegateSet,tag.lastTokenID));
168             } //}}}
169
//{{{ SEQ_REGEXP
170
else if (tag.tagName.equals("SEQ_REGEXP"))
171             {
172                 if(tag.lastStart == null)
173                 {
174                     error("empty-tag","SEQ_REGEXP");
175                     return;
176                 }
177
178                 try
179                 {
180                     if (null != tag.lastHashChars)
181                     {
182                         rules.addRule(ParserRule.createRegexpSequenceRule(
183                             tag.lastStartPosMatch,tag.lastHashChars.toCharArray(),
184                             tag.lastStart.toString(),tag.lastDelegateSet,
185                             tag.lastTokenID,findParent("RULES").lastIgnoreCase));
186                     }
187                     else
188                     {
189                         rules.addRule(ParserRule.createRegexpSequenceRule(
190                             tag.lastHashChar,tag.lastStartPosMatch,
191                             tag.lastStart.toString(),tag.lastDelegateSet,
192                             tag.lastTokenID,findParent("RULES").lastIgnoreCase));
193                     }
194                 }
195                 catch(PatternSyntaxException JavaDoc re)
196                 {
197                     error("regexp",re);
198                 }
199             } //}}}
200
//{{{ SPAN
201
else if (tag.tagName.equals("SPAN"))
202             {
203                 if(tag.lastStart == null)
204                 {
205                     error("empty-tag","BEGIN");
206                     return;
207                 }
208
209                 if(tag.lastEnd == null)
210                 {
211                     error("empty-tag","END");
212                     return;
213                 }
214
215                 rules.addRule(ParserRule
216                     .createSpanRule(
217                     tag.lastStartPosMatch,tag.lastStart.toString(),
218                     tag.lastEndPosMatch,tag.lastEnd.toString(),
219                     tag.lastDelegateSet,
220                     tag.lastTokenID,tag.lastExcludeMatch,
221                     tag.lastNoLineBreak,
222                     tag.lastNoWordBreak,
223                     tag.lastNoEscape));
224             } //}}}
225
//{{{ SPAN_REGEXP
226
else if (tag.tagName.equals("SPAN_REGEXP"))
227             {
228                 if(tag.lastStart == null)
229                 {
230                     error("empty-tag","BEGIN");
231                     return;
232                 }
233
234                 if(tag.lastEnd == null)
235                 {
236                     error("empty-tag","END");
237                     return;
238                 }
239
240                 try
241                 {
242                     if (null != tag.lastHashChars)
243                     {
244                         rules.addRule(ParserRule
245                             .createRegexpSpanRule(
246                             tag.lastStartPosMatch,tag.lastHashChars.toCharArray(),
247                             tag.lastStart.toString(),
248                             tag.lastEndPosMatch,tag.lastEnd.toString(),
249                             tag.lastDelegateSet,
250                             tag.lastTokenID,
251                             tag.lastExcludeMatch,
252                             tag.lastNoLineBreak,
253                             tag.lastNoWordBreak,
254                             findParent("RULES").lastIgnoreCase,
255                             tag.lastNoEscape));
256                     }
257                     else
258                     {
259                         rules.addRule(ParserRule
260                             .createRegexpSpanRule(
261                             tag.lastHashChar,
262                             tag.lastStartPosMatch,tag.lastStart.toString(),
263                             tag.lastEndPosMatch,tag.lastEnd.toString(),
264                             tag.lastDelegateSet,
265                             tag.lastTokenID,
266                             tag.lastExcludeMatch,
267                             tag.lastNoLineBreak,
268                             tag.lastNoWordBreak,
269                             findParent("RULES").lastIgnoreCase,
270                             tag.lastNoEscape));
271                     }
272                 }
273                 catch(PatternSyntaxException JavaDoc re)
274                 {
275                     error("regexp",re);
276                 }
277             } //}}}
278
//{{{ EOL_SPAN
279
else if (tag.tagName.equals("EOL_SPAN"))
280             {
281                 if(tag.lastStart == null)
282                 {
283                     error("empty-tag","EOL_SPAN");
284                     return;
285                 }
286
287                 rules.addRule(ParserRule.createEOLSpanRule(
288                     tag.lastStartPosMatch,tag.lastStart.toString(),
289                     tag.lastDelegateSet,tag.lastTokenID,
290                     tag.lastExcludeMatch));
291             } //}}}
292
//{{{ EOL_SPAN_REGEXP
293
else if (tag.tagName.equals("EOL_SPAN_REGEXP"))
294             {
295                 if(tag.lastStart == null)
296                 {
297                     error("empty-tag","EOL_SPAN_REGEXP");
298                     return;
299                 }
300
301                 try
302                 {
303                     if (null != tag.lastHashChars)
304                     {
305                         rules.addRule(ParserRule.createRegexpEOLSpanRule(
306                             tag.lastStartPosMatch,tag.lastHashChars.toCharArray(),
307                             tag.lastStart.toString(),tag.lastDelegateSet,
308                             tag.lastTokenID,tag.lastExcludeMatch,
309                             findParent("RULES").lastIgnoreCase));
310                     }
311                     else
312                     {
313                         rules.addRule(ParserRule.createRegexpEOLSpanRule(
314                             tag.lastHashChar,tag.lastStartPosMatch,
315                             tag.lastStart.toString(),tag.lastDelegateSet,
316                             tag.lastTokenID,tag.lastExcludeMatch,
317                             findParent("RULES").lastIgnoreCase));
318                     }
319                 }
320                 catch(PatternSyntaxException JavaDoc re)
321                 {
322                     error("regexp",re);
323                 }
324             } //}}}
325
//{{{ MARK_FOLLOWING
326
else if (tag.tagName.equals("MARK_FOLLOWING"))
327             {
328                 if(tag.lastStart == null)
329                 {
330                     error("empty-tag","MARK_FOLLOWING");
331                     return;
332                 }
333
334                 rules.addRule(ParserRule
335                     .createMarkFollowingRule(
336                     tag.lastStartPosMatch,tag.lastStart.toString(),
337                     tag.lastTokenID,tag.lastExcludeMatch));
338             } //}}}
339
//{{{ MARK_PREVIOUS
340
else if (tag.tagName.equals("MARK_PREVIOUS"))
341             {
342                 if(tag.lastStart == null)
343                 {
344                     error("empty-tag","MARK_PREVIOUS");
345                     return;
346                 }
347
348                 rules.addRule(ParserRule
349                     .createMarkPreviousRule(
350                     tag.lastStartPosMatch,tag.lastStart.toString(),
351                     tag.lastTokenID,tag.lastExcludeMatch));
352             } //}}}
353
//{{{ Keywords
354
else if (
355                 !tag.tagName.equals("END")
356                 && !tag.tagName.equals("BEGIN")
357                 && !tag.tagName.equals("KEYWORDS")
358                 && !tag.tagName.equals("MODE")
359             ) {
360                 byte token = Token.stringToToken(tag.tagName);
361                 if(token != -1)
362                     addKeyword(tag.lastKeyword.toString(),token);
363             } //}}}
364
}
365         else
366         {
367             // can't happen
368
throw new InternalError JavaDoc();
369         }
370     } //}}}
371

372     //{{{ startDocument() method
373
public void startDocument()
374     {
375         props = new Hashtable<String JavaDoc, String JavaDoc>();
376         pushElement(null, null);
377     } //}}}
378

379     //{{{ endDocument() method
380
public void endDocument()
381     {
382         ParserRuleSet[] rulesets = marker.getRuleSets();
383         for(int i = 0; i < rulesets.length; i++)
384         {
385             rulesets[i].resolveImports();
386         }
387     } //}}}
388

389     //{{{ getTokenMarker() method
390
/**
391      * Returns the TokenMarker.
392      *
393      * @return a TokenMarker it cannot be null
394      */

395     public TokenMarker getTokenMarker()
396     {
397         return marker;
398     } //}}}
399

400     //{{{ getModeProperties() method
401
public Hashtable<String JavaDoc, String JavaDoc> getModeProperties()
402     {
403         return modeProps;
404     } //}}}
405

406     //{{{ Protected members
407

408     //{{{ error() method
409
/**
410      * Reports an error.
411      * You must override this method so that the mode loader can do error
412      * reporting.
413      * @param msg The error type
414      * @param subst A <code>String</code> or a <code>Throwable</code>
415      * containing specific information
416      * @since jEdit 4.2pre1
417      */

418     protected abstract void error(String JavaDoc msg, Object JavaDoc subst);
419     //}}}
420

421     //{{{ getTokenMarker() method
422
/**
423      * Returns the token marker for the given mode.
424      * You must override this method so that the mode loader can resolve
425      * delegate targets.
426      * @param mode The mode name
427      * @since jEdit 4.2pre1
428      */

429     protected abstract TokenMarker getTokenMarker(String JavaDoc mode);
430     //}}}
431

432     //}}}
433

434     //{{{ Private members
435

436     //{{{ Instance variables
437
private String JavaDoc modeName;
438     /** The token marker cannot be null. */
439     private final TokenMarker marker;
440     private KeywordMap keywords;
441     /** this stack can contains null elements. */
442     private Stack<TagDecl> stateStack;
443     private String JavaDoc propName;
444     private String JavaDoc propValue;
445     private Hashtable<String JavaDoc, String JavaDoc> props;
446     private Hashtable<String JavaDoc, String JavaDoc> modeProps;
447     private ParserRuleSet rules;
448     //}}}
449

450     //{{{ addKeyword() method
451
private void addKeyword(String JavaDoc k, byte id)
452     {
453         if(k == null)
454         {
455             error("empty-keyword",null);
456             return;
457         }
458
459         if (keywords == null) return;
460         keywords.add(k,id);
461     } //}}}
462

463     //{{{ pushElement() method
464
private TagDecl pushElement(String JavaDoc name, Attributes JavaDoc attrs)
465     {
466         if (name != null)
467         {
468             TagDecl tag = new TagDecl(name, attrs);
469             stateStack.push(tag);
470             return tag;
471         }
472         else
473         {
474             stateStack.push(null);
475             return null;
476         }
477     } //}}}
478

479     //{{{ peekElement() method
480
private TagDecl peekElement()
481     {
482         return stateStack.peek();
483     } //}}}
484

485     //{{{ popElement() method
486
private TagDecl popElement()
487     {
488         return stateStack.pop();
489     } //}}}
490

491     //{{{ findParent() method
492
/**
493      * Finds the first element whose tag matches 'tagName',
494      * searching backwards in the stack.
495      */

496     private TagDecl findParent(String JavaDoc tagName)
497     {
498         for (int idx = stateStack.size() - 1; idx >= 0; idx--)
499         {
500             TagDecl tag = stateStack.get(idx);
501             if (tag.tagName.equals(tagName))
502                 return tag;
503         }
504         return null;
505     } //}}}
506

507     //}}}
508

509     /**
510      * Hold info about what tag was read and what attributes were
511      * set in the XML file, to be kept by the handler in a stack
512      * (similar to the way tag names were kept in a stack before).
513      */

514     private class TagDecl
515     {
516
517         public TagDecl(String JavaDoc tagName, Attributes JavaDoc attrs)
518         {
519             this.tagName = tagName;
520
521             String JavaDoc tmp;
522
523             propName = attrs.getValue("NAME");
524             propValue = attrs.getValue("VALUE");
525
526             tmp = attrs.getValue("TYPE");
527             if (tmp != null)
528             {
529                 lastTokenID = Token.stringToToken(tmp);
530                 if(lastTokenID == -1)
531                     error("token-invalid",tmp);
532             }
533
534             lastAtLineStart = "TRUE".equals(attrs.getValue("AT_LINE_START"));
535             lastAtWhitespaceEnd = "TRUE".equals(attrs.getValue("AT_WHITESPACE_END"));
536             lastAtWordStart = "TRUE".equals(attrs.getValue("AT_WORD_START"));
537             lastNoLineBreak = "TRUE".equals(attrs.getValue("NO_LINE_BREAK"));
538             lastNoWordBreak = "TRUE".equals(attrs.getValue("NO_WORD_BREAK"));
539             lastNoEscape = "TRUE".equals(attrs.getValue("NO_ESCAPE"));
540             lastExcludeMatch = "TRUE".equals(attrs.getValue("EXCLUDE_MATCH"));
541             lastIgnoreCase = (attrs.getValue("IGNORE_CASE") == null ||
542                     "TRUE".equals(attrs.getValue("IGNORE_CASE")));
543             lastHighlightDigits = "TRUE".equals(attrs.getValue("HIGHLIGHT_DIGITS"));;
544             lastDigitRE = attrs.getValue("DIGIT_RE");
545
546             tmp = attrs.getValue("NO_WORD_SEP");
547             if (tmp != null)
548                 lastNoWordSep = tmp;
549
550             tmp = attrs.getValue("AT_CHAR");
551             if (tmp != null)
552             {
553                 try
554                 {
555                     termChar = Integer.parseInt(tmp);
556                 }
557                 catch (NumberFormatException JavaDoc e)
558                 {
559                     error("termchar-invalid",tmp);
560                     termChar = -1;
561                 }
562             }
563
564             lastEscape = attrs.getValue("ESCAPE");
565             lastSetName = attrs.getValue("SET");
566
567             tmp = attrs.getValue("DELEGATE");
568             if (tmp != null)
569             {
570                 String JavaDoc delegateMode, delegateSetName;
571
572                 int index = tmp.indexOf("::");
573
574                 if(index != -1)
575                 {
576                     delegateMode = tmp.substring(0,index);
577                     delegateSetName = tmp.substring(index + 2);
578                 }
579                 else
580                 {
581                     delegateMode = modeName;
582                     delegateSetName = tmp;
583                 }
584
585                 TokenMarker delegateMarker = getTokenMarker(delegateMode);
586                 if(delegateMarker == null)
587                     error("delegate-invalid",tmp);
588                 else
589                 {
590                     lastDelegateSet = delegateMarker
591                         .getRuleSet(delegateSetName);
592                     if(delegateMarker == marker
593                         && lastDelegateSet == null)
594                     {
595                         // stupid hack to handle referencing
596
// a rule set that is defined later!
597
lastDelegateSet = new ParserRuleSet(
598                             delegateMode,
599                             delegateSetName);
600                         lastDelegateSet.setDefault(Token.INVALID);
601                         marker.addRuleSet(lastDelegateSet);
602                     }
603                     else if(lastDelegateSet == null)
604                         error("delegate-invalid",tmp);
605                 }
606             }
607
608             tmp = attrs.getValue("DEFAULT");
609             if (tmp != null)
610             {
611                 lastDefaultID = Token.stringToToken(tmp);
612                 if(lastDefaultID == -1)
613                 {
614                     error("token-invalid",tmp);
615                     lastDefaultID = Token.NULL;
616                 }
617             }
618
619             lastHashChar = attrs.getValue("HASH_CHAR");
620             lastHashChars = attrs.getValue("HASH_CHARS");
621             if ((null != lastHashChar) && (null != lastHashChars))
622             {
623                 error("hash-char-and-hash-chars-mutually-exclusive",null);
624                 lastHashChars = null;
625             }
626         }
627
628         public void setText(char[] c, int off, int len)
629         {
630             if (tagName.equals("EOL_SPAN") ||
631                 tagName.equals("EOL_SPAN_REGEXP") ||
632                 tagName.equals("MARK_PREVIOUS") ||
633                 tagName.equals("MARK_FOLLOWING") ||
634                 tagName.equals("SEQ") ||
635                 tagName.equals("SEQ_REGEXP") ||
636                 tagName.equals("BEGIN")
637             )
638             {
639                 TagDecl target = this;
640                 if (tagName.equals("BEGIN"))
641                     target = stateStack.get(stateStack.size() - 2);
642
643                 if (target.lastStart == null)
644                 {
645                     target.lastStart = new StringBuffer JavaDoc();
646                     target.lastStart.append(c, off, len);
647                     target.lastStartPosMatch = ((target.lastAtLineStart ? ParserRule.AT_LINE_START : 0)
648                         | (target.lastAtWhitespaceEnd ? ParserRule.AT_WHITESPACE_END : 0)
649                         | (target.lastAtWordStart ? ParserRule.AT_WORD_START : 0));
650                     target.lastAtLineStart = false;
651                     target.lastAtWordStart = false;
652                     target.lastAtWhitespaceEnd = false;
653                 }
654                 else
655                 {
656                     target.lastStart.append(c, off, len);
657                 }
658             }
659             else if (tagName.equals("END"))
660             {
661                 TagDecl target = stateStack.get(stateStack.size() - 2);
662                 if (target.lastEnd == null)
663                 {
664                     target.lastEnd = new StringBuffer JavaDoc();
665                     target.lastEnd.append(c, off, len);
666                     target.lastEndPosMatch = ((target.lastAtLineStart ? ParserRule.AT_LINE_START : 0)
667                         | (target.lastAtWhitespaceEnd ? ParserRule.AT_WHITESPACE_END : 0)
668                         | (target.lastAtWordStart ? ParserRule.AT_WORD_START : 0));
669                     target.lastAtLineStart = false;
670                     target.lastAtWordStart = false;
671                     target.lastAtWhitespaceEnd = false;
672                 }
673                 else
674                 {
675                     target.lastEnd.append(c, off, len);
676                 }
677             }
678             else
679             {
680                 if (lastKeyword == null)
681                     lastKeyword = new StringBuffer JavaDoc();
682                 lastKeyword.append(c, off, len);
683             }
684         }
685
686         public String JavaDoc tagName;
687         public StringBuffer JavaDoc lastStart;
688         public StringBuffer JavaDoc lastEnd;
689         public StringBuffer JavaDoc lastKeyword;
690         public String JavaDoc lastSetName;
691         public String JavaDoc lastEscape;
692         public ParserRuleSet lastDelegateSet;
693         public String JavaDoc lastNoWordSep = "_";
694         public ParserRuleSet rules;
695         public byte lastDefaultID = Token.NULL;
696         public byte lastTokenID;
697         public int termChar = -1;
698         public boolean lastNoLineBreak;
699         public boolean lastNoWordBreak;
700         public boolean lastExcludeMatch;
701         public boolean lastIgnoreCase = true;
702         public boolean lastHighlightDigits;
703         public boolean lastAtLineStart;
704         public boolean lastAtWhitespaceEnd;
705         public boolean lastAtWordStart;
706         public boolean lastNoEscape;
707         public int lastStartPosMatch;
708         public int lastEndPosMatch;
709         public String JavaDoc lastDigitRE;
710         public String JavaDoc lastHashChar;
711         public String JavaDoc lastHashChars;
712     }
713 }
714
Popular Tags