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, line, i1, "!--" ) )
58  					{
59  						i += 3;
60  						token = Token.COMMENT1;
61  					}
62  					else if( SyntaxUtilities.regionMatches( true, line, i1, "?php" ) )
63  					{
64  						addToken( 5, Token.LABEL );
65  						lastOffset = lastKeyword = ( i += 4 ) + 1;
66  						token = SCRIPT;
67  					}
68  					else if( SyntaxUtilities.regionMatches( true, line, i1, "?" ) )
69  					{
70  						addToken( 2, Token.LABEL );
71  						lastOffset = lastKeyword = ( i += 1 ) + 1;
72  						token = SCRIPT;
73  					}
74  					else if( SyntaxUtilities.regionMatches( true, line, i1, "script>" ) )
75  					{
76  						addToken( 8, Token.LABEL );
77  						lastOffset = lastKeyword = ( i += 7 ) + 1;
78  						token = SCRIPT;
79  					}
80  					else
81  					{
82  						token = Token.KEYWORD1;
83  					}
84  					break;
85  				case '&' :
86  					addToken( i - lastOffset, token );
87  					lastOffset = lastKeyword = i;
88  					token = Token.KEYWORD2;
89  					break;
90  				}
91  				break;
92  			case Token.KEYWORD1 : // Inside a tag
93  				backslash = false;
94  				if( c == '>' )
95  				{
96  					addToken( i1 - lastOffset, token );
97  					lastOffset = lastKeyword = i1;
98  					token = Token.NULL;
99  				}
100 				break;
101 			case Token.KEYWORD2 : // Inside an entity
102 				backslash = false;
103 				if( c == ';' )
104 				{
105 					addToken( i1 - lastOffset, token );
106 					lastOffset = lastKeyword = i1;
107 					token = Token.NULL;
108 					break;
109 				}
110 				break;
111 			case Token.COMMENT1 : // Inside a comment
112 				backslash = false;
113 				if( SyntaxUtilities.regionMatches( false, line, i, "-->" ) )
114 				{
115 					addToken( i + 3 - lastOffset, token );
116 					i += 2;
117 					lastOffset = lastKeyword = i + 1;
118 					token = Token.NULL;
119 				}
120 				break;
121 			case SCRIPT : // Inside a JavaScript or PHP
122 				switch( c )
123 				{
124 				case '<' :
125 					backslash = false;
126 					doKeyword( line, i, c );
127 					if( SyntaxUtilities.regionMatches( true, line, i1, "/script>" ) )
128 					{
129 						// Ending the script
130 						addToken( i - lastOffset, Token.KEYWORD3 );
131 						addToken( 9, Token.LABEL );
132 						lastOffset = lastKeyword = ( i += 8 ) + 1;
133 						token = Token.NULL;
134 					}
135 					else
136 					{
137 						// < operator
138 						addToken( i - lastOffset, Token.KEYWORD3 );
139 						addToken( 1, Token.OPERATOR );
140 						lastOffset = lastKeyword = i1;
141 					}
142 					break;
143 				case '?' :
144 					backslash = false;
145 					doKeyword( line, i, c );
146 					if( array[i1] == '>' )
147 					{
148 						// Ending the script
149 						addToken( i - lastOffset, Token.KEYWORD3 );
150 						addToken( 2, Token.LABEL );
151 						lastOffset = lastKeyword = ( i += 1 ) + 1;
152 						token = Token.NULL;
153 					}
154 					else
155 					{
156 						// ? operator
157 						addToken( i - lastOffset, Token.KEYWORD3 );
158 						addToken( 1, Token.OPERATOR );
159 						lastOffset = lastKeyword = i1;
160 					}
161 					break;
162 				case '"' :
163 					if( backslash )
164 						backslash = false;
165 					else
166 					{
167 						doKeyword( line, i, c );
168 						addToken( i - lastOffset, Token.KEYWORD3 );
169 						lastOffset = lastKeyword = i;
170 						token = Token.LITERAL1;
171 					}
172 					break;
173 				case '\'' :
174 					if( backslash )
175 						backslash = false;
176 					else
177 					{
178 						doKeyword( line, i, c );
179 						addToken( i - lastOffset, Token.KEYWORD3 );
180 						lastOffset = lastKeyword = i;
181 						token = Token.LITERAL2;
182 					}
183 					break;
184 				case '#' :
185 					doKeyword( line, i, c );
186 					addToken( i - lastOffset, Token.KEYWORD3 );
187 					addToken( length - i, Token.COMMENT2 );
188 					lastOffset = lastKeyword = length;
189 					break loop;
190 				case '/' :
191 					backslash = false;
192 					doKeyword( line, i, c );
193 					if( length - i > 1 ) /* This is the same as if(length > i + 1) */
194 					{
195 						addToken( i - lastOffset, Token.KEYWORD3 );
196 						lastOffset = lastKeyword = i;
197 						if( array[i1] == '/' )
198 						{
199 							addToken( length - i, Token.COMMENT2 );
200 							lastOffset = lastKeyword = length;
201 							break loop;
202 						}
203 						else if( array[i1] == '*' )
204 						{
205 							token = Token.COMMENT2;
206 						}
207 						else
208 						{
209 							// / operator
210 							addToken( i - lastOffset, Token.KEYWORD3 );
211 							addToken( 1, Token.OPERATOR );
212 							lastOffset = lastKeyword = i1;
213 						}
214 					}
215 					else
216 					{
217 						// / operator
218 						addToken( i - lastOffset, Token.KEYWORD3 );
219 						addToken( 1, Token.OPERATOR );
220 						lastOffset = lastKeyword = i1;
221 					}
222 					break;
223 				default :
224 					backslash = false;
225 					if( !Character.isLetterOrDigit( c ) && c != '_' && c != '$' )
226 					{
227 						doKeyword( line, i, c );
228 						if( c != ' ' )
229 						{
230 							// assume non alphanumeric characters are operators
231 							addToken( i - lastOffset, Token.KEYWORD3 );
232 							addToken( 1, Token.OPERATOR );
233 							lastOffset = lastKeyword = i1;
234 						}
235 					}
236 					break;
237 				}
238 				break;
239 			case Token.LITERAL1 : // Script "..."
240 				if( backslash )
241 					backslash = false;
242 				else if( c == '"' )
243 				{
244 					addToken( i1 - lastOffset, Token.LITERAL1 );
245 					lastOffset = lastKeyword = i1;
246 					token = SCRIPT;
247 				}
248 				break;
249 			case Token.LITERAL2 : // Script '...'
250 				if( backslash )
251 					backslash = false;
252 				else if( c == '\'' )
253 				{
254 					addToken( i1 - lastOffset, Token.LITERAL1 );
255 					lastOffset = lastKeyword = i1;
256 					token = SCRIPT;
257 				}
258 				break;
259 			case Token.COMMENT2 : // Inside a Script comment
260 				backslash = false;
261 				if( c == '*' && length - i > 1 && array[i1] == '/' )
262 				{
263 					addToken( i + 2 - lastOffset, Token.COMMENT2 );
264 					i += 1;
265 					lastOffset = lastKeyword = i + 1;
266 					token = SCRIPT;
267 				}
268 				break;
269 			default :
270 				throw new InternalError( "Invalid state: " + token );
271 			}
272 		}
273 
274 		switch( token )
275 		{
276 		case Token.LITERAL1 :
277 			addToken( length - lastOffset, Token.LITERAL1 );
278 			break;
279 		case Token.LITERAL2 :
280 			addToken( length - lastOffset, Token.LITERAL2 );
281 			break;
282 		case Token.KEYWORD2 :
283 			addToken( length - lastOffset, Token.INVALID );
284 			token = Token.NULL;
285 			break;
286 		case SCRIPT :
287 			doKeyword( line, length, '\0' );
288 			addToken( length - lastOffset, Token.KEYWORD3 );
289 			break;
290 		default :
291 			addToken( length - lastOffset, token );
292 			break;
293 		}
294 
295 		return token;
296 	}
297 
298 	// private members
299 	private static KeywordMap keywords;
300 	private int lastOffset;
301 	private int lastKeyword;
302 
303 	static
304 	{
305 		keywords = new KeywordMap( false );
306 		keywords.add( "function", Token.KEYWORD2 );
307 		keywords.add( "class", Token.KEYWORD2 );
308 		keywords.add( "var", Token.KEYWORD2 );
309 		keywords.add( "require", Token.KEYWORD2 );
310 		keywords.add( "include", Token.KEYWORD2 );
311 		keywords.add( "else", Token.KEYWORD1 );
312 		keywords.add( "elseif", Token.KEYWORD1 );
313 		keywords.add( "do", Token.KEYWORD1 );
314 		keywords.add( "for", Token.KEYWORD1 );
315 		keywords.add( "if", Token.KEYWORD1 );
316 		keywords.add( "endif", Token.KEYWORD1 );
317 		keywords.add( "in", Token.KEYWORD1 );
318 		keywords.add( "new", Token.KEYWORD1 );
319 		keywords.add( "return", Token.KEYWORD1 );
320 		keywords.add( "while", Token.KEYWORD1 );
321 		keywords.add( "endwhile", Token.KEYWORD1 );
322 		keywords.add( "with", Token.KEYWORD1 );
323 		keywords.add( "break", Token.KEYWORD1 );
324 		keywords.add( "switch", Token.KEYWORD1 );
325 		keywords.add( "case", Token.KEYWORD1 );
326 		keywords.add( "continue", Token.KEYWORD1 );
327 		keywords.add( "default", Token.KEYWORD1 );
328 		keywords.add( "echo", Token.KEYWORD1 );
329 		keywords.add( "false", Token.KEYWORD1 );
330 		keywords.add( "this", Token.KEYWORD1 );
331 		keywords.add( "true", Token.KEYWORD1 );
332 		keywords.add( "array", Token.KEYWORD1 );
333 		keywords.add( "extends", Token.KEYWORD1 );
334 	}
335 
336 	private boolean doKeyword( Segment line, int i, char c )
337 	{
338 		int i1 = i + 1;
339 
340 		int len = i - lastKeyword;
341 		byte id = keywords.lookup( line, lastKeyword, len );
342 		if( id != Token.NULL )
343 		{
344 			if( lastKeyword != lastOffset )
345 				addToken( lastKeyword - lastOffset, Token.KEYWORD3 );
346 			addToken( len, id );
347 			lastOffset = i;
348 		}
349 		lastKeyword = i1;
350 		return false;
351 	}
352 }