View Javadoc

1   /*
2    * PHPTokenMarker.java - Token marker for PHP
3    * Copyright (C) 1999 Clancy Malcolm
4    * Based on HTMLTokenMarker.java Copyright (C) 1998, 1999 Slava Pestov
5    *
6    * You may use and modify this package for any purpose. Redistribution is
7    * permitted, in both source and binary form, provided that this notice
8    * remains intact in all source distributions of this package.
9    */
10  
11  package org.syntax.jedit.tokenmarker;
12  
13  import javax.swing.text.Segment;
14  
15  import org.syntax.jedit.KeywordMap;
16  import org.syntax.jedit.SyntaxUtilities;
17  
18  /***
19   * PHP token marker.
20   *
21   * @author Clancy Malcolm
22   * @version $Id: PHPTokenMarker.java,v 1.1 1999/12/14 04:20:35 sp Exp $
23   */
24  public class PHPTokenMarker extends TokenMarker
25  {
26  	public static final byte SCRIPT = Token.INTERNAL_FIRST;
27  
28  	public byte markTokensImpl(byte token, Segment line, int lineIndex)
29  	{
30  		char[] array = line.array;
31  		int offset = line.offset;
32  		lastOffset = offset;
33  		lastKeyword = offset;
34  		int length = line.count + offset;
35  		boolean backslash = false;
36  
37  loop:		for(int i = offset; i < length; i++)
38  		{
39  			int i1 = (i+1);
40  
41  			char c = array[i];
42  			if(c == '//')
43  			{
44  				backslash = !backslash;
45  				continue;
46  			}
47  
48  			switch(token)
49  			{
50  			case Token.NULL: // HTML text
51  				backslash = false;
52  				switch(c)
53  				{
54  				case '<':
55  					addToken(i - lastOffset,token);
56  					lastOffset = lastKeyword = i;
57  					if(SyntaxUtilities.regionMatches(false,
58  						line,i1,"!--"))
59  					{
60  						i += 3;
61  						token = Token.COMMENT1;
62  					}
63  					else if(SyntaxUtilities.regionMatches(
64  						true,line,i1,"?php"))
65  					{
66  						addToken(5,Token.LABEL);
67  						lastOffset = lastKeyword = (i += 4) + 1;
68  						token = SCRIPT;
69  					}
70  					else if(SyntaxUtilities.regionMatches(
71  						true,line,i1,"?"))
72  					{
73  						addToken(2,Token.LABEL);
74  						lastOffset = lastKeyword = (i += 1) + 1;
75  						token = SCRIPT;
76  					}
77  					else if(SyntaxUtilities.regionMatches(
78  						true,line,i1,"script>"))
79  					{
80  						addToken(8,Token.LABEL);
81  						lastOffset = lastKeyword = (i += 7) + 1;
82  						token = SCRIPT;
83  					}
84  					else
85  					{
86  						token = Token.KEYWORD1;
87  					}
88  					break;
89  				case '&':
90  					addToken(i - lastOffset,token);
91  					lastOffset = lastKeyword = i;
92  					token = Token.KEYWORD2;
93  					break;
94  				}
95  				break;
96  			case Token.KEYWORD1: // Inside a tag
97  				backslash = false;
98  				if(c == '>')
99  				{
100 					addToken(i1 - lastOffset,token);
101 					lastOffset = lastKeyword = i1;
102 					token = Token.NULL;
103 				}
104 				break;
105 			case Token.KEYWORD2: // Inside an entity
106 				backslash = false;
107 				if(c == ';')
108 				{
109 					addToken(i1 - lastOffset,token);
110 					lastOffset = lastKeyword = i1;
111 					token = Token.NULL;
112 					break;
113 				}
114 				break;
115 			case Token.COMMENT1: // Inside a comment
116 				backslash = false;
117 				if(SyntaxUtilities.regionMatches(false,line,i,"-->"))
118 				{
119 					addToken(i + 3 - lastOffset,token);
120 					i += 2;
121 					lastOffset = lastKeyword = i + 1;
122 					token = Token.NULL;
123 				}
124 				break;
125 			case SCRIPT: // Inside a JavaScript or PHP
126 				switch(c)
127 				{
128 				case '<':
129 					backslash = false;
130 					doKeyword(line,i,c);
131 					if(SyntaxUtilities.regionMatches(true,
132 						line,i1,"/script>"))
133 					{
134 						//Ending the script
135 						addToken(i - lastOffset,
136 							Token.KEYWORD3);
137 						addToken(9,Token.LABEL);
138 						lastOffset = lastKeyword = (i += 8) + 1;
139 						token = Token.NULL;
140 					}
141 					else
142 					{
143 						// < operator
144 						addToken(i - lastOffset,
145 							Token.KEYWORD3);
146 						addToken(1,Token.OPERATOR);
147 						lastOffset = lastKeyword = i1;
148 					}
149 					break;
150 				case '?':
151 					backslash = false;
152 					doKeyword(line, i, c);
153 					if (array[i1] == '>')
154 					{
155 						//Ending the script
156 						addToken(i - lastOffset,
157 						Token.KEYWORD3);
158 						addToken(2,Token.LABEL);
159 						lastOffset = lastKeyword = (i += 1) + 1;
160 						token = Token.NULL;
161 					}
162 					else
163 					{
164 						//? operator
165 						addToken(i - lastOffset, Token.KEYWORD3);
166 						addToken(1,Token.OPERATOR);
167 						lastOffset = lastKeyword = i1;
168 					}
169 					break;
170 				case '"':
171 					if(backslash)
172 						backslash = false;
173 					else
174 					{
175 						doKeyword(line,i,c);
176 						addToken(i - lastOffset,Token.KEYWORD3);
177 						lastOffset = lastKeyword = i;
178 						token = Token.LITERAL1;
179 					}
180 					break;
181 				case '\'':
182 					if(backslash)
183 						backslash = false;
184 					else
185 					{
186 						doKeyword(line,i,c);
187 						addToken(i - lastOffset,Token.KEYWORD3);
188 						lastOffset = lastKeyword = i;
189 						token = Token.LITERAL2;
190 					}
191 					break;
192 				case '#':
193 					doKeyword(line,i,c);
194 					addToken(i - lastOffset,Token.KEYWORD3);
195 					addToken(length - i,Token.COMMENT2);
196 					lastOffset = lastKeyword = length;
197 					break loop;
198 				case '/':
199 					backslash = false;
200 					doKeyword(line,i,c);
201 					if(length - i > 1)  /*This is the same as if(length > i + 1) */
202 					{
203 						addToken(i - lastOffset,Token.KEYWORD3);
204 						lastOffset = lastKeyword = i;
205 						if(array[i1] == '/')
206 						{
207 							addToken(length - i,Token.COMMENT2);
208 							lastOffset = lastKeyword = length;
209 							break loop;
210 						}
211 						else if(array[i1] == '*')
212 						{
213 							token = Token.COMMENT2;
214 						}
215 						else
216 						{
217 							// / operator
218 							addToken(i - lastOffset, Token.KEYWORD3);
219 							addToken(1,Token.OPERATOR);
220 							lastOffset = lastKeyword = i1;
221 						}
222 	 				}
223 					else
224 					{
225 						// / operator
226 						addToken(i - lastOffset, Token.KEYWORD3);
227 						addToken(1,Token.OPERATOR);
228 						lastOffset = lastKeyword = i1;
229 					}
230 					break;
231 				default:
232 					backslash = false;
233 					if(!Character.isLetterOrDigit(c)
234 						&& c != '_' && c != '$')
235 					{
236 						doKeyword(line,i,c);
237 						if (c != ' ')
238 						{
239 							//assume non alphanumeric characters are operators
240 							addToken(i - lastOffset, Token.KEYWORD3);
241 							addToken(1,Token.OPERATOR);
242 							lastOffset = lastKeyword = i1;
243 						}
244 					}
245 					break;
246 				}
247 				break;
248 			case Token.LITERAL1: // Script "..."
249 				if(backslash)
250 					backslash = false;
251 				else if(c == '"')
252 				{
253 					addToken(i1 - lastOffset,Token.LITERAL1);
254 					lastOffset = lastKeyword = i1;
255 					token = SCRIPT;
256 				}
257 				break;
258 			case Token.LITERAL2: // Script '...'
259 				if(backslash)
260 					backslash = false;
261 				else if(c == '\'')
262 				{
263 					addToken(i1 - lastOffset,Token.LITERAL1);
264 					lastOffset = lastKeyword = i1;
265 					token = SCRIPT;
266 				}
267 				break;
268 			case Token.COMMENT2: // Inside a Script comment
269 				backslash = false;
270 				if(c == '*' && length - i > 1 && array[i1] == '/')
271 				{
272 					addToken(i + 2 - lastOffset,Token.COMMENT2);
273 					i += 1;
274 					lastOffset = lastKeyword = i + 1;
275 					token = SCRIPT;
276 				}
277 				break;
278 			default:
279 				throw new InternalError("Invalid state: "
280 					+ token);
281 			}
282 		}
283 
284 		switch(token)
285 		{
286 		case Token.LITERAL1:
287 			addToken(length - lastOffset,Token.LITERAL1);
288 			break;
289 		case Token.LITERAL2:
290 			addToken(length - lastOffset,Token.LITERAL2);
291 			break;
292 		case Token.KEYWORD2:
293 			addToken(length - lastOffset,Token.INVALID);
294 			token = Token.NULL;
295 			break;
296 		case SCRIPT:
297 			doKeyword(line,length,'\0');
298 			addToken(length - lastOffset,Token.KEYWORD3);
299 			break;
300 		default:
301 			addToken(length - lastOffset,token);
302 			break;
303 		}
304 
305 		return token;
306 	}
307 
308 	// private members
309 	private static KeywordMap keywords;
310 	private int lastOffset;
311 	private int lastKeyword;
312 
313 	static
314 	{
315 		keywords = new KeywordMap(false);
316 		keywords.add("function",Token.KEYWORD2);
317 		keywords.add("class",Token.KEYWORD2);
318 		keywords.add("var",Token.KEYWORD2);
319 		keywords.add("require",Token.KEYWORD2);
320 		keywords.add("include",Token.KEYWORD2);
321 		keywords.add("else",Token.KEYWORD1);
322 		keywords.add("elseif",Token.KEYWORD1);
323 		keywords.add("do",Token.KEYWORD1);
324 		keywords.add("for",Token.KEYWORD1);
325 		keywords.add("if",Token.KEYWORD1);
326 		keywords.add("endif",Token.KEYWORD1);
327 		keywords.add("in",Token.KEYWORD1);
328 		keywords.add("new",Token.KEYWORD1);
329 		keywords.add("return",Token.KEYWORD1);
330 		keywords.add("while",Token.KEYWORD1);
331 		keywords.add("endwhile",Token.KEYWORD1);
332 		keywords.add("with",Token.KEYWORD1);
333 		keywords.add("break",Token.KEYWORD1);
334 		keywords.add("switch",Token.KEYWORD1);
335 		keywords.add("case",Token.KEYWORD1);
336 		keywords.add("continue",Token.KEYWORD1);
337 		keywords.add("default",Token.KEYWORD1);
338 		keywords.add("echo",Token.KEYWORD1);
339 		keywords.add("false",Token.KEYWORD1);
340 		keywords.add("this",Token.KEYWORD1);
341 		keywords.add("true",Token.KEYWORD1);
342 		keywords.add("array",Token.KEYWORD1);
343 		keywords.add("extends",Token.KEYWORD1);
344 	}
345 
346 	private boolean doKeyword(Segment line, int i, char c)
347 	{
348 		int i1 = i+1;
349 
350 		int len = i - lastKeyword;
351 		byte id = keywords.lookup(line,lastKeyword,len);
352 		if(id != Token.NULL)
353 		{
354 			if(lastKeyword != lastOffset)
355 				addToken(lastKeyword - lastOffset,Token.KEYWORD3);
356 			addToken(len,id);
357 			lastOffset = i;
358 		}
359 		lastKeyword = i1;
360 		return false;
361 	}
362 }