Repository: systemml
Updated Branches:
  refs/heads/master e2875cae4 -> c250adab3


[SYSTEMML-2315] JMLC API extensions for passing multiple dml scripts

This patch extends the JMLC API for multiple dml scripts. Specifically,
we now allow scripts with import (i.e., source) statements where all
additional scripts are handed over in memory to avoid invalid relative
file lookups (because most JMLC applications load there scripts from
resource streams). Furthermore, this includes a major refactoring of the
handling of dml/pydml imports to avoid unnecessary redundancy.


Project: http://git-wip-us.apache.org/repos/asf/systemml/repo
Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/c250adab
Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/c250adab
Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/c250adab

Branch: refs/heads/master
Commit: c250adab3ee17aa767fbe8af966ec8cabe9ba797
Parents: e2875ca
Author: Matthias Boehm <mboe...@gmail.com>
Authored: Fri May 11 15:54:07 2018 -0700
Committer: Matthias Boehm <mboe...@gmail.com>
Committed: Fri May 11 15:54:07 2018 -0700

----------------------------------------------------------------------
 .../org/apache/sysml/api/jmlc/Connection.java   | 22 ++++-
 .../org/apache/sysml/parser/ParserFactory.java  | 18 ++--
 .../parser/common/CommonSyntacticValidator.java | 64 +++++++++++--
 .../sysml/parser/common/StatementInfo.java      |  2 -
 .../sysml/parser/dml/DmlSyntacticValidator.java | 64 +++----------
 .../parser/pydml/PydmlSyntacticValidator.java   | 60 +++---------
 .../sysml/runtime/util/UtilFunctions.java       |  6 +-
 .../functions/jmlc/NamespaceFunctionTest.java   | 99 ++++++++++++++++++++
 src/test/scripts/functions/jmlc/bar1.dml        | 27 ++++++
 src/test/scripts/functions/jmlc/bar2.dml        | 29 ++++++
 src/test/scripts/functions/jmlc/foo.dml         | 30 ++++++
 .../functions/jmlc/ZPackageSuite.java           |  1 +
 12 files changed, 302 insertions(+), 120 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/main/java/org/apache/sysml/api/jmlc/Connection.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/api/jmlc/Connection.java 
b/src/main/java/org/apache/sysml/api/jmlc/Connection.java
index 8684e72..7eb262f 100644
--- a/src/main/java/org/apache/sysml/api/jmlc/Connection.java
+++ b/src/main/java/org/apache/sysml/api/jmlc/Connection.java
@@ -26,7 +26,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.Arrays;
-import java.util.HashMap;
+import java.util.Collections;
 import java.util.Map;
 
 import org.apache.hadoop.fs.FileSystem;
@@ -201,7 +201,7 @@ public class Connection implements Closeable
         * @return PreparedScript object representing the precompiled script
         */
        public PreparedScript prepareScript( String script, String[] inputs, 
String[] outputs, boolean parsePyDML) {
-               return prepareScript(script, new HashMap<String,String>(), 
inputs, outputs, parsePyDML);
+               return prepareScript(script, Collections.emptyMap(), inputs, 
outputs, parsePyDML);
        }
        
        /**
@@ -215,6 +215,21 @@ public class Connection implements Closeable
         * @return PreparedScript object representing the precompiled script
         */
        public PreparedScript prepareScript( String script, Map<String, String> 
args, String[] inputs, String[] outputs, boolean parsePyDML) {
+               return prepareScript(script, Collections.emptyMap(), args, 
inputs, outputs, parsePyDML);
+       }
+       
+       /**
+        * Prepares (precompiles) a script, sets input parameter values, and 
registers input and output variables.
+        * 
+        * @param script string representing of the DML or PyDML script
+        * @param nsscript map (name, script) of the DML or PyDML namespace 
scripts
+        * @param args map of input parameters ($) and their values
+        * @param inputs string array of input variables to register
+        * @param outputs string array of output variables to register
+        * @param parsePyDML {@code true} if PyDML, {@code false} if DML
+        * @return PreparedScript object representing the precompiled script
+        */
+       public PreparedScript prepareScript(String script, Map<String,String> 
nsscripts, Map<String, String> args, String[] inputs, String[] outputs, boolean 
parsePyDML) {
                DMLScript.SCRIPT_TYPE = parsePyDML ? ScriptType.PYDML : 
ScriptType.DML;
                
                //check for valid names of passed arguments
@@ -235,7 +250,8 @@ public class Connection implements Closeable
                Program rtprog = null;
                try {
                        //parsing
-                       ParserWrapper parser = 
ParserFactory.createParser(parsePyDML ? ScriptType.PYDML : ScriptType.DML);
+                       ParserWrapper parser = ParserFactory.createParser(
+                               parsePyDML ? ScriptType.PYDML : ScriptType.DML, 
nsscripts);
                        DMLProgram prog = parser.parse(null, script, args);
                        
                        //language validate

http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/main/java/org/apache/sysml/parser/ParserFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/parser/ParserFactory.java 
b/src/main/java/org/apache/sysml/parser/ParserFactory.java
index 2d4e273..6b2b686 100644
--- a/src/main/java/org/apache/sysml/parser/ParserFactory.java
+++ b/src/main/java/org/apache/sysml/parser/ParserFactory.java
@@ -19,6 +19,9 @@
 
 package org.apache.sysml.parser;
 
+import java.util.Collections;
+import java.util.Map;
+
 import org.apache.sysml.api.mlcontext.ScriptType;
 import org.apache.sysml.parser.common.CommonSyntacticValidator;
 import org.apache.sysml.parser.dml.DMLParserWrapper;
@@ -26,24 +29,25 @@ import org.apache.sysml.parser.pydml.PyDMLParserWrapper;
 
 public class ParserFactory {
 
+       public static ParserWrapper createParser(ScriptType scriptType) {
+               return createParser(scriptType, Collections.emptyMap());
+       }
+       
        /**
         * Factory method for creating parser wrappers
         * 
-        * @param scriptType
-        *            type of script
+        * @param scriptType type of script
+        * @param nsscripts map of namespace scripts (name, script)
         * @return parser wrapper (DMLParserWrapper or PyDMLParserWrapper)
         */
-       public static ParserWrapper createParser(ScriptType scriptType) {
+       public static ParserWrapper createParser(ScriptType scriptType, 
Map<String, String> nsscripts) {
                ParserWrapper ret = null;
-
                // create the parser instance
                switch (scriptType) {
                        case DML: ret = new DMLParserWrapper(); break;
                        case PYDML: ret = new PyDMLParserWrapper(); break;
                }
-               CommonSyntacticValidator.init();
-
+               CommonSyntacticValidator.init(nsscripts);
                return ret;
        }
-
 }

http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/main/java/org/apache/sysml/parser/common/CommonSyntacticValidator.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/sysml/parser/common/CommonSyntacticValidator.java 
b/src/main/java/org/apache/sysml/parser/common/CommonSyntacticValidator.java
index 3226895..ab9c330 100644
--- a/src/main/java/org/apache/sysml/parser/common/CommonSyntacticValidator.java
+++ b/src/main/java/org/apache/sysml/parser/common/CommonSyntacticValidator.java
@@ -19,11 +19,13 @@
 
 package org.apache.sysml.parser.common;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.regex.Pattern;
 
@@ -45,6 +47,7 @@ import org.apache.sysml.parser.Expression.DataOp;
 import org.apache.sysml.parser.Expression.DataType;
 import org.apache.sysml.parser.Expression.ValueType;
 import org.apache.sysml.parser.FunctionCallIdentifier;
+import org.apache.sysml.parser.ImportStatement;
 import org.apache.sysml.parser.IntIdentifier;
 import org.apache.sysml.parser.LanguageException;
 import org.apache.sysml.parser.MultiAssignmentStatement;
@@ -63,24 +66,26 @@ import org.apache.sysml.parser.BuiltinConstant;
  * Contains fields and (helper) methods common to {@link 
DmlSyntacticValidator} and {@link PydmlSyntacticValidator}
  */
 public abstract class CommonSyntacticValidator {
-
+       private static final String DEF_WORK_DIR = ".";
+       
+       //externally loaded dml scripts filename (unmodified) / script
+       protected static ThreadLocal<HashMap<String, String>> _tScripts = new 
ThreadLocal<HashMap<String, String>>() {
+               @Override protected HashMap<String, String> initialValue() { 
return new HashMap<>(); }
+       };
+       //imported scripts to prevent infinite recursion, modified filename / 
namespace
+       protected static ThreadLocal<HashMap<String, String>> _f2NS = new 
ThreadLocal<HashMap<String, String>>() {
+               @Override protected HashMap<String, String> initialValue() { 
return new HashMap<>(); }
+       };
+       
        protected final CustomErrorListener errorListener;
        protected final String currentFile;
-       protected String _workingDir = ".";   //current working directory
+       protected String _workingDir = DEF_WORK_DIR;
        protected Map<String,String> argVals = null;
        protected String sourceNamespace = null;
-       // Track imported scripts to prevent infinite recursion
-       protected static ThreadLocal<HashMap<String, String>> _scripts = new 
ThreadLocal<HashMap<String, String>>() {
-               @Override protected HashMap<String, String> initialValue() { 
return new HashMap<>(); }
-       };
        // Map namespaces to full paths as defined only from source statements 
in this script (i.e., currentFile)
        protected HashMap<String, String> sources;
        // Names of new internal and external functions defined in this script 
(i.e., currentFile)
        protected Set<String> functions;
-       
-       public static void init() {
-               _scripts.get().clear();
-       }
 
        public CommonSyntacticValidator(CustomErrorListener errorListener, 
Map<String,String> argVals, String sourceNamespace, Set<String> prepFunctions) {
                this.errorListener = errorListener;
@@ -90,6 +95,17 @@ public abstract class CommonSyntacticValidator {
                sources = new HashMap<>();
                functions = (null != prepFunctions) ? prepFunctions : new 
HashSet<>();
        }
+       
+       public static void init() {
+               _f2NS.get().clear();
+       }
+       
+       public static void init(Map<String, String> scripts) {
+               _f2NS.get().clear();
+               _tScripts.get().clear();
+               for( Entry<String,String> e : scripts.entrySet() )
+                       _tScripts.get().put(getDefWorkingFilePath(e.getKey()), 
e.getValue());
+       }
 
        protected void notifyErrorListeners(String message, Token op) {
                if (!DMLScript.VALIDATOR_IGNORE_ISSUES) {
@@ -150,6 +166,24 @@ public abstract class CommonSyntacticValidator {
                String path = sources.get(namespace);
                return (path != null && path.length() > 0) ? path : namespace;
        }
+       
+       public String getWorkingFilePath(String filePath) {
+               return getWorkingFilePath(filePath, _workingDir);
+       }
+       
+       public static String getDefWorkingFilePath(String filePath) {
+               return getWorkingFilePath(filePath, DEF_WORK_DIR);
+       }
+       
+       private static String getWorkingFilePath(String filePath, String 
workingDir) {
+               return !new File(filePath).isAbsolute() ?
+                       workingDir + File.separator + filePath : filePath;
+       }
+       
+       public String getNamespaceSafe(Token ns) {
+               return (ns != null && ns.getText() != null && 
!ns.getText().isEmpty()) ?
+                       ns.getText() : DMLProgram.DEFAULT_NAMESPACE;
+       }
 
        protected void validateNamespace(String namespace, String filePath, 
ParserRuleContext ctx) {
                if (!sources.containsKey(namespace)) {
@@ -161,6 +195,16 @@ public abstract class CommonSyntacticValidator {
                        notifyErrorListeners("Namespace Conflict: '" + 
namespace + "' already defined as " + sources.get(namespace), ctx.start);
                }
        }
+       
+       protected void setupContextInfo(StatementInfo info, String namespace, 
String filePath, String filePath2, DMLProgram prog ) {
+               info.namespaces = new HashMap<>();
+               info.namespaces.put(getQualifiedNamespace(namespace), prog);
+               ImportStatement istmt = new ImportStatement();
+               istmt.setCompletePath(filePath);
+               istmt.setFilename(filePath2);
+               istmt.setNamespace(namespace);
+               info.stmt = istmt;
+       }
 
        protected void setFileLineColumn(Expression expr, ParserRuleContext 
ctx) {
                expr.setCtxValuesAndFilename(ctx, currentFile);

http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/main/java/org/apache/sysml/parser/common/StatementInfo.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/parser/common/StatementInfo.java 
b/src/main/java/org/apache/sysml/parser/common/StatementInfo.java
index aad5a6a..941298b 100644
--- a/src/main/java/org/apache/sysml/parser/common/StatementInfo.java
+++ b/src/main/java/org/apache/sysml/parser/common/StatementInfo.java
@@ -34,7 +34,6 @@ import org.apache.sysml.parser.Statement;
  */
 
 public class StatementInfo {
-
        public Statement stmt = null;
        
        // Valid only for import statements
@@ -43,5 +42,4 @@ public class StatementInfo {
        // Valid only for function statement
        //public String namespace = DMLProgram.DEFAULT_NAMESPACE;
        public String functionName = "";
-
 }

http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidator.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidator.java 
b/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidator.java
index ba5b2db..5624f2a 100644
--- a/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidator.java
+++ b/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidator.java
@@ -19,7 +19,6 @@
 
 package org.apache.sysml.parser.dml;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -44,7 +43,6 @@ import org.apache.sysml.parser.ForStatement;
 import org.apache.sysml.parser.FunctionCallIdentifier;
 import org.apache.sysml.parser.FunctionStatement;
 import org.apache.sysml.parser.IfStatement;
-import org.apache.sysml.parser.ImportStatement;
 import org.apache.sysml.parser.IndexedIdentifier;
 import org.apache.sysml.parser.IterablePredicate;
 import org.apache.sysml.parser.LanguageException;
@@ -110,6 +108,7 @@ import 
org.apache.sysml.parser.dml.DmlParser.TypedArgNoAssignContext;
 import org.apache.sysml.parser.dml.DmlParser.UnaryExpressionContext;
 import org.apache.sysml.parser.dml.DmlParser.ValueTypeContext;
 import org.apache.sysml.parser.dml.DmlParser.WhileStatementContext;
+import org.apache.sysml.runtime.util.UtilFunctions;
 
 
 public class DmlSyntacticValidator extends CommonSyntacticValidator implements 
DmlListener {
@@ -375,67 +374,39 @@ public class DmlSyntacticValidator extends 
CommonSyntacticValidator implements D
 
 
        // -----------------------------------------------------------------
-       //                      "src" statment
+       //                      "source" statement
        // -----------------------------------------------------------------
 
        @Override
-       public void exitImportStatement(ImportStatementContext ctx)
-       {
-               //prepare import filepath
-               String filePath = ctx.filePath.getText();
-               String namespace = DMLProgram.DEFAULT_NAMESPACE;
-               if(ctx.namespace != null && ctx.namespace.getText() != null && 
!ctx.namespace.getText().isEmpty()) {
-                       namespace = ctx.namespace.getText();
-               }
-               if((filePath.startsWith("\"") && filePath.endsWith("\"")) ||
-                               filePath.startsWith("'") && 
filePath.endsWith("'")) {
-                       filePath = filePath.substring(1, filePath.length()-1);
-               }
-
-               File file = new File(filePath);
-               if (!file.isAbsolute()) {
-                       //concatenate working directory to filepath
-                       filePath = _workingDir + File.separator + filePath;
-               }
+       public void exitImportStatement(ImportStatementContext ctx) {
+               String filePath = 
getWorkingFilePath(UtilFunctions.unquote(ctx.filePath.getText()));
+               String namespace = getNamespaceSafe(ctx.namespace);
 
                validateNamespace(namespace, filePath, ctx);
                String scriptID = DMLProgram.constructFunctionKey(namespace, 
filePath);
 
                DMLProgram prog = null;
-               if (!_scripts.get().containsKey(scriptID))
-               {
-                       _scripts.get().put(scriptID, namespace);
+               if (!_f2NS.get().containsKey(scriptID)) {
+                       _f2NS.get().put(scriptID, namespace);
                        try {
-                               prog = (new 
DMLParserWrapper()).doParse(filePath, null, getQualifiedNamespace(namespace), 
argVals);
-                       } catch (ParseException e) {
+                               prog = (new 
DMLParserWrapper()).doParse(filePath,
+                                       _tScripts.get().get(filePath), 
getQualifiedNamespace(namespace), argVals);
+                       }
+                       catch (ParseException e) {
                                notifyErrorListeners(e.getMessage(), ctx.start);
                                return;
                        }
-               // Custom logic whether to proceed ahead or not. Better than 
the current exception handling mechanism
                        if(prog == null) {
                                notifyErrorListeners("One or more errors found 
during importing a program from file " + filePath, ctx.start);
                                return;
                        }
-                       else {
-                               ctx.info.namespaces = new HashMap<>();
-                               
ctx.info.namespaces.put(getQualifiedNamespace(namespace), prog);
-                               ctx.info.stmt = new ImportStatement();
-                               ((ImportStatement) 
ctx.info.stmt).setCompletePath(filePath);
-                               ((ImportStatement) 
ctx.info.stmt).setFilePath(ctx.filePath.getText());
-                               ((ImportStatement) 
ctx.info.stmt).setNamespace(namespace);
-                       }
+                       setupContextInfo(ctx.info, namespace, filePath, 
ctx.filePath.getText(), prog);
                }
-               else
-               {
+               else {
                        // Skip redundant parsing (to prevent potential 
infinite recursion) and
                        // create empty program for this context to allow 
processing to continue.
                        prog = new DMLProgram();
-                       ctx.info.namespaces = new HashMap<>();
-                       
ctx.info.namespaces.put(getQualifiedNamespace(namespace), prog);
-                       ctx.info.stmt = new ImportStatement();
-                       ((ImportStatement) 
ctx.info.stmt).setCompletePath(filePath);
-                       ((ImportStatement) 
ctx.info.stmt).setFilePath(ctx.filePath.getText());
-                       ((ImportStatement) 
ctx.info.stmt).setNamespace(namespace);
+                       setupContextInfo(ctx.info, namespace, filePath, 
ctx.filePath.getText(), prog);
                }
        }
 
@@ -826,12 +797,7 @@ public class DmlSyntacticValidator extends 
CommonSyntacticValidator implements D
        @Override
        public void exitPathStatement(PathStatementContext ctx) {
                PathStatement stmt = new PathStatement(ctx.pathValue.getText());
-               String filePath = ctx.pathValue.getText();
-               if((filePath.startsWith("\"") && filePath.endsWith("\"")) ||
-                               filePath.startsWith("'") && 
filePath.endsWith("'")) {
-                       filePath = filePath.substring(1, filePath.length()-1);
-               }
-
+               String filePath = 
UtilFunctions.unquote(ctx.pathValue.getText());
                _workingDir = filePath;
                ctx.info.stmt = stmt;
        }

http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/main/java/org/apache/sysml/parser/pydml/PydmlSyntacticValidator.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/sysml/parser/pydml/PydmlSyntacticValidator.java 
b/src/main/java/org/apache/sysml/parser/pydml/PydmlSyntacticValidator.java
index 117dff1..85adc3a 100644
--- a/src/main/java/org/apache/sysml/parser/pydml/PydmlSyntacticValidator.java
+++ b/src/main/java/org/apache/sysml/parser/pydml/PydmlSyntacticValidator.java
@@ -19,7 +19,6 @@
 
 package org.apache.sysml.parser.pydml;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -47,7 +46,6 @@ import org.apache.sysml.parser.ForStatement;
 import org.apache.sysml.parser.FunctionCallIdentifier;
 import org.apache.sysml.parser.FunctionStatement;
 import org.apache.sysml.parser.IfStatement;
-import org.apache.sysml.parser.ImportStatement;
 import org.apache.sysml.parser.IndexedIdentifier;
 import org.apache.sysml.parser.IntIdentifier;
 import org.apache.sysml.parser.IterablePredicate;
@@ -114,6 +112,7 @@ import 
org.apache.sysml.parser.pydml.PydmlParser.TypedArgNoAssignContext;
 import org.apache.sysml.parser.pydml.PydmlParser.UnaryExpressionContext;
 import org.apache.sysml.parser.pydml.PydmlParser.ValueDataTypeCheckContext;
 import org.apache.sysml.parser.pydml.PydmlParser.WhileStatementContext;
+import org.apache.sysml.runtime.util.UtilFunctions;
 
 /**
  * TODO: Refactor duplicated parser code dml/pydml (entire package).
@@ -479,60 +478,34 @@ public class PydmlSyntacticValidator extends 
CommonSyntacticValidator implements
        @Override
        public void exitImportStatement(ImportStatementContext ctx)
        {
-               //prepare import filepath
-               String filePath = ctx.filePath.getText();
-               String namespace = DMLProgram.DEFAULT_NAMESPACE;
-               if(ctx.namespace != null && ctx.namespace.getText() != null && 
!ctx.namespace.getText().isEmpty()) {
-                       namespace = ctx.namespace.getText();
-               }
-               if((filePath.startsWith("\"") && filePath.endsWith("\"")) ||
-                               filePath.startsWith("'") && 
filePath.endsWith("'")) {
-                       filePath = filePath.substring(1, filePath.length()-1);
-               }
-
-               File file = new File(filePath);
-               if (!file.isAbsolute()) {
-                       //concatenate working directory to filepath
-                       filePath = _workingDir + File.separator + filePath;
-               }
+               String filePath = 
getWorkingFilePath(UtilFunctions.unquote(ctx.filePath.getText()));
+               String namespace = getNamespaceSafe(ctx.namespace);
+               
                validateNamespace(namespace, filePath, ctx);
                String scriptID = DMLProgram.constructFunctionKey(namespace, 
filePath);
 
                DMLProgram prog = null;
-               if (!_scripts.get().containsKey(scriptID))
-               {
-                       _scripts.get().put(scriptID, namespace);
+               if (!_f2NS.get().containsKey(scriptID)) {
+                       _f2NS.get().put(scriptID, namespace);
                        try {
-                               prog = (new 
PyDMLParserWrapper()).doParse(filePath, null, getQualifiedNamespace(namespace), 
argVals);
-                       } catch (ParseException e) {
+                               prog = (new 
PyDMLParserWrapper()).doParse(filePath,
+                                       _tScripts.get().get(filePath), 
getQualifiedNamespace(namespace), argVals);
+                       }
+                       catch (ParseException e) {
                                notifyErrorListeners(e.getMessage(), ctx.start);
                                return;
                        }
-               // Custom logic whether to proceed ahead or not. Better than 
the current exception handling mechanism
                        if(prog == null) {
                                notifyErrorListeners("One or more errors found 
during importing a program from file " + filePath, ctx.start);
                                return;
                        }
-                       else {
-                               ctx.info.namespaces = new HashMap<>();
-                               
ctx.info.namespaces.put(getQualifiedNamespace(namespace), prog);
-                               ctx.info.stmt = new ImportStatement();
-                               ((ImportStatement) 
ctx.info.stmt).setCompletePath(filePath);
-                               ((ImportStatement) 
ctx.info.stmt).setFilePath(ctx.filePath.getText());
-                               ((ImportStatement) 
ctx.info.stmt).setNamespace(namespace);
-                       }
+                       setupContextInfo(ctx.info, namespace, filePath, 
ctx.filePath.getText(), prog);
                }
-               else
-               {
+               else {
                        // Skip redundant parsing (to prevent potential 
infinite recursion) and
                        // create empty program for this context to allow 
processing to continue.
                        prog = new DMLProgram();
-                       ctx.info.namespaces = new HashMap<>();
-                       
ctx.info.namespaces.put(getQualifiedNamespace(namespace), prog);
-                       ctx.info.stmt = new ImportStatement();
-                       ((ImportStatement) 
ctx.info.stmt).setCompletePath(filePath);
-                       ((ImportStatement) 
ctx.info.stmt).setFilePath(ctx.filePath.getText());
-                       ((ImportStatement) 
ctx.info.stmt).setNamespace(namespace);
+                       setupContextInfo(ctx.info, namespace, filePath, 
ctx.filePath.getText(), prog);
                }
        }
 
@@ -1470,12 +1443,7 @@ public class PydmlSyntacticValidator extends 
CommonSyntacticValidator implements
        @Override
        public void exitPathStatement(PathStatementContext ctx) {
                PathStatement stmt = new PathStatement(ctx.pathValue.getText());
-               String filePath = ctx.pathValue.getText();
-               if((filePath.startsWith("\"") && filePath.endsWith("\"")) ||
-                               filePath.startsWith("'") && 
filePath.endsWith("'")) {
-                       filePath = filePath.substring(1, filePath.length()-1);
-               }
-
+               String filePath = 
UtilFunctions.unquote(ctx.pathValue.getText());
                _workingDir = filePath;
                ctx.info.stmt = stmt;
        }

http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/main/java/org/apache/sysml/runtime/util/UtilFunctions.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/runtime/util/UtilFunctions.java 
b/src/main/java/org/apache/sysml/runtime/util/UtilFunctions.java
index 1947c00..e32cb22 100644
--- a/src/main/java/org/apache/sysml/runtime/util/UtilFunctions.java
+++ b/src/main/java/org/apache/sysml/runtime/util/UtilFunctions.java
@@ -533,9 +533,9 @@ public class UtilFunctions
        }
        
        public static String unquote(String s) {
-               if (s != null
-                               && s.length() >=2 && ((s.startsWith("\"") && 
s.endsWith("\"")) 
-                                       || (s.startsWith("'") && 
s.endsWith("'")))) {
+               if (s != null && s.length() >=2 
+                       && ((s.startsWith("\"") && s.endsWith("\"")) 
+                       || (s.startsWith("'") && s.endsWith("'")))) {
                        s = s.substring(1, s.length() - 1);
                }
                return s;

http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/test/java/org/apache/sysml/test/integration/functions/jmlc/NamespaceFunctionTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/sysml/test/integration/functions/jmlc/NamespaceFunctionTest.java
 
b/src/test/java/org/apache/sysml/test/integration/functions/jmlc/NamespaceFunctionTest.java
new file mode 100644
index 0000000..8b65eb8
--- /dev/null
+++ 
b/src/test/java/org/apache/sysml/test/integration/functions/jmlc/NamespaceFunctionTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sysml.test.integration.functions.jmlc;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sysml.api.jmlc.Connection;
+import org.apache.sysml.api.jmlc.PreparedScript;
+import org.apache.sysml.api.jmlc.ResultVariables;
+import org.apache.sysml.runtime.io.IOUtilFunctions;
+import org.apache.sysml.runtime.matrix.data.MatrixBlock;
+import org.apache.sysml.test.integration.AutomatedTestBase;
+import org.apache.sysml.test.integration.TestConfiguration;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class NamespaceFunctionTest extends AutomatedTestBase 
+{
+       private final static String TEST_NAME1 = "foo.dml";
+       private final static String TEST_NAME2 = "bar1.dml";
+       private final static String TEST_NAME3 = "bar2.dml";
+       
+       private final static String TEST_DIR = "functions/jmlc/";
+       private final static String TEST_CLASS_DIR = TEST_DIR + 
NamespaceFunctionTest.class.getSimpleName() + "/";
+       
+       private final static int rows = 700;
+       private final static int cols = 30;
+       private final static double sparsity1 = 0.7;
+       private final static double sparsity2 = 0.1;
+       
+       
+       @Override
+       public void setUp() {
+               addTestConfiguration(TEST_NAME1, new 
TestConfiguration(TEST_CLASS_DIR, TEST_NAME1, new String[] { "F2" }) ); 
+       }
+       
+       @Test
+       public void testJMLCNamespaceDense() throws IOException {
+               runJMLCNamespaceTest(false);
+       }
+       
+       @Test
+       public void testJMLCNamespaceSparse() throws IOException {
+               runJMLCNamespaceTest(true);
+       }
+       
+
+       private void runJMLCNamespaceTest(boolean sparse) 
+               throws IOException
+       {
+               TestConfiguration config = getTestConfiguration(TEST_NAME1);
+               loadTestConfiguration(config);
+               
+               //load scripts and create prepared script
+               Connection conn = new Connection();
+               String script1 = conn.readScript(SCRIPT_DIR + TEST_DIR + 
TEST_NAME1);
+               Map<String,String> nsscripts = new HashMap<>();
+               nsscripts.put(TEST_NAME2, conn.readScript(SCRIPT_DIR + TEST_DIR 
+ TEST_NAME2));
+               nsscripts.put(TEST_NAME3, conn.readScript(SCRIPT_DIR + TEST_DIR 
+ TEST_NAME3));
+               PreparedScript pstmt = conn.prepareScript(script1,
+                       nsscripts, Collections.emptyMap(), new String[]{"X"}, 
new String[]{"Z"}, false);
+               
+               //generate input data
+               double sparsity = sparse ? sparsity2 : sparsity1;
+               MatrixBlock X = MatrixBlock.randOperations(rows, cols, 
sparsity, -1, 1, "uniform", 7);
+               
+               //execute script and get result
+               pstmt.setMatrix("X", X, true);
+               ResultVariables rs = pstmt.executeScript();
+               MatrixBlock Z = rs.getMatrixBlock("Z");
+               IOUtilFunctions.closeSilently(conn);
+               
+               //compare results
+               for(int i=0; i<rows; i++)
+                       for(int j=0; j<cols; j++)
+                               Assert.assertEquals(X.quickGetValue(i, j)+10,
+                                       Z.quickGetValue(i, j), 1e-10);
+       }
+}

http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/test/scripts/functions/jmlc/bar1.dml
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/jmlc/bar1.dml 
b/src/test/scripts/functions/jmlc/bar1.dml
new file mode 100644
index 0000000..6b92e1a
--- /dev/null
+++ b/src/test/scripts/functions/jmlc/bar1.dml
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+exec = function(matrix[double] A) return (matrix[double] B) {
+  B = A;
+  for(i in 1:2) {
+    B = B + i;
+  }  
+}

http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/test/scripts/functions/jmlc/bar2.dml
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/jmlc/bar2.dml 
b/src/test/scripts/functions/jmlc/bar2.dml
new file mode 100644
index 0000000..58998d1
--- /dev/null
+++ b/src/test/scripts/functions/jmlc/bar2.dml
@@ -0,0 +1,29 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("bar1.dml") as ns3
+
+exec = function(matrix[double] A) return (matrix[double] B) {
+  B = A + 1;
+  for(i in 1:2) {
+    B = ns3::exec(B);
+  }  
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/test/scripts/functions/jmlc/foo.dml
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/jmlc/foo.dml 
b/src/test/scripts/functions/jmlc/foo.dml
new file mode 100644
index 0000000..b05c90b
--- /dev/null
+++ b/src/test/scripts/functions/jmlc/foo.dml
@@ -0,0 +1,30 @@
+#-------------------------------------------------------------
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#-------------------------------------------------------------
+
+source("bar1.dml") as ns1
+source("bar2.dml") as ns2
+
+X = read($1);
+
+Y = ns1::exec(X);
+Z = ns2::exec(Y);
+
+write(Z, $2)

http://git-wip-us.apache.org/repos/asf/systemml/blob/c250adab/src/test_suites/java/org/apache/sysml/test/integration/functions/jmlc/ZPackageSuite.java
----------------------------------------------------------------------
diff --git 
a/src/test_suites/java/org/apache/sysml/test/integration/functions/jmlc/ZPackageSuite.java
 
b/src/test_suites/java/org/apache/sysml/test/integration/functions/jmlc/ZPackageSuite.java
index 6c0135c..9969cc0 100644
--- 
a/src/test_suites/java/org/apache/sysml/test/integration/functions/jmlc/ZPackageSuite.java
+++ 
b/src/test_suites/java/org/apache/sysml/test/integration/functions/jmlc/ZPackageSuite.java
@@ -40,6 +40,7 @@ import org.junit.runners.Suite;
        JMLCInputStreamReadTest.class,
        JMLCParfor2ForCompileTest.class,
        ReuseModelVariablesTest.class,
+       NamespaceFunctionTest.class,
        MulticlassSVMScoreTest.class
 })
 

Reply via email to