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
9 IBM Corporation - Initial implementation
10 Klaus Hartlage - www.eclipseproject.de
11 **********************************************************************/
12 package net.sourceforge.phpeclipse.phpeditor.php;
14 import java.util.ArrayList;
15 import java.util.List;
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;
25 * This scanner recognizes the JavaDoc comments and Java multi line comments.
27 public class PHPPartitionScanner extends RuleBasedPartitionScanner {
29 private final static String SKIP = "__skip"; //$NON-NLS-1$
30 public final static String HTML_MULTILINE_COMMENT = "__html_multiline_comment"; //$NON-NLS-1$
31 // public final static String JAVA_DOC= "__java_javadoc"; //$NON-NLS-1$
32 public final static String PHP = "__php"; //$NON-NLS-1$
33 //public final static String HTML = "__html"; //$NON-NLS-1$
35 public final static IToken php = new Token(PHP);
36 //public final static IToken html = new Token(HTML);
37 public final static IToken comment = new Token(HTML_MULTILINE_COMMENT);
39 protected final static char[] php0EndSequence = { '<', '?' };
40 protected final static char[] php1EndSequence = { '<', '?', 'p', 'h', 'p' };
41 protected final static char[] php2EndSequence = { '<', '?', 'P', 'H', 'P' };
43 private StringBuffer test;
45 public class PHPMultiLineRule extends MultiLineRule {
47 public PHPMultiLineRule(String startSequence, String endSequence, IToken token) {
48 super(startSequence, endSequence, token);
51 public PHPMultiLineRule(String startSequence, String endSequence, IToken token, char escapeCharacter) {
52 super(startSequence, endSequence, token, escapeCharacter);
55 protected boolean endSequenceDetected(ICharacterScanner scanner) {
59 boolean lineCommentMode = false;
60 boolean multiLineCommentMode = false;
61 boolean stringMode = false;
63 char[][] delimiters = scanner.getLegalLineDelimiters();
64 while ((c = scanner.read()) != ICharacterScanner.EOF) {
66 // read until end of line
67 while ((c = scanner.read()) != ICharacterScanner.EOF) {
68 if (fEndSequence.length > 0 && c == fEndSequence[0]) {
69 // Check if the specified end sequence has been found.
70 if (sequenceDetected(scanner, fEndSequence, true))
72 } else if (c == '\n') {
77 } else if (c == '/' && (c = scanner.read()) != ICharacterScanner.EOF) {
79 // read until end of line
80 while ((c = scanner.read()) != ICharacterScanner.EOF) {
81 if (fEndSequence.length > 0 && c == fEndSequence[0]) {
82 // Check if the specified end sequence has been found.
83 if (sequenceDetected(scanner, fEndSequence, true))
85 } else if (c == '\n') {
90 } else if (c == '*') {
92 while ((c = scanner.read()) != ICharacterScanner.EOF) {
93 if (c == '*' && (c = scanner.read()) != ICharacterScanner.EOF) {
105 } else if (c == '"') {
107 while ((c = scanner.read()) != ICharacterScanner.EOF) {
110 } else if (c == '"') {
115 } else if (c == '\'') {
117 while ((c = scanner.read()) != ICharacterScanner.EOF) {
120 } else if (c == '\'') {
127 if (c == fEscapeCharacter) {
128 // Skip the escaped character.
130 } else if (fEndSequence.length > 0 && c == fEndSequence[0]) {
131 // Check if the specified end sequence has been found.
132 if (sequenceDetected(scanner, fEndSequence, true))
134 } else if (fBreaksOnEOL) {
135 // Check for end of line since it can be used to terminate the pattern.
136 for (int i = 0; i < delimiters.length; i++) {
137 if (c == delimiters[i][0] && sequenceDetected(scanner, delimiters[i], false))
142 boolean phpMode = false;
143 if (c == ICharacterScanner.EOF) {
151 // public class HTMLMultiLineRule extends MultiLineRule {
153 // public HTMLMultiLineRule(String startSequence, String endSequence, IToken token) {
154 // super(startSequence, endSequence, token);
157 // public HTMLMultiLineRule(String startSequence, String endSequence, IToken token, char escapeCharacter) {
158 // super(startSequence, endSequence, token, escapeCharacter);
161 // protected boolean endSequenceDetected(ICharacterScanner scanner) {
164 // char[][] delimiters = scanner.getLegalLineDelimiters();
165 // while ((c = scanner.read()) != ICharacterScanner.EOF) {
167 // // scanner.unread();
168 // if (sequenceDetected(scanner, php2EndSequence, true)) {
177 // if (sequenceDetected(scanner, php1EndSequence, true)) {
186 // if (sequenceDetected(scanner, php0EndSequence, true)) {
192 // // scanner.read();
200 // protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) {
204 // if (endSequenceDetected(scanner))
209 // int c = scanner.read();
210 // // if (c == fStartSequence[0]) {
211 // // if (sequenceDetected(scanner, fStartSequence, false)) {
212 // if (endSequenceDetected(scanner))
219 // return Token.UNDEFINED;
222 // public IToken evaluate(ICharacterScanner scanner, boolean resume) {
223 // if (fColumn == UNDEFINED)
224 // return doEvaluate(scanner, resume);
226 // int c = scanner.read();
228 // // if (c == fStartSequence[0])
229 // return (fColumn == scanner.getColumn() ? doEvaluate(scanner, resume) : Token.UNDEFINED);
231 // // return Token.UNDEFINED;
235 // public class HTMLPatternRule implements IPredicateRule {
237 // protected static final int UNDEFINED = -1;
239 // /** The token to be returned on success */
240 // protected IToken fToken;
242 // /** The pattern's column constrain */
243 // protected int fColumn = UNDEFINED;
244 // /** The pattern's escape character */
245 // protected char fEscapeCharacter;
246 // /** Indicates whether end of line termines the pattern */
247 // protected boolean fBreaksOnEOL;
250 // * Creates a rule for the given starting and ending sequence.
251 // * When these sequences are detected the rule will return the specified token.
252 // * Alternatively, the sequence can also be ended by the end of the line.
253 // * Any character which follows the given escapeCharacter will be ignored.
255 // * @param startSequence the pattern's start sequence
256 // * @param endSequence the pattern's end sequence, <code>null</code> is a legal value
257 // * @param token the token which will be returned on success
258 // * @param escapeCharacter any character following this one will be ignored
259 // * @param indicates whether the end of the line also termines the pattern
261 // public HTMLPatternRule(IToken token) {
263 // fEscapeCharacter = (char) 0;
264 // fBreaksOnEOL = false;
268 // * Sets a column constraint for this rule. If set, the rule's token
269 // * will only be returned if the pattern is detected starting at the
270 // * specified column. If the column is smaller then 0, the column
271 // * constraint is considered removed.
273 // * @param column the column in which the pattern starts
275 // public void setColumnConstraint(int column) {
277 // column = UNDEFINED;
282 // * Evaluates this rules without considering any column constraints.
284 // * @param scanner the character scanner to be used
285 // * @return the token resulting from this evaluation
287 // protected IToken doEvaluate(ICharacterScanner scanner) {
288 // return doEvaluate(scanner, false);
292 // * Evaluates this rules without considering any column constraints. Resumes
293 // * detection, i.e. look sonly for the end sequence required by this rule if the
294 // * <code>resume</code> flag is set.
296 // * @param scanner the character scanner to be used
297 // * @param resume <code>true</code> if detection should be resumed, <code>false</code> otherwise
298 // * @return the token resulting from this evaluation
301 // protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) {
305 // if (endSequenceDetected(scanner))
310 // int c = scanner.read();
311 // // if (c == fStartSequence[0]) {
312 // // if (sequenceDetected(scanner, fStartSequence, false)) {
313 // if (endSequenceDetected(scanner))
320 // return Token.UNDEFINED;
324 // * @see IRule#evaluate
326 // public IToken evaluate(ICharacterScanner scanner) {
327 // return evaluate(scanner, false);
331 // * Returns whether the end sequence was detected. As the pattern can be considered
332 // * ended by a line delimiter, the result of this method is <code>true</code> if the
333 // * rule breaks on the end of the line, or if the EOF character is read.
335 // * @param scanner the character scanner to be used
336 // * @return <code>true</code> if the end sequence has been detected
338 // protected boolean endSequenceDetected(ICharacterScanner scanner) {
341 // char[][] delimiters = scanner.getLegalLineDelimiters();
342 // while ((c = scanner.read()) != ICharacterScanner.EOF) {
344 // // scanner.unread();
345 // if (sequenceDetected(scanner, php2EndSequence, true)) {
354 // if (sequenceDetected(scanner, php1EndSequence, true)) {
363 // if (sequenceDetected(scanner, php0EndSequence, true)) {
369 // // scanner.read();
378 // * Returns whether the next characters to be read by the character scanner
379 // * are an exact match with the given sequence. No escape characters are allowed
380 // * within the sequence. If specified the sequence is considered to be found
381 // * when reading the EOF character.
383 // * @param scanner the character scanner to be used
384 // * @param sequence the sequence to be detected
385 // * @param eofAllowed indicated whether EOF terminates the pattern
386 // * @return <code>true</code> if the given sequence has been detected
388 // protected boolean sequenceDetected(ICharacterScanner scanner, char[] sequence, boolean eofAllowed) {
389 // for (int i = 1; i < sequence.length; i++) {
390 // int c = scanner.read();
391 // if (c == ICharacterScanner.EOF && eofAllowed) {
393 // } else if (c != sequence[i]) {
394 // // Non-matching character detected, rewind the scanner back to the start.
396 // for (int j = i - 1; j > 0; j--)
406 // * @see IPredicateRule#evaluate(ICharacterScanner, boolean)
409 // public IToken evaluate(ICharacterScanner scanner, boolean resume) {
410 // if (fColumn == UNDEFINED)
411 // return doEvaluate(scanner, resume);
413 // int c = scanner.read();
415 // // if (c == fStartSequence[0])
416 // return (fColumn == scanner.getColumn() ? doEvaluate(scanner, resume) : Token.UNDEFINED);
418 // // return Token.UNDEFINED;
422 // * @see IPredicateRule#getSuccessToken()
425 // public IToken getSuccessToken() {
430 * Detector for empty comments.
432 // static class EmptyCommentDetector implements IWordDetector {
435 // * Method declared on IWordDetector
437 // public boolean isWordStart(char c) {
438 // return (c == '/');
442 // * Method declared on IWordDetector
444 // public boolean isWordPart(char c) {
445 // return (c == '*' || c == '/');
452 // static class WordPredicateRule extends WordRule implements IPredicateRule {
454 // private IToken fSuccessToken;
456 // public WordPredicateRule(IToken successToken) {
457 // super(new EmptyCommentDetector());
458 // fSuccessToken = successToken;
459 // addWord("/**/", fSuccessToken);
463 // * @see org.eclipse.jface.text.rules.IPredicateRule#evaluate(ICharacterScanner, boolean)
465 // public IToken evaluate(ICharacterScanner scanner, boolean resume) {
466 // return super.evaluate(scanner);
470 // * @see org.eclipse.jface.text.rules.IPredicateRule#getSuccessToken()
472 // public IToken getSuccessToken() {
473 // return fSuccessToken;
478 * Creates the partitioner and sets up the appropriate rules.
480 public PHPPartitionScanner() {
483 // IToken php = new Token(PHP);
484 // IToken html = new Token(HTML);
485 // IToken comment = new Token(HTML_MULTILINE_COMMENT);
487 List rules = new ArrayList();
489 // Add rule for single line comments.
490 // rules.add(new EndOfLineRule("//", Token.UNDEFINED));
492 // Add rule for strings and character constants.
493 // rules.add(new SingleLineRule("\"", "\"", Token.UNDEFINED, '\\'));
494 // rules.add(new SingleLineRule("'", "'", Token.UNDEFINED, '\\'));
496 // Add special case word rule.
497 // rules.add(new WordPredicateRule(comment));
499 // Add rules for multi-line comments and javadoc.
500 //rules.add(new MultiLineRule("/**", "*/", javaDoc));
501 // rules.add(new HTMLMultiLineRule("<", "<?", html));
503 rules.add(new MultiLineRule("<!--", "-->", comment));
504 rules.add(new PHPMultiLineRule("<?\r", "?>", php));
505 rules.add(new PHPMultiLineRule("<?\n", "?>", php));
506 rules.add(new PHPMultiLineRule("<?\t", "?>", php));
507 rules.add(new PHPMultiLineRule("<? ", "?>", php));
509 rules.add(new PHPMultiLineRule("<?php", "?>", php));
510 rules.add(new PHPMultiLineRule("<?PHP", "?>", php));
512 rules.add(new PHPMultiLineRule("<?pHP", "?>", php));
513 rules.add(new PHPMultiLineRule("<?PhP", "?>", php));
514 rules.add(new PHPMultiLineRule("<?PHp", "?>", php));
516 rules.add(new PHPMultiLineRule("<?Php", "?>", php));
517 rules.add(new PHPMultiLineRule("<?pHp", "?>", php));
518 rules.add(new PHPMultiLineRule("<?phP", "?>", php));
519 // rules.add(new HTMLPatternRule(html)); // "<", "<?",
520 //Add rule for processing instructions
522 IPredicateRule[] result = new IPredicateRule[rules.size()];
523 rules.toArray(result);
524 setPredicateRules(result);
525 // setDefaultReturnToken(html);
528 // public IToken nextToken() {
530 // if (fContentType == null || fRules == null)
531 // return getNextToken();
533 // fTokenOffset= fOffset;
534 // fColumn= UNDEFINED;
535 // boolean resume= (fPartitionOffset < fOffset);
537 // IPredicateRule rule;
540 // for (int i= 0; i < fRules.length; i++) {
541 // rule= (IPredicateRule) fRules[i];
542 // token= rule.getSuccessToken();
543 // if (fContentType.equals(token.getData())) {
545 // fTokenOffset= fPartitionOffset;
546 // token= rule.evaluate(this, resume);
547 // if (!token.isUndefined()) {
548 // fContentType= null;
554 // fContentType= null;
555 // return getNextToken();
558 // public IToken getNextToken() {
564 // fTokenOffset= fOffset;
565 // fColumn= UNDEFINED;
567 // if (fRules != null) {
568 // for (int i= 0; i < fRules.length; i++) {
569 // token= (fRules[i].evaluate(this));
570 // if (!token.isUndefined())
575 // if (read() == EOF)
578 // return fDefaultReturnToken;