diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h index 6fc12a3a369400b7814346c72741e2a89b1b6f1b..8d35f0b38cef269d07cb41e1c2be1b172c0c87e8 100644 --- a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h +++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h @@ -214,7 +214,16 @@ static int Rvsnprintf(char *buf, size_t size, const char *format, va_list ap) { void Rf_errorcall(SEXP x, const char *format, ...) { TRACE0(); - UNIMPLEMENTED; + // See also comments in Rf_error + char buf[BUFSIZE]; + va_list(ap); + va_start(ap,format); + Rvsnprintf(buf, BUFSIZE - 1, format, ap); + va_end(ap); + ((call_Rf_errorcall) callbacks[Rf_errorcall_x])(x, ensure_string(buf)); + checkExitCall(); + // Should not reach here + unimplemented("Unexpected return from Rf_errorcall, should be no return function"); } void Rf_warningcall(SEXP x, const char *format, ...) { @@ -253,7 +262,7 @@ void Rf_error(const char *format, ...) { // RError.error does quite a lot of stuff including potentially searching for R condition handlers // and, if it finds any, does not return, but throws a different exception than RError. // We definitely need to exit the FFI call and we certainly cannot return to our caller. - char buf[8192]; + char buf[BUFSIZE]; va_list(ap); va_start(ap,format); Rvsnprintf(buf, BUFSIZE - 1, format, ap); diff --git a/com.oracle.truffle.r.native/version.source b/com.oracle.truffle.r.native/version.source index 21e72e8ac3d7e23bd6532b5f1f4a6bdf8362e6cf..95f9650f0151d7c0d3aecf40355d88effbd5b7a7 100644 --- a/com.oracle.truffle.r.native/version.source +++ b/com.oracle.truffle.r.native/version.source @@ -1 +1 @@ -48 +49 diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java index 00894b2b3b2a29c27e2283783b9344330ff407c8..2132fb8c92c6c75705e584d404c7253e9709ceac 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java @@ -64,6 +64,7 @@ import com.oracle.truffle.r.nodes.unary.PrecedenceNodeGen; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; 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.Utils; @@ -302,9 +303,8 @@ public abstract class Bind extends RBaseNode { if (!GetDimAttributeNode.isArray(dim) || dim.length == 1) { RStringVector names = extractNamesNode.execute(vec); firstDimNames = names == null ? RNull.instance : names; - } else { - RInternalError.unimplemented("binding multi-dimensional arrays is not supported"); } + // dimnames are simply ignored for arrays with 3 and more dimensions } if (firstDimNames != RNull.instance) { RAbstractStringVector names = (RAbstractStringVector) firstDimNames; @@ -365,43 +365,74 @@ public abstract class Bind extends RBaseNode { } } } else { - RInternalError.unimplemented("binding multi-dimensional arrays is not supported"); - return 0; + for (int i = 0; i < resDim; i++) { + dimNamesArray[ind++] = RRuntime.NAMES_ATTR_EMPTY_VALUE; + } + return -ind; } } } /** * @param vectors vectors to be combined - * @param res result dims - * @param bindDims columns dim (cbind) or rows dim (rbind) - * @return whether number of rows (cbind) or columns (rbind) in vectors is the same + * @param res (output) dimensions of the resulting matrix. + * @param bindDims (output, size == vectors.length) for each vector gives how many columns + * (cbind) it will fill in the resulting matrix, i.e. 1 for vectors and columns count + * for matrices. + * @return whether some vectors will have to be recycled, i.e. iterated more than once when + * filling the result */ protected boolean getResultDimensions(RAbstractVector[] vectors, int[] res, int[] bindDims) { + /* + * From the documentation: if there are several matrix arguments, they must all have the + * same number of columns (or rows) and this will be the number of columns (or rows) of the + * result. If all the arguments are vectors, the number of columns (rows) in the result is + * equal to the length of the longest vector. Values in shorter arguments are recycled to + * achieve this length (with a warning if they are recycled only fractionally) + * + * When the arguments consist of a mix of matrices and vectors the number of columns (rows) + * of the result is determined by the number of columns (rows) of the matrix arguments. Any + * vectors have their values recycled or subsetted to achieve this length. + */ + assert vectors.length > 0; + // NOTE: naming is chosen for cbind version, but it applies to rbind too + int rowsCountMatrix = -1; // the number of rows of the first matrix argument if any + int rowsCountVector = 0; // the max length of simple vectors + int minRowsCountVector = 0; // the min length of simple vectors, to determine return value + int[] rowsCountsVectors = new int[vectors.length]; // rows count of each vector/matrix + int columnsCount = 0; // the total number of columns (cbind) in the resulting matrix int srcDim1Ind = type == BindType.cbind ? 0 : 1; int srcDim2Ind = type == BindType.cbind ? 1 : 0; - assert vectors.length > 0; - RAbstractVector v = vectorProfile.profile(vectors[0]); - int[] dim = getDimensions(v, getVectorDimensions(v)); - assert dim.length == 2; - bindDims[0] = dim[srcDim2Ind]; - res[srcDim1Ind] = dim[srcDim1Ind]; - res[srcDim2Ind] = dim[srcDim2Ind]; - boolean notEqualDims = false; - for (int i = 1; i < vectors.length; i++) { - RAbstractVector v2 = vectorProfile.profile(vectors[i]); - int[] dims = getDimensions(v2, getVectorDimensions(v2)); - assert dims.length == 2; + for (int i = 0; i < vectors.length; i++) { + RAbstractVector v = vectorProfile.profile(vectors[i]); + int[] dims = getVectorDimensions(v); + if (dims == null || dims.length != 2) { + int vectorLen = v.getLength(); + rowsCountsVectors[i] = vectorLen; + rowsCountVector = Math.max(rowsCountVector, vectorLen); + minRowsCountVector = Math.min(minRowsCountVector, vectorLen); + columnsCount++; + bindDims[i] = 1; + continue; + } + columnsCount += dims[srcDim2Ind]; bindDims[i] = dims[srcDim2Ind]; - if (dims[srcDim1Ind] != res[srcDim1Ind]) { - notEqualDims = true; - if (dims[srcDim1Ind] > res[srcDim1Ind]) { - res[srcDim1Ind] = dims[srcDim1Ind]; - } + if (rowsCountMatrix == -1) { + rowsCountMatrix = dims[srcDim1Ind]; + + } else if (rowsCountMatrix != dims[srcDim1Ind]) { + error(type == BindType.cbind ? Message.ROWS_MUST_MATCH : Message.COLS_MUST_MATCH, i + 1); + } + } + res[srcDim2Ind] = columnsCount; + int resultRowsCount = res[srcDim1Ind] = rowsCountMatrix != -1 ? rowsCountMatrix : rowsCountVector; + for (int i = 0; i < vectors.length; i++) { + if (rowsCountsVectors[i] != 0 && rowsCountsVectors[i] > resultRowsCount) { + warning(type == BindType.cbind ? Message.ROWS_NOT_MULTIPLE : Message.COLUMNS_NOT_MULTIPLE, i + 1); + break; // reported only for first ocurrence } - res[srcDim2Ind] += dims[srcDim2Ind]; } - return notEqualDims; + return minRowsCountVector < resultRowsCount; } protected int[] getDimensions(RAbstractVector vector, int[] dimensions) { @@ -504,21 +535,24 @@ public abstract class Bind extends RBaseNode { } // compute result vector values - int vecLength = vec.getLength(); - for (int j = 0; j < vecLength; j++) { - result.transferElementSameType(ind++, vec, j); - } - if (rowsAndColumnsNotEqual) { - everSeenNotEqualRows.enter(); - if (vecLength < resultDimensions[0]) { - // re-use vector elements - int k = 0; - for (int j = 0; j < resultDimensions[0] - vecLength; j++, k = Utils.incMod(k, vecLength)) { - result.transferElementSameType(ind++, vectors[i], k); - } - - if (k != 0) { - RError.warning(this, RError.Message.ROWS_NOT_MULTIPLE, i + 1); + int[] dims = getDimensions(vec, getVectorDimensions(vec)); + assert dims.length == 2; + for (int col = 0; col < dims[1]; col++) { + int rowsCount = Math.min(dims[0], resultDimensions[0]); + for (int row = 0; row < rowsCount; row++) { + result.transferElementSameType(ind++, vec, dims[0] * col + row); + } + if (rowsAndColumnsNotEqual) { + everSeenNotEqualRows.enter(); + if (rowsCount < resultDimensions[0]) { + // re-use vector elements + int k = 0; + for (int j = 0; j < resultDimensions[0] - dims[0]; j++, k = Utils.incMod(k, dims[0])) { + result.transferElementSameType(ind++, vectors[i], dims[0] * col + k); + } + if (k != 0) { + RError.warning(this, RError.Message.ROWS_NOT_MULTIPLE, i + 1); + } } } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java index 96b23862edb16fb271658697755d570303163c1a..eb61710d5e4fa123dbfb62a8b509f1215917d241 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -86,6 +86,7 @@ import com.oracle.truffle.r.runtime.conn.FileConnections.CompressedRConnection; import com.oracle.truffle.r.runtime.conn.FileConnections.FileRConnection; import com.oracle.truffle.r.runtime.conn.PipeConnections.PipeRConnection; import com.oracle.truffle.r.runtime.conn.RConnection; +import com.oracle.truffle.r.runtime.conn.RConnection.ReadLineWarning; import com.oracle.truffle.r.runtime.conn.RawConnections.RawRConnection; import com.oracle.truffle.r.runtime.conn.SocketConnections.RSocketConnection; import com.oracle.truffle.r.runtime.conn.TextConnections.TextRConnection; @@ -616,7 +617,7 @@ public abstract class ConnectionFunctions { protected Object readLines(int con, int n, boolean ok, boolean warn, @SuppressWarnings("unused") String encoding, boolean skipNul) { // TODO Implement argument 'encoding'. try (RConnection openConn = RConnection.fromIndex(con).forceOpen("rt")) { - String[] lines = openConn.readLines(n, warn, skipNul); + String[] lines = openConn.readLines(n, ReadLineWarning.allIf(warn), skipNul); if (n > 0 && lines.length < n && !ok) { throw error(RError.Message.TOO_FEW_LINES_READ_LINES); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java index 53722a742e32cf765583cf16426b0e8e2856a9bd..1e1194bbfc6eafdce215b24b087809cd5aaf806d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java @@ -87,9 +87,7 @@ public class OptionsFunctions { Arrays.sort(entries, new Comparator<Map.Entry<String, Object>>() { @Override public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) { - String k1 = o1.getKey(); - String k2 = o2.getKey(); - return collator == null ? k1.compareTo(k2) : collator.compare(k1, k2); + return RLocale.compare(collator, o1.getKey(), o2.getKey()); } }); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java index 784cddf210d8607425d303da5ff9f39d42771fa5..78a6313f14b39fcf2a3226bd9e355e20478162df 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -30,6 +30,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; +import java.util.EnumSet; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; @@ -49,6 +50,7 @@ import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.conn.ConnectionSupport; import com.oracle.truffle.r.runtime.conn.RConnection; +import com.oracle.truffle.r.runtime.conn.RConnection.ReadLineWarning; import com.oracle.truffle.r.runtime.conn.StdConnections; import com.oracle.truffle.r.runtime.context.Engine.ParseException; import com.oracle.truffle.r.runtime.context.RContext; @@ -119,7 +121,7 @@ public abstract class Parse extends RBuiltinNode.Arg6 { throw RError.nyi(this, "parse from stdin not implemented"); } try (RConnection openConn = connection.forceOpen("r")) { - lines = openConn.readLines(0, false, false); + lines = openConn.readLines(0, EnumSet.noneOf(ReadLineWarning.class), false); } catch (IOException ex) { throw error(RError.Message.PARSE_ERROR); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java index 7b259a032417427dcf6ccadc1215beee3ae44117..faeb83d55f43a524fe83ad2236ffa0d87f41182c 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -27,6 +27,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.IO; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; import java.io.IOException; +import java.util.EnumSet; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -43,6 +44,7 @@ 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.conn.RConnection; +import com.oracle.truffle.r.runtime.conn.RConnection.ReadLineWarning; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; @@ -71,7 +73,7 @@ public abstract class ReadDCF extends RBuiltinNode.Arg3 { keepWhiteSet.add(keepWhite.getDataAt(i)); } } - dcf = DCF.read(openConn.readLines(0, true, false), keepWhiteSet); + dcf = DCF.read(openConn.readLines(0, EnumSet.noneOf(ReadLineWarning.class), false), keepWhiteSet); } catch (IOException ex) { throw error(RError.Message.ERROR_READING_CONNECTION, ex.getMessage()); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java index 0cbba8600c47507e83e6e659b4620b82e98f2548..ac44cef5b20eed6f5bc50dab7ffff4585a075a25 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java @@ -29,6 +29,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; import java.io.IOException; import java.util.ArrayList; +import java.util.EnumSet; import java.util.HashMap; import com.oracle.truffle.api.CompilerDirectives; @@ -44,6 +45,7 @@ import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.conn.RConnection; +import com.oracle.truffle.r.runtime.conn.RConnection.ReadLineWarning; import com.oracle.truffle.r.runtime.conn.StdConnections; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -189,7 +191,7 @@ public abstract class Scan extends RBuiltinNode.Arg19 { try (RConnection openConn = data.con.forceOpen("r")) { if (nskip > 0) { - openConn.readLines(nskip, true, skipNull); + openConn.readLines(nskip, EnumSet.of(ReadLineWarning.EMBEDDED_NUL), skipNull); } if (what instanceof RList) { return scanFrame((RList) what, nmax, nlines, flush, fill, strip == RRuntime.LOGICAL_TRUE, blSkip, multiLine, data); @@ -276,7 +278,7 @@ public abstract class Scan extends RBuiltinNode.Arg19 { private static String[] getItems(LocalData data, boolean blSkip) throws IOException { while (true) { - String[] str = data.con.readLines(1, true, false); + String[] str = data.con.readLines(1, EnumSet.of(ReadLineWarning.EMBEDDED_NUL), false); if (str == null || str.length == 0) { return null; } else { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java index 9c3477a46d7a568cbccfa619e0074fff5027a88d..8d14c507c30459f83ad60a679890af47693e47be 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java @@ -5,7 +5,7 @@ * * Copyright (c) 1995-2012, The R Core Team * Copyright (c) 2003, The R Foundation - * Copyright (c) 2015, 2017, Oracle and/or its affiliates + * Copyright (c) 2015, 2018, Oracle and/or its affiliates * * All rights reserved. */ @@ -13,6 +13,7 @@ package com.oracle.truffle.r.nodes.builtin.base.foreign; import java.io.IOException; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -22,6 +23,7 @@ import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.conn.RConnection; +import com.oracle.truffle.r.runtime.conn.RConnection.ReadLineWarning; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; @@ -47,7 +49,7 @@ public abstract class ReadTableHead extends RExternalBuiltinNode.Arg7 { List<String> lines = new ArrayList<>(nlines); int totalLines = 0; while (totalLines < nlines) { - String[] readLines = openConn.readLines(nlines - totalLines, true, skipNull); + String[] readLines = openConn.readLines(nlines - totalLines, EnumSet.of(ReadLineWarning.EMBEDDED_NUL, ReadLineWarning.INCOMPLETE_LAST_LINE), skipNull); if (readLines.length == 0) { break; } 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 529b416957f177c0e4fd65bc6962234277010b35..2226824b9fc6c9b2e58a01a580589c10b745f1cc 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 @@ -589,6 +589,7 @@ public final class RError extends RuntimeException implements TruffleException { IS_NULL("'%s' is NULL"), MUST_BE_SCALAR("'%s' must be of length 1"), ROWS_MUST_MATCH("number of rows of matrices must match (see arg %d)"), + COLS_MUST_MATCH("number of columns of matrices must match (see arg %d)"), ROWS_NOT_MULTIPLE("number of rows of result is not a multiple of vector length (arg %d)"), ARG_ONE_OF("'%s' should be one of %s"), MUST_BE_SQUARE_MATRIX("'%s' must be a square matrix"), diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RLocale.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RLocale.java index 649cb26fc0696879100374bbf4f87c3dafba0364..d0f4a304f5c003bbbfc722fe2f8ca874400f0235 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RLocale.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RLocale.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -74,6 +74,10 @@ public enum RLocale { return collator; } + public static int compare(Collator collator, String k1, String k2) { + return collator == null ? k1.compareTo(k2) : collator.compare(k1, k2); + } + public static final class ContextStateImpl implements RContext.ContextState { private final EnumMap<RLocale, Locale> locales = new EnumMap<>(RLocale.class); private final EnumMap<RLocale, Charset> charsets = new EnumMap<>(RLocale.class); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java index 50b92a236f95b5ea132d1b95f65f775e6d7c5598..d60b9779df596070a35d174b733b3aeecdf37d55 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -37,6 +37,7 @@ import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.util.ArrayList; import java.util.Arrays; +import java.util.EnumSet; import java.util.LinkedList; import java.util.List; @@ -372,7 +373,7 @@ public class ConnectionSupport { private static final int INVALID_DESCRIPTOR = -1; @Override - public String[] readLines(int n, boolean warn, boolean skipNul) throws IOException { + public String[] readLines(int n, EnumSet<ReadLineWarning> warn, boolean skipNul) throws IOException { throw RInternalError.shouldNotReachHere("INVALID CONNECTION"); } @@ -757,7 +758,7 @@ public class ConnectionSupport { opened = true; } - protected String[] readLinesInternal(int n, boolean warn, boolean skipNul) throws IOException { + protected String[] readLinesInternal(int n, EnumSet<ReadLineWarning> warn, boolean skipNul) throws IOException { checkOpen(); return theConnection.readLines(n, warn, skipNul); } @@ -956,7 +957,7 @@ public class ConnectionSupport { * available. */ @TruffleBoundary - private String[] readLinesWithPushBack(int n, boolean warn, boolean skipNul) throws IOException { + private String[] readLinesWithPushBack(int n, EnumSet<ReadLineWarning> warn, boolean skipNul) throws IOException { // NOTE: 'n' may be negative indicating to read as much lines as available final List<String> res; if (n >= 0) { @@ -996,7 +997,7 @@ public class ConnectionSupport { } @Override - public String[] readLines(int n, boolean warn, boolean skipNul) throws IOException { + public String[] readLines(int n, EnumSet<ReadLineWarning> warn, boolean skipNul) throws IOException { if (pushBack == null) { return readLinesInternal(n, warn, skipNul); } else if (pushBack.size() == 0) { 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 ea6a5e4b639760dee73ee1dda69aa626b3d891bb..b490128e61711ec8309b7019f1fb95a5f7db14f0 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -37,6 +37,7 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.util.ArrayList; +import java.util.EnumSet; import java.util.Objects; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -129,13 +130,13 @@ abstract class DelegateRConnection extends RObject implements RConnection, ByteC /** * {@code readLines} from the connection. It would be convenient to use a {@link BufferedReader} * but mixing binary and text operations, which is a requirement, would then be difficult. - * - * @param warn Specifies if warnings should be output. + * + * @param warn Specifies which warnings should be output. * @param skipNul Specifies if the null character should be ignored. */ @Override @TruffleBoundary - public String[] readLines(int n, boolean warn, boolean skipNul) throws IOException { + public String[] readLines(int n, EnumSet<ReadLineWarning> warn, boolean skipNul) throws IOException { base.setIncomplete(false); ArrayList<String> lines = new ArrayList<>(); int totalRead = 0; @@ -165,7 +166,7 @@ abstract class DelegateRConnection extends RObject implements RConnection, ByteC base.setIncomplete(true); } else { lines.add(incompleteFinalLine); - if (warn) { + if (warn.contains(ReadLineWarning.INCOMPLETE_LAST_LINE)) { RError.warning(RError.SHOW_CALLER, RError.Message.INCOMPLETE_FINAL_LINE, base.getSummaryDescription()); } } @@ -184,7 +185,7 @@ abstract class DelegateRConnection extends RObject implements RConnection, ByteC } } else if (ch == 0) { nullRead = true; - if (warn && !skipNul) { + if (warn.contains(ReadLineWarning.EMBEDDED_NUL) && !skipNul) { RError.warning(RError.SHOW_CALLER, RError.Message.LINE_CONTAINS_EMBEDDED_NULLS, lines.size() + 1); } } 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 f436a0a2f12b44520dafa0c0a63caff6467bde1a..3f0553fdd73f71cda736c760648ac460f5acec9b 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -25,6 +25,7 @@ package com.oracle.truffle.r.runtime.conn; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; +import java.util.EnumSet; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; @@ -41,7 +42,7 @@ abstract class DelegateWriteRConnection extends DelegateRConnection { } @Override - public String[] readLines(int n, boolean warn, boolean skipNul) throws IOException { + public String[] readLines(int n, EnumSet<ReadLineWarning> warn, boolean skipNul) throws IOException { throw new IOException(RError.Message.CANNOT_READ_CONNECTION.message); } 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 7ff189d0fa6fac2e3b4329be7b9817bd15023b8b..1f3bbdfbf71f2394d003ec1e71e285bdc2e41778 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -37,6 +37,7 @@ import java.nio.file.OpenOption; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -443,7 +444,7 @@ public class FileConnections { } @Override - public String[] readLines(int n, boolean warn, boolean skipNul) throws IOException { + public String[] readLines(int n, EnumSet<ReadLineWarning> warn, boolean skipNul) throws IOException { setReadPosition(); return super.readLines(n, warn, skipNul); } @@ -598,7 +599,7 @@ public class FileConnections { } @Override - public String[] readLines(int n, boolean warn, boolean skipNul) throws IOException { + public String[] readLines(int n, EnumSet<ReadLineWarning> warn, boolean skipNul) throws IOException { setReadPosition(); return super.readLines(n, warn, skipNul); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java index df7d420c8b6200f86b2afaa6d244e1e3bfef8c1c..374e37367768cac51bfc998151644244b7b6c269 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, 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 @@ -27,6 +27,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; +import java.util.EnumSet; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.runtime.conn.ConnectionSupport.BaseRConnection; @@ -129,6 +130,15 @@ public interface RConnection extends AutoCloseable, RTruffleObject { WRITE } + enum ReadLineWarning { + EMBEDDED_NUL, + INCOMPLETE_LAST_LINE; + + public static EnumSet<ReadLineWarning> allIf(boolean warn) { + return warn ? EnumSet.of(ReadLineWarning.EMBEDDED_NUL, ReadLineWarning.INCOMPLETE_LAST_LINE) : EnumSet.noneOf(ReadLineWarning.class); + } + } + /** * Support for {@code isSeekable} Internal. */ @@ -209,7 +219,7 @@ public interface RConnection extends AutoCloseable, RTruffleObject { * Read (n > 0 up to n else unlimited) lines on the connection. */ @TruffleBoundary - String[] readLines(int n, boolean warn, boolean skipNul) throws IOException; + String[] readLines(int n, EnumSet<ReadLineWarning> warn, boolean skipNul) throws IOException; /** * Returns {@code true} iff this is a text mode connection. diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java index fdbf611d927d1a4819af8be9f4888742857d1bd5..9925131aadadfd5366cfa5272335025067ba8ed7 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -27,6 +27,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.EnumSet; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.runtime.RError; @@ -202,7 +203,7 @@ public class StdConnections { @Override @TruffleBoundary - public String[] readLinesInternal(int n, boolean warn, boolean skipNul) throws IOException { + public String[] readLinesInternal(int n, EnumSet<ReadLineWarning> warn, boolean skipNul) throws IOException { ArrayList<String> lines = new ArrayList<>(); String line; while ((line = console.readLine()) != null) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java index 6b3fdc386347450f0f2eaafbb1ec09508d14ec23..f40da5e0697d492d885655aa1d4988d935c2790a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -27,6 +27,7 @@ import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; import java.util.ArrayList; +import java.util.EnumSet; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; @@ -104,7 +105,7 @@ public class TextConnections { } @Override - public String[] readLines(int n, boolean warn, boolean skipNul) throws IOException { + public String[] readLines(int n, EnumSet<ReadLineWarning> warn, boolean skipNul) throws IOException { int nleft = lines.length - index; int nlines = nleft; if (n > 0) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/REnvTruffleFrameAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/REnvTruffleFrameAccess.java index a1bab552c1dc30ab68c0bca1e7a14104eb392708..c6c6e182eb57c4e97c18e400aa8204830bf5dd1a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/REnvTruffleFrameAccess.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/REnvTruffleFrameAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -22,9 +22,12 @@ */ package com.oracle.truffle.r.runtime.env.frame; +import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.HashSet; +import java.util.Locale; import java.util.Set; import java.util.regex.Pattern; @@ -38,7 +41,9 @@ import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RLocale; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RStringVector; @@ -193,7 +198,14 @@ public final class REnvTruffleFrameAccess extends REnvFrameAccess { String[] data = new String[matchedNamesList.size()]; matchedNamesList.toArray(data); if (sorted) { - Arrays.sort(data); + Locale locale = RContext.getInstance().stateRLocale.getLocale(RLocale.COLLATE); + Collator collator = locale == Locale.ROOT || locale == null ? null : RLocale.getOrderCollator(locale); + Arrays.sort(data, new Comparator<String>() { + @Override + public int compare(String o1, String o2) { + return RLocale.compare(collator, o1, o2); + } + }); } return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR); } 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 7550b1b88e80478fb75c145a6122116e3c67ef70..a71b1f60210c9ae60f1f65e2deb8e9a5cd8998e6 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 @@ -12661,6 +12661,26 @@ Loading required package: splines head foo2 ##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind# +#cbind(1, 1:4, matrix(1:8, nrow=2)) + [,1] [,2] [,3] [,4] [,5] [,6] +[1,] 1 1 1 3 5 7 +[2,] 1 2 2 4 6 8 +Warning message: +In cbind(1, 1:4, matrix(1:8, nrow = 2)) : + number of rows of result is not a multiple of vector length (arg 2) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind#Output.IgnoreWarningContext# +#cbind(1:2, 1:3, 1:4) + [,1] [,2] [,3] +[1,] 1 1 1 +[2,] 2 2 2 +[3,] 1 3 3 +[4,] 2 1 4 +Warning message: +In cbind(1:2, 1:3, 1:4) : + number of rows of result is not a multiple of vector length (arg 2) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind# #cbind(55, character(0)) [,1] [1,] "55" @@ -12670,6 +12690,15 @@ head a [1,] "55" +##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind# +#cbind(array(1:8,c(2,4),list(c('x','y'), c('a','b', 'a2', 'b2'))), 1:8) + a b a2 b2 +x 1 3 5 7 1 +y 2 4 6 8 2 +Warning message: +In cbind(array(1:8, c(2, 4), list(c("x", "y"), c("a", "b", "a2", : + number of rows of result is not a multiple of vector length (arg 2) + ##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind# #cbind(character(0)) [,1] @@ -12679,6 +12708,11 @@ head [,1] [1,] "f" +##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind# +#cbind(matrix(1:4,nrow=2), matrix(1:8,nrow=4)) +Error in cbind(matrix(1:4, nrow = 2), matrix(1:8, nrow = 4)) : + number of rows of matrices must match (see arg 2) + ##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind# #v <- 1:3; attr(v, 'a') <- 'a'; attr(v, 'a1') <- 'a1'; cbind(v); cbind(v, v) v @@ -12914,6 +12948,42 @@ c 2 <NA> 2 <NA> 2 +##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames# +#cbind(array(1:8,c(2,2),list(c('a','b'), c('d','e'))), array(1:4,c(2,2),list(c('f','g'), c('h','i')))) + d e h i +a 1 3 1 3 +b 2 4 2 4 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#Output.IgnoreWarningContext# +#cbind(array(1:8,c(2,2),list(c('a','b'), c('d','e'))), array(1:8,c(2,2,2),list(c('a1','b1'), c('d1','e1'), c('f1','g1')))) + d e +a 1 3 1 +b 2 4 2 +Warning message: +In cbind(array(1:8, c(2, 2), list(c("a", "b"), c("d", "e"))), array(1:8, : + number of rows of result is not a multiple of vector length (arg 2) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames# +#cbind(array(1:8,c(2,2,2),list(c('a','b'), c('d','e'), c('f','g'))), array(1:8,c(2,2,2),list(c('a1','b1'), c('d1','e1'), c('f1','g1')))) + [,1] [,2] +[1,] 1 1 +[2,] 2 2 +[3,] 3 3 +[4,] 4 4 +[5,] 5 5 +[6,] 6 6 +[7,] 7 7 +[8,] 8 8 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames# +#cbind(array(1:8,c(2,4),list(c('x','y'), c('a','b', 'a2', 'b2'))), array(1:8,c(2,2,2),list(c('a1','b1'), c('d1','e1'), c('f1','g1')))) + a b a2 b2 +x 1 3 5 7 1 +y 2 4 6 8 2 +Warning message: +In cbind(array(1:8, c(2, 4), list(c("x", "y"), c("a", "b", "a2", : + number of rows of result is not a multiple of vector length (arg 2) + ##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames# #{ attributes(cbind(1L)) } $dim diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cbind.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cbind.java index 4f598802c30f2be8ad7db72b85954c3181e5b4c3..81f4608d39ae4e2164a607bf9846dc2c753c772c 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cbind.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cbind.java @@ -4,7 +4,7 @@ * http://www.gnu.org/licenses/gpl-2.0.html * * Copyright (c) 2012-2014, Purdue University - * Copyright (c) 2013, 2017, Oracle and/or its affiliates + * Copyright (c) 2013, 2018, Oracle and/or its affiliates * * All rights reserved. */ @@ -106,6 +106,11 @@ public class TestBuiltin_cbind extends TestBase { assertEval("v <- 1; attr(v, 'a') <- 'a'; attr(v, 'a1') <- 'a1'; cbind(v); cbind(v, v)"); assertEval("v <- 1:3; attr(v, 'a') <- 'a'; attr(v, 'a1') <- 'a1'; cbind(v); cbind(v, v)"); assertEval("v <- 1:3; v1<-1:3; attr(v, 'a') <- 'a'; attr(v1, 'a1') <- 'a1'; cbind(v, v1)"); + + assertEval("cbind(array(1:8,c(2,4),list(c('x','y'), c('a','b', 'a2', 'b2'))), 1:8)"); + assertEval("cbind(1, 1:4, matrix(1:8, nrow=2))"); + assertEval("cbind(matrix(1:4,nrow=2), matrix(1:8,nrow=4))"); + assertEval(Output.IgnoreWarningContext, "cbind(1:2, 1:3, 1:4)"); } @Test @@ -166,6 +171,11 @@ public class TestBuiltin_cbind extends TestBase { assertEval("{ attributes(cbind(integer(0), integer(0))) }"); assertEval("{ attributes(cbind(c(1), integer(0))) }"); assertEval("{ attributes(cbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), integer(0))) }"); + + assertEval("cbind(array(1:8,c(2,2,2),list(c('a','b'), c('d','e'), c('f','g'))), array(1:8,c(2,2,2),list(c('a1','b1'), c('d1','e1'), c('f1','g1'))))"); + assertEval("cbind(array(1:8,c(2,2),list(c('a','b'), c('d','e'))), array(1:4,c(2,2),list(c('f','g'), c('h','i'))))"); + assertEval(Output.IgnoreWarningContext, "cbind(array(1:8,c(2,2),list(c('a','b'), c('d','e'))), array(1:8,c(2,2,2),list(c('a1','b1'), c('d1','e1'), c('f1','g1'))))"); + assertEval("cbind(array(1:8,c(2,4),list(c('x','y'), c('a','b', 'a2', 'b2'))), array(1:8,c(2,2,2),list(c('a1','b1'), c('d1','e1'), c('f1','g1'))))"); } @Test