001: /*
002: * ParserRuleSet.java - A set of parser rules
003: * :tabSize=8:indentSize=8:noTabs=false:
004: * :folding=explicit:collapseFolds=1:
005: *
006: * Copyright (C) 1999 mike dillon
007: * Portions copyright (C) 2001, 2002 Slava Pestov
008: *
009: * This program is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU General Public License
011: * as published by the Free Software Foundation; either version 2
012: * of the License, or any later version.
013: *
014: * This program is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
017: * GNU General Public License for more details.
018: *
019: * You should have received a copy of the GNU General Public License
020: * along with this program; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
022: */
023:
024: package org.gjt.sp.jedit.syntax;
025:
026: //{{{ Imports
027: import java.util.*;
028: import java.util.regex.Pattern;
029:
030: //}}}
031:
032: /**
033: * A set of parser rules.
034: * @author mike dillon
035: * @version $Id: ParserRuleSet.java 11079 2007-11-16 03:20:00Z vanza $
036: */
037: public class ParserRuleSet {
038: //{{{ getStandardRuleSet() method
039: /**
040: * Returns a parser rule set that highlights everything with the
041: * specified token type.
042: * @param id The token type
043: */
044: public static ParserRuleSet getStandardRuleSet(byte id) {
045: return standard[id];
046: } //}}}
047:
048: //{{{ ParserRuleSet constructor
049: public ParserRuleSet(String modeName, String setName) {
050: this .modeName = modeName;
051: this .setName = setName;
052: ruleMap = new HashMap<Character, List<ParserRule>>();
053: imports = new ArrayList<ParserRuleSet>();
054: } //}}}
055:
056: //{{{ getModeName() method
057: public String getModeName() {
058: return modeName;
059: } //}}}
060:
061: //{{{ getSetName() method
062: public String getSetName() {
063: return setName;
064: } //}}}
065:
066: //{{{ getName() method
067: public String getName() {
068: return modeName + "::" + setName;
069: } //}}}
070:
071: //{{{ getProperties() method
072: public Hashtable<String, String> getProperties() {
073: return props;
074: } //}}}
075:
076: //{{{ setProperties() method
077: public void setProperties(Hashtable<String, String> props) {
078: this .props = props;
079: _noWordSep = null;
080: } //}}}
081:
082: //{{{ resolveImports() method
083: /**
084: * Resolves all rulesets added with {@link #addRuleSet(ParserRuleSet)}.
085: * @since jEdit 4.2pre3
086: */
087: public void resolveImports() {
088: for (ParserRuleSet ruleset : imports) {
089: if (!ruleset.imports.isEmpty()) {
090: //prevent infinite recursion
091: ruleset.imports.remove(this );
092: ruleset.resolveImports();
093: }
094:
095: for (List<ParserRule> rules : ruleset.ruleMap.values()) {
096: for (ParserRule rule : rules) {
097: addRule(rule);
098: }
099: }
100:
101: if (ruleset.keywords != null) {
102: if (keywords == null)
103: keywords = new KeywordMap(ignoreCase);
104: keywords.add(ruleset.keywords);
105: }
106: }
107: imports.clear();
108: } //}}}
109:
110: //{{{ addRuleSet() method
111: /**
112: * Adds all rules contained in the given ruleset.
113: * @param ruleset The ruleset
114: * @since jEdit 4.2pre3
115: */
116: public void addRuleSet(ParserRuleSet ruleset) {
117: imports.add(ruleset);
118: } //}}}
119:
120: //{{{ addRule() method
121: public void addRule(ParserRule r) {
122: ruleCount++;
123: Character[] keys;
124: if (null == r.upHashChars) {
125: keys = new Character[1];
126: if ((null == r.upHashChar) || (0 >= r.upHashChar.length())) {
127: keys[0] = null;
128: } else {
129: keys[0] = Character.valueOf(r.upHashChar.charAt(0));
130: }
131: } else {
132: keys = new Character[r.upHashChars.length];
133: int i = 0;
134: for (char upHashChar : r.upHashChars) {
135: keys[i++] = upHashChar;
136: }
137: }
138: for (Character key : keys) {
139: List<ParserRule> rules = ruleMap.get(key);
140: if (null == rules) {
141: rules = new ArrayList<ParserRule>();
142: ruleMap.put(key, rules);
143: }
144: int ruleAmount = rules.size();
145: rules.add(r);
146: // fill the deprecated ParserRule.next pointer
147: if (ruleAmount > 0) {
148: rules.get(ruleAmount).next = r;
149: }
150: }
151: } //}}}
152:
153: //{{{ getRules() method
154: /**
155: * @deprecated As the linking between rules is not anymore done within the rule, use {@link #getRules(Character)} instead
156: */
157: public ParserRule getRules(char ch) {
158: List<ParserRule> rules = getRules(Character.valueOf(ch));
159: return rules.get(0);
160: } //}}}
161:
162: //{{{ getRules() method
163: public List<ParserRule> getRules(Character key) {
164: Character upperKey = null == key ? null : Character
165: .valueOf(Character.toUpperCase(key.charValue()));
166: List<ParserRule> rules = ruleMap.get(upperKey);
167: if (null == rules) {
168: rules = new ArrayList<ParserRule>();
169: } else {
170: rules = new ArrayList<ParserRule>(rules);
171: }
172: if (null != upperKey) {
173: List<ParserRule> nullRules = ruleMap.get(null);
174: if (null != nullRules) {
175: int rulesSize = rules.size();
176: if ((0 < rulesSize) && (0 < nullRules.size())) {
177: rules.get(rulesSize - 1).next = nullRules.get(0);
178: }
179: rules.addAll(nullRules);
180: }
181: }
182: return rules;
183: } //}}}
184:
185: //{{{ getRuleCount() method
186: public int getRuleCount() {
187: return ruleCount;
188: } //}}}
189:
190: //{{{ getTerminateChar() method
191: /**
192: * Returns the number of chars that can be read before the rule parsing stops.
193: *
194: * @return a number of chars or -1 (default value) if there is no limit
195: */
196: public int getTerminateChar() {
197: return terminateChar;
198: } //}}}
199:
200: //{{{ setTerminateChar() method
201: public void setTerminateChar(int atChar) {
202: terminateChar = (atChar >= 0) ? atChar : -1;
203: } //}}}
204:
205: //{{{ getIgnoreCase() method
206: public boolean getIgnoreCase() {
207: return ignoreCase;
208: } //}}}
209:
210: //{{{ setIgnoreCase() method
211: public void setIgnoreCase(boolean b) {
212: ignoreCase = b;
213: } //}}}
214:
215: //{{{ getKeywords() method
216: public KeywordMap getKeywords() {
217: return keywords;
218: } //}}}
219:
220: //{{{ setKeywords() method
221: public void setKeywords(KeywordMap km) {
222: keywords = km;
223: _noWordSep = null;
224: } //}}}
225:
226: //{{{ getHighlightDigits() method
227: public boolean getHighlightDigits() {
228: return highlightDigits;
229: } //}}}
230:
231: //{{{ setHighlightDigits() method
232: public void setHighlightDigits(boolean highlightDigits) {
233: this .highlightDigits = highlightDigits;
234: } //}}}
235:
236: //{{{ getDigitRegexp() method
237: public Pattern getDigitRegexp() {
238: return digitRE;
239: } //}}}
240:
241: //{{{ setDigitRegexp() method
242: public void setDigitRegexp(Pattern digitRE) {
243: this .digitRE = digitRE;
244: } //}}}
245:
246: //{{{ getEscapeRule() method
247: public ParserRule getEscapeRule() {
248: return escapeRule;
249: } //}}}
250:
251: //{{{ setEscapeRule() method
252: public void setEscapeRule(ParserRule escapeRule) {
253: this .escapeRule = escapeRule;
254: } //}}}
255:
256: //{{{ getDefault() method
257: public byte getDefault() {
258: return defaultToken;
259: } //}}}
260:
261: //{{{ setDefault() method
262: public void setDefault(byte def) {
263: defaultToken = def;
264: } //}}}
265:
266: //{{{ getNoWordSep() method
267: public String getNoWordSep() {
268: if (_noWordSep == null) {
269: _noWordSep = noWordSep;
270: if (noWordSep == null)
271: noWordSep = "";
272: if (keywords != null)
273: noWordSep += keywords.getNonAlphaNumericChars();
274: }
275: return noWordSep;
276: } //}}}
277:
278: //{{{ setNoWordSep() method
279: public void setNoWordSep(String noWordSep) {
280: this .noWordSep = noWordSep;
281: _noWordSep = null;
282: } //}}}
283:
284: //{{{ isBuiltIn() method
285: /**
286: * Returns if this is a built-in ruleset.
287: * @since jEdit 4.2pre1
288: */
289: public boolean isBuiltIn() {
290: return builtIn;
291: } //}}}
292:
293: //{{{ toString() method
294: public String toString() {
295: return getClass().getName() + '[' + modeName + "::" + setName
296: + ']';
297: } //}}}
298:
299: //{{{ Private members
300: private static ParserRuleSet[] standard;
301:
302: static {
303: standard = new ParserRuleSet[Token.ID_COUNT];
304: for (byte i = 0; i < Token.ID_COUNT; i++) {
305: standard[i] = new ParserRuleSet(null, null);
306: standard[i].setDefault(i);
307: standard[i].builtIn = true;
308: }
309: }
310:
311: private String modeName, setName;
312: private Hashtable<String, String> props;
313:
314: private KeywordMap keywords;
315:
316: private int ruleCount;
317:
318: private Map<Character, List<ParserRule>> ruleMap;
319:
320: private final List<ParserRuleSet> imports;
321:
322: /**
323: * The number of chars that can be read before the parsing stops.
324: * <TERMINATE AT_CHAR="1" />
325: */
326: private int terminateChar = -1;
327: private boolean ignoreCase = true;
328: private byte defaultToken;
329: private ParserRule escapeRule;
330:
331: private boolean highlightDigits;
332: private Pattern digitRE;
333:
334: private String _noWordSep;
335: private String noWordSep;
336:
337: private boolean builtIn;
338: //}}}
339: }
|