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 implements IPHPPartitionScannerConstants {
29 // private final static String SKIP = "__skip"; //$NON-NLS-1$
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$
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);
40 protected final static char[] php0EndSequence = { '<', '?' };
41 protected final static char[] php1EndSequence = { '<', '?', 'p', 'h', 'p' };
42 protected final static char[] php2EndSequence = { '<', '?', 'P', 'H', 'P' };
44 private StringBuffer test;
46 public class PHPMultiLineRule extends MultiLineRule {
48 public PHPMultiLineRule(String startSequence, String endSequence, IToken token) {
49 super(startSequence, endSequence, token);
52 public PHPMultiLineRule(String startSequence, String endSequence, IToken token, char escapeCharacter) {
53 super(startSequence, endSequence, token, escapeCharacter);
56 protected boolean endSequenceDetected(ICharacterScanner scanner) {
60 boolean lineCommentMode = false;
61 boolean multiLineCommentMode = false;
62 boolean stringMode = false;
64 char[][] delimiters = scanner.getLegalLineDelimiters();
65 while ((c = scanner.read()) != ICharacterScanner.EOF) {
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))
73 } else if (c == '\n') {
78 } else if (c == '/' && (c = scanner.read()) != ICharacterScanner.EOF) {
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))
86 } else if (c == '\n') {
91 } else if (c == '*') {
93 while ((c = scanner.read()) != ICharacterScanner.EOF) {
94 if (c == '*' && (c = scanner.read()) != ICharacterScanner.EOF) {
106 } else if (c == '"') {
108 while ((c = scanner.read()) != ICharacterScanner.EOF) {
111 } else if (c == '"') {
116 } else if (c == '\'') {
118 while ((c = scanner.read()) != ICharacterScanner.EOF) {
121 } else if (c == '\'') {
128 if (c == fEscapeCharacter) {
129 // Skip the escaped character.
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))
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))
143 boolean phpMode = false;
144 if (c == ICharacterScanner.EOF) {
152 // public class HTMLMultiLineRule extends MultiLineRule {
154 // public HTMLMultiLineRule(String startSequence, String endSequence, IToken token) {
155 // super(startSequence, endSequence, token);
158 // public HTMLMultiLineRule(String startSequence, String endSequence, IToken token, char escapeCharacter) {
159 // super(startSequence, endSequence, token, escapeCharacter);
162 // protected boolean endSequenceDetected(ICharacterScanner scanner) {
165 // char[][] delimiters = scanner.getLegalLineDelimiters();
166 // while ((c = scanner.read()) != ICharacterScanner.EOF) {
168 // // scanner.unread();
169 // if (sequenceDetected(scanner, php2EndSequence, true)) {
178 // if (sequenceDetected(scanner, php1EndSequence, true)) {
187 // if (sequenceDetected(scanner, php0EndSequence, true)) {
193 // // scanner.read();
201 // protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) {
205 // if (endSequenceDetected(scanner))
210 // int c = scanner.read();
211 // // if (c == fStartSequence[0]) {
212 // // if (sequenceDetected(scanner, fStartSequence, false)) {
213 // if (endSequenceDetected(scanner))
220 // return Token.UNDEFINED;
223 // public IToken evaluate(ICharacterScanner scanner, boolean resume) {
224 // if (fColumn == UNDEFINED)
225 // return doEvaluate(scanner, resume);
227 // int c = scanner.read();
229 // // if (c == fStartSequence[0])
230 // return (fColumn == scanner.getColumn() ? doEvaluate(scanner, resume) : Token.UNDEFINED);
232 // // return Token.UNDEFINED;
236 // public class HTMLPatternRule implements IPredicateRule {
238 // protected static final int UNDEFINED = -1;
240 // /** The token to be returned on success */
241 // protected IToken fToken;
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;
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.
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
262 // public HTMLPatternRule(IToken token) {
264 // fEscapeCharacter = (char) 0;
265 // fBreaksOnEOL = false;
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.
274 // * @param column the column in which the pattern starts
276 // public void setColumnConstraint(int column) {
278 // column = UNDEFINED;
283 // * Evaluates this rules without considering any column constraints.
285 // * @param scanner the character scanner to be used
286 // * @return the token resulting from this evaluation
288 // protected IToken doEvaluate(ICharacterScanner scanner) {
289 // return doEvaluate(scanner, false);
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.
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
302 // protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) {
306 // if (endSequenceDetected(scanner))
311 // int c = scanner.read();
312 // // if (c == fStartSequence[0]) {
313 // // if (sequenceDetected(scanner, fStartSequence, false)) {
314 // if (endSequenceDetected(scanner))
321 // return Token.UNDEFINED;
325 // * @see IRule#evaluate
327 // public IToken evaluate(ICharacterScanner scanner) {
328 // return evaluate(scanner, false);
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.
336 // * @param scanner the character scanner to be used
337 // * @return <code>true</code> if the end sequence has been detected
339 // protected boolean endSequenceDetected(ICharacterScanner scanner) {
342 // char[][] delimiters = scanner.getLegalLineDelimiters();
343 // while ((c = scanner.read()) != ICharacterScanner.EOF) {
345 // // scanner.unread();
346 // if (sequenceDetected(scanner, php2EndSequence, true)) {
355 // if (sequenceDetected(scanner, php1EndSequence, true)) {
364 // if (sequenceDetected(scanner, php0EndSequence, true)) {
370 // // scanner.read();
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.
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
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) {
394 // } else if (c != sequence[i]) {
395 // // Non-matching character detected, rewind the scanner back to the start.
397 // for (int j = i - 1; j > 0; j--)
407 // * @see IPredicateRule#evaluate(ICharacterScanner, boolean)
410 // public IToken evaluate(ICharacterScanner scanner, boolean resume) {
411 // if (fColumn == UNDEFINED)
412 // return doEvaluate(scanner, resume);
414 // int c = scanner.read();
416 // // if (c == fStartSequence[0])
417 // return (fColumn == scanner.getColumn() ? doEvaluate(scanner, resume) : Token.UNDEFINED);
419 // // return Token.UNDEFINED;
423 // * @see IPredicateRule#getSuccessToken()
426 // public IToken getSuccessToken() {
431 * Detector for empty comments.
433 // static class EmptyCommentDetector implements IWordDetector {
436 // * Method declared on IWordDetector
438 // public boolean isWordStart(char c) {
439 // return (c == '/');
443 // * Method declared on IWordDetector
445 // public boolean isWordPart(char c) {
446 // return (c == '*' || c == '/');
453 // static class WordPredicateRule extends WordRule implements IPredicateRule {
455 // private IToken fSuccessToken;
457 // public WordPredicateRule(IToken successToken) {
458 // super(new EmptyCommentDetector());
459 // fSuccessToken = successToken;
460 // addWord("/**/", fSuccessToken);
464 // * @see org.eclipse.jface.text.rules.IPredicateRule#evaluate(ICharacterScanner, boolean)
466 // public IToken evaluate(ICharacterScanner scanner, boolean resume) {
467 // return super.evaluate(scanner);
471 // * @see org.eclipse.jface.text.rules.IPredicateRule#getSuccessToken()
473 // public IToken getSuccessToken() {
474 // return fSuccessToken;
479 * Creates the partitioner and sets up the appropriate rules.
481 public PHPPartitionScanner() {
484 // IToken php = new Token(PHP);
485 // IToken html = new Token(HTML);
486 // IToken comment = new Token(HTML_MULTILINE_COMMENT);
488 List rules = new ArrayList();
490 // Add rule for single line comments.
491 // rules.add(new EndOfLineRule("//", Token.UNDEFINED));
493 // Add rule for strings and character constants.
494 // rules.add(new SingleLineRule("\"", "\"", Token.UNDEFINED, '\\'));
495 // rules.add(new SingleLineRule("'", "'", Token.UNDEFINED, '\\'));
497 // Add special case word rule.
498 // rules.add(new WordPredicateRule(comment));
500 // Add rules for multi-line comments and javadoc.
501 //rules.add(new MultiLineRule("/**", "*/", javaDoc));
502 // rules.add(new HTMLMultiLineRule("<", "<?", html));
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));
510 rules.add(new PHPMultiLineRule("<?php", "?>", php));
511 rules.add(new PHPMultiLineRule("<?PHP", "?>", php));
513 rules.add(new PHPMultiLineRule("<?pHP", "?>", php));
514 rules.add(new PHPMultiLineRule("<?PhP", "?>", php));
515 rules.add(new PHPMultiLineRule("<?PHp", "?>", php));
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
523 IPredicateRule[] result = new IPredicateRule[rules.size()];
524 rules.toArray(result);
525 setPredicateRules(result);
526 // setDefaultReturnToken(html);
529 // public IToken nextToken() {
531 // if (fContentType == null || fRules == null)
532 // return getNextToken();
534 // fTokenOffset= fOffset;
535 // fColumn= UNDEFINED;
536 // boolean resume= (fPartitionOffset < fOffset);
538 // IPredicateRule rule;
541 // for (int i= 0; i < fRules.length; i++) {
542 // rule= (IPredicateRule) fRules[i];
543 // token= rule.getSuccessToken();
544 // if (fContentType.equals(token.getData())) {
546 // fTokenOffset= fPartitionOffset;
547 // token= rule.evaluate(this, resume);
548 // if (!token.isUndefined()) {
549 // fContentType= null;
555 // fContentType= null;
556 // return getNextToken();
559 // public IToken getNextToken() {
565 // fTokenOffset= fOffset;
566 // fColumn= UNDEFINED;
568 // if (fRules != null) {
569 // for (int i= 0; i < fRules.length; i++) {
570 // token= (fRules[i].evaluate(this));
571 // if (!token.isUndefined())
576 // if (read() == EOF)
579 // return fDefaultReturnToken;