69bc1d5679ca62734bf01b9f6ca40bd3e6aae6fb
[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.26 2005-05-05 14:06:38 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.phpeclipse.ui.text.rules.AbstractPartitioner;
19
20 import org.eclipse.core.internal.indexing.AbstractPagePolicy;
21 import org.eclipse.jface.text.Assert;
22 import org.eclipse.jface.text.BadLocationException;
23 import org.eclipse.jface.text.IDocument;
24 import org.eclipse.jface.text.rules.ICharacterScanner;
25 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
26 import org.eclipse.jface.text.rules.IToken;
27 import org.eclipse.jface.text.rules.Token;
28
29 /**
30  * 
31  * 
32  * @author Igor Malinin
33  */
34 public class PHPPartitionScanner implements IPartitionTokenScanner {
35   //    public static final String JSP_DIRECTIVE = "__jsp_directive";
36   //    public static final String JSP_COMMENT = "__jsp_comment";
37   //// public static final String JSP_TAG = "__jsp_tag";
38   //    public static final String JSP_DECLARATION = "__jsp_declaration";
39   public static final String PHP_SCRIPTING_AREA = "__php_scripting_area ";
40
41   //    public static final String JSP_EXPRESSION = "__jsp_expression";
42
43   public static final int STATE_DEFAULT = 0;
44
45   //    public static final int STATE_TAG = 1;
46   //    public static final int STATE_SCRIPT = 2;
47
48   private IDocument document;
49
50   private int begin;
51
52   private int end;
53
54   private int offset;
55
56   private int length;
57
58   private int position;
59
60   private int state;
61
62   private Map tokens = new HashMap();
63
64   public PHPPartitionScanner() {
65   }
66
67   /*
68    * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
69    */
70   public IToken nextToken() {
71     offset += length;
72
73     /*
74      * switch (state) { case STATE_TAG: return nextTagToken(); }
75      */
76
77     switch (read()) {
78     case ICharacterScanner.EOF:
79       state = STATE_DEFAULT;
80       return getToken(null);
81
82     case '<':
83       switch (read()) {
84       case ICharacterScanner.EOF:
85         state = STATE_DEFAULT;
86         return getToken(null);
87
88       case '?': // <%SCRIPLET <%@DIRECTIVE <%!DECLARATION <%=EXPRESSION <%--COMMENT
89         int ch = read();
90         //                                               if (Character.isWhitespace((char)ch)) {
91         //                                                 return nextJSPToken(PHP_SCRIPTING_AREA);
92         //                                               }
93         switch (ch) {
94         case ICharacterScanner.EOF:
95           state = STATE_DEFAULT;
96           return getToken(PHP_SCRIPTING_AREA);
97
98         //                                                      case '-': // <%- <%--COMMENT
99         //                                                              switch (read()) {
100         //                                                                      case ICharacterScanner.EOF:
101         //                                                                      case '-': // <%--
102         //                                                                              return nextCommentToken();
103         //                                                              }
104         //
105         //                                                              break;
106         }
107
108         return scanUntilPHPEndToken(PHP_SCRIPTING_AREA);
109       }
110
111       unread();
112     }
113
114     loop: while (true) {
115       switch (read()) {
116       case ICharacterScanner.EOF:
117         state = STATE_DEFAULT;
118         return getToken(null);
119
120       case '<':
121         switch (read()) {
122         case ICharacterScanner.EOF:
123           state = STATE_DEFAULT;
124           return getToken(null);
125
126         case '?':
127           unread();
128           break;
129
130         case '<':
131           unread();
132
133         default:
134           continue loop;
135         }
136
137         unread();
138
139         state = STATE_DEFAULT;
140         return getToken(null);
141       }
142     }
143   }
144
145   private IToken scanUntilPHPEndToken(String token) {
146     int ch = read();
147     while (true) {
148       switch (ch) {
149       case ICharacterScanner.EOF:
150         state = STATE_DEFAULT;
151         return getToken(token);
152       case '"': // double quoted string
153         // read until end of double quoted string
154         if (!readUntilEscapedDQ()) {
155           state = STATE_DEFAULT;
156           return getToken(token);
157         }
158         break;
159       case '\'': // single quoted string
160         // read until end of single quoted string
161         if (!readUntilEscapedSQ()) {
162           state = STATE_DEFAULT;
163           return getToken(token);
164         }
165         break;
166       case '/': // comment start?
167         ch = read();
168         switch (ch) {
169         case ICharacterScanner.EOF:
170           break;
171         case '/':
172           // read until end of line
173           readSingleLine();
174           break;
175         case '*':
176           // read until end of comment
177           readMultiLineComment();
178           break;
179         default:
180           continue;
181         }
182         break;
183       case '#': // line comment
184         // read until end of line
185         readSingleLine();
186         break;
187       case '?':
188         ch = read();
189         switch (ch) {
190         case ICharacterScanner.EOF:
191         case '>':
192           state = STATE_DEFAULT;
193           return getToken(token);
194
195         case '?':
196           continue;
197         }
198       }
199
200       ch = read();
201     }
202   }
203
204   //    private IToken nextCommentToken() {
205   //            int ch = read();
206   //            loop: while (true) {
207   //                    switch (ch) {
208   //                            case ICharacterScanner.EOF:
209   //                                    break loop;
210   //
211   //                            case '-': // - --%>
212   //                                    ch = read();
213   //                                    switch (ch) {
214   //                                            case ICharacterScanner.EOF:
215   //                                                    break loop;
216   //
217   //                                            case '-': // -- --%>
218   //                                                    ch = read();
219   //                                                    switch (ch) {
220   //                                                            case ICharacterScanner.EOF:
221   //                                                                    break loop;
222   //
223   //                                                            case '%': // --% --%>
224   //                                                                    ch = read();
225   //                                                                    switch (ch) {
226   //                                                                            case ICharacterScanner.EOF:
227   //                                                                            case '>':
228   //                                                                                    break loop;
229   //                                                                    }
230   //
231   //                                                                    continue loop;
232   //
233   //                                                            case '-': // --- ---%>
234   //                                                                    unread();
235   //                                                                    continue loop;
236   //                                                    }
237   //
238   //                                                    ch = read();
239   //                                                    continue loop;
240   //                                    }
241   //                    }
242   //
243   //                    ch = read();
244   //            }
245   //
246   //            return getToken(JSP_COMMENT);
247   //    }
248
249   private IToken getToken(String type) {
250     length = position - offset;
251
252     if (length == 0) {
253       return Token.EOF;
254     }
255
256     if (type == null) {
257       return Token.UNDEFINED;
258     }
259
260     IToken token = (IToken) tokens.get(type);
261     if (token == null) {
262       token = new Token(type);
263       tokens.put(type, token);
264     }
265
266     return token;
267   }
268
269   private int read() {
270     if (position >= end) {
271       return ICharacterScanner.EOF;
272     }
273
274     try {
275       return document.getChar(position++);
276     } catch (BadLocationException e) {
277       --position;
278       return ICharacterScanner.EOF;
279     }
280   }
281
282   private boolean readUntilEscapedDQ() {
283     // search last double quoted character
284     if (position >= end) {
285       return false;
286     }
287     try {
288       char ch;
289       while (true) {
290         ch = document.getChar(position++);
291         if (ch == '\\') {
292           ch = document.getChar(position++); // ignore escaped character
293         } else if (ch == '"') {
294           return true;
295         }
296       }
297     } catch (BadLocationException e) {
298       --position;
299     }
300     return false;
301   }
302   
303   private boolean readUntilEscapedSQ() {
304     // search last single quoted character
305     if (position >= end) {
306       return false;
307     }
308     try {  
309       char ch;
310       while (true) {
311         ch = document.getChar(position++); 
312         if (ch == '\\') {
313           ch = document.getChar(position++); // ignore escaped character
314         } else if (ch == '\'') {
315           return true;
316         }
317       }
318     } catch (BadLocationException e) {
319       --position;
320     }
321     return false;
322   }
323
324   private void readSingleLine() {
325     if (position >= end) {
326       return;
327     }
328     try {
329       while (document.getChar(position++) != '\n') {
330
331       }
332     } catch (BadLocationException e) {
333       --position;
334       return;
335     }
336   }
337
338   private void readMultiLineComment() {
339     if (position >= end) {
340       return;
341     }
342     try {
343       char ch;
344       while (true) {
345         ch = document.getChar(position++);
346         if (ch == '*') {
347           if (document.getChar(position) == '/') {
348             position++;
349             break;
350           }
351         }
352       }
353     } catch (BadLocationException e) {
354       --position;
355       return;
356     }
357   }
358
359   private void unread() {
360     --position;
361   }
362
363   /*
364    * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset()
365    */
366   public int getTokenOffset() {
367     if (AbstractPartitioner.DEBUG) {
368       Assert.isTrue(offset >= 0, Integer.toString(offset));
369     }
370     return offset;
371   }
372
373   /*
374    * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength()
375    */
376   public int getTokenLength() {
377     return length;
378   }
379
380   /*
381    * @see org.eclipse.jface.text.rules.ITokenScanner#setRange(IDocument, int, int)
382    */
383   public void setRange(IDocument document, int offset, int length) {
384     this.document = document;
385     this.begin = offset;
386     this.end = offset + length;
387
388     this.offset = offset;
389     this.position = offset;
390     this.length = 0;
391   }
392
393   /*
394    * @see org.eclipse.jface.text.rules.IPartitionTokenScanner
395    */
396   public void setPartialRange(IDocument document, int offset, int length, String contentType, int partitionOffset) {
397     state = STATE_DEFAULT;
398     //    if (partitionOffset > -1) {
399     //          int delta= offset - partitionOffset;
400     //          if (delta > 0) {
401     //                  this.setRange(document, partitionOffset, length + delta);
402     //                  return;
403     //          }
404     //  }
405     setRange(document, partitionOffset, length);
406   }
407
408   //    private boolean isContinuationPartition(IDocument document, int offset) {
409   //            try {
410   //                    String type = document.getContentType(offset - 1);
411   //
412   //                    if (type != IDocument.DEFAULT_CONTENT_TYPE) {
413   //                            return true;
414   //                    }
415   //            } catch (BadLocationException e) {}
416   //
417   //            return false;
418   //    }
419 }