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.31 2005-10-09 11:24:07 axelcl Exp $
12 **********************************************************************/
13 package net.sourceforge.phpeclipse.phpeditor.php;
15 import java.util.ArrayList;
16 import java.util.HashMap;
19 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
20 import net.sourceforge.phpeclipse.ui.text.rules.AbstractPartitioner;
22 import org.eclipse.jface.text.Assert;
23 import org.eclipse.jface.text.BadLocationException;
24 import org.eclipse.jface.text.IDocument;
25 import org.eclipse.jface.text.rules.ICharacterScanner;
26 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
27 import org.eclipse.jface.text.rules.IToken;
28 import org.eclipse.jface.text.rules.Token;
33 * @author Igor Malinin
35 public class PHPPartitionScanner implements IPartitionTokenScanner {
36 public static final String PHP_SCRIPTING_AREA = "__php_scripting_area ";
38 public static final int STATE_DEFAULT = 0;
40 // public static final int STATE_TAG = 1;
41 // public static final int STATE_SCRIPT = 2;
43 private IDocument document;
57 private Map tokens = new HashMap();
59 public PHPPartitionScanner() {
63 * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
65 public IToken nextToken() {
69 * switch (state) { case STATE_TAG: return nextTagToken(); }
73 case ICharacterScanner.EOF:
74 // state = STATE_DEFAULT;
75 return getToken(null);
79 case ICharacterScanner.EOF:
80 // state = STATE_DEFAULT;
81 return getToken(null);
87 // case ICharacterScanner.EOF:
88 // state = STATE_DEFAULT;
89 // return getToken(PHP_SCRIPTING_AREA);
91 return scanUntilPHPEndToken(PHP_SCRIPTING_AREA);
99 case ICharacterScanner.EOF:
100 // state = STATE_DEFAULT;
101 return getToken(null);
105 case ICharacterScanner.EOF:
106 // state = STATE_DEFAULT;
107 return getToken(null);
122 // state = STATE_DEFAULT;
123 return getToken(null);
128 private IToken scanUntilPHPEndToken(String token) {
132 case ICharacterScanner.EOF:
133 // state = STATE_DEFAULT;
134 return getToken(token);
135 case '"': // double quoted string
136 // read until end of double quoted string
137 if (!readUntilEscapedDQ()) {
138 // state = STATE_DEFAULT;
139 return getToken(token);
142 case '<': // heredoc string
145 case ICharacterScanner.EOF:
150 case ICharacterScanner.EOF:
153 // read until end of heredoc string
154 if (!readUntilEscapedHEREDOC()) {
155 // state = STATE_DEFAULT;
156 return getToken(token);
161 case '\'': // single quoted string
162 // read until end of single quoted string
163 if (!readUntilEscapedSQ()) {
164 // state = STATE_DEFAULT;
165 return getToken(token);
168 case '/': // comment start?
171 case ICharacterScanner.EOF:
174 // read until end of line
175 if (!readSingleLine()) {
176 // state = STATE_DEFAULT;
177 return getToken(token);
181 // read until end of comment
182 if (!readMultiLineComment()) {
183 // state = STATE_DEFAULT;
184 return getToken(token);
191 case '#': // line comment
192 // read until end of line
193 if (!readSingleLine()) {
194 // state = STATE_DEFAULT;
195 return getToken(token);
201 case ICharacterScanner.EOF:
203 // state = STATE_DEFAULT;
204 return getToken(token);
217 private IToken getToken(String type) {
218 length = position - offset;
226 // System.out.println("Length<0:"+document.get(offset,5)+""+length);
227 // } catch (BadLocationException e) {
228 // e.printStackTrace();
233 return Token.UNDEFINED;
236 IToken token = (IToken) tokens.get(type);
238 token = new Token(type);
239 tokens.put(type, token);
246 if (position >= end) {
247 return ICharacterScanner.EOF;
251 return document.getChar(position++);
252 } catch (BadLocationException e) {
254 return ICharacterScanner.EOF;
258 private boolean readUntilEscapedDQ() {
259 // search last double quoted character
263 if (position >= end) {
266 ch = document.getChar(position++);
268 if (position >= end) {
271 ch = document.getChar(position++); // ignore escaped character
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 character
296 } else if (ch == '\'') {
300 } catch (BadLocationException e) {
306 private boolean readUntilEscapedHEREDOC() {
307 // search until heredoc ends
310 StringBuffer buf = new StringBuffer();
312 if (position >= end) {
315 ch = document.getChar(position++);
316 if (!Scanner.isPHPIdentifierStart(ch)) {
319 while (Scanner.isPHPIdentifierPart(ch)) {
321 if (position >= end) {
324 ch = document.getChar(position++);
326 heredocIdent = buf.toString().toCharArray();
328 if (position >= end) {
331 ch = document.getChar(position++);
332 if (ch == '\n') { // heredoc could end after a newline
335 if (position >= end) {
338 if (pos==heredocIdent.length) {
341 ch = document.getChar(position++); // ignore escaped character
342 if (ch != heredocIdent[pos]) {
347 } else if (ch == '"') {
351 } catch (BadLocationException e) {
357 private boolean readSingleLine() {
360 if (position >= end) {
363 } while (document.getChar(position++) != '\n');
365 } catch (BadLocationException e) {
371 private boolean readMultiLineComment() {
375 if (position >= end) {
378 ch = document.getChar(position++);
380 if (position >= end) {
383 if (document.getChar(position) == '/') {
389 } catch (BadLocationException e) {
395 private void unread() {
400 * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset()
402 public int getTokenOffset() {
403 if (AbstractPartitioner.DEBUG) {
404 Assert.isTrue(offset >= 0, Integer.toString(offset));
410 * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength()
412 public int getTokenLength() {
417 * @see org.eclipse.jface.text.rules.ITokenScanner#setRange(IDocument, int,
420 public void setRange(IDocument document, int offset, int length) {
421 this.document = document;
422 // this.begin = offset;
423 this.end = offset + length;
425 this.offset = offset;
426 this.position = offset;
431 * @see org.eclipse.jface.text.rules.IPartitionTokenScanner
433 public void setPartialRange(IDocument document, int offset, int length, String contentType, int partitionOffset) {
434 // state = STATE_DEFAULT;
435 if (partitionOffset > -1) {
436 int delta = offset - partitionOffset;
438 setRange(document, partitionOffset, length + delta);
442 setRange(document, partitionOffset, length);
445 // private boolean isContinuationPartition(IDocument document, int offset) {
447 // String type = document.getContentType(offset - 1);
449 // if (type != IDocument.DEFAULT_CONTENT_TYPE) {
452 // } catch (BadLocationException e) {}