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 4a350001e6212c0f0f9d45643a09a097ad44fc13..d2ca4dcfab9f20c1f83b72b7ea0a685f2ad8bb53 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 @@ -22,10 +22,7 @@ */ 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.nodes.builtin.CastBuilder.Predef.toBoolean; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.trueValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*; import static com.oracle.truffle.r.runtime.RVisibility.CUSTOM; import static com.oracle.truffle.r.runtime.RVisibility.OFF; import static com.oracle.truffle.r.runtime.builtins.RBehavior.IO; @@ -48,15 +45,17 @@ import java.util.zip.ZipException; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.TypeSystemReference; import com.oracle.truffle.r.nodes.builtin.CastBuilder; +import com.oracle.truffle.r.nodes.builtin.CastBuilder.HeadPhaseBuilder; +import com.oracle.truffle.r.nodes.builtin.CastBuilder.InitialPhaseBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.base.ConnectionFunctionsFactory.WriteDataNodeGen; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RVisibility; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.conn.ConnectionSupport.BaseRConnection; import com.oracle.truffle.r.runtime.conn.FileConnections.FileRConnection; @@ -125,20 +124,51 @@ public abstract class ConnectionFunctions { } } - @RBuiltin(name = "file", kind = INTERNAL, parameterNames = {"description", "open", "blocking", "encoding", "raw"}, behavior = IO) - public abstract static class File extends RBuiltinNode { - - @Override - protected void createCasts(CastBuilder casts) { + private abstract static class CastHelper extends RBuiltinNode { + protected void description(CastBuilder casts) { casts.arg("description").mustBe(stringValue()).asStringVector().shouldBe(singleElement(), RError.Message.ARGUMENT_ONLY_FIRST_1, "description").findFirst().notNA(); + } - casts.arg("open").mustBe(stringValue()).asStringVector().findFirst().notNA(); + protected HeadPhaseBuilder<String> open(CastBuilder casts) { + return casts.arg("open").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst().notNA(); + } - casts.arg("blocking").asLogicalVector().findFirst().map(toBoolean()).mustBe(trueValue(), RError.Message.NYI, "non-blocking mode not supported"); + protected void encoding(CastBuilder casts) { + casts.arg("encoding").asStringVector().mustBe(singleElement()).findFirst(); + } + + protected void raw(CastBuilder casts) { + casts.arg("raw").asLogicalVector().findFirst().notNA().map(toBoolean()); + } + + protected void blocking(CastBuilder casts) { + casts.arg("blocking").asLogicalVector().findFirst().notNA().map(toBoolean()); + } + + protected void connection(CastBuilder casts) { + casts.arg("con").mustBe(instanceOf(RConnection.class)); + } + + protected void nchars(CastBuilder casts) { + casts.arg("nchars").asIntegerVector().mustBe(nullValue().not().and(notEmpty())); + } + + protected void useBytes(CastBuilder casts) { + casts.arg("useBytes").asLogicalVector().findFirst().notNA().map(toBoolean()); + } - casts.arg("encoding").asStringVector().findFirst(); + } + + @RBuiltin(name = "file", kind = INTERNAL, parameterNames = {"description", "open", "blocking", "encoding", "raw"}, behavior = IO) + public abstract static class File extends CastHelper { - casts.arg("raw").asLogicalVector().findFirst().map(toBoolean()); + @Override + protected void createCasts(CastBuilder casts) { + description(casts); + open(casts); + casts.arg("blocking").asLogicalVector().findFirst().map(toBoolean()).mustBe(trueValue(), RError.Message.NYI, "non-blocking mode not supported"); + encoding(casts); + raw(casts); } @Specialization @@ -167,11 +197,6 @@ public abstract class ConnectionFunctions { } } - @SuppressWarnings("unused") - @Fallback - protected Object file(Object description, Object open, Object blocking, Object encoding, Object raw) { - throw RError.error(this, RError.Message.INVALID_UNNAMED_ARGUMENTS); - } } /** @@ -180,13 +205,21 @@ public abstract class ConnectionFunctions { * uncompressed. */ @RBuiltin(name = "gzfile", kind = INTERNAL, parameterNames = {"description", "open", "encoding", "compression"}, behavior = IO) - public abstract static class GZFile extends RBuiltinNode { + public abstract static class GZFile extends CastHelper { + @Override + protected void createCasts(CastBuilder casts) { + description(casts); + open(casts); + encoding(casts); + casts.arg("compression").asIntegerVector().findFirst().notNA().mustBe(gte(0).and(lte(9))); + } + @Specialization @TruffleBoundary @SuppressWarnings("unused") - protected Object gzFile(RAbstractStringVector description, RAbstractStringVector open, RAbstractStringVector encoding, double compression) { + protected Object gzFile(RAbstractStringVector description, String open, RAbstractStringVector encoding, int compression) { try { - return new GZIPRConnection(description.getDataAt(0), open.getDataAt(0)); + return new GZIPRConnection(description.getDataAt(0), open); } catch (ZipException ex) { // wasn't a gzip file, try uncompressed text try { @@ -205,63 +238,90 @@ public abstract class ConnectionFunctions { } } - @RBuiltin(name = "textConnection", kind = INTERNAL, parameterNames = {"nm", "object", "open", "env", "type"}, behavior = IO) - public abstract static class TextConnection extends RBuiltinNode { + @RBuiltin(name = "textConnection", kind = INTERNAL, parameterNames = {"description", "text", "open", "env", "encoding"}, behavior = IO) + public abstract static class TextConnection extends CastHelper { + @Override + protected void createCasts(CastBuilder casts) { + description(casts); + // TODO how to have either a RNull or a String/RStringVector and have the latter coerced + // to a + // RAbstractStringVector to avoid the explicit handling in the specialization + casts.arg("text").mustBe(nullValue().or(stringValue())); + open(casts).mustBe(equalTo("").or(equalTo("r").or(equalTo("w").or(equalTo("a")))), RError.Message.UNSUPPORTED_MODE); + casts.arg("env").mustBe(nullValue().not(), RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class)); + casts.arg("encoding").asIntegerVector().findFirst().notNA(); + } + + private static RAbstractStringVector forceStringVector(Object text) { + if (text instanceof String) { + return RDataFactory.createStringVectorFromScalar((String) text); + } else { + return (RAbstractStringVector) text; + } + } + @Specialization @TruffleBoundary - protected Object textConnection(RAbstractStringVector nm, RAbstractStringVector object, RAbstractStringVector open, REnvironment env, @SuppressWarnings("unused") RAbstractIntVector encoding) { - if (nm.getLength() != 1) { - throw RError.error(this, RError.Message.INVALID_ARGUMENT, "description"); + protected Object textConnection(String description, Object text, String open, REnvironment env, @SuppressWarnings("unused") int encoding) { + RAbstractStringVector object; + if (open.length() == 0 || open.equals("r")) { + if (text == RNull.instance) { + throw RError.error(this, RError.Message.INVALID_ARGUMENT, "text"); + } else { + object = forceStringVector(text); + } + } else { + if (text == RNull.instance) { + throw RError.nyi(this, "textConnection: NULL"); + } else { + object = forceStringVector(text); + } } - // TODO more error checking as per GnuR try { - return new TextRConnection(nm.getDataAt(0), object, env, open.getDataAt(0)); + return new TextRConnection(description, object, env, open); } 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(this, RError.Message.INVALID_OR_UNIMPLEMENTED_ARGUMENTS); - } } @RBuiltin(name = "textConnectionValue", kind = INTERNAL, parameterNames = {"con"}, behavior = IO) public abstract static class TextConnectionValue extends RBuiltinNode { + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("con").mustBe(instanceOf(TextRConnection.class), RError.Message.NOT_A_TEXT_CONNECTION); + } + @Specialization @TruffleBoundary - protected Object textConnection(RConnection conn) { - if (conn instanceof TextRConnection) { - return RDataFactory.createStringVector(((TextRConnection) conn).getValue(), RDataFactory.COMPLETE_VECTOR); - } else { - throw RError.error(this, RError.Message.NOT_A_TEXT_CONNECTION); - } + protected Object textConnection(TextRConnection conn) { + return RDataFactory.createStringVector(conn.getValue(), RDataFactory.COMPLETE_VECTOR); } } @RBuiltin(name = "socketConnection", kind = INTERNAL, parameterNames = {"host", "port", "server", "blocking", "open", "encoding", "timeout"}, behavior = IO) - public abstract static class SocketConnection extends RBuiltinNode { + public abstract static class SocketConnection extends CastHelper { @Override protected void createCasts(CastBuilder casts) { - casts.toInteger(1); - casts.toInteger(6); + casts.arg("host").mustBe(scalarStringValue()); + casts.arg("port").asIntegerVector().findFirst().notNA().mustBe(gte(0)); + casts.arg("server").asLogicalVector().findFirst().notNA().map(toBoolean()); + open(casts); + blocking(casts); + casts.arg("timeout").asIntegerVector().findFirst(); } @Specialization @TruffleBoundary - protected Object socketConnection(RAbstractStringVector host, RAbstractIntVector portVec, byte server, byte blocking, RAbstractStringVector open, - @SuppressWarnings("unused") RAbstractStringVector encoding, RAbstractIntVector timeoutVec) { - int port = portVec.getDataAt(0); - String modeString = open.getDataAt(0); - int timeout = timeoutVec.getDataAt(0); + protected Object socketConnection(String host, int port, boolean server, boolean blocking, String open, + @SuppressWarnings("unused") RAbstractStringVector encoding, int timeout) { try { - if (RRuntime.fromLogical(server)) { - return new RSocketConnection(modeString, true, host.getDataAt(0), port, RRuntime.fromLogical(blocking), timeout); + if (server) { + return new RSocketConnection(open, true, host, port, blocking, timeout); } else { - return new RSocketConnection(modeString, false, host.getDataAt(0), port, RRuntime.fromLogical(blocking), timeout); + return new RSocketConnection(open, false, host, port, blocking, timeout); } } catch (IOException ex) { throw RError.error(this, RError.Message.CANNOT_OPEN_CONNECTION); @@ -270,12 +330,21 @@ public abstract class ConnectionFunctions { } @RBuiltin(name = "url", kind = INTERNAL, parameterNames = {"description", "open", "blocking", "encoding"}, behavior = IO) - public abstract static class URLConnection extends RBuiltinNode { + public abstract static class URLConnection extends CastHelper { + + @Override + protected void createCasts(CastBuilder casts) { + description(casts); + open(casts); + blocking(casts); + encoding(casts); + } + @Specialization @TruffleBoundary - protected Object urlConnection(RAbstractStringVector url, RAbstractStringVector open, @SuppressWarnings("unused") byte blocking, @SuppressWarnings("unused") RAbstractStringVector encoding) { + protected Object urlConnection(String url, String open, @SuppressWarnings("unused") boolean blocking, @SuppressWarnings("unused") String encoding) { try { - return new URLRConnection(url.getDataAt(0), open.getDataAt(0)); + return new URLRConnection(url, open); } catch (MalformedURLException ex) { throw RError.error(this, RError.Message.UNSUPPORTED_URL_SCHEME); } catch (IOException ex) { @@ -324,10 +393,18 @@ public abstract class ConnectionFunctions { } @RBuiltin(name = "open", visibility = OFF, kind = INTERNAL, parameterNames = {"con", "open", "blocking"}, behavior = IO) - public abstract static class Open extends CheckIsConnAdapter { + public abstract static class Open extends CastHelper { + + @Override + protected void createCasts(CastBuilder casts) { + connection(casts); + open(casts); + blocking(casts); + } + @Specialization @TruffleBoundary - protected Object open(RConnection con, RAbstractStringVector open, @SuppressWarnings("unused") byte blocking) { + protected Object open(RConnection con, String open, @SuppressWarnings("unused") boolean blocking) { RContext.getInstance().setVisible(false); try { BaseRConnection baseConn = getBaseConnection(con); @@ -338,30 +415,29 @@ public abstract class ConnectionFunctions { RError.warning(this, RError.Message.ALREADY_OPEN_CONNECTION); return RNull.instance; } - baseConn.open(open.getDataAt(0)); + baseConn.open(open); } catch (IOException ex) { throw RError.error(this, RError.Message.GENERIC, ex.getMessage()); } return RNull.instance; } - @SuppressWarnings("unused") - @Fallback - @TruffleBoundary - protected Object open(Object con, Object open, Object blocking) { - checkIsConnection(con); - throw RError.error(this, RError.Message.INVALID_ARG_TYPE); - } } @RBuiltin(name = "isOpen", kind = INTERNAL, parameterNames = {"con", "rw"}, behavior = IO) - public abstract static class IsOpen extends CheckIsConnAdapter { + public abstract static class IsOpen extends CastHelper { + @Override + protected void createCasts(CastBuilder casts) { + connection(casts); + casts.arg("rw").asIntegerVector().findFirst(); + } + @Specialization @TruffleBoundary - protected RLogicalVector isOpen(RConnection con, RAbstractIntVector rw) { + protected RLogicalVector isOpen(RConnection con, int rw) { BaseRConnection baseCon = getBaseConnection(con); boolean result = baseCon.isOpen(); - switch (rw.getDataAt(0)) { + switch (rw) { case 0: break; case 1: @@ -376,20 +452,19 @@ public abstract class ConnectionFunctions { return RDataFactory.createLogicalVectorFromScalar(result); } - @Fallback - @TruffleBoundary - protected Object isOpen(Object con, @SuppressWarnings("unused") Object rw) { - checkIsConnection(con); - throw RError.error(this, RError.Message.INVALID_ARG_TYPE); - } } @RBuiltin(name = "close", visibility = OFF, kind = INTERNAL, parameterNames = {"con", "type"}, behavior = IO) - public abstract static class Close extends CheckIsConnAdapter { + public abstract static class Close extends CastHelper { + @Override + protected void createCasts(CastBuilder casts) { + connection(casts); + casts.arg("type").asStringVector().findFirst(); + } + @Specialization @TruffleBoundary - protected Object close(RConnection con) { - RContext.getInstance().setVisible(false); + protected Object close(RConnection con, @SuppressWarnings("unused") String type) { try { con.closeAndDestroy(); } catch (IOException ex) { @@ -398,19 +473,13 @@ public abstract class ConnectionFunctions { return RNull.instance; } - @Fallback - @TruffleBoundary - protected Object close(Object con) { - checkIsConnection(con); - throw RError.error(this, RError.Message.INVALID_ARG_TYPE); - } } /** * This is inherited by the {@code readXX/writeXXX} builtins that are required to "close" a * connection that they opened. It does not destroy the connection. */ - private abstract static class InternalCloseHelper extends RBuiltinNode { + private abstract static class InternalCloseHelper extends CastHelper { protected void internalClose(RConnection con) throws RError { try { BaseRConnection baseConn = getBaseConnection(con); @@ -426,18 +495,21 @@ public abstract class ConnectionFunctions { @Override protected void createCasts(CastBuilder casts) { - casts.toLogical(2); - casts.toLogical(3); - casts.toLogical(5); + connection(casts); + casts.arg("n").asIntegerVector().findFirst().notNA(); + casts.arg("ok").asLogicalVector().findFirst().notNA().map(toBoolean()); + casts.arg("warn").asLogicalVector().findFirst().notNA().map(toBoolean()); + encoding(casts); + casts.arg("skipNul").asLogicalVector().findFirst().notNA().map(toBoolean()); } @Specialization @TruffleBoundary - protected Object readLines(RConnection con, int n, byte ok, byte warn, @SuppressWarnings("unused") String encoding, byte skipNul) { + protected Object readLines(RConnection con, int n, boolean ok, boolean warn, @SuppressWarnings("unused") String encoding, boolean skipNul) { // TODO implement all the arguments try (RConnection openConn = con.forceOpen("rt")) { - String[] lines = openConn.readLines(n, RRuntime.fromLogical(warn), RRuntime.fromLogical(skipNul)); - if (n > 0 && lines.length < n && ok == RRuntime.LOGICAL_FALSE) { + String[] lines = openConn.readLines(n, warn, skipNul); + if (n > 0 && lines.length < n && !ok) { throw RError.error(this, RError.Message.TOO_FEW_LINES_READ_LINES); } return RDataFactory.createStringVector(lines, RDataFactory.COMPLETE_VECTOR); @@ -446,26 +518,23 @@ public abstract class ConnectionFunctions { } } - @Specialization - @TruffleBoundary - protected Object readLines(RConnection con, double n, byte ok, byte warn, String encoding, byte skipNul) { - return readLines(con, (int) n, ok, warn, encoding, skipNul); - } - - @SuppressWarnings("unused") - @Fallback - protected Object readLines(Object con, Object n, Object ok, Object warn, Object encoding, Object skipNul) { - throw RError.error(this, RError.Message.INVALID_UNNAMED_ARGUMENTS); - } } @RBuiltin(name = "writeLines", visibility = OFF, kind = INTERNAL, parameterNames = {"text", "con", "sep", "useBytes"}, behavior = IO) public abstract static class WriteLines extends InternalCloseHelper { + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("text").asStringVector().mustBe(nullValue().not().and(instanceOf(RAbstractStringVector.class))); + connection(casts); + casts.arg("sep").asStringVector().findFirst(); + useBytes(casts); + } + @Specialization @TruffleBoundary - protected RNull writeLines(RAbstractStringVector text, RConnection con, RAbstractStringVector sep, byte useBytes) { + protected RNull writeLines(RAbstractStringVector text, RConnection con, String sep, boolean useBytes) { try (RConnection openConn = con.forceOpen("wt")) { - openConn.writeLines(text, sep.getDataAt(0), RRuntime.fromLogical(useBytes)); + openConn.writeLines(text, sep, useBytes); } catch (IOException x) { throw RError.error(this, RError.Message.ERROR_WRITING_CONNECTION, x.getMessage()); } @@ -473,15 +542,15 @@ public abstract class ConnectionFunctions { return RNull.instance; } - @SuppressWarnings("unused") - @Fallback - protected RNull writeLines(Object text, Object con, Object sep, Object useBytes) { - throw RError.error(this, RError.Message.INVALID_UNNAMED_ARGUMENTS); - } } @RBuiltin(name = "flush", visibility = OFF, kind = INTERNAL, parameterNames = {"con"}, behavior = IO) - public abstract static class Flush extends RBuiltinNode { + public abstract static class Flush extends CastHelper { + @Override + protected void createCasts(CastBuilder casts) { + connection(casts); + } + @Specialization @TruffleBoundary protected RNull flush(RConnection con) { @@ -494,66 +563,47 @@ public abstract class ConnectionFunctions { } } - @RBuiltin(name = "pushBack", visibility = OFF, kind = INTERNAL, parameterNames = {"data", "connection", "newLine", "type"}, behavior = IO) - public abstract static class PushBack extends RBuiltinNode { + @RBuiltin(name = "pushBack", visibility = OFF, kind = INTERNAL, parameterNames = {"data", "con", "newLine", "type"}, behavior = IO) + public abstract static class PushBack extends CastHelper { @Override protected void createCasts(CastBuilder casts) { - casts.toCharacter(0); + casts.arg("data").asStringVector().mustBe(nullValue().not().and(instanceOf(RAbstractStringVector.class))); + connection(casts); + casts.arg("newLine").asLogicalVector().findFirst().notNA().map(toBoolean()); + casts.arg("type").asIntegerVector().findFirst(); } @Specialization @TruffleBoundary - protected RNull pushBack(RAbstractStringVector data, RConnection connection, RAbstractLogicalVector newLine, @SuppressWarnings("unused") RAbstractIntVector type) { - if (newLine.getLength() == 0) { - throw RError.error(this, RError.Message.INVALID_ARGUMENT, "newLine"); - } - connection.pushBack(data, newLine.getDataAt(0) == RRuntime.LOGICAL_TRUE); + protected Object pushBack(RAbstractStringVector data, RConnection connection, boolean newLine, @SuppressWarnings("unused") int type) { + connection.pushBack(data, newLine); return RNull.instance; } - @SuppressWarnings("unused") - @Specialization - @TruffleBoundary - protected Object pushBack(RAbstractStringVector data, RConnection connection, RNull newLine, RAbstractIntVector type) { - throw RError.error(this, RError.Message.INVALID_ARGUMENT, "newLine"); - } - - @SuppressWarnings("unused") - @Specialization(guards = "!newLineIsLogical(newLine)") - @TruffleBoundary - protected Object pushBack(RAbstractStringVector data, RConnection connection, RAbstractVector newLine, RAbstractIntVector type) { - throw RError.error(this, RError.Message.INVALID_ARGUMENT, "newLine"); - } - - @SuppressWarnings("unused") - @Fallback - @TruffleBoundary - protected Object pushBack(Object data, Object connection, Object newLine, Object encoding) { - throw RError.error(this, RError.Message.INVALID_CONNECTION); - } - - protected boolean newLineIsLogical(RAbstractVector newLine) { - return newLine.getElementClass() == RLogical.class; - } } - @RBuiltin(name = "pushBackLength", kind = INTERNAL, parameterNames = {"connection"}, behavior = IO) - public abstract static class PushBackLength extends RBuiltinNode { + @RBuiltin(name = "pushBackLength", kind = INTERNAL, parameterNames = {"con"}, behavior = IO) + public abstract static class PushBackLength extends CastHelper { + @Override + protected void createCasts(CastBuilder casts) { + connection(casts); + } @Specialization protected int pushBackLength(RConnection connection) { return connection.pushBackLength(); } - @Fallback - protected Object pushBacklLength(@SuppressWarnings("unused") Object connection) { - throw RError.error(this, RError.Message.INVALID_CONNECTION); - } } - @RBuiltin(name = "clearPushBack", visibility = OFF, kind = INTERNAL, parameterNames = {"connection"}, behavior = IO) - public abstract static class PushBackClear extends RBuiltinNode { + @RBuiltin(name = "clearPushBack", visibility = OFF, kind = INTERNAL, parameterNames = {"con"}, behavior = IO) + public abstract static class PushBackClear extends CastHelper { + + @Override + protected void createCasts(CastBuilder casts) { + connection(casts); + } @Specialization protected RNull pushBackClear(RConnection connection) { @@ -561,34 +611,31 @@ public abstract class ConnectionFunctions { return RNull.instance; } - @Fallback - protected Object pushBackClear(@SuppressWarnings("unused") Object connection) { - throw RError.error(this, RError.Message.INVALID_CONNECTION); - } } @RBuiltin(name = "readChar", kind = INTERNAL, parameterNames = {"con", "nchars", "useBytes"}, behavior = IO) public abstract static class ReadChar extends InternalCloseHelper { - @SuppressWarnings("unused") - @Specialization(guards = "ncharsEmpty(nchars)") - protected RStringVector readCharNcharsEmpty(RConnection con, RAbstractIntVector nchars, RAbstractLogicalVector useBytes) { - return RDataFactory.createEmptyStringVector(); + @Override + protected void createCasts(CastBuilder casts) { + connection(casts); + nchars(casts); + useBytes(casts); } @SuppressWarnings("unused") - @Specialization(guards = "useBytesEmpty(useBytes)") - protected RStringVector readCharUseBytesEmpty(RConnection con, RAbstractIntVector nchars, RAbstractLogicalVector useBytes) { - throw RError.error(this, RError.Message.INVALID_ARGUMENT, "useBytes"); + @Specialization(guards = "ncharsEmpty(nchars)") + protected RStringVector readCharNcharsEmpty(RConnection con, RAbstractIntVector nchars, boolean useBytes) { + return RDataFactory.createEmptyStringVector(); } - @Specialization(guards = {"!ncharsEmpty(nchars)", "!useBytesEmpty(useBytes)"}) + @Specialization(guards = "!ncharsEmpty(nchars)") @TruffleBoundary - protected RStringVector readChar(RConnection con, RAbstractIntVector nchars, RAbstractLogicalVector useBytes) { + protected RStringVector readChar(RConnection con, RAbstractIntVector nchars, boolean useBytes) { try (RConnection openConn = con.forceOpen("rb")) { String[] data = new String[nchars.getLength()]; for (int i = 0; i < data.length; i++) { - data[i] = openConn.readChar(nchars.getDataAt(i), useBytes.getDataAt(0) == RRuntime.LOGICAL_TRUE); + data[i] = openConn.readChar(nchars.getDataAt(i), useBytes); } return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR); } catch (IOException x) { @@ -600,16 +647,22 @@ public abstract class ConnectionFunctions { return nchars.getLength() == 0; } - boolean useBytesEmpty(RAbstractLogicalVector useBytes) { - return useBytes.getLength() == 0; - } } - @RBuiltin(name = "writeChar", visibility = CUSTOM, kind = INTERNAL, parameterNames = {"object", "con", "nchars", "eos", "useBytes"}, behavior = IO) + @RBuiltin(name = "writeChar", visibility = CUSTOM, kind = INTERNAL, parameterNames = {"object", "con", "nchars", "sep", "useBytes"}, behavior = IO) public abstract static class WriteChar extends InternalCloseHelper { + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("object").asStringVector(); + casts.arg("con").mustBe(instanceOf(RConnection.class).or(instanceOf(RAbstractRawVector.class))); + nchars(casts); + casts.arg("sep").mustBe(stringValue().or(nullValue())); + useBytes(casts); + } + @TruffleBoundary @Specialization - protected RNull writeChar(RAbstractStringVector object, RConnection con, RAbstractIntVector nchars, RAbstractStringVector eos, byte useBytes) { + protected RNull writeChar(RAbstractStringVector object, RConnection con, RAbstractIntVector nchars, RAbstractStringVector sep, boolean useBytes) { try (RConnection openConn = con.forceOpen("wb")) { int length = object.getLength(); for (int i = 0; i < length; i++) { @@ -619,7 +672,7 @@ public abstract class ConnectionFunctions { if (pad > 0) { RError.warning(this, RError.Message.MORE_CHARACTERS); } - openConn.writeChar(s, pad, eos.getDataAt(i % length), RRuntime.fromLogical(useBytes)); + openConn.writeChar(s, pad, sep.getDataAt(i % length), useBytes); } } catch (IOException x) { throw RError.error(this, RError.Message.ERROR_WRITING_CONNECTION, x.getMessage()); @@ -627,6 +680,13 @@ public abstract class ConnectionFunctions { RContext.getInstance().setVisible(false); return RNull.instance; } + + @SuppressWarnings("unused") + @TruffleBoundary + @Specialization + protected RNull writeChar(RAbstractStringVector object, RConnection con, RAbstractIntVector nchars, RNull sep, boolean useBytes) { + throw RError.nyi(this, "writeChar(sep=NULL)"); + } } /** @@ -908,11 +968,6 @@ public abstract class ConnectionFunctions { return buffer; } - @SuppressWarnings("unused") - @Fallback - protected ByteBuffer fallback(Object value, int size, boolean swap, boolean useBytes) { - throw RError.nyi(this, "vector type"); - } } @RBuiltin(name = "writeBin", visibility = CUSTOM, kind = INTERNAL, parameterNames = {"object", "con", "size", "swap", "useBytes"}, behavior = IO) @@ -962,7 +1017,7 @@ public abstract class ConnectionFunctions { @Override protected void createCasts(CastBuilder casts) { - casts.toInteger(0); + casts.arg("what").asIntegerVector().findFirst(); } @Specialization @@ -987,7 +1042,13 @@ public abstract class ConnectionFunctions { } @RBuiltin(name = "isSeekable", kind = INTERNAL, parameterNames = "con", behavior = IO) - public abstract static class IsSeekable extends RBuiltinNode { + public abstract static class IsSeekable extends CastHelper { + @Override + protected void createCasts(CastBuilder casts) { + connection(casts); + + } + @Specialization @TruffleBoundary protected byte isSeekable(RConnection con) { @@ -996,13 +1057,21 @@ public abstract class ConnectionFunctions { } @RBuiltin(name = "seek", kind = INTERNAL, parameterNames = {"con", "where", "origin", "rw"}, behavior = IO) - public abstract static class Seek extends RBuiltinNode { + public abstract static class Seek extends CastHelper { + @Override + protected void createCasts(CastBuilder casts) { + connection(casts); + casts.arg("where").asDoubleVector().findFirst(); + casts.arg("origin").asIntegerVector().findFirst(); + casts.arg("rw").asIntegerVector().findFirst(); + } + @Specialization @TruffleBoundary - protected long seek(RConnection con, RAbstractDoubleVector where, RAbstractIntVector origin, RAbstractIntVector rw) { - long offset = (long) where.getDataAt(0); + protected long seek(RConnection con, double where, int origin, int rw) { + long offset = (long) where; try { - return con.seek(offset, RConnection.SeekMode.values()[origin.getDataAt(0)], RConnection.SeekRWMode.values()[rw.getDataAt(0)]); + return con.seek(offset, RConnection.SeekMode.values()[origin], RConnection.SeekRWMode.values()[rw]); } catch (IOException x) { throw RError.error(this, RError.Message.GENERIC, x.getMessage()); } 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 19fdca79bccaab9ff7feb64cf32cd921e99aafab..108a51926b12a0273dd3aa891d1fcc2038f2f464 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 @@ -300,6 +300,7 @@ public final class RError extends RuntimeException { DECREASING_TRUE_FALSE("'decreasing' must be TRUE or FALSE"), ARGUMENT_LENGTHS_DIFFER("argument lengths differ"), ZERO_LENGTH_PATTERN("zero-length pattern"), + UNSUPPORTED_MODE("unsupported mode"), ALL_CONNECTIONS_IN_USE("all connections are in use"), CANNOT_READ_CONNECTION("cannot read from this connection"), CONNECTION_NOT_OPEN_READ("connection not open for reading"),