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