55d87835600258ff3deaa714b6ce5c3761aaeb6b
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / php / PHPPartitionScanner.java
1 /**********************************************************************
2  Copyright (c) 2002  Widespace, OU  and others.
3  All rights reserved.   This program and the accompanying materials
4  are made available under the terms of the Common Public License v1.0
5  which accompanies this distribution, and is available at
6  http://solareclipse.sourceforge.net/legal/cpl-v10.html
7
8  Contributors:
9  Igor Malinin - initial contribution
10
11  $Id: PHPPartitionScanner.java,v 1.35 2007-03-17 14:07:31 axelcl Exp $
12  **********************************************************************/
13 package net.sourceforge.phpeclipse.phpeditor.php;
14
15 import java.util.HashMap;
16 import java.util.Map;
17
18 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
19 import net.sourceforge.phpeclipse.ui.text.rules.AbstractPartitioner;
20
21 //incastrix
22 //import org.eclipse.jface.text.Assert;
23 import org.eclipse.core.runtime.Assert;
24 import org.eclipse.jface.text.BadLocationException;
25 import org.eclipse.jface.text.IDocument;
26 import org.eclipse.jface.text.rules.ICharacterScanner;
27 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
28 import org.eclipse.jface.text.rules.IToken;
29 import org.eclipse.jface.text.rules.Token;
30
31 /**
32  * 
33  * 
34  * @author Igor Malinin
35  */
36 public class PHPPartitionScanner implements IPartitionTokenScanner {
37         public static final String PHP_SCRIPTING_AREA = "__php_scripting_area ";
38
39         public static final int STATE_DEFAULT = 0;
40
41         // public static final int STATE_TAG = 1;
42         // public static final int STATE_SCRIPT = 2;
43
44         private IDocument document;
45
46         // private int begin;
47
48         private int end;
49
50         private int offset;
51
52         private int length;
53
54         private int position;
55
56         // private int state;
57
58         private Map tokens = new HashMap();
59
60         public PHPPartitionScanner() {
61         }
62
63         /*
64          * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
65          */
66         public IToken nextToken() {
67                 offset += length;
68
69                 /*
70                  * switch (state) { case STATE_TAG: return nextTagToken(); }
71                  */
72
73                 switch (read()) {
74                 case ICharacterScanner.EOF:
75                         // state = STATE_DEFAULT;
76                         return getToken(null);
77
78                 case '<':
79                         switch (read()) {
80                         case ICharacterScanner.EOF:
81                                 // state = STATE_DEFAULT;
82                                 return getToken(null);
83
84                         case '?': // <?
85                                 // int ch = read();
86                                 //
87                                 // switch (ch) {
88                                 // case ICharacterScanner.EOF:
89                                 // state = STATE_DEFAULT;
90                                 // return getToken(PHP_SCRIPTING_AREA);
91                                 // }
92                                 return scanUntilPHPEndToken(PHP_SCRIPTING_AREA);
93                         }
94
95                         unread();
96                 }
97
98                 loop: while (true) {
99                         switch (read()) {
100                         case ICharacterScanner.EOF:
101                                 // state = STATE_DEFAULT;
102                                 return getToken(null);
103
104                         case '<':
105                                 switch (read()) {
106                                 case ICharacterScanner.EOF:
107                                         // state = STATE_DEFAULT;
108                                         return getToken(null);
109
110                                 case '?':
111                                         unread();
112                                         break;
113
114                                 case '<':
115                                         unread();
116
117                                 default:
118                                         continue loop;
119                                 }
120
121                                 unread();
122
123                                 // state = STATE_DEFAULT;
124                                 return getToken(null);
125                         }
126                 }
127         }
128
129         private IToken scanUntilPHPEndToken(String token) {
130                 int ch = read();
131                 while (true) {
132                         switch (ch) {
133                         case ICharacterScanner.EOF:
134                                 // state = STATE_DEFAULT;
135                                 return getToken(token);
136                         case '"': // double quoted string
137                                 // read until end of double quoted string
138                                 if (!readUntilEscapedDQ()) {
139                                         // state = STATE_DEFAULT;
140                                         return getToken(token);
141                                 }
142                                 break;
143                         case '<': // heredoc string
144                                 ch = read();
145                                 switch (ch) {
146                                 case ICharacterScanner.EOF:
147                                         break;
148                                 case '<':
149                                         ch = read();
150                                         switch (ch) {
151                                         case ICharacterScanner.EOF:
152                                                 break;
153                                         case '<':
154                                                 // read until end of heredoc string
155                                                 if (!readUntilEscapedHEREDOC()) {
156                                                         // state = STATE_DEFAULT;
157                                                         return getToken(token);
158                                                 }
159                                         }
160                                 }
161                                 break;
162                         case '\'': // single quoted string
163                                 // read until end of single quoted string
164                                 if (!readUntilEscapedSQ()) {
165                                         // state = STATE_DEFAULT;
166                                         return getToken(token);
167                                 }
168                                 break;
169                         case '/': // comment start?
170                                 ch = read();
171                                 switch (ch) {
172                                 case ICharacterScanner.EOF:
173                                         break;
174                                 case '/':
175                                         // read until end of line
176                                         if (!readSingleLine()) {
177                                                 // state = STATE_DEFAULT;
178                                                 return getToken(token);
179                                         }
180                                         break;
181                                 case '*':
182                                         // read until end of comment
183                                         if (!readMultiLineComment()) {
184                                                 // state = STATE_DEFAULT;
185                                                 return getToken(token);
186                                         }
187                                         break;
188                                 default:
189                                         continue;
190                                 }
191                                 break;
192                         case '#': // line comment
193                                 // read until end of line
194                                 if (!readSingleLine()) {
195                                         // state = STATE_DEFAULT;
196                                         return getToken(token);
197                                 }
198                                 break;
199                         case '?':
200                                 ch = read();
201                                 switch (ch) {
202                                 case ICharacterScanner.EOF:
203                                 case '>':
204                                         // state = STATE_DEFAULT;
205                                         return getToken(token);
206
207                                 case '?':
208                                         continue;
209                                 default:
210                                         continue;
211                                 }
212                         }
213
214                         ch = read();
215                 }
216         }
217
218         private IToken getToken(String type) {
219                 length = position - offset;
220
221                 if (length == 0) {
222                         return Token.EOF;
223                 }
224
225                 // if (length<0) {
226                 // try {
227                 // System.out.println("Length<0:"+document.get(offset,5)+""+length);
228                 // } catch (BadLocationException e) {
229                 // e.printStackTrace();
230                 // }
231                 // }
232
233                 if (type == null) {
234                         return Token.UNDEFINED;
235                 }
236
237                 IToken token = (IToken) tokens.get(type);
238                 if (token == null) {
239                         token = new Token(type);
240                         tokens.put(type, token);
241                 }
242
243                 return token;
244         }
245
246         private int read() {
247                 if (position >= end) {
248                         return ICharacterScanner.EOF;
249                 }
250
251                 try {
252                         return document.getChar(position++);
253                 } catch (BadLocationException e) {
254                         --position;
255                         return ICharacterScanner.EOF;
256                 }
257         }
258
259         private boolean readUntilEscapedDQ() {
260                 // search last double quoted character
261                 try {
262                         char ch;
263                         while (true) {
264                                 if (position >= end) {
265                                         return false;
266                                 }
267                                 ch = document.getChar(position++);
268                                 if (ch == '\\') {
269                                         if (position >= end) {
270                                                 return false;
271                                         }
272                                         ch = document.getChar(position++); // ignore escaped
273                                         // character
274                                 } else if (ch == '"') {
275                                         return true;
276                                 }
277                         }
278                 } catch (BadLocationException e) {
279                         --position;
280                 }
281                 return false;
282         }
283
284         private boolean readUntilEscapedSQ() {
285                 // search last single quoted character
286                 try {
287                         char ch;
288                         while (true) {
289                                 if (position >= end) {
290                                         return false;
291                                 }
292                                 ch = document.getChar(position++);
293                                 if (ch == '\\') {
294                                         if (position >= end) {
295                                                 return false;
296                                         }
297                                         ch = document.getChar(position++); // ignore escaped
298                                         // character
299                                 } else if (ch == '\'') {
300                                         return true;
301                                 }
302                         }
303                 } catch (BadLocationException e) {
304                         --position;
305                 }
306                 return false;
307         }
308
309         private boolean readUntilEscapedHEREDOC() {
310                 // search until heredoc ends
311                 try {
312                         char ch;
313                         StringBuffer buf = new StringBuffer();
314                         char[] heredocIdent;
315                         if (position >= end) {
316                                 return false;
317                         }
318                         ch = document.getChar(position++);
319                         // #1493165 start
320                         while (ch == ' ') {
321                                 if (position >= end) {
322                                         return false;
323                                 }
324                                 ch = document.getChar(position++);
325                         }
326                         // #1493165 end
327                         if (!Scanner.isPHPIdentifierStart(ch)) {
328                                 return false;
329                         }
330                         while (Scanner.isPHPIdentifierPart(ch)) {
331                                 buf.append(ch);
332                                 if (position >= end) {
333                                         return false;
334                                 }
335                                 ch = document.getChar(position++);
336                         }
337                         heredocIdent = buf.toString().toCharArray();
338                         while (true) {
339                                 if (position >= end) {
340                                         return false;
341                                 }
342                                 ch = document.getChar(position++);
343                                 if (ch == '\n') { // heredoc could end after a newline
344                                         int pos = 0;
345                                         while (true) {
346                                                 if (position >= end) {
347                                                         return false;
348                                                 }
349                                                 if (pos == heredocIdent.length) {
350                                                         return true;
351                                                 }
352                                                 ch = document.getChar(position++); // ignore escaped
353                                                 // character
354                                                 if (ch != heredocIdent[pos]) {
355                                                         break;
356                                                 }
357                                                 pos++;
358                                         }
359                                 }
360                         }
361                 } catch (BadLocationException e) {
362                         --position;
363                 }
364                 return false;
365         }
366
367         private boolean readSingleLine() {
368                 try {
369                         do {
370                                 if (position >= end) {
371                                         return false;
372                                 }
373                         } while (document.getChar(position++) != '\n');
374                         return true;
375                 } catch (BadLocationException e) {
376                         --position;
377                 }
378                 return false;
379         }
380
381         private boolean readMultiLineComment() {
382                 try {
383                         char ch;
384                         while (true) {
385                                 if (position >= end) {
386                                         return false;
387                                 }
388                                 ch = document.getChar(position++);
389                                 if (ch == '*') {
390                                         if (position >= end) {
391                                                 return false;
392                                         }
393                                         if (document.getChar(position) == '/') {
394                                                 position++;
395                                                 return true;
396                                         }
397                                 }
398                         }
399                 } catch (BadLocationException e) {
400                         --position;
401                 }
402                 return false;
403         }
404
405         private void unread() {
406                 --position;
407         }
408
409         /*
410          * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset()
411          */
412         public int getTokenOffset() {
413                 if (AbstractPartitioner.DEBUG) {
414                         Assert.isTrue(offset >= 0, Integer.toString(offset));
415                 }
416                 return offset;
417         }
418
419         /*
420          * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength()
421          */
422         public int getTokenLength() {
423                 return length;
424         }
425
426         /*
427          * @see org.eclipse.jface.text.rules.ITokenScanner#setRange(IDocument, int,
428          *      int)
429          */
430         public void setRange(IDocument document, int offset, int length) {
431                 this.document = document;
432                 // this.begin = offset;
433                 this.end = offset + length;
434
435                 this.offset = offset;
436                 this.position = offset;
437                 this.length = 0;
438         }
439
440         /*
441          * @see org.eclipse.jface.text.rules.IPartitionTokenScanner
442          */
443         public void setPartialRange(IDocument document, int offset, int length,
444                         String contentType, int partitionOffset) {
445                 // state = STATE_DEFAULT;
446                 if (partitionOffset > -1) {
447                         int delta = offset - partitionOffset;
448                         if (delta > 0) {
449                                 setRange(document, partitionOffset, length + delta);
450                                 return;
451                         }
452                 }
453                 setRange(document, partitionOffset, length);
454         }
455
456         // private boolean isContinuationPartition(IDocument document, int offset) {
457         // try {
458         // String type = document.getContentType(offset - 1);
459         //
460         // if (type != IDocument.DEFAULT_CONTENT_TYPE) {
461         // return true;
462         // }
463         // } catch (BadLocationException e) {}
464         //
465         // return false;
466         // }
467 }