PageRenderTime 157ms CodeModel.GetById 103ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 1ms

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