Browse Source

HPCC-10150 Add support for relative imports using $.^.^.X

Signed-off-by: Gavin Halliday <gavin.halliday@lexisnexis.com>
Gavin Halliday 11 years ago
parent
commit
376ad5fd58

+ 2 - 0
ecl/eclcc/eclcc.cpp

@@ -1214,6 +1214,8 @@ void EclCC::processXmlFile(EclCompileInstance & instance, const char *archiveXML
 
     EclRepositoryArray repositories;
     repositories.append(*LINK(pluginsRepository));
+    if (archiveTree->getPropBool("@useLocalSystemLibraries", false)) // Primarily for testing.
+        repositories.append(*LINK(libraryRepository));
 
     Owned<IFileContents> contents;
     StringBuffer fullPath; // Here so it doesn't get freed when leaving the else block

+ 2 - 0
ecl/hql/hqlatoms.cpp

@@ -107,6 +107,7 @@ IAtom * compressedAtom;
 IAtom * __compressed__Atom;
 IAtom * _conditionFolded_Atom;
 IAtom * constAtom;
+IAtom * _container_Atom;
 IAtom * contextAtom;
 IAtom * contextSensitiveAtom;
 IAtom * costAtom;
@@ -519,6 +520,7 @@ MODULE_INIT(INIT_PRIORITY_HQLATOM)
     MAKEATOM(__compressed__);
     MAKESYSATOM(conditionFolded);
     MAKEATOM(const);
+    MAKESYSATOM(container);
     MAKEATOM(context);
     MAKEATOM(contextSensitive);
     MAKEATOM(cost);

+ 1 - 0
ecl/hql/hqlatoms.hpp

@@ -109,6 +109,7 @@ extern HQL_API IAtom * compressedAtom;
 extern HQL_API IAtom * __compressed__Atom;
 extern HQL_API IAtom * _conditionFolded_Atom;
 extern HQL_API IAtom * constAtom;
+extern HQL_API IAtom * _container_Atom;
 extern HQL_API IAtom * contextAtom;
 extern HQL_API IAtom * contextSensitiveAtom;
 extern HQL_API IAtom * costAtom;

+ 2 - 2
ecl/hql/hqldesc.cpp

@@ -29,7 +29,7 @@ void getFullName(StringBuffer & name, IHqlExpression * expr)
     }
     else
     {
-        const char * module = expr->queryFullModuleId()->str();
+        const char * module = expr->queryFullContainerId()->str();
         if (module && *module)
             name.append(module).append(".");
         name.append(expr->queryName());
@@ -54,7 +54,7 @@ void setFullNameProp(IPropertyTree * tree, const char * prop, IHqlExpression * e
     if (scope)
         tree->setProp(prop, scope->queryFullName());
     else
-        setFullNameProp(tree, prop, expr->queryFullModuleId()->lower()->str(), expr->queryName()->str());
+        setFullNameProp(tree, prop, expr->queryFullContainerId()->lower()->str(), expr->queryName()->str());
 }
 
 static int compareSymbolsByPosition(IInterface * * pleft, IInterface * * pright)

+ 1 - 0
ecl/hql/hqlerrors.hpp

@@ -423,6 +423,7 @@
 #define ERR_PluginNoScripting       2391
 #define ERR_ZERO_SIZE_VIRTUAL       2392
 #define ERR_BAD_JOINGROUP_FIELD     2393
+#define ERR_CANNOT_ACCESS_CONTAINER 2394
 
 #define ERR_ASSERTION_FAILS         100000
 

+ 18 - 3
ecl/hql/hqlexpr.cpp

@@ -6633,9 +6633,9 @@ bool CHqlAnnotation::isFullyBound() const
     return body->isFullyBound();
 }
 
-IIdAtom * CHqlAnnotation::queryFullModuleId() const
+IIdAtom * CHqlAnnotation::queryFullContainerId() const
 {
-    return body->queryFullModuleId();
+    return body->queryFullContainerId();
 }
 
 IHqlExpression * CHqlAnnotation::queryProperty(ExprPropKind kind)
@@ -6907,7 +6907,7 @@ bool CHqlSymbolAnnotation::equals(const IHqlExpression & other) const
     if ((symbolFlags != other.getSymbolFlags()) || (funcdef != other.queryFunctionDefinition()))
         return false;
 
-    if (moduleId != other.queryFullModuleId())
+    if (moduleId != other.queryFullContainerId())
         return false;
 
     if (op == no_nobody)
@@ -7533,24 +7533,29 @@ extern HQL_API IFileContents * createFileContentsSubset(IFileContents * contents
 CHqlScope::CHqlScope(node_operator _op, IIdAtom * _id, const char * _fullName)
 : CHqlExpressionWithType(_op, NULL), id(_id), fullName(_fullName)
 {
+    containerId = NULL;
     type = this;
+    initContainer();
 }
 
 CHqlScope::CHqlScope(IHqlScope* scope)
 : CHqlExpressionWithType(no_scope, NULL)
 {
     id = scope->queryId();
+    containerId = NULL;
     fullName.set(scope->queryFullName());
     CHqlScope* s = QUERYINTERFACE(scope, CHqlScope);
     if (s && s->text)
         text.set(s->text);
     type = this;
+    initContainer();
 }
 
 CHqlScope::CHqlScope(node_operator _op) 
 : CHqlExpressionWithType(_op, NULL)
 {
     id = NULL;
+    containerId = NULL;
     type = this;
 }
 
@@ -7560,6 +7565,16 @@ CHqlScope::~CHqlScope()
         type = NULL;
 }
 
+void CHqlScope::initContainer()
+{
+    if (fullName)
+    {
+        const char * dot = strrchr(fullName, '.');
+        if (dot)
+            containerId = createIdAtom(fullName, dot-fullName);
+    }
+}
+
 bool CHqlScope::assignableFrom(ITypeInfo * source)
 {
     if (source == this)

+ 1 - 1
ecl/hql/hqlexpr.hpp

@@ -1107,7 +1107,7 @@ interface IHqlExpression : public IInterface
     virtual unsigned getInfoFlags2() const = 0;
 
     virtual ISourcePath * querySourcePath() const = 0;
-    virtual IIdAtom * queryFullModuleId() const = 0;              // only defined for a named symbol
+    virtual IIdAtom * queryFullContainerId() const = 0;              // only defined for a named symbol and global module.
     virtual int  getStartLine() const = 0;
     virtual int  getStartColumn() const = 0;
     virtual IPropertyTree * getDocumentation() const = 0;

+ 6 - 3
ecl/hql/hqlexpr.ipp

@@ -253,7 +253,7 @@ public:
     virtual IHqlExpression * cloneAllAnnotations(IHqlExpression * body) { return LINK(body); }
     virtual void unwindList(HqlExprArray &dst, node_operator);
 
-    virtual IIdAtom *           queryFullModuleId() const { return NULL; }
+    virtual IIdAtom *           queryFullContainerId() const { return NULL; }
     virtual ISourcePath *   querySourcePath() const { return NULL; }
 
     virtual IInterface *    queryTransformExtra();
@@ -529,7 +529,7 @@ public:
     virtual IHqlExpression * clone(HqlExprArray &);
     virtual IHqlExpression * cloneAnnotation(IHqlExpression * body) = 0;
     virtual IHqlExpression * cloneAllAnnotations(IHqlExpression * body);
-    virtual IIdAtom * queryFullModuleId() const;
+    virtual IIdAtom * queryFullContainerId() const;
     virtual bool isFullyBound() const;
     virtual IHqlExpression *addOperand(IHqlExpression *);
     virtual StringBuffer& getTextBuf(StringBuffer& buf);
@@ -552,7 +552,7 @@ public:
 
     virtual IAtom * queryName() const { return id->lower(); }
     virtual IIdAtom * queryId() const { return id; }
-    virtual IIdAtom * queryFullModuleId() const { return moduleId; }
+    virtual IIdAtom * queryFullContainerId() const { return moduleId; }
     virtual IHqlExpression *queryFunctionDefinition() const;
     virtual unsigned getSymbolFlags() const;
 
@@ -1006,6 +1006,7 @@ class HQL_API CHqlScope : public CHqlExpressionWithType, implements IHqlScope, i
 protected:
     Owned<IFileContents> text;
     IIdAtom * id;
+    IIdAtom * containerId;
     StringAttr fullName;                //Fully qualified name of this nested module   E.g.: PARENT.CHILD.GRANDCHILD
     SymbolTable symbols;
 
@@ -1037,6 +1038,7 @@ public:
     virtual IAtom * queryName() const {return id->lower();}
     virtual IIdAtom * queryId() const { return id; }
     virtual const char * queryFullName() const  { return fullName; }
+    virtual IIdAtom * queryFullContainerId() const { return containerId; }
     virtual ISourcePath * querySourcePath() const { return text ? text->querySourcePath() : NULL; }
 
     virtual void ensureSymbolsDefined(HqlLookupContext & ctx) { }
@@ -1089,6 +1091,7 @@ public:
     virtual void deserialize(MemoryBuffer &) { UNIMPLEMENTED; }
 
 protected:
+    void initContainer();
     void throwRecursiveError(IIdAtom * id);
 };
 

+ 4 - 0
ecl/hql/hqlgram.y

@@ -713,6 +713,10 @@ importId
                         {
                             $$.setExpr(createAttribute(_dot_Atom, $1.getExpr(), createId($3.getId())), $1);
                         }
+    | importId '.' '^'
+                        {
+                            $$.setExpr(createAttribute(_container_Atom, $1.getExpr()), $1);
+                        }
     ;
 
 defineType

+ 20 - 2
ecl/hql/hqlgram2.cpp

@@ -9925,7 +9925,8 @@ IHqlExpression * HqlGram::resolveImportModule(const attribute & errpos, IHqlExpr
 {
     if (isDollarModule(expr))
         return LINK(queryExpression(globalScope));
-    if (expr->queryName() != _dot_Atom)
+    IAtom * name = expr->queryName();
+    if ((name != _dot_Atom) && (name != _container_Atom))
     {
         if (!lookupCtx.queryRepository())
         {
@@ -9965,11 +9966,28 @@ IHqlExpression * HqlGram::resolveImportModule(const attribute & errpos, IHqlExpr
     OwnedHqlExpr parent = resolveImportModule(errpos, expr->queryChild(0));
     if (!parent)
         return NULL;
+
+    const char * parentName = parent->queryId()->str();
+    if (name == _container_Atom)
+    {
+        const char * containerName = parent->queryFullContainerId()->str();
+        //This is a bit ugly - remove the last qualified module, and resolve the name again.  A more "correct" method
+        //saving container pointers hit problems because remote scopes within CHqlMergedScope containers have a remote
+        //scope as the parent, rather than the merged scope...
+        if (containerName)
+        {
+            OwnedHqlExpr matched = getResolveAttributeFullPath(containerName, LSFpublic, lookupCtx);
+            if (matched)
+                return matched.getClear();
+        }
+        reportError(ERR_CANNOT_ACCESS_CONTAINER, errpos, "Cannot access container for Object '%s'", parentName);
+        return NULL;
+    }
+
     IIdAtom * childId = expr->queryChild(1)->queryId();
     OwnedHqlExpr resolved = parent->queryScope()->lookupSymbol(childId, LSFpublic, lookupCtx);
     if (!resolved)
     {
-        const char * parentName = parent->queryName()->str();
         if (!parentName)
             parentName = "$";
         reportError(ERR_OBJ_NOSUCHFIELD, errpos, "Object '%s' does not have a field named '%s'", parentName, childId->str());

+ 2 - 2
ecl/hql/hqlthql.cpp

@@ -220,7 +220,7 @@ StringBuffer & HqltHql::appendId(StringBuffer & s, IIdAtom * id)
 
 StringBuffer &HqltHql::makeUniqueName(IHqlExpression * expr, StringBuffer &s)
 {
-    IIdAtom * moduleName = expr->queryFullModuleId();
+    IIdAtom * moduleName = expr->queryFullContainerId();
     if (moduleName && !ignoreModuleNames)
     {
         if (isPublicSymbol(expr))
@@ -3049,7 +3049,7 @@ StringBuffer &HqltHql::doAlias(IHqlExpression * expr, StringBuffer &name, bool i
 
 #ifdef SHOW_SYMBOL_LOCATION
         if (expandProcessed)
-            newdef.append(expr->queryFullModuleId()).append("(").append(expr->getStartLine()).append(",").append(expr->getStartColumn()).append("):");
+            newdef.append(expr->queryFullContainerId()).append("(").append(expr->getStartLine()).append(",").append(expr->getStartColumn()).append("):");
 #endif
         newdef.append(exports);
         lookupSymbolName(expr, name);

+ 2 - 2
ecl/hqlcpp/hqlgraph.cpp

@@ -383,7 +383,7 @@ void LogicalGraphCreator::createGraphActivity(IHqlExpression * expr)
     if (symbol)
     {
         addAttribute("name", symbol->queryId()->str());
-        addAttribute("module", symbol->queryFullModuleId()->str());
+        addAttribute("module", symbol->queryFullContainerId()->str());
         addAttributeInt("line", symbol->getStartLine());
         addAttributeInt("column", symbol->getStartColumn());
     }
@@ -573,7 +573,7 @@ const char * LogicalGraphCreator::getActivityText(IHqlExpression * expr, StringB
 {
     if (expr->queryBody() != expr)
     {
-        IIdAtom * module = includeModuleInText ? expr->queryFullModuleId() : NULL;
+        IIdAtom * module = includeModuleInText ? expr->queryFullContainerId() : NULL;
         IIdAtom * name = includeNameInText ? expr->queryId() : NULL;
         StringBuffer header;
         if (module)

+ 58 - 0
ecl/regress/issue10150.eclxml

@@ -0,0 +1,58 @@
+<Archive>
+<!--
+
+    HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+
+    Licensed 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.
+-->
+ <Module name="common">
+  <Attribute name="v1">
+export v1 := 'Hello';
+  </Attribute>
+ </Module>
+ <Module name="a.b.c">
+  <Attribute name="x">
+export x := 3;
+  </Attribute>
+  <Attribute name="y">
+export y := 2;
+  </Attribute>
+  <Attribute name="z">
+import $ as common;
+export z := common.x * common.y;
+  </Attribute>
+ </Module>
+ <Module name="a.b.d">
+  <Attribute name="x">
+export x := 30;
+  </Attribute>
+  <Attribute name="y">
+export y := 20;
+  </Attribute>
+  <Attribute name="z">
+import $ as common;
+import $.^ as parent;
+export z := common.x * parent.c.y;
+  </Attribute>
+ </Module>
+ <Query>
+
+import common;
+import a.b.c as m1;
+import a.b.d as m2;
+output(common.v1);
+output(m1.z);
+output(m2.z);
+
+ </Query>
+</Archive>

+ 29 - 0
ecl/regress/issue10150b.eclxml

@@ -0,0 +1,29 @@
+<Archive build="internal_4.3.0-closedown0" eclVersion="4.3.0" useLocalSystemLibraries="1">
+ <Query attributePath="regress.module7"/>
+ <Module key="regress" name="regress">
+  <Attribute key="module7" name="module7" sourcePath="module7.ecl">
+   /*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+
+    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+    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 &quot;AS IS&quot; 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.
+############################################################################## */
+
+import Std.Str;
+import Std.Str.^.Uni;
+
+output(Str.toUpperCase(&apos;x&apos;));
+output(Uni.toUpperCase(U&apos;x&apos;));&#10;
+  </Attribute>
+ </Module>
+</Archive>