001: package net.xoetrope.builder.editor.syntaxhighlight;
002:
003: /*
004: * PHPTokenMarker.java - Token marker for PHP
005: * Copyright (C) 1999 Clancy Malcolm
006: * Based on HTMLTokenMarker.java Copyright (C) 1998, 1999 Slava Pestov
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: * PHP token marker.
017: *
018: * @author Clancy Malcolm
019: * @version $Id: PHPTokenMarker.java,v 1.22 2005/01/05 17:20:49 luano Exp $
020: */
021: public class PHPTokenMarker extends TokenMarker {
022: public static final byte SCRIPT = Token.INTERNAL_FIRST;
023:
024: public byte markTokensImpl(byte token, Segment line, int lineIndex) {
025: char[] array = line.array;
026: int offset = line.offset;
027: lastOffset = offset;
028: lastKeyword = offset;
029: int length = line.count + offset;
030: boolean backslash = false;
031:
032: loop: for (int i = offset; i < length; i++) {
033: int i1 = (i + 1);
034:
035: char c = array[i];
036: if (c == '\\') {
037: backslash = !backslash;
038: continue;
039: }
040:
041: switch (token) {
042: case Token.NULL: // HTML text
043: backslash = false;
044: switch (c) {
045: case '<':
046: addToken(i - lastOffset, token);
047: lastOffset = lastKeyword = i;
048: if (SyntaxUtilities.regionMatches(false, line, i1,
049: "!--")) {
050: i += 3;
051: token = Token.COMMENT1;
052: } else if (SyntaxUtilities.regionMatches(true,
053: line, i1, "?php")) {
054: addToken(5, Token.LABEL);
055: lastOffset = lastKeyword = (i += 4) + 1;
056: token = SCRIPT;
057: } else if (SyntaxUtilities.regionMatches(true,
058: line, i1, "?")) {
059: addToken(2, Token.LABEL);
060: lastOffset = lastKeyword = (i += 1) + 1;
061: token = SCRIPT;
062: } else if (SyntaxUtilities.regionMatches(true,
063: line, i1, "script>")) {
064: addToken(8, Token.LABEL);
065: lastOffset = lastKeyword = (i += 7) + 1;
066: token = SCRIPT;
067: } else {
068: token = Token.KEYWORD1;
069: }
070: break;
071: case '&':
072: addToken(i - lastOffset, token);
073: lastOffset = lastKeyword = i;
074: token = Token.KEYWORD2;
075: break;
076: }
077: break;
078: case Token.KEYWORD1: // Inside a tag
079: backslash = false;
080: if (c == '>') {
081: addToken(i1 - lastOffset, token);
082: lastOffset = lastKeyword = i1;
083: token = Token.NULL;
084: }
085: break;
086: case Token.KEYWORD2: // Inside an entity
087: backslash = false;
088: if (c == ';') {
089: addToken(i1 - lastOffset, token);
090: lastOffset = lastKeyword = i1;
091: token = Token.NULL;
092: break;
093: }
094: break;
095: case Token.COMMENT1: // Inside a comment
096: backslash = false;
097: if (SyntaxUtilities
098: .regionMatches(false, line, i, "-->")) {
099: addToken(i + 3 - lastOffset, token);
100: i += 2;
101: lastOffset = lastKeyword = i + 1;
102: token = Token.NULL;
103: }
104: break;
105: case SCRIPT: // Inside a JavaScript or PHP
106: switch (c) {
107: case '<':
108: backslash = false;
109: doKeyword(line, i, c);
110: if (SyntaxUtilities.regionMatches(true, line, i1,
111: "/script>")) {
112: //Ending the script
113: addToken(i - lastOffset, Token.KEYWORD3);
114: addToken(9, Token.LABEL);
115: lastOffset = lastKeyword = (i += 8) + 1;
116: token = Token.NULL;
117: } else {
118: // < operator
119: addToken(i - lastOffset, Token.KEYWORD3);
120: addToken(1, Token.OPERATOR);
121: lastOffset = lastKeyword = i1;
122: }
123: break;
124: case '?':
125: backslash = false;
126: doKeyword(line, i, c);
127: if (array[i1] == '>') {
128: //Ending the script
129: addToken(i - lastOffset, Token.KEYWORD3);
130: addToken(2, Token.LABEL);
131: lastOffset = lastKeyword = (i += 1) + 1;
132: token = Token.NULL;
133: } else {
134: //? operator
135: addToken(i - lastOffset, Token.KEYWORD3);
136: addToken(1, Token.OPERATOR);
137: lastOffset = lastKeyword = i1;
138: }
139: break;
140: case '"':
141: if (backslash)
142: backslash = false;
143: else {
144: doKeyword(line, i, c);
145: addToken(i - lastOffset, Token.KEYWORD3);
146: lastOffset = lastKeyword = i;
147: token = Token.LITERAL1;
148: }
149: break;
150: case '\'':
151: if (backslash)
152: backslash = false;
153: else {
154: doKeyword(line, i, c);
155: addToken(i - lastOffset, Token.KEYWORD3);
156: lastOffset = lastKeyword = i;
157: token = Token.LITERAL2;
158: }
159: break;
160: case '#':
161: doKeyword(line, i, c);
162: addToken(i - lastOffset, Token.KEYWORD3);
163: addToken(length - i, Token.COMMENT2);
164: lastOffset = lastKeyword = length;
165: break loop;
166: case '/':
167: backslash = false;
168: doKeyword(line, i, c);
169: if (length - i > 1) /*This is the same as if(length > i + 1) */
170: {
171: addToken(i - lastOffset, Token.KEYWORD3);
172: lastOffset = lastKeyword = i;
173: if (array[i1] == '/') {
174: addToken(length - i, Token.COMMENT2);
175: lastOffset = lastKeyword = length;
176: break loop;
177: } else if (array[i1] == '*') {
178: token = Token.COMMENT2;
179: } else {
180: // / operator
181: addToken(i - lastOffset, Token.KEYWORD3);
182: addToken(1, Token.OPERATOR);
183: lastOffset = lastKeyword = i1;
184: }
185: } else {
186: // / operator
187: addToken(i - lastOffset, Token.KEYWORD3);
188: addToken(1, Token.OPERATOR);
189: lastOffset = lastKeyword = i1;
190: }
191: break;
192: default:
193: backslash = false;
194: if (!Character.isLetterOrDigit(c) && c != '_'
195: && c != '$') {
196: doKeyword(line, i, c);
197: if (c != ' ') {
198: //assume non alphanumeric characters are operators
199: addToken(i - lastOffset, Token.KEYWORD3);
200: addToken(1, Token.OPERATOR);
201: lastOffset = lastKeyword = i1;
202: }
203: }
204: break;
205: }
206: break;
207: case Token.LITERAL1: // Script "..."
208: if (backslash)
209: backslash = false;
210: else if (c == '"') {
211: addToken(i1 - lastOffset, Token.LITERAL1);
212: lastOffset = lastKeyword = i1;
213: token = SCRIPT;
214: }
215: break;
216: case Token.LITERAL2: // Script '...'
217: if (backslash)
218: backslash = false;
219: else if (c == '\'') {
220: addToken(i1 - lastOffset, Token.LITERAL1);
221: lastOffset = lastKeyword = i1;
222: token = SCRIPT;
223: }
224: break;
225: case Token.COMMENT2: // Inside a Script comment
226: backslash = false;
227: if (c == '*' && length - i > 1 && array[i1] == '/') {
228: addToken(i + 2 - lastOffset, Token.COMMENT2);
229: i += 1;
230: lastOffset = lastKeyword = i + 1;
231: token = SCRIPT;
232: }
233: break;
234: default:
235: throw new InternalError("Invalid state: " + token);
236: }
237: }
238:
239: switch (token) {
240: case Token.LITERAL1:
241: addToken(length - lastOffset, Token.LITERAL1);
242: break;
243: case Token.LITERAL2:
244: addToken(length - lastOffset, Token.LITERAL2);
245: break;
246: case Token.KEYWORD2:
247: addToken(length - lastOffset, Token.INVALID);
248: token = Token.NULL;
249: break;
250: case SCRIPT:
251: doKeyword(line, length, '\0');
252: addToken(length - lastOffset, Token.KEYWORD3);
253: break;
254: default:
255: addToken(length - lastOffset, token);
256: break;
257: }
258:
259: return token;
260: }
261:
262: // private members
263: private static KeywordMap keywords;
264: private int lastOffset;
265: private int lastKeyword;
266:
267: static {
268: keywords = new KeywordMap(false);
269: keywords.add("function", Token.KEYWORD2);
270: keywords.add("class", Token.KEYWORD2);
271: keywords.add("var", Token.KEYWORD2);
272: keywords.add("require", Token.KEYWORD2);
273: keywords.add("include", Token.KEYWORD2);
274: keywords.add("else", Token.KEYWORD1);
275: keywords.add("elseif", Token.KEYWORD1);
276: keywords.add("do", Token.KEYWORD1);
277: keywords.add("for", Token.KEYWORD1);
278: keywords.add("if", Token.KEYWORD1);
279: keywords.add("endif", Token.KEYWORD1);
280: keywords.add("in", Token.KEYWORD1);
281: keywords.add("new", Token.KEYWORD1);
282: keywords.add("return", Token.KEYWORD1);
283: keywords.add("while", Token.KEYWORD1);
284: keywords.add("endwhile", Token.KEYWORD1);
285: keywords.add("with", Token.KEYWORD1);
286: keywords.add("break", Token.KEYWORD1);
287: keywords.add("switch", Token.KEYWORD1);
288: keywords.add("case", Token.KEYWORD1);
289: keywords.add("continue", Token.KEYWORD1);
290: keywords.add("default", Token.KEYWORD1);
291: keywords.add("echo", Token.KEYWORD1);
292: keywords.add("false", Token.KEYWORD1);
293: keywords.add("this", Token.KEYWORD1);
294: keywords.add("true", Token.KEYWORD1);
295: keywords.add("array", Token.KEYWORD1);
296: keywords.add("extends", Token.KEYWORD1);
297: }
298:
299: private boolean doKeyword(Segment line, int i, char c) {
300: int i1 = i + 1;
301:
302: int len = i - lastKeyword;
303: byte id = keywords.lookup(line, lastKeyword, len);
304: if (id != Token.NULL) {
305: if (lastKeyword != lastOffset)
306: addToken(lastKeyword - lastOffset, Token.KEYWORD3);
307: addToken(len, id);
308: lastOffset = i;
309: }
310: lastKeyword = i1;
311: return false;
312: }
313: }
|