Java tutorial
/* * cbg.editor Eclipse plugin * Copyright(c) 2002, Chris Grindstaff * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package com.rohanclan.afae.modes; import java.io.IOException; import java.util.Iterator; import java.util.List; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import com.rohanclan.afae.AfaePlugin; import com.rohanclan.afae.editor.AfaeEditorTools; import com.rohanclan.afae.partition.AfaePartitionScanner; /** * Reads a mode file and does call backs to the SyntaxListener to create the * needed parts of the mode file * * @author robrohan */ public class ModeReader implements IModeConstants { /** The listener used to build up the rules */ protected ISyntaxListener listener; /** * * @param listener */ public ModeReader(ISyntaxListener listener) { super(); this.listener = listener; } /** * Read in a mode file by filename * * @param filename */ @SuppressWarnings("unchecked") public void read(String filename) { SAXReader reader = new SAXReader(); Document doc = null; try { doc = reader.read(AfaeEditorTools.getFile(filename)); } catch (DocumentException e) { AfaePlugin.logError("read() on file " + filename, e, ModeReader.class); e.printStackTrace(); return; } catch (IOException ioe) { AfaePlugin.logError("read() on file " + filename, ioe, ModeReader.class); ioe.printStackTrace(); } Element root = doc.getRootElement(); // parse the properties (if they exist) if (root.element(TAG_PROPS) != null) { for (Iterator<Element> z = root.element(TAG_PROPS).elements(TAG_PROPERTY).iterator(); z.hasNext();) { Element singleprop = (Element) z.next(); String name = singleprop.attributeValue(ATTR_NAME, ""); String value = singleprop.attributeValue(ATTR_VALUE); // if we get the start and end comments set them into the mode if (name.equals(ATTR_VALUE_START_COMMENT)) { listener.setStartComment(value); } else if (name.equals(ATTR_VALUE_STOP_COMMENT)) { listener.setEndComment(value); } //Should we add the properties we don't understand? } } // Loop over all the rule in the mode file for (Iterator<Element> iter = root.elementIterator(TAG_RULES); iter.hasNext();) { Element rulesElement = (Element) iter.next(); createRule(rulesElement); /* * Because order of rules is important we must read the elements in * order instead of using elementIterators("SPAN", etc) */ List<Element> allTypes = rulesElement.elements(); for (Iterator<Element> allTypesI = allTypes.iterator(); allTypesI.hasNext();) { Element element = (Element) allTypesI.next(); // does a bit switch... createType(element); } } } /** * RULEs are handled else where this handles all the items inside a rule * (SPANS, KEYWORDS, etc) * * @param element * the DOM element to parse */ private void createType(Element element) { if (element.getName().equals(TAG_SPAN)) { createSpan(element); } else if (element.getName().equals(TAG_EOL_SPAN)) { createEOL(element); } else if (element.getName().equals(TAG_SPAN_REGEXP)) { createRegexpSpan(element); } else if (element.getName().equals(TAG_SEQ)) { createTextSequence(element); } else if (element.getName().equals(TAG_KEYWORDS)) { createKeywords(element); } else if (element.getName().equals(TAG_MARK_PREVIOUS)) { createMark(element, true); } else if (element.getName().equals(TAG_MARK_FOLLOWING)) { createMark(element, false); } else if (element.getName().equals(TAG_WHITESPACE)) { // ignore for now } else { AfaePlugin.logWarn("Ignore unknown element " + element.getName(), null, ModeReader.class); } } /** * Create a keyword Map with AfaePartitionScanner.[CONSTANT] as the key and * an array of strings as the value (see toStringArray) * * @param keywordsE */ @SuppressWarnings("unchecked") private void createKeywords(Element keywordsE) { KeywordMap keywords = new KeywordMap(bool(keywordsE, "IGNORE_CASE", true)); keywords.setAtLineStart(bool(keywordsE, "AT_LINE_START", false)); // ok this is kind of odd... in the keyword map using the // PartitionScanner // constants add a String[] of keywords for the child elements of // <KEYWORD> // from teh mode file keywords.put(KEYWORD1, toStringArray(keywordsE.elements(KEYWORD1))); keywords.put(KEYWORD2, toStringArray(keywordsE.elements(KEYWORD2))); keywords.put(KEYWORD3, toStringArray(keywordsE.elements(KEYWORD3))); keywords.put(COMMENT1, toStringArray(keywordsE.elements(COMMENT1))); keywords.put(COMMENT2, toStringArray(keywordsE.elements(COMMENT2))); keywords.put(LITERAL1, toStringArray(keywordsE.elements(LITERAL1))); keywords.put(LITERAL2, toStringArray(keywordsE.elements(LITERAL2))); keywords.put(LABEL, toStringArray(keywordsE.elements(LABEL))); keywords.put(FUNCTION, toStringArray(keywordsE.elements(FUNCTION))); keywords.put(MARKUP, toStringArray(keywordsE.elements(MARKUP))); keywords.put(OPERATOR, toStringArray(keywordsE.elements(OPERATOR))); keywords.put(DIGIT, toStringArray(keywordsE.elements(DIGIT))); keywords.put(INVALID, toStringArray(keywordsE.elements(INVALID))); listener.newKeywords(keywords); } /** * Turns a list of keyword elements into a string array for use in the * KeywordMap So, for example: * * <pre> * <KEYWORD1>CDATA</KEYWORD1> * ... * <KEYWORD1>EMPTY</KEYWORD1> * </pre> * * becomes * * <pre> * String[]{ CDATA ,..., EMPTY } * </pre> * * @param list * a list of DOM elements of * @return */ private String[] toStringArray(List<Element> list) { if (list.isEmpty()) return new String[0]; String[] strings = new String[list.size()]; int i = 0; for (Iterator<Element> iter = list.iterator(); iter.hasNext();) { strings[i] = ((Element) iter.next()).getText(); i++; } return strings; } /** * Invokes the listeners newTextSequence to add a new text sequence * * element from the mode file * * @param seqElement */ private void createTextSequence(Element seqElement) { boolean atLineStart = bool(seqElement, "AT_LINE_START", false); boolean atWhitespaceEnd = bool(seqElement, "AT_WHITESPACE_END", false); boolean atWordStart = bool(seqElement, "AT_WORD_START", false); String type = seqElement.attributeValue("TYPE"); String delegate = seqElement.attributeValue("DELEGATE"); listener.newTextSequence(type, seqElement.getText(), atLineStart, atWhitespaceEnd, atWordStart, delegate); } /** * Invokes the listeners newEOLSpan * * @param eolElement */ private void createEOL(Element eolElement) { String type = eolElement.attributeValue("TYPE"); boolean atLineStart = bool(eolElement, "AT_LINE_START", false); boolean excludeMatch = bool(eolElement, "EXCLUDE_MATCH", false); boolean noLineBreak = bool(eolElement, "NO_LINE_BREAK", false); boolean noWordBreak = bool(eolElement, "NO_WORD_BREAK", false); boolean ignoreCase = bool(eolElement, "IGNORE_CASE", false); String delegate = eolElement.attributeValue("DELEGATE"); String escape = eolElement.attributeValue("ESCAPE"); //listener.newEOLSpan(type, eolElement.getText(), atLineStart); listener.newEOLSpan(type, eolElement.getText(), atLineStart, excludeMatch, noLineBreak, noWordBreak, ignoreCase, delegate, escape); } /** * Invokes the listeners newSpan * * @param spanElement */ private void createSpan(Element spanElement) { String type = spanElement.attributeValue("TYPE"); boolean atLineStart = bool(spanElement, "AT_LINE_START", false); boolean excludeMatch = bool(spanElement, "EXCLUDE_MATCH", false); boolean noLineBreak = bool(spanElement, "NO_LINE_BREAK", false); boolean noWordBreak = bool(spanElement, "NO_WORD_BREAK", false); boolean ignoreCase = bool(spanElement, "IGNORE_CASE", false); String delegate = spanElement.attributeValue("DELEGATE"); String escape = spanElement.attributeValue("ESCAPE"); String begin = spanElement.element("BEGIN").getText(); String end = spanElement.element("END").getText(); listener.newSpan(type, begin, end, atLineStart, excludeMatch, noLineBreak, noWordBreak, ignoreCase, delegate, escape); } private void createRegexpSpan(Element spanElement) { String type = spanElement.attributeValue("TYPE"); //HASH_CHAR must be there String hash_chars = spanElement.attributeValue("HASH_CHAR"); boolean atLineStart = bool(spanElement, "AT_LINE_START", false); boolean excludeMatch = bool(spanElement, "EXCLUDE_MATCH", false); boolean noLineBreak = bool(spanElement, "NO_LINE_BREAK", false); boolean noWordBreak = bool(spanElement, "NO_WORD_BREAK", false); boolean ignoreCase = bool(spanElement, "IGNORE_CASE", false); String delegate = spanElement.attributeValue("DELEGATE"); String escape = spanElement.attributeValue("ESCAPE"); String begin = spanElement.element("BEGIN").getText(); String end = spanElement.element("END").getText(); listener.newSpanRegexp(type, begin, end, hash_chars, atLineStart, excludeMatch, noLineBreak, noWordBreak, ignoreCase, delegate, escape); } /** * Invokes the listeners newMark * * @param markElement * @param isPrevious */ private void createMark(Element markElement, boolean isPrevious) { boolean atLineStart = bool(markElement, "AT_LINE_START", false); boolean atWhitespaceEnd = bool(markElement, "AT_WHITESPACE_END", false); boolean excludeMatch = bool(markElement, "EXCLUDE_MATCH", false); boolean atWordStart = bool(markElement, "AT_WORD_START", false); String type = markElement.attributeValue("TYPE"); String delegate = markElement.attributeValue("DELEGATE"); listener.newMark(type, markElement.getText(), atLineStart, atWhitespaceEnd, atWordStart, delegate, isPrevious, excludeMatch); } /** * Invokes the listeners newRules Create a rule from an XML element in the * mode file (DOM) * * @param rulesElement */ protected void createRule(Element rulesElement) { // get the name for this set of rules, and use MAIN if its the main set // of // rules because it may not have an attribtues "SET" String name = rulesElement.attributeValue("SET", Rule.DEFAULT_NAME); // read in the rules configuration and setup defaults if they dont exist boolean highlightDigits = bool(rulesElement, "HIGHLIGHT_DIGITS", false); boolean ignoreCase = bool(rulesElement, "IGNORE_CASE", true); String digitRE = rulesElement.attributeValue("DIGIT_RE"); char escape = rulesElement.attributeValue("ESCAPE", "" + (char) 0).charAt(0); String defaultTokenType = rulesElement.attributeValue("DEFAULT", AfaePartitionScanner.NULL); // create a new rule listener.newRules(name, highlightDigits, ignoreCase, digitRE, escape, defaultTokenType); } /** * Create a java boolean out of a ture/false setting in the mode file * * @param element * @param attributeName * @param defaultValue * @return */ protected boolean bool(Element element, String attributeName, boolean defaultValue) { return Boolean.valueOf(element.attributeValue(attributeName, String.valueOf(defaultValue))).booleanValue(); } }