diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java index 3df94adeb5f6b2628e155046868fa10f6280a2c3..004ef00391e0417bea13374007b7cf7421d7806b 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java @@ -22,6 +22,8 @@ */ package com.oracle.truffle.r.engine; +import java.io.PrintStream; +import java.io.PrintWriter; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -380,11 +382,15 @@ final class REngine implements Engine, Engine.Timings { } catch (ReturnException ex) { return ex.getResult(); } catch (DebugExitException | JumpToTopLevelException | ExitException | ThreadDeath e) { + CompilerDirectives.transferToInterpreter(); throw e; } catch (RError e) { CompilerDirectives.transferToInterpreter(); throw e; } catch (Throwable t) { + CompilerDirectives.transferToInterpreter(); + // other errors didn't produce an output yet + RInternalError.reportError(t); throw t; } finally { RContext.setThreadLocalInstance(oldContext); diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java index 0901e341ed7968d6bd23a261cc6ee89e9fa31920..a173a08ec6434ba0b0ac7cf5e8bba231bb3e4fe7 100644 --- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java +++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java @@ -269,7 +269,7 @@ public class RCommand { } else if (e.isExit()) { // usually from quit throw new ExitException(e.getExitStatus()); - } else if (e.isHostException()) { + } else if (e.isHostException() || e.isInternalError()) { // we continue the repl even though the system may be broken lastStatus = 1; } else if (e.isGuestException()) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java index 79152550b9fa1d292b20e134f0182470f1179629..ccc5f3390a4957c3831ae29c75721005c5d54f9a 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java @@ -39,6 +39,7 @@ import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode; import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RegExp; @@ -221,81 +222,85 @@ public class GrepFunctions { protected Object doGrep(String patternArg, RAbstractStringVector vector, boolean ignoreCase, boolean value, boolean perlPar, boolean fixed, @SuppressWarnings("unused") boolean useBytes, boolean invert, boolean grepl) { - boolean perl = perlPar; - perl = checkPerlFixed(perlPar, fixed); - checkCaseFixed(ignoreCase, fixed); - - String pattern = patternArg; - int len = vector.getLength(); - if (RRuntime.isNA(pattern)) { - return value ? allStringNAResult(len) : allIntNAResult(len); - } - boolean[] matches = new boolean[len]; - if (!perl) { - // TODO case - if (!fixed) { - pattern = RegExp.checkPreDefinedClasses(pattern); + try { + boolean perl = perlPar; + perl = checkPerlFixed(perlPar, fixed); + checkCaseFixed(ignoreCase, fixed); + + String pattern = patternArg; + int len = vector.getLength(); + if (RRuntime.isNA(pattern)) { + return value ? allStringNAResult(len) : allIntNAResult(len); } - findAllMatches(matches, pattern, vector, fixed, ignoreCase); - } else { - PCRERFFI.Result pcre = compilePerlPattern(pattern, ignoreCase); - // TODO pcre_study for vectors > 10 ? (cf GnuR) - int[] ovector = new int[30]; - for (int i = 0; i < len; i++) { - String text = vector.getDataAt(i); - if (!RRuntime.isNA(text)) { - if (execNode.execute(pcre.result, 0, text, 0, 0, ovector) >= 0) { - matches[i] = true; + boolean[] matches = new boolean[len]; + if (!perl) { + // TODO case + if (!fixed) { + pattern = RegExp.checkPreDefinedClasses(pattern); + } + findAllMatches(matches, pattern, vector, fixed, ignoreCase); + } else { + PCRERFFI.Result pcre = compilePerlPattern(pattern, ignoreCase); + // TODO pcre_study for vectors > 10 ? (cf GnuR) + int[] ovector = new int[30]; + for (int i = 0; i < len; i++) { + String text = vector.getDataAt(i); + if (!RRuntime.isNA(text)) { + if (execNode.execute(pcre.result, 0, text, 0, 0, ovector) >= 0) { + matches[i] = true; + } } } } - } - if (grepl) { - byte[] data = new byte[len]; - for (int i = 0; i < len; i++) { - data[i] = RRuntime.asLogical(matches[i]); + if (grepl) { + byte[] data = new byte[len]; + for (int i = 0; i < len; i++) { + data[i] = RRuntime.asLogical(matches[i]); + } + return RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR); } - return RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR); - } - int nmatches = 0; - for (int i = 0; i < len; i++) { - if (invert ^ matches[i]) { - nmatches++; + int nmatches = 0; + for (int i = 0; i < len; i++) { + if (invert ^ matches[i]) { + nmatches++; + } } - } - if (nmatches == 0) { - return value ? RDataFactory.createEmptyStringVector() : RDataFactory.createEmptyIntVector(); - } else { - if (value) { - RStringVector oldNames = vector.getNames(); - String[] newNames = null; - if (oldNames != null) { - newNames = new String[nmatches]; - } - String[] data = new String[nmatches]; - int j = 0; - for (int i = 0; i < len; i++) { - if (invert ^ matches[i]) { - if (newNames != null) { - newNames[j] = oldNames.getDataAt(i); + if (nmatches == 0) { + return value ? RDataFactory.createEmptyStringVector() : RDataFactory.createEmptyIntVector(); + } else { + if (value) { + RStringVector oldNames = vector.getNames(); + String[] newNames = null; + if (oldNames != null) { + newNames = new String[nmatches]; + } + String[] data = new String[nmatches]; + int j = 0; + for (int i = 0; i < len; i++) { + if (invert ^ matches[i]) { + if (newNames != null) { + newNames[j] = oldNames.getDataAt(i); + } + data[j++] = vector.getDataAt(i); } - data[j++] = vector.getDataAt(i); } - } - return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR, newNames == null ? null : RDataFactory.createStringVector(newNames, RDataFactory.COMPLETE_VECTOR)); - } else { - int[] data = new int[nmatches]; - int j = 0; - for (int i = 0; i < len; i++) { - if (invert ^ matches[i]) { - data[j++] = i + 1; + return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR, newNames == null ? null : RDataFactory.createStringVector(newNames, RDataFactory.COMPLETE_VECTOR)); + } else { + int[] data = new int[nmatches]; + int j = 0; + for (int i = 0; i < len; i++) { + if (invert ^ matches[i]) { + data[j++] = i + 1; + } } + return RDataFactory.createIntVector(data, RDataFactory.COMPLETE_VECTOR); } - return RDataFactory.createIntVector(data, RDataFactory.COMPLETE_VECTOR); } + } catch (PatternSyntaxException e) { + throw error(Message.INVALID_REGEXP_REASON, patternArg, e.getMessage()); } } @@ -543,8 +548,7 @@ public class GrepFunctions { ret.copyAttributesFrom(vector); return ret; } catch (PatternSyntaxException e) { - CompilerDirectives.transferToInterpreter(); - throw new RInternalError(e, "internal error: %s", e.getMessage()); + throw error(Message.INVALID_REGEXP_REASON, patternArg, e.getMessage()); } } @@ -784,71 +788,76 @@ public class GrepFunctions { @TruffleBoundary protected Object regexp(RAbstractStringVector patternArg, RAbstractStringVector vector, boolean ignoreCase, boolean perl, boolean fixed, boolean useBytesL, @Cached("createCommon()") CommonCodeNode common) { - common.checkExtraArgs(false, false, false, useBytesL, false); - if (patternArg.getLength() > 1) { - throw RInternalError.unimplemented("multi-element patterns in regexpr not implemented yet"); - } - String pattern = patternArg.getDataAt(0); - if (!perl) { - pattern = RegExp.checkPreDefinedClasses(pattern); - } - // TODO: useBytes normally depends on the value of the parameter and (if false) on - // whether the string is ASCII - boolean useBytes = true; - boolean hasAnyCapture = false; - int[] result = new int[vector.getLength()]; - int[] matchLength = new int[vector.getLength()]; - String[] captureNames = null; - int[] captureStart = null; - int[] captureLength = null; - if (pattern.length() == 0) { - // emtpy pattern - Arrays.fill(result, 1); - } else { - for (int i = 0; i < vector.getLength(); i++) { - Info res = getInfo(common, pattern, vector.getDataAt(i), ignoreCase, perl, fixed).get(0); - result[i] = res.index; - matchLength[i] = res.size; - if (res.hasCapture) { - hasAnyCapture = true; - if (captureNames == null) { - // first time we see captures - captureNames = res.captureNames; - captureStart = new int[captureNames.length * vector.getLength()]; - captureLength = new int[captureNames.length * vector.getLength()]; - // previous matches had no capture - fill in result with -1-s - for (int k = 0; k < i; k++) { - setNoCaptureValues(captureStart, captureLength, captureNames.length, vector.getLength(), k); + try { + common.checkExtraArgs(false, false, false, useBytesL, false); + if (patternArg.getLength() > 1) { + throw RInternalError.unimplemented("multi-element patterns in regexpr not implemented yet"); + } + String pattern = patternArg.getDataAt(0); + if (!perl) { + pattern = RegExp.checkPreDefinedClasses(pattern); + } + // TODO: useBytes normally depends on the value of the parameter and (if false) on + // whether the string is ASCII + boolean useBytes = true; + boolean hasAnyCapture = false; + int[] result = new int[vector.getLength()]; + int[] matchLength = new int[vector.getLength()]; + String[] captureNames = null; + int[] captureStart = null; + int[] captureLength = null; + if (pattern.length() == 0) { + // emtpy pattern + Arrays.fill(result, 1); + } else { + for (int i = 0; i < vector.getLength(); i++) { + Info res = getInfo(common, pattern, vector.getDataAt(i), ignoreCase, perl, fixed).get(0); + result[i] = res.index; + matchLength[i] = res.size; + if (res.hasCapture) { + hasAnyCapture = true; + if (captureNames == null) { + // first time we see captures + captureNames = res.captureNames; + captureStart = new int[captureNames.length * vector.getLength()]; + captureLength = new int[captureNames.length * vector.getLength()]; + // previous matches had no capture - fill in result with -1-s + for (int k = 0; k < i; k++) { + setNoCaptureValues(captureStart, captureLength, captureNames.length, vector.getLength(), k); + } } + assert captureNames.length == res.captureStart.length; + assert captureNames.length == res.captureLength.length; + for (int j = 0; j < captureNames.length; j++) { + captureStart[j * vector.getLength() + i] = res.captureStart[j]; + captureLength[j * vector.getLength() + i] = res.captureLength[j]; + } + } else if (hasAnyCapture) { + // no capture for this part of the vector, but there are previous + // captures + setNoCaptureValues(captureStart, captureLength, captureNames.length, vector.getLength(), i); } - assert captureNames.length == res.captureStart.length; - assert captureNames.length == res.captureLength.length; - for (int j = 0; j < captureNames.length; j++) { - captureStart[j * vector.getLength() + i] = res.captureStart[j]; - captureLength[j * vector.getLength() + i] = res.captureLength[j]; - } - } else if (hasAnyCapture) { - // no capture for this part of the vector, but there are previous captures - setNoCaptureValues(captureStart, captureLength, captureNames.length, vector.getLength(), i); } } + RIntVector ret = RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR); + setMatchLengthAttrNode.execute(ret, RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR)); + if (useBytes) { + setUseBytesAttrNode.execute(ret, RRuntime.LOGICAL_TRUE); + } + if (hasAnyCapture) { + RStringVector captureNamesVec = RDataFactory.createStringVector(captureNames, RDataFactory.COMPLETE_VECTOR); + RIntVector captureStartVec = RDataFactory.createIntVector(captureStart, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length}); + setDimNamesAttrNode.execute(captureStartVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()})); + setCaptureStartAttrNode.execute(ret, captureStartVec); + RIntVector captureLengthVec = RDataFactory.createIntVector(captureLength, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length}); + setDimNamesAttrNode.execute(captureLengthVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()})); + setCaptureLengthAttrNode.execute(ret, captureLengthVec); + setCaptureNamesAttrNode.execute(ret, captureNamesVec); + } + return ret; + } catch (PatternSyntaxException e) { + throw error(Message.INVALID_REGEXP_REASON, patternArg, e.getMessage()); } - RIntVector ret = RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR); - setMatchLengthAttrNode.execute(ret, RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR)); - if (useBytes) { - setUseBytesAttrNode.execute(ret, RRuntime.LOGICAL_TRUE); - } - if (hasAnyCapture) { - RStringVector captureNamesVec = RDataFactory.createStringVector(captureNames, RDataFactory.COMPLETE_VECTOR); - RIntVector captureStartVec = RDataFactory.createIntVector(captureStart, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length}); - setDimNamesAttrNode.execute(captureStartVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()})); - setCaptureStartAttrNode.execute(ret, captureStartVec); - RIntVector captureLengthVec = RDataFactory.createIntVector(captureLength, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length}); - setDimNamesAttrNode.execute(captureLengthVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()})); - setCaptureLengthAttrNode.execute(ret, captureLengthVec); - setCaptureNamesAttrNode.execute(ret, captureNamesVec); - } - return ret; } protected List<Info> getInfo(CommonCodeNode common, String pattern, String text, boolean ignoreCase, boolean perl, boolean fixed) { @@ -960,39 +969,43 @@ public class GrepFunctions { @TruffleBoundary protected Object regexp(RAbstractStringVector patternArg, RAbstractStringVector vector, boolean ignoreCase, boolean fixed, boolean useBytes, @Cached("createCommon()") CommonCodeNode common) { - common.checkExtraArgs(false, false, false, useBytes, false); - if (patternArg.getLength() > 1) { - throw RInternalError.unimplemented("multi-element patterns in regexpr not implemented yet"); - } - RList ret = RDataFactory.createList(vector.getLength()); - String pattern = patternArg.getDataAt(0); - pattern = RegExp.checkPreDefinedClasses(pattern); - // TODO: useBytes normally depends on the value of the parameter and (if false) on - // whether the string is ASCII - for (int i = 0; i < vector.getLength(); i++) { - int[] matchPos; - int[] matchLength; - if (pattern.length() == 0) { - // emtpy pattern - matchPos = new int[]{1}; - matchLength = new int[]{0}; - } else { - List<Info> res = getInfo(pattern, vector.getDataAt(i), ignoreCase, fixed); - matchPos = new int[res.size()]; - matchLength = new int[res.size()]; - for (int j = 0; j < res.size(); j++) { - matchPos[j] = res.get(j).index; - matchLength[j] = res.get(j).size; + try { + common.checkExtraArgs(false, false, false, useBytes, false); + if (patternArg.getLength() > 1) { + throw RInternalError.unimplemented("multi-element patterns in regexpr not implemented yet"); + } + RList ret = RDataFactory.createList(vector.getLength()); + String pattern = patternArg.getDataAt(0); + pattern = RegExp.checkPreDefinedClasses(pattern); + // TODO: useBytes normally depends on the value of the parameter and (if false) on + // whether the string is ASCII + for (int i = 0; i < vector.getLength(); i++) { + int[] matchPos; + int[] matchLength; + if (pattern.length() == 0) { + // emtpy pattern + matchPos = new int[]{1}; + matchLength = new int[]{0}; + } else { + List<Info> res = getInfo(pattern, vector.getDataAt(i), ignoreCase, fixed); + matchPos = new int[res.size()]; + matchLength = new int[res.size()]; + for (int j = 0; j < res.size(); j++) { + matchPos[j] = res.get(j).index; + matchLength[j] = res.get(j).size; + } } + RIntVector matches = RDataFactory.createIntVector(matchPos, RDataFactory.COMPLETE_VECTOR); + setMatchLengthAttrNode.execute(matches, RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR)); + ret.setElement(i, matches); } - RIntVector matches = RDataFactory.createIntVector(matchPos, RDataFactory.COMPLETE_VECTOR); - setMatchLengthAttrNode.execute(matches, RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR)); - ret.setElement(i, matches); - } - if (useBytes) { - setUseBytesAttrNode.execute(ret, RRuntime.LOGICAL_TRUE); + if (useBytes) { + setUseBytesAttrNode.execute(ret, RRuntime.LOGICAL_TRUE); + } + return ret; + } catch (PatternSyntaxException e) { + throw error(Message.INVALID_REGEXP_REASON, patternArg, e.getMessage()); } - return ret; } protected List<Info> getInfo(String pattern, String text, boolean ignoreCase, boolean fixed) { @@ -1069,68 +1082,72 @@ public class GrepFunctions { @Override protected Object regexp(RAbstractStringVector patternArg, RAbstractStringVector vector, boolean ignoreCaseL, boolean perlL, boolean fixedL, boolean useBytesL, @Cached("createCommon()") CommonCodeNode common) { - common.checkExtraArgs(false, false, false, useBytesL, false); - boolean ignoreCase = ignoreCaseL; - boolean fixed = fixedL; - boolean perl = perlL; - if (patternArg.getLength() > 1) { - throw RInternalError.unimplemented("multi-element patterns in gregexpr not implemented yet"); - } - String pattern = patternArg.getDataAt(0); - if (!perl) { - pattern = RegExp.checkPreDefinedClasses(pattern); - } - // TODO: useBytes normally depends on the value of the parameter and (if false) on - // whether the string is ASCII - boolean useBytes = true; - Object[] result = new Object[vector.getLength()]; - boolean hasAnyCapture = false; - RStringVector captureNames = null; - for (int i = 0; i < vector.getLength(); i++) { - RIntVector res; - if (pattern.length() == 0) { - String txt = vector.getDataAt(i); - res = RDataFactory.createIntVector(txt.length()); - for (int j = 0; j < txt.length(); j++) { - res.setDataAt(res.getDataWithoutCopying(), j, j + 1); - } - setMatchLengthAttrNode.execute(res, RDataFactory.createIntVector(txt.length())); - if (useBytes) { - setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE); - } - } else { - List<Info> l = getInfo(common, pattern, vector.getDataAt(i), ignoreCase, perl, fixed); - res = toIndexOrSizeVector(l, true); - setMatchLengthAttrNode.execute(res, toIndexOrSizeVector(l, false)); - if (useBytes) { - setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE); - } - RIntVector captureStart = toCaptureStartOrLength(l, true); - if (captureStart != null) { - RIntVector captureLength = toCaptureStartOrLength(l, false); - assert captureLength != null; - captureNames = getCaptureNamesVector(l); - assert captureNames.getLength() > 0; - if (!hasAnyCapture) { - // set previous result list elements to "no capture" - for (int j = 0; j < i; j++) { - setNoCaptureAttributes((RIntVector) result[j], captureNames); + try { + common.checkExtraArgs(false, false, false, useBytesL, false); + boolean ignoreCase = ignoreCaseL; + boolean fixed = fixedL; + boolean perl = perlL; + if (patternArg.getLength() > 1) { + throw RInternalError.unimplemented("multi-element patterns in gregexpr not implemented yet"); + } + String pattern = patternArg.getDataAt(0); + if (!perl) { + pattern = RegExp.checkPreDefinedClasses(pattern); + } + // TODO: useBytes normally depends on the value of the parameter and (if false) on + // whether the string is ASCII + boolean useBytes = true; + Object[] result = new Object[vector.getLength()]; + boolean hasAnyCapture = false; + RStringVector captureNames = null; + for (int i = 0; i < vector.getLength(); i++) { + RIntVector res; + if (pattern.length() == 0) { + String txt = vector.getDataAt(i); + res = RDataFactory.createIntVector(txt.length()); + for (int j = 0; j < txt.length(); j++) { + res.setDataAt(res.getDataWithoutCopying(), j, j + 1); + } + setMatchLengthAttrNode.execute(res, RDataFactory.createIntVector(txt.length())); + if (useBytes) { + setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE); + } + } else { + List<Info> l = getInfo(common, pattern, vector.getDataAt(i), ignoreCase, perl, fixed); + res = toIndexOrSizeVector(l, true); + setMatchLengthAttrNode.execute(res, toIndexOrSizeVector(l, false)); + if (useBytes) { + setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE); + } + RIntVector captureStart = toCaptureStartOrLength(l, true); + if (captureStart != null) { + RIntVector captureLength = toCaptureStartOrLength(l, false); + assert captureLength != null; + captureNames = getCaptureNamesVector(l); + assert captureNames.getLength() > 0; + if (!hasAnyCapture) { + // set previous result list elements to "no capture" + for (int j = 0; j < i; j++) { + setNoCaptureAttributes((RIntVector) result[j], captureNames); + } } + hasAnyCapture = true; + setCaptureStartAttrNode.execute(res, captureStart); + setCaptureLengthAttrNode.execute(res, captureLength); + setCaptureNamesAttrNode.execute(res, captureNames); + } else if (hasAnyCapture) { + assert captureNames != null; + // it's capture names from previous iteration, so copy + setNoCaptureAttributes(res, (RStringVector) captureNames.copy()); } - hasAnyCapture = true; - setCaptureStartAttrNode.execute(res, captureStart); - setCaptureLengthAttrNode.execute(res, captureLength); - setCaptureNamesAttrNode.execute(res, captureNames); - } else if (hasAnyCapture) { - assert captureNames != null; - // it's capture names from previous iteration, so copy - setNoCaptureAttributes(res, (RStringVector) captureNames.copy()); } - } - result[i] = res; + result[i] = res; + } + return RDataFactory.createList(result); + } catch (PatternSyntaxException e) { + throw error(Message.INVALID_REGEXP_REASON, patternArg, e.getMessage()); } - return RDataFactory.createList(result); } private static RIntVector toIndexOrSizeVector(List<Info> list, boolean index) { @@ -1374,30 +1391,34 @@ public class GrepFunctions { continue; } String currentSplit = splits[i % splits.length]; - if (currentSplit.isEmpty()) { - result[i] = na.check(data) ? RDataFactory.createNAStringVector() : emptySplitIntl(data); - } else if (RRuntime.isNA(currentSplit)) { - // NA doesn't split - result[i] = RDataFactory.createStringVectorFromScalar(data); - } else { - RStringVector resultItem; - if (na.check(data)) { - resultItem = RDataFactory.createNAStringVector(); + try { + if (currentSplit.isEmpty()) { + result[i] = na.check(data) ? RDataFactory.createNAStringVector() : emptySplitIntl(data); + } else if (RRuntime.isNA(currentSplit)) { + // NA doesn't split + result[i] = RDataFactory.createStringVectorFromScalar(data); } else { - if (perl) { - resultItem = splitPerl(data, pcreSplits[i % splits.length]); + RStringVector resultItem; + if (na.check(data)) { + resultItem = RDataFactory.createNAStringVector(); } else { - resultItem = splitIntl(data, currentSplit, fixed); - } - if (resultItem.getLength() == 0) { - if (fixed) { - resultItem = RDataFactory.createStringVector(data); + if (perl) { + resultItem = splitPerl(data, pcreSplits[i % splits.length]); } else { - resultItem = RDataFactory.createStringVector(data.length()); + resultItem = splitIntl(data, currentSplit, fixed); + } + if (resultItem.getLength() == 0) { + if (fixed) { + resultItem = RDataFactory.createStringVector(data); + } else { + resultItem = RDataFactory.createStringVector(data.length()); + } } } + result[i] = resultItem; } - result[i] = resultItem; + } catch (PatternSyntaxException e) { + throw error(Message.INVALID_REGEXP_REASON, currentSplit, e.getMessage()); } } RList ret = RDataFactory.createList(result); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java index 9194da7ea85e1b5ce831b8ee9be14bbce72b7ebc..983421fd3ae1dde3d2cd91a6cdc7bb731278090e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java @@ -636,6 +636,7 @@ public final class RError extends RuntimeException implements TruffleException { FIRST_ARGUMENT_MUST_BE_CHARACTER("the first argument must be of mode character"), ALL_ATTRIBUTES_NAMES("all attributes must have names [%d does not]"), INVALID_REGEXP("invalid regular expression '%s'"), + INVALID_REGEXP_REASON("invalid regular expression '%s': %s"), COERCING_ARGUMENT("coercing argument of type '%s' to %s"), MUST_BE_TRUE_FALSE_ENVIRONMENT("'%s' must be TRUE, FALSE or an environment"), UNKNOWN_OBJECT_MODE("object '%s' of mode '%s' was not found"), diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java index 05cbf60199af40a84500f1c03bf8633d4ff5ec4f..a115d68198ca807b5c99bde0ba01ec0d2706b6c8 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java @@ -179,6 +179,7 @@ public final class RInternalError extends Error implements TruffleException { System.err.println(out.toString()); System.err.println(verboseStackTrace); } + String message = t instanceof RInternalError && t.getMessage() != null && !t.getMessage().isEmpty() ? t.getMessage() : "internal error: " + t.getClass().getSimpleName(); if (FastROptions.PrintErrorStacktracesToFile.getBooleanValue()) { String suffix = contextId == 0 ? "" : "-" + Integer.toString(contextId); Path logfile = Utils.getLogPath("fastr_errors.log" + suffix); @@ -190,12 +191,14 @@ public final class RInternalError extends Error implements TruffleException { } catch (IOException e) { e.printStackTrace(); } - String message = t instanceof RInternalError && t.getMessage() != null && !t.getMessage().isEmpty() ? t.getMessage() : "internal error: " + t.getClass().getSimpleName(); - System.out.println(message + " (see fastr_errors.log" + suffix + ")"); + System.err.println(message + " (see fastr_errors.log" + suffix + ")"); if (RContext.isEmbedded()) { Utils.rSuicide("FastR internal error"); } } + if (!FastROptions.PrintErrorStacktraces.getBooleanValue() && !FastROptions.PrintErrorStacktracesToFile.getBooleanValue()) { + System.err.println(message); + } } } catch (Throwable t) { System.err.println("error while reporting internal error:"); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RegExp.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RegExp.java index 519a11a0231f4c3b5d4a622b7bf1e6bb195ef8e6..d0be846c39ceb35722674b2e739774f67a6dddb3 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RegExp.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RegExp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,14 +68,33 @@ public class RegExp { * predefined classes like "[:alpha:]" with "\p{Alpha}". */ boolean withinCharClass = false; + int parensNesting = 0; int i = 0; while (i < result.length()) { switch (result.charAt(i)) { + case '(': + if (withinCharClass) { + result = result.substring(0, i) + '\\' + result.substring(i); + i++; // skip the newly inserted '\\' + } else { + parensNesting++; + } + break; + case ')': + if (withinCharClass || parensNesting == 0) { + result = result.substring(0, i) + '\\' + result.substring(i); + i++; // skip the newly inserted '\\' + } else { + parensNesting--; + } + break; case '\\': if (withinCharClass) { result = result.substring(0, i) + '\\' + result.substring(i); + i++; // skip the newly inserted '\\' + } else { + i++; // skip the next character } - i++; break; case '[': if (withinCharClass) { diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 612e6518136b6eab6f4ada74465779a2f2af4ed8..d95319518ad0ca4ef9b50fb14346f19b24b0e1a7 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -25512,6 +25512,41 @@ attr(,"useBytes") [1] TRUE +##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#Output.IgnoreErrorMessage# +#grep('(()', ')') +Error in grep("(()", ")") : + invalid regular expression '(()', reason 'Missing ')'' + +##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep# +#grep('(())', ')') +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#Output.IgnoreErrorMessage# +#grep('([(]', ')') +Error in grep("([(]", ")") : + invalid regular expression '([(]', reason 'Missing ')'' + +##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#Output.IgnoreErrorMessage# +#grep('([)]', ')') +Error in grep("([)]", ")") : + invalid regular expression '([)]', reason 'Missing ')'' + +##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep# +#grep('))', ')') +integer(0) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep# +#grep('))', '))') +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep# +#grep('[(]', ')') +integer(0) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep# +#grep('[)]', ')') +[1] 1 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep# #{ .Internal(grep("7", 7, F, F, F, F, F, F)) } Error: invalid 'text' argument diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java index cedba3a7b675e17cae5911a62c6df338d04ac1be..d5c5148e5700bf77b247ef7607dab95add6a7a71 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java @@ -98,6 +98,15 @@ public class TestBuiltin_grep extends TestBase { // Expected output: integer(0) // FastR output: [1] 1 assertEval(Ignored.ImplementationError, "{ grep('^ *$', ' \\n') }"); + + assertEval("grep('[(]', ')')"); + assertEval("grep('[)]', ')')"); + assertEval("grep('(())', ')')"); + assertEval("grep('))', ')')"); + assertEval("grep('))', '))')"); + assertEval(Output.IgnoreErrorMessage, "grep('([)]', ')')"); + assertEval(Output.IgnoreErrorMessage, "grep('([(]', ')')"); + assertEval(Output.IgnoreErrorMessage, "grep('(()', ')')"); } @Test