001: /*
002: * Copyright (C) 2005 - 2008 JasperSoft Corporation. All rights reserved.
003: * http://www.jaspersoft.com.
004: *
005: * Unless you have purchased a commercial license agreement from JasperSoft,
006: * the following license terms apply:
007: *
008: * This program is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU General Public License version 2 as published by
010: * the Free Software Foundation.
011: *
012: * This program is distributed WITHOUT ANY WARRANTY; and without the
013: * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
014: * See the GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, see http://www.gnu.org/licenses/gpl.txt
018: * or write to:
019: *
020: * Free Software Foundation, Inc.,
021: * 59 Temple Place - Suite 330,
022: * Boston, MA USA 02111-1307
023: *
024: *
025: *
026: *
027: * PHPTokenMarker.java
028: *
029: */
030:
031: package org.syntax.jedit.tokenmarker;
032:
033: import org.syntax.jedit.*;
034: import javax.swing.text.Segment;
035:
036: /**
037: * PHP token marker.
038: *
039: * @author Clancy Malcolm
040: * @version $Id: PHPTokenMarker.java 1167 2008-01-15 18:49:05Z gtoffoli $
041: */
042: public class PHPTokenMarker extends TokenMarker {
043: public static final byte SCRIPT = Token.INTERNAL_FIRST;
044:
045: public byte markTokensImpl(byte token, Segment line, int lineIndex) {
046: char[] array = line.array;
047: int offset = line.offset;
048: lastOffset = offset;
049: lastKeyword = offset;
050: int length = line.count + offset;
051: boolean backslash = false;
052:
053: loop: for (int i = offset; i < length; i++) {
054: int i1 = (i + 1);
055:
056: char c = array[i];
057: if (c == '\\') {
058: backslash = !backslash;
059: continue;
060: }
061:
062: switch (token) {
063: case Token.NULL: // HTML text
064: backslash = false;
065: switch (c) {
066: case '<':
067: addToken(i - lastOffset, token);
068: lastOffset = lastKeyword = i;
069: if (SyntaxUtilities.regionMatches(false, line, i1,
070: "!--")) {
071: i += 3;
072: token = Token.COMMENT1;
073: } else if (SyntaxUtilities.regionMatches(true,
074: line, i1, "?php")) {
075: addToken(5, Token.LABEL);
076: lastOffset = lastKeyword = (i += 4) + 1;
077: token = SCRIPT;
078: } else if (SyntaxUtilities.regionMatches(true,
079: line, i1, "?")) {
080: addToken(2, Token.LABEL);
081: lastOffset = lastKeyword = (i += 1) + 1;
082: token = SCRIPT;
083: } else if (SyntaxUtilities.regionMatches(true,
084: line, i1, "script>")) {
085: addToken(8, Token.LABEL);
086: lastOffset = lastKeyword = (i += 7) + 1;
087: token = SCRIPT;
088: } else {
089: token = Token.KEYWORD1;
090: }
091: break;
092: case '&':
093: addToken(i - lastOffset, token);
094: lastOffset = lastKeyword = i;
095: token = Token.KEYWORD2;
096: break;
097: }
098: break;
099: case Token.KEYWORD1: // Inside a tag
100: backslash = false;
101: if (c == '>') {
102: addToken(i1 - lastOffset, token);
103: lastOffset = lastKeyword = i1;
104: token = Token.NULL;
105: }
106: break;
107: case Token.KEYWORD2: // Inside an entity
108: backslash = false;
109: if (c == ';') {
110: addToken(i1 - lastOffset, token);
111: lastOffset = lastKeyword = i1;
112: token = Token.NULL;
113: break;
114: }
115: break;
116: case Token.COMMENT1: // Inside a comment
117: backslash = false;
118: if (SyntaxUtilities
119: .regionMatches(false, line, i, "-->")) {
120: addToken(i + 3 - lastOffset, token);
121: i += 2;
122: lastOffset = lastKeyword = i + 1;
123: token = Token.NULL;
124: }
125: break;
126: case SCRIPT: // Inside a JavaScript or PHP
127: switch (c) {
128: case '<':
129: backslash = false;
130: doKeyword(line, i, c);
131: if (SyntaxUtilities.regionMatches(true, line, i1,
132: "/script>")) {
133: //Ending the script
134: addToken(i - lastOffset, Token.KEYWORD3);
135: addToken(9, Token.LABEL);
136: lastOffset = lastKeyword = (i += 8) + 1;
137: token = Token.NULL;
138: } else {
139: // < operator
140: addToken(i - lastOffset, Token.KEYWORD3);
141: addToken(1, Token.OPERATOR);
142: lastOffset = lastKeyword = i1;
143: }
144: break;
145: case '?':
146: backslash = false;
147: doKeyword(line, i, c);
148: if (array[i1] == '>') {
149: //Ending the script
150: addToken(i - lastOffset, Token.KEYWORD3);
151: addToken(2, Token.LABEL);
152: lastOffset = lastKeyword = (i += 1) + 1;
153: token = Token.NULL;
154: } else {
155: //? operator
156: addToken(i - lastOffset, Token.KEYWORD3);
157: addToken(1, Token.OPERATOR);
158: lastOffset = lastKeyword = i1;
159: }
160: break;
161: case '"':
162: if (backslash)
163: backslash = false;
164: else {
165: doKeyword(line, i, c);
166: addToken(i - lastOffset, Token.KEYWORD3);
167: lastOffset = lastKeyword = i;
168: token = Token.LITERAL1;
169: }
170: break;
171: case '\'':
172: if (backslash)
173: backslash = false;
174: else {
175: doKeyword(line, i, c);
176: addToken(i - lastOffset, Token.KEYWORD3);
177: lastOffset = lastKeyword = i;
178: token = Token.LITERAL2;
179: }
180: break;
181: case '#':
182: doKeyword(line, i, c);
183: addToken(i - lastOffset, Token.KEYWORD3);
184: addToken(length - i, Token.COMMENT2);
185: lastOffset = lastKeyword = length;
186: break loop;
187: case '/':
188: backslash = false;
189: doKeyword(line, i, c);
190: if (length - i > 1) /*This is the same as if(length > i + 1) */
191: {
192: addToken(i - lastOffset, Token.KEYWORD3);
193: lastOffset = lastKeyword = i;
194: if (array[i1] == '/') {
195: addToken(length - i, Token.COMMENT2);
196: lastOffset = lastKeyword = length;
197: break loop;
198: } else if (array[i1] == '*') {
199: token = Token.COMMENT2;
200: } else {
201: // / operator
202: addToken(i - lastOffset, Token.KEYWORD3);
203: addToken(1, Token.OPERATOR);
204: lastOffset = lastKeyword = i1;
205: }
206: } else {
207: // / operator
208: addToken(i - lastOffset, Token.KEYWORD3);
209: addToken(1, Token.OPERATOR);
210: lastOffset = lastKeyword = i1;
211: }
212: break;
213: default:
214: backslash = false;
215: if (!Character.isLetterOrDigit(c) && c != '_'
216: && c != '$') {
217: doKeyword(line, i, c);
218: if (c != ' ') {
219: //assume non alphanumeric characters are operators
220: addToken(i - lastOffset, Token.KEYWORD3);
221: addToken(1, Token.OPERATOR);
222: lastOffset = lastKeyword = i1;
223: }
224: }
225: break;
226: }
227: break;
228: case Token.LITERAL1: // Script "..."
229: if (backslash)
230: backslash = false;
231: else if (c == '"') {
232: addToken(i1 - lastOffset, Token.LITERAL1);
233: lastOffset = lastKeyword = i1;
234: token = SCRIPT;
235: }
236: break;
237: case Token.LITERAL2: // Script '...'
238: if (backslash)
239: backslash = false;
240: else if (c == '\'') {
241: addToken(i1 - lastOffset, Token.LITERAL1);
242: lastOffset = lastKeyword = i1;
243: token = SCRIPT;
244: }
245: break;
246: case Token.COMMENT2: // Inside a Script comment
247: backslash = false;
248: if (c == '*' && length - i > 1 && array[i1] == '/') {
249: addToken(i + 2 - lastOffset, Token.COMMENT2);
250: i += 1;
251: lastOffset = lastKeyword = i + 1;
252: token = SCRIPT;
253: }
254: break;
255: default:
256: throw new InternalError("Invalid state: " + token);
257: }
258: }
259:
260: switch (token) {
261: case Token.LITERAL1:
262: addToken(length - lastOffset, Token.LITERAL1);
263: break;
264: case Token.LITERAL2:
265: addToken(length - lastOffset, Token.LITERAL2);
266: break;
267: case Token.KEYWORD2:
268: addToken(length - lastOffset, Token.INVALID);
269: token = Token.NULL;
270: break;
271: case SCRIPT:
272: doKeyword(line, length, '\0');
273: addToken(length - lastOffset, Token.KEYWORD3);
274: break;
275: default:
276: addToken(length - lastOffset, token);
277: break;
278: }
279:
280: return token;
281: }
282:
283: // private members
284: private static KeywordMap keywords;
285: private int lastOffset;
286: private int lastKeyword;
287:
288: static {
289: keywords = new KeywordMap(false);
290: keywords.add("function", Token.KEYWORD2);
291: keywords.add("class", Token.KEYWORD2);
292: keywords.add("var", Token.KEYWORD2);
293: keywords.add("require", Token.KEYWORD2);
294: keywords.add("include", Token.KEYWORD2);
295: keywords.add("else", Token.KEYWORD1);
296: keywords.add("elseif", Token.KEYWORD1);
297: keywords.add("do", Token.KEYWORD1);
298: keywords.add("for", Token.KEYWORD1);
299: keywords.add("if", Token.KEYWORD1);
300: keywords.add("endif", Token.KEYWORD1);
301: keywords.add("in", Token.KEYWORD1);
302: keywords.add("new", Token.KEYWORD1);
303: keywords.add("return", Token.KEYWORD1);
304: keywords.add("while", Token.KEYWORD1);
305: keywords.add("endwhile", Token.KEYWORD1);
306: keywords.add("with", Token.KEYWORD1);
307: keywords.add("break", Token.KEYWORD1);
308: keywords.add("switch", Token.KEYWORD1);
309: keywords.add("case", Token.KEYWORD1);
310: keywords.add("continue", Token.KEYWORD1);
311: keywords.add("default", Token.KEYWORD1);
312: keywords.add("echo", Token.KEYWORD1);
313: keywords.add("false", Token.KEYWORD1);
314: keywords.add("this", Token.KEYWORD1);
315: keywords.add("true", Token.KEYWORD1);
316: keywords.add("array", Token.KEYWORD1);
317: keywords.add("extends", Token.KEYWORD1);
318: }
319:
320: private boolean doKeyword(Segment line, int i, char c) {
321: int i1 = i + 1;
322:
323: int len = i - lastKeyword;
324: byte id = keywords.lookup(line, lastKeyword, len);
325: if (id != Token.NULL) {
326: if (lastKeyword != lastOffset)
327: addToken(lastKeyword - lastOffset, Token.KEYWORD3);
328: addToken(len, id);
329: lastOffset = i;
330: }
331: lastKeyword = i1;
332: return false;
333: }
334: }
|