diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java index 635ec096266e654196e0ba316bf4b1b073197384..1416ca77c41feada5d35aee74e388cf51f641710 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java @@ -427,27 +427,14 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe @TruffleBoundary private static String encodeComplex(RComplex x, int wr, int dr, int er, int wi, int di, int ei, char cdec, int digits, String naString) { - String buff; - String im; - String re; - boolean flagNegIm = false; - RComplex y; - - double xr = x.getRealPart(); - double xi = x.getImaginaryPart(); - /* IEEE allows signed zeros; strip these here */ - if (xr == 0.0) { - xr = 0.0; - } - if (xi == 0.0) { - xi = 0.0; - } + double xr = RRuntime.normalizeZero(x.getRealPart()); + double xi = RRuntime.normalizeZero(x.getImaginaryPart()); if (RRuntime.isNA(xr) || RRuntime.isNA(xi)) { int g = Math.min(wr + wi + 2, (NB - 1)); String fmt = "%" + Utils.asBlankArg(g) + "s"; - buff = Utils.snprintf(NB, + return Utils.snprintf(NB, fmt, /* was "%*s%*s", R_print.gap, "", */ naString); } else { @@ -456,24 +443,25 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe * get strange trailing zeros. But we do want to avoid printing small exponentials that * are probably garbage. */ - y = zprecr(x, digits); + RComplex y = zprecr(x, digits); + String re; if (y.getRealPart() == 0.) { re = DoubleVectorPrinter.encodeReal(y.getRealPart(), wr, dr, er, cdec, naString); } else { re = DoubleVectorPrinter.encodeReal(xr, wr, dr, er, cdec, naString); } - flagNegIm = xi < 0; + boolean flagNegIm = xi < 0; if (flagNegIm) { xi = -xi; } + String im; if (y.getImaginaryPart() == 0.) { im = DoubleVectorPrinter.encodeReal(y.getImaginaryPart(), wi, di, ei, cdec, naString); } else { im = DoubleVectorPrinter.encodeReal(xi, wi, di, ei, cdec, naString); } - buff = snprintf(NB, "%s%s%si", re, flagNegIm ? "-" : "+", im); + return snprintf(NB, "%s%s%si", re, flagNegIm ? "-" : "+", im); } - return buff; } public static String[] format(RAbstractComplexVector value, boolean trim, int nsmall, int width, char decimalMark, PrintParameters pp) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java index 9ee413f6e6f9a50696f92847f6361c4628c1038d..d3ebedd8fe3c597764ce73f4e78956df9d057640 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java @@ -11,11 +11,7 @@ */ package com.oracle.truffle.r.nodes.builtin.base.printer; -import static com.oracle.truffle.r.nodes.builtin.base.printer.Utils.snprintf; - import java.io.IOException; -import java.math.RoundingMode; -import java.text.DecimalFormat; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.runtime.RRuntime; @@ -312,9 +308,9 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect * assumption that R_dec_min_exponent+303 is in range. Representation of 1e+303 has * low error. */ - rPrec = (rPrec * 1e+303) / Math.pow(10, kp + 303); + rPrec = (rPrec * 1e+303) / DECIMAL_WEIGHTS[kp + 303 + DECIMAL_SHIFT]; } else { - rPrec /= Math.pow(10, kp); + rPrec /= DECIMAL_WEIGHTS[kp + DECIMAL_SHIFT]; } if (rPrec < tbl[digits]) { rPrec *= 10.0; @@ -354,7 +350,6 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect double fuzz = 0.5 / tbl[1 + rgt]; // kpower can be bigger than the table. roundingwidens = kpower > 0 && kpower <= KP_MAX && r < tbl[kpower + 1] - fuzz; - } return new ScientificDouble(sgn, kpower, nsig, roundingwidens); @@ -386,14 +381,27 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect return encodeReal(x, dm.maxWidth, dm.d, dm.e, '.', pp); } - // caching some commonly used formats - private static final DecimalFormat[] CACHED_FORMATS = new DecimalFormat[32]; + private static final int DECIMAL_SHIFT = 350; + private static final double[][] DECIMAL_VALUES = new double[700][10]; + private static final double[] DECIMAL_WEIGHTS = new double[700]; + + static { + for (int i = 0; i < DECIMAL_WEIGHTS.length; i++) { + DECIMAL_WEIGHTS[i] = Math.pow(10, i - DECIMAL_SHIFT); + } + for (int i = 0; i < DECIMAL_VALUES.length; i++) { + for (int i2 = 0; i2 < 10; i2++) { + DECIMAL_VALUES[i][i2] = Math.pow(10, i - DECIMAL_SHIFT) * i2; + } + } + } @TruffleBoundary static String encodeReal(double initialX, int w, int d, int e, char cdec, String naString) { /* IEEE allows signed zeros (yuck!) */ double x = RRuntime.normalizeZero(initialX); + StringBuilder str = new StringBuilder(w); if (!RRuntime.isFinite(x)) { String id; if (RRuntime.isNA(x)) { @@ -403,49 +411,120 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect } else { id = x > 0 ? "Inf" : "-Inf"; } - return prependBlanks(w, id); - } else if (e != 0) { - String fmt = String.format((d != 0) ? "%%#%d.%de" : "%%%d.%de", Math.min(w, (NB - 1)), d); - String result; - if (Math.abs(x) < 1e-300 && Math.abs(x) >= Double.MIN_VALUE) { - // work around java formatting bug for small numbers like 1.53160350210786e-322 - result = snprintf(NB, fmt, x * 1e100); - StringBuilder str = new StringBuilder(result); - assert str.charAt(str.length() - 3) == '2'; - str.setCharAt(str.length() - 3, '3'); - result = str.toString(); - } else { - result = snprintf(NB, fmt, x); + int blanks = w - id.length(); + for (int i = 0; i < blanks; i++) { + str.append(' '); } - return result.replace('.', cdec); - } else { /* e = 0 */ - DecimalFormat df = null; - if (d < CACHED_FORMATS.length) { - df = CACHED_FORMATS[d]; + str.append(id); + } else { + boolean negated = x < 0; + if (negated) { + x = -x; } - if (df == null) { - df = new DecimalFormat("#.#"); - df.setRoundingMode(RoundingMode.HALF_EVEN); - df.setDecimalSeparatorAlwaysShown(false); - df.setMinimumFractionDigits(d); - df.setMaximumFractionDigits(d); - if (d < CACHED_FORMATS.length) { - CACHED_FORMATS[d] = df; + if (e != 0) { + + boolean shifted = false; + int log10; + int adjustedE = e; + if (x == 0) { + log10 = 0; + } else { + if (x < 1e-300) { + shifted = true; + x *= 1e100; + } + log10 = (int) Math.log10(x); + if (DECIMAL_WEIGHTS[log10 + DECIMAL_SHIFT] > x) { + // log10 behaves differently for < 1.0 + log10--; + } + if (log10 <= -100 || log10 >= 100) { + adjustedE = 3; + } + } + int blanks = w // target width + - (negated ? 1 : 0) // "-" + - 1 // digits before "." + - (d > 0 ? 1 : 0) // "." + - d // digits after "." + - 1 // "e" + - 1 // "+/-" for exponent + - Math.max(2, adjustedE); // digits for exponent + for (int i = 0; i < blanks; i++) { + str.append(' '); + } + // round towards next digit instead of truncating + double rounded = x + DECIMAL_VALUES[log10 - d - 1 + DECIMAL_SHIFT][5]; + if (Double.isFinite(rounded)) { + x = rounded; + // the rounding might have modified the exponent + if (DECIMAL_WEIGHTS[log10 + 1 + DECIMAL_SHIFT] <= x) { + log10++; + } + } + if (negated) { + str.append('-'); + } + x = appendDigit(x, log10, str); + if (d > 0) { + str.append(cdec); + for (int i = 1; i <= d; i++) { + x = appendDigit(x, log10 - i, str); + } + } + str.append('e'); + if (log10 < 0) { + str.append('-'); + log10 = -log10; + } else { + str.append('+'); + } + if (shifted) { + log10 += 100; + } + if (adjustedE >= 3) { + str.append((char) ('0' + (log10 / 100))); + log10 = log10 % 100; + } + str.append((char) ('0' + (log10 / 10))); + str.append((char) ('0' + (log10 % 10))); + } else { /* e == 0 */ + // round towards next digit instead of truncating + x += DECIMAL_VALUES[-d - 1 + DECIMAL_SHIFT][5]; + + int log10 = x == 0 ? 0 : Math.max((int) Math.log10(x), 0); + int blanks = w // target width + - (negated ? 1 : 0) // "-" + - (log10 + 1) // digits before "." + - (d > 0 ? 1 : 0) // "." + - d; // digits after "." + + for (int i = 0; i < blanks; i++) { + str.append(' '); + } + if (negated) { + str.append('-'); + } + for (int i = log10; i >= 0; i--) { + x = appendDigit(x, i, str); + } + if (d > 0) { + str.append(cdec); + for (int i = 1; i <= d; i++) { + x = appendDigit(x, -i, str); + } } } - return prependBlanks(w, df.format(x)).replace('.', cdec); } + assert str.length() >= w; + return str.toString(); } - private static String prependBlanks(int width, String id) { - if (id.length() >= width) { - return id; - } - StringBuilder str = new StringBuilder(width); - for (int i = 0; i < width - id.length(); i++) { - str.append(' '); - } - return str.append(id).toString(); + private static double appendDigit(double x, int digit, StringBuilder str) { + int c = (int) (x / DECIMAL_WEIGHTS[digit + DECIMAL_SHIFT]); + assert c >= 0 && c <= 9; + str.append((char) ('0' + c)); + return x - DECIMAL_VALUES[digit + DECIMAL_SHIFT][c]; } public static String[] format(RAbstractDoubleVector value, boolean trim, int nsmall, int width, char decimalMark, PrintParameters pp) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FormatMetrics.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FormatMetrics.java index 052d4675874c6853669d8229963763e069e200ca..c0f020d91e9eaba2f3b4519c7d60493d2ef0c40b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FormatMetrics.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FormatMetrics.java @@ -25,7 +25,7 @@ package com.oracle.truffle.r.nodes.builtin.base.printer; /** * The generic formatting metrics. N.B. This class is public since it is used in the PrettyWriter * public API. - * + * * @see PrettyWriter */ public class FormatMetrics { @@ -34,7 +34,6 @@ public class FormatMetrics { int maxWidth; FormatMetrics(int maxWidth) { - super(); this.originalMaxWidth = maxWidth; this.maxWidth = maxWidth; } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java index 5453a2fa40ab27cf826ab8da4ca2a6f58cda10b8..f9d0ea7c4f89cb0cf9b1470a644d0615fee0eed6 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java @@ -46,7 +46,7 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector @Override protected FormatMetrics formatVector(int offs, int len) { - return formatIntVector(vector, offs, len, printCtx.parameters().getNaWidth()); + return new FormatMetrics(formatIntVectorInternal(vector, offs, len, printCtx.parameters().getNaWidth())); } @Override @@ -66,7 +66,7 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector } } - public static FormatMetrics formatIntVector(RAbstractIntVector x, int offs, int n, int naWidth) { + static int formatIntVectorInternal(RAbstractIntVector x, int offs, int n, int naWidth) { int xmin = RRuntime.INT_MAX_VALUE; int xmax = RRuntime.INT_MIN_VALUE; boolean naflag = false; @@ -105,21 +105,62 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector fieldwidth = l; } } + return fieldwidth; + } + + private static final int[][] DECIMAL_VALUES = new int[10][10]; + private static final int[] DECIMAL_WEIGHTS = new int[10]; - return new FormatMetrics(fieldwidth); + static { + for (int i = 0; i < DECIMAL_WEIGHTS.length; i++) { + DECIMAL_WEIGHTS[i] = (int) Math.pow(10, i); + } + for (int i = 0; i < DECIMAL_VALUES.length; i++) { + for (int i2 = 0; i2 < 10; i2++) { + DECIMAL_VALUES[i][i2] = (int) (Math.pow(10, i) * i2); + } + } } - /* - * There is no documented (or enforced) limit on 'w' here, so use snprintf - */ - static int NB = 1000; + public static String encodeInteger(int initialX, int w, PrintParameters pp) { + StringBuilder str = new StringBuilder(w); - public static String encodeInteger(int x, int w, PrintParameters pp) { - if (x == RRuntime.INT_NA) { - return Utils.snprintf(NB, "%" + Utils.asBlankArg(Math.min(w, (NB - 1))) + "s", pp.getNaString()); + int x = initialX; + if (RRuntime.isNA(x)) { + String id = pp.getNaString(); + for (int i = w - id.length(); i > 0; i--) { + str.append(' '); + } + str.append(id); } else { - return Utils.snprintf(NB, "%" + Utils.asBlankArg(Math.min(w, (NB - 1))) + "d", x); + boolean negated = false; + if (x < 0) { + negated = true; + x = -x; + } + int log10 = x == 0 ? 0 : (int) Math.log10(x); + int blanks = w // target width + - (negated ? 1 : 0) // "-" + - (log10 + 1); // digits + + for (int i = 0; i < blanks; i++) { + str.append(' '); + } + if (negated) { + str.append('-'); + } + for (int i = log10; i >= 0; i--) { + x = appendDigit(x, i, str); + } } + return str.toString(); + } + + private static int appendDigit(int x, int digit, StringBuilder str) { + int c = x / DECIMAL_WEIGHTS[digit]; + assert c >= 0 && c <= 9; + str.append((char) ('0' + c)); + return x - DECIMAL_VALUES[digit][c]; } public static String[] format(RAbstractIntVector value, boolean trim, int width, PrintParameters pp) { @@ -127,8 +168,7 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector if (trim) { w = 1; } else { - FormatMetrics metrics = formatIntVector(value, 0, value.getLength(), pp.getNaWidth()); - w = metrics.maxWidth; + w = formatIntVectorInternal(value, 0, value.getLength(), pp.getNaWidth()); } w = Math.max(w, width); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java index 3cde3e059f0377c95c9090efa054f8b38b05f3e0..143286861af82a99f79bd35bbf5d0f5d780dacc7 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java @@ -78,8 +78,8 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> { } else if (tmp instanceof RAbstractLogicalVector) { RAbstractLogicalVector lv = (RAbstractLogicalVector) tmp; if (lv.getLength() == 1) { - FormatMetrics fm = LogicalVectorPrinter.formatLogicalVector(lv, 0, 1, pp.getNaWidth()); - pbuf = LogicalVectorPrinter.encodeLogical(lv.getDataAt(0), fm.maxWidth, pp); + int width = LogicalVectorPrinter.formatLogicalVectorInternal(lv, 0, 1, pp.getNaWidth()); + pbuf = LogicalVectorPrinter.encodeLogical(lv.getDataAt(0), width, pp); } else { pbuf = "Logical," + lv.getLength(); } @@ -90,8 +90,8 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> { pbuf = "factor," + iv.getLength(); } else { if (iv.getLength() == 1) { - FormatMetrics fm = IntegerVectorPrinter.formatIntVector(iv, 0, 1, pp.getNaWidth()); - pbuf = IntegerVectorPrinter.encodeInteger(iv.getDataAt(0), fm.maxWidth, pp); + int width = IntegerVectorPrinter.formatIntVectorInternal(iv, 0, 1, pp.getNaWidth()); + pbuf = IntegerVectorPrinter.encodeInteger(iv.getDataAt(0), width, pp); } else { pbuf = "Integer," + iv.getLength(); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java index 29231624992cce41ae975e5c03bbc1b88038f6fa..3421a15d5b01f989d577a8e5b274bea67a117002 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java @@ -11,9 +11,6 @@ */ package com.oracle.truffle.r.nodes.builtin.base.printer; -import static com.oracle.truffle.r.nodes.builtin.base.printer.IntegerVectorPrinter.NB; -import static com.oracle.truffle.r.nodes.builtin.base.printer.Utils.snprintf; - import java.io.IOException; import com.oracle.truffle.r.runtime.RRuntime; @@ -47,13 +44,12 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe @Override protected FormatMetrics formatVector(int offs, int len) { - return formatLogicalVector(vector, offs, len, printCtx.parameters().getNaWidth()); + return new FormatMetrics(formatLogicalVectorInternal(vector, offs, len, printCtx.parameters().getNaWidth())); } @Override protected void printElement(int i, FormatMetrics fm) throws IOException { - String v = encodeLogical(vector.getDataAt(i), fm.maxWidth, printCtx.parameters()); - out.print(v); + out.print(encodeLogical(vector.getDataAt(i), fm.maxWidth, printCtx.parameters())); } @Override @@ -67,7 +63,7 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe } } - static FormatMetrics formatLogicalVector(RAbstractLogicalVector x, int offs, int n, int naWidth) { + static int formatLogicalVectorInternal(RAbstractLogicalVector x, int offs, int n, int naWidth) { int fieldwidth = 1; for (int i = 0; i < n; i++) { byte xi = x.getDataAt(offs + i); @@ -83,18 +79,29 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe /* this is the widest it can be, so stop */ } } - return new FormatMetrics(fieldwidth); + return fieldwidth; } static String encodeLogical(byte x, int w, PrintParameters pp) { - final String fmt = "%" + Utils.asBlankArg(Math.min(w, (NB - 1))) + "s"; + String id; if (x == RRuntime.LOGICAL_NA) { - return snprintf(NB, fmt, pp.getNaString()); - } else if (x != 0) { - return snprintf(NB, fmt, "TRUE"); + id = pp.getNaString(); + } else if (x != RRuntime.LOGICAL_FALSE) { + id = "TRUE"; } else { - return snprintf(NB, fmt, "FALSE"); + id = "FALSE"; + } + if (id.length() == w) { + return id; + } + int blanks = w // target width + - id.length(); // text + StringBuilder str = new StringBuilder(); + for (int i = 0; i < blanks; i++) { + str.append(' '); } + str.append(id); + return str.toString(); } public static String[] format(RAbstractLogicalVector value, boolean trim, int width, PrintParameters pp) { @@ -102,8 +109,7 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe if (trim) { w = 1; } else { - FormatMetrics metrics = formatLogicalVector(value, 0, value.getLength(), pp.getNaWidth()); - w = metrics.maxWidth; + w = formatLogicalVectorInternal(value, 0, value.getLength(), pp.getNaWidth()); } w = Math.max(w, width); diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java index 94f637415f1fe568928a9a04b078e6e1ded0cad0..e7e235f3364dccf7ef83477e84354303437ac3d4 100644 --- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java +++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java @@ -91,6 +91,7 @@ public class ParserGeneration { "different warning for hex and dec integer literals", "raise ZERO_LENGTH_VARIABLE errors in parser", "support for file delimiter", - "pass along TruffleRLanguage" + "pass along TruffleRLanguage", + "convert line endings" }; } diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g index 9d70c927cee394c83f6d886ab6b652d75fea877f..2cfda4f041a34406cae79c0440ec0ed04bab8790 100644 --- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g +++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g @@ -29,6 +29,10 @@ package com.oracle.truffle.r.parser; import java.util.ArrayList; import java.util.List; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.net.URISyntaxException; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.frame.MaterializedFrame; @@ -149,9 +153,15 @@ import com.oracle.truffle.r.runtime.RError; if(q0 != -1 && q1 != -1) { String path = commentLine.substring(q0+1, q1); try { - source = RSource.fromFileName(path, false); + String content = new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8); + String lineEnding = detectLineEnding(initialSource.getCode()); + content = convertToLineEnding(content, lineEnding); + source = RSource.fromFileName(content, path, false); fileStartOffset = commentToken.getStopIndex() + 1; } catch (IOException e) { + resetSource(); + } catch (URISyntaxException e) { + resetSource(); } } else { // fall back and use the initial source (the file being parsed) @@ -165,6 +175,25 @@ import com.oracle.truffle.r.runtime.RError; fileStartOffset = 0; } + private String detectLineEnding(String code) { + int lf = code.indexOf("\n"); + int crlf = code.indexOf("\r\n"); + + if(crlf != -1 && crlf < lf) { + return "\r\n"; + } + return "\n"; + } + + private String convertToLineEnding(String content, String lineEnding) { + if("\n".equals(lineEnding)) { + return content.replaceAll("\\r\\n", "\n"); + } else if("\r\n".equals(lineEnding)) { + return content.replaceAll("\\n", "\r\n"); + } + return content; + } + // without this override, the parser will not throw exceptions if it can recover @Override protected Object recoverFromMismatchedToken(IntStream input, int expected, BitSet follow) throws RecognitionException { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateRConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateRConnection.java index d43eeb8e783e736fc98265c4972b04c6e6cd8f68..79911c2ea1a89f89c83829060c0a7021336f1895 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateRConnection.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateRConnection.java @@ -54,26 +54,40 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; * </p> */ abstract class DelegateRConnection implements RConnection, ByteChannel { - private static final int DEFAULT_CACHE_SIZE = 16 * 1024; + public static final int DEFAULT_CACHE_SIZE = 16 * 1024; protected final BaseRConnection base; private final ByteBuffer cache; + private final boolean readCache; DelegateRConnection(BaseRConnection base) { - this(base, DEFAULT_CACHE_SIZE); + this(base, DEFAULT_CACHE_SIZE, true); } - DelegateRConnection(BaseRConnection base, int cacheSize) { + DelegateRConnection(BaseRConnection base, int cacheSize, boolean readCache) { this.base = Objects.requireNonNull(base); + this.readCache = readCache; if (cacheSize > 0) { cache = ByteBuffer.allocate(cacheSize); - // indicate that there are no remaining bytes in the buffer - cache.flip(); + + // indicate that there are no remaining bytes in the buffer to read + if (readCache) { + cache.flip(); + } } else { cache = null; } } + private static int transfer(ByteBuffer from, ByteBuffer to) { + int nbytes = Math.min(to.remaining(), from.remaining()); + if (nbytes > 0) { + to.put(from.array(), from.arrayOffset() + from.position(), nbytes); + from.position(from.position() + nbytes); + } + return nbytes; + } + @Override public int getDescriptor() { return base.getDescriptor(); @@ -438,7 +452,7 @@ abstract class DelegateRConnection implements RConnection, ByteChannel { @Override @TruffleBoundary public int read(ByteBuffer dst) throws IOException { - if (cache != null) { + if (readCache && cache != null) { final int bytesRequested = dst.remaining(); int totalBytesRead = 0; int bytesToRead = 0; @@ -459,7 +473,19 @@ abstract class DelegateRConnection implements RConnection, ByteChannel { @Override @TruffleBoundary public int write(ByteBuffer src) throws IOException { - return getChannel().write(src); + if (!readCache && cache != null) { + int total = 0; + while (src.hasRemaining()) { + total += transfer(src, cache); + if (!cache.hasRemaining()) { + flush(); + } + } + return total; + } else { + invalidateCache(); + return getChannel().write(src); + } } /** @@ -471,7 +497,7 @@ abstract class DelegateRConnection implements RConnection, ByteChannel { * </p> */ protected int readInternal() throws IOException { - if (cache != null) { + if (readCache && cache != null) { ensureDataAvailable(1); if (!cache.hasRemaining()) { return -1; @@ -567,7 +593,11 @@ abstract class DelegateRConnection implements RConnection, ByteChannel { @Override public void flush() throws IOException { - // nothing to do for channels + if (!readCache && cache != null) { + cache.flip(); + getChannel().write(cache); + cache.clear(); + } } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadRConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadRConnection.java index d4b11c2d5723c037e1839c5f26b05f31b6e98bb5..ba4245207dd183a0c38d76259ca6c078a764431e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadRConnection.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadRConnection.java @@ -38,7 +38,7 @@ public abstract class DelegateReadRConnection extends DelegateRConnection { } protected DelegateReadRConnection(BaseRConnection base, int cacheSize) { - super(base, cacheSize); + super(base, cacheSize, true); } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadWriteRConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadWriteRConnection.java index c445251b02495f80207f0c2507bcc046e64eadb9..01c2464bd6523b45e5ddf7ff394780b0c061a387 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadWriteRConnection.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadWriteRConnection.java @@ -31,7 +31,7 @@ abstract class DelegateReadWriteRConnection extends DelegateRConnection { } protected DelegateReadWriteRConnection(BaseRConnection base, int cacheSize) { - super(base, cacheSize); + super(base, cacheSize, true); } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateWriteRConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateWriteRConnection.java index 16503501a0914f0e299d5e7c06f1eda99d0d4e88..f436a0a2f12b44520dafa0c0a63caff6467bde1a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateWriteRConnection.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateWriteRConnection.java @@ -33,7 +33,11 @@ import com.oracle.truffle.r.runtime.conn.ConnectionSupport.BaseRConnection; abstract class DelegateWriteRConnection extends DelegateRConnection { protected DelegateWriteRConnection(BaseRConnection base) { - super(base, 0); + super(base, 0, false); + } + + protected DelegateWriteRConnection(BaseRConnection base, int cacheSize) { + super(base, cacheSize, false); } @Override @@ -75,4 +79,10 @@ abstract class DelegateWriteRConnection extends DelegateRConnection { public boolean canWrite() { return true; } + + @Override + public void close() throws IOException { + flush(); + super.close(); + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java index b14529c998dfd7df4fa202a0df4e432724a99b7c..36e4f8e3fc6c6f19d8ecf941678405190e11214c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java @@ -324,7 +324,7 @@ public class FileConnections { private final FileChannel channel; FileWriteBinaryConnection(BasePathRConnection base, boolean append) throws IOException { - super(base); + super(base, 0); List<OpenOption> opts = new ArrayList<>(); opts.add(StandardOpenOption.WRITE); opts.add(StandardOpenOption.CREATE);