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 }