]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/utils/MemoReader.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/utils/MemoReader.java
new file mode 100644 (file)
index 0000000..3d74887
--- /dev/null
@@ -0,0 +1,187 @@
+package org.simantics.scl.compiler.internal.parsing.utils;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.simantics.scl.compiler.errors.Locations;
+
+/**
+ * A wrapper to reader that remembers the last characters
+ * read and line numbers.
+ * 
+ * @author Hannu Niemistö
+ */
+public class MemoReader extends Reader {
+    Reader base;
+    
+    char[] buffer = new char[80];
+    int absoluteBegin = 0;
+    int begin = 0;
+    int end = 0;
+    
+    int firstLine = 1;
+    int[] lineLocations = new int[8];
+    int lineLocationsPos;
+    
+    public MemoReader(Reader base) {
+        this.base = base;
+        addLine(0);
+    }
+    
+    private int findLineLocationArrayOffset(int location) {
+        int l = 0;
+        int h = lineLocationsPos;
+        while(l+1 < h) {
+            int c = (l+h)>>1;
+            int loc = lineLocations[c];
+            if(loc <= location)
+                l = c;
+            else
+                h = c;
+        }
+        return l;
+    }
+    
+    private void addLine(int location) {
+        if(lineLocationsPos == lineLocations.length) {
+            int p = findLineLocationArrayOffset(absoluteBegin);
+            if(p*2 >= lineLocationsPos)
+                System.arraycopy(lineLocations, p, lineLocations, 0, lineLocationsPos-p);
+            else {
+                int[] newLineLocations = new int[lineLocations.length*2];
+                System.arraycopy(lineLocations, p, newLineLocations, 0, lineLocationsPos-p);
+                lineLocations = newLineLocations;
+            }
+            lineLocationsPos -= p;
+            firstLine += p;
+        }
+        lineLocations[lineLocationsPos++] = location;
+    }
+    
+    public String locationToString(int location) {
+        int lOffset = findLineLocationArrayOffset(location);
+        int row = lOffset + firstLine;
+        int column = location + 1 - lineLocations[lOffset];
+        return row + ":" + column;
+    }
+    
+    public String locationToString(long location) {
+        if(location == Locations.NO_LOCATION)
+            return "";
+        else
+            return locationToString(Locations.beginOf(location)) 
+                    + "-" +
+                    locationToString(Locations.endOf(location))
+                    + ": ";
+    }
+    
+    public String locationUnderlining(long coupledLocation) {
+        int beginRow;
+        int beginColumn;
+        int endRow;
+        int endColumn;
+        {
+            int location = Locations.beginOf(coupledLocation);
+            int lOffset = findLineLocationArrayOffset(location);
+            beginRow = lOffset + firstLine;
+            beginColumn = location - lineLocations[lOffset] + 2;
+        }
+        {
+            int location = Locations.endOf(coupledLocation);
+            int lOffset = findLineLocationArrayOffset(location);
+            endRow = lOffset + firstLine;
+            endColumn = location - lineLocations[lOffset] + 2;
+        }
+        StringBuilder b = new StringBuilder();
+        while(b.length() < beginColumn)
+            b.append(' ');
+        if(beginRow == endRow) {
+            int end = Math.max(endColumn, beginColumn+1);
+            while(b.length() < end)
+                b.append('^');
+        }
+        else
+            b.append("^^^...");
+        b.append(" (").append(beginRow).append(':').append(beginColumn).append('-')
+        .append(endRow).append(':').append(endColumn).append(')');
+        return b.toString();
+    }
+
+    private void ensureCapacity(int count) {
+        if(end + count > buffer.length) {
+            if(end - begin + count <= buffer.length) {
+                System.arraycopy(buffer, begin, buffer, 0, end-begin);
+                end -= begin;
+                begin = 0;
+            }
+            else {
+                char[] newBuffer = new char[Math.max(buffer.length*2, end+count)];
+                System.arraycopy(buffer, begin, newBuffer, begin, end-begin);
+                buffer = newBuffer;
+            }
+        }
+    }
+    
+    @Override
+    public int read(char[] cbuf, int off, int len) throws IOException {
+        int count = base.read(cbuf, off, len);
+        if(count > 0) {
+            for(int i=0;i<count;++i)
+                if(cbuf[off+i] == '\n')
+                    addLine(end+i+1);
+            ensureCapacity(count);
+            System.arraycopy(cbuf, off, buffer, end, count);
+            end += count;
+        }
+        return count;
+    }
+    
+    @Override
+    public int read() throws IOException {
+        int result = base.read();
+        if(result >= 0) {
+            ensureCapacity(1);
+            buffer[end++] = (char)result;
+            if(result == '\n')
+                addLine(end);
+        }
+        return result;
+    }
+    
+    public String extractString(long location) {
+        int requestedBegin = Locations.beginOf(location);
+        int requestedEnd = Locations.endOf(location);
+        if(requestedBegin < absoluteBegin)
+            throw new IllegalArgumentException();
+        return new String(buffer,
+                begin + requestedBegin - absoluteBegin,
+                requestedEnd-requestedBegin);
+    }
+    
+    public void forgetEverythingBefore(int location) {
+        begin += location-absoluteBegin;
+        absoluteBegin = location;
+    }
+
+    @Override
+    public void close() throws IOException {
+        base.close();
+    }
+
+    public String getLastCommand() {
+        while(true) {
+            try {
+                int c = read();
+                if(c < 0 || c == '\n')
+                    break;
+            } catch (IOException e) {
+                break;
+            }
+        }
+        int p = begin;
+        if(buffer[p] == '\n')
+            ++p;
+        return new String(buffer, p, end-p);
+    }
+
+}