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;
22 //import org.eclipse.jface.text.Assert;
23 import org.eclipse.core.runtime.Assert;
24 import org.eclipse.jface.text.BadLocationException;
25 import org.eclipse.jface.text.IDocument;
26 import org.eclipse.jface.text.rules.ICharacterScanner;
27 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
28 import org.eclipse.jface.text.rules.IToken;
29 import org.eclipse.jface.text.rules.Token;
34 * @author Igor Malinin
36 public class PHPPartitionScanner implements IPartitionTokenScanner {
37 public static final String PHP_SCRIPTING_AREA = "__php_scripting_area ";
39 public static final int STATE_DEFAULT = 0;
41 // public static final int STATE_TAG = 1;
42 // public static final int STATE_SCRIPT = 2;
44 private IDocument document;
58 private Map tokens = new HashMap();
60 public PHPPartitionScanner() {
64 * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
66 public IToken nextToken() {
70 * switch (state) { case STATE_TAG: return nextTagToken(); }
74 case ICharacterScanner.EOF:
75 // state = STATE_DEFAULT;
76 return getToken(null);
80 case ICharacterScanner.EOF:
81 // state = STATE_DEFAULT;
82 return getToken(null);
88 // case ICharacterScanner.EOF:
89 // state = STATE_DEFAULT;
90 // return getToken(PHP_SCRIPTING_AREA);
92 return scanUntilPHPEndToken(PHP_SCRIPTING_AREA);
100 case ICharacterScanner.EOF:
101 // state = STATE_DEFAULT;
102 return getToken(null);
106 case ICharacterScanner.EOF:
107 // state = STATE_DEFAULT;
108 return getToken(null);
123 // state = STATE_DEFAULT;
124 return getToken(null);
129 private IToken scanUntilPHPEndToken(String token) {
133 case ICharacterScanner.EOF:
134 // state = STATE_DEFAULT;
135 return getToken(token);
136 case '"': // double quoted string
137 // read until end of double quoted string
138 if (!readUntilEscapedDQ()) {
139 // state = STATE_DEFAULT;
140 return getToken(token);
143 case '<': // heredoc string
146 case ICharacterScanner.EOF:
151 case ICharacterScanner.EOF:
154 // read until end of heredoc string
155 if (!readUntilEscapedHEREDOC()) {
156 // state = STATE_DEFAULT;
157 return getToken(token);
162 case '\'': // single quoted string
163 // read until end of single quoted string
164 if (!readUntilEscapedSQ()) {
165 // state = STATE_DEFAULT;
166 return getToken(token);
169 case '/': // comment start?
172 case ICharacterScanner.EOF:
175 // read until end of line
176 if (!readSingleLine()) {
177 // state = STATE_DEFAULT;
178 return getToken(token);
182 // read until end of comment
183 if (!readMultiLineComment()) {
184 // state = STATE_DEFAULT;
185 return getToken(token);
192 case '#': // line comment
193 // read until end of line
194 if (!readSingleLine()) {
195 // state = STATE_DEFAULT;
196 return getToken(token);
202 case ICharacterScanner.EOF:
204 // state = STATE_DEFAULT;
205 return getToken(token);
218 private IToken getToken(String type) {
219 length = position - offset;
227 // System.out.println("Length<0:"+document.get(offset,5)+""+length);
228 // } catch (BadLocationException e) {
229 // e.printStackTrace();
234 return Token.UNDEFINED;
237 IToken token = (IToken) tokens.get(type);
239 token = new Token(type);
240 tokens.put(type, token);
247 if (position >= end) {
248 return ICharacterScanner.EOF;
252 return document.getChar(position++);
253 } catch (BadLocationException e) {
255 return ICharacterScanner.EOF;
259 private boolean readUntilEscapedDQ() {
260 // search last double quoted character
264 if (position >= end) {
267 ch = document.getChar(position++);
269 if (position >= end) {
272 ch = document.getChar(position++); // ignore escaped
274 } else if (ch == '"') {
278 } catch (BadLocationException e) {
284 private boolean readUntilEscapedSQ() {
285 // search last single quoted character
289 if (position >= end) {
292 ch = document.getChar(position++);
294 if (position >= end) {
297 ch = document.getChar(position++); // ignore escaped
299 } else if (ch == '\'') {
303 } catch (BadLocationException e) {
310 * Read until HEREDOC ends
314 private boolean readUntilEscapedHEREDOC() {
317 StringBuffer buf = new StringBuffer();
320 if (position >= end) {
324 ch = document.getChar(position++);
328 if (position >= end) {
331 ch = document.getChar(position++);
334 if (!Scanner.isPHPIdentifierStart(ch)) {
338 while (Scanner.isPHPIdentifierPart(ch)) {
340 if (position >= end) {
343 ch = document.getChar(position++);
346 heredocIdent = buf.toString().toCharArray();
349 if (position >= end) {
353 ch = document.getChar (position++); // Get the next character from file
355 if (ch == '\n') { // heredoc could end after a newline
359 if (position >= end) { // If we are at the end of file
360 return false; // Return
363 if (pos == heredocIdent.length) { // If the found length equals the length of heredoc id
364 return true; // we found the end of heredoc
367 ch = document.getChar (position++); // Ignore escaped character
369 if (ch != heredocIdent[pos]) { // If current character doesn't match the heredoc id
370 break; // break the heredoc end search
373 pos++; // Character matched the heredoc id so far
377 } catch (BadLocationException e) {
383 private boolean readSingleLine() {
386 if (position >= end) {
389 } while (document.getChar(position++) != '\n');
391 } catch (BadLocationException e) {
397 private boolean readMultiLineComment() {
401 if (position >= end) {
404 ch = document.getChar(position++);
406 if (position >= end) {
409 if (document.getChar(position) == '/') {
415 } catch (BadLocationException e) {
421 private void unread() {
426 * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset()
428 public int getTokenOffset() {
429 if (AbstractPartitioner.DEBUG) {
430 Assert.isTrue(offset >= 0, Integer.toString(offset));
436 * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength()
438 public int getTokenLength() {
443 * @see org.eclipse.jface.text.rules.ITokenScanner#setRange(IDocument, int,
446 public void setRange(IDocument document, int offset, int length) {
447 this.document = document;
448 // this.begin = offset;
449 this.end = offset + length;
451 this.offset = offset;
452 this.position = offset;
457 * @see org.eclipse.jface.text.rules.IPartitionTokenScanner
459 public void setPartialRange(IDocument document, int offset, int length,
460 String contentType, int partitionOffset) {
461 // state = STATE_DEFAULT;
462 if (partitionOffset > -1) {
463 int delta = offset - partitionOffset;
465 setRange(document, partitionOffset, length + delta);
469 setRange(document, partitionOffset, length);
472 // private boolean isContinuationPartition(IDocument document, int offset) {
474 // String type = document.getContentType(offset - 1);
476 // if (type != IDocument.DEFAULT_CONTENT_TYPE) {
479 // } catch (BadLocationException e) {}