From cefea8cc24ce145cb94c6537430c0304ae32bb6b Mon Sep 17 00:00:00 2001
From: stepan <stepan.sindelar@oracle.com>
Date: Mon, 11 Sep 2017 15:56:42 +0200
Subject: [PATCH] NFI based Parse.c implementation

---
 .../ffi/impl/common/JavaUpCallsRFFIImpl.java  | 28 ++++++++---
 .../r/ffi/impl/common/ParseResult.java        | 46 -------------------
 .../fficall/src/common/rffi_upcalls.h         |  2 +
 .../fficall/src/truffle_common/Parse.c        | 26 ++---------
 .../packages/testrffi/testrffi/R/testrffi.R   |  4 ++
 .../packages/testrffi/testrffi/src/init.c     |  1 +
 .../packages/testrffi/testrffi/src/testrffi.c | 14 +++++-
 .../packages/testrffi/testrffi/src/testrffi.h |  2 +
 .../testrffi/testrffi/tests/simpleTests.R     |  4 ++
 9 files changed, 52 insertions(+), 75 deletions(-)
 delete mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/ParseResult.java

diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
index ebb04b5f27..9c843d17e4 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
@@ -44,7 +44,6 @@ import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.ffi.impl.common.ParseResult.ParseStatus;
 import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
@@ -66,6 +65,7 @@ import com.oracle.truffle.r.runtime.conn.ConnectionSupport.BaseRConnection;
 import com.oracle.truffle.r.runtime.conn.ConnectionSupport.InvalidConnection;
 import com.oracle.truffle.r.runtime.conn.NativeConnections.NativeRConnection;
 import com.oracle.truffle.r.runtime.conn.RConnection;
+import com.oracle.truffle.r.runtime.context.Engine.IncompleteSourceException;
 import com.oracle.truffle.r.runtime.context.Engine.ParseException;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.CharSXPWrapper;
@@ -1058,22 +1058,36 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
         return p.isEvaluated() ? p.getValue() : RUnboundValue.instance;
     }
 
+    private enum ParseStatus {
+        PARSE_NULL,
+        PARSE_OK,
+        PARSE_INCOMPLETE,
+        PARSE_ERROR,
+        PARSE_EOF
+    }
+
     @Override
     public Object R_ParseVector(Object text, int n, Object srcFile) {
-        // TODO general case
-        assert n == 1;
-        assert srcFile == RNull.instance;
+        // TODO general case + all statuses
+        assert n == 1 : "unsupported: R_ParseVector with n != 0.";
+        assert srcFile == RNull.instance : "unsupported: R_ParseVector with non-null srcFile argument.";
         String textString = RRuntime.asString(text);
         assert textString != null;
 
+        Object[] resultData = new Object[2];
         try {
             Source source = RSource.fromTextInternal(textString, RSource.Internal.R_PARSEVECTOR);
             RExpression exprs = RContext.getEngine().parse(source);
-            return new ParseResult(ParseStatus.PARSE_OK.ordinal(), exprs);
+            resultData[0] = RDataFactory.createIntVectorFromScalar(ParseStatus.PARSE_OK.ordinal());
+            resultData[1] = exprs;
+        } catch (IncompleteSourceException ex) {
+            resultData[0] = RDataFactory.createIntVectorFromScalar(ParseStatus.PARSE_INCOMPLETE.ordinal());
+            resultData[1] = RNull.instance;
         } catch (ParseException ex) {
-            // TODO incomplete
-            return new ParseResult(ParseStatus.PARSE_ERROR.ordinal(), RNull.instance);
+            resultData[0] = RDataFactory.createIntVectorFromScalar(ParseStatus.PARSE_ERROR.ordinal());
+            resultData[1] = RNull.instance;
         }
+        return RDataFactory.createList(resultData);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/ParseResult.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/ParseResult.java
deleted file mode 100644
index 58cf577ae8..0000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/ParseResult.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * 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.ffi.impl.common;
-
-import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;
-
-/**
- * Used in implementation of {@link UpCallsRFFI#R_ParseVector(Object, int, Object)}.
- */
-public class ParseResult {
-    public enum ParseStatus {
-        PARSE_NULL,
-        PARSE_OK,
-        PARSE_INCOMPLETE,
-        PARSE_ERROR,
-        PARSE_EOF
-    }
-
-    @SuppressWarnings("unused") private final int parseStatus;
-    @SuppressWarnings("unused") private final Object expr;
-
-    ParseResult(int parseStatus, Object expr) {
-        this.parseStatus = parseStatus;
-        this.expr = expr;
-    }
-}
diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
index 3e7d642615..9c61534e99 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
+++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
@@ -278,6 +278,8 @@ typedef double (*call_Rf_runif)(double x, double y);
 
 typedef SEXP (*call_getvar)();
 
+typedef SEXP (*call_R_ParseVector)(SEXP text, int n, SEXP srcFile);
+
 // connections
 
 typedef int (*call_FASTR_getConnectionChar)(SEXP connection);
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/Parse.c b/com.oracle.truffle.r.native/fficall/src/truffle_common/Parse.c
index 41aabde10d..f23500e579 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/Parse.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/Parse.c
@@ -21,29 +21,13 @@
  * questions.
  */
 
+#include "../truffle_nfi/rffiutils.h"
+#include "rffi_upcalls.h"
 
-#if FALSE
-
-#include <rffiutils.h>
 #include <R_ext/Parse.h>
 
-static jmethodID parseMethodID;
-static jclass parseResultClass;
-static jfieldID parseStatusFieldID;
-static jfieldID parseExprFieldID;
-
-
-void init_parse(JNIEnv *env) {
-	parseMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_ParseVector", "(Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;", 0);
-	parseResultClass = checkFindClass(env, "com/oracle/truffle/r/ffi/impl/common/ParseResult");
-	parseStatusFieldID = checkGetFieldID(env, parseResultClass, "parseStatus", "I", 0);
-	parseExprFieldID = checkGetFieldID(env, parseResultClass, "expr", "Ljava/lang/Object;", 0);
-}
-
 SEXP R_ParseVector(SEXP text, int n, ParseStatus *z, SEXP srcfile) {
-	JNIEnv *env = getEnv();
-	jobject result = (*env)->CallObjectMethod(env, UpCallsRFFIObject, parseMethodID, text, n, srcfile);
-	*z = (*env)->GetIntField(env, result, parseStatusFieldID);
-    return (*env)->GetObjectField(env, result, parseExprFieldID);
+    SEXP resultList = ((call_R_ParseVector)callbacks[R_ParseVector_x])(text, n, srcfile);
+    *z = Rf_asInteger(VECTOR_ELT(resultList, 0));
+    return VECTOR_ELT(resultList, 1);
 }
-#endif
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
index 90b45a76cf..62ed8ab623 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
@@ -187,4 +187,8 @@ rffi.readConnection <- function(connection) {
 
 rffi.createNativeConnection <- function() {
     .Call('test_createNativeConnection');
+}
+
+rffi.parseVector <- function(x) {
+    .Call('test_ParseVector', x);
 }
\ No newline at end of file
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
index ba9eb2458c..9daac422f9 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
@@ -80,6 +80,7 @@ static const R_CallMethodDef CallEntries[] = {
         CALLDEF(test_writeConnection, 1),
         CALLDEF(test_readConnection, 1),
         CALLDEF(test_createNativeConnection, 0),
+        CALLDEF(test_ParseVector, 1),
         {NULL, NULL, 0}
 };
 
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
index 92287d4ab1..4c6ff95296 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
 #include <Rinternals.h>
 #include <Rinterface.h>
 #include <R_ext/Connections.h>
+#include <R_ext/Parse.h>
 #include <string.h>
 #include "testrffi.h"
 
@@ -521,3 +522,14 @@ SEXP test_createNativeConnection() {
     // customConn->read = &testrfficonn_read; TODO: read test
     return newConnSEXP;
 }
+
+SEXP test_ParseVector(SEXP src) {
+    ParseStatus status;
+    SEXP parseResult, result;
+    PROTECT(parseResult = R_ParseVector(src, 1, &status, R_NilValue));
+    PROTECT(result = allocVector(VECSXP, 2));
+    SET_VECTOR_ELT(result, 0, ScalarInteger(status));
+    SET_VECTOR_ELT(result, 1, parseResult);
+    UNPROTECT(2);
+    return result;
+}
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h
index 21f9e40baf..7ff8cb06fd 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h
@@ -103,3 +103,5 @@ extern SEXP test_writeConnection(SEXP conn);
 extern SEXP test_readConnection(SEXP conn);
 
 extern SEXP test_createNativeConnection(void);
+
+extern SEXP test_ParseVector(SEXP src);
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R
index 3a8138ae62..9a19441a3d 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R
@@ -76,3 +76,7 @@ rffi.inlined_length(expr[[1]])
 #
 # foo <-function(...) rffi.inlined_length(get('...'))
 # foo(a = 1, b = 2, c = 3, d = 42)
+
+rffi.parseVector('1+2')
+rffi.parseVector('.*/-')
+rffi.parseVector('1+')
\ No newline at end of file
-- 
GitLab