From c0cff4bc4974ff4de282964d07c744dcda3e2bff Mon Sep 17 00:00:00 2001 From: stepan <stepan.sindelar@oracle.com> Date: Tue, 7 Nov 2017 16:26:20 +0100 Subject: [PATCH] Implement chartr builtin --- .../device/awt/BufferedImageDevice.java | 4 +- .../r/nodes/builtin/base/BasePackage.java | 1 + .../truffle/r/nodes/builtin/base/CharTr.java | 102 ++++++++++++++++++ .../com/oracle/truffle/r/runtime/RError.java | 1 + .../truffle/r/test/ExpectedTestOutput.test | 49 ++++++++- .../r/test/builtins/TestBuiltin_chartr.java | 21 +++- 6 files changed, 167 insertions(+), 11 deletions(-) create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharTr.java diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/BufferedImageDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/BufferedImageDevice.java index c392fed266..3a98f5eca2 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/BufferedImageDevice.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/BufferedImageDevice.java @@ -31,6 +31,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import javax.imageio.ImageIO; @@ -75,7 +76,8 @@ public final class BufferedImageDevice extends Graphics2DDevice implements FileG private void saveImage() throws DeviceCloseException { try { - if (!Files.exists(Paths.get(filename).getParent())) { + Path parent = Paths.get(filename).getParent(); + if (parent != null && !Files.exists(parent)) { // Bug in JDK? when the path contains directory that does not exist, the code throws // NPE and prints out to the standard output (!) stack trace of // FileNotFoundException. We still catch the exception, because this check and diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index 44da8c02ea..9d4903d78d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -713,6 +713,7 @@ public class BasePackage extends RBuiltinPackage { add(Tabulate.class, TabulateNodeGen::create); add(TempDir.class, TempDirNodeGen::create); add(TempFile.class, TempFileNodeGen::create); + add(CharTr.class, CharTr::create); add(ToLowerOrUpper.ToLower.class, ToLowerOrUpperFactory.ToLowerNodeGen::create); add(ToLowerOrUpper.ToUpper.class, ToLowerOrUpperFactory.ToUpperNodeGen::create); add(Traceback.class, TracebackNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharTr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharTr.java new file mode 100644 index 0000000000..6c81776bed --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharTr.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; +import static com.oracle.truffle.r.runtime.RError.Message.X_LONGER_THAN_Y; +import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; +import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.nodes.attributes.RemoveRegAttributesNode; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.function.opt.ReuseTemporaryNode; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; + +@RBuiltin(name = "chartr", kind = INTERNAL, parameterNames = {"old", "new", "x"}, behavior = PURE) +public abstract class CharTr extends RBuiltinNode.Arg3 { + + static { + Casts casts = new Casts(CharTr.class); + casts.arg("old").mustBe(stringValue()).asStringVector().shouldBe(singleElement(), Message.ARGUMENT_ONLY_FIRST, "old").findFirst(); + casts.arg("new").mustBe(stringValue()).asStringVector().shouldBe(singleElement(), Message.ARGUMENT_ONLY_FIRST, "new").findFirst(); + casts.arg("x").mustBe(stringValue()).asStringVector(); + } + + public static CharTr create() { + return CharTrNodeGen.create(); + } + + @Specialization + RStringVector doIt(String oldStr, String newStr, RAbstractStringVector values, + @Cached("create()") RemoveRegAttributesNode removeRegAttributesNode, + @Cached("create()") ReuseTemporaryNode reuseTemporaryNode) { + if (newStr.length() < oldStr.length()) { + throw error(X_LONGER_THAN_Y, "old", "new"); + } + RStringVector result = (RStringVector) reuseTemporaryNode.execute(values); + removeRegAttributesNode.execute(result); + Object store = result.getInternalStore(); + for (int i = 0; i < result.getLength(); i++) { + String value = result.getDataAt(store, i); + if (RRuntime.isNA(value)) { + continue; + } + int replaceIdx = 0; + while (replaceIdx < oldStr.length()) { + if (replaceIdx + 2 < oldStr.length() && oldStr.charAt(replaceIdx + 1) == '-') { + value = replaceRange(replaceIdx, oldStr, newStr, value); + replaceIdx += 3; + } else { + value = value.replace(oldStr.charAt(replaceIdx), newStr.charAt(replaceIdx)); + replaceIdx++; + } + } + result.setDataAt(store, i, value); + } + return result; + } + + private String replaceRange(int replaceIdx, String oldStr, String newStr, String value) { + if (replaceIdx + 2 >= newStr.length() || newStr.charAt(replaceIdx + 1) != '-') { + throw error(X_LONGER_THAN_Y, "old", "new"); + } + int oldEnd = oldStr.charAt(replaceIdx + 2); + int oldStart = oldStr.charAt(replaceIdx); + int newStart = newStr.charAt(replaceIdx); + int newEnd = newStr.charAt(replaceIdx + 2); + if (newEnd - newStart < oldEnd - oldStart) { + throw error(X_LONGER_THAN_Y, "old", "new"); + } + for (int rangeIdx = 0; rangeIdx <= oldEnd - oldStart; rangeIdx++) { + value = value.replace((char) (oldStart + rangeIdx), (char) (newStart + rangeIdx)); + } + return value; + } +} 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 bae562ba67..d34706d3fa 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 @@ -379,6 +379,7 @@ public final class RError extends RuntimeException implements TruffleException { NA_INTRODUCED_COERCION("NAs introduced by coercion"), NA_INTRODUCED_COERCION_INT("NAs introduced by coercion to integer range"), ARGUMENT_WHICH_NOT_LOGICAL("argument to 'which' is not logical"), + X_LONGER_THAN_Y("'%s' is longer than '%s'"), X_NUMERIC("'x' must be numeric"), X_LIST_ATOMIC("'x' must be a list or atomic vector"), X_ARRAY_TWO("'x' must be an array of at least two dimensions"), 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 076a5762ff..cafcf1f643 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 @@ -13811,26 +13811,65 @@ integer(0) #argv <- list(character(0), c('semiTransparency', 'transparentBackground', 'rasterImage', 'capture', 'locator', 'events'), 0L); .Internal(charmatch(argv[[1]], argv[[2]], argv[[3]])) integer(0) -##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.testchartr1#Ignored.Unimplemented# +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.testchartr1# #argv <- list('.', '.', c('0.02', '0.06', '0.11', '0.22', '0.56', '1.1')); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]])) [1] "0.02" "0.06" "0.11" "0.22" "0.56" "1.1" -##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.testchartr2#Ignored.Unimplemented# +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.testchartr2# #argv <- list('iXs', 'why', 'MiXeD cAsE 123'); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]])) [1] "MwheD cAyE 123" -##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.testchartr3#Ignored.Unimplemented# +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.testchartr3# #argv <- list('a-cX', 'D-Fw', 'MiXeD cAsE 123'); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]])) [1] "MiweD FAsE 123" -##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.testchartr4#Ignored.Unimplemented# +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.testchartr4# #argv <- list('.', '.', character(0)); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]])) character(0) -##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.testchartr6#Ignored.Unimplemented# +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.testchartr6# #argv <- structure(list(old = 'NA', new = 'na', x = c('NA', NA, 'BANANA')), .Names = c('old', 'new', 'x'));do.call('chartr', argv) [1] "na" NA "Banana" +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.tests# +#chartr('0-5', '0-', 'ah3g4t') +Error in chartr("0-5", "0-", "ah3g4t") : 'old' is longer than 'new' + +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.tests# +#chartr('0-5', '0-3', 'ah3g4t') +Error in chartr("0-5", "0-3", "ah3g4t") : 'old' is longer than 'new' + +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.tests# +#chartr('0-5', '045', 'ah3g4t') +Error in chartr("0-5", "045", "ah3g4t") : 'old' is longer than 'new' + +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.tests# +#chartr(c('a','b'), c('c', 'e'), c('abc', 'efb')) +[1] "cbc" "efb" +Warning messages: +1: In chartr(c("a", "b"), c("c", "e"), c("abc", "efb")) : + argument 'old' has length > 1 and only the first element will be used +2: In chartr(c("a", "b"), c("c", "e"), c("abc", "efb")) : + argument 'new' has length > 1 and only the first element will be used + +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.tests# +#chartr(c('a','b'), c(3, 2), c('abc', 'efb')) +Error in chartr(c("a", "b"), c(3, 2), c("abc", "efb")) : + invalid 'new' argument +In addition: Warning message: +In chartr(c("a", "b"), c(3, 2), c("abc", "efb")) : + argument 'old' has length > 1 and only the first element will be used + +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.tests# +#chartr(c('abq'), 'cd', c('agbc', 'efb')) +Error in chartr(c("abq"), "cd", c("agbc", "efb")) : + 'old' is longer than 'new' + +##com.oracle.truffle.r.test.builtins.TestBuiltin_chartr.tests# +#chartr(c(3, 2), c('q', 'c'), c('abc', 'efb')) +Error in chartr(c(3, 2), c("q", "c"), c("abc", "efb")) : + invalid 'old' argument + ##com.oracle.truffle.r.test.builtins.TestBuiltin_chol.testChol# #{ chol(1) } [,1] diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_chartr.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_chartr.java index ea22fa4553..c3d332a3b5 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_chartr.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_chartr.java @@ -19,26 +19,37 @@ public class TestBuiltin_chartr extends TestBase { @Test public void testchartr1() { - assertEval(Ignored.Unimplemented, "argv <- list('.', '.', c('0.02', '0.06', '0.11', '0.22', '0.56', '1.1')); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]]))"); + assertEval("argv <- list('.', '.', c('0.02', '0.06', '0.11', '0.22', '0.56', '1.1')); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]]))"); } @Test public void testchartr2() { - assertEval(Ignored.Unimplemented, "argv <- list('iXs', 'why', 'MiXeD cAsE 123'); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]]))"); + assertEval("argv <- list('iXs', 'why', 'MiXeD cAsE 123'); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]]))"); } @Test public void testchartr3() { - assertEval(Ignored.Unimplemented, "argv <- list('a-cX', 'D-Fw', 'MiXeD cAsE 123'); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]]))"); + assertEval("argv <- list('a-cX', 'D-Fw', 'MiXeD cAsE 123'); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]]))"); } @Test public void testchartr4() { - assertEval(Ignored.Unimplemented, "argv <- list('.', '.', character(0)); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]]))"); + assertEval("argv <- list('.', '.', character(0)); .Internal(chartr(argv[[1]], argv[[2]], argv[[3]]))"); } @Test public void testchartr6() { - assertEval(Ignored.Unimplemented, "argv <- structure(list(old = 'NA', new = 'na', x = c('NA', NA, 'BANANA')), .Names = c('old', 'new', 'x'));do.call('chartr', argv)"); + assertEval("argv <- structure(list(old = 'NA', new = 'na', x = c('NA', NA, 'BANANA')), .Names = c('old', 'new', 'x'));do.call('chartr', argv)"); + } + + @Test + public void tests() { + assertEval("chartr(c('abq'), 'cd', c('agbc', 'efb'))"); + assertEval("chartr(c('a','b'), c('c', 'e'), c('abc', 'efb'))"); + assertEval("chartr(c('a','b'), c(3, 2), c('abc', 'efb'))"); + assertEval("chartr(c(3, 2), c('q', 'c'), c('abc', 'efb'))"); + assertEval("chartr('0-5', '0-3', 'ah3g4t')"); + assertEval("chartr('0-5', '0-', 'ah3g4t')"); + assertEval("chartr('0-5', '045', 'ah3g4t')"); } } -- GitLab