41db8c47b8260ec303488fe2cedae15312150169
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / PHPCodeReader.java
1 package net.sourceforge.phpdt.internal.ui.text;
2
3 /*
4  * (c) Copyright IBM Corp. 2000, 2001.
5  * All Rights Reserved.
6  */
7
8 import java.io.IOException;
9
10 import org.eclipse.jface.text.BadLocationException;
11 import org.eclipse.jface.text.IDocument;
12
13 import net.sourceforge.phpdt.internal.corext.phpdoc.SingleCharReader;
14
15 /**
16  * Reads from a document either forwards or backwards. May be configured to
17  * skip comments and strings.
18  */
19 public class PHPCodeReader extends SingleCharReader {
20         
21         /** The EOF character */
22         public static final int EOF= -1;
23         
24         private boolean fSkipComments= false;
25         private boolean fSkipStrings= false;
26         private boolean fForward= false;
27         
28         private IDocument fDocument;
29         private int fOffset;
30         
31         private int fEnd= -1;
32         private int fCachedLineNumber= -1;
33         private int fCachedLineOffset= -1;
34         
35         
36         public PHPCodeReader() {
37         }
38         
39         /**
40          * Returns the offset of the last read character. Should only be called after read has been called.
41          */
42         public int getOffset() {
43                 return fForward ? fOffset -1 : fOffset;
44         }
45         
46         public void configureForwardReader(IDocument document, int offset, int length, boolean skipComments, boolean skipStrings) throws IOException {
47                 fDocument= document;
48                 fOffset= offset;
49                 fSkipComments= skipComments;
50                 fSkipStrings= skipStrings;
51                 
52                 fForward= true;
53                 fEnd= Math.min(fDocument.getLength(), fOffset + length);                
54         }
55         
56         public void configureBackwardReader(IDocument document, int offset, boolean skipComments, boolean skipStrings) throws IOException {
57                 fDocument= document;
58                 fOffset= offset;
59                 fSkipComments= skipComments;
60                 fSkipStrings= skipStrings;
61                 
62                 fForward= false;
63                 try {
64                         fCachedLineNumber= fDocument.getLineOfOffset(fOffset);
65                 } catch (BadLocationException x) {
66                         throw new IOException(x.getMessage());
67                 }
68         }
69         
70         /*
71          * @see Reader#close()
72          */
73         public void close() throws IOException {
74                 fDocument= null;
75         }
76         
77         /*
78          * @see SingleCharReader#read()
79          */
80         public int read() throws IOException {
81                 try {
82                         return fForward ? readForwards() : readBackwards();
83                 } catch (BadLocationException x) {
84                         throw new IOException(x.getMessage());
85                 }
86         }
87         
88         private void gotoCommentEnd() throws BadLocationException {
89                 while (fOffset < fEnd) {
90                         char current= fDocument.getChar(fOffset++);
91                         if (current == '*') {
92                                 if (fOffset < fEnd && fDocument.getChar(fOffset) == '/') {
93                                         ++ fOffset;
94                                         return;
95                                 }
96                         }
97                 }
98         }
99         
100         private void gotoStringEnd(char delimiter) throws BadLocationException {
101                 while (fOffset < fEnd) {
102                         char current= fDocument.getChar(fOffset++);
103                         if (current == '\\') {
104                                 // ignore escaped characters
105                                 ++ fOffset;
106                         } else if (current == delimiter) {
107                                 return;
108                         }
109                 }
110         }
111         
112         private void gotoLineEnd() throws BadLocationException {
113                 int line= fDocument.getLineOfOffset(fOffset);
114                 fOffset= fDocument.getLineOffset(line + 1);
115         }
116         
117         private int readForwards() throws BadLocationException {
118                 while (fOffset < fEnd) {
119                         char current= fDocument.getChar(fOffset++);
120                         
121                         switch (current) {
122                                 case '/':
123                                         
124                                         if (fSkipComments && fOffset < fEnd) {
125                                                 char next= fDocument.getChar(fOffset);
126                                                 if (next == '*') {
127                                                         // a comment starts, advance to the comment end
128                                                         ++ fOffset;
129                                                         gotoCommentEnd();
130                                                         continue;
131                                                 } else if (next == '/') {
132                                                         // '//'-comment starts, advance to the line end
133                                                         gotoLineEnd();
134                                                         continue;
135                                                 }
136                                         }
137                                         
138                                         return current;
139                                         
140                                 case '"':
141                                 case '\'':
142                                 
143                                         if (fSkipStrings) {
144                                                 gotoStringEnd(current);
145                                                 continue;
146                                         }
147                                         
148                                         return current;
149                         }
150                         
151                         return current;
152                 }
153                 
154                 return EOF;
155         }
156         
157         private void handleSingleLineComment() throws BadLocationException {
158                 int line= fDocument.getLineOfOffset(fOffset);
159                 if (line < fCachedLineNumber) {
160                         fCachedLineNumber= line;
161                         fCachedLineOffset= fDocument.getLineOffset(line);
162                         int offset= fOffset;
163                         while (fCachedLineOffset < offset) {
164                                 char current= fDocument.getChar(offset--);
165                                 if (current == '/' && fCachedLineOffset <= offset && fDocument.getChar(offset) == '/') {
166                                         fOffset= offset;
167                                         return;
168                                 }
169                         }
170                 }
171         }
172         
173         private void gotoCommentStart() throws BadLocationException {
174                 while (0 < fOffset) {
175                         char current= fDocument.getChar(fOffset--);
176                         if (current == '*' && 0 <= fOffset && fDocument.getChar(fOffset) == '/')
177                                 return;
178                 }
179         }
180         
181         private void gotoStringStart(char delimiter) throws BadLocationException {
182                 while (0 < fOffset) {
183                         char current= fDocument.getChar(fOffset);
184                         if (current == delimiter) {
185                                 if ( !(0 <= fOffset && fDocument.getChar(fOffset -1) == '\\'))
186                                         return;
187                         }
188                         -- fOffset;
189                 }
190         }
191                 
192         private int readBackwards() throws BadLocationException {
193                 
194                 while (0 < fOffset) {
195                         -- fOffset;
196                         
197                         handleSingleLineComment();
198                         
199                         char current= fDocument.getChar(fOffset);
200                         switch (current) {
201                                 case '/':
202                                         
203                                         if (fSkipComments && fOffset > 1) {
204                                                 char next= fDocument.getChar(fOffset - 1);
205                                                 if (next == '*') {
206                                                         // a comment ends, advance to the comment start
207                                                         fOffset -= 2;
208                                                         gotoCommentStart();
209                                                         continue;
210                                                 }
211                                         }
212                                         
213                                         return current;
214                                         
215                                 case '"':
216                                 case '\'':
217                                 
218                                         if (fSkipStrings) {
219                                                 -- fOffset;
220                                                 gotoStringStart(current);
221                                                 continue;
222                                         }
223                                         
224                                         return current;
225                         }
226                         
227                         return current;
228                 }
229                 
230                 return EOF;
231         }
232 }
233