]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/utils/MemoReader.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / parsing / utils / MemoReader.java
1 package org.simantics.scl.compiler.internal.parsing.utils;
2
3 import java.io.IOException;
4 import java.io.Reader;
5
6 import org.simantics.scl.compiler.errors.Locations;
7
8 /**
9  * A wrapper to reader that remembers the last characters
10  * read and line numbers.
11  * 
12  * @author Hannu Niemistö
13  */
14 public class MemoReader extends Reader {
15     Reader base;
16     
17     char[] buffer = new char[80];
18     int absoluteBegin = 0;
19     int begin = 0;
20     int end = 0;
21     
22     int firstLine = 1;
23     int[] lineLocations = new int[8];
24     int lineLocationsPos;
25     
26     public MemoReader(Reader base) {
27         this.base = base;
28         addLine(0);
29     }
30     
31     private int findLineLocationArrayOffset(int location) {
32         int l = 0;
33         int h = lineLocationsPos;
34         while(l+1 < h) {
35             int c = (l+h)>>1;
36             int loc = lineLocations[c];
37             if(loc <= location)
38                 l = c;
39             else
40                 h = c;
41         }
42         return l;
43     }
44     
45     private void addLine(int location) {
46         if(lineLocationsPos == lineLocations.length) {
47             int p = findLineLocationArrayOffset(absoluteBegin);
48             if(p*2 >= lineLocationsPos)
49                 System.arraycopy(lineLocations, p, lineLocations, 0, lineLocationsPos-p);
50             else {
51                 int[] newLineLocations = new int[lineLocations.length*2];
52                 System.arraycopy(lineLocations, p, newLineLocations, 0, lineLocationsPos-p);
53                 lineLocations = newLineLocations;
54             }
55             lineLocationsPos -= p;
56             firstLine += p;
57         }
58         lineLocations[lineLocationsPos++] = location;
59     }
60     
61     public String locationToString(int location) {
62         int lOffset = findLineLocationArrayOffset(location);
63         int row = lOffset + firstLine;
64         int column = location + 1 - lineLocations[lOffset];
65         return row + ":" + column;
66     }
67     
68     public String locationToString(long location) {
69         if(location == Locations.NO_LOCATION)
70             return "";
71         else
72             return locationToString(Locations.beginOf(location)) 
73                     + "-" +
74                     locationToString(Locations.endOf(location))
75                     + ": ";
76     }
77     
78     public String locationUnderlining(long coupledLocation) {
79         int beginRow;
80         int beginColumn;
81         int endRow;
82         int endColumn;
83         {
84             int location = Locations.beginOf(coupledLocation);
85             int lOffset = findLineLocationArrayOffset(location);
86             beginRow = lOffset + firstLine;
87             beginColumn = location - lineLocations[lOffset] + 2;
88         }
89         {
90             int location = Locations.endOf(coupledLocation);
91             int lOffset = findLineLocationArrayOffset(location);
92             endRow = lOffset + firstLine;
93             endColumn = location - lineLocations[lOffset] + 2;
94         }
95         StringBuilder b = new StringBuilder();
96         while(b.length() < beginColumn)
97             b.append(' ');
98         if(beginRow == endRow) {
99             int end = Math.max(endColumn, beginColumn+1);
100             while(b.length() < end)
101                 b.append('^');
102         }
103         else
104             b.append("^^^...");
105         b.append(" (").append(beginRow).append(':').append(beginColumn).append('-')
106         .append(endRow).append(':').append(endColumn).append(')');
107         return b.toString();
108     }
109
110     private void ensureCapacity(int count) {
111         if(end + count > buffer.length) {
112             if(end - begin + count <= buffer.length) {
113                 System.arraycopy(buffer, begin, buffer, 0, end-begin);
114                 end -= begin;
115                 begin = 0;
116             }
117             else {
118                 char[] newBuffer = new char[Math.max(buffer.length*2, end+count)];
119                 System.arraycopy(buffer, begin, newBuffer, begin, end-begin);
120                 buffer = newBuffer;
121             }
122         }
123     }
124     
125     @Override
126     public int read(char[] cbuf, int off, int len) throws IOException {
127         int count = base.read(cbuf, off, len);
128         if(count > 0) {
129             for(int i=0;i<count;++i)
130                 if(cbuf[off+i] == '\n')
131                     addLine(end+i+1);
132             ensureCapacity(count);
133             System.arraycopy(cbuf, off, buffer, end, count);
134             end += count;
135         }
136         return count;
137     }
138     
139     @Override
140     public int read() throws IOException {
141         int result = base.read();
142         if(result >= 0) {
143             ensureCapacity(1);
144             buffer[end++] = (char)result;
145             if(result == '\n')
146                 addLine(end);
147         }
148         return result;
149     }
150     
151     public String extractString(long location) {
152         int requestedBegin = Locations.beginOf(location);
153         int requestedEnd = Locations.endOf(location);
154         if(requestedBegin < absoluteBegin)
155             throw new IllegalArgumentException();
156         return new String(buffer,
157                 begin + requestedBegin - absoluteBegin,
158                 requestedEnd-requestedBegin);
159     }
160     
161     public void forgetEverythingBefore(int location) {
162         begin += location-absoluteBegin;
163         absoluteBegin = location;
164     }
165
166     @Override
167     public void close() throws IOException {
168         base.close();
169     }
170
171     public String getLastCommand() {
172         while(true) {
173             try {
174                 int c = read();
175                 if(c < 0 || c == '\n')
176                     break;
177             } catch (IOException e) {
178                 break;
179             }
180         }
181         int p = begin;
182         if(buffer[p] == '\n')
183             ++p;
184         return new String(buffer, p, end-p);
185     }
186
187 }