*** empty log message ***
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / php / PHPPartitionScanner.java
1 /**
2  * This program and the accompanying materials
3  * are made available under the terms of the Common Public License v1.0
4  * which accompanies this distribution, and is available at
5  * http://www.eclipse.org/legal/cpl-v10.html
6  * Created on 05.03.2003
7  *
8  * @author Stefan Langer (musk)
9  * @version $Revision: 1.15 $
10  */
11 package net.sourceforge.phpeclipse.phpeditor.php;
12
13 import java.util.*;
14
15 import org.eclipse.jface.text.*;
16 import org.eclipse.jface.text.rules.*;
17
18 /**
19  * 
20  */
21 public class PHPPartitionScanner implements IPartitionTokenScanner {
22   private static final boolean DEBUG = false;
23   private IDocument fDocument = null;
24   private int fOffset = -1;
25   private String fContentType = IPHPPartitionScannerConstants.HTML;
26   private String fPrevContentType;
27
28   private boolean partitionBorder = false;
29   private int fTokenOffset;
30   private int fEnd = -1;
31   private int fLength;
32   private Map tokens = new HashMap();
33
34   public PHPPartitionScanner() {
35     this.tokens.put(
36       IPHPPartitionScannerConstants.PHP,
37       new Token(IPHPPartitionScannerConstants.PHP));
38     this.tokens.put(
39       IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT,
40       new Token(IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT));
41     this.tokens.put(
42       IPHPPartitionScannerConstants.HTML,
43       new Token(IPHPPartitionScannerConstants.HTML));
44     this.tokens.put(
45       IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT,
46       new Token(IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT));
47     this.tokens.put(
48       IDocument.DEFAULT_CONTENT_TYPE,
49       new Token(IDocument.DEFAULT_CONTENT_TYPE));
50   }
51
52   private IToken getToken(String type) {
53     fLength = fOffset - fTokenOffset;
54     IToken token = (IToken) this.tokens.get(type);
55     Assert.isNotNull(token, "Token for type \"" + type + "\" not found!");
56     if (DEBUG) {
57       System.out.println(
58         "Partition: fTokenOffset="
59           + fTokenOffset
60           + " fContentType="
61           + fContentType
62           + " fLength="
63           + fLength);
64     }
65     return token;
66   }
67
68 /* (non-Javadoc)
69  * @see org.eclipse.jface.text.rules.IPartitionTokenScanner#setPartialRange(org.eclipse.jface.text.IDocument, int, int, java.lang.String, int)
70  */
71 public void setPartialRange(
72     IDocument document,
73     int offset,
74     int length,
75     String contentType,
76     int partitionOffset)
77 {
78     this.setRange(document, offset, length);
79     if (DEBUG)
80     {
81         System.out.println(
82             "PartialRange: contentType="
83                 + contentType
84                 + " partitionOffset="
85                 + partitionOffset);
86     }
87         
88         if(offset == partitionOffset)
89         {
90                 try
91         {
92             fContentType = fDocument.getContentType(offset);
93         }
94         catch (BadLocationException e)
95         {
96             //should never happen
97         }
98         }
99     else if (this.tokens.containsKey(contentType))
100         fContentType = contentType;
101     // TODO Calculate previouse contenttype
102     if (partitionOffset > -1)
103     {
104         partitionBorder = false;
105         fTokenOffset = partitionOffset;
106     }
107 }
108
109   /* (non-Javadoc)
110    * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength()
111    */
112   public int getTokenLength() {
113     return fLength;
114   }
115
116   /* (non-Javadoc)
117    * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset()
118    */
119   public int getTokenOffset() {
120     return fTokenOffset;
121   }
122
123 /* (non-Javadoc)
124  * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
125  */
126 public IToken nextToken()
127 {
128     int c;
129
130     // check if we are not allready at the end of the
131     // file
132     if ((c = read()) == ICharacterScanner.EOF)
133     {
134         partitionBorder = false;
135         return Token.EOF;
136     }
137     else
138         unread();
139
140     if (partitionBorder)
141     {
142         fTokenOffset = fOffset;
143         partitionBorder = false;
144     }
145
146     while ((c = read()) != ICharacterScanner.EOF)
147     {
148         switch (c)
149         {
150             case '<' :
151                 if (fContentType
152                     != IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT
153                     && checkPattern(new char[] { '?', 'p', 'h', 'p' }, true))
154                 {
155                     if (fContentType != IPHPPartitionScannerConstants.PHP
156                         && fOffset - 5 > 0)
157                     {
158                         fOffset -= 5;
159                         IToken token = getToken(fContentType);
160                         // save previouse contenttype
161                         fPrevContentType = fContentType;
162
163                         fContentType = IPHPPartitionScannerConstants.PHP;
164
165                         return token;
166                     }
167                     else
168                         fContentType = IPHPPartitionScannerConstants.PHP;
169
170                     // remember offset of this partition
171                     fTokenOffset = fOffset - 5;
172                 }
173                 else if (
174                     fContentType
175                         != IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT
176                     && checkPattern(new char[] { '?' }, false))
177                 {
178                     if (fContentType != IPHPPartitionScannerConstants.PHP
179                         && fOffset - 2 > 0)
180                     {
181                         fOffset -= 2;
182                             IToken token = getToken(fContentType);
183                 // save previouse contenttype
184                         fPrevContentType =
185                         fContentType;
186                             fContentType = IPHPPartitionScannerConstants.PHP;
187                             return token;
188                             }
189                     else
190                         fContentType = IPHPPartitionScannerConstants.PHP;
191             // remember offset of this partition
192                         fTokenOffset = fOffset - 2;
193                             }
194                 else if (checkPattern(new char[] { '!', '-', '-' }))
195                 { // return previouse partition
196                 if (
197                     fContentType
198                         != IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT
199                     && fOffset - 4 > 0)
200                     {
201                         fOffset -= 4;
202                             IToken token = getToken(fContentType);
203                             fContentType =
204                                 IPHPPartitionScannerConstants
205                                     .HTML_MULTILINE_COMMENT;
206                             return token;
207                             }
208                     else
209                         fContentType =
210                             IPHPPartitionScannerConstants
211                                 .HTML_MULTILINE_COMMENT;
212                             fTokenOffset = fOffset - 4;
213                             }
214                 break; case '?' :
215                 if (fContentType == IPHPPartitionScannerConstants.PHP)
216                 {
217                     if ((c = read()) == '>')
218                     { // TODO Actually calculate the previouse contenttype from the document
219                     if (
220                         fPrevContentType
221                         != null)
222                             fContentType = fPrevContentType; else
223                                 fContentType =
224                                     IPHPPartitionScannerConstants.HTML;
225                                     partitionBorder = true;
226                                     return getToken(
227                                         IPHPPartitionScannerConstants.PHP);
228                                     }
229                     else if (c != ICharacterScanner.EOF)
230                         unread(); }
231                 break; case '-' :
232                 if (fContentType
233                     == IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT
234                     && checkPattern(new char[] { '-', '>' }))
235                 {
236                     fContentType = IPHPPartitionScannerConstants.HTML;
237                         partitionBorder = true;
238                         return getToken(
239                             IPHPPartitionScannerConstants
240                                 .HTML_MULTILINE_COMMENT);
241                         }
242                 break; case '/' :
243                 if ((c = read()) == '*')
244                 { // MULTINE COMMENT JAVASCRIPT, CSS, PHP
245                 if (
246                     fContentType == IPHPPartitionScannerConstants.PHP
247                     && fOffset - 2 > 0)
248                     {
249                         fOffset -= 2;
250                             IToken token = getToken(fContentType);
251                             fContentType =
252                                 IPHPPartitionScannerConstants
253                                     .PHP_MULTILINE_COMMENT;
254                             return token;
255                             }
256                     else if (
257                         fContentType
258                             == IPHPPartitionScannerConstants
259                                 .PHP_MULTILINE_COMMENT)
260                     {
261
262                         fTokenOffset = fOffset - 2; }
263
264                 }
265                 else if (c != ICharacterScanner.EOF)
266                     unread(); break; case '*' :
267                         if ((c = read()) == '/')
268                         {
269                             if (fContentType
270                                 == IPHPPartitionScannerConstants
271                                     .PHP_MULTILINE_COMMENT)
272                             {
273                                 fContentType =
274                                     IPHPPartitionScannerConstants.PHP;
275                                     partitionBorder = true;
276                                     return getToken(
277                                         IPHPPartitionScannerConstants
278                                             .PHP_MULTILINE_COMMENT);
279                                     }
280                             else if (
281                                 fContentType
282                                     == IPHPPartitionScannerConstants
283                                         .CSS_MULTILINE_COMMENT)
284                             {
285                             }
286                             else if (
287                                 fContentType
288                                     == IPHPPartitionScannerConstants
289                                         .JS_MULTILINE_COMMENT)
290                             {
291                             }
292                         }
293                         else if (c != ICharacterScanner.EOF)
294                             unread(); break; }
295     } // end of file reached but we have to return the
296     // last partition.
297     return getToken(fContentType);
298         }
299   /* (non-Javadoc)
300    * @see org.eclipse.jface.text.rules.ITokenScanner#setRange(org.eclipse.jface.text.IDocument, int, int)
301    */
302   public void setRange(IDocument document, int offset, int length) {
303     if (DEBUG) {
304       System.out.println("SET RANGE: offset=" + offset + " length=" + length);
305     }
306
307     fDocument = document;
308     fOffset = offset;
309     fTokenOffset = offset;
310     fLength = 0;
311     fEnd = fOffset + length;
312     //partitionBorder = false;
313   }
314
315   private int read() {
316     try {
317       if (fOffset < fEnd) {
318         return fDocument.getChar(fOffset++);
319       }
320       return ICharacterScanner.EOF;
321     } catch (BadLocationException e) {
322       // should never happen
323       // TODO write stacktrace to log
324       fOffset = fEnd;
325       return ICharacterScanner.EOF;
326     }
327   }
328
329   private void unread() {
330     --fOffset;
331   }
332
333   private boolean checkPattern(char[] pattern) {
334     return checkPattern(pattern, false);
335   }
336
337   /**
338    * Check if next character sequence read from document is equals to 
339    * the provided pattern. Pattern is read from left to right until the 
340    * first character read doesn't match. If this happens all read characters are
341    * unread.
342    * @param pattern The pattern to check.
343    * @return <code>true</code> if pattern is equals else returns <code>false</code>.
344    */
345   private boolean checkPattern(char[] pattern, boolean ignoreCase) {
346     int prevOffset = fOffset;
347     for (int i = 0; i < pattern.length; i++) {
348       int c = read();
349
350       if (c == ICharacterScanner.EOF
351         || !letterEquals(c, pattern[i], ignoreCase)) {
352         fOffset = prevOffset;
353         return false;
354       }
355     }
356
357     return true;
358   }
359
360   private boolean letterEquals(int test, char letter, boolean ignoreCase) {
361     if (test == letter)
362       return true;
363     else if (
364       ignoreCase
365         && Character.isLowerCase(letter)
366         && test == Character.toUpperCase(letter))
367       return true;
368     else if (
369       ignoreCase
370         && Character.isUpperCase(letter)
371         && test == Character.toLowerCase(letter))
372       return true;
373
374     return false;
375   }
376
377 }