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