Added PHPDoc Scanner and Code Completion Processor
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / php / PHPPartitionScanner.java
1 /**********************************************************************
2 Copyright (c) 2000, 2002 IBM Corp. 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://www.eclipse.org/legal/cpl-v10.html
7
8 Contributors:
9     IBM Corporation - Initial implementation
10     Klaus Hartlage - www.eclipseproject.de
11 **********************************************************************/
12 package net.sourceforge.phpeclipse.phpeditor.php;
13
14 import java.util.ArrayList;
15 import java.util.List;
16
17 import org.eclipse.jface.text.rules.ICharacterScanner;
18 import org.eclipse.jface.text.rules.IPredicateRule;
19 import org.eclipse.jface.text.rules.IToken;
20 import org.eclipse.jface.text.rules.MultiLineRule;
21 import org.eclipse.jface.text.rules.RuleBasedPartitionScanner;
22 import org.eclipse.jface.text.rules.Token;
23
24 /**
25  * This scanner recognizes the JavaDoc comments and Java multi line comments.
26  */
27 public class PHPPartitionScanner extends RuleBasedPartitionScanner implements IPHPPartitionScannerConstants {
28
29  // private final static String SKIP = "__skip"; //$NON-NLS-1$
30  
31 //  public final static String HTML_MULTILINE_COMMENT = "__html_multiline_comment"; //$NON-NLS-1$
32 //  //  public final static String JAVA_DOC= "__java_javadoc"; //$NON-NLS-1$
33 //  public final static String PHP = "__php"; //$NON-NLS-1$
34 //  //public final static String HTML = "__html"; //$NON-NLS-1$
35
36   public final static IToken php = new Token(PHP);
37   //public final static IToken html = new Token(HTML);
38   public final static IToken comment = new Token(HTML_MULTILINE_COMMENT);
39
40   protected final static char[] php0EndSequence = { '<', '?' };
41   protected final static char[] php1EndSequence = { '<', '?', 'p', 'h', 'p' };
42   protected final static char[] php2EndSequence = { '<', '?', 'P', 'H', 'P' };
43
44   private StringBuffer test;
45
46   public class PHPMultiLineRule extends MultiLineRule {
47
48     public PHPMultiLineRule(String startSequence, String endSequence, IToken token) {
49       super(startSequence, endSequence, token);
50     }
51
52     public PHPMultiLineRule(String startSequence, String endSequence, IToken token, char escapeCharacter) {
53       super(startSequence, endSequence, token, escapeCharacter);
54     }
55
56     protected boolean endSequenceDetected(ICharacterScanner scanner) {
57       int c;
58       int c2;
59
60       boolean lineCommentMode = false;
61       boolean multiLineCommentMode = false;
62       boolean stringMode = false;
63
64       char[][] delimiters = scanner.getLegalLineDelimiters();
65       while ((c = scanner.read()) != ICharacterScanner.EOF) {
66         if (c == '#') {
67           // read until end of line
68           while ((c = scanner.read()) != ICharacterScanner.EOF) {
69             if (fEndSequence.length > 0 && c == fEndSequence[0]) {
70               // Check if the specified end sequence has been found.
71               if (sequenceDetected(scanner, fEndSequence, true))
72                 return true;
73             } else if (c == '\n') {
74               break;
75             }
76           }
77           continue;
78         } else if (c == '/' && (c = scanner.read()) != ICharacterScanner.EOF) {
79           if (c == '/') {
80             // read until end of line
81             while ((c = scanner.read()) != ICharacterScanner.EOF) {
82               if (fEndSequence.length > 0 && c == fEndSequence[0]) {
83                 // Check if the specified end sequence has been found.
84                 if (sequenceDetected(scanner, fEndSequence, true))
85                   return true;
86               } else if (c == '\n') {
87                 break;
88               }
89             }
90             continue;
91           } else if (c == '*') {
92             // multi-line comment
93             while ((c = scanner.read()) != ICharacterScanner.EOF) {
94               if (c == '*' && (c = scanner.read()) != ICharacterScanner.EOF) {
95                 if (c == '/') {
96                   break;
97                 }
98                 scanner.unread();
99               }
100             }
101
102             continue;
103           } else {
104             scanner.unread();
105           }
106         } else if (c == '"') {
107           // string mode
108           while ((c = scanner.read()) != ICharacterScanner.EOF) {
109             if (c == '\\') {
110               c = scanner.read();
111             } else if (c == '"') {
112               break;
113             }
114           }
115           continue;
116         } else if (c == '\'') {
117           // string mode
118           while ((c = scanner.read()) != ICharacterScanner.EOF) {
119             if (c == '\\') {
120               c = scanner.read();
121             } else if (c == '\'') {
122               break;
123             }
124           }
125           continue;
126         }
127
128         if (c == fEscapeCharacter) {
129           // Skip the escaped character.
130           scanner.read();
131         } else if (fEndSequence.length > 0 && c == fEndSequence[0]) {
132           // Check if the specified end sequence has been found.
133           if (sequenceDetected(scanner, fEndSequence, true))
134             return true;
135         } else if (fBreaksOnEOL) {
136           // Check for end of line since it can be used to terminate the pattern.
137           for (int i = 0; i < delimiters.length; i++) {
138             if (c == delimiters[i][0] && sequenceDetected(scanner, delimiters[i], false))
139               return true;
140           }
141         }
142       } 
143       boolean phpMode = false;
144       if (c == ICharacterScanner.EOF) {
145         phpMode = true;
146       }
147       scanner.unread();
148       return phpMode;
149     }
150   }
151
152   //  public class HTMLMultiLineRule extends MultiLineRule {
153   //
154   //    public HTMLMultiLineRule(String startSequence, String endSequence, IToken token) {
155   //      super(startSequence, endSequence, token);
156   //    }
157   //
158   //    public HTMLMultiLineRule(String startSequence, String endSequence, IToken token, char escapeCharacter) {
159   //      super(startSequence, endSequence, token, escapeCharacter);
160   //    }
161   //
162   //    protected boolean endSequenceDetected(ICharacterScanner scanner) {
163   //      int c;
164   //
165   //      char[][] delimiters = scanner.getLegalLineDelimiters();
166   //      while ((c = scanner.read()) != ICharacterScanner.EOF) {
167   //        if (c == '<') {
168   //          //       scanner.unread();
169   //          if (sequenceDetected(scanner, php2EndSequence, true)) {
170   //            // <?PHP
171   //            scanner.unread();
172   //            scanner.unread();
173   //            scanner.unread();
174   //            scanner.unread();
175   //            scanner.unread();
176   //            return true;
177   //          }
178   //          if (sequenceDetected(scanner, php1EndSequence, true)) {
179   //            // <?php
180   //            scanner.unread();
181   //            scanner.unread();
182   //            scanner.unread();
183   //            scanner.unread();
184   //            scanner.unread();
185   //            return true;
186   //          }
187   //          if (sequenceDetected(scanner, php0EndSequence, true)) {
188   //            // <?
189   //            scanner.unread();
190   //            scanner.unread();
191   //            return true;
192   //          }
193   //          //      scanner.read();
194   //        }
195   //
196   //      }
197   //      scanner.unread();
198   //      return false;
199   //    }
200   //
201   //    protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) {
202   //
203   //      if (resume) {
204   //
205   //        if (endSequenceDetected(scanner))
206   //          return fToken;
207   //
208   //      } else {
209   //
210   //        int c = scanner.read();
211   //        //     if (c == fStartSequence[0]) {
212   //        //       if (sequenceDetected(scanner, fStartSequence, false)) {
213   //        if (endSequenceDetected(scanner))
214   //          return fToken;
215   //        //       }
216   //        //     }
217   //      }
218   //
219   //      scanner.unread();
220   //      return Token.UNDEFINED;
221   //    }
222   //
223   //    public IToken evaluate(ICharacterScanner scanner, boolean resume) {
224   //      if (fColumn == UNDEFINED)
225   //        return doEvaluate(scanner, resume);
226   //
227   //      int c = scanner.read();
228   //      scanner.unread();
229   //      //    if (c == fStartSequence[0])
230   //      return (fColumn == scanner.getColumn() ? doEvaluate(scanner, resume) : Token.UNDEFINED);
231   //      //    else
232   //      //      return Token.UNDEFINED;
233   //    }
234   //  }
235
236 //  public class HTMLPatternRule implements IPredicateRule {
237 //
238 //    protected static final int UNDEFINED = -1;
239 //
240 //    /** The token to be returned on success */
241 //    protected IToken fToken;
242 //
243 //    /** The pattern's column constrain */
244 //    protected int fColumn = UNDEFINED;
245 //    /** The pattern's escape character */
246 //    protected char fEscapeCharacter;
247 //    /** Indicates whether end of line termines the pattern */
248 //    protected boolean fBreaksOnEOL;
249 //
250 //    /**
251 //     * Creates a rule for the given starting and ending sequence.
252 //     * When these sequences are detected the rule will return the specified token.
253 //     * Alternatively, the sequence can also be ended by the end of the line.
254 //     * Any character which follows the given escapeCharacter will be ignored.
255 //     *
256 //     * @param startSequence the pattern's start sequence
257 //     * @param endSequence the pattern's end sequence, <code>null</code> is a legal value
258 //     * @param token the token which will be returned on success
259 //     * @param escapeCharacter any character following this one will be ignored
260 //     * @param indicates whether the end of the line also termines the pattern
261 //     */
262 //    public HTMLPatternRule(IToken token) {
263 //      fToken = token;
264 //      fEscapeCharacter = (char) 0;
265 //      fBreaksOnEOL = false;
266 //    }
267 //
268 //    /**
269 //     * Sets a column constraint for this rule. If set, the rule's token
270 //     * will only be returned if the pattern is detected starting at the 
271 //     * specified column. If the column is smaller then 0, the column
272 //     * constraint is considered removed.
273 //     *
274 //     * @param column the column in which the pattern starts
275 //     */
276 //    public void setColumnConstraint(int column) {
277 //      if (column < 0)
278 //        column = UNDEFINED;
279 //      fColumn = column;
280 //    }
281 //
282 //    /**
283 //     * Evaluates this rules without considering any column constraints.
284 //     *
285 //     * @param scanner the character scanner to be used
286 //     * @return the token resulting from this evaluation
287 //     */
288 //    protected IToken doEvaluate(ICharacterScanner scanner) {
289 //      return doEvaluate(scanner, false);
290 //    }
291 //
292 //    /**
293 //     * Evaluates this rules without considering any column constraints. Resumes
294 //     * detection, i.e. look sonly for the end sequence required by this rule if the
295 //     * <code>resume</code> flag is set.
296 //     *
297 //     * @param scanner the character scanner to be used
298 //     * @param resume <code>true</code> if detection should be resumed, <code>false</code> otherwise
299 //     * @return the token resulting from this evaluation
300 //     * @since 2.0
301 //     */
302 //    protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) {
303 //
304 //      if (resume) {
305 //
306 //        if (endSequenceDetected(scanner))
307 //          return fToken;
308 //
309 //      } else {
310 //
311 //        int c = scanner.read();
312 //        //      if (c == fStartSequence[0]) {
313 //        //        if (sequenceDetected(scanner, fStartSequence, false)) {
314 //        if (endSequenceDetected(scanner))
315 //          return fToken;
316 //        //        }
317 //        //      }
318 //      }
319 //
320 //      scanner.unread();
321 //      return Token.UNDEFINED;
322 //    }
323 //
324 //    /*
325 //     * @see IRule#evaluate
326 //     */
327 //    public IToken evaluate(ICharacterScanner scanner) {
328 //      return evaluate(scanner, false);
329 //    }
330 //
331 //    /**
332 //     * Returns whether the end sequence was detected. As the pattern can be considered 
333 //     * ended by a line delimiter, the result of this method is <code>true</code> if the 
334 //     * rule breaks on the end  of the line, or if the EOF character is read.
335 //     *
336 //     * @param scanner the character scanner to be used
337 //     * @return <code>true</code> if the end sequence has been detected
338 //     */
339 //    protected boolean endSequenceDetected(ICharacterScanner scanner) {
340 //      int c;
341 //
342 //      char[][] delimiters = scanner.getLegalLineDelimiters();
343 //      while ((c = scanner.read()) != ICharacterScanner.EOF) {
344 //        if (c == '<') {
345 //          //       scanner.unread();
346 //          if (sequenceDetected(scanner, php2EndSequence, true)) {
347 //            // <?PHP
348 //            scanner.unread();
349 //            scanner.unread();
350 //            scanner.unread();
351 //            scanner.unread();
352 //            scanner.unread();
353 //            return true;
354 //          }
355 //          if (sequenceDetected(scanner, php1EndSequence, true)) {
356 //            // <?php
357 //            scanner.unread();
358 //            scanner.unread();
359 //            scanner.unread();
360 //            scanner.unread();
361 //            scanner.unread();
362 //            return true;
363 //          }
364 //          if (sequenceDetected(scanner, php0EndSequence, true)) {
365 //            // <?
366 //            scanner.unread();
367 //            scanner.unread();
368 //            return true;
369 //          }
370 //          //      scanner.read();
371 //        }
372 //
373 //      }
374 //      scanner.unread();
375 //      return false;
376 //    }
377 //
378 //    /**
379 //     * Returns whether the next characters to be read by the character scanner
380 //     * are an exact match with the given sequence. No escape characters are allowed 
381 //     * within the sequence. If specified the sequence is considered to be found
382 //     * when reading the EOF character.
383 //     *
384 //     * @param scanner the character scanner to be used
385 //     * @param sequence the sequence to be detected
386 //     * @param eofAllowed indicated whether EOF terminates the pattern
387 //     * @return <code>true</code> if the given sequence has been detected
388 //     */
389 //    protected boolean sequenceDetected(ICharacterScanner scanner, char[] sequence, boolean eofAllowed) {
390 //      for (int i = 1; i < sequence.length; i++) {
391 //        int c = scanner.read();
392 //        if (c == ICharacterScanner.EOF && eofAllowed) {
393 //          return true;
394 //        } else if (c != sequence[i]) {
395 //          // Non-matching character detected, rewind the scanner back to the start.
396 //          scanner.unread();
397 //          for (int j = i - 1; j > 0; j--)
398 //            scanner.unread();
399 //          return false;
400 //        }
401 //      }
402 //
403 //      return true;
404 //    }
405 //
406 //    /*
407 //     * @see IPredicateRule#evaluate(ICharacterScanner, boolean)
408 //     * @since 2.0
409 //     */
410 //    public IToken evaluate(ICharacterScanner scanner, boolean resume) {
411 //      if (fColumn == UNDEFINED)
412 //        return doEvaluate(scanner, resume);
413 //
414 //      int c = scanner.read();
415 //      scanner.unread();
416 //      //    if (c == fStartSequence[0])
417 //      return (fColumn == scanner.getColumn() ? doEvaluate(scanner, resume) : Token.UNDEFINED);
418 //      //    else
419 //      //      return Token.UNDEFINED;
420 //    }
421 //
422 //    /*
423 //     * @see IPredicateRule#getSuccessToken()
424 //     * @since 2.0
425 //     */
426 //    public IToken getSuccessToken() {
427 //      return fToken;
428 //    }
429 //  }
430   /**
431    * Detector for empty comments.
432    */
433 //  static class EmptyCommentDetector implements IWordDetector {
434 //
435 //    /* (non-Javadoc)
436 //    * Method declared on IWordDetector
437 //      */
438 //    public boolean isWordStart(char c) {
439 //      return (c == '/');
440 //    }
441 //
442 //    /* (non-Javadoc)
443 //    * Method declared on IWordDetector
444 //      */
445 //    public boolean isWordPart(char c) {
446 //      return (c == '*' || c == '/');
447 //    }
448 //  };
449
450   /**
451    * 
452    */
453 //  static class WordPredicateRule extends WordRule implements IPredicateRule {
454 //
455 //    private IToken fSuccessToken;
456 //
457 //    public WordPredicateRule(IToken successToken) {
458 //      super(new EmptyCommentDetector());
459 //      fSuccessToken = successToken;
460 //      addWord("/**/", fSuccessToken);
461 //    }
462 //
463 //    /*
464 //     * @see org.eclipse.jface.text.rules.IPredicateRule#evaluate(ICharacterScanner, boolean)
465 //     */
466 //    public IToken evaluate(ICharacterScanner scanner, boolean resume) {
467 //      return super.evaluate(scanner);
468 //    }
469 //
470 //    /*
471 //     * @see org.eclipse.jface.text.rules.IPredicateRule#getSuccessToken()
472 //     */
473 //    public IToken getSuccessToken() {
474 //      return fSuccessToken;
475 //    }
476 //  };
477
478   /**
479    * Creates the partitioner and sets up the appropriate rules.
480    */
481   public PHPPartitionScanner() {
482     super();
483
484     //    IToken php = new Token(PHP);
485     //    IToken html = new Token(HTML);
486     //    IToken comment = new Token(HTML_MULTILINE_COMMENT);
487
488     List rules = new ArrayList();
489
490     // Add rule for single line comments.
491     //  rules.add(new EndOfLineRule("//", Token.UNDEFINED));
492
493     // Add rule for strings and character constants.
494     //          rules.add(new SingleLineRule("\"", "\"", Token.UNDEFINED, '\\'));
495     //  rules.add(new SingleLineRule("'", "'", Token.UNDEFINED, '\\')); 
496
497     // Add special case word rule.
498     //    rules.add(new WordPredicateRule(comment));
499
500     // Add rules for multi-line comments and javadoc.
501     //rules.add(new MultiLineRule("/**", "*/", javaDoc));
502     //  rules.add(new HTMLMultiLineRule("<", "<?", html));
503
504     rules.add(new MultiLineRule("<!--", "-->", comment));
505     rules.add(new PHPMultiLineRule("<?\r", "?>", php));
506     rules.add(new PHPMultiLineRule("<?\n", "?>", php));
507     rules.add(new PHPMultiLineRule("<?\t", "?>", php));
508     rules.add(new PHPMultiLineRule("<? ", "?>", php));
509
510     rules.add(new PHPMultiLineRule("<?php", "?>", php));
511     rules.add(new PHPMultiLineRule("<?PHP", "?>", php));
512
513     rules.add(new PHPMultiLineRule("<?pHP", "?>", php));
514     rules.add(new PHPMultiLineRule("<?PhP", "?>", php));
515     rules.add(new PHPMultiLineRule("<?PHp", "?>", php));
516
517     rules.add(new PHPMultiLineRule("<?Php", "?>", php));
518     rules.add(new PHPMultiLineRule("<?pHp", "?>", php));
519     rules.add(new PHPMultiLineRule("<?phP", "?>", php));
520     //    rules.add(new HTMLPatternRule(html)); // "<", "<?",
521     //Add rule for processing instructions
522
523     IPredicateRule[] result = new IPredicateRule[rules.size()];
524     rules.toArray(result);
525     setPredicateRules(result);
526    // setDefaultReturnToken(html);
527   }
528
529   //    public IToken nextToken() {
530   //      
531   //      if (fContentType == null || fRules == null)
532   //        return getNextToken();
533   //      
534   //      fTokenOffset= fOffset;
535   //      fColumn= UNDEFINED;
536   //      boolean resume= (fPartitionOffset < fOffset);
537   //          
538   //      IPredicateRule rule;
539   //      IToken token;
540   //      
541   //      for (int i= 0; i < fRules.length; i++) {
542   //        rule= (IPredicateRule) fRules[i];
543   //        token= rule.getSuccessToken();
544   //        if (fContentType.equals(token.getData())) {
545   //          if (resume)
546   //            fTokenOffset= fPartitionOffset;
547   //          token= rule.evaluate(this, resume);
548   //          if (!token.isUndefined()) {
549   //            fContentType= null;
550   //            return token;
551   //          }
552   //        }
553   //      }
554   //      
555   //      fContentType= null;
556   //      return getNextToken();
557   //    }
558   //    
559   //    public IToken getNextToken() {
560   //      
561   //      IToken token;
562   //      
563   //      while (true) {
564   //        
565   //        fTokenOffset= fOffset;
566   //        fColumn= UNDEFINED;
567   //        
568   //        if (fRules != null) {
569   //          for (int i= 0; i < fRules.length; i++) {
570   //            token= (fRules[i].evaluate(this));
571   //            if (!token.isUndefined())
572   //              return token;
573   //          }
574   //        }
575   //        
576   //        if (read() == EOF)
577   //          return Token.EOF;
578   //        else
579   //          return fDefaultReturnToken;
580   //      }
581   //    }
582 }