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