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 accd564d49a4a5328ba79b9c1d01bb2b369cb3ab..1344948d94e19b1ced0e53d54805717487080ec2 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 @@ -151,12 +151,22 @@ public abstract class ConnectionFunctions { @TruffleBoundary protected Object textConnection(RAbstractStringVector nm, RAbstractStringVector object, RAbstractStringVector open, REnvironment env, @SuppressWarnings("unused") RIntVector encoding) { controlVisibility(); + if (nm.getLength() != 1) { + throw RError.error(getEncapsulatingSourceSection(), RError.Message.INVALID_ARGUMENT, "description"); + } + // TODO more error checking as per GnuR try { return new TextRConnection(nm.getDataAt(0), object, env, open.getDataAt(0)); } catch (IOException ex) { throw RInternalError.shouldNotReachHere(); } } + + @SuppressWarnings("unused") + @Fallback + protected Object textConnection(Object nm, Object object, Object open, Object env, Object encoding) { + throw RError.error(getEncapsulatingSourceSection(), RError.Message.INVALID_OR_UNIMPLEMENTED_ARGUMENTS); + } } @RBuiltin(name = "textConnectionValue", kind = INTERNAL, parameterNames = {"con"}) diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java index 75c26ad53304c20c3300754562d41823551144db..9b25f060d68ea08788c27e8512369eb9c6c6edbe 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java @@ -721,6 +721,7 @@ public class RDeparse { case REALSXP: case CPLXSXP: case RAWSXP: + obj = checkScalarVector(obj); vector2buff(state, (RVector) obj); break; @@ -760,6 +761,22 @@ public class RDeparse { } } + private static RVector checkScalarVector(Object obj) { + if (obj instanceof String) { + return RDataFactory.createStringVectorFromScalar((String) obj); + } else if (obj instanceof Byte) { + return RDataFactory.createLogicalVectorFromScalar((Byte) obj); + } else if (obj instanceof Integer) { + return RDataFactory.createIntVectorFromScalar((Integer) obj); + } else if (obj instanceof Double) { + return RDataFactory.createDoubleVectorFromScalar((Double) obj); + } else if (obj instanceof RComplex) { + return RDataFactory.createComplexVectorFromScalar((RComplex) obj); + } else { + return (RVector) obj; + } + } + @SuppressWarnings("unused") private static boolean curlyahead(Object obj) { return false; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java index bbd989a72a585839db7d16e0ae7852b26c2388f1..5fcc530c9acdb05b171db53cbb6bbb9b507cca98 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java @@ -1073,20 +1073,16 @@ public class RSerialize { stream.writeInt(flags); switch (type) { case STRSXP: { - RStringVector vec = (RStringVector) obj; - stream.writeInt(vec.getLength()); - for (int i = 0; i < vec.getLength(); i++) { - writeItem(vec.getDataAt(i)); - } - break; - } - - case CHARSXP: { - String s = (String) obj; - if (s == RRuntime.STRING_NA) { - stream.writeInt(-1); + if (obj instanceof String) { + // length 1 vector + stream.writeInt(1); + writeCHARSXP((String) obj); } else { - stream.writeString(s); + RStringVector vec = (RStringVector) obj; + stream.writeInt(vec.getLength()); + for (int i = 0; i < vec.getLength(); i++) { + writeCHARSXP(vec.getDataAt(i)); + } } break; } @@ -1229,6 +1225,20 @@ public class RSerialize { } } + /** + * Write the element of a STRSXP. We can't call {@link #writeItem} because that always + * treats a {@code String} as an STRSXP. + */ + private void writeCHARSXP(String s) throws IOException { + int flags = Flags.packFlags(SEXPTYPE.CHARSXP, 0, false, false, false); + stream.writeInt(flags); + if (s == RRuntime.STRING_NA) { + stream.writeInt(-1); + } else { + stream.writeString(s); + } + } + private void writeAttributes(RAttributes attributes) throws IOException { // have to convert to GnuR pairlist Iterator<RAttribute> iter = attributes.iterator(); 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 7e3136db3457ed593238b72778b83b3b6aca79f6..7551bb4ad04188c2488888295383dce47cd854e5 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 @@ -37,13 +37,13 @@ import com.oracle.truffle.r.runtime.env.REnvironment.PutException; public class TextConnections { public static class TextRConnection extends BaseRConnection { - protected String nm; + protected String description; protected RAbstractStringVector object; protected REnvironment env; - public TextRConnection(String nm, RAbstractStringVector object, REnvironment env, String modeString) throws IOException { + public TextRConnection(String description, RAbstractStringVector object, REnvironment env, String modeString) throws IOException { super(ConnectionClass.Text, modeString, AbstractOpenMode.Read); - this.nm = nm; + this.description = description; this.object = object; this.env = env; openNonLazyConnection(); @@ -51,7 +51,7 @@ public class TextConnections { @Override public String getSummaryDescription() { - return nm; + return description; } @Override @@ -152,16 +152,21 @@ public class TextConnections { private static class TextWriteRConnection extends DelegateWriteRConnection implements GetConnectionValue { private String incompleteLine; private RStringVector textVec; + private String idName; private void initTextVec(RStringVector v, TextRConnection textBase) { + if (textBase.description.equals("NULL")) { + throw RError.nyi(null, "anonymous text output connection"); + } + idName = textBase.object.getDataAt(0); try { textVec = v; - textBase.env.put(textBase.nm, textVec); + textBase.env.put(idName, textVec); } catch (PutException ex) { throw RError.error((SourceSection) null, ex); } // lock the binding - textBase.env.lockBinding(textBase.nm); + textBase.env.lockBinding(idName); } protected TextWriteRConnection(BaseRConnection base) { @@ -179,7 +184,7 @@ public class TextConnections { public void closeAndDestroy() throws IOException { base.closed = true; TextRConnection textBase = (TextRConnection) base; - textBase.env.unlockBinding(textBase.nm); + textBase.env.unlockBinding(idName); } @Override @@ -222,7 +227,7 @@ public class TextConnections { } // TODO: not thread safe TextRConnection textBase = (TextRConnection) base; - textBase.env.unlockBinding(textBase.nm); + textBase.env.unlockBinding(idName); // TODO: is vector really complete? initTextVec(RDataFactory.createStringVector(updateData, RDataFactory.COMPLETE_VECTOR), textBase); } @@ -234,8 +239,7 @@ public class TextConnections { @Override public void writeString(String s, boolean nl) throws IOException { - // TODO Auto-generated method stub - + throw RError.nyi(null, "writeString on text connection"); } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java index 51e0dd53168abbf098469572c342e2567c44fd0c..7c4c7e3af1681dcb9edc7cadf2a43a8f2b9e1a51 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java @@ -29,47 +29,48 @@ public enum SEXPTYPE { ENVSXP(4, REnvironment.class), /* environments */ PROMSXP(5, RPromise.class), /* promises: [un]evaluated closure arguments */ LANGSXP(6, RLanguage.class), /* language constructs (special lists) */ - SPECIALSXP(7, null), /* special forms */ - BUILTINSXP(8, null), /* builtin non-special forms */ - CHARSXP(9, String.class), /* "scalar" string type (internal only) */ + SPECIALSXP(7), /* special forms */ + BUILTINSXP(8), /* builtin non-special forms */ + CHARSXP(9), /* "scalar" string type (GnuR internal only) */ LGLSXP(10, RLogicalVector.class), /* logical vectors */ INTSXP(13, RIntVector.class), /* integer vectors */ REALSXP(14, RDoubleVector.class), /* real variables */ CPLXSXP(15, RComplexVector.class), /* complex variables */ - STRSXP(16, RStringVector.class), /* string vectors */ + STRSXP(16, new Class<?>[]{RStringVector.class, String.class}), /* string vectors */ DOTSXP(17, RPairList.class), /* dot-dot-dot object */ - ANYSXP(18, null), /* make "any" args work */ + ANYSXP(18), /* make "any" args work */ VECSXP(19, RList.class), /* generic vectors */ EXPRSXP(20, RExpression.class), /* expressions vectors */ - BCODESXP(21, null), /* byte code */ - EXTPTRSXP(22, null), /* external pointer */ - WEAKREFSXP(23, null), /* weak reference */ + BCODESXP(21), /* byte code */ + EXTPTRSXP(22), /* external pointer */ + WEAKREFSXP(23), /* weak reference */ RAWSXP(24, RRawVector.class), /* raw bytes */ - S4SXP(25, null), /* S4 non-vector */ + S4SXP(25), /* S4 non-vector */ - NEWSXP(30, null), /* fresh node created in new page */ - FREESXP(31, null), /* node released by GC */ + NEWSXP(30), /* fresh node created in new page */ + FREESXP(31), /* node released by GC */ FUNSXP(99, RFunction.class), /* Closure or Builtin */ // used in RSerialize - REFSXP(255, null), - NILVALUE_SXP(254, null), - GLOBALENV_SXP(253, null), - UNBOUNDVALUE_SXP(252, null), + REFSXP(255), + NILVALUE_SXP(254), + GLOBALENV_SXP(253), + UNBOUNDVALUE_SXP(252), MISSINGARG_SXP(251, RMissing.class), - BASENAMESPACE_SXP(250, null), - NAMESPACESXP(249, null), - PACKAGESXP(248, null), - PERSISTSXP(247, null), - BCREPDEF(244, null), - BCREPREF(243, null), - EMPTYENV_SXP(242, null), - BASEENV_SXP(241, null), - ATTRLANGSXP(240, null), - ATTRLISTSXP(239, null), + BASENAMESPACE_SXP(250), + NAMESPACESXP(249), + PACKAGESXP(248), + PERSISTSXP(247), + BCREPDEF(244), + BCREPREF(243), + EMPTYENV_SXP(242), + BASEENV_SXP(241), + ATTRLANGSXP(240), + ATTRLISTSXP(239), // FastR scalar variants of GnuR vector types + // TODO remove these FASTR_DOUBLE(300, Double.class), FASTR_INT(301, Integer.class), FASTR_BYTE(302, Byte.class), @@ -79,13 +80,23 @@ public enum SEXPTYPE { FASTR_SOURCESECTION(306, SourceSection.class); public final int code; - public final Class<?> fastRClass; + public final Class<?>[] fastRClasses; - @CompilationFinal private static final SEXPTYPE[] VALUES = values(); + @CompilationFinal private static final SEXPTYPE[] NON_NULL_VALUES; - SEXPTYPE(int code, Class<?> fastRClass) { + SEXPTYPE(int code) { this.code = code; - this.fastRClass = fastRClass; + this.fastRClasses = null; + } + + SEXPTYPE(int code, Class<?>[] fastRClasses) { + this.code = code; + this.fastRClasses = fastRClasses; + + } + + SEXPTYPE(int code, Class<?> fastRClass) { + this(code, new Class<?>[]{fastRClass}); } private static final Map<Integer, SEXPTYPE> codeMap = new HashMap<>(); @@ -100,9 +111,15 @@ public enum SEXPTYPE { * {@code type} field on the {@link RPairList} has to be consulted. */ public static SEXPTYPE typeForClass(Class<?> fastRClass) { - for (SEXPTYPE type : VALUES) { - if (fastRClass == type.fastRClass) { - return type; + for (SEXPTYPE type : NON_NULL_VALUES) { + if (type.fastRClasses.length == 1) { + if (fastRClass == type.fastRClasses[0]) { + return type; + } + } else { + if (fastRClass == type.fastRClasses[0] || fastRClass == type.fastRClasses[1]) { + return type; + } } } throw RInternalError.shouldNotReachHere(fastRClass.getName()); @@ -137,8 +154,19 @@ public enum SEXPTYPE { } static { + int nonNullCount = 0; for (SEXPTYPE type : SEXPTYPE.values()) { SEXPTYPE.codeMap.put(type.code, type); + if (type.fastRClasses != null) { + nonNullCount++; + } + } + NON_NULL_VALUES = new SEXPTYPE[nonNullCount]; + nonNullCount = 0; + for (SEXPTYPE type : SEXPTYPE.values()) { + if (type.fastRClasses != null) { + NON_NULL_VALUES[nonNullCount++] = type; + } } }