diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
index fe2eb079f49965a9bee08d91dbbc37b11f1d4a35..ec84baa9ed60d1161117164700bfa7e8d2c38e46 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
@@ -282,7 +282,6 @@ public final class REngine implements RContext.Engine {
             ConsoleHandler ch = singleton.context.getConsoleHandler();
             ch.println("Unsupported specialization in node " + use.getNode().getClass().getSimpleName() + " - supplied values: " +
                             Arrays.asList(use.getSuppliedValues()).stream().map(v -> v.getClass().getSimpleName()).collect(Collectors.toList()));
-            use.printStackTrace();
             return null;
         } catch (RecognitionException | RuntimeException e) {
             singleton.context.getConsoleHandler().println("Exception while parsing: " + e);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java
index 6a090aa20916500a2b7eef0d6a7fd80b3bc9259b..9f26ab728d2741459b29f24c1ae7882c02632193 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java
@@ -69,24 +69,24 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     }
 
     @Specialization(guards = {"!empty"})
-    protected int anyDuplicatedFromStart(VirtualFrame frame, RAbstractVector x, RAbstractVector incomparables, byte fromLast) {
+    protected int anyDuplicatedFromStart(VirtualFrame frame, RAbstractContainer x, RAbstractContainer incomparables, byte fromLast) {
         initChildren();
         RType xType = typeof.execute(frame, x);
         if (fromLastProfile.profile(fromLast == RRuntime.LOGICAL_TRUE)) {
-            return getIndexFromLast(x, (RAbstractVector) (castTypeNode.execute(frame, incomparables, xType)));
+            return getIndexFromLast(x, (RAbstractContainer) (castTypeNode.execute(frame, incomparables, xType)));
         } else {
-            return getIndexFromStart(x, (RAbstractVector) (castTypeNode.execute(frame, incomparables, xType)));
+            return getIndexFromStart(x, (RAbstractContainer) (castTypeNode.execute(frame, incomparables, xType)));
         }
     }
 
     @SuppressWarnings("unused")
     @Specialization(guards = "empty")
-    protected int anyDuplicatedEmpty(RAbstractVector x, RAbstractVector incomparables, byte fromLast) {
+    protected int anyDuplicatedEmpty(RAbstractContainer x, RAbstractContainer incomparables, byte fromLast) {
         return 0;
     }
 
     @TruffleBoundary
-    private static int getIndexFromStart(RAbstractVector x, RAbstractVector incomparables) {
+    private static int getIndexFromStart(RAbstractContainer x, RAbstractContainer incomparables) {
         HashSet<Object> incompContents = new HashSet<>();
         HashSet<Object> vectorContents = new HashSet<>();
         for (int i = 0; i < incomparables.getLength(); i++) {
@@ -106,7 +106,7 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     }
 
     @TruffleBoundary
-    private static int getIndexFromStart(RAbstractVector x) {
+    private static int getIndexFromStart(RAbstractContainer x) {
         HashSet<Object> vectorContents = new HashSet<>();
         vectorContents.add(x.getDataAtAsObject(0));
         for (int i = 1; i < x.getLength(); i++) {
@@ -120,7 +120,7 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     }
 
     @TruffleBoundary
-    public static int getIndexFromLast(RAbstractVector x, RAbstractVector incomparables) {
+    public static int getIndexFromLast(RAbstractContainer x, RAbstractContainer incomparables) {
         HashSet<Object> incompContents = new HashSet<>();
         HashSet<Object> vectorContents = new HashSet<>();
         for (int i = 0; i < incomparables.getLength(); i++) {
@@ -140,7 +140,7 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     }
 
     @TruffleBoundary
-    private static int getIndexFromLast(RAbstractVector x) {
+    private static int getIndexFromLast(RAbstractContainer x) {
         HashSet<Object> vectorContents = new HashSet<>();
         vectorContents.add(x.getDataAtAsObject(x.getLength() - 1));
         for (int i = x.getLength() - 2; i >= 0; i--) {
@@ -154,11 +154,11 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     }
 
     @SuppressWarnings("unused")
-    protected boolean isIncomparable(RAbstractVector x, byte incomparables, byte fromLast) {
+    protected boolean isIncomparable(RAbstractContainer x, byte incomparables, byte fromLast) {
         return incomparables == RRuntime.LOGICAL_TRUE;
     }
 
-    protected boolean empty(RAbstractVector x) {
+    protected boolean empty(RAbstractContainer x) {
         return x.getLength() == 0;
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java
index 72f437bf2d5276c9b0301e3ef1223cd9c2ac170f..aeb370ad79feb51187e6a06efdeb31e75b1997b8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java
@@ -161,7 +161,12 @@ public abstract class AsCharacter extends RBuiltinNode {
                 return RDataFactory.createStringVector(data, RDataFactory.INCOMPLETE_VECTOR);
             } else {
                 for (int i = 0; i < data.length; i++) {
-                    data[i] = vec.getDataAt(value.getVector().getDataAt(i) - 1);
+                    int val = value.getVector().getDataAt(i);
+                    if (RRuntime.isNA(val)) {
+                        data[i] = RRuntime.NA_HEADER;
+                    } else {
+                        data[i] = vec.getDataAt(val - 1);
+                    }
                 }
                 return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR);
             }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java
index 096951c0d0e09ca6ebd44d29da4065f9be98b8c8..d60ee330421bcaa84241df1241b4919948070434 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java
@@ -137,4 +137,10 @@ public abstract class AsDouble extends RBuiltinNode {
         controlVisibility();
         return castDoubleVector(frame, vector);
     }
+
+    @Specialization
+    protected RDoubleVector asDouble(VirtualFrame frame, RFactor vector) {
+        return asDouble(frame, vector.getVector());
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java
index ff874767f293d04fa9151e12ff93417bd7039150..547ba5daa653a3603df949dab407907cc2343015 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java
@@ -133,8 +133,7 @@ public abstract class AsInteger extends RBuiltinNode {
 
     @Specialization
     protected RIntVector asInteger(RFactor factor) {
-        controlVisibility();
-        return factor.getVector();
+        return asInteger(factor.getVector());
     }
 
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java
index 2a18bb988bb34c4d0a1dba2b21dcb9ea6b3ba7fc..b50cb5243b83a66f7baa7e48188d76b3fec04310 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java
@@ -101,8 +101,8 @@ public abstract class AsLogical extends RBuiltinNode {
     }
 
     @Specialization
-    protected RLogicalVector asLogical(VirtualFrame frame, RAbstractVector vector) {
+    protected RLogicalVector asLogical(VirtualFrame frame, RAbstractContainer container) {
         controlVisibility();
-        return castLogicalVector(frame, vector);
+        return castLogicalVector(frame, container);
     }
 }
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 8d22b579121f52be4927c7d92137a1c215b342b5..de7553e14890f9674cfdf7752798dc06741e9fd6 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
@@ -168,6 +168,12 @@ public abstract class ConnectionFunctions {
             return theConnection.getInputStream();
         }
 
+        @Override
+        public OutputStream getOutputStream() throws IOException {
+            checkOpen();
+            return theConnection.getOutputStream();
+        }
+
         @Override
         public void writeLines(RAbstractStringVector lines, String sep) throws IOException {
             checkOpen();
@@ -233,6 +239,10 @@ public abstract class ConnectionFunctions {
             // nothing to do
         }
 
+        @Override
+        public OutputStream getOutputStream() {
+            throw RInternalError.shouldNotReachHere();
+        }
     }
 
     private abstract static class DelegateWriteRConnection extends DelegateRConnection {
@@ -245,6 +255,11 @@ public abstract class ConnectionFunctions {
             throw new IOException(RError.Message.CANNOT_READ_CONNECTION.message);
         }
 
+        @Override
+        public InputStream getInputStream() {
+            throw RInternalError.shouldNotReachHere();
+        }
+
     }
 
     /**
@@ -285,6 +300,11 @@ public abstract class ConnectionFunctions {
             throw RInternalError.shouldNotReachHere();
         }
 
+        @Override
+        public OutputStream getOutputStream() {
+            throw RInternalError.shouldNotReachHere();
+        }
+
         @Override
         public void close() throws IOException {
             throw RInternalError.shouldNotReachHere();
@@ -400,8 +420,8 @@ public abstract class ConnectionFunctions {
         }
 
         @Override
-        public InputStream getInputStream() throws IOException {
-            throw RInternalError.shouldNotReachHere();
+        public OutputStream getOutputStream() throws IOException {
+            return outputStream;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Dim.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Dim.java
index 64fe80b7d89ee025dbd2e0d933a8db63ee57701e..b3da390c39b65835322cee41edf31a25468ecb7f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Dim.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Dim.java
@@ -73,16 +73,16 @@ public abstract class Dim extends RBuiltinNode {
         return RNull.instance;
     }
 
-    @Specialization(guards = "!hasDimensions")
-    protected RNull dim(RAbstractVector vector) {
+    @Specialization(guards = {"!hasDimensions", "!isDataFrame"})
+    protected RNull dim(RAbstractContainer container) {
         controlVisibility();
         return RNull.instance;
     }
 
-    @Specialization(guards = "hasDimensions")
-    protected RIntVector dimWithDimensions(RAbstractVector vector) {
+    @Specialization(guards = {"hasDimensions", "!isDataFrame"})
+    protected RIntVector dimWithDimensions(RAbstractContainer container) {
         controlVisibility();
-        return RDataFactory.createIntVector(vector.getDimensions(), RDataFactory.COMPLETE_VECTOR);
+        return RDataFactory.createIntVector(container.getDimensions(), RDataFactory.COMPLETE_VECTOR);
     }
 
     @Specialization
@@ -91,8 +91,12 @@ public abstract class Dim extends RBuiltinNode {
         return RDataFactory.createIntVector(new int[]{dataFrameRowNames(frame, dataFrame), dataFrame.getLength()}, RDataFactory.COMPLETE_VECTOR);
     }
 
-    public static boolean hasDimensions(RAbstractVector vector) {
-        return vector.hasDimensions();
+    public static boolean isDataFrame(RAbstractContainer container) {
+        return container.getElementClass() == RDataFrame.class;
+    }
+
+    public static boolean hasDimensions(RAbstractContainer container) {
+        return container.hasDimensions();
     }
 
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
index 49fa4b5ef08f8a5570eb2e54d7f26bc913edb23c..e1edbd2628f6c5776f3a6da68b68ff07ed8dc45c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
@@ -40,19 +40,19 @@ public abstract class DimNames extends RBuiltinNode {
     }
 
     @Specialization(guards = "!isNull")
-    protected RList getDimNames(RAbstractVector vector) {
+    protected RList getDimNames(RAbstractContainer container) {
         controlVisibility();
-        return vector.getDimNames();
+        return container.getDimNames();
     }
 
     @Specialization(guards = "isNull")
-    protected RNull getDimNamesNull(@SuppressWarnings("unused") RAbstractVector vector) {
+    protected RNull getDimNamesNull(@SuppressWarnings("unused") RAbstractContainer vector) {
         controlVisibility();
         return RNull.instance;
     }
 
-    protected boolean isNull(RAbstractVector vector) {
-        return vector.getDimNames() == null;
+    protected boolean isNull(RAbstractContainer container) {
+        return container.getDimNames() == null;
     }
 
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
index a881407971880e04ca684dc1a66dd08129e1c4d9..ebf063b71dffefaff13aaf04a55a5eed6eb5f286 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
@@ -100,14 +100,14 @@ public class DynLoadFunctions {
                 data[i] = dllInfo;
             }
             RList result = RDataFactory.createList(data, RDataFactory.createStringVector(names, RDataFactory.COMPLETE_VECTOR));
-            RVector.setClassAttr(result, RDataFactory.createStringVectorFromScalar(DLLINFOLIST_CLASS), null, null);
+            RVector.setVectorClassAttr(result, RDataFactory.createStringVectorFromScalar(DLLINFOLIST_CLASS), null, null);
             return result;
         }
     }
 
     private static RList createDLLInfoList(Object[] data) {
         RList dllInfo = RDataFactory.createList(data, RDataFactory.createStringVector(DLLInfo.NAMES, RDataFactory.COMPLETE_VECTOR));
-        RVector.setClassAttr(dllInfo, RDataFactory.createStringVectorFromScalar(DLLINFO_CLASS), null, null);
+        RVector.setVectorClassAttr(dllInfo, RDataFactory.createStringVectorFromScalar(DLLINFO_CLASS), null, null);
         return dllInfo;
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java
index 41bb9c8adaf5989b8d7c706ea9a6a388d170e6b7..2d12a2bf032f27e981b2060119c56c7daf82bec4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java
@@ -32,7 +32,7 @@ import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.nodes.access.*;
 import com.oracle.truffle.r.nodes.builtin.*;
-import com.oracle.truffle.r.nodes.builtin.utils.CountFields;
+import com.oracle.truffle.r.nodes.builtin.utils.*;
 import com.oracle.truffle.r.nodes.unary.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -579,13 +579,15 @@ public class ForeignFunctions {
         // Transcribed from GnuR, library/utils/src/io.c
         @TruffleBoundary
         @Specialization(guards = "isWriteTable")
-        protected Object doWriteTable(VirtualFrame frame, RList f, RArgsValuesAndNames args) {
+        protected Object doWriteTable(VirtualFrame frame, @SuppressWarnings("unused") RList f, RArgsValuesAndNames args) {
             controlVisibility();
             Object[] argValues = args.getValues();
-            Object x = argValues[0];
-            Object con = argValues[1];
-            if (!(con instanceof RConnection)) {
+            Object conArg = argValues[1];
+            RConnection con;
+            if (!(conArg instanceof RConnection)) {
                 throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, "'file' is not a connection");
+            } else {
+                con = (RConnection) conArg;
             }
             // TODO check connection writeable
 
@@ -599,10 +601,10 @@ public class ForeignFunctions {
             Object quoteArg = argValues[9];
             byte qmethod = castLogical(frame, argValues[10]);
 
-            String sep;
-            String eol;
-            String na;
-            String dec;
+            String csep;
+            String ceol;
+            String cna;
+            String cdec;
 
             if (nr == RRuntime.INT_NA) {
                 invalidArgument("nr");
@@ -613,25 +615,24 @@ public class ForeignFunctions {
             if (!(rnamesArg instanceof RNull) && isString(rnamesArg) == null) {
                 invalidArgument("rnames");
             }
-            if ((sep = isString(sepArg)) == null) {
+            if ((csep = isString(sepArg)) == null) {
                 invalidArgument("sep");
             }
-            if ((eol = isString(eolArg)) == null) {
+            if ((ceol = isString(eolArg)) == null) {
                 invalidArgument("eol");
             }
-            if ((na = isString(naArg)) == null) {
+            if ((cna = isString(naArg)) == null) {
                 invalidArgument("na");
             }
-            if ((dec = isString(decArg)) == null) {
+            if ((cdec = isString(decArg)) == null) {
                 invalidArgument("dec");
             }
             if (qmethod == RRuntime.LOGICAL_NA) {
                 invalidArgument("qmethod");
             }
-            if (dec.length() != 1) {
+            if (cdec.length() != 1) {
                 throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, "'dec' must be a single character");
             }
-            char cdec = dec.charAt(0);
             boolean[] quoteCol = new boolean[nc];
             boolean quoteRn = false;
             RIntVector quote = (RIntVector) quoteArg;
@@ -644,7 +645,11 @@ public class ForeignFunctions {
                     quoteCol[qi - 1] = true;
                 }
             }
-            // TODO call WriteTable
+            try {
+                WriteTable.execute(con, argValues[0], nr, nc, rnamesArg, csep, ceol, cna, cdec.charAt(0), RRuntime.fromLogical(qmethod), quoteCol, quoteRn);
+            } catch (IOException | IllegalArgumentException ex) {
+                throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage());
+            }
             return RNull.instance;
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
index 4e0c8e5e25433a92d32f1b0669163d473dfa49c2..47f8b92b2b92b5a5c3420239ccefb013027ed43b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
@@ -167,7 +167,7 @@ public abstract class Format extends RBuiltinNode {
 
     @SuppressWarnings("unused")
     @Specialization(guards = "!wrongArgs")
-    protected RStringVector format(VirtualFrame frame, RAbstractIntVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec,
+    protected RStringVector format(RAbstractIntVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec,
                     RLogicalVector naEncodeVec, RAbstractVector sciVec) {
         if (value.getLength() == 0) {
             return RDataFactory.createEmptyStringVector();
@@ -248,12 +248,18 @@ public abstract class Format extends RBuiltinNode {
 
     @SuppressWarnings("unused")
     @Specialization(guards = "!wrongArgs")
-    protected RStringVector format(VirtualFrame frame, RStringVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec,
-                    RLogicalVector naEncodeVec, RAbstractVector sciVec) {
+    protected RStringVector format(RStringVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec,
+                    RAbstractVector sciVec) {
         // TODO: implement full semantics
         return value;
     }
 
+    @Specialization(guards = "!wrongArgs")
+    protected RStringVector format(RFactor value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec,
+                    RAbstractVector sciVec) {
+        return format(value.getVector(), trimVec, digitsVec, nsmallVec, widthVec, justifyVec, naEncodeVec, sciVec);
+    }
+
     // TruffleDSL bug - should not need multiple guards here
     protected boolean wrongArgsObject(@SuppressWarnings("unused") Object value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec,
                     RLogicalVector naEncodeVec, RAbstractVector sciVec) {
@@ -288,7 +294,7 @@ public abstract class Format extends RBuiltinNode {
         return false;
     }
 
-    protected boolean wrongArgs(RAbstractVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec,
+    protected boolean wrongArgs(RAbstractContainer value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec,
                     RAbstractVector sciVec) {
         return wrongArgsObject(value, trimVec, digitsVec, nsmallVec, widthVec, justifyVec, naEncodeVec, sciVec);
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
index c330411359b5db4de315d1ba6a4c29e9ab5f8746..da6df56c0b4dc1fc8301e55993735d543742594d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
@@ -146,4 +146,10 @@ public abstract class IsNA extends RBuiltinNode {
         controlVisibility();
         return RRuntime.LOGICAL_FALSE;
     }
+
+    @Specialization
+    protected RLogicalVector isNA(RFactor value) {
+        return isNA(value.getVector());
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
index 89570da0f4624a0ad412da55b5e2060c53430803..4af928c4d319c21e85eca9135fe9c3e32b469b52 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
@@ -103,6 +103,12 @@ public class IsTypeFunctions {
             return arg.getElementClass() == Object.class;
         }
 
+        @Specialization
+        protected byte isAtomic(RFactor arg) {
+            controlVisibility();
+            return RRuntime.LOGICAL_TRUE;
+        }
+
     }
 
     @RBuiltin(name = "is.call", kind = PRIMITIVE, parameterNames = {"x"})
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
index efa2d560ffd323ac0cb5ded1a4fdb5334c039087..9edbd53f30eb6535a8aad7e37eed72c8a606666b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
@@ -314,7 +314,7 @@ public class LaFunctions {
             RDoubleVector modulusVec = RDataFactory.createDoubleVectorFromScalar(modulus);
             modulusVec.setAttr("logarithm", useLogIn);
             RList result = RDataFactory.createList(new Object[]{modulusVec, sign}, NAMES_VECTOR);
-            RList.setClassAttr(result, DET_CLASS, null, null);
+            RList.setVectorClassAttr(result, DET_CLASS, null, null);
             return result;
         }
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java
index a00d5102dd3a9386c0615a6753b68289a2af50df..bf38632c7ca1036932c027556fdbc3bbcda67bde 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java
@@ -24,9 +24,12 @@ package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.runtime.RBuiltinKind.*;
 
+import java.util.function.*;
+
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.nodes.access.*;
 import com.oracle.truffle.r.nodes.builtin.*;
@@ -38,42 +41,104 @@ import com.oracle.truffle.r.runtime.data.RPromise.PromiseProfile;
 @RBuiltin(name = "missing", kind = PRIMITIVE, parameterNames = {"x"}, nonEvalArgs = {0})
 public abstract class Missing extends RBuiltinNode {
 
-    private final PromiseProfile promiseProfile = new PromiseProfile();
+    @Child private InlineCacheNode<Frame, Symbol> repCache;
 
-    @Child private GetMissingValueNode getMissingValue;
+    private final ConditionProfile isSymbolNullProfile = ConditionProfile.createBinaryProfile();
 
-    @Specialization
-    protected byte missing(VirtualFrame frame, RPromise promise) {
-        controlVisibility();
-        // Unwrap current promise, as it's irrelevant for 'missing'
-        RNode argExpr = (RNode) promise.getRep();
-        Symbol symbol = RMissingHelper.unwrapSymbol(argExpr);
+    private static InlineCacheNode<Frame, Symbol> createRepCache(int level) {
+        Function<Symbol, RNode> reify = symbol -> createNodeForRep(symbol, level);
+        BiFunction<Frame, Symbol, Object> generic = (frame, symbol) -> RRuntime.asLogical(RMissingHelper.isMissingArgument(frame, symbol));
+        return InlineCacheNode.create(3, reify, generic);
+    }
+
+    private static RNode createNodeForRep(Symbol symbol, int level) {
         if (symbol == null) {
-            return RRuntime.asLogical(false);
+            return ConstantNode.create(RRuntime.LOGICAL_FALSE);
         }
+        return new MissingCheckLevel(symbol, level);
+    }
 
-        // Read symbols value directly
-        if (getMissingValue == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            getMissingValue = insert(GetMissingValueNode.create(symbol));
+    private static class MissingCheckLevel extends RNode {
+
+        @Child private GetMissingValueNode getMissingValue;
+        @Child private InlineCacheNode<Frame, Symbol> recursive;
+
+        private final ConditionProfile isNullProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile isMissingProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile isPromiseProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile isSymbolNullProfile = ConditionProfile.createBinaryProfile();
+        private final PromiseProfile promiseProfile = new PromiseProfile();
+        private final int level;
+
+        public MissingCheckLevel(Symbol symbol, int level) {
+            this.level = level;
+            this.getMissingValue = GetMissingValueNode.create(symbol);
         }
-        Object obj = getMissingValue.execute(frame);
-        if (obj == null) {
-            // In case we are not able to read the symbol in current frame: This is not an argument
-            // and thus return false
-            return RRuntime.asLogical(false);
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            // Read symbols value directly
+            Object value = getMissingValue.execute(frame);
+            if (isNullProfile.profile(value == null)) {
+                // In case we are not able to read the symbol in current frame: This is not an
+                // argument and thus return false
+                return RRuntime.LOGICAL_FALSE;
+            }
+
+            if (isMissingProfile.profile(value == RMissing.instance)) {
+                return RRuntime.LOGICAL_TRUE;
+            }
+
+            assert level < 30;
+            // This might be a promise...
+            if (isPromiseProfile.profile(value instanceof RPromise)) {
+                RPromise promise = (RPromise) value;
+                if (level == 0 && promise.isDefault(promiseProfile)) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
+                if (level > 0 && promise.isEvaluated(promiseProfile)) {
+                    return RRuntime.LOGICAL_FALSE;
+                }
+                if (recursive == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    recursive = insert(createRepCache(level + 1));
+                }
+                // Check: If there is a cycle, return true. (This is done like in GNU R)
+                if (promise.isUnderEvaluation(promiseProfile)) {
+                    return RRuntime.LOGICAL_TRUE;
+                }
+                try {
+                    promise.setUnderEvaluation(true);
+                    Symbol symbol = RMissingHelper.unwrapSymbol((RNode) promise.getRep());
+                    return isSymbolNullProfile.profile(symbol == null) ? RRuntime.LOGICAL_FALSE : recursive.execute(promise.getFrame(), symbol);
+                } finally {
+                    promise.setUnderEvaluation(false);
+                }
+            }
+            return RRuntime.LOGICAL_FALSE;
         }
+    }
 
-        return RRuntime.asLogical(RMissingHelper.isMissing(obj, promiseProfile));
+    @Specialization
+    protected byte missing(VirtualFrame frame, RPromise promise) {
+        controlVisibility();
+        if (repCache == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            repCache = insert(createRepCache(0));
+        }
+        Symbol symbol = RMissingHelper.unwrapSymbol((RNode) promise.getRep());
+        return isSymbolNullProfile.profile(symbol == null) ? RRuntime.LOGICAL_FALSE : (byte) repCache.execute(frame, symbol);
     }
 
-    @Specialization(guards = "!isPromise")
-    protected byte missing(Object obj) {
+    @Specialization
+    protected byte missing(@SuppressWarnings("unused") RMissing obj) {
         controlVisibility();
-        return RRuntime.asLogical(RMissingHelper.isMissing(obj, promiseProfile));
+        return RRuntime.LOGICAL_TRUE;
     }
 
-    public boolean isPromise(Object obj) {
-        return obj instanceof RPromise;
+    @Fallback
+    protected byte missing(@SuppressWarnings("unused") Object obj) {
+        controlVisibility();
+        return RRuntime.LOGICAL_FALSE;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java
index 96e572bfb2d7240a1f682721b6891c3f71f99304..cd3c4edb7128191dc8ae56b02746bb653aaaf063 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java
@@ -28,6 +28,7 @@ import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.Node.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
@@ -41,8 +42,10 @@ import com.oracle.truffle.r.nodes.function.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
 import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute;
+import com.oracle.truffle.r.runtime.data.closures.*;
 import com.oracle.truffle.r.runtime.data.model.*;
 import com.oracle.truffle.r.runtime.env.*;
+import com.oracle.truffle.r.runtime.ops.na.*;
 
 @SuppressWarnings("unused")
 @NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "listElementName", type = RNode.class), @NodeChild(value = "quote", type = RNode.class),
@@ -518,9 +521,13 @@ public abstract class PrettyPrinterNode extends RNode {
                 resultBuilder.append(vector.getLength() - maxPrint);
                 resultBuilder.append(" entries ]");
             }
-            RAttributes attributes = vector.getAttributes();
-            if (attributes != null) {
-                resultBuilder.append(printAttributes(vector, attributes));
+            if (!(vector instanceof RFactorToStringVectorClosure)) {
+                // it's a bit of a hack, but factors are meant to be printed using the S3 function
+                // anyway - the idea is to suppress attribute printing for factors nested in lists
+                RAttributes attributes = vector.getAttributes();
+                if (attributes != null) {
+                    resultBuilder.append(printAttributes(vector, attributes));
+                }
             }
             return builderToString(resultBuilder);
         }
@@ -1014,6 +1021,8 @@ public abstract class PrettyPrinterNode extends RNode {
 
         @Child private PrettyPrinterNode prettyPrinter;
 
+        private final NACheck naCheck = NACheck.create();
+
         private void initCast(Object listElementName) {
             if (prettyPrinter == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -1121,6 +1130,27 @@ public abstract class PrettyPrinterNode extends RNode {
             return prettyPrintSingleElement(operand, listElementName, quote, right);
         }
 
+        // TODO: this should be handled by an S3 function
+        @TruffleBoundary
+        @Specialization
+        protected String prettyPrintListElement(RFactor operand, Object listElementName, byte quote, byte right) {
+            StringBuilder sb = new StringBuilder(prettyPrintSingleElement(RClosures.createFactorToStringVector(operand, naCheck), listElementName, RRuntime.LOGICAL_FALSE, right));
+            sb.append("\nLevels:");
+            Object attr = operand.getVector().getAttr(RRuntime.LEVELS_ATTR_KEY);
+            if (attr != null) {
+                if (attr instanceof String) {
+                    sb.append(" ");
+                    sb.append(attr.toString());
+                } else {
+                    RAbstractStringVector vec = (RAbstractStringVector) attr;
+                    for (int i = 0; i < vec.getLength(); i++) {
+                        sb.append(" ");
+                        sb.append(vec.getDataAt(i));
+                    }
+                }
+            }
+            return sb.toString();
+        }
     }
 
     @NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "isQuoted", type = RNode.class)})
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java
index 5b4deb547537bd121ebb92104b211ffc5d50b35e..fcc23b4d159c2eac5ce04b236226bdf2fad83153 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java
@@ -75,16 +75,25 @@ public abstract class Structure extends RBuiltinNode {
         Object[] values = args.getValues();
         String[] argNames = getSuppliedArgsNames();
         validateArgNames(argNames);
+        RAbstractContainer res = obj;
         for (int i = 0; i < values.length; i++) {
             Object value = fixupValue(values[i]);
             String attrName = fixupAttrName(argNames[i + 1]);
-            if (value == RNull.instance) {
-                obj.removeAttr(attrName);
+            if (attrName.equals(RRuntime.CLASS_ATTR_KEY)) {
+                if (value == RNull.instance) {
+                    res = (RAbstractContainer) res.setClassAttr(null);
+                } else {
+                    res = (RAbstractContainer) res.setClassAttr((RStringVector) value);
+                }
             } else {
-                obj.setAttr(attrName, value);
+                if (value == RNull.instance) {
+                    res.removeAttr(attrName);
+                } else {
+                    res.setAttr(attrName, value);
+                }
             }
         }
-        return obj;
+        return res;
     }
 
     private Object fixupValue(Object value) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java
index 03ef8a58d23cd2fabfa762bd1268775a9ead3f8a..78aa089824addcc4edd5c63a273d83dc567247cc 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java
@@ -163,9 +163,8 @@ public abstract class TypeConvert extends RBuiltinNode {
                 }
             }
             RIntVector res = RDataFactory.createIntVector(data, complete);
-            res.setAttr("levels", RDataFactory.createStringVector(levelsArray, RDataFactory.COMPLETE_VECTOR));
-            res.setAttr("class", RDataFactory.createStringVector("factor"));
-            return RDataFactory.createFactor(res);
+            res.setLevels(RDataFactory.createStringVector(levelsArray, RDataFactory.COMPLETE_VECTOR));
+            return RVector.setVectorClassAttr(res, RDataFactory.createStringVector("factor"), null, null);
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
index eb31cd844a3b507e5dbdc44ca31776eb3da61af2..e5cf9deda213d3b50990031152b8629995aad884 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
@@ -35,7 +35,7 @@ public abstract class UnClass extends RBuiltinNode {
             if (resultVector.isShared()) {
                 resultVector = resultVector.copy();
             }
-            return RVector.setClassAttr(resultVector, null, null, null);
+            return RVector.setVectorClassAttr(resultVector, null, null, null);
         }
         return arg;
     }
@@ -48,7 +48,7 @@ public abstract class UnClass extends RBuiltinNode {
         if (resultFrame.isShared()) {
             resultFrame = resultFrame.copy();
         }
-        return RVector.setClassAttr(resultFrame.getVector(), null, arg, null);
+        return RVector.setVectorClassAttr(resultFrame.getVector(), null, arg, null);
     }
 
     @Specialization
@@ -59,6 +59,6 @@ public abstract class UnClass extends RBuiltinNode {
         if (resultFrame.isShared()) {
             resultFrame = resultFrame.copy();
         }
-        return RVector.setClassAttr(resultFrame.getVector(), null, null, arg);
+        return RVector.setVectorClassAttr(resultFrame.getVector(), null, null, arg);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
index 9cc09ec1e4d84395cd5dea0798e1d1c1645ca325..5dc2897803a17a4a35e0067229a1fd98cc115e64 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
@@ -99,7 +99,7 @@ public abstract class UpdateAttr extends RInvisibleBuiltinNode {
         } else if (name.equals(RRuntime.DIMNAMES_ATTR_KEY)) {
             return updateDimNames(frame, resultVector, value);
         } else if (name.equals(RRuntime.CLASS_ATTR_KEY)) {
-            return RVector.setClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null);
+            return RVector.setVectorClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null);
         } else if (name.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
             resultVector.setRowNames(null);
         } else if (name.equals(RRuntime.LEVELS_ATTR_KEY)) {
@@ -114,11 +114,11 @@ public abstract class UpdateAttr extends RInvisibleBuiltinNode {
     @TruffleBoundary
     public static RAbstractContainer setClassAttrFromObject(RVector resultVector, RAbstractContainer container, Object value, SourceSection sourceSection) {
         if (value instanceof RStringVector) {
-            return RVector.setClassAttr(resultVector, (RStringVector) value, container.getElementClass() == RDataFrame.class ? container : null,
+            return RVector.setVectorClassAttr(resultVector, (RStringVector) value, container.getElementClass() == RDataFrame.class ? container : null,
                             container.getElementClass() == RFactor.class ? container : null);
         }
         if (value instanceof String) {
-            return RVector.setClassAttr(resultVector, RDataFactory.createStringVector((String) value), container.getElementClass() == RDataFrame.class ? container : null,
+            return RVector.setVectorClassAttr(resultVector, RDataFactory.createStringVector((String) value), container.getElementClass() == RDataFrame.class ? container : null,
                             container.getElementClass() == RFactor.class ? container : null);
         }
         throw RError.error(sourceSection, RError.Message.SET_INVALID_CLASS_ATTR);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
index e057dd8e85058fa8143487c7c56b1901aef861b5..1026beea51f893fae726a59c2c250392da7d0f44 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
@@ -89,7 +89,7 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
     }
 
     @Specialization
-    protected RAbstractVector updateAttributes(VirtualFrame frame, RAbstractContainer container, RList list) {
+    protected RAbstractContainer updateAttributes(VirtualFrame frame, RAbstractContainer container, RList list) {
         controlVisibility();
         Object listNamesObject = list.getNames();
         if (listNamesObject == null || listNamesObject == RNull.instance) {
@@ -97,6 +97,7 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
         }
         RStringVector listNames = (RStringVector) listNamesObject;
         RVector resultVector = container.materializeNonSharedVector();
+        RAbstractContainer res = resultVector;
         if (numAttributesProfile.profile(list.getLength() == 0)) {
             resultVector.resetAllAttributes(true);
         } else {
@@ -113,9 +114,9 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
             // set the dim attribute first
             setDimAttribute(frame, resultVector, list);
             // set the remaining attributes in order
-            setRemainingAttributes(frame, container, resultVector, list);
+            res = setRemainingAttributes(frame, container, resultVector, list);
         }
-        return resultVector;
+        return res;
     }
 
     @TruffleBoundary
@@ -155,10 +156,11 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
     }
 
     @ExplodeLoop
-    private void setRemainingAttributes(VirtualFrame virtualFrame, RAbstractContainer container, RVector resultVector, RList sourceList) {
+    private RAbstractContainer setRemainingAttributes(VirtualFrame virtualFrame, RAbstractContainer container, RVector resultVector, RList sourceList) {
         RStringVector listNames = (RStringVector) sourceList.getNames();
         int length = sourceList.getLength();
         assert length > 0 : "Length should be > 0 for ExplodeLoop";
+        RAbstractContainer res = resultVector;
         for (int i = 0; i < sourceList.getLength(); i++) {
             Object value = sourceList.getDataAt(i);
             String attrName = listNames.getDataAt(i);
@@ -174,9 +176,9 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
                 }
             } else if (attrName.equals(RRuntime.CLASS_ATTR_KEY)) {
                 if (value == RNull.instance) {
-                    RVector.setClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null);
+                    res = RVector.setVectorClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null);
                 } else {
-                    UpdateAttr.setClassAttrFromObject(resultVector, container, value, getEncapsulatingSourceSection());
+                    res = UpdateAttr.setClassAttrFromObject(resultVector, container, value, getEncapsulatingSourceSection());
                 }
             } else if (attrName.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
                 resultVector.setRowNames(castVector(virtualFrame, value));
@@ -190,6 +192,7 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode {
                 }
             }
         }
+        return res;
     }
 
     @Fallback
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
index b3675f366db369c158ec27d7f1b2bf98afc7e8bc..37fa0e9d465ea96cd68cb0f540b5e68ec3131a63 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
@@ -61,7 +61,7 @@ public abstract class UpdateClass extends RBuiltinNode {
     protected Object setClass(RAbstractContainer arg, @SuppressWarnings("unused") RNull className) {
         controlVisibility();
         RVector resultVector = arg.materializeNonSharedVector();
-        return RVector.setClassAttr(resultVector, null, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
+        return RVector.setVectorClassAttr(resultVector, null, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
     }
 
     @Specialization
@@ -102,7 +102,7 @@ public abstract class UpdateClass extends RBuiltinNode {
             throw RError.error(getEncapsulatingSourceSection(), RError.Message.NOT_ARRAY_UPDATE_CLASS);
         }
 
-        return RVector.setClassAttr(resultVector, RDataFactory.createStringVector(className), arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg
+        return RVector.setVectorClassAttr(resultVector, RDataFactory.createStringVector(className), arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg
                         : null);
     }
 
@@ -111,7 +111,7 @@ public abstract class UpdateClass extends RBuiltinNode {
     protected Object setClass(RAbstractContainer arg, RStringVector className) {
         controlVisibility();
         RVector resultVector = arg.materializeNonSharedVector();
-        return RVector.setClassAttr(resultVector, className, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
+        return RVector.setVectorClassAttr(resultVector, className, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
     }
 
     public Object setClass(RFunction arg, @SuppressWarnings("unused") Object className) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
index c9d49853b917dadec1fc28443c79387dd7185d5e..bda5ebe634a64bbaaee2959a01c772c0840c4129 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
@@ -76,7 +76,7 @@ public abstract class UpdateOldClass extends RInvisibleBuiltinNode {
     protected Object setOldClass(RAbstractContainer arg, RStringVector className) {
         controlVisibility();
         RVector resultVector = arg.materializeNonSharedVector();
-        return RVector.setClassAttr(resultVector, className, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
+        return RVector.setVectorClassAttr(resultVector, className, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
     }
 
     @Specialization
@@ -84,7 +84,7 @@ public abstract class UpdateOldClass extends RInvisibleBuiltinNode {
     protected Object setOldClass(RAbstractContainer arg, @SuppressWarnings("unused") RNull className) {
         controlVisibility();
         RVector resultVector = arg.materializeNonSharedVector();
-        return RVector.setClassAttr(resultVector, null, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
+        return RVector.setVectorClassAttr(resultVector, null, arg.getElementClass() == RDataFrame.class ? arg : null, arg.getElementClass() == RFactor.class ? arg : null);
     }
 
     @TruffleBoundary
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
index 200ede3e97bf0f1721c4ff94b64261702a39600a..480169c013a924a88259accdc8287cd4048fb1a9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
@@ -64,7 +64,17 @@ public abstract class UpdateStorageMode extends RBuiltinNode {
                     if (attrs != null) {
                         RAttributable rresult = (RAttributable) result;
                         for (RAttribute attr : attrs) {
-                            rresult.setAttr(attr.getName(), attr.getValue());
+                            String attrName = attr.getName();
+                            Object v = attr.getValue();
+                            if (attrName.equals(RRuntime.CLASS_ATTR_KEY)) {
+                                if (v == RNull.instance) {
+                                    rresult = rresult.setClassAttr(null);
+                                } else {
+                                    rresult = rresult.setClassAttr((RStringVector) v);
+                                }
+                            } else {
+                                rresult.setAttr(attrName, v);
+                            }
                         }
                     }
                 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java
index dc2afb7fbf7a5cce07af04b5024a4947ccebcc3e..23fdfd3d6b48b615ceceec9dfd41c45baa0b85c9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java
@@ -15,6 +15,7 @@ import static com.oracle.truffle.r.runtime.RBuiltinKind.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.nodes.access.*;
 import com.oracle.truffle.r.nodes.builtin.*;
@@ -87,6 +88,7 @@ public abstract class UseMethod extends RBuiltinNode {
         }
     }
 
+    @NodeInfo(cost = NodeCost.UNINITIALIZED)
     private static final class UninitializedUseMethodNode extends UseMethodNode {
 
         protected final int depth;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java
index ee32d4b062fadb17d7d596c269dce3e39d15f781..5395974b3fdf0e9df8b8f302dbeb8bb70f4f03d1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java
@@ -47,12 +47,12 @@ import static com.oracle.truffle.r.runtime.RBuiltinKind.INTERNAL;
  */
 public class WhichFunctions {
 
-    @RBuiltin(name = "which", kind = INTERNAL, parameterNames = {"x", "arr.ind", "useNames"})
+    @RBuiltin(name = "which", kind = INTERNAL, parameterNames = {"x"})
     public abstract static class Which extends RBuiltinNode {
 
         @Override
         public RNode[] getParameterValues() {
-            return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(RRuntime.LOGICAL_FALSE), ConstantNode.create(RRuntime.LOGICAL_TRUE)};
+            return new RNode[]{ConstantNode.create(RMissing.instance)};
         }
 
         @Specialization
@@ -69,7 +69,7 @@ public class WhichFunctions {
             for (int i = 0; i < result.length; ++i) {
                 result[i] = w.get(i) + 1;
             }
-            return RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR);
+            return RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR, x.getNames());
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/UtilsPackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/UtilsPackage.java
index cec62105707b90d71030ad92ee9012dcddc8242a..17c80f02362ccbc7127038dad606ef06d7ea06bd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/UtilsPackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/UtilsPackage.java
@@ -1,12 +1,24 @@
 /*
- * This material is distributed under the GNU General Public License
- * Version 2. You may review the terms of this license at
- * http://www.gnu.org/licenses/gpl-2.0.html
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
- * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, Oracle and/or its affiliates
+ * 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.
  *
- * All rights reserved.
+ * 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.utils;
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/WriteTable.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/WriteTable.java
new file mode 100644
index 0000000000000000000000000000000000000000..b842fb3814ac9f458cf4a610f5b556a4c43e0dd7
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/WriteTable.java
@@ -0,0 +1,165 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 1995-2012, The R Core Team
+ * Copyright (c) 2003, The R Foundation
+ * Copyright (c) 2014, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.nodes.builtin.utils;
+
+import java.io.*;
+
+import com.oracle.truffle.r.runtime.*;
+import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.model.*;
+
+//Transcribed from GnuR, library/utils/src/io.c
+
+//Checkstyle: stop
+public class WriteTable {
+    // @formatter:off
+    public static Object execute(RConnection con, Object xx, int nr, int nc, Object rnames, String csep, String ceol, String cna,
+                  char cdec, boolean qmethod, boolean[] quoteCol, boolean quoteRn) throws IOException, IllegalArgumentException {
+        // @formatter:on
+        OutputStream os = con.getOutputStream();
+        String tmp = null;
+        if (xx instanceof RDataFrame) { /* A data frame */
+            RVector xy = ((RDataFrame) xx).getVector();
+            RVector x = (RVector) xy.getDataAtAsObject(0);
+
+            /* handle factors internally, check integrity */
+            RStringVector[] levels = new RStringVector[nc];
+            for (int j = 0; j < nc; j++) {
+                RAbstractContainer xj = (RAbstractContainer) x.getDataAtAsObject(j);
+                if (xj.getLength() != nr) {
+                    throw new IllegalArgumentException("corrupt data frame -- length of column " + (j + 1) + " does not not match nrows");
+                }
+                if (isFactor(xj)) {
+                    levels[j] = (RStringVector) xj.getAttributes().get("levels");
+                }
+            }
+
+            for (int i = 0; i < nr; i++) {
+                // if (i % 1000 == 999)
+                // R_CheckUserInterrupt();
+                if (!(rnames instanceof RNull)) {
+                    os.write(encodeElement2((RStringVector) rnames, i, quoteRn, qmethod, cdec).getBytes());
+                    os.write(csep.getBytes());
+                }
+                for (int j = 0; j < nc; j++) {
+                    RAbstractContainer xj = (RAbstractContainer) x.getDataAtAsObject(j);
+                    if (j > 0)
+                        os.write(csep.getBytes());
+                    if (isna(xj, i)) {
+                        tmp = cna;
+                    } else {
+                        if (levels[j] != null) {
+                            tmp = encodeElement2(levels[j], (int) xj.getDataAtAsObject(i) - 1, quoteCol[j], qmethod, cdec);
+                        } else {
+                            tmp = encodeElement2((RAbstractVector) xj, i, quoteCol[j], qmethod, cdec);
+                        }
+                        /* if(cdec) change_dec(tmp, cdec, TYPEOF(xj)); */
+                    }
+                    os.write(tmp.getBytes());
+                }
+                os.write(ceol.getBytes());
+            }
+
+        } else { /* A matrix */
+
+            // if (!isVectorAtomic(x))
+            // UNIMPLEMENTED_TYPE("write.table, matrix method", x);
+            RVector x = (RVector) xx;
+            /* quick integrity check */
+            if (x.getLength() != nr * nc) {
+                throw new IllegalArgumentException("corrupt matrix -- dims not not match length");
+            }
+
+            for (int i = 0; i < nr; i++) {
+                if (i % 1000 == 999) {
+                    // R_CheckUserInterrupt();
+                }
+                if (!(rnames instanceof RNull)) {
+                    os.write(encodeElement2((RStringVector) rnames, i, quoteRn, qmethod, cdec).getBytes());
+                    os.write(csep.getBytes());
+                }
+                for (int j = 0; j < nc; j++) {
+                    if (j > 0) {
+                        os.write(csep.getBytes());
+                    }
+                    if (isna(x, i + j * nr)) {
+                        tmp = cna;
+                    } else {
+                        tmp = encodeElement2(x, i + j * nr, quoteCol[j], qmethod, cdec);
+                        /* if(cdec) change_dec(tmp, cdec, TYPEOF(x)); */
+                    }
+                    os.write(tmp.getBytes());
+                }
+                os.write(ceol.getBytes());
+            }
+
+        }
+        return RNull.instance;
+    }
+
+    /* a version of EncodeElement with different escaping of char strings */
+    private static String encodeElement2(RAbstractVector x, int indx, boolean quote, boolean qmethod, char cdec) {
+        if (indx < 0 || indx >= x.getLength()) {
+            throw new IllegalArgumentException("index out of range");
+        }
+        if (x instanceof RStringVector) {
+            RStringVector sx = (RStringVector) x;
+            StringBuffer sb = new StringBuffer();
+            String p0 = /* translateChar */sx.getDataAt(indx);
+            if (!quote)
+                return p0;
+            sb.append('"');
+            for (int i = 0; i < p0.length(); i++) {
+                char p = p0.charAt(i);
+                if (p == '"') {
+                    sb.append(qmethod ? '\\' : '"');
+                }
+                sb.append(p);
+            }
+            sb.append('"');
+            return sb.toString();
+        }
+        return encodeElement(x, indx, quote ? '"' : 0, cdec);
+    }
+
+    private static boolean isna(RAbstractContainer x, int indx) {
+        if (x instanceof RLogicalVector) {
+            return RRuntime.isNA(((RLogicalVector) x).getDataAt(indx));
+        } else if (x instanceof RDoubleVector) {
+            return RRuntime.isNA(((RDoubleVector) x).getDataAt(indx));
+        } else if (x instanceof RIntVector) {
+            return RRuntime.isNA(((RIntVector) x).getDataAt(indx));
+        } else if (x instanceof RStringVector) {
+            return RRuntime.isNA(((RStringVector) x).getDataAt(indx));
+        } else if (x instanceof RComplexVector) {
+            RComplexVector cvec = (RComplexVector) x;
+            RComplex c = cvec.getDataAt(indx);
+            return c.isNA();
+        } else {
+            return false;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static String encodeElement(Object x, int indx, char quote, char dec) {
+        throw RInternalError.unimplemented();
+    }
+
+    private static boolean isFactor(RAbstractContainer v) {
+        for (int i = 0; i < v.getClassHierarchy().getLength(); i++) {
+            if (v.getClassHierarchy().getDataAt(i).equals("factor")) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/CallInlineCacheNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/CallInlineCacheNode.java
index f8f7fff1860d11c0ee70b63ad6234d0ac2e035f2..6ebcf6cbb962f8edf51c26d98b8eb60cf069339d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/CallInlineCacheNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/CallInlineCacheNode.java
@@ -45,6 +45,7 @@ public abstract class CallInlineCacheNode extends Node {
         return new UninitializedCallInlineCacheNode(maxPicDepth);
     }
 
+    @NodeInfo(cost = NodeCost.UNINITIALIZED)
     private static final class UninitializedCallInlineCacheNode extends CallInlineCacheNode {
 
         private final int maxPicDepth;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java
index f490925043f3a64b033c7db61d163746d5f9724f..f80ceb6a9f9b8f28018adceabe8ebe8c077e8062 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java
@@ -74,6 +74,7 @@ public abstract class InlineCacheNode<F extends Frame, T> extends Node {
         return create(maxPicDepth, closure -> (RNode) closure.getExpr(), (frame, closure) -> RContext.getEngine().evalPromise(closure, frame.materialize()));
     }
 
+    @NodeInfo(cost = NodeCost.UNINITIALIZED)
     private static final class UninitializedInlineCacheNode<F extends Frame, T> extends InlineCacheNode<F, T> {
 
         private final int maxPicDepth;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/FrameSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/FrameSlotNode.java
index 0f88a96422ac34b27c4c18862f6d8557869bb061..2b12522378a4dc8363781d2d9e1375fd959629ea 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/FrameSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/FrameSlotNode.java
@@ -67,6 +67,7 @@ public abstract class FrameSlotNode extends Node {
         return new PresentFrameSlotNode(slot);
     }
 
+    @NodeInfo(cost = NodeCost.UNINITIALIZED)
     private static final class UnresolvedFrameSlotNode extends FrameSlotNode {
 
         private final Object identifier;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java
index 411c469e4a26860f6a418d598179fb717b6b8dbd..4f8dce9a8b1775a9f5754680b6e44521a0253c0f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java
@@ -278,6 +278,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
         RType getMode();
     }
 
+    @NodeInfo(cost = NodeCost.UNINITIALIZED)
     public static final class UnresolvedReadVariableNode extends ReadVariableNode implements HasMode {
 
         // TODO It seems a refactoring would be appropriate to encapsulate all fields (symbol, mode,
@@ -460,6 +461,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
         }
     }
 
+    @NodeInfo(cost = NodeCost.UNINITIALIZED)
     public static final class UnResolvedReadLocalVariableNode extends ReadVariableNode implements HasMode {
         private final Symbol symbol;
         private final RType mode;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java
index b322e5d520d2c0f63d18388948b44e326808d047..b459fcff3dd6929beb88f672908c4a2ff0ed6485 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java
@@ -25,6 +25,7 @@ package com.oracle.truffle.r.nodes.access;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.r.nodes.*;
@@ -152,6 +153,7 @@ public abstract class WriteVariableNode extends RNode implements VisibilityContr
 
     public abstract void execute(VirtualFrame frame, Object value);
 
+    @NodeInfo(cost = NodeCost.UNINITIALIZED)
     @NodeFields({@NodeField(name = "name", type = String.class), @NodeField(name = "mode", type = Mode.class)})
     public abstract static class UnresolvedWriteLocalVariableNode extends WriteVariableNode {
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java
index e853324fdf9307d15d45f1701ce9d49c36b16723..42cc3f0d73727ff0f766e5231a30dc66ca76f5c1 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java
@@ -184,6 +184,14 @@ public abstract class AccessArrayNode extends RNode {
         return RDataFactory.createStringVector(namesData, namesNACheck.neverSeenNA());
     }
 
+    // TODO: ultimately factor accesses should be turned into generic function
+    @Specialization
+    protected Object accessFactor(VirtualFrame frame, RFactor factor, int recLevel, Object position, RAbstractLogicalVector dropDim) {
+        RIntVector res = (RIntVector) castVector(frame, accessRecursive(frame, factor.getVector(), position, recLevel, dropDim));
+        res.setLevels(factor.getVector().getAttr(RRuntime.LEVELS_ATTR_KEY));
+        return RVector.setVectorClassAttr(res, RDataFactory.createStringVector("factor"), null, null);
+    }
+
     @SuppressWarnings("unused")
     @Specialization(guards = {"inRecursion", "isFirstPositionPositive"})
     protected RNull accessNullInRecursionPosPositive(RNull vector, int recLevel, RAbstractIntVector positions, RAbstractLogicalVector dropDim) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/CoerceVector.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/CoerceVector.java
index eec8bfc66da0e9e94c01b80404bb1c5bad7d1e68..d6d5c8f5ea150b6d87162d763660e75cd61573a9 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/CoerceVector.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/CoerceVector.java
@@ -129,8 +129,8 @@ public abstract class CoerceVector extends RNode {
         throw RError.error(getEncapsulatingSourceSection(), RError.Message.SUBASSIGN_TYPE_FIX, "integer", "raw");
     }
 
-    @Specialization
-    protected RList coerce(VirtualFrame frame, RAbstractIntVector value, RList vector, Object operand) {
+    @Specialization(guards = "isVectorListOrDataFrame")
+    protected RAbstractContainer coerce(VirtualFrame frame, RAbstractIntVector value, RAbstractContainer vector, Object operand) {
         return vector;
     }
 
@@ -167,7 +167,7 @@ public abstract class CoerceVector extends RNode {
     }
 
     @Specialization
-    protected RList coerce(VirtualFrame frame, RAbstractDoubleVector value, RList vector, Object operand) {
+    protected RAbstractContainer coerce(VirtualFrame frame, RAbstractDoubleVector value, RAbstractContainer vector, Object operand) {
         return vector;
     }
 
@@ -203,8 +203,8 @@ public abstract class CoerceVector extends RNode {
         throw RError.error(getEncapsulatingSourceSection(), RError.Message.SUBASSIGN_TYPE_FIX, "logical", "raw");
     }
 
-    @Specialization
-    protected RList coerce(VirtualFrame frame, RAbstractLogicalVector value, RList vector, Object operand) {
+    @Specialization(guards = "isVectorListOrDataFrame")
+    protected RAbstractContainer coerce(VirtualFrame frame, RAbstractLogicalVector value, RAbstractContainer vector, Object operand) {
         return vector;
     }
 
@@ -240,8 +240,8 @@ public abstract class CoerceVector extends RNode {
         throw RError.error(getEncapsulatingSourceSection(), RError.Message.SUBASSIGN_TYPE_FIX, "character", "raw");
     }
 
-    @Specialization
-    protected RList coerce(VirtualFrame frame, RAbstractStringVector value, RList vector, Object operand) {
+    @Specialization(guards = "isVectorListOrDataFrame")
+    protected RAbstractContainer coerce(VirtualFrame frame, RAbstractStringVector value, RAbstractContainer vector, Object operand) {
         return vector;
     }
 
@@ -277,8 +277,8 @@ public abstract class CoerceVector extends RNode {
         throw RError.error(getEncapsulatingSourceSection(), RError.Message.SUBASSIGN_TYPE_FIX, "complex", "raw");
     }
 
-    @Specialization
-    protected RList coerce(VirtualFrame frame, RAbstractComplexVector value, RList vector, Object operand) {
+    @Specialization(guards = "isVectorListOrDataFrame")
+    protected RAbstractContainer coerce(VirtualFrame frame, RAbstractComplexVector value, RAbstractContainer vector, Object operand) {
         return vector;
     }
 
@@ -294,15 +294,15 @@ public abstract class CoerceVector extends RNode {
         throw RError.error(getEncapsulatingSourceSection(), RError.Message.SUBASSIGN_TYPE_FIX, "raw", RRuntime.classToString(vector.getElementClass(), false));
     }
 
-    @Specialization
-    protected RList coerce(VirtualFrame frame, RAbstractRawVector value, RList vector, Object operand) {
+    @Specialization(guards = "isVectorListOrDataFrame")
+    protected RAbstractContainer coerce(VirtualFrame frame, RAbstractRawVector value, RAbstractContainer vector, Object operand) {
         return vector;
     }
 
     // list vector value
 
-    @Specialization
-    protected RList coerce(VirtualFrame frame, RList value, RList vector, Object operand) {
+    @Specialization(guards = "isVectorListOrDataFrame")
+    protected RAbstractContainer coerce(VirtualFrame frame, RList value, RAbstractContainer vector, Object operand) {
         return vector;
     }
 
@@ -314,21 +314,21 @@ public abstract class CoerceVector extends RNode {
     // data frame value
 
     @Specialization
-    protected RList coerce(VirtualFrame frame, RDataFrame value, RAbstractVector vector, Object operand) {
+    protected RList coerce(VirtualFrame frame, RDataFrame value, RAbstractContainer vector, Object operand) {
         return (RList) castList(frame, vector);
     }
 
     // factor value
 
     @Specialization
-    protected Object coerce(VirtualFrame frame, RFactor value, RAbstractVector vector, Object operand) {
+    protected Object coerce(VirtualFrame frame, RFactor value, RAbstractContainer vector, Object operand) {
         return coerceRecursive(frame, value.getVector(), vector, operand);
     }
 
     // function vector value
 
     @Specialization
-    protected RFunction coerce(RFunction value, RAbstractVector vector, Object operand) {
+    protected RFunction coerce(RFunction value, RAbstractContainer vector, Object operand) {
         throw RError.error(getEncapsulatingSourceSection(), RError.Message.SUBASSIGN_TYPE_FIX, "closure", RRuntime.classToString(vector.getElementClass(), false));
     }
 
@@ -358,4 +358,7 @@ public abstract class CoerceVector extends RNode {
         return vector.getElementClass() == Object.class;
     }
 
+    protected boolean isVectorListOrDataFrame(RAbstractContainer value, RAbstractContainer vector) {
+        return vector.getElementClass() == Object.class || vector.getElementClass() == RDataFrame.class;
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java
index 6a1cfd0c93db3532420a91ca67ee01e3931542c6..5892d9d53419ddd74bc4e36e537f3247295285d3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java
@@ -25,6 +25,7 @@ package com.oracle.truffle.r.nodes.access.array.write;
 import java.util.*;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.source.*;
@@ -58,6 +59,8 @@ public abstract class UpdateArrayHelperNode extends RNode {
 
     protected abstract Object executeUpdate(VirtualFrame frame, Object v, Object value, int recLevel, Object positions, Object vector);
 
+    @CompilationFinal private boolean recursiveIsSubset;
+
     @Child private UpdateArrayHelperNode updateRecursive;
     @Child private CastComplexNode castComplex;
     @Child private CastDoubleNode castDouble;
@@ -84,18 +87,30 @@ public abstract class UpdateArrayHelperNode extends RNode {
 
     public UpdateArrayHelperNode(boolean isSubset) {
         this.isSubset = isSubset;
+        this.recursiveIsSubset = isSubset;
     }
 
     public UpdateArrayHelperNode(UpdateArrayHelperNode other) {
         this.isSubset = other.isSubset;
+        this.recursiveIsSubset = other.recursiveIsSubset;
     }
 
-    private Object updateRecursive(VirtualFrame frame, Object v, Object value, Object vector, Object operand, int recLevel) {
-        if (updateRecursive == null) {
+    private Object updateRecursive(VirtualFrame frame, Object v, Object value, Object vector, Object operand, int recLevel, boolean forDataFrame) {
+        // for data frames, recursive update is the same as for lists but as if the [[]] operator
+        // was used
+        if (updateRecursive == null || (forDataFrame && isSubset) || (!forDataFrame && isSubset != recursiveIsSubset)) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            updateRecursive = insert(UpdateArrayHelperNodeFactory.create(this.isSubset, null, null, null, null, null));
+            boolean newIsSubset = this.isSubset;
+            if (forDataFrame && isSubset) {
+                newIsSubset = false;
+            }
+            updateRecursive = insert(UpdateArrayHelperNodeFactory.create(newIsSubset, null, null, null, null, null));
         }
-        return executeUpdate(frame, v, value, recLevel, operand, vector);
+        return updateRecursive.executeUpdate(frame, v, value, recLevel, operand, vector);
+    }
+
+    private Object updateRecursive(VirtualFrame frame, Object v, Object value, Object vector, Object operand, int recLevel) {
+        return updateRecursive(frame, v, value, vector, operand, recLevel, false);
     }
 
     private Object castComplex(VirtualFrame frame, Object operand) {
@@ -178,6 +193,17 @@ public abstract class UpdateArrayHelperNode extends RNode {
     }
 
     @Specialization
+    protected Object update(VirtualFrame frame, Object v, Object value, int recLevel, Object positions, RDataFrame vector) {
+        RVector inner = vector.getVector();
+        RVector res = (RVector) updateRecursive(frame, v, value, inner, positions, recLevel, true);
+        if (res != inner) {
+            return RDataFactory.createDataFrame(res);
+        } else {
+            return vector;
+        }
+    }
+
+    @Specialization(guards = "isSubset")
     protected Object update(VirtualFrame frame, Object v, RFactor value, int recLevel, Object positions, Object vector) {
         return updateRecursive(frame, v, value.getVector(), vector, positions, recLevel);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
index 3b2e1647c639918a561c3c1d97aafa85331bdc0f..ca31defef717cb4c7268e3c49f94a3b39e86a222 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
@@ -88,6 +88,28 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode {
         return specializeToUnaryOp().execute(frame, left);
     }
 
+    @Specialization
+    protected RLogicalVector doFactorOp(RFactor left, @SuppressWarnings("unused") RNull right) {
+        if (left.isOrdered()) {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_ORDERED_FACTORS, arithmetic.opName());
+
+        } else {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, arithmetic.opName());
+        }
+        return RDataFactory.createNAVector(left.getLength() == 0 ? 1 : left.getLength());
+    }
+
+    @Specialization
+    protected RLogicalVector doFactorOp(@SuppressWarnings("unused") RNull left, RFactor right) {
+        if (right.isOrdered()) {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_ORDERED_FACTORS, arithmetic.opName());
+
+        } else {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, arithmetic.opName());
+        }
+        return RDataFactory.createNAVector(right.getLength() == 0 ? 1 : right.getLength());
+    }
+
     @Specialization
     protected RDoubleVector doLeftNull(RNull left, RAbstractIntVector right) {
         return doRightNull(right, left);
@@ -103,6 +125,12 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode {
         return doRightNull(right, left);
     }
 
+    @SuppressWarnings("unused")
+    @Specialization(guards = "nonNumeric")
+    protected RComplexVector doLeftNull(RNull left, RAbstractVector right) {
+        throw RError.error(this.getSourceSection(), RError.Message.NON_NUMERIC_BINARY);
+    }
+
     @Specialization
     protected RComplexVector doLeftNull(RNull left, RAbstractComplexVector right) {
         return doRightNull(right, left);
@@ -132,31 +160,37 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode {
         return RDataFactory.createEmptyComplexVector();
     }
 
+    @SuppressWarnings("unused")
+    @Specialization(guards = "nonNumeric")
+    protected RComplexVector doRightNull(RAbstractVector left, RNull right) {
+        throw RError.error(this.getSourceSection(), RError.Message.NON_NUMERIC_BINARY);
+    }
+
     @SuppressWarnings("unused")
     @Specialization
     protected RDoubleVector doRightNull(RNull left, RNull right) {
         return RDataFactory.createEmptyDoubleVector();
     }
 
-    @Specialization
-    protected Object doLeftString(RAbstractStringVector left, Object right) {
+    @Specialization(guards = "!isFactorRight")
+    protected Object doLeftString(RAbstractStringVector left, RAbstractContainer right) {
         return doRightString(right, left);
     }
 
     @SuppressWarnings("unused")
-    @Specialization
-    protected Object doRightString(Object left, RAbstractStringVector right) {
+    @Specialization(guards = "!isFactorLeft")
+    protected Object doRightString(RAbstractContainer left, RAbstractStringVector right) {
         throw RError.error(this.getSourceSection(), RError.Message.NON_NUMERIC_BINARY);
     }
 
-    @Specialization
-    protected Object doLeftRaw(RAbstractRawVector left, Object right) {
+    @Specialization(guards = "!isFactorRight")
+    protected Object doLeftRaw(RAbstractRawVector left, RAbstractContainer right) {
         return doRightRaw(right, left);
     }
 
     @SuppressWarnings("unused")
-    @Specialization
-    protected Object doRightRaw(Object left, RAbstractRawVector right) {
+    @Specialization(guards = "!isFactorLeft")
+    protected Object doRightRaw(RAbstractContainer left, RAbstractRawVector right) {
         throw RError.error(this.getSourceSection(), RError.Message.NON_NUMERIC_BINARY);
     }
 
@@ -490,6 +524,50 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode {
         return performComplexVectorOpSameLength(left, right);
     }
 
+    // factors
+
+    @Specialization
+    protected RLogicalVector doFactorOp(RFactor left, RAbstractContainer right) {
+        if (left.isOrdered()) {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_ORDERED_FACTORS, arithmetic.opName());
+
+        } else {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, arithmetic.opName());
+        }
+        return RDataFactory.createNAVector(Math.max(left.getLength(), right.getLength()));
+    }
+
+    @Specialization
+    protected RLogicalVector doFactorOp(RAbstractContainer left, RFactor right) {
+        if (right.isOrdered()) {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_ORDERED_FACTORS, arithmetic.opName());
+
+        } else {
+            RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, arithmetic.opName());
+        }
+        return RDataFactory.createNAVector(Math.max(left.getLength(), right.getLength()));
+    }
+
+    protected boolean nonNumeric(@SuppressWarnings("unused") RNull left, RAbstractContainer right) {
+        return right.getElementClass() == RString.class || right.getElementClass() == RRaw.class;
+    }
+
+    protected boolean nonNumeric(RAbstractContainer left) {
+        return left.getElementClass() == RString.class || left.getElementClass() == RRaw.class;
+    }
+
+    protected boolean isFactorLeft(RAbstractContainer left) {
+        return left.getElementClass() == RFactor.class;
+    }
+
+    protected boolean isFactorRight(@SuppressWarnings("unused") RAbstractStringVector left, RAbstractContainer right) {
+        return right.getElementClass() == RFactor.class;
+    }
+
+    protected boolean isFactorRight(@SuppressWarnings("unused") RAbstractRawVector left, RAbstractContainer right) {
+        return right.getElementClass() == RFactor.class;
+    }
+
     // implementation
 
     private void copyAttributes(RVector ret, RAbstractVector left, RAbstractVector right) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
index d8c732f9d642aef5e1f54539446aa27a8299a6a0..40bec6926fa771ed92988b51ca2b2782a1a1ffd0 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.binary;
 
+import java.util.*;
+
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
@@ -293,12 +295,39 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
     // null
 
     @Specialization
-    protected RLogicalVector doNull(RNull left, Object right) {
+    protected RLogicalVector doNull(RNull left, RNull right) {
         return RDataFactory.createLogicalVector(0);
     }
 
-    @Specialization
-    protected RLogicalVector doNull(Object left, RNull right) {
+    @Specialization(guards = "!isFactor")
+    protected RLogicalVector doNull(RNull left, RAbstractContainer right) {
+        return RDataFactory.createLogicalVector(0);
+    }
+
+    @Specialization(guards = "!isFactor")
+    protected RLogicalVector doNull(RAbstractContainer left, RNull right) {
+        return RDataFactory.createLogicalVector(0);
+    }
+
+    @Specialization(guards = "!meaningfulOp")
+    protected RLogicalVector doFactorOpError(RFactor left, RNull right) {
+        RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
+        return RDataFactory.createNAVector(left.getLength() == 0 ? 1 : left.getLength());
+    }
+
+    @Specialization(guards = "!meaningfulOp")
+    protected RLogicalVector doFactorOpError(RNull left, RFactor right) {
+        RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
+        return RDataFactory.createNAVector(right.getLength() == 0 ? 1 : right.getLength());
+    }
+
+    @Specialization(guards = "meaningfulOp")
+    protected RLogicalVector doFactorOp(RFactor left, RNull right) {
+        return RDataFactory.createLogicalVector(0);
+    }
+
+    @Specialization(guards = "meaningfulOp")
+    protected RLogicalVector doFactorOp(RNull left, RFactor right) {
         return RDataFactory.createLogicalVector(0);
     }
 
@@ -703,72 +732,62 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
 
     // factor and scalar
 
-    @Specialization(guards = "!isEq")
-    protected RLogicalVector doFactorOp(RFactor left, Object right) {
-        throw RError.error(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
-    }
-
-    @Specialization(guards = "!isEq")
-    protected RLogicalVector doFactorOp(Object left, RFactor right) {
-        throw RError.error(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
-    }
-
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, int right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.intToString(right, false), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(int left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.intToString(left, false), true);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, double right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.doubleToString(right), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(double left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.doubleToString(left), true);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, byte right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.logicalToString(right), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(byte left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.logicalToString(left), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, String right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), right, false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(String left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), left, true);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, RComplex right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.complexToString(right), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RComplex left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.complexToString(left), true);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RFactor left, RRaw right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.rawToString(right), false);
     }
 
-    @Specialization(guards = "isEq")
+    @Specialization(guards = "meaningfulOp")
     protected RLogicalVector doFactorOp(RRaw left, RFactor right) {
         return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.rawToString(left), true);
     }
@@ -863,22 +882,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         return performStringVectorOpSameLength(left, RClosures.createIntToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doIntVectorDifferentLength(RAbstractIntVector left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createIntToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doIntVectorSameLength(RAbstractIntVector left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createIntToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doIntVectorDifferentLength(RFactor left, RAbstractIntVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createIntToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doIntVectorSameLength(RFactor left, RAbstractIntVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createIntToStringVector(right, rightNACheck));
     }
@@ -975,22 +994,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         return performStringVectorOpSameLength(left, RClosures.createDoubleToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doDoubleVectorDifferentLength(RAbstractDoubleVector left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createDoubleToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doDoubleVectorSameLength(RAbstractDoubleVector left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createDoubleToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doDoubleVectorDifferentLength(RFactor left, RAbstractDoubleVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createDoubleToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doDoubleVectorSameLength(RFactor left, RAbstractDoubleVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createDoubleToStringVector(right, rightNACheck));
     }
@@ -1067,22 +1086,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         return performStringVectorOpSameLength(left, RClosures.createLogicalToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doLogicalVectorDifferentLength(RAbstractLogicalVector left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createLogicalToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doLogicalVectorSameLength(RAbstractLogicalVector left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createLogicalToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doLogicalVectorDifferentLength(RFactor left, RAbstractLogicalVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createLogicalToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doLogicalVectorSameLength(RFactor left, RAbstractLogicalVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createLogicalToStringVector(right, rightNACheck));
     }
@@ -1139,22 +1158,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         return performStringVectorOpSameLength(left, right);
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RStringVector left, RFactor right) {
         return performStringVectorOpDifferentLength(left, RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RStringVector left, RFactor right) {
         return performStringVectorOpSameLength(left, RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RFactor left, RStringVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), right);
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RFactor left, RStringVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), right);
     }
@@ -1201,56 +1220,68 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
 
     // factor and vectors
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RFactor left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RFactor left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RFactor left, RAbstractComplexVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createComplexToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RFactor left, RAbstractComplexVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createComplexToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RAbstractComplexVector left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createComplexToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RAbstractComplexVector left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createComplexToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLength(RFactor left, RRawVector right) {
         return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createRawToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLength(RFactor left, RRawVector right) {
         return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createRawToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"!areSameLength", "isEq"})
+    @Specialization(guards = {"!areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorDifferentLengthRRawVector(RRawVector left, RFactor right) {
         return performStringVectorOpDifferentLength(RClosures.createRawToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
-    @Specialization(guards = {"areSameLength", "isEq"})
+    @Specialization(guards = {"areSameLength", "meaningfulOp"})
     protected RLogicalVector doStringVectorSameLengthRRawVector(RRawVector left, RFactor right) {
         return performStringVectorOpSameLength(RClosures.createRawToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck));
     }
 
+    @Specialization(guards = "!meaningfulOp")
+    protected RLogicalVector doFactorOp(RFactor left, RAbstractContainer right) {
+        RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
+        return RDataFactory.createNAVector(Math.max(left.getLength(), right.getLength()));
+    }
+
+    @Specialization(guards = "!meaningfulOp")
+    protected RLogicalVector doFactorOp(RAbstractContainer left, RFactor right) {
+        RError.warning(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName());
+        return RDataFactory.createNAVector(Math.max(left.getLength(), right.getLength()));
+    }
+
     // complex vector and vectors
 
     @Specialization(guards = "!areSameLength")
@@ -1338,16 +1369,48 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
 
     // guards
 
-    public boolean isEq(RFactor left, RFactor right) {
-        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual;
+    public boolean isFactor(RAbstractContainer left, RNull right) {
+        return left.getElementClass() == RFactor.class;
+    }
+
+    public boolean isFactor(RNull left, RAbstractContainer right) {
+        return right.getElementClass() == RFactor.class;
+    }
+
+    public boolean isFactor(RFactor left, RAbstractContainer right) {
+        return right.getElementClass() == RFactor.class;
+    }
+
+    public boolean isFactor(RAbstractContainer left, RFactor right) {
+        return left.getElementClass() == RFactor.class;
+    }
+
+    public boolean meaningfulOp(RFactor left, RFactor right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || (left.isOrdered() && right.isOrdered());
+    }
+
+    public boolean meaningfulOp(RFactor left, RNull right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || left.isOrdered();
+    }
+
+    public boolean meaningfulOp(RNull left, RFactor right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || right.isOrdered();
+    }
+
+    public boolean meaningfulOp(RFactor left, RAbstractContainer right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || left.isOrdered();
+    }
+
+    public boolean meaningfulOp(RAbstractContainer left, RFactor right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || right.isOrdered();
     }
 
-    public boolean isEq(RFactor left, Object right) {
-        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual;
+    public boolean meaningfulOp(RFactor left, Object right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || left.isOrdered();
     }
 
-    public boolean isEq(Object left, RFactor right) {
-        return !(logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual);
+    public boolean meaningfulOp(Object left, RFactor right) {
+        return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || right.isOrdered();
     }
 
     private boolean isVectorizedLogicalOp() {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
index facf67fe88f69062a1065ea7b445b25642c32762..20559f41ade8dd2f40dbcd1b560c14edfe926d29 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
@@ -31,6 +31,8 @@ public abstract class CastTypeNode extends BinaryNode {
     @Child private CastToVectorNode castToVectorNode;
     @Child private TypeofNode typeof;
 
+    @Child private CastTypeNode castRecursive;
+
     public abstract Object execute(VirtualFrame frame, Object value, RType type);
 
     @SuppressWarnings("unused")
@@ -94,6 +96,12 @@ public abstract class CastTypeNode extends BinaryNode {
         return null;
     }
 
+    @Specialization
+    protected Object doCastDataFrame(VirtualFrame frame, RDataFrame value, RType type) {
+        initCastRecursive();
+        return castRecursive.execute(frame, value.getVector(), type);
+    }
+
     @SuppressWarnings("unused")
     protected static boolean isString(RAbstractVector value, RType type) {
         return type == RType.Character;
@@ -190,4 +198,12 @@ public abstract class CastTypeNode extends BinaryNode {
             castListNode = insert(CastListNodeFactory.create(null, false, false, false));
         }
     }
+
+    private void initCastRecursive() {
+        if (castRecursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            castRecursive = insert(CastTypeNodeFactory.create(null, null));
+        }
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
index 85da4d65572fe1f9bc1bb4d86e7b07829df31916..4bb6e4b09dad0323ae6beefbe746292b09d66978 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
@@ -309,7 +309,7 @@ public class ArgumentMatcher {
             }
 
             // Search for argument name inside formal arguments
-            int fi = findParameterPosition(formalNames, suppliedNames[si], matchedFormalArgs, si, hasVarArgs, suppliedArgs[si], callSrc, argsSrc);
+            int fi = findParameterPosition(formalNames, suppliedNames[si], matchedFormalArgs, si, hasVarArgs, suppliedArgs[si], callSrc, argsSrc, varArgIndex);
             if (fi >= 0) {
                 resultArgs[fi] = suppliedArgs[si];
                 matchedSuppliedArgs.set(si);
@@ -497,12 +497,13 @@ public class ArgumentMatcher {
      * @param debugArgNode
      * @param callSrc
      * @param argsSrc
+     * @param varArgIndex
      *
      * @return The position of the given suppliedName inside the formalNames. Throws errors if the
      *         argument has been matched before
      */
     private static <T> int findParameterPosition(String[] formalNames, String suppliedName, BitSet matchedSuppliedArgs, int suppliedIndex, boolean hasVarArgs, T debugArgNode, SourceSection callSrc,
-                    SourceSection argsSrc) {
+                    SourceSection argsSrc, int varArgIndex) {
         int found = -1;
         for (int i = 0; i < formalNames.length; i++) {
             if (formalNames[i] == null) {
@@ -518,7 +519,8 @@ public class ArgumentMatcher {
                 }
                 matchedSuppliedArgs.set(found);
                 break;
-            } else if (!suppliedName.isEmpty() && formalName.startsWith(suppliedName)) {
+            } else if (!suppliedName.isEmpty() && formalName.startsWith(suppliedName) && ((varArgIndex != FormalArguments.NO_VARARG && i < varArgIndex) || varArgIndex == FormalArguments.NO_VARARG)) {
+                // partial-match only if the formal argument is positioned before ...
                 if (found >= 0) {
                     throw RError.error(argsSrc, RError.Message.ARGUMENT_MATCHES_MULTIPLE, 1 + suppliedIndex);
                 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchedCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchedCallNode.java
index 0607daa5d946784ed1aa1c723dfb0fbd9acc57ee..c3df06bafcf2058493a3bbc81fffd886cabef197 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchedCallNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchedCallNode.java
@@ -13,6 +13,7 @@ package com.oracle.truffle.r.nodes.function;
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.runtime.*;
@@ -49,6 +50,7 @@ public abstract class DispatchedCallNode extends RNode {
 
     public abstract Object executeInternal(VirtualFrame frame, RStringVector type, Object[] args);
 
+    @NodeInfo(cost = NodeCost.UNINITIALIZED)
     private static final class UninitializedDispatchedCallNode extends DispatchedCallNode {
         private final int depth;
         private final String genericName;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetMissingValueNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetMissingValueNode.java
index 276d56ed99d80120a4f0da05b06458cfc92800fd..a4f59b9f05ded0ab468a822ece4460f20445d512 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetMissingValueNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetMissingValueNode.java
@@ -24,19 +24,22 @@ package com.oracle.truffle.r.nodes.function;
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.r.nodes.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.r.nodes.access.*;
 
 /**
  * This is a node abstraction for the functionality defined in
  * {@link RMissingHelper#getMissingValue(Frame,Symbol)}.
  */
-public abstract class GetMissingValueNode extends RNode {
+public abstract class GetMissingValueNode extends Node {
 
     public static GetMissingValueNode create(Symbol sym) {
         return new UninitializedGetMissingValueNode(sym);
     }
 
+    public abstract Object execute(Frame frame);
+
+    @NodeInfo(cost = NodeCost.UNINITIALIZED)
     private static final class UninitializedGetMissingValueNode extends GetMissingValueNode {
 
         private final Symbol sym;
@@ -46,11 +49,10 @@ public abstract class GetMissingValueNode extends RNode {
         }
 
         @Override
-        public Object execute(VirtualFrame frame) {
+        public Object execute(Frame frame) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             FrameSlot slot = frame.getFrameDescriptor().findFrameSlot(sym.getName());
-            GetMissingValueNode gmvn = new ResolvedGetMissingValueNode(slot);
-            return replace(gmvn).execute(frame);
+            return replace(new ResolvedGetMissingValueNode(slot)).execute(frame);
         }
 
     }
@@ -64,7 +66,7 @@ public abstract class GetMissingValueNode extends RNode {
         }
 
         @Override
-        public Object execute(VirtualFrame frame) {
+        public Object execute(Frame frame) {
             if (slot == null) {
                 return null;
             }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
index 766b15a752c1a731dc85e24abf2aee9e48bf6d28..b108aa97e1a4b0408ac871b8da0b761373374038 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
@@ -74,13 +74,13 @@ import com.oracle.truffle.r.runtime.data.*;
  *  U = {@link UninitializedCallNode}: Forms the uninitialized end of the function PIC
  *  D = {@link DispatchedCallNode}: Function fixed, no varargs
  *  G = {@link GenericCallNode}: Function arbitrary, no varargs (generic case)
- * 
+ *
  *  UV = {@link UninitializedCallNode} with varargs,
  *  UVC = {@link UninitializedVarArgsCacheCallNode} with varargs, for varargs cache
  *  DV = {@link DispatchedVarArgsCallNode}: Function fixed, with cached varargs
  *  DGV = {@link DispatchedGenericVarArgsCallNode}: Function fixed, with arbitrary varargs (generic case)
  *  GV = {@link GenericVarArgsCallNode}: Function arbitrary, with arbitrary varargs (generic case)
- * 
+ *
  * (RB = {@link RBuiltinNode}: individual functions that are builtins are represented by this node
  * which is not aware of caching). Due to {@link CachedCallNode} (see below) this is transparent to
  * the cache and just behaves like a D/DGV)
@@ -93,11 +93,11 @@ import com.oracle.truffle.r.runtime.data.*;
  * non varargs, max depth:
  * |
  * D-D-D-U
- * 
+ *
  * no varargs, generic (if max depth is exceeded):
  * |
  * D-D-D-D-G
- * 
+ *
  * varargs:
  * |
  * DV-DV-UV         <- function call target identity level cache
@@ -105,7 +105,7 @@ import com.oracle.truffle.r.runtime.data.*;
  *    DV
  *    |
  *    UVC           <- varargs signature level cache
- * 
+ *
  * varargs, max varargs depth exceeded:
  * |
  * DV-DV-UV
@@ -117,7 +117,7 @@ import com.oracle.truffle.r.runtime.data.*;
  *    DV
  *    |
  *    DGV
- * 
+ *
  * varargs, max function depth exceeded:
  * |
  * DV-DV-DV-DV-GV
@@ -374,6 +374,7 @@ public abstract class RCallNode extends RNode {
      *
      * @see RCallNode
      */
+    @NodeInfo(cost = NodeCost.UNINITIALIZED)
     public static final class UninitializedCallNode extends RootCallNode {
 
         private final int depth;
@@ -544,6 +545,7 @@ public abstract class RCallNode extends RNode {
      *
      * @see RCallNode
      */
+    @NodeInfo(cost = NodeCost.UNINITIALIZED)
     public static final class UninitializedVarArgsCacheCallNode extends VarArgsCacheCallNode {
         @Child private CallArgumentsNode args;
         private int depth = 1;  // varargs cached is started with a [DV] DispatchedVarArgsCallNode
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RMissingHelper.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RMissingHelper.java
index 655fee04826b8ac6a488464abe2a5b5f652e20ea..84d79f708cc8fa6f78c32fde97ae370ebd6833e7 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RMissingHelper.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RMissingHelper.java
@@ -34,30 +34,6 @@ import com.oracle.truffle.r.runtime.data.RPromise.*;
  * would induce unnecessary dependencies otherwise.
  */
 public class RMissingHelper {
-    /**
-     * This function determines whether an arguments value - given as 'value' - is missing. An
-     * argument is missing when it has not been provided to the current function call (DEFAULTED or
-     * {@code value == RMissing.instance}, if argument has default value), OR if the value that has
-     * been provided once was a missing argument. (cp. R language definition and Internals 1.5.1
-     * Missingness).
-     *
-     * @param value The value that should be examined
-     * @return <code>true</code> iff this value is 'missing' in the definition of R
-     */
-    public static boolean isMissing(Object value, PromiseProfile promiseProfile) {
-        if (value == RMissing.instance) {
-            return true;
-        }
-
-        // This might be a promise...
-        if (value instanceof RPromise) {
-            RPromise promise = (RPromise) value;
-            if (promise.isDefault(promiseProfile) || isMissingSymbol(promise)) {
-                return true;
-            }
-        }
-        return false;
-    }
 
     /**
      * This method determines whether a given {@link Symbol} is missing in the given frame. This is
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
index 0a6857b8a718338e1c25ff723bde49040e66f110..10268ef185d1ae4d183080c91af702c3b47cf6a7 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
+import java.util.*;
+
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.*;
@@ -179,6 +181,18 @@ public abstract class CastLogicalNode extends CastNode {
         return missing;
     }
 
+    @Specialization
+    protected Object asLogical(VirtualFrame frame, RDataFrame dataFrame) {
+        return castLogicalRecursive(frame, dataFrame.getVector());
+    }
+
+    @Specialization
+    protected RLogicalVector asLogical(RFactor factor) {
+        byte[] data = new byte[factor.getLength()];
+        Arrays.fill(data, RRuntime.LOGICAL_NA);
+        return RDataFactory.createLogicalVector(data, RDataFactory.INCOMPLETE_VECTOR);
+    }
+
     @Fallback
     @TruffleBoundary
     public int doOther(Object operand) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RConnection.java
index 760444abf70eb99ff0857f3f95f4984de75518e5..5ca7160374ec866c2568f03c256f56a51631f99b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RConnection.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RConnection.java
@@ -123,10 +123,17 @@ public abstract class RConnection implements RClassHierarchy {
     }
 
     /**
-     * Return the underlying input stream (for internal use).
+     * Return the underlying input stream (for internal use). TODO Replace with a more principled
+     * solution.
      */
     public abstract InputStream getInputStream() throws IOException;
 
+    /**
+     * Return the underlying output stream (for internal use). TODO Replace with a more principled
+     * solution.
+     */
+    public abstract OutputStream getOutputStream() throws IOException;
+
     /**
      * Close the connection.
      */
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 81d268d5a291760d87055e89ec544852b701e580..f68e681012a1566a26c49a05059bac7370b4b49e 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
@@ -559,7 +559,8 @@ public final class RError extends RuntimeException {
         IS_NA_TO_NON_VECTOR("is.na() applied to non-(list or vector) of type '%s'"),
         NOT_MEANINGFUL_FOR_FACTORS("%s not meaningful for factors"),
         INPUTS_DIFFERENT_LENGTHS("inputs of different lengths"),
-        MATRIX_LIKE_REQUIRED("a matrix-like object is required as argument to '%s'");
+        MATRIX_LIKE_REQUIRED("a matrix-like object is required as argument to '%s'"),
+        NOT_MEANINGFUL_FOR_ORDERED_FACTORS("'%s' is not meaningful for ordered factors");
 
         public final String message;
         private final boolean hasArgs;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
index 69f26f12cc788fbc6fa1b76439f0831912e81247..38bebb8777999c0fcb84ac1162a8fb7898d9008b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
@@ -100,6 +100,8 @@ public class RRuntime {
     public static final String[] CLASS_INTEGER = new String[]{"integer", "numeric"};
     public static final String[] CLASS_DOUBLE = new String[]{"double", "numeric"};
 
+    public static final String CLASS_ORDERED = "ordered";
+
     public static final String WHICH = "which";
 
     public static final String WHAT = "what";
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 290652e0f5d82a2b221b04331195ec03646c1439..e2f49ac88dcbb020b042f773dd469427bde058a0 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
@@ -362,7 +362,7 @@ public class RSerialize {
                     } else if (tag.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
                         vec.setRowNames(car);
                     } else if (tag.equals(RRuntime.CLASS_ATTR_KEY)) {
-                        RVector.setClassAttr(vec, (RStringVector) car, null, null);
+                        result = RVector.setVectorClassAttr(vec, (RStringVector) car, null, null);
                     } else {
                         vec.setAttr(tag, car);
                     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
index 2746fdb5eac3fb98dfe9dfb6e213a7fddb7f1a2c..4b795f9d393c001b004791d4978f971340937459 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.data;
 
+import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.env.*;
 
 /**
@@ -46,7 +47,7 @@ public interface RAttributable {
 
     /**
      * Set the attribute {@code name} to {@code value}, overwriting any existing value. This is
-     * generic; a class may need to override this to handle certain attributes specially,
+     * generic; a class may need to override this to handle certain attributes specially.
      */
     default void setAttr(String name, Object value) {
         RAttributes attributes = getAttributes();
@@ -58,7 +59,7 @@ public interface RAttributable {
 
     /**
      * Remove the attribute {@code name}. No error if {@code name} is not an attribute. This is
-     * generic; a class may need to override this to handle certain attributes specially,
+     * generic; a class may need to override this to handle certain attributes specially.
      */
     default void removeAttr(String name) {
         RAttributes attributes = getAttributes();
@@ -66,4 +67,10 @@ public interface RAttributable {
             attributes.remove(name);
         }
     }
+
+    default RAttributable setClassAttr(RStringVector classAttr) {
+        setAttr(RRuntime.CLASS_ATTR_KEY, classAttr);
+        return this;
+    }
+
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
index d7ae5ec067ca56b881ee81d3ea2f997a20ae5a35..8c8f02ad26173dd8b5ff47c9e03392259e47dafc 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.runtime.data;
 
+import java.util.*;
+
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.RPromise.Closure;
@@ -176,6 +178,12 @@ public final class RDataFactory {
         return traceDataCreated(new RLogicalVector(data, complete, dims, names));
     }
 
+    public static RLogicalVector createNAVector(int length) {
+        byte[] data = new byte[length];
+        Arrays.fill(data, RRuntime.LOGICAL_NA);
+        return createLogicalVector(data, INCOMPLETE_VECTOR);
+    }
+
     public static RIntSequence createAscendingRange(int start, int end) {
         assert start <= end;
         return traceDataCreated(new RIntSequence(start, 1, end - start + 1));
@@ -304,8 +312,8 @@ public final class RDataFactory {
         return traceDataCreated(new RExpression(list));
     }
 
-    public static RFactor createFactor(RIntVector vector) {
-        return traceDataCreated(new RFactor(vector));
+    public static RFactor createFactor(RIntVector vector, boolean ordered) {
+        return traceDataCreated(new RFactor(vector, ordered));
     }
 
     public static RVector createObjectVector(Object[] data, boolean completeVector) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFrame.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFrame.java
index d008396f97af91560eecd38010df53bcf614e6a7..41d6acbfbe38c1d2413e27f4028c8e0964754098 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFrame.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFrame.java
@@ -71,6 +71,11 @@ public final class RDataFrame implements RShareable, RAbstractContainer {
         return vector.getAttributes();
     }
 
+    @Override
+    public boolean hasDimensions() {
+        return vector.hasDimensions();
+    }
+
     @Override
     public int[] getDimensions() {
         return vector.getDimensions();
@@ -137,4 +142,9 @@ public final class RDataFrame implements RShareable, RAbstractContainer {
         return vector.getElementIndexByNameInexact(name);
     }
 
+    @Override
+    public RAbstractContainer setClassAttr(RStringVector classAttr) {
+        return RVector.setVectorClassAttr(vector, classAttr, this, null);
+    }
+
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
index c4ee0a45e9aca3001bf58459af2b17f15d7044e7..0d3e58755205d0179cc655741041b146bf8fc826 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
@@ -52,6 +52,10 @@ public class RExpression implements RShareable, RAbstractContainer {
         return data.getLength();
     }
 
+    public boolean hasDimensions() {
+        return data.hasDimensions();
+    }
+
     public int[] getDimensions() {
         return data.getDimensions();
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java
index f58a701846c0a9f8696b6db0f1712476222caf6e..95330a9bb1f29368496be5893f746564e9f94bec 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java
@@ -28,14 +28,21 @@ public final class RFactor implements RShareable, RAbstractContainer {
 
     private RIntVector vector;
 
-    public RFactor(RIntVector vector) {
+    private final boolean ordered;
+
+    public RFactor(RIntVector vector, boolean ordered) {
         this.vector = vector;
+        this.ordered = ordered;
     }
 
     public RIntVector getVector() {
         return vector;
     }
 
+    public boolean isOrdered() {
+        return ordered;
+    }
+
     @Override
     public int getLength() {
         return vector.getLength();
@@ -63,7 +70,7 @@ public final class RFactor implements RShareable, RAbstractContainer {
 
     @Override
     public RFactor copy() {
-        return RDataFactory.createFactor((RIntVector) vector.copy());
+        return RDataFactory.createFactor((RIntVector) vector.copy(), ordered);
     }
 
     @Override
@@ -71,6 +78,11 @@ public final class RFactor implements RShareable, RAbstractContainer {
         return vector.getAttributes();
     }
 
+    @Override
+    public boolean hasDimensions() {
+        return vector.hasDimensions();
+    }
+
     @Override
     public int[] getDimensions() {
         return vector.getDimensions();
@@ -141,4 +153,9 @@ public final class RFactor implements RShareable, RAbstractContainer {
         vector.setLevels(newLevels);
     }
 
+    @Override
+    public RAbstractContainer setClassAttr(RStringVector classAttr) {
+        return RVector.setVectorClassAttr(vector, classAttr, null, this);
+    }
+
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
index b664d05590357305d8e9a9d024c0049e8f2c2b1b..6bf246f615e87d578df04b0b48e587602094c903 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
@@ -72,6 +72,11 @@ public class RLanguage extends RLanguageRep implements RAbstractContainer, RAttr
         return length;
     }
 
+    public boolean hasDimensions() {
+        // TODO
+        return false;
+    }
+
     public int[] getDimensions() {
         // TODO
         return null;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
index 6e5ac36178c796ac3ebbe05c84166da108627325..add5a33aafe4df22f7aaed9308fd343d29890df1 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
@@ -123,6 +123,10 @@ public class RPairList implements RAttributable, RAbstractContainer {
         return result;
     }
 
+    public boolean hasDimensions() {
+        return true;
+    }
+
     public int[] getDimensions() {
         return new int[]{1};
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
index f4a3e81da5c94fa07805b1fa1f5d3920c82baa19..50e8e7f91f8bbd6391aafc4ffa6a4c805809ccc2 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
@@ -180,7 +180,7 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
         } else if (name.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
             setRowNames(value);
         } else if (name.equals(RRuntime.CLASS_ATTR_KEY)) {
-            setClassAttr(this, (RStringVector) value, null, null);
+            throw Utils.nyi("The \"class\" attribute should be set using a separate method");
         } else {
             attributes.put(name, value);
         }
@@ -204,7 +204,7 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
             } else if (name.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
                 setRowNames(null);
             } else if (name.equals(RRuntime.CLASS_ATTR_KEY)) {
-                setClassAttr(this, (RStringVector) null, null, null);
+                throw Utils.nyi("The \"class\" attribute should be reset using a separate method");
             } else {
                 attributes.remove(name);
             }
@@ -369,11 +369,7 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
     }
 
     public final int[] getDimensions() {
-        if (hasDimensions()) {
-            return dimensions;
-        } else {
-            return null;
-        }
+        return dimensions;
     }
 
     public final void setDimensions(int[] newDimensions) {
@@ -400,17 +396,33 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
         }
     }
 
-    public static RAbstractContainer setClassAttr(RVector vector, RStringVector classAttr, RAbstractContainer enclosingDataFrame, RAbstractContainer enclosingFactor) {
+    @Override
+    public RAbstractContainer setClassAttr(RStringVector classAttr) {
+        return setClassAttrInternal(this, classAttr, null, null, true);
+    }
+
+    public static RAbstractContainer setVectorClassAttr(RVector vector, RStringVector classAttr, RAbstractContainer enclosingDataFrame, RAbstractContainer enclosingFactor) {
+        return setClassAttrInternal(vector, classAttr, enclosingDataFrame, enclosingFactor, false);
+    }
+
+    private static RAbstractContainer setClassAttrInternal(RVector vector, RStringVector classAttr, RAbstractContainer enclosingDataFrame, RAbstractContainer enclosingFactor, boolean convertToInt) {
         if (vector.attributes == null && classAttr != null && classAttr.getLength() != 0) {
             vector.initAttributes();
         }
         if (vector.attributes != null && (classAttr == null || classAttr.getLength() == 0)) {
             vector.removeAttributeMapping(RRuntime.CLASS_ATTR_KEY);
-            // class attribute removed - no longer a data frame (even if it was before)
+            // class attribute removed - no longer a data frame or factor (even if it was before)
             return vector;
         } else if (classAttr != null && classAttr.getLength() != 0) {
+            boolean ordered = false;
             for (int i = 0; i < classAttr.getLength(); i++) {
-                if (RType.DataFrame.getName().equals(classAttr.getDataAt(i))) {
+                String attr = classAttr.getDataAt(i);
+                if (RRuntime.CLASS_ORDERED.equals(attr)) {
+                    // "ordered" must be specified before "factor" - hence it's enough to do the
+                    // check only before encountering the "factor"
+                    ordered = true;
+                }
+                if (RType.DataFrame.getName().equals(attr)) {
                     vector.putAttribute(RRuntime.CLASS_ATTR_KEY, classAttr);
                     if (enclosingDataFrame != null) {
                         // was a frame and still is a frame
@@ -419,18 +431,31 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
                         // it's a data frame now
                         return RDataFactory.createDataFrame(vector);
                     }
-                } else if (RType.Factor.getName().equals(classAttr.getDataAt(i))) {
-                    if (vector.getElementClass() != RInt.class) {
-                        // TODO: add source section
-                        throw RError.error(null, RError.Message.ADDING_INVALID_CLASS, "factor");
-                    }
+                } else if (RType.Factor.getName().equals(attr)) {
                     vector.putAttribute(RRuntime.CLASS_ATTR_KEY, classAttr);
                     if (enclosingFactor != null) {
                         // was a factor and still is a factor
                         return enclosingFactor;
                     } else {
+                        RIntVector resVector;
+                        if (vector.getElementClass() != RInt.class) {
+                            if (vector.getElementClass() == RDouble.class && convertToInt) {
+                                RAbstractDoubleVector sourceVector = (RAbstractDoubleVector) vector;
+                                int[] data = new int[sourceVector.getLength()];
+                                for (int j = 0; j < data.length; j++) {
+                                    data[j] = RRuntime.double2int(sourceVector.getDataAt(j));
+                                }
+                                resVector = RDataFactory.createIntVector(data, sourceVector.isComplete());
+                                resVector.copyAttributesFrom(sourceVector);
+                            } else {
+                                // TODO: add source section
+                                throw RError.error(null, RError.Message.ADDING_INVALID_CLASS, "factor");
+                            }
+                        } else {
+                            resVector = (RIntVector) vector;
+                        }
                         // it's a factor now
-                        return RDataFactory.createFactor((RIntVector) vector);
+                        return RDataFactory.createFactor(resVector, ordered);
                     }
                 }
             }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java
index cb2c3ca812dd0859281f3f864c63d0e840635b0a..e437f164d4b32c3244ebaf65e0ed62e676d3ae35 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java
@@ -42,13 +42,24 @@ public class RFactorToStringVectorClosure extends RToStringVectorClosure impleme
         if (this.levels == null) {
             RError.warning(RError.Message.IS_NA_TO_NON_VECTOR, "NULL");
         }
+        naCheck.enable(this.vector);
     }
 
     public String getDataAt(int index) {
-        if (levels == null) {
+        if (levels == null || levels.getLength() == 0) {
             return RRuntime.STRING_NA;
         } else {
-            return this.levels.getDataAt(vector.getDataAt(index) - 1);
+            int val = vector.getDataAt(index);
+            if (naCheck.check(val)) {
+                return RRuntime.STRING_NA;
+            } else {
+                String l = levels.getDataAt(val - 1);
+                if (naCheck.check(l)) {
+                    return "NA"; // for comparison
+                } else {
+                    return l;
+                }
+            }
         }
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java
index 73dfc6e291dca2e4d5c4fd4d1128f050665789cb..8c304539330942f4470444bedf2281de9eb654b4 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java
@@ -28,6 +28,8 @@ public interface RAbstractContainer extends RAttributable, RClassHierarchy {
 
     int getLength();
 
+    boolean hasDimensions();
+
     int[] getDimensions();
 
     Class<?> getElementClass();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
index 1f7a32abe1f2513ef3e05c616dc5e8c7d9425a7e..bc37448c2807ca0676a435d9682e58efc4baffbd 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
@@ -136,6 +136,8 @@ public abstract class BinaryArithmetic extends Operation {
         return supportsIntResult;
     }
 
+    public abstract String opName();
+
     public abstract int op(int left, int right);
 
     public abstract double op(double left, double right);
@@ -178,6 +180,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(true, true, true);
         }
 
+        @Override
+        public String opName() {
+            return "+";
+        }
+
         @Override
         public int op(int left, int right) {
             try {
@@ -227,6 +234,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(false, false, true);
         }
 
+        @Override
+        public String opName() {
+            return "-";
+        }
+
         @Override
         public int op(int left, int right) {
             try {
@@ -275,6 +287,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(true, true, true);
         }
 
+        @Override
+        public String opName() {
+            return "*";
+        }
+
         @Override
         public int op(int left, int right) {
             try {
@@ -398,6 +415,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(false, false, false);
         }
 
+        @Override
+        public String opName() {
+            return "/";
+        }
+
         @Override
         public final int op(int left, int right) {
             throw RInternalError.shouldNotReachHere();
@@ -470,6 +492,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(false, false, true);
         }
 
+        @Override
+        public String opName() {
+            return "%/%";
+        }
+
         @Override
         public int op(int left, int right) {
             if (right != 0) {
@@ -510,6 +537,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(false, false, true);
         }
 
+        @Override
+        public String opName() {
+            return "%%";
+        }
+
         @Override
         public int op(int left, int right) {
             // LICENSE: transcribed code from GNU R, which is licensed under GPL
@@ -552,6 +584,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(false, false, false);
         }
 
+        @Override
+        public String opName() {
+            return "^";
+        }
+
         @Override
         public int op(int left, int right) {
             throw RInternalError.shouldNotReachHere();
@@ -951,6 +988,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(true, true, true);
         }
 
+        @Override
+        public String opName() {
+            throw Utils.nyi();
+        }
+
         @Override
         public int op(int left, int right) {
             return Math.max(left, right);
@@ -980,6 +1022,11 @@ public abstract class BinaryArithmetic extends Operation {
             super(true, true, true);
         }
 
+        @Override
+        public String opName() {
+            throw Utils.nyi();
+        }
+
         @Override
         public int op(int left, int right) {
             return Math.min(left, right);
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 7768931c5e2f2fa0464e9e404d1d71540c1663ed..7e79b7ee32e59954bd88e49ce5d201c40ccdfd05 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
@@ -8347,6 +8347,14 @@ x
 [1,] 10+0i -4+0i
 [2,] -2+0i  0+0i
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ as.logical(factor(c("a", "b", "a"))) }
+[1] NA NA NA
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ as.logical(factor(integer())) }
+logical(0)
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-c("1","2","3"); class(x)<-"factor"; x }
 Error in class(x) <- "factor" :
@@ -8357,6 +8365,28 @@ Error in class(x) <- "factor" :
 Error in class(x) <- "factor" :
   adding class "factor" to an invalid object
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-c(1L, 2L, 1L); class(x)<-c("factor", "ordered"); levels(x)<-c("a", "b"); x + "a" }
+[1] NA NA NA
+Warning message:
+In Ops.factor(x, "a") : + not meaningful for factors
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-c(1L, 2L, 1L); class(x)<-c("factor", "ordered"); levels(x)<-c("a", "b"); x > "a" }
+[1] NA NA NA
+Warning message:
+In Ops.factor(x, "a") : > not meaningful for factors
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-c(1L, 2L, 1L); class(x)<-c("ordered", "factor"); levels(x)<-c("a", "b"); x + "a" }
+[1] NA NA NA
+Warning message:
+In Ops.ordered(x, "a") : '+' is not meaningful for ordered factors
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-c(1L, 2L, 1L); class(x)<-c("ordered", "factor"); levels(x)<-c("a", "b"); x > "a" }
+[1] FALSE  TRUE FALSE
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-c(1L,2L,3L); class(x)<-"factor"; x }
 Error in print.factor(1:3) : replacement has length zero
@@ -8369,6 +8399,22 @@ NULL
 #{ x<-factor(c("a", "b", "a")); attr(x, "levels")<-character(); as.character(x) }
 [1] NA NA NA
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a")); is.atomic(x) }
+[1] TRUE
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a")); x + "a" }
+[1] NA NA NA
+Warning message:
+In Ops.factor(x, "a") : + not meaningful for factors
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a")); x + c("a", "b") }
+[1] NA NA NA
+Warning message:
+In Ops.factor(x, c("a", "b")) : + not meaningful for factors
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-factor(c("a", "b", "a")); x == "a" }
 [1]  TRUE FALSE  TRUE
@@ -8394,6 +8440,50 @@ In Ops.factor(x, "a") : > not meaningful for factors
 Warning message:
 In Ops.factor(x, c("a", "b")) : > not meaningful for factors
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a")); x[1] }
+[1] a
+Levels: a b
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a")); x[2] }
+[1] b
+Levels: a b
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a")); x[[1]] }
+[1] a
+Levels: a b
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a")); x[[2]] }
+[1] b
+Levels: a b
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a")); x[c(1,2)] }
+[1] a b
+Levels: a b
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a")); x[c(1,2,3,4)] }
+[1] a    b    a    <NA>
+Levels: a b
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a"), ordered=TRUE); is.atomic(x) }
+[1] TRUE
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a"), ordered=TRUE); x + "a" }
+[1] NA NA NA
+Warning message:
+In Ops.ordered(x, "a") : '+' is not meaningful for ordered factors
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("a", "b", "a"), ordered=TRUE); x > "a" }
+[1] FALSE  TRUE FALSE
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-factor(c("a", "b", "a", "c")); x == c("a", "b") }
 [1]  TRUE  TRUE  TRUE FALSE
@@ -8405,6 +8495,10 @@ Warning message:
 In y[1] <- x :
   number of items to replace is not a multiple of replacement length
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("c", "b", "a", "c")); y<-c(1); y[[1]]<-x; y }
+Error in y[[1]] <- x : more elements supplied than there are to replace
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{ x<-factor(c("c", "b", "a", "c")); y<-list(1); y[1]<-x; y }
 [[1]]
@@ -8414,6 +8508,52 @@ Warning message:
 In y[1] <- x :
   number of items to replace is not a multiple of replacement length
 
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-factor(c("c", "b", "a", "c")); y<-list(1); y[[1]]<-x; y }
+[[1]]
+[1] c b a c
+Levels: a b c
+
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(1,2,1), .Label=c("a", "b"), class = c('factor'), .Names=c("111","112","113")); y<-structure(c(1,2,1), .Label=c("a", "b"), class = c('factor'), .Names=c("111","112","113")); x+y }
+[1] NA NA NA
+Warning message:
+In Ops.factor(x, y) : + not meaningful for factors
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(1,2,1), .Label=c("a", "b"), class = c('factor'), .Names=c("111","112","113")); y<-structure(c(1,2,1), .Label=c("a", "b"), class = c('factor'), .Names=c("111","112","113")); x==y }
+[1] TRUE TRUE TRUE
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(1.1,2.2,1.1), .Label=c("a", "b"), class = c('factor')); attributes(x) }
+$levels
+[1] "a" "b"
+
+$class
+[1] "factor"
+
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(1.1,2.2,1.1), .Label=c("a", "b"), class = c('factor')); x }
+[1] a b a
+Levels: a b
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(1.2,2.2,1.1), .Label=c("a", "b"), class = c('factor')); x }
+[1] a b a
+Levels: a b
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(c(2.2,3.2,2.1), .Label=c("a", "b"), class = c('factor')); as.integer(x) }
+[1] 2 3 2
+
+##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
+#{ x<-structure(factor(c("a","b","c")), class=NULL); x }
+[1] 1 2 3
+attr(,"levels")
+[1] "a" "b" "c"
+
 ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor
 #{data = c(1,2,2,3,1,2,3,3,1,2,3,3,1);fdata<-factor(data);levels(fdata) = c('I','II','III');print(fdata);}
  [1] I   II  II  III I   II  III III I   II  III III I
@@ -16315,6 +16455,32 @@ $x
 [1] FALSE  TRUE  TRUE
 
 
+##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testMisc
+#{ n = c(2, 3, 5); s = c("aa", "bb", "cc"); df = data.frame(n, s); df[[1]] <- c(22,33,55); df }
+   n  s
+1 22 aa
+2 33 bb
+3 55 cc
+
+##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testMisc
+#{ y<-data.frame(7); as.logical(y) }
+[1] TRUE
+
+##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testMisc
+#{ y<-data.frame(c(1,2,3)); as.logical(y) }
+Error: (list) object cannot be coerced to type 'logical'
+
+##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testMisc
+#{ y<-data.frame(integer()); as.logical(y) }
+[1] NA
+
+##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testPrint
+#{ n = c(2, 3, 5); s = c(TRUE, FALSE, TRUE); df = data.frame(n, s); df }
+  n     s
+1 2  TRUE
+2 3 FALSE
+3 5  TRUE
+
 ##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testPrint
 #{ x<-c(1,2); class(x)<-"data.frame"; row.names(x)<-integer(); x }
 NULL
@@ -16332,6 +16498,13 @@ NULL
 1  7
 2 42
 
+##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testPrint
+#{ x<-data.frame(n=c("2", "3", "5"), s=c("TRUE", "FALSE", "TRUE"), check.names=FALSE, row.names=c("1", "2", "3")); x }
+  n     s
+1 2  TRUE
+2 3 FALSE
+3 5  TRUE
+
 ##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testPrint
 #{ x<-integer(); class(x)<-"data.frame"; x }
 data frame with 0 columns and 0 rows
@@ -17029,6 +17202,33 @@ Error in f(h = 1) : argument 1 matches multiple formal arguments
 #{ f <- function(hello, hi) { hello + hi } ; f(hello = 1, bye = 3) }
 Error in f(hello = 1, bye = 3) : unused argument (bye = 3)
 
+##com.oracle.truffle.r.test.simple.TestSimpleFunctions.testMatching
+#{ f<-function(..., val=1) { c(list(...), val) }; f(v=7, 2) }
+$v
+[1] 7
+
+[[2]]
+[1] 2
+
+[[3]]
+[1] 1
+
+
+##com.oracle.truffle.r.test.simple.TestSimpleFunctions.testMatching
+#{ f<-function(er=1, ..., val=1) { c(list(...), val, er) }; f(v=7, 2, e=8) }
+$v
+[1] 7
+
+[[2]]
+[1] 2
+
+[[3]]
+[1] 1
+
+[[4]]
+[1] 8
+
+
 ##com.oracle.truffle.r.test.simple.TestSimpleFunctions.testMatching
 #{ x<-function(foo,bar){foo*bar} ; x(f=10,2) }
 [1] 20
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java
index aa5c62f0f6c9f80729d29bf7413dbb9e8ac9f1a3..3546d4f0fb34d477391964a3af346ae9aed0c00e 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java
@@ -8158,6 +8158,101 @@ public class AllTests extends TestBase {
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\", \"c\")); x == c(\"a\", \"b\") }");
     }
 
+    @Test
+    public void TestSimpleBuiltins_testFactor_c6b2929aec56f236a9015269d6d5e6f0() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); x > \"a\" }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_e759d4fccb890277ccc9ddb8fcb0dec3() {
+        assertEval("{ x<-c(1L, 2L, 1L); class(x)<-c(\"ordered\", \"factor\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_9383599e2b32f549f5e46351c2e6bd9b() {
+        assertEval("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-list(1); y[[1]]<-x; y }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_ef37cc56e92b1c4a3742f47b97df2525() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[1] }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_e1467f269d5a2fed20d121b42b6669e7() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[[1]] }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_49d94f4cc6d874fdd626f78a760dd79e() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[2] }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_b1b8488bfeafbcf09b786073c66c0a31() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[[2]] }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_9c518bdf01e419e3635b3da6dd82b34a() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[c(1,2)] }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_1d1ee9908bd60f3714927a245349a33e() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[c(1,2,3,4)] }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_fdae08cc3544f4e5c971d2303a796eeb() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); is.atomic(x) }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_5302c7a50fda26503b5d1f681cec279c() {
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); is.atomic(x) }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_a8153cc5be539920818caa4f7d546190() {
+        assertEval("{ as.logical(factor(c(\"a\", \"b\", \"a\"))) }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_19ca5910d2b0103d936cfdd499387aa2() {
+        assertEval("{ as.logical(factor(integer())) }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_efa5f97d32564f78732db53e6862362e() {
+        assertEval("{ x<-structure(c(1.1,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); attributes(x) }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_d5fd844e772c2e96c1266f8c4e181e7a() {
+        assertEval("{ x<-structure(c(1.1,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); x }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_69974a637dd01d933a0274513b334646() {
+        assertEval("{ x<-structure(c(1.2,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); x }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_1d6da35b510c64fda496cd4d92b0b8dd() {
+        assertEval("{ x<-structure(c(2.2,3.2,2.1), .Label=c(\"a\", \"b\"), class = c('factor')); as.integer(x) }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_c97bd5071d6a70f07678a33414644e52() {
+        assertEval("{ x<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); y<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); x==y }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_a87228cb9283d7ba484ab0b60059e1bf() {
+        assertEval("{ x<-structure(factor(c(\"a\",\"b\",\"c\")), class=NULL); x }");
+    }
+
     @Test
     public void TestSimpleBuiltins_testFactor_2ef7de52def309425a9b70965111f004() {
         assertEvalError("{ x<-c(1,2,3); class(x)<-\"factor\"; x }");
@@ -8173,14 +8268,19 @@ public class AllTests extends TestBase {
         assertEvalError("{ x<-c(1L,2L,3L); class(x)<-\"factor\"; x }");
     }
 
+    @Test
+    public void TestSimpleBuiltins_testFactor_778d87ada7ac057126f8a27cfe882a81() {
+        assertEvalError("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-c(1); y[[1]]<-x; y }");
+    }
+
     @Test
     public void TestSimpleBuiltins_testFactor_8e866be378d6495f8d649996dcb5bb3c() {
-        assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > \"a\" }");
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x > \"a\" }");
     }
 
     @Test
-    public void TestSimpleBuiltins_testFactor_7cd2b27121f6c77b417a436d60108819() {
-        assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }");
+    public void TestSimpleBuiltins_testFactor_cab09968ee0783bc157730e05358ed0c() {
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x + \"a\" }");
     }
 
     @Test
@@ -8188,6 +8288,36 @@ public class AllTests extends TestBase {
         assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x == c(\"a\", \"b\") }");
     }
 
+    @Test
+    public void TestSimpleBuiltins_testFactor_7cd2b27121f6c77b417a436d60108819() {
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_a34678ac5082e00e15dd97ecd53f0e12() {
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x + c(\"a\", \"b\") }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_7b9d1da1c475fe180c3d19653a62003e() {
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); x + \"a\" }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_e1f4890b0e585468d589f92e64e8fe43() {
+        assertEvalWarning("{ x<-c(1L, 2L, 1L); class(x)<-c(\"factor\", \"ordered\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_442949c79222d476ad19ed8d25f6d67b() {
+        assertEvalWarning("{ x<-c(1L, 2L, 1L); class(x)<-c(\"ordered\", \"factor\"); levels(x)<-c(\"a\", \"b\"); x + \"a\" }");
+    }
+
+    @Test
+    public void TestSimpleBuiltins_testFactor_b998c6b80f80df4ef39a60ff889bc0e4() {
+        assertEvalWarning("{ x<-c(1L, 2L, 1L); class(x)<-c(\"factor\", \"ordered\"); levels(x)<-c(\"a\", \"b\"); x + \"a\" }");
+    }
+
     @Test
     public void TestSimpleBuiltins_testFactor_9b48b1721b63ffee900121993a15bb82() {
         assertEvalWarning("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-list(1); y[1]<-x; y }");
@@ -8198,6 +8328,11 @@ public class AllTests extends TestBase {
         assertEvalWarning("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-c(1); y[1]<-x; y }");
     }
 
+    @Test
+    public void TestSimpleBuiltins_testFactor_79abe62e1800fec0bdfb1ee89b43889b() {
+        assertEvalWarning("{ x<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); y<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); x+y }");
+    }
+
     @Test
     public void TestSimpleBuiltins_testFileListing_9646bfd3fb553824f1f54cc5d04b8219() {
         assertEval("{ list.files(\"test/r/simple/data/tree1\") }");
@@ -17128,6 +17263,26 @@ public class AllTests extends TestBase {
         assertEval("{ x <- c(1, 2, 3); xa <- as.data.frame(x); lapply(xa, function(x) x > 1) }");
     }
 
+    @Test
+    public void TestSimpleDataFrames_testMisc_19e026dd42148710ae11cdde5dc3b73e() {
+        assertEval("{ n = c(2, 3, 5); s = c(\"aa\", \"bb\", \"cc\"); df = data.frame(n, s); df[[1]] <- c(22,33,55); df }");
+    }
+
+    @Test
+    public void TestSimpleDataFrames_testMisc_e52a62b09e6557563b89aed7622a090f() {
+        assertEval("{ y<-data.frame(7); as.logical(y) }");
+    }
+
+    @Test
+    public void TestSimpleDataFrames_testMisc_41c31f4873ee11a67409c7646ea787b9() {
+        assertEval("{ y<-data.frame(integer()); as.logical(y) }");
+    }
+
+    @Test
+    public void TestSimpleDataFrames_testMisc_526983ed080a1f64591401d75eba5c80() {
+        assertEvalError("{ y<-data.frame(c(1,2,3)); as.logical(y) }");
+    }
+
     @Test
     public void TestSimpleDataFrames_testPrint_da9c92f6582f469a3303b14bf936c77e() {
         assertEval("{x<-c(1,2); class(x)<-\"data.frame\"; x}");
@@ -17153,6 +17308,16 @@ public class AllTests extends TestBase {
         assertEval("{ x<-c(7,42); y<-data.frame(x); y }");
     }
 
+    @Test
+    public void TestSimpleDataFrames_testPrint_674621fc7276825fddf39eadfa8b8e45() {
+        assertEval("{ n = c(2, 3, 5); s = c(TRUE, FALSE, TRUE); df = data.frame(n, s); df }");
+    }
+
+    @Test
+    public void TestSimpleDataFrames_testPrint_a7771c300d3a272d55b6385a70e8b9b5() {
+        assertEval("{ x<-data.frame(n=c(\"2\", \"3\", \"5\"), s=c(\"TRUE\", \"FALSE\", \"TRUE\"), check.names=FALSE, row.names=c(\"1\", \"2\", \"3\")); x }");
+    }
+
     @Test
     public void TestSimpleDataFrames_testRowNames_a3af62479ea621f4e185c40355da07ce() {
         assertEval("{ x<-c(1,2); row.names(x)<-NULL; attributes(x) }");
@@ -18023,6 +18188,16 @@ public class AllTests extends TestBase {
         assertEval("{ x<-function(foo,bar){foo*bar} ; x(fo=10, bar=2) }");
     }
 
+    @Test
+    public void TestSimpleFunctions_testMatching_3044cf7c3e46ee0ed1d82185d7fa28f8() {
+        assertEval("{ f<-function(..., val=1) { c(list(...), val) }; f(v=7, 2) }");
+    }
+
+    @Test
+    public void TestSimpleFunctions_testMatching_a44e5e17d1cee7de52a7be40ceccc694() {
+        assertEval("{ f<-function(er=1, ..., val=1) { c(list(...), val, er) }; f(v=7, 2, e=8) }");
+    }
+
     @Test
     public void TestSimpleFunctions_testMatching_7c113e0683905a2c65072aebc1cf14dc() {
         assertEvalError("{ f <- function(hello, hi) { hello + hi } ; f(h = 1) }");
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java
index 7b5a43f148d77d29f37939bee478b7a489524141..1a6704c9ddf422596c63afadf8cdc6d979e29557 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java
@@ -3902,14 +3902,49 @@ public class TestSimpleBuiltins extends TestBase {
         assertEvalError("{ x<-c(1L,2L,3L); class(x)<-\"factor\"; x }");
 
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x == \"a\" }");
-        assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > \"a\" }");
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x > \"a\" }");
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x + \"a\" }");
 
         assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x == c(\"a\", \"b\") }");
-        assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }");
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }");
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x + c(\"a\", \"b\") }");
         assertEval("{ x<-factor(c(\"a\", \"b\", \"a\", \"c\")); x == c(\"a\", \"b\") }");
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); x > \"a\" }");
+        assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); x + \"a\" }");
+
+        assertEval("{ x<-c(1L, 2L, 1L); class(x)<-c(\"ordered\", \"factor\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }");
+        assertEvalWarning("{ x<-c(1L, 2L, 1L); class(x)<-c(\"factor\", \"ordered\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }");
+        assertEvalWarning("{ x<-c(1L, 2L, 1L); class(x)<-c(\"ordered\", \"factor\"); levels(x)<-c(\"a\", \"b\"); x + \"a\" }");
+        assertEvalWarning("{ x<-c(1L, 2L, 1L); class(x)<-c(\"factor\", \"ordered\"); levels(x)<-c(\"a\", \"b\"); x + \"a\" }");
 
         assertEvalWarning("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-list(1); y[1]<-x; y }");
         assertEvalWarning("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-c(1); y[1]<-x; y }");
+        assertEval("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-list(1); y[[1]]<-x; y }");
+        assertEvalError("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-c(1); y[[1]]<-x; y }");
+
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[1] }");
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[[1]] }");
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[2] }");
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[[2]] }");
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[c(1,2)] }");
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[c(1,2,3,4)] }");
+
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); is.atomic(x) }");
+        assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); is.atomic(x) }");
+
+        assertEval("{ as.logical(factor(c(\"a\", \"b\", \"a\"))) }");
+        assertEval("{ as.logical(factor(integer())) }");
+
+        assertEval("{ x<-structure(c(1.1,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); attributes(x) }");
+        assertEval("{ x<-structure(c(1.1,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); x }");
+        assertEval("{ x<-structure(c(1.2,2.2,1.1), .Label=c(\"a\", \"b\"), class = c('factor')); x }");
+        assertEval("{ x<-structure(c(2.2,3.2,2.1), .Label=c(\"a\", \"b\"), class = c('factor')); as.integer(x) }");
+
+        assertEval("{ x<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); y<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); x==y }");
+        assertEvalWarning("{ x<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); y<-structure(c(1,2,1), .Label=c(\"a\", \"b\"), class = c('factor'), .Names=c(\"111\",\"112\",\"113\")); x+y }");
+
+        assertEval("{ x<-structure(factor(c(\"a\",\"b\",\"c\")), class=NULL); x }");
+
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java
index 2ec6c750bab29350b5bb620df8ff9112162ff9cd..feb33af1adae8cd05320fbf4f24dfeb522aa0237 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java
@@ -122,6 +122,8 @@ public class TestSimpleDataFrames extends TestBase {
 
         assertEval("{ x<-c(1,2); y<-data.frame(x); y }");
         assertEval("{ x<-c(7,42); y<-data.frame(x); y }");
+        assertEval("{ n = c(2, 3, 5); s = c(TRUE, FALSE, TRUE); df = data.frame(n, s); df }");
+        assertEval("{ x<-data.frame(n=c(\"2\", \"3\", \"5\"), s=c(\"TRUE\", \"FALSE\", \"TRUE\"), check.names=FALSE, row.names=c(\"1\", \"2\", \"3\")); x }");
     }
 
     @Test
@@ -135,4 +137,15 @@ public class TestSimpleDataFrames extends TestBase {
     public void testLapply() {
         assertEval("{ x <- c(1, 2, 3); xa <- as.data.frame(x); lapply(xa, function(x) x > 1) }");
     }
+
+    @Test
+    public void testMisc() {
+        assertEval("{ n = c(2, 3, 5); s = c(\"aa\", \"bb\", \"cc\"); df = data.frame(n, s); df[[1]] <- c(22,33,55); df }");
+
+        assertEval("{ y<-data.frame(7); as.logical(y) }");
+        assertEval("{ y<-data.frame(integer()); as.logical(y) }");
+        assertEvalError("{ y<-data.frame(c(1,2,3)); as.logical(y) }");
+
+    }
+
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleFunctions.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleFunctions.java
index b054e012279b9cbea86c91e3d9f510e3b93074dc..67de58daf94189c30512c12a33f8df7bd83dd95a 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleFunctions.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleFunctions.java
@@ -168,6 +168,10 @@ public class TestSimpleFunctions extends TestBase {
         assertEvalError("{ f <- function(hello, hi) { hello + hi } ; f(h = 1) }");
         assertEvalError("{ f <- function(hello, hi) { hello + hi } ; f(hello = 1, bye = 3) }");
         assertEvalError("{ f <- function(a) { a } ; f(1,2) }");
+
+        // with ... partial-match only if formal parameter are before ...
+        assertEval("{ f<-function(..., val=1) { c(list(...), val) }; f(v=7, 2) }");
+        assertEval("{ f<-function(er=1, ..., val=1) { c(list(...), val, er) }; f(v=7, 2, e=8) }");
     }
 
     @Test
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index ae129fa904741d4c8d7e26e63c07b3cc4456613a..6ac47a08e131939ad2457537ccd4b71f1dce69da 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -67,7 +67,8 @@ com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/stats/
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/stats/Rnorm.java,gnu_r.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/stats/StatsUtil.java,gnu_r_statsutil.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/CountFields.java,gnu_r.copyright
-com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/UtilsPackage.java,purdue.copyright
+com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/CountFields.java,gnu_r.copyright
+com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/WriteTable.java,gnu_r.copyright
 com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParseException.java,purdue.copyright
 com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParseUtil.java,purdue.copyright
 com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g,purdue.copyright