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