1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation 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 API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.text;
13 import net.sourceforge.phpeclipse.ui.text.rules.AbstractPartitioner;
15 import org.eclipse.jface.text.Assert;
16 import org.eclipse.jface.text.IDocument;
17 import org.eclipse.jface.text.rules.ICharacterScanner;
18 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
19 import org.eclipse.jface.text.rules.IToken;
20 import org.eclipse.jface.text.rules.Token;
23 * This scanner recognizes the JavaDoc comments, Java multi line comments, Java
24 * single line comments, Java strings.
26 public class FastJavaPartitionScanner implements IPartitionTokenScanner, IPHPPartitions {
29 private static final int PHP = 0;
31 private static final int SINGLE_LINE_COMMENT = 1;
33 private static final int MULTI_LINE_COMMENT = 2;
35 private static final int PHPDOC = 3;
37 private static final int STRING_DQ = 4;
39 private static final int STRING_SQ = 5;
41 private static final int STRING_HEREDOC = 6;
43 // beginning of prefixes and postfixes
44 private static final int NONE = 0;
46 private static final int BACKSLASH = 1; // postfix for STRING_DQ and CHARACTER
48 private static final int SLASH = 2; // prefix for SINGLE_LINE or MULTI_LINE or
51 private static final int SLASH_STAR = 3; // prefix for MULTI_LINE_COMMENT or
54 private static final int SLASH_STAR_STAR = 4; // prefix for MULTI_LINE_COMMENT
57 private static final int STAR = 5; // postfix for MULTI_LINE_COMMENT or
60 private static final int CARRIAGE_RETURN = 6; // postfix for STRING_DQ,
62 // SINGLE_LINE_COMMENT
64 // private static final int HEREDOC = 7;
67 private final BufferedDocumentScanner fScanner = new BufferedDocumentScanner(1000); // faster
70 /** The offset of the last returned token. */
71 private int fTokenOffset;
73 /** The length of the last returned token. */
74 private int fTokenLength;
76 /** The state of the scanner. */
79 /** The last significant characters read. */
82 /** The amount of characters already read on first call to nextToken(). */
83 private int fPrefixLength;
85 // emulate JavaPartitionScanner
86 private boolean fEmulate = false;
88 private int fJavaOffset;
90 private int fJavaLength;
92 private final IToken[] fTokens = new IToken[] { new Token(null), new Token(PHP_SINGLELINE_COMMENT),
93 new Token(PHP_MULTILINE_COMMENT), new Token(PHP_PHPDOC_COMMENT), new Token(PHP_STRING_DQ), new Token(PHP_STRING_SQ),
94 new Token(PHP_STRING_HEREDOC) };
96 public FastJavaPartitionScanner(boolean emulate) {
100 public FastJavaPartitionScanner() {
105 * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
107 public IToken nextToken() {
109 // emulate JavaPartitionScanner
111 if (fJavaOffset != -1 && fTokenOffset + fTokenLength != fJavaOffset + fJavaLength) {
112 fTokenOffset += fTokenLength;
120 fTokenOffset += fTokenLength;
121 fTokenLength = fPrefixLength;
124 final int ch = fScanner.read();
128 case ICharacterScanner.EOF:
129 if (fTokenLength > 0) {
130 fLast = NONE; // ignore last
131 return preFix(fState, PHP, NONE, 0);
140 // emulate JavaPartitionScanner
141 if (!fEmulate && fLast != CARRIAGE_RETURN) {
142 fLast = CARRIAGE_RETURN;
149 case SINGLE_LINE_COMMENT:
153 if (fTokenLength > 0) {
154 IToken token = fTokens[fState];
156 // emulate JavaPartitionScanner
162 fLast = CARRIAGE_RETURN;
182 case SINGLE_LINE_COMMENT:
186 // assert(fTokenLength > 0);
187 return postFix(fState);
195 if (fState == SINGLE_LINE_COMMENT) {
196 int nextch = fScanner.read();
198 // <h1>This is an <?php # echo 'simple' ?> example.</h1>
202 return postFix(fState);
205 // bug #1404228: Crash on <?php // comment ?>
206 if (nextch!=ICharacterScanner.EOF) {
213 if (!fEmulate && fLast == CARRIAGE_RETURN) {
215 case SINGLE_LINE_COMMENT:
234 newState = STRING_SQ;
239 newState = STRING_DQ;
243 last = CARRIAGE_RETURN;
258 fLast = NONE; // ignore fLast
259 return preFix(fState, newState, last, 1);
272 if (fTokenLength > 0) {
273 return preFix(PHP, SINGLE_LINE_COMMENT, NONE, 1);
275 preFix(PHP, SINGLE_LINE_COMMENT, NONE, 1);
276 fTokenOffset += fTokenLength;
277 fTokenLength = fPrefixLength;
281 if (fLast == SLASH) {
282 if (fTokenLength - getLastLength(fLast) > 0) {
283 return preFix(PHP, SINGLE_LINE_COMMENT, NONE, 2);
285 preFix(PHP, SINGLE_LINE_COMMENT, NONE, 2);
286 fTokenOffset += fTokenLength;
287 fTokenLength = fPrefixLength;
298 if (fLast == SLASH) {
299 if (fTokenLength - getLastLength(fLast) > 0)
300 return preFix(PHP, MULTI_LINE_COMMENT, SLASH_STAR, 2);
302 preFix(PHP, MULTI_LINE_COMMENT, SLASH_STAR, 2);
303 fTokenOffset += fTokenLength;
304 fTokenLength = fPrefixLength;
314 fLast = NONE; // ignore fLast
315 if (fTokenLength > 0)
316 return preFix(PHP, STRING_SQ, NONE, 1);
318 preFix(PHP, STRING_SQ, NONE, 1);
319 fTokenOffset += fTokenLength;
320 fTokenLength = fPrefixLength;
325 fLast = NONE; // ignore fLast
326 if (fTokenLength > 0)
327 return preFix(PHP, STRING_DQ, NONE, 1);
329 preFix(PHP, STRING_DQ, NONE, 1);
330 fTokenOffset += fTokenLength;
331 fTokenLength = fPrefixLength;
341 case SINGLE_LINE_COMMENT:
349 case SLASH_STAR_STAR:
350 return postFix(MULTI_LINE_COMMENT);
353 return postFix(PHPDOC);
372 case MULTI_LINE_COMMENT:
375 if (fLast == SLASH_STAR) {
376 fLast = SLASH_STAR_STAR;
387 return postFix(MULTI_LINE_COMMENT);
402 fLast = (fLast == BACKSLASH) ? NONE : BACKSLASH;
407 if (fLast != BACKSLASH) {
408 return postFix(STRING_DQ);
423 fLast = (fLast == BACKSLASH) ? NONE : BACKSLASH;
428 if (fLast != BACKSLASH) {
429 return postFix(STRING_SQ);
444 // fLast= (fLast == BACKSLASH) ? NONE : BACKSLASH;
449 // if (fLast != BACKSLASH) {
450 // return postFix(CHARACTER);
466 private static final int getLastLength(int last) {
474 case CARRIAGE_RETURN:
483 case SLASH_STAR_STAR:
488 private final void consume() {
493 private final IToken postFix(int state) {
498 return fTokens[state];
501 private final IToken preFix(int state, int newState, int last, int prefixLength) {
502 // emulate JavaPartitionScanner
503 if (fEmulate && state == PHP && (fTokenLength - getLastLength(fLast) > 0)) {
504 fTokenLength -= getLastLength(fLast);
505 fJavaOffset = fTokenOffset;
506 fJavaLength = fTokenLength;
509 fPrefixLength = prefixLength;
511 return fTokens[state];
514 fTokenLength -= getLastLength(fLast);
516 fPrefixLength = prefixLength;
517 IToken token = fTokens[state];
523 private static int getState(String contentType) {
525 if (contentType == null)
528 else if (contentType.equals(PHP_SINGLELINE_COMMENT))
529 return SINGLE_LINE_COMMENT;
531 else if (contentType.equals(PHP_MULTILINE_COMMENT))
532 return MULTI_LINE_COMMENT;
534 else if (contentType.equals(PHP_PHPDOC_COMMENT))
537 else if (contentType.equals(PHP_STRING_DQ))
540 else if (contentType.equals(PHP_STRING_SQ))
543 else if (contentType.equals(PHP_STRING_HEREDOC))
544 return STRING_HEREDOC;
546 // else if (contentType.equals(JAVA_CHARACTER))
554 * @see IPartitionTokenScanner#setPartialRange(IDocument, int, int, String,
557 public void setPartialRange(IDocument document, int offset, int length, String contentType, int partitionOffset) {
558 fScanner.setRange(document, offset, length);
559 setRange(document, offset, length);
560 fTokenOffset = partitionOffset;
562 fPrefixLength = offset - partitionOffset;
565 if (offset == partitionOffset) {
566 // restart at beginning of partition
569 fState = getState(contentType);
572 // emulate JavaPartitionScanner
580 * @see ITokenScanner#setRange(IDocument, int, int)
582 public void setRange(IDocument document, int offset, int length) {
583 fScanner.setRange(document, offset, length);
584 fTokenOffset = offset;
590 // emulate JavaPartitionScanner
598 * @see ITokenScanner#getTokenLength()
600 public int getTokenLength() {
605 * @see ITokenScanner#getTokenOffset()
607 public int getTokenOffset() {
608 if (AbstractPartitioner.DEBUG) {
609 Assert.isTrue(fTokenOffset >= 0, Integer.toString(fTokenOffset));