001: package net.xoetrope.builder.editor.syntaxhighlight;
002:
003: /*
004: * EiffelTokenMarker.java - Eiffel token marker
005: * Copyright (C) 1999 Slava Pestov
006: * Copyright (C) 1999 Artur Biesiadowski
007: *
008: * You may use and modify this package for any purpose. Redistribution is
009: * permitted, in both source and binary form, provided that this notice
010: * remains intact in all source distributions of this package.
011: */
012:
013: import javax.swing.text.Segment;
014:
015: /**
016: * Eiffel token Marker.
017: *
018: * @author Artur Biesiadowski
019: */
020: public class EiffelTokenMarker extends TokenMarker {
021:
022: public EiffelTokenMarker() {
023: this .keywords = getKeywords();
024: }
025:
026: public byte markTokensImpl(byte token, Segment line, int lineIndex) {
027: char[] array = line.array;
028: int offset = line.offset;
029: lastOffset = offset;
030: lastKeyword = offset;
031: int length = line.count + offset;
032: boolean backslash = false;
033:
034: loop: for (int i = offset; i < length; i++) {
035: int i1 = (i + 1);
036:
037: char c = array[i];
038: if (c == '%') {
039: backslash = !backslash;
040: continue;
041: }
042:
043: switch (token) {
044: case Token.NULL:
045: switch (c) {
046: case '"':
047: doKeyword(line, i, c);
048: if (backslash)
049: backslash = false;
050: else {
051: addToken(i - lastOffset, token);
052: token = Token.LITERAL1;
053: lastOffset = lastKeyword = i;
054: }
055: break;
056: case '\'':
057: doKeyword(line, i, c);
058: if (backslash)
059: backslash = false;
060: else {
061: addToken(i - lastOffset, token);
062: token = Token.LITERAL2;
063: lastOffset = lastKeyword = i;
064: }
065: break;
066: case ':':
067: if (lastKeyword == offset) {
068: if (doKeyword(line, i, c))
069: break;
070: backslash = false;
071: addToken(i1 - lastOffset, Token.LABEL);
072: lastOffset = lastKeyword = i1;
073: } else if (doKeyword(line, i, c))
074: break;
075: break;
076: case '-':
077: backslash = false;
078: doKeyword(line, i, c);
079: if (length - i > 1) {
080: switch (array[i1]) {
081: case '-':
082: addToken(i - lastOffset, token);
083: addToken(length - i, Token.COMMENT1);
084: lastOffset = lastKeyword = length;
085: break loop;
086: }
087: }
088: break;
089: default:
090: backslash = false;
091: if (!Character.isLetterOrDigit(c) && c != '_')
092: doKeyword(line, i, c);
093: break;
094: }
095: break;
096: case Token.COMMENT1:
097: case Token.COMMENT2:
098: throw new RuntimeException("Wrong eiffel parser state");
099: case Token.LITERAL1:
100: if (backslash)
101: backslash = false;
102: else if (c == '"') {
103: addToken(i1 - lastOffset, token);
104: token = Token.NULL;
105: lastOffset = lastKeyword = i1;
106: }
107: break;
108: case Token.LITERAL2:
109: if (backslash)
110: backslash = false;
111: else if (c == '\'') {
112: addToken(i1 - lastOffset, Token.LITERAL1);
113: token = Token.NULL;
114: lastOffset = lastKeyword = i1;
115: }
116: break;
117: default:
118: throw new InternalError("Invalid state: " + token);
119: }
120: }
121:
122: if (token == Token.NULL)
123: doKeyword(line, length, '\0');
124:
125: switch (token) {
126: case Token.LITERAL1:
127: case Token.LITERAL2:
128: addToken(length - lastOffset, Token.INVALID);
129: token = Token.NULL;
130: break;
131: case Token.KEYWORD2:
132: addToken(length - lastOffset, token);
133: if (!backslash)
134: token = Token.NULL;
135: default:
136: addToken(length - lastOffset, token);
137: break;
138: }
139:
140: return token;
141: }
142:
143: public static KeywordMap getKeywords() {
144: if (eiffelKeywords == null) {
145: eiffelKeywords = new KeywordMap(true);
146: eiffelKeywords.add("alias", Token.KEYWORD1);
147: eiffelKeywords.add("all", Token.KEYWORD1);
148: eiffelKeywords.add("and", Token.KEYWORD1);
149: eiffelKeywords.add("as", Token.KEYWORD1);
150: eiffelKeywords.add("check", Token.KEYWORD1);
151: eiffelKeywords.add("class", Token.KEYWORD1);
152: eiffelKeywords.add("creation", Token.KEYWORD1);
153: eiffelKeywords.add("debug", Token.KEYWORD1);
154: eiffelKeywords.add("deferred", Token.KEYWORD1);
155: eiffelKeywords.add("do", Token.KEYWORD1);
156: eiffelKeywords.add("else", Token.KEYWORD1);
157: eiffelKeywords.add("elseif", Token.KEYWORD1);
158: eiffelKeywords.add("end", Token.KEYWORD1);
159: eiffelKeywords.add("ensure", Token.KEYWORD1);
160: eiffelKeywords.add("expanded", Token.KEYWORD1);
161: eiffelKeywords.add("export", Token.KEYWORD1);
162: eiffelKeywords.add("external", Token.KEYWORD1);
163: eiffelKeywords.add("feature", Token.KEYWORD1);
164: eiffelKeywords.add("from", Token.KEYWORD1);
165: eiffelKeywords.add("frozen", Token.KEYWORD1);
166: eiffelKeywords.add("if", Token.KEYWORD1);
167: eiffelKeywords.add("implies", Token.KEYWORD1);
168: eiffelKeywords.add("indexing", Token.KEYWORD1);
169: eiffelKeywords.add("infix", Token.KEYWORD1);
170: eiffelKeywords.add("inherit", Token.KEYWORD1);
171: eiffelKeywords.add("inspect", Token.KEYWORD1);
172: eiffelKeywords.add("invariant", Token.KEYWORD1);
173: eiffelKeywords.add("is", Token.KEYWORD1);
174: eiffelKeywords.add("like", Token.KEYWORD1);
175: eiffelKeywords.add("local", Token.KEYWORD1);
176: eiffelKeywords.add("loop", Token.KEYWORD1);
177: eiffelKeywords.add("not", Token.KEYWORD1);
178: eiffelKeywords.add("obsolete", Token.KEYWORD1);
179: eiffelKeywords.add("old", Token.KEYWORD1);
180: eiffelKeywords.add("once", Token.KEYWORD1);
181: eiffelKeywords.add("or", Token.KEYWORD1);
182: eiffelKeywords.add("prefix", Token.KEYWORD1);
183: eiffelKeywords.add("redefine", Token.KEYWORD1);
184: eiffelKeywords.add("rename", Token.KEYWORD1);
185: eiffelKeywords.add("require", Token.KEYWORD1);
186: eiffelKeywords.add("rescue", Token.KEYWORD1);
187: eiffelKeywords.add("retry", Token.KEYWORD1);
188: eiffelKeywords.add("select", Token.KEYWORD1);
189: eiffelKeywords.add("separate", Token.KEYWORD1);
190: eiffelKeywords.add("then", Token.KEYWORD1);
191: eiffelKeywords.add("undefine", Token.KEYWORD1);
192: eiffelKeywords.add("until", Token.KEYWORD1);
193: eiffelKeywords.add("variant", Token.KEYWORD1);
194: eiffelKeywords.add("when", Token.KEYWORD1);
195: eiffelKeywords.add("xor", Token.KEYWORD1);
196:
197: eiffelKeywords.add("current", Token.LITERAL2);
198: eiffelKeywords.add("false", Token.LITERAL2);
199: eiffelKeywords.add("precursor", Token.LITERAL2);
200: eiffelKeywords.add("result", Token.LITERAL2);
201: eiffelKeywords.add("strip", Token.LITERAL2);
202: eiffelKeywords.add("true", Token.LITERAL2);
203: eiffelKeywords.add("unique", Token.LITERAL2);
204: eiffelKeywords.add("void", Token.LITERAL2);
205:
206: }
207: return eiffelKeywords;
208: }
209:
210: // private members
211: private static KeywordMap eiffelKeywords;
212:
213: private boolean cpp;
214: private KeywordMap keywords;
215: private int lastOffset;
216: private int lastKeyword;
217:
218: private boolean doKeyword(Segment line, int i, char c) {
219: int i1 = i + 1;
220: boolean klassname = false;
221:
222: int len = i - lastKeyword;
223: byte id = keywords.lookup(line, lastKeyword, len);
224: if (id == Token.NULL) {
225: klassname = true;
226: for (int at = lastKeyword; at < lastKeyword + len; at++) {
227: char ch = line.array[at];
228: if (ch != '_' && !Character.isUpperCase(ch)) {
229: klassname = false;
230: break;
231: }
232: }
233: if (klassname)
234: id = Token.KEYWORD3;
235: }
236:
237: if (id != Token.NULL) {
238: if (lastKeyword != lastOffset)
239: addToken(lastKeyword - lastOffset, Token.NULL);
240: addToken(len, id);
241: lastOffset = i;
242: }
243: lastKeyword = i1;
244: return false;
245: }
246: }
|