1 /**********************************************************************
2 Copyright (c) 2002 Widespace, OU 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://solareclipse.sourceforge.net/legal/cpl-v10.html
9 Igor Malinin - initial contribution
11 $Id: PHPPartitionScanner.java,v 1.35 2007-03-17 14:07:31 axelcl Exp $
12 **********************************************************************/
13 package net.sourceforge.phpeclipse.phpeditor.php;
15 import java.util.HashMap;
18 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
19 import net.sourceforge.phpeclipse.ui.text.rules.AbstractPartitioner;
21 import org.eclipse.jface.text.Assert;
22 import org.eclipse.jface.text.BadLocationException;
23 import org.eclipse.jface.text.IDocument;
24 import org.eclipse.jface.text.rules.ICharacterScanner;
25 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
26 import org.eclipse.jface.text.rules.IToken;
27 import org.eclipse.jface.text.rules.Token;
32 * @author Igor Malinin
34 public class PHPPartitionScanner implements IPartitionTokenScanner {
35 public static final String PHP_SCRIPTING_AREA = "__php_scripting_area ";
37 public static final int STATE_DEFAULT = 0;
39 // public static final int STATE_TAG = 1;
40 // public static final int STATE_SCRIPT = 2;
42 private IDocument document;
56 private Map tokens = new HashMap();
58 public PHPPartitionScanner() {
62 * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
64 public IToken nextToken() {
68 * switch (state) { case STATE_TAG: return nextTagToken(); }
72 case ICharacterScanner.EOF:
73 // state = STATE_DEFAULT;
74 return getToken(null);
78 case ICharacterScanner.EOF:
79 // state = STATE_DEFAULT;
80 return getToken(null);
86 // case ICharacterScanner.EOF:
87 // state = STATE_DEFAULT;
88 // return getToken(PHP_SCRIPTING_AREA);
90 return scanUntilPHPEndToken(PHP_SCRIPTING_AREA);
98 case ICharacterScanner.EOF:
99 // state = STATE_DEFAULT;
100 return getToken(null);
104 case ICharacterScanner.EOF:
105 // state = STATE_DEFAULT;
106 return getToken(null);
121 // state = STATE_DEFAULT;
122 return getToken(null);
127 private IToken scanUntilPHPEndToken(String token) {
131 case ICharacterScanner.EOF:
132 // state = STATE_DEFAULT;
133 return getToken(token);
134 case '"': // double quoted string
135 // read until end of double quoted string
136 if (!readUntilEscapedDQ()) {
137 // state = STATE_DEFAULT;
138 return getToken(token);
141 case '<': // heredoc string
144 case ICharacterScanner.EOF:
149 case ICharacterScanner.EOF:
152 // read until end of heredoc string
153 if (!readUntilEscapedHEREDOC()) {
154 // state = STATE_DEFAULT;
155 return getToken(token);
160 case '\'': // single quoted string
161 // read until end of single quoted string
162 if (!readUntilEscapedSQ()) {
163 // state = STATE_DEFAULT;
164 return getToken(token);
167 case '/': // comment start?
170 case ICharacterScanner.EOF:
173 // read until end of line
174 if (!readSingleLine()) {
175 // state = STATE_DEFAULT;
176 return getToken(token);
180 // read until end of comment
181 if (!readMultiLineComment()) {
182 // state = STATE_DEFAULT;
183 return getToken(token);
190 case '#': // line comment
191 // read until end of line
192 if (!readSingleLine()) {
193 // state = STATE_DEFAULT;
194 return getToken(token);
200 case ICharacterScanner.EOF:
202 // state = STATE_DEFAULT;
203 return getToken(token);
216 private IToken getToken(String type) {
217 length = position - offset;
225 // System.out.println("Length<0:"+document.get(offset,5)+""+length);
226 // } catch (BadLocationException e) {
227 // e.printStackTrace();
232 return Token.UNDEFINED;
235 IToken token = (IToken) tokens.get(type);
237 token = new Token(type);
238 tokens.put(type, token);
245 if (position >= end) {
246 return ICharacterScanner.EOF;
250 return document.getChar(position++);
251 } catch (BadLocationException e) {
253 return ICharacterScanner.EOF;
257 private boolean readUntilEscapedDQ() {
258 // search last double quoted character
262 if (position >= end) {
265 ch = document.getChar(position++);
267 if (position >= end) {
270 ch = document.getChar(position++); // ignore escaped
272 } else if (ch == '"') {
276 } catch (BadLocationException e) {
282 private boolean readUntilEscapedSQ() {
283 // search last single quoted character
287 if (position >= end) {
290 ch = document.getChar(position++);
292 if (position >= end) {
295 ch = document.getChar(position++); // ignore escaped
297 } else if (ch == '\'') {
301 } catch (BadLocationException e) {
307 private boolean readUntilEscapedHEREDOC() {
308 // search until heredoc ends
311 StringBuffer buf = new StringBuffer();
313 if (position >= end) {
316 ch = document.getChar(position++);
319 if (position >= end) {
322 ch = document.getChar(position++);
325 if (!Scanner.isPHPIdentifierStart(ch)) {
328 while (Scanner.isPHPIdentifierPart(ch)) {
330 if (position >= end) {
333 ch = document.getChar(position++);
335 heredocIdent = buf.toString().toCharArray();
337 if (position >= end) {
340 ch = document.getChar(position++);
341 if (ch == '\n') { // heredoc could end after a newline
344 if (position >= end) {
347 if (pos == heredocIdent.length) {
350 ch = document.getChar(position++); // ignore escaped
352 if (ch != heredocIdent[pos]) {
359 } catch (BadLocationException e) {
365 private boolean readSingleLine() {
368 if (position >= end) {
371 } while (document.getChar(position++) != '\n');
373 } catch (BadLocationException e) {
379 private boolean readMultiLineComment() {
383 if (position >= end) {
386 ch = document.getChar(position++);
388 if (position >= end) {
391 if (document.getChar(position) == '/') {
397 } catch (BadLocationException e) {
403 private void unread() {
408 * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset()
410 public int getTokenOffset() {
411 if (AbstractPartitioner.DEBUG) {
412 Assert.isTrue(offset >= 0, Integer.toString(offset));
418 * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength()
420 public int getTokenLength() {
425 * @see org.eclipse.jface.text.rules.ITokenScanner#setRange(IDocument, int,
428 public void setRange(IDocument document, int offset, int length) {
429 this.document = document;
430 // this.begin = offset;
431 this.end = offset + length;
433 this.offset = offset;
434 this.position = offset;
439 * @see org.eclipse.jface.text.rules.IPartitionTokenScanner
441 public void setPartialRange(IDocument document, int offset, int length,
442 String contentType, int partitionOffset) {
443 // state = STATE_DEFAULT;
444 if (partitionOffset > -1) {
445 int delta = offset - partitionOffset;
447 setRange(document, partitionOffset, length + delta);
451 setRange(document, partitionOffset, length);
454 // private boolean isContinuationPartition(IDocument document, int offset) {
456 // String type = document.getContentType(offset - 1);
458 // if (type != IDocument.DEFAULT_CONTENT_TYPE) {
461 // } catch (BadLocationException e) {}