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