Pārlūkot izejas kodu

HPCC-21224 Compile-time syntax check for R plugin

Also fixes a lurking bug in the demangler used when constant-folding external
functions.

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 6 gadi atpakaļ
vecāks
revīzija
8ebe6fd4a5

+ 8 - 6
ecl/hql/hqlutil.cpp

@@ -8187,8 +8187,10 @@ public:
         StringBuffer namespaceValue;
         StringBuffer namespaceValue;
         getAttribute(body, namespaceAtom, namespaceValue);
         getAttribute(body, namespaceAtom, namespaceValue);
         if (namespaceValue.length())
         if (namespaceValue.length())
-            mangled.append("N").append(namespaceValue.length()).append(lookupRepeat(namespaceValue));
-
+        {
+            VStringBuffer nsName("%d%s", namespaceValue.length(), namespaceValue.str());
+            mangled.append("N").append(lookupRepeat(nsName));
+        }
         mangled.append(entrypoint.length()).append(entrypoint);
         mangled.append(entrypoint.length()).append(entrypoint);
         if (namespaceValue.length())
         if (namespaceValue.length())
             mangled.append("E");
             mangled.append("E");
@@ -8198,13 +8200,13 @@ public:
         mangleFunctionReturnType(mangledReturn, mangledReturnParameters, retType);
         mangleFunctionReturnType(mangledReturn, mangledReturnParameters, retType);
 
 
         if (functionBodyUsesContext(body))
         if (functionBodyUsesContext(body))
-            mangled.append("P12ICodeContext");
+            mangled.append(lookupRepeat("P12ICodeContext"));
         else if (body->hasAttribute(globalContextAtom) )
         else if (body->hasAttribute(globalContextAtom) )
-            mangled.append("P18IGlobalCodeContext");
+            mangled.append(lookupRepeat("P18IGlobalCodeContext"));
         else if (body->hasAttribute(userMatchFunctionAtom))
         else if (body->hasAttribute(userMatchFunctionAtom))
-            mangled.append("P12IMatchWalker");
+            mangled.append(lookupRepeat("P12IMatchWalker"));
         if (functionBodyIsActivity(body))
         if (functionBodyIsActivity(body))
-            mangled.append("P20IThorActivityContext");
+            mangled.append(lookupRepeat("P20IThorActivityContext"));
 
 
         mangled.append(mangledReturnParameters);
         mangled.append(mangledReturnParameters);
 
 

+ 7 - 0
ecl/regress/checkR.ecl

@@ -0,0 +1,7 @@
+IMPORT R;
+
+integer testError(integer val) := EMBED(R)
+  print val
+ENDEMBED;
+
+testError(10)

+ 2 - 0
plugins/Rembed/R.ecllib

@@ -17,9 +17,11 @@
 
 
 EXPORT Language := SERVICE : plugin('Rembed')
 EXPORT Language := SERVICE : plugin('Rembed')
   boolean getEmbedContext():cpp,pure,namespace='Rembed',entrypoint='getEmbedContext',prototype='IEmbedContext* getEmbedContext()';
   boolean getEmbedContext():cpp,pure,namespace='Rembed',entrypoint='getEmbedContext',prototype='IEmbedContext* getEmbedContext()';
+  STRING syntaxCheck(const varstring funcname, UTF8 body, const varstring argnames, const varstring compileOptions, const varstring persistOptions):cpp,pure,namespace='Rembed',entrypoint='syntaxCheck',fold;
   unload():cpp,pure,namespace='Rembed',entrypoint='unload';
   unload():cpp,pure,namespace='Rembed',entrypoint='unload';
 END;
 END;
 
 
 EXPORT getEmbedContext := Language.getEmbedContext;
 EXPORT getEmbedContext := Language.getEmbedContext;
+EXPORT syntaxCheck := Language.syntaxCheck;
 EXPORT boolean supportsImport := false;
 EXPORT boolean supportsImport := false;
 EXPORT boolean supportsScript := true;
 EXPORT boolean supportsScript := true;

+ 17 - 2
plugins/Rembed/Rembed.cpp

@@ -1396,9 +1396,24 @@ extern DECL_EXPORT IEmbedContext* getEmbedContext()
     return new REmbedContext;
     return new REmbedContext;
 }
 }
 
 
-extern DECL_EXPORT bool syntaxCheck(const char *script)
+extern DECL_EXPORT void syntaxCheck(size32_t & __lenResult, char * & __result, const char *funcname, size32_t charsBody, const char * body, const char *argNames, const char *compilerOptions, const char *persistOptions)
 {
 {
-    return true; // MORE
+    StringBuffer result;
+    try
+    {
+        Owned<REmbedFunctionContext> ctx =  new REmbedFunctionContext(*queryGlobalState()->R);
+        // MORE - could check supplied persistOptions are valid
+        StringBuffer text;
+        text.append(rtlUtf8Size(charsBody, body), body);
+        text.stripChar('\r');
+        Rcpp::ExpressionVector exp(text);
+    }
+    catch (std::exception &E)
+    {
+        result.append("Rembed: Parse error from R while checking embedded code"); // Unfortunately we don't get any info about the error position or nature, just "Parse error."
+    }
+    __lenResult = result.length();
+    __result = result.detach();
 }
 }
 
 
 } // namespace
 } // namespace