From e2fe2b10edbb9496b47dcc192f1dd4180c1d3c73 Mon Sep 17 00:00:00 2001
From: Lukas Stadler <lukas.stadler@oracle.com>
Date: Thu, 22 Mar 2018 18:35:54 +0100
Subject: [PATCH] allow coercion to LISTSXP/LANGSXP from native API

---
 .../truffle/r/ffi/impl/nodes/CoerceNodes.java | 59 +++++++++++--------
 1 file changed, 35 insertions(+), 24 deletions(-)

diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java
index 83d2bc03c1..a42c04d175 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java
@@ -58,39 +58,51 @@ import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 
 public final class CoerceNodes {
 
-    public abstract static class VectorToPairListNode extends FFIUpCallNode.Arg1 {
+    public static final class VectorToPairListNode extends FFIUpCallNode.Arg1 {
 
-        @Child private CopyOfRegAttributesNode copyRegAttributesNode;
-        @Child private GetNamesAttributeNode getNamesAttributeNode;
+        @Child private CastPairListNode cast = CastPairListNode.create(SEXPTYPE.LISTSXP);
+
+        @Override
+        public Object executeObject(Object value) {
+            return cast.doCast(value);
+        }
+
+        public static VectorToPairListNode create() {
+            return new VectorToPairListNode();
+        }
+    }
+
+    public abstract static class CastPairListNode extends CastNode {
+
+        private final SEXPTYPE type;
+
+        @Child private CopyOfRegAttributesNode copyRegAttributesNode = CopyOfRegAttributesNode.create();
+        @Child private GetNamesAttributeNode getNamesAttributeNode = GetNamesAttributeNode.create();
+
+        protected CastPairListNode(SEXPTYPE type) {
+            this.type = type;
+        }
 
         @Specialization
         protected Object convert(RAbstractVector v) {
-
             RStringVector names = getNamesAttributeNode.getNames(v);
             SEXPTYPE gnurType = SEXPTYPE.gnuRTypeForObject(v);
 
-            RPairList head = null;
-            RPairList prev = null;
+            Object current = RNull.instance;
             assert names == null || names.getLength() == v.getLength();
-            for (int i = 0; i < v.getLength(); i++) {
+            for (int i = v.getLength() - 1; i >= 0; i--) {
                 Object element = v.getDataAtAsObject(i);
                 adjustSharing(v, element);
-                RPairList cur = RDataFactory.createPairList(element, RNull.instance, names != null ? RDataFactory.createSymbol(names.getDataAt(i)) : RNull.instance, gnurType);
-
-                if (prev == null) {
-                    assert head == null;
-                    head = cur;
-                } else {
-                    prev.setCdr(cur);
-                }
-                prev = cur;
+                current = RDataFactory.createPairList(element, current, names != null ? RDataFactory.createSymbol(names.getDataAt(i)) : RNull.instance, gnurType);
             }
-            if (head != null) {
+            if (current != RNull.instance) {
                 // also copy regular attributes
-                copyRegAttributesNode.execute(v, head);
-                return head;
+                RPairList pl = (RPairList) current;
+                copyRegAttributesNode.execute(v, pl);
+                pl.setType(type);
+                pl.allowClosure();
             }
-            return RNull.instance;
+            return current;
         }
 
         private static void adjustSharing(RAbstractVector origin, Object element) {
@@ -110,8 +122,8 @@ public final class CoerceNodes {
             }
         }
 
-        public static VectorToPairListNode create() {
-            return CoerceNodesFactory.VectorToPairListNodeGen.create();
+        public static CastPairListNode create(SEXPTYPE type) {
+            return CoerceNodesFactory.CastPairListNodeGen.create(type);
         }
 
         private static int getSharingLevel(RShareable r) {
@@ -234,9 +246,8 @@ public final class CoerceNodes {
                 case NILSXP:
                     return new CastNullNode();
                 case LISTSXP:
-                    throw RInternalError.unimplemented("Rf_coerceVector unimplemented for PairLists.");
                 case LANGSXP:
-                    throw RInternalError.unimplemented("Rf_coerceVector unimplemented for RPairList.");
+                    return CastPairListNode.create(type);
                 case ENVSXP:
                     return new EnvironmentCast();
                 case VECSXP:
-- 
GitLab