浏览代码

HPCC-9556 Refactor warning handling and implement #ONWARNING

This patch restructures the warning handling so it is always reported via the
report() virtual, and also maps the warning levels using the same chain.

eclcc now supports -w<n>=option to configure the behaviour for a particular warning.

Signed-off-by: Gavin Halliday <gavin.halliday@lexisnexis.com>
Gavin Halliday 11 年之前
父节点
当前提交
785ae866ac
共有 57 个文件被更改,包括 1183 次插入794 次删除
  1. 5 5
      common/fileview2/fvtransform.cpp
  2. 80 35
      ecl/eclcc/eclcc.cpp
  3. 186 134
      ecl/hql/hqlerror.cpp
  4. 98 62
      ecl/hql/hqlerror.hpp
  5. 6 60
      ecl/hql/hqlexpr.cpp
  6. 1 23
      ecl/hql/hqlexpr.hpp
  7. 15 10
      ecl/hql/hqlfold.cpp
  8. 4 3
      ecl/hql/hqlfold.hpp
  9. 2 1
      ecl/hql/hqlfold.ipp
  10. 5 3
      ecl/hql/hqlgram.hpp
  11. 9 7
      ecl/hql/hqlgram.y
  12. 57 50
      ecl/hql/hqlgram2.cpp
  13. 1 1
      ecl/hql/hqlir.cpp
  14. 20 21
      ecl/hql/hqlopt.cpp
  15. 2 2
      ecl/hql/hqlopt.hpp
  16. 2 1
      ecl/hql/hqlopt.ipp
  17. 2 2
      ecl/hql/hqlparse.cpp
  18. 3 1
      ecl/hql/hqlplugininfo.cpp
  19. 0 20
      ecl/hql/hqlrepository.cpp
  20. 0 4
      ecl/hql/hqlrepository.hpp
  21. 191 112
      ecl/hql/hqlutil.cpp
  22. 49 53
      ecl/hql/hqlutil.hpp
  23. 4 4
      ecl/hql/hqlvalid.cpp
  24. 1 1
      ecl/hql/hqlvalid.hpp
  25. 25 21
      ecl/hql/hqlwuerr.cpp
  26. 1 2
      ecl/hql/hqlwuerr.hpp
  27. 0 2
      ecl/hqlcpp/hqlcerrors.hpp
  28. 1 1
      ecl/hqlcpp/hqlckey.cpp
  29. 14 8
      ecl/hqlcpp/hqlcpp.cpp
  30. 6 5
      ecl/hqlcpp/hqlcpp.ipp
  31. 1 1
      ecl/hqlcpp/hqlcppds.cpp
  32. 7 7
      ecl/hqlcpp/hqlcpputil.cpp
  33. 1 1
      ecl/hqlcpp/hqlcpputil.hpp
  34. 11 13
      ecl/hqlcpp/hqlhtcpp.cpp
  35. 1 1
      ecl/hqlcpp/hqliter.cpp
  36. 5 5
      ecl/hqlcpp/hqlresource.cpp
  37. 1 1
      ecl/hqlcpp/hqlresource.ipp
  38. 25 19
      ecl/hqlcpp/hqlsource.cpp
  39. 1 1
      ecl/hqlcpp/hqltcppc.cpp
  40. 39 84
      ecl/hqlcpp/hqlttcpp.cpp
  41. 5 7
      ecl/hqlcpp/hqlttcpp.ipp
  42. 24 0
      ecl/regress/issue9556.ecl
  43. 10 0
      ecl/regress/issue9556a.eclxml
  44. 10 0
      ecl/regress/issue9556b.eclxml
  45. 10 0
      ecl/regress/issue9556c.eclxml
  46. 10 0
      ecl/regress/issue9556d.eclxml
  47. 10 0
      ecl/regress/issue9556e.eclxml
  48. 25 0
      ecl/regress/issue9556f.eclxml
  49. 25 0
      ecl/regress/issue9556g.eclxml
  50. 32 0
      ecl/regress/issue9556h.eclxml
  51. 27 0
      ecl/regress/issue9556i.eclxml
  52. 29 0
      ecl/regress/issue9556j.eclxml
  53. 28 0
      ecl/regress/issue9556k.eclxml
  54. 27 0
      ecl/regress/issue9556l_err.eclxml
  55. 27 0
      ecl/regress/issue9556m_err.eclxml
  56. 1 0
      esp/services/ws_dfu/ws_dfuService.cpp
  57. 1 0
      esp/services/ws_workunits/ws_workunitsHelpers.cpp

+ 5 - 5
common/fileview2/fvtransform.cpp

@@ -241,8 +241,8 @@ void ViewFieldECLTransformer::transform(unsigned & lenTarget, char * & target, u
     actuals.append(*LINK(sourceExpr));
     appendArray(actuals, extraArgs);
 
-    ThrowingErrorReceiver errors;
-    OwnedHqlExpr call = createBoundFunction(&errors, function, actuals, NULL, true);
+    Owned<IErrorReceiver> errorReporter = createThrowingErrorReceiver();
+    OwnedHqlExpr call = createBoundFunction(errorReporter, function, actuals, NULL, true);
     OwnedHqlExpr castValue = ensureExprType(call, utf8Type);
     OwnedHqlExpr folded = quickFoldExpression(castValue, NULL, 0);
     IValue * foldedValue = folded->queryValue();
@@ -294,12 +294,12 @@ void ViewTransformerRegistry::addPlugins(const char * name)
     loadedPlugins.setown(new SafePluginMap(&pluginCtx, true));
     loadedPlugins->loadFromList(name);
 
-    ThrowingErrorReceiver errors;
-    dataServer.setown(createNewSourceFileEclRepository(&errors, name, ESFallowplugins, 0));
+    Owned<IErrorReceiver> errorReporter = createThrowingErrorReceiver();
+    dataServer.setown(createNewSourceFileEclRepository(errorReporter, name, ESFallowplugins, 0));
 
     HqlScopeArray scopes;
     HqlParseContext parseCtx(dataServer, NULL);
-    HqlLookupContext ctx(parseCtx, &errors);
+    HqlLookupContext ctx(parseCtx, errorReporter);
     getRootScopes(scopes, dataServer, ctx);
 
     ForEachItemIn(i, scopes)

+ 80 - 35
ecl/eclcc/eclcc.cpp

@@ -43,6 +43,7 @@
 
 #include "hqlgram.hpp"
 #include "hqltrans.ipp"
+#include "hqlutil.hpp"
 
 #include "build-config.h"
 #include "rmtfile.hpp"
@@ -194,8 +195,8 @@ static bool getHomeFolder(StringBuffer & homepath)
 struct EclCompileInstance
 {
 public:
-    EclCompileInstance(IFile * _inputFile, IErrorReceiver & _errs, FILE * _errout, const char * _outputFilename, bool _legacyImport, bool _legacyWhen) :
-      inputFile(_inputFile), errs(&_errs), errout(_errout), outputFilename(_outputFilename)
+    EclCompileInstance(IFile * _inputFile, IErrorReceiver & _errorProcessor, FILE * _errout, const char * _outputFilename, bool _legacyImport, bool _legacyWhen) :
+      inputFile(_inputFile), errorProcessor(&_errorProcessor), errout(_errout), outputFilename(_outputFilename)
     {
         legacyImport = _legacyImport;
         legacyWhen = _legacyWhen;
@@ -208,12 +209,14 @@ public:
     }
 
     void logStats();
+    void checkEclVersionCompatible();
     bool reportErrorSummary();
+    inline IErrorReceiver & queryErrorProcessor() { return *errorProcessor; }
+
 
 public:
     Linked<IFile> inputFile;
     Linked<IPropertyTree> archive;
-    Linked<IErrorReceiver> errs;
     Linked<IWorkUnit> wu;
     Owned<IEclRepository> dataServer;  // A member which can be cleared after parsing the query
     OwnedHqlExpr query;  // parsed query - cleared when generating to free memory
@@ -232,6 +235,9 @@ public:
         offset_t xmlSize;
         offset_t cppSize;
     } stats;
+
+protected:
+    Linked<IErrorReceiver> errorProcessor;
 };
 
 class EclCC : public CInterfaceOf<ICodegenContextCallback>
@@ -294,9 +300,9 @@ protected:
     void evaluateResult(EclCompileInstance & instance);
     bool generatePrecompiledHeader();
     void generateOutput(EclCompileInstance & instance);
-    void instantECL(EclCompileInstance & instance, IWorkUnit *wu, const char * queryFullName, IErrorReceiver *errs, const char * outputFile);
+    void instantECL(EclCompileInstance & instance, IWorkUnit *wu, const char * queryFullName, IErrorReceiver & errorProcessor, const char * outputFile);
     bool isWithinPath(const char * sourcePathname, const char * searchPath);
-    void getComplexity(IWorkUnit *wu, IHqlExpression * query, IErrorReceiver *errs);
+    void getComplexity(IWorkUnit *wu, IHqlExpression * query, IErrorReceiver & errorProcessor);
     void outputXmlToOutputFile(EclCompileInstance & instance, IPropertyTree * xml);
     void processSingleQuery(EclCompileInstance & instance,
                                IFileContents * queryContents,
@@ -305,7 +311,7 @@ protected:
     void processFile(EclCompileInstance & info);
     void processReference(EclCompileInstance & instance, const char * queryAttributePath);
     void processBatchFiles();
-    void reportCompileErrors(IErrorReceiver *errs, const char * processName);
+    void reportCompileErrors(IErrorReceiver & errorProcessor, const char * processName);
     void setDebugOption(const char * name, bool value);
     void usage();
 
@@ -343,6 +349,7 @@ protected:
     StringArray inputFileNames;
     StringArray applicationOptions;
     StringArray debugOptions;
+    StringArray warningMappings;
     StringArray compileOptions;
     StringArray linkOptions;
     StringArray libraryPaths;
@@ -662,7 +669,7 @@ ICppCompiler * EclCC::createCompiler(const char * coreName, const char * sourceD
     return compiler.getClear();
 }
 
-void EclCC::reportCompileErrors(IErrorReceiver *errs, const char * processName)
+void EclCC::reportCompileErrors(IErrorReceiver & errorProcessor, const char * processName)
 {
     StringBuffer failText;
     StringBuffer absCCLogName;
@@ -672,7 +679,7 @@ void EclCC::reportCompileErrors(IErrorReceiver *errs, const char * processName)
         absCCLogName = "log file";
 
     failText.appendf("Compile/Link failed for %s (see '%s' for details)",processName,absCCLogName.str());
-    errs->reportError(ERR_INTERNALEXCEPTION, failText.toCharArray(), processName, 0, 0, 0);
+    errorProcessor.reportError(ERR_INTERNALEXCEPTION, failText.toCharArray(), processName, 0, 0, 0);
     try
     {
         StringBuffer s;
@@ -705,7 +712,7 @@ void EclCC::reportCompileErrors(IErrorReceiver *errs, const char * processName)
 
 //=========================================================================================
 
-void EclCC::instantECL(EclCompileInstance & instance, IWorkUnit *wu, const char * queryFullName, IErrorReceiver *errs, const char * outputFile)
+void EclCC::instantECL(EclCompileInstance & instance, IWorkUnit *wu, const char * queryFullName, IErrorReceiver & errorProcessor, const char * outputFile)
 {
     StringBuffer processName(outputFile);
     if (instance.query && containsAnyActions(instance.query))
@@ -717,7 +724,7 @@ void EclCC::instantECL(EclCompileInstance & instance, IWorkUnit *wu, const char
             bool optSaveCpp = optSaveTemps || optNoCompile || wu->getDebugValueBool("saveCppTempFiles", false);
             //New scope - testing things are linked correctly
             {
-                Owned<IHqlExprDllGenerator> generator = createDllGenerator(errs, processName.toCharArray(), NULL, wu, templateDir, optTargetClusterType, this, false);
+                Owned<IHqlExprDllGenerator> generator = createDllGenerator(&errorProcessor, processName.toCharArray(), NULL, wu, templateDir, optTargetClusterType, this, false);
 
                 setWorkunitHash(wu, instance.query);
                 if (!optShared)
@@ -756,7 +763,7 @@ void EclCC::instantECL(EclCompileInstance & instance, IWorkUnit *wu, const char
                     }
 
                     if (!compileOk)
-                        reportCompileErrors(errs, processName);
+                        reportCompileErrors(errorProcessor, processName);
                 }
                 else
                     wu->setState(generateOk ? WUStateCompleted : WUStateFailed);
@@ -790,7 +797,7 @@ void EclCC::instantECL(EclCompileInstance & instance, IWorkUnit *wu, const char
             {
                 StringBuffer exceptionText;
                 e->errorMessage(exceptionText);
-                errs->reportError(ERR_INTERNALEXCEPTION, exceptionText.toCharArray(), queryFullName, 1, 0, 0);
+                errorProcessor.reportError(ERR_INTERNALEXCEPTION, exceptionText.toCharArray(), queryFullName, 1, 0, 0);
             }
             e->Release();
         }
@@ -809,9 +816,9 @@ void EclCC::instantECL(EclCompileInstance & instance, IWorkUnit *wu, const char
 
 //=========================================================================================
 
-void EclCC::getComplexity(IWorkUnit *wu, IHqlExpression * query, IErrorReceiver *errs)
+void EclCC::getComplexity(IWorkUnit *wu, IHqlExpression * query, IErrorReceiver & errs)
 {
-    double complexity = getECLcomplexity(query, errs, wu, optTargetClusterType);
+    double complexity = getECLcomplexity(query, &errs, wu, optTargetClusterType);
     LOG(MCstats, unknownJob, "Complexity = %g", complexity);
 }
 
@@ -930,7 +937,7 @@ void EclCC::evaluateResult(EclCompileInstance & instance)
         query = query->queryChild(0);
     if (query->getOperator()==no_createdictionary)
         query = query->queryChild(0);
-    OwnedHqlExpr folded = foldHqlExpression(query, NULL, HFOthrowerror|HFOloseannotations|HFOforcefold|HFOfoldfilterproject|HFOconstantdatasets);
+    OwnedHqlExpr folded = foldHqlExpression(instance.queryErrorProcessor(), query, NULL, HFOthrowerror|HFOloseannotations|HFOforcefold|HFOfoldfilterproject|HFOconstantdatasets);
     StringBuffer out;
     IValue *result = folded->queryValue();
     if (result)
@@ -998,8 +1005,33 @@ void EclCC::processSingleQuery(EclCompileInstance & instance,
 #endif
 
     Owned<IErrorReceiver> wuErrs = new WorkUnitErrorReceiver(instance.wu, "eclcc");
-    Owned<IErrorReceiver> errs = createCompoundErrorReceiver(instance.errs, wuErrs);
+    Owned<IErrorReceiver> compoundErrs = createCompoundErrorReceiver(&instance.queryErrorProcessor(), wuErrs);
+    Owned<ErrorSeverityMapper> severityMapper = new ErrorSeverityMapper(*compoundErrs);
+
+    //Apply command line mappings...
+    ForEachItemIn(i, warningMappings)
+    {
+        if (!severityMapper->addCommandLineMapping(warningMappings.item(i)))
+            return;
 
+        //Preserve command line mappings in the generated archive
+        if (instance.archive)
+            instance.archive->addPropTree("OnWarning", createPTree())->setProp("@value",warningMappings.item(i));
+    }
+
+    //Apply preserved onwarning mappings from any source archive
+    if (instance.srcArchive)
+    {
+        Owned<IPropertyTreeIterator> iter = instance.srcArchive->getElements("OnWarning");
+        ForEach(*iter)
+        {
+            const char * option = iter->query().queryProp("@value");
+            if (!severityMapper->addCommandLineMapping(option))
+                return;
+        }
+    }
+
+    IErrorReceiver & errorProcessor = *severityMapper;
     //All dlls/exes are essentially cloneable because you may be running multiple instances at once
     //The only exception would be a dll created for a one-time query.  (Currently handled by eclserver.)
     instance.wu->setCloneable(true);
@@ -1012,7 +1044,7 @@ void EclCC::processSingleQuery(EclCompileInstance & instance,
 
     bool withinRepository = (queryAttributePath && *queryAttributePath);
     bool syntaxChecking = instance.wu->getDebugValueBool("syntaxCheck", false);
-    size32_t prevErrs = errs->errCount();
+    size32_t prevErrs = errorProcessor.errCount();
     unsigned startTime = msTick();
     const char * sourcePathname = queryContents ? queryContents->querySourcePath()->str() : NULL;
     const char * defaultErrorPathname = sourcePathname ? sourcePathname : queryAttributePath;
@@ -1048,7 +1080,7 @@ void EclCC::processSingleQuery(EclCompileInstance & instance,
 
         try
         {
-            HqlLookupContext ctx(parseCtx, errs);
+            HqlLookupContext ctx(parseCtx, &errorProcessor);
 
             if (withinRepository)
             {
@@ -1059,11 +1091,11 @@ void EclCC::processSingleQuery(EclCompileInstance & instance,
                 }
 
                 instance.query.setown(getResolveAttributeFullPath(queryAttributePath, LSFpublic, ctx));
-                if (!instance.query && !syntaxChecking && (errs->errCount() == prevErrs))
+                if (!instance.query && !syntaxChecking && (errorProcessor.errCount() == prevErrs))
                 {
                     StringBuffer msg;
                     msg.append("Could not resolve attribute ").append(queryAttributePath);
-                    errs->reportError(3, msg.str(), defaultErrorPathname, 0, 0, 0);
+                    errorProcessor.reportError(3, msg.str(), defaultErrorPathname, 0, 0, 0);
                 }
             }
             else
@@ -1086,7 +1118,7 @@ void EclCC::processSingleQuery(EclCompileInstance & instance,
                 }
             }
 
-            gatherWarnings(ctx.errs, instance.query);
+            gatherParseWarnings(ctx.errs, instance.query);
 
             if (instance.query && !syntaxChecking && !optGenerateMeta && !optEvaluateResult)
                 instance.query.setown(convertAttributeToQuery(instance.query, ctx));
@@ -1099,14 +1131,14 @@ void EclCC::processSingleQuery(EclCompileInstance & instance,
             if (optIncludeMeta || optGenerateMeta)
                 instance.generatedMeta.setown(parseCtx.getMetaTree());
 
-            if (optEvaluateResult && !errs->errCount() && instance.query)
+            if (optEvaluateResult && !errorProcessor.errCount() && instance.query)
                 evaluateResult(instance);
         }
         catch (IException *e)
         {
             StringBuffer s;
             e->errorMessage(s);
-            errs->reportError(3, s.toCharArray(), defaultErrorPathname, 1, 0, 0);
+            errorProcessor.reportError(3, s.toCharArray(), defaultErrorPathname, 1, 0, 0);
             e->Release();
         }
     }
@@ -1114,9 +1146,9 @@ void EclCC::processSingleQuery(EclCompileInstance & instance,
     //Free up the repository (and any cached expressions) as soon as the expression has been parsed
     instance.dataServer.clear();
 
-    if (!syntaxChecking && (errs->errCount() == prevErrs) && (!instance.query || !containsAnyActions(instance.query)))
+    if (!syntaxChecking && (errorProcessor.errCount() == prevErrs) && (!instance.query || !containsAnyActions(instance.query)))
     {
-        errs->reportError(3, "Query is empty", defaultErrorPathname, 1, 0, 0);
+        errorProcessor.reportError(3, "Query is empty", defaultErrorPathname, 1, 0, 0);
         return;
     }
 
@@ -1146,10 +1178,10 @@ void EclCC::processSingleQuery(EclCompileInstance & instance,
             targetFilename.append(".eclout");
     }
 
-    if (errs->errCount() == prevErrs)
+    if (errorProcessor.errCount() == prevErrs)
     {
         const char * queryFullName = NULL;
-        instantECL(instance, instance.wu, queryFullName, errs, targetFilename);
+        instantECL(instance, instance.wu, queryFullName, errorProcessor, targetFilename);
     }
     else
     {
@@ -1202,7 +1234,7 @@ void EclCC::processXmlFile(EclCompileInstance & instance, const char *archiveXML
 
     instance.eclVersion.set(archiveTree->queryProp("@eclVersion"));
     if (optCheckEclVersion)
-        checkEclVersionCompatible(instance.errs, instance.eclVersion);
+        instance.checkEclVersionCompatible();
 
     Owned<IEclSourceCollection> archiveCollection;
     if (archiveTree->getPropBool("@testRemoteInterface", false))
@@ -1287,7 +1319,7 @@ void EclCC::processFile(EclCompileInstance & instance)
     //deployed to the eclcc machine via other means (typically via a version-control system)
     if (!allowAccess("userECL") && (!optQueryRepositoryReference || queryText->length()))
     {
-        instance.errs->reportError(HQLERR_UserCodeNotAllowed, HQLERR_UserCodeNotAllowed_Text, NULL, 1, 0, 0);
+        instance.queryErrorProcessor().reportError(HQLERR_UserCodeNotAllowed, HQLERR_UserCodeNotAllowed_Text, NULL, 1, 0, 0);
     }
     else if (isArchiveQuery(queryTxt))
     {
@@ -1354,7 +1386,7 @@ void EclCC::processFile(EclCompileInstance & instance)
                 Owned<IEclSourceCollection> inputFileCollection = createSingleDefinitionEclCollection(attributePath, queryText);
                 repositories.append(*createRepository(inputFileCollection));
 
-                Owned<IEclSourceCollection> directory = createFileSystemEclCollection(instance.errs, thisDirectory, 0, 0);
+                Owned<IEclSourceCollection> directory = createFileSystemEclCollection(&instance.queryErrorProcessor(), thisDirectory, 0, 0);
                 Owned<IEclRepository> directoryRepository = createRepository(directory, moduleName);
                 Owned<IEclRepository> nested = createNestedRepository(moduleNameId, directoryRepository);
                 repositories.append(*LINK(nested));
@@ -1650,6 +1682,12 @@ void EclCC::setDebugOption(const char * name, bool value)
 }
 
 
+void EclCompileInstance::checkEclVersionCompatible()
+{
+    //Strange function that might modify errorProcessor...
+    ::checkEclVersionCompatible(errorProcessor, eclVersion);
+}
+
 void EclCompileInstance::logStats()
 {
     if (wu && wu->getDebugValueBool("logCompileStats", false))
@@ -1665,12 +1703,12 @@ void EclCompileInstance::logStats()
 
 bool EclCompileInstance::reportErrorSummary()
 {
-    if (errs->errCount() || errs->warnCount())
+    if (errorProcessor->errCount() || errorProcessor->warnCount())
     {
-        fprintf(errout, "%d error%s, %d warning%s\n", errs->errCount(), errs->errCount()<=1 ? "" : "s",
-                errs->warnCount(), errs->warnCount()<=1?"":"s");
+        fprintf(errout, "%d error%s, %d warning%s\n", errorProcessor->errCount(), errorProcessor->errCount()<=1 ? "" : "s",
+                errorProcessor->warnCount(), errorProcessor->warnCount()<=1?"":"s");
     }
-    return errs->errCount() != 0;
+    return errorProcessor->errCount() != 0;
 }
 
 //=========================================================================================
@@ -1917,6 +1955,11 @@ bool EclCC::parseCommandLineOptions(int argc, const char* argv[])
         else if (iter.matchFlag(optWorkUnit, "-wu"))
         {
         }
+        else if (iter.matchFlag(tempArg, "-w"))
+        {
+            //Any other option beginning -wxxx are treated as warning mappings
+            warningMappings.append(tempArg);
+        }
         else if (strcmp(arg, "-")==0)
         {
             inputFileNames.append("stdin:");
@@ -2032,6 +2075,8 @@ const char * const helpText[] = {
     "    -specs file   Read eclcc configuration from specified file",
     "!   -split m:n    Process a subset m of n input files (only with -b option)",
     "    -v --verbose  Output additional tracing information while compiling",
+    "    -wcode=level  Set the severity for a particular warning code",
+    "!                 level=ignore|log|warning|error|fail",
     "    --version     Output version information",
     "!   --timings     Output additional timing information",
     "!",
@@ -2115,7 +2160,7 @@ void EclCC::processBatchedFile(IFile & file, bool multiThreaded)
             //Following only produces output if the system has been compiled with TRANSFORM_STATS defined
             dbglogTransformStats(true);
             if (info.wu &&
-                (info.wu->getDebugValueBool("generatePartialOutputOnError", false) || info.errs->errCount() == 0))
+                (info.wu->getDebugValueBool("generatePartialOutputOnError", false) || info.queryErrorProcessor().errCount() == 0))
             {
                 exportWorkUnitToXMLFile(info.wu, xmlFilename, XML_NoBinaryEncode64, true, false);
                 Owned<IFile> xml = createIFile(xmlFilename);

+ 186 - 134
ecl/hql/hqlerror.cpp

@@ -19,25 +19,107 @@
 #include "hqlerror.hpp"
 #include "hqlerrors.hpp"
 
-void MultiErrorReceiver::reportError(int errNo, const char* msg, const char * filename, int lineno, int column, int position)
+class HQL_API CECLError : public CInterfaceOf<IECLError>
+{
+public:
+    CECLError(ErrorSeverity _severity, int _no, const char* _msg, const char* _filename, int _lineno, int _column, int _position);
+
+    virtual int             errorCode() const { return no; }
+    virtual StringBuffer &  errorMessage(StringBuffer & ret) const { return ret.append(msg); }
+    virtual MessageAudience errorAudience() const { return MSGAUD_user; }
+    virtual const char* getFilename() const { return filename; }
+    virtual WarnErrorCategory getCategory() const { return WECunknown; }
+    virtual int getLine() const { return lineno; }
+    virtual int getColumn() const { return column; }
+    virtual int getPosition() const { return position; }
+    virtual StringBuffer& toString(StringBuffer&) const;
+    virtual ErrorSeverity getSeverity() const { return severity; }
+    virtual IECLError * cloneSetSeverity(ErrorSeverity _severity) const;
+
+protected:
+    ErrorSeverity severity;
+    int no;
+    StringAttr msg;
+    StringAttr filename;
+    int lineno;
+    int column;
+    int position;
+};
+
+CECLError::CECLError(ErrorSeverity _severity, int _no, const char* _msg, const char* _filename, int _lineno, int _column, int _position):
+  severity(_severity), msg(_msg), filename(_filename)
+{
+    no = _no;
+    lineno = _lineno;
+    column = _column;
+    position = _position;
+}
+
+
+StringBuffer& CECLError::toString(StringBuffer& buf) const
+{
+    buf.append(filename);
+
+    if(lineno && column)
+        buf.append('(').append(lineno).append(',').append(column).append(')');
+    buf.append(" : ");
+
+    buf.append(no).append(": ").append(msg);
+    return buf;
+}
+
+IECLError * CECLError::cloneSetSeverity(ErrorSeverity newSeverity) const
+{
+    return new CECLError(newSeverity,
+                         errorCode(), msg, filename,
+                         getLine(), getColumn(), getPosition());
+}
+
+extern HQL_API IECLError *createECLError(ErrorSeverity severity, int errNo, const char *msg, const char * filename, int lineno, int column, int pos)
+{
+    return new CECLError(severity,errNo,msg,filename,lineno,column,pos);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+
+void IErrorReceiver::reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int position)
 {
     Owned<IECLError> err = createECLError(errNo,msg,filename,lineno,column,position);
     report(err);
 }
 
-void MultiErrorReceiver::reportWarning(int warnNo, const char* msg, const char * filename, int lineno, int column, int position)
+void IErrorReceiver::reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int position)
 {
-    Owned<IECLError> warn = createECLWarning(warnNo,msg,filename,lineno,column,position);
+    Owned<IECLError> warn = createECLError(SeverityWarning,warnNo,msg,filename,lineno,column,position);
     report(warn);
 }
 
-void MultiErrorReceiver::report(IECLError* error) 
+//---------------------------------------------------------------------------------------------------------------------
+
+void ErrorReceiverSink::report(IECLError* error)
 {
-    msgs.append(*LINK(error)); 
-    if (error->isError())
-        errs++;
-    else
+    switch (error->getSeverity())
+    {
+    case SeverityWarning:
         warns++;
+        break;
+    case SeverityError:
+    case SeverityFatal:
+        errs++;
+        break;
+    }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+
+
+
+void MultiErrorReceiver::report(IECLError* error)
+{
+    ErrorReceiverSink::report(error);
+
+    msgs.append(*LINK(error));
+
     StringBuffer msg;
     DBGLOG("reportError(%d:%d) : %s", error->getLine(), error->getColumn(), error->errorMessage(msg).str());
 }
@@ -58,48 +140,12 @@ IECLError *MultiErrorReceiver::firstError()
     ForEachItemIn(i, msgs)
     {
         IECLError* error = item(i);
-        if (error->isError())
+        if (isError(error->getSeverity()))
             return error;
     }
     return NULL;
 }
 
-CECLError::CECLError(bool _isError, int _no, const char* _msg, const char* _filename, int _lineno, int _column, int _position):
-  msg(_msg), filename(_filename)
-{
-    iserror = _isError;
-    no = _no;
-    lineno = _lineno;
-    column = _column;
-    position = _position;
-}
-
-
-StringBuffer& CECLError::toString(StringBuffer& buf)
-{
-    buf.append(filename);
-    
-    if(lineno && column)
-        buf.append('(').append(lineno).append(',').append(column).append(')');
-    buf.append(" : ");
-
-    buf.append(no).append(": ").append(msg);
-    return buf;
-}
-
-extern HQL_API IECLError *createECLError(bool isError, int errNo, const char *msg, const char * filename, int lineno, int column, int pos)
-{
-    return new CECLError(isError,errNo,msg,filename,lineno,column,pos);
-}
-
-extern HQL_API IECLError * changeErrorType(bool isError, IECLError * error)
-{
-    StringBuffer msg;
-    return new CECLError(isError,
-                         error->errorCode(), error->errorMessage(msg).str(), error->getFilename(), 
-                         error->getLine(), error->getColumn(), error->getPosition());
-}
-
 extern HQL_API void reportErrors(IErrorReceiver & receiver, IECLErrorArray & errors)
 {
     ForEachItemIn(i, errors)
@@ -108,43 +154,44 @@ extern HQL_API void reportErrors(IErrorReceiver & receiver, IECLErrorArray & err
 
 //---------------------------------------------------------------------------------------------------------------------
 
-class HQL_API FileErrorReceiver : public CInterface, implements IErrorReceiver
+class HQL_API FileErrorReceiver : public ErrorReceiverSink
 {
 public:
-    IMPLEMENT_IINTERFACE;
-
-    int errcount;
-    int warncount;
-    FILE *f;
-
     FileErrorReceiver(FILE *_f)
     {
-        errcount = 0;
-        warncount = 0;
         f = _f;
     }
 
-    virtual void reportError(int errNo, const char *msg, const char * filename, int _lineno, int _column, int _pos)
+    virtual void report(IECLError* error)
     {
-        errcount++;
-        if (!filename) filename = "";
-        fprintf(f, "%s(%d,%d): error C%04d: %s\n", filename, _lineno, _column, errNo, msg);
-    }
+        ErrorReceiverSink::report(error);
 
-    virtual void reportWarning(int warnNo, const char *msg, const char * filename, int _lineno, int _column, int _pos)
-    {
-        warncount++;
-        if (!filename) filename = *unknownAtom;
-        fprintf(f, "%s(%d,%d): warning C%04d: %s\n", filename, _lineno, _column, warnNo, msg);
-    }
+        ErrorSeverity severity = error->getSeverity();
+        if (severity <= SeverityInfo)
+            return;
 
-    virtual void report(IECLError* e)
-    {
-        expandReportError(this, e);
+        unsigned code = error->errorCode();
+        const char * filename = error->getFilename();
+        unsigned line = error->getLine();
+        unsigned column = error->getColumn();
+        unsigned position = error->getPosition();
+
+        StringBuffer msg;
+        error->errorMessage(msg);
+        if (isError(severity))
+        {
+            if (!filename) filename = "";
+            fprintf(f, "%s(%d,%d): error C%04d: %s\n", filename, line, column, code, msg.str());
+        }
+        else
+        {
+            if (!filename) filename = *unknownAtom;
+            fprintf(f, "%s(%d,%d): warning C%04d: %s\n", filename, line, column, code, msg.str());
+        }
     }
 
-    virtual size32_t errCount() { return errcount; };
-    virtual size32_t warnCount() { return warncount; };
+protected:
+    FILE *f;
 };
 
 extern HQL_API IErrorReceiver *createFileErrorReceiver(FILE *f)
@@ -154,18 +201,31 @@ extern HQL_API IErrorReceiver *createFileErrorReceiver(FILE *f)
 
 //---------------------------------------------------------------------------------------------------------------------
 
-void ThrowingErrorReceiver::reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int pos)
+class HQL_API ThrowingErrorReceiver : public ErrorReceiverSink
 {
-    throw createECLError(errNo, msg, filename, lineno, column, pos);
-}
+    virtual void report(IECLError* error);
+};
 
 void ThrowingErrorReceiver::report(IECLError* error)
 {
-    expandReportError(this, error);
+    throw error;
 }
 
-void ThrowingErrorReceiver::reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
+IErrorReceiver * createThrowingErrorReceiver()
+{
+    return new ThrowingErrorReceiver;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+
+class HQL_API NullErrorReceiver : public ErrorReceiverSink
 {
+public:
+};
+
+IErrorReceiver * createNullErrorReceiver()
+{
+    return new NullErrorReceiver;
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -189,85 +249,77 @@ void reportError(IErrorReceiver * errors, int errNo, const ECLlocation & loc, co
 }
 
 
-void expandReportError(IErrorReceiver * errors, IECLError* error)
-{
-    StringBuffer msg;
-    error->errorMessage(msg);
-    if (error->isError())
-        errors->reportError(error->errorCode(), msg.str(), error->getFilename(), error->getLine(), error->getColumn(), error->getPosition());
-    else
-        errors->reportWarning(error->errorCode(), msg.str(), error->getFilename(), error->getLine(), error->getColumn(), error->getPosition());
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------
-
-class IndirectErrorReceiver : public CInterface, implements IErrorReceiver
+class ErrorInserter : public IndirectErrorReceiver
 {
 public:
-    IndirectErrorReceiver(IErrorReceiver * _prev) : prev(_prev) {}
-    IMPLEMENT_IINTERFACE
+    ErrorInserter(IErrorReceiver & _prev, IECLError * _error) : IndirectErrorReceiver(_prev), error(_error) {}
 
-    virtual void reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int pos)
-    {
-        prev->reportError(errNo, msg, filename, lineno, column, pos);
-    }
-    virtual void report(IECLError* err)
-    {
-        prev->report(err);
-    }
-    virtual void reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
-    {
-        prev->reportWarning(warnNo, msg, filename, lineno, column, pos);
-    }
-    virtual size32_t errCount()
+    virtual void report(IECLError* error)
     {
-        return prev->errCount();
+        if (isError(error->getSeverity()))
+            flush();
+        IndirectErrorReceiver::report(error);
     }
-    virtual size32_t warnCount()
+
+protected:
+    void flush()
     {
-        return prev->warnCount();
+        if (error)
+        {
+            IndirectErrorReceiver::report(error);
+            error.clear();
+        }
     }
 
 protected:
-    Linked<IErrorReceiver> prev;
+    Linked<IECLError> error;
 };
 
-class ErrorInserter : public IndirectErrorReceiver
+//---------------------------------------------------------------------------------------------------------------------
+
+class AbortingErrorReceiver : public IndirectErrorReceiver
 {
 public:
-    ErrorInserter(IErrorReceiver * _prev, IECLError * _error) : IndirectErrorReceiver(_prev), error(_error) {}
+    AbortingErrorReceiver(IErrorReceiver & _prev) : IndirectErrorReceiver(_prev) {}
 
-    virtual void reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int pos)
+    virtual void report(IECLError* error)
     {
-        flush();
-        IndirectErrorReceiver::reportError(errNo, msg, filename, lineno, column, pos);
-    }
-    virtual void report(IECLError* err)
-    {
-        flush();
-        IndirectErrorReceiver::report(err);
-    }
-    virtual void reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
-    {
-        flush();
-        IndirectErrorReceiver::reportWarning(warnNo, msg, filename, lineno, column, pos);
+        Owned<IECLError> mappedError = prevErrorProcessor->mapError(error);
+        prevErrorProcessor->report(mappedError);
+        if (isError(mappedError->getSeverity()))
+            throw MakeStringExceptionDirect(HQLERR_ErrorAlreadyReported, "");
     }
+};
 
-protected:
-    void flush()
+IErrorReceiver * createAbortingErrorReceiver(IErrorReceiver & prev)
+{
+    return new AbortingErrorReceiver(prev);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+
+class DedupingErrorReceiver : public IndirectErrorReceiver
+{
+public:
+    DedupingErrorReceiver(IErrorReceiver & _prev) : IndirectErrorReceiver(_prev) {}
+
+    virtual void report(IECLError* error)
     {
-        if (error)
-        {
-            IndirectErrorReceiver::report(error);
-            error.clear();
-        }
+        if (errors.contains(*error))
+            return;
+        errors.append(*LINK(error));
+        IndirectErrorReceiver::report(error);
     }
 
-protected:
-    Linked<IECLError> error;
+private:
+    Array errors;
 };
 
+IErrorReceiver * createDedupingErrorReceiver(IErrorReceiver & prev)
+{
+    return new DedupingErrorReceiver(prev);
+}
+
 //---------------------------------------------------------------------------------------------------------------------
 
 void checkEclVersionCompatible(Shared<IErrorReceiver> & errors, const char * eclVersion)
@@ -291,8 +343,8 @@ void checkEclVersionCompatible(Shared<IErrorReceiver> & errors, const char * ecl
             {
                 //This adds the warning if any other warnings occur.
                 VStringBuffer msg("Mismatch in subminor version number (%s v %s)", eclVersion, LANGUAGE_VERSION);
-                Owned<IECLError> warning = createECLWarning(HQLERR_VersionMismatch, msg.str(), NULL, 0, 0);
-                errors.setown(new ErrorInserter(errors, warning));
+                Owned<IECLError> warning = createECLError(SeverityWarning, HQLERR_VersionMismatch, msg.str(), NULL, 0, 0);
+                errors.setown(new ErrorInserter(*errors, warning));
             }
         }
     }

+ 98 - 62
ecl/hql/hqlerror.hpp

@@ -19,102 +19,138 @@
 
 #include "jhash.hpp"
 #include "jexcept.hpp"
-#include "hqlexpr.hpp"
+#include "hql.hpp"
 
-class HQL_API CECLError : public CInterface, implements IECLError
-{
-public:
-    IMPLEMENT_IINTERFACE;
+#define HQLERR_ErrorAlreadyReported             4799            // special case...
 
-    CECLError(bool _isError, int _no, const char* _msg, const char* _filename, int _lineno, int _column, int _position);
+enum ErrorSeverity
+{
+    SeverityIgnore,
+    SeverityInfo,
+    SeverityWarning,
+    SeverityError,    // a warning treated as an error
+    SeverityFatal,      // a fatal error - can't be mapped to anything else
+    SeverityUnknown,
+};
 
-    virtual int             errorCode() const { return no; }
-    virtual StringBuffer &  errorMessage(StringBuffer & ret) const { return ret.append(msg); }
-    virtual MessageAudience errorAudience() const { return MSGAUD_user; }
-    virtual const char* getFilename() { return filename; }
-    virtual int getLine() { return lineno; }
-    virtual int getColumn() { return column; }
-    virtual int getPosition() { return position; }
-    virtual StringBuffer& toString(StringBuffer&);
-    virtual bool isError() { return iserror; }
+inline bool isError(ErrorSeverity severity) { return severity >= SeverityError; }
+inline bool isFatal(ErrorSeverity severity) { return severity == SeverityFatal; }
 
-protected:
-    bool iserror;
-    int no;
-    StringAttr msg;
-    StringAttr filename;
-    int lineno;
-    int column;
-    int position;
+//TBD in a separate commit - add support for warnings to be associated with different categories
+enum WarnErrorCategory
+{
+    WECunknown,
 };
 
-class HQL_API MultiErrorReceiver : public CInterface, implements IErrorReceiver
+interface HQL_API IECLError: public IException
 {
 public:
-    MultiErrorReceiver() { errs = warns = 0; }
+    virtual const char* getFilename() const = 0;
+    virtual WarnErrorCategory getCategory() const = 0;
+    virtual int getLine() const = 0;
+    virtual int getColumn() const = 0;
+    virtual int getPosition() const = 0;
+    virtual StringBuffer& toString(StringBuffer&) const = 0;
+    virtual ErrorSeverity getSeverity() const = 0;
+    virtual IECLError * cloneSetSeverity(ErrorSeverity _severity) const = 0;
+};
+inline bool isFatal(IECLError * error) { return isFatal(error->getSeverity()); }
 
-    virtual void reportError(int errNo, const char* msg, const char * filename=0, int lineno=0, int column=0, int position=1);
-    virtual void reportWarning(int warnNo, const char* msg, const char * filename, int lineno, int column, int position);
-    virtual void report(IECLError* error);
+interface HQL_API IErrorReceiver : public IInterface
+{
+    virtual void report(IECLError* error) = 0;
+    virtual IECLError * mapError(IECLError * error) = 0;
+    virtual size32_t errCount() = 0;
+    virtual size32_t warnCount() = 0;
+
+    //global helper functions
+    void reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int pos);
+    void reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos);
+};
 
-    size32_t length() { return errCount() + warnCount();}
-    size32_t errCount() { return errs; }
-    size32_t warnCount() { return warns; }
-    IECLError* item(size32_t index) { return &msgs.item(index); }
-    IECLError* firstError();
-    StringBuffer& toString(StringBuffer&);
-    void clear() { msgs.kill(); }
-    IMPLEMENT_IINTERFACE;
+typedef IArrayOf<IECLError> IECLErrorArray;
+
+
+//---------------------------------------------------------------------------------------------------------------------
+
+class HQL_API ErrorReceiverSink : public CInterfaceOf<IErrorReceiver>
+{
+public:
+    ErrorReceiverSink() { errs = warns = 0; }
+
+    virtual IECLError * mapError(IECLError * error) { return LINK(error); }
+    virtual void report(IECLError* err);
+    virtual size32_t errCount() { return errs; }
+    virtual size32_t warnCount() { return warns; }
 
 private:
-    IECLErrorArray msgs;
     unsigned errs;
     unsigned warns;
 };
 
-class HQL_API ThrowingErrorReceiver : public CInterface, implements IErrorReceiver
+//---------------------------------------------------------------------------------------------------------------------
+
+class IndirectErrorReceiver : public CInterfaceOf<IErrorReceiver>
 {
-    IMPLEMENT_IINTERFACE
+public:
+    IndirectErrorReceiver(IErrorReceiver & _prev) : prevErrorProcessor(&_prev) {}
+
+    virtual void report(IECLError* error)
+    {
+        prevErrorProcessor->report(error);
+    }
+    virtual IECLError * mapError(IECLError * error)
+    {
+        return prevErrorProcessor->mapError(error);
+    }
+    virtual size32_t errCount()
+    {
+        return prevErrorProcessor->errCount();
+    }
+    virtual size32_t warnCount()
+    {
+        return prevErrorProcessor->warnCount();
+    }
 
-    virtual void reportError(int errNo, const char *msg, const char *filename=NULL, int lineno=0, int column=0, int pos=0);
-    virtual void report(IECLError* error);
-    virtual void reportWarning(int warnNo, const char *msg, const char *filename=NULL, int lineno=0, int column=0, int pos=0);
-    virtual size32_t errCount() { return 0; }
-    virtual size32_t warnCount() { return 0; }
+protected:
+    Linked<IErrorReceiver> prevErrorProcessor;
 };
 
-class HQL_API NullErrorReceiver : public CInterface, implements IErrorReceiver
+//---------------------------------------------------------------------------------------------------------------------
+
+class HQL_API MultiErrorReceiver : public ErrorReceiverSink
 {
 public:
-    IMPLEMENT_IINTERFACE;
+    MultiErrorReceiver() {}
+
+    virtual void report(IECLError* err);
 
-    void reportError(int errNo, const char *msg,  const char * filename, int _lineno, int _column, int _pos) { numErrors++; }
-    void reportWarning(int warnNo, const char *msg,  const char * filename, int _lineno, int _column, int _pos) { numWarnings++; }
-    void report(IECLError* err) { if (err->isError()) numErrors++; else numWarnings++; }
-    virtual size32_t errCount() { return numErrors; };
-    virtual size32_t warnCount() { return numWarnings; };
+    size32_t length() { return errCount() + warnCount();}
+    IECLError* item(size32_t index) { return &msgs.item(index); }
+    IECLError* firstError();
+    StringBuffer& toString(StringBuffer& out);
+    void clear() { msgs.kill(); }
 
 private:
-    unsigned numErrors;
-    unsigned numWarnings;
+    IECLErrorArray msgs;
 };
 
+//---------------------------------------------------------------------------------------------------------------------
 
-extern HQL_API IECLError *createECLError(bool isError, int errNo, const char *msg, const char *filename, int lineno=0, int column=0, int pos=0);
+extern HQL_API IECLError *createECLError(ErrorSeverity severity, int errNo, const char *msg, const char *filename, int lineno=0, int column=0, int pos=0);
 inline IECLError * createECLError(int errNo, const char *msg, const char *filename, int lineno=0, int column=0, int pos=0)
 {
-    return createECLError(true, errNo, msg, filename, lineno, column, pos);
-}
-inline IECLError *createECLWarning(int errNo, const char *msg, const char *filename, int lineno=0, int column=0, int pos=0)
-{
-    return createECLError(false, errNo, msg, filename, lineno, column, pos);
+    return createECLError(SeverityFatal, errNo, msg, filename, lineno, column, pos);
 }
-extern HQL_API IECLError *changeErrorType(bool isError, IECLError * error);
 extern HQL_API void reportErrors(IErrorReceiver & receiver, IECLErrorArray & errors);
 void HQL_API reportErrorVa(IErrorReceiver * errors, int errNo, const ECLlocation & loc, const char* format, va_list args);
 void HQL_API reportError(IErrorReceiver * errors, int errNo, const ECLlocation & loc, const char * format, ...) __attribute__((format(printf, 4, 5)));
-void HQL_API expandReportError(IErrorReceiver * errors, IECLError* error);
-extern HQL_API IErrorReceiver *createFileErrorReceiver(FILE *f);
+
+extern HQL_API IErrorReceiver * createFileErrorReceiver(FILE *f);
+extern HQL_API IErrorReceiver * createNullErrorReceiver();
+extern HQL_API IErrorReceiver * createThrowingErrorReceiver();
+extern HQL_API IErrorReceiver * createAbortingErrorReceiver(IErrorReceiver & prev);
+extern HQL_API IErrorReceiver * createDedupingErrorReceiver(IErrorReceiver & prev);
 
 extern HQL_API void checkEclVersionCompatible(Shared<IErrorReceiver> & errors, const char * eclVersion);
 

+ 6 - 60
ecl/hql/hqlexpr.cpp

@@ -8173,7 +8173,6 @@ extern HQL_API void ensureSymbolsDefined(IHqlExpression * scopeExpr, HqlLookupCo
 
 void exportSymbols(IPropertyTree* data, IHqlScope * scope, HqlLookupContext & ctx)
 {
-    ThrowingErrorReceiver errs;
     scope->ensureSymbolsDefined(ctx); 
 
     data->setProp("@name", scope->queryFullName());
@@ -9104,8 +9103,8 @@ IHqlScope * CHqlVirtualScope::deriveConcreteScope()
 void CHqlVirtualScope::resolveUnboundSymbols()
 {
     IHqlExpression * virtualAttr = queryAttribute(_virtualSeq_Atom);
-    ThrowingErrorReceiver errors;
-    HqlDummyLookupContext localCtx(&errors);
+    Owned<IErrorReceiver> errorReporter = createThrowingErrorReceiver();
+    HqlDummyLookupContext localCtx(errorReporter);
     SymbolTableIterator iter(symbols);
     HqlExprArray defines;
     ForEach(iter)
@@ -9256,8 +9255,8 @@ IHqlScope * CHqlForwardScope::queryResolvedScope(HqlLookupContext * context)
     {
         //Generally we should have a lookup context passed in so the archive is updated correctly
         //But currently painful in one context, so allow it to be omitted.
-        ThrowingErrorReceiver errors;
-        HqlDummyLookupContext localCtx(&errors);
+        Owned<IErrorReceiver> errorReporter = createThrowingErrorReceiver();
+        HqlDummyLookupContext localCtx(errorReporter);
         HqlLookupContext * activeContext = context ? context : &localCtx;
         HqlExprArray syms;
         getSymbols(syms);
@@ -15701,8 +15700,8 @@ extern HQL_API IPropertyTree * gatherAttributeDependencies(IEclRepository * data
     HqlParseContext parseCtx(dataServer, NULL);
     parseCtx.nestedDependTree.setown(createPTree("Dependencies"));
 
-    NullErrorReceiver errorHandler;
-    HqlLookupContext ctx(parseCtx, &errorHandler);
+    Owned<IErrorReceiver> errorHandler = createNullErrorReceiver();
+    HqlLookupContext ctx(parseCtx, errorHandler);
     if (items && *items)
     {
         loop
@@ -15747,49 +15746,6 @@ IHqlExpression * createGroupedAttribute(IHqlExpression * grouping)
 }
 
 
-static HqlTransformerInfo warningCollectingTransformerInfo("WarningCollectingTransformer");
-class WarningCollectingTransformer : public QuickHqlTransformer
-{
-public:
-    WarningCollectingTransformer(IErrorReceiver & _errs) : QuickHqlTransformer(warningCollectingTransformerInfo, &_errs) { }
-
-    virtual void doAnalyse(IHqlExpression * expr)
-    {
-        switch (expr->getAnnotationKind())
-        {
-        case annotate_meta:
-            collector.processMetaAnnotation(expr);
-            break;
-        case annotate_warning:
-            collector.processWarningAnnotation(expr);
-            break;
-        case annotate_symbol:
-            {
-                WarningProcessor::OnWarningState saved;
-                collector.pushSymbol(saved, expr);
-                QuickHqlTransformer::doAnalyse(expr);
-                collector.popSymbol(saved);
-                return;
-            }
-        case annotate_none:
-            collector.checkForGlobalOnWarning(expr);
-            break;
-        }
-        QuickHqlTransformer::doAnalyse(expr);
-    }
-
-    void report(IHqlExpression * expr)
-    {
-        analyse(expr);
-        collector.report(*errors);
-    }
-
-
-protected:
-    WarningProcessor collector;
-};
-
-
 IHqlExpression * createTypeTransfer(IHqlExpression * expr, ITypeInfo * _newType)
 {
     Owned<ITypeInfo> newType = _newType;
@@ -15809,16 +15765,6 @@ IHqlExpression * createTypeTransfer(IHqlExpression * expr, ITypeInfo * _newType)
 }
 
 
-void gatherWarnings(IErrorReceiver * errs, IHqlExpression * expr)
-{
-    if (!errs || !expr)
-        return;
-
-    WarningCollectingTransformer collector(*errs);
-    collector.report(expr);
-}
-
-
 //Make sure the expression doesn't get leaked if an exception occurs when closing it.
 IHqlExpression * closeAndLink(IHqlExpression * expr)
 {

+ 1 - 23
ecl/hql/hqlexpr.hpp

@@ -62,6 +62,7 @@
 #include "jprop.hpp"
 #include "jptree.hpp"
 #include "defvalue.hpp"
+#include "hqlerror.hpp"
 
 interface IXmlScope;
 interface IHqlScope;
@@ -805,28 +806,6 @@ enum ExprPropKind
     typedef unsigned short node_operator;
 #endif
 
-interface HQL_API IECLError: public IException
-{
-public:
-    virtual const char* getFilename() = 0;
-    virtual int getLine() = 0;
-    virtual int getColumn() = 0;
-    virtual int getPosition() = 0;
-    virtual StringBuffer& toString(StringBuffer&) = 0;
-    virtual bool isError() = 0;
-};
-
-interface HQL_API IErrorReceiver : public IInterface
-{
-    virtual void reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int pos) = 0;
-    virtual void report(IECLError* err) = 0;
-    virtual void reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos) = 0;
-    virtual size32_t errCount() = 0;
-    virtual size32_t warnCount() = 0;
-};
-
-typedef IArrayOf<IECLError> IECLErrorArray;
-
 interface IHqlSimpleScope : public IInterface
 {
     virtual IHqlExpression *lookupSymbol(IIdAtom * name) = 0;
@@ -1816,7 +1795,6 @@ inline int boolToInt(bool x)                    { return x ? 1 : 0; }
 extern HQL_API IHqlExpression * createFunctionDefinition(IIdAtom * name, IHqlExpression * value, IHqlExpression * parms, IHqlExpression * defaults, IHqlExpression * attrs);
 extern HQL_API IHqlExpression * createFunctionDefinition(IIdAtom * name, HqlExprArray & args);
 extern HQL_API IHqlExpression * queryNonDelayedBaseAttribute(IHqlExpression * expr);
-extern HQL_API void gatherWarnings(IErrorReceiver * errs, IHqlExpression * expr);
 
 #define NO_AGGREGATE        \
          no_count:          \

+ 15 - 10
ecl/hql/hqlfold.cpp

@@ -4854,8 +4854,7 @@ IHqlExpression * CExprFolderTransformer::doFoldTransformed(IHqlExpression * unfo
             if (expr->queryChild(0)->getOperator() == no_list)
             {
                 ECLlocation dummyLocation(0, 0, 0, NULL);
-                ThrowingErrorReceiver errorReporter;
-                OwnedHqlExpr inlineTable = convertTempTableToInlineTable(errorReporter, dummyLocation, expr);
+                OwnedHqlExpr inlineTable = convertTempTableToInlineTable(errorProcessor, dummyLocation, expr);
                 if (expr != inlineTable)
                     return inlineTable.getClear();
             }
@@ -4888,8 +4887,8 @@ FolderTransformInfo::~FolderTransformInfo()
 }
 
 static HqlTransformerInfo cExprFolderTransformerInfo("CExprFolderTransformer");
-CExprFolderTransformer::CExprFolderTransformer(ITemplateContext * _templateContext, unsigned _options)
-: NewHqlTransformer(cExprFolderTransformerInfo), templateContext(_templateContext)
+CExprFolderTransformer::CExprFolderTransformer(IErrorReceiver & _errorProcessor, ITemplateContext * _templateContext, unsigned _options)
+: NewHqlTransformer(cExprFolderTransformerInfo), templateContext(_templateContext), errorProcessor(_errorProcessor)
 {
     foldOptions = _options;
 }
@@ -6044,7 +6043,13 @@ IHqlExpression * CExprFolderTransformer::transformExpanded(IHqlExpression * expr
 
 //---------------------------------------------------------------------------
 
-IHqlExpression * foldHqlExpression(IHqlExpression * expr, ITemplateContext *templateContext, unsigned foldOptions)
+IHqlExpression * foldHqlExpression(IHqlExpression * expr)
+{
+    Owned<IErrorReceiver> errorProcessor = createNullErrorReceiver();
+    return foldHqlExpression(*errorProcessor, expr);
+}
+
+IHqlExpression * foldHqlExpression(IErrorReceiver & errorProcessor, IHqlExpression * expr, ITemplateContext *templateContext, unsigned foldOptions)
 {
     if (!expr)
         return NULL;
@@ -6065,7 +6070,7 @@ IHqlExpression * foldHqlExpression(IHqlExpression * expr, ITemplateContext *temp
         break;
     }
 
-    CExprFolderTransformer folder(templateContext, foldOptions);
+    CExprFolderTransformer folder(errorProcessor, templateContext, foldOptions);
 
 #if 0
     dbglogExpr(expr);
@@ -6080,12 +6085,12 @@ IHqlExpression * foldHqlExpression(IHqlExpression * expr, ITemplateContext *temp
     return ret;
 }
 
-IHqlExpression * foldScopedHqlExpression(IHqlExpression * dataset, IHqlExpression * expr, unsigned foldOptions)
+IHqlExpression * foldScopedHqlExpression(IErrorReceiver & errorProcessor, IHqlExpression * dataset, IHqlExpression * expr, unsigned foldOptions)
 {
     if (!expr)
         return NULL;
 
-    CExprFolderTransformer folder(NULL, foldOptions);
+    CExprFolderTransformer folder(errorProcessor, NULL, foldOptions);
 
     if (dataset)
         folder.setScope(dataset);
@@ -6096,9 +6101,9 @@ IHqlExpression * foldScopedHqlExpression(IHqlExpression * dataset, IHqlExpressio
 }
 
 
-void foldHqlExpression(HqlExprArray & tgt, HqlExprArray & src, unsigned foldOptions)
+void foldHqlExpression(IErrorReceiver & errorProcessor, HqlExprArray & tgt, HqlExprArray & src, unsigned foldOptions)
 {
-    CExprFolderTransformer folder(NULL, foldOptions);
+    CExprFolderTransformer folder(errorProcessor, NULL, foldOptions);
     folder.transformRoot(src, tgt);
 }
 

+ 4 - 3
ecl/hql/hqlfold.hpp

@@ -51,9 +51,10 @@ extern HQLFOLD_API IHqlExpression * foldConstantOperator(IHqlExpression * expr,
 extern HQLFOLD_API IHqlExpression * quickFoldExpression(IHqlExpression * expr, ITemplateContext *context=NULL, unsigned options=0);
 extern HQLFOLD_API void quickFoldExpressions(HqlExprArray & target, const HqlExprArray & source, ITemplateContext *context, unsigned options);
 
-extern HQLFOLD_API IHqlExpression * foldHqlExpression(IHqlExpression * expr, ITemplateContext *context=NULL, unsigned options=0);
-extern HQLFOLD_API IHqlExpression * foldScopedHqlExpression(IHqlExpression * dataset, IHqlExpression * expr, unsigned options=0);
-extern HQLFOLD_API void foldHqlExpression(HqlExprArray & tgt, HqlExprArray & src, unsigned options=0);
+extern HQLFOLD_API IHqlExpression * foldHqlExpression(IHqlExpression * expr); // No errors reported.
+extern HQLFOLD_API IHqlExpression * foldHqlExpression(IErrorReceiver & errorProcessor, IHqlExpression * expr, ITemplateContext *context=NULL, unsigned options=0);
+extern HQLFOLD_API IHqlExpression * foldScopedHqlExpression(IErrorReceiver & errorProcessor, IHqlExpression * dataset, IHqlExpression * expr, unsigned options=0);
+extern HQLFOLD_API void foldHqlExpression(IErrorReceiver & errorProcessor, HqlExprArray & tgt, HqlExprArray & src, unsigned options=0);
 extern HQLFOLD_API IHqlExpression * lowerCaseHqlExpr(IHqlExpression * expr);
 extern HQLFOLD_API IHqlExpression * foldExprIfConstant(IHqlExpression * expr);
 

+ 2 - 1
ecl/hql/hqlfold.ipp

@@ -67,7 +67,7 @@ class CExprFolderTransformer : public FOLD_PARENT, public NullFolderMixin
 {
     typedef FOLD_PARENT PARENT;
 public:
-    CExprFolderTransformer(ITemplateContext *templateContext, unsigned _options);
+    CExprFolderTransformer(IErrorReceiver & _errorProcessor, ITemplateContext *templateContext, unsigned _options);
 
     void setScope(IHqlExpression * expr)                { stopDatasetTransform(expr); }
 
@@ -112,6 +112,7 @@ private:
 
 protected:
     ITemplateContext *templateContext;
+    IErrorReceiver & errorProcessor;
     unsigned foldOptions;
     StringBuffer nodeText[2];
 };

+ 5 - 3
ecl/hql/hqlgram.hpp

@@ -577,10 +577,11 @@ public:
     void reportWarningVa(int errNo, const attribute& a, const char* format, va_list args);
     void reportWarning(int warnNo, const char *msg, int lineno, int column);
     void addResult(IHqlExpression *query, const attribute& errpos);
-    bool okToReportError(const ECLlocation & pos);
-// interface IErrorReceiver
+
+    // interface IErrorReceiver
     virtual void reportError(int errNo, const char *msg, const char *filename=NULL, int lineno=0, int column=0, int pos=0);
-    virtual void report(IECLError*);
+    virtual void report(IECLError * error);
+    virtual IECLError * mapError(IECLError * error);
     virtual void reportWarning(int warnNo, const char *msg, const char *filename=NULL, int lineno=0, int column=0, int pos=0);
     virtual size32_t errCount();
     virtual size32_t warnCount();
@@ -834,6 +835,7 @@ protected:
     bool legacyWhenSemantics;
     bool isQuery;
     bool parseConstantText;
+    bool expandingMacroPosition;
     unsigned m_maxErrorsAllowed;
 
     IECLErrorArray pendingWarnings;

+ 9 - 7
ecl/hql/hqlgram.y

@@ -1666,9 +1666,11 @@ failure
     ;
 
 warningAction
-    : TOK_IGNORE        {   $$.setExpr(createAttribute(ignoreAtom), $1); }
+    : TOK_LOG           {   $$.setExpr(createAttribute(logAtom), $1); }
+    | TOK_IGNORE        {   $$.setExpr(createAttribute(ignoreAtom), $1); }
     | TOK_WARNING       {   $$.setExpr(createAttribute(warningAtom), $1); }
     | TOK_ERROR         {   $$.setExpr(createAttribute(errorAtom), $1); }
+    | FAIL              {   $$.setExpr(createAttribute(failAtom), $1); }
     ;
 
 optPersistOpts
@@ -5187,7 +5189,7 @@ compareExpr
                             parser->normalizeExpression($4, type_dictionary, false);
                             OwnedHqlExpr dict = $4.getExpr();
                             OwnedHqlExpr row = createValue(no_rowvalue, makeNullType(), $1.getExpr());
-                            OwnedHqlExpr indict = createINDictExpr(parser->errorHandler, $4.pos, row, dict);
+                            OwnedHqlExpr indict = createINDictExpr(*parser->errorHandler, $4.pos, row, dict);
                             $$.setExpr(getInverse(indict));
                             $$.setPosition($3);
                         }
@@ -5198,7 +5200,7 @@ compareExpr
                             parser->normalizeExpression($4, type_dictionary, false);
                             OwnedHqlExpr dict = $4.getExpr();
                             OwnedHqlExpr row = $1.getExpr();
-                            OwnedHqlExpr indict = createINDictRow(parser->errorHandler, $4.pos, row, dict);
+                            OwnedHqlExpr indict = createINDictRow(*parser->errorHandler, $4.pos, row, dict);
                             $$.setExpr(getInverse(indict));
                             $$.setPosition($3);
                         }
@@ -5209,7 +5211,7 @@ compareExpr
                             parser->normalizeExpression($3, type_dictionary, false);
                             OwnedHqlExpr dict = $3.getExpr();
                             OwnedHqlExpr row = createValue(no_rowvalue, makeNullType(), $1.getExpr());
-                            $$.setExpr(createINDictExpr(parser->errorHandler, $3.pos, row, dict));
+                            $$.setExpr(createINDictExpr(*parser->errorHandler, $3.pos, row, dict));
                             $$.setPosition($2);
                         }
     | dataRow TOK_IN dictionary
@@ -5219,7 +5221,7 @@ compareExpr
                             parser->normalizeExpression($3, type_dictionary, false);
                             OwnedHqlExpr dict = $3.getExpr();
                             OwnedHqlExpr row = $1.getExpr();
-                            $$.setExpr(createINDictRow(parser->errorHandler, $3.pos, row, dict));
+                            $$.setExpr(createINDictRow(*parser->errorHandler, $3.pos, row, dict));
                             $$.setPosition($2);
                         }
     | dataSet EQ dataSet    
@@ -6941,7 +6943,7 @@ dataRow
                             $3.unwindCommaList(args);
                             OwnedHqlExpr dict = $1.getExpr();
                             OwnedHqlExpr row = createValue(no_rowvalue, makeNullType(), args);
-                            $$.setExpr(createSelectMapRow(parser->errorHandler, $3.pos, dict, row));
+                            $$.setExpr(createSelectMapRow(*parser->errorHandler, $3.pos, dict, row));
                         }
     | dataSet '[' NOBOUNDCHECK expression ']'
                         {   
@@ -7089,7 +7091,7 @@ simpleDataRow
     | ROW '(' inlineDatasetValue ',' recordDef ')'
                         {
                             OwnedHqlExpr row = createRow(no_temprow, $3.getExpr(), $5.getExpr());
-                            $$.setExpr(convertTempRowToCreateRow(parser->errorHandler, $3.pos, row));
+                            $$.setExpr(convertTempRowToCreateRow(*parser->errorHandler, $3.pos, row));
                             $$.setPosition($1);
                         }
     | ROW '(' startLeftSeqRow ',' recordDef ')' endSelectorSequence

+ 57 - 50
ecl/hql/hqlgram2.cpp

@@ -366,6 +366,7 @@ void HqlGram::init(IHqlScope * _globalScope, IHqlScope * _containerScope)
     lexObject = NULL;
     expectedAttribute = NULL;
     pendingAttributes = NULL;
+    expandingMacroPosition = false;
 
     outerScopeAccessDepth = 0;
     inType = false;
@@ -430,6 +431,7 @@ int HqlGram::yyLex(attribute * yylval, const short * activeState)
 void HqlGram::cleanCurTransform()
 {
     attribute pseudoErrPos;
+    pseudoErrPos.pos.clear();
     loop
     {
         IHqlExpression * ret = endTransform(pseudoErrPos);
@@ -5766,68 +5768,46 @@ void HqlGram::reportErrorUnexpectedX(const attribute& errpos, IAtom * unexpected
     reportError(ERR_UNEXPECTED_ATTRX, errpos, "Unexpected attribute %s", unexpected->str());
 }
 
-bool HqlGram::okToReportError(const ECLlocation & pos)
-{
-    if (errorHandler && !errorDisabled)
-    {
-        if (getMaxErrorsAllowed()>0 && errorHandler->errCount() >= getMaxErrorsAllowed())
-        {
-            errorHandler->reportError(ERR_ERROR_TOOMANY,"Too many errors; parsing aborted",pos.sourcePath->str(),pos.lineno,pos.column,pos.position);
-            abortParsing();
-            return false;
-        }
-        return true;
-    }
-    return false;
-}
-
 void HqlGram::doReportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
 {
-    if (associateWarnings)
-        pendingWarnings.append(*createECLWarning(warnNo, msg, filename, lineno, column, pos));
-    else
-        errorHandler->reportWarning(warnNo, msg, filename, lineno, column, pos);
+    Owned<IECLError> error = createECLError(SeverityWarning, warnNo, msg, filename, lineno, column, pos);
+    report(error);
 }
 
 void HqlGram::reportMacroExpansionPosition(int errNo, HqlLex * lexer, bool isError)
 {
+    if (expandingMacroPosition)
+        return;
     HqlLex * macro = lexer->getMacroLex();
     if (!macro)
-        return; 
+        return;
+
     reportMacroExpansionPosition(errNo, macro, isError);
     StringBuffer s;
     s.appendf("While expanding macro %s", macro->getMacroName());
+
+    expandingMacroPosition = true;
     if (isError)
         errorHandler->reportError(errNo, s.str(), lexer->querySourcePath()->str(), lexer->get_yyLineNo(), lexer->get_yyColumn(), 0);
     else
         doReportWarning(errNo, s.str(), lexer->querySourcePath()->str(), lexer->get_yyLineNo(), lexer->get_yyColumn(), 0);
+    expandingMacroPosition = false;
 }
     
 void HqlGram::reportErrorVa(int errNo, const ECLlocation & pos, const char* format, va_list args)
 {
-    if (okToReportError(pos))
-    {
-        StringBuffer msg;
-        msg.valist_appendf(format, args);
-        errorHandler->reportError(errNo, msg.str(), pos.sourcePath->str(), pos.lineno, pos.column, pos.position);
-        reportMacroExpansionPosition(errNo, lexObject, true);
-    }
+    StringBuffer msg;
+    msg.valist_appendf(format, args);
+    Owned<IECLError> error = createECLError(errNo, msg.str(), pos.sourcePath->str(), pos.lineno, pos.column, pos.position);
+    report(error);
 }
 
 void HqlGram::reportError(int errNo, const char *msg, int lineno, int column, int position)
 {
     if (errorHandler && !errorDisabled)
     {
-        if (getMaxErrorsAllowed()>0 && errorHandler->errCount() >= getMaxErrorsAllowed())
-        {
-            errorHandler->reportError(ERR_ERROR_TOOMANY,"Too many errors; parsing aborted",querySourcePathText(),lineno,column,position);
-            abortParsing();
-        }
-        else
-        {
-            errorHandler->reportError(errNo, msg, lexObject->queryActualSourcePath()->str(), lineno, column, position);
-            reportMacroExpansionPosition(errNo, lexObject, true);
-        }
+        Owned<IECLError> error = createECLError(errNo, msg, lexObject->queryActualSourcePath()->str(), lineno, column, position);
+        report(error);
     }
 }
 
@@ -5841,8 +5821,8 @@ void HqlGram::reportWarning(int warnNo, const ECLlocation & pos, const char* for
         msg.valist_appendf(format, args);
         va_end(args);
 
-        doReportWarning(warnNo, msg.str(), pos.sourcePath->str(), pos.lineno, pos.column, pos.position);
-        reportMacroExpansionPosition(warnNo, lexObject, false);
+        Owned<IECLError> error = createECLError(SeverityWarning, warnNo, msg.str(), pos.sourcePath->str(), pos.lineno, pos.column, pos.position);
+        report(error);
     }
 }
 
@@ -5853,31 +5833,58 @@ void HqlGram::reportWarningVa(int warnNo, const attribute& a, const char* format
     {
         StringBuffer msg;
         msg.valist_appendf(format, args);
-        doReportWarning(warnNo, msg.str(), pos.sourcePath->str(), pos.lineno, pos.column, pos.position);
-        reportMacroExpansionPosition(warnNo, lexObject, false);
+        Owned<IECLError> error = createECLError(SeverityWarning, warnNo, msg.str(), pos.sourcePath->str(), pos.lineno, pos.column, pos.position);
+        report(error);
     }
 }
 
 void HqlGram::reportWarning(int warnNo, const char *msg, int lineno, int column)
 {
     if (errorHandler && !errorDisabled)
-    {
         doReportWarning(warnNo, msg, querySourcePathText(), lineno, column, 0);
-        reportMacroExpansionPosition(warnNo, lexObject, false);
-    }
 }
 
 
 //interface IErrorReceiver
-void HqlGram::reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int pos)
+void HqlGram::reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int position)
 {
-    Owned<ISourcePath> sourcePath = createSourcePath(filename);
-    ECLlocation loc(lineno, column, pos, sourcePath);
-    if (okToReportError(loc))
-        errorHandler->reportError(errNo, msg, filename, lineno, column, pos);
+    Owned<IECLError> err = createECLError(errNo,msg,filename,lineno,column,position);
+    report(err);
 }
 
-void HqlGram::report(IECLError* error) { expandReportError(this, error); }
+IECLError * HqlGram::mapError(IECLError * error)
+{
+    return errorHandler->mapError(error);
+}
+
+void HqlGram::report(IECLError* error)
+{
+    if (errorHandler && !errorDisabled)
+    {
+        //Severity of warnings are not mapped here.  Fatal errors are reported directly.  Others are delayed
+        //(and may possibly be disabled by local onWarnings etc.)
+        bool isFatalError = (error->getSeverity() == SeverityFatal);
+        if (!isFatalError)
+        {
+            if (associateWarnings)
+                pendingWarnings.append(*LINK(error));
+            else
+                errorHandler->report(error);
+        }
+        else
+        {
+            errorHandler->report(error);
+
+            if (getMaxErrorsAllowed()>0 && errorHandler->errCount() >= getMaxErrorsAllowed())
+            {
+                errorHandler->reportError(ERR_ERROR_TOOMANY,"Too many errors; parsing aborted",error->getFilename(),error->getLine(),error->getColumn(),error->getPosition());
+                abortParsing();
+            }
+        }
+
+        reportMacroExpansionPosition(error->errorCode(), lexObject, isFatalError);
+    }
+}
 
 void HqlGram::reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
 {

+ 1 - 1
ecl/hql/hqlir.cpp

@@ -1341,7 +1341,7 @@ public:
                 appendStringAsCPP(line, msg.length(), msg.str(), false);
                 line.append("'");
                 line.append(",").append(warning->errorAudience());
-                line.append(",").append(warning->isError());
+                line.append(",").append((unsigned)warning->getSeverity());
                 line.append(")");
                 break;
             }

+ 20 - 21
ecl/hql/hqlopt.cpp

@@ -80,14 +80,14 @@ IHqlExpression * createFilterCondition(const HqlExprArray & conds, IHqlExpressio
 }
 
 
-bool optimizeFilterConditions(HqlExprArray & conds)
+bool optimizeFilterConditions(IErrorReceiver & errorProcessor, HqlExprArray & conds)
 {
     ForEachItemInRev(i, conds)
     {
         IHqlExpression & cur = conds.item(i);
         if (cur.isConstant())
         {
-            OwnedHqlExpr folded = foldHqlExpression(&cur);
+            OwnedHqlExpr folded = foldHqlExpression(errorProcessor, &cur);
             IValue * value = folded->queryValue();
             if (value)
             {
@@ -218,7 +218,7 @@ void ExpandComplexityMonitor::onExpand(IHqlExpression * select, IHqlExpression *
 
 //---------------------------------------------------------------------------
 static HqlTransformerInfo cTreeOptimizerInfo("CTreeOptimizer");
-CTreeOptimizer::CTreeOptimizer(unsigned _options) : PARENT(cTreeOptimizerInfo)
+CTreeOptimizer::CTreeOptimizer(IErrorReceiver & _errorProcessor, unsigned _options) : PARENT(cTreeOptimizerInfo), errorProcessor(_errorProcessor)
 {
     options = _options;
     optimizeFlags |= TCOtransformNonActive;
@@ -934,7 +934,7 @@ bool CTreeOptimizer::expandFilterCondition(HqlExprArray & expanded, HqlExprArray
 
             if (expandedFilter->isConstant())
             {
-                expandedFilter.setown(foldHqlExpression(expandedFilter));
+                expandedFilter.setown(foldHqlExpression(errorProcessor, expandedFilter));
                 IValue * value = expandedFilter->queryValue();
                 if (value && !value->getBoolValue())
                 {
@@ -1008,7 +1008,7 @@ IHqlExpression * CTreeOptimizer::hoistFilterOverProject(IHqlExpression * transfo
     HqlExprArray expanded, unexpanded;
     if (expandFilterCondition(expanded, unexpanded, transformed, true, onlyKeyed))
     {
-        if (optimizeFilterConditions(expanded))
+        if (optimizeFilterConditions(errorProcessor, expanded))
             return getOptimizedFilter(transformed, expanded);
 
         OwnedHqlExpr filterExpr = createFilterCondition(expanded);
@@ -1063,7 +1063,7 @@ IHqlExpression * CTreeOptimizer::getHoistedFilter(IHqlExpression * transformed,
 
         if (expandedFilter->isConstant())
         {
-            expandedFilter.setown(foldHqlExpression(expandedFilter));
+            expandedFilter.setown(foldHqlExpression(errorProcessor, expandedFilter));
             IValue * value = expandedFilter->queryValue();
             if (value)
             {
@@ -1955,7 +1955,7 @@ IHqlExpression * CTreeOptimizer::expandFields(TableProjectMapper * mapper, IHqlE
 {
     OwnedHqlExpr expandedFilter = mapper->expandFields(expr, oldDataset, newDataset, _expandCallback);
     if (options & HOOfold)
-        expandedFilter.setown(foldScopedHqlExpression(newDataset, expandedFilter));
+        expandedFilter.setown(foldScopedHqlExpression(errorProcessor, newDataset, expandedFilter));
     return expandedFilter.getClear();
 }
 
@@ -2554,8 +2554,7 @@ IHqlExpression * CTreeOptimizer::doCreateTransformed(IHqlExpression * transforme
             if (child->getOperator() == no_list)
             {
                 ECLlocation dummyLocation(0, 0, 0, NULL);
-                ThrowingErrorReceiver errorReporter;
-                OwnedHqlExpr inlineTable = convertTempTableToInlineTable(errorReporter, dummyLocation, transformed);
+                OwnedHqlExpr inlineTable = convertTempTableToInlineTable(errorProcessor, dummyLocation, transformed);
                 if (transformed != inlineTable)
                     return inlineTable.getClear();
             }
@@ -2783,8 +2782,8 @@ IHqlExpression * CTreeOptimizer::doCreateTransformed(IHqlExpression * transforme
                         break;
                     if (transformed->queryAttribute(onFailAtom) != child->queryAttribute(onFailAtom))
                         break;
-                    OwnedHqlExpr parentLimit = foldHqlExpression(transformed->queryChild(1));
-                    OwnedHqlExpr childLimit = foldHqlExpression(child->queryChild(1));
+                    OwnedHqlExpr parentLimit = foldHqlExpression(errorProcessor, transformed->queryChild(1));
+                    OwnedHqlExpr childLimit = foldHqlExpression(errorProcessor, child->queryChild(1));
                     if (parentLimit == childLimit)
                         return removeParentNode(transformed);
 
@@ -2822,16 +2821,16 @@ IHqlExpression * CTreeOptimizer::doCreateTransformed(IHqlExpression * transforme
                 break;
             case no_choosen:
                 {
-                    OwnedHqlExpr parentLimit = foldHqlExpression(transformed->queryChild(1));
-                    OwnedHqlExpr childLimit = foldHqlExpression(child->queryChild(1));
+                    OwnedHqlExpr parentLimit = foldHqlExpression(errorProcessor, transformed->queryChild(1));
+                    OwnedHqlExpr childLimit = foldHqlExpression(errorProcessor, child->queryChild(1));
                     if (getIntValue(parentLimit, 0) > getIntValue(childLimit, I64C(0x7fffffffffffffff)))
                         return removeParentNode(transformed);
                     break;
                 }
             case no_topn:
                 {
-                    OwnedHqlExpr parentLimit = foldHqlExpression(transformed->queryChild(1));
-                    OwnedHqlExpr childLimit = foldHqlExpression(child->queryChild(2));
+                    OwnedHqlExpr parentLimit = foldHqlExpression(errorProcessor, transformed->queryChild(1));
+                    OwnedHqlExpr childLimit = foldHqlExpression(errorProcessor, child->queryChild(2));
                     if (getIntValue(parentLimit, 0) > getIntValue(childLimit, I64C(0x7fffffffffffffff)))
                         return removeParentNode(transformed);
                     break;
@@ -3033,7 +3032,7 @@ IHqlExpression * CTreeOptimizer::doCreateTransformed(IHqlExpression * transforme
                         if (!expandedFilter->isConstant())
                             break;
 
-                        OwnedHqlExpr folded = foldHqlExpression(expandedFilter);
+                        OwnedHqlExpr folded = foldHqlExpression(errorProcessor, expandedFilter);
                         IValue * value = folded->queryValue();
                         if (!value)
                             break;
@@ -3902,23 +3901,23 @@ bool CTreeOptimizer::isSharedOrUnknown(IHqlExpression * expr)
     return (extra->useCount != 1);
 }
 
-IHqlExpression * optimizeHqlExpression(IHqlExpression * expr, unsigned options)
+IHqlExpression * optimizeHqlExpression(IErrorReceiver & errorProcessor, IHqlExpression * expr, unsigned options)
 {
     //The no_compound can get very heavily nested => unwind to save stack traversal.  We really should support nary no_compound
     HqlExprArray args, newArgs;
     unwindCommaCompound(args, expr);
-    optimizeHqlExpression(newArgs, args, options);
+    optimizeHqlExpression(errorProcessor, newArgs, args, options);
     OwnedHqlExpr optimized = createActionList(newArgs);
     //If the graph was optimized then it is highly likely there are now constant folding opportunities
     if (expr != optimized)
-        return foldHqlExpression(optimized);
+        return foldHqlExpression(errorProcessor, optimized);
     return optimized.getClear();
 }
 
 
-void optimizeHqlExpression(HqlExprArray & target, HqlExprArray & source, unsigned options)
+void optimizeHqlExpression(IErrorReceiver & errorProcessor, HqlExprArray & target, HqlExprArray & source, unsigned options)
 {
-    CTreeOptimizer optimizer(options);
+    CTreeOptimizer optimizer(errorProcessor, options);
     optimizer.analyseArray(source, 0);
     optimizer.transformRoot(source, target);
 }

+ 2 - 2
ecl/hql/hqlopt.hpp

@@ -34,7 +34,7 @@ enum
     HOOexpensive                = 0x0200,   // include potentially expensive optimizations
 };
 
-extern HQL_API IHqlExpression * optimizeHqlExpression(IHqlExpression * expr, unsigned options);
-extern HQL_API void optimizeHqlExpression(HqlExprArray & target, HqlExprArray & source, unsigned options);
+extern HQL_API IHqlExpression * optimizeHqlExpression(IErrorReceiver & errorProcessor, IHqlExpression * expr, unsigned options);
+extern HQL_API void optimizeHqlExpression(IErrorReceiver & errorProcessor, HqlExprArray & target, HqlExprArray & source, unsigned options);
 
 #endif

+ 2 - 1
ecl/hql/hqlopt.ipp

@@ -41,7 +41,7 @@ class CTreeOptimizer : public NewHqlTransformer, public NullFolderMixin
 {
     friend class ExpandMonitor;
 public:
-    CTreeOptimizer(unsigned _options);
+    CTreeOptimizer(IErrorReceiver & _errorProcessor, unsigned _options);
 
 protected:
     virtual void analyseExpr(IHqlExpression * expr);
@@ -123,6 +123,7 @@ protected:
 
 protected:
     typedef NewHqlTransformer PARENT;
+    IErrorReceiver & errorProcessor;
     unsigned options;
     StringBuffer nodeText[2];
     HqlExprAttr noHoistAttr;

+ 2 - 2
ecl/hql/hqlparse.cpp

@@ -1747,7 +1747,7 @@ IValue *HqlLex::foldConstExpression(const YYSTYPE & errpos, IHqlExpression * exp
         try 
         {
             CTemplateContext context(this, yyParser->lookupCtx, xmlScope, startLine, startCol);
-            OwnedHqlExpr folded = foldHqlExpression(expr, &context, HFOthrowerror|HFOfoldimpure|HFOforcefold);
+            OwnedHqlExpr folded = foldHqlExpression(*yyParser, expr, &context, HFOthrowerror|HFOfoldimpure|HFOforcefold);
             if (folded)
             {
                 if (folded->queryValue())
@@ -1815,7 +1815,7 @@ void HqlLex::doApply(YYSTYPE & returnToken)
     if (actions)
     {
         CTemplateContext context(this, yyParser->lookupCtx, xmlScope,line,col);
-        OwnedHqlExpr folded = foldHqlExpression(actions, &context, HFOthrowerror|HFOfoldimpure|HFOforcefold);
+        OwnedHqlExpr folded = foldHqlExpression(*yyParser, actions, &context, HFOthrowerror|HFOfoldimpure|HFOforcefold);
     }
     else
         reportError(returnToken, ERR_EXPECTED_CONST, "Constant expression expected");

+ 3 - 1
ecl/hql/hqlplugininfo.cpp

@@ -15,12 +15,14 @@
     limitations under the License.
 ############################################################################## */
 
-#include "jfile.hpp" 
+#include "jfile.hpp"
+#include "jlog.hpp"
 #include "hqlerror.hpp"
 #include "hqlcollect.hpp"
 #include "hqlrepository.hpp"
 #include "hqlplugins.hpp"
 #include "hqlplugininfo.hpp"
+#include "hqlexpr.hpp"
 
 namespace repositoryCommon {
 

+ 0 - 20
ecl/hql/hqlrepository.cpp

@@ -85,26 +85,6 @@ extern HQL_API void importRootModulesToScope(IHqlScope * scope, HqlLookupContext
 
 //-------------------------------------------------------------------------------------------------------------------
 
-void lookupAllRootDefinitions(IHqlScope * scope, HqlLookupContext & ctx)
-{
-    HqlExprArray rootSymbols;
-    scope->getSymbols(rootSymbols);
-    ForEachItemIn(i, rootSymbols)
-    {
-        ::Release(scope->lookupSymbol(rootSymbols.item(i).queryId(), LSFsharedOK, ctx));
-    }
-}
-
-void lookupAllRootDefinitions(IEclRepository * repository)
-{
-    HqlParseContext parseCtx(repository, NULL);
-    ThrowingErrorReceiver errs;
-    HqlLookupContext ctx(parseCtx, &errs);
-    lookupAllRootDefinitions(repository->queryRootScope(), ctx);
-}
-
-//-------------------------------------------------------------------------------------------------------------------
-
 IHqlExpression * getResolveAttributeFullPath(const char * attrname, unsigned lookupFlags, HqlLookupContext & ctx)
 {
     Owned<IHqlScope> parentScope;

+ 0 - 4
ecl/hql/hqlrepository.hpp

@@ -37,10 +37,6 @@ extern HQL_API void getRootScopes(HqlScopeArray & rootScopes, IEclRepository * r
 extern HQL_API void getImplicitScopes(HqlScopeArray & implicitScopes, IEclRepository * repository, IHqlScope * scope, HqlLookupContext & ctx);
 extern HQL_API void importRootModulesToScope(IHqlScope * scope, HqlLookupContext & ctx);
 
-
-extern HQL_API void lookupAllRootDefinitions(IHqlScope * scope, HqlLookupContext & ctx);
-extern HQL_API void lookupAllRootDefinitions(IEclRepository * repository);
-
 extern HQL_API IHqlScope * getResolveDottedScope(const char * modname, unsigned lookupFlags, HqlLookupContext & ctx);
 extern HQL_API IHqlExpression * getResolveAttributeFullPath(const char * attrname, unsigned lookupFlags, HqlLookupContext & ctx);
 

+ 191 - 112
ecl/hql/hqlutil.cpp

@@ -1222,7 +1222,8 @@ IHqlExpression * createImpureOwn(IHqlExpression * expr)
 
 IHqlExpression * getNormalizedFilename(IHqlExpression * filename)
 {
-    OwnedHqlExpr folded = foldHqlExpression(filename, NULL, HFOloseannotations);
+    Owned<IErrorReceiver> errorProcessor = createNullErrorReceiver();
+    OwnedHqlExpr folded = foldHqlExpression(*errorProcessor, filename, NULL, HFOloseannotations);
     return lowerCaseHqlExpr(folded);
 }
 
@@ -5469,8 +5470,8 @@ bool isNullList(IHqlExpression * expr)
 class TempTableTransformer
 {
 public:
-    TempTableTransformer(IErrorReceiver * _errors, ECLlocation & _location, bool _strictTypeChecking = false)
-      : errors(_errors), defaultLocation(_location), strictTypeChecking(_strictTypeChecking)
+    TempTableTransformer(IErrorReceiver & _errorProcessor, ECLlocation & _location, bool _strictTypeChecking = false)
+      : errorProcessor(_errorProcessor), defaultLocation(_location), strictTypeChecking(_strictTypeChecking)
     {}
 
     IHqlExpression * createTempTableTransform(IHqlExpression * curRow, IHqlExpression * record);
@@ -5483,7 +5484,7 @@ protected:
     void reportError(IHqlExpression * location, int code,const char *format, ...) __attribute__((format(printf, 4, 5)));
 
 protected:
-    IErrorReceiver * errors;
+    IErrorReceiver & errorProcessor;
     ECLlocation & defaultLocation;
     bool strictTypeChecking;
 };
@@ -5698,7 +5699,7 @@ void TempTableTransformer::createTempTableAssign(HqlExprArray & assigns, IHqlExp
         {
             OwnedHqlExpr cond = replaceSelfRefSelector(expr->queryChild(0), selector);
             OwnedHqlExpr mapped = mapper.transformRoot(cond);
-            mapped.setown(foldHqlExpression(mapped, NULL, HFOfoldimpure|HFOforcefold));
+            mapped.setown(foldHqlExpression(errorProcessor, mapped, NULL, HFOfoldimpure|HFOforcefold));
             IValue * mappedValue = mapped->queryValue();
 
             if (included)
@@ -5727,8 +5728,6 @@ void TempTableTransformer::createTempTableAssign(HqlExprArray & assigns, IHqlExp
 
 void TempTableTransformer::reportError(IHqlExpression * location, int code,const char *format, ...)
 {
-    if (!errors) return;
-
     ECLlocation * where = &defaultLocation;
     ECLlocation thisLocation;
     if (location)
@@ -5742,13 +5741,12 @@ void TempTableTransformer::reportError(IHqlExpression * location, int code,const
     va_start(args, format);
     errorMsg.valist_appendf(format, args);
     va_end(args);
-    errors->reportError(code, errorMsg.str(), where->sourcePath->str(), where->lineno, where->column, where->position);
+    Owned<IECLError> err = createECLError(code, errorMsg.str(), where->sourcePath->str(), where->lineno, where->column, where->position);
+    errorProcessor.report(err);
 }
 
 void TempTableTransformer::reportWarning(IHqlExpression * location, int code,const char *format, ...)
 {
-    if (!errors) return;
-
     ECLlocation * where = &defaultLocation;
     ECLlocation thisLocation;
     if (location)
@@ -5762,7 +5760,7 @@ void TempTableTransformer::reportWarning(IHqlExpression * location, int code,con
     va_start(args, format);
     errorMsg.valist_appendf(format, args);
     va_end(args);
-    errors->reportWarning(code, errorMsg.str(), where->sourcePath->str(), where->lineno, where->column, where->position);
+    errorProcessor.reportWarning(code, errorMsg.str(), where->sourcePath->str(), where->lineno, where->column, where->position);
 }
 
 IHqlExpression *getDictionaryKeyRecord(IHqlExpression *record)
@@ -5817,23 +5815,23 @@ IHqlExpression *getDictionarySearchRecord(IHqlExpression *record)
     return recursiveStretchFields(keyrec);
 }
 
-IHqlExpression * createSelectMapRow(IErrorReceiver * errors, ECLlocation & location, IHqlExpression * dict, IHqlExpression *values)
+IHqlExpression * createSelectMapRow(IErrorReceiver & errorProcessor, ECLlocation & location, IHqlExpression * dict, IHqlExpression *values)
 {
     OwnedHqlExpr record = getDictionarySearchRecord(dict->queryRecord());
-    TempTableTransformer transformer(errors, location, true);
+    TempTableTransformer transformer(errorProcessor, location, true);
     OwnedHqlExpr newTransform = transformer.createTempTableTransform(values, record);
     return createRow(no_selectmap, LINK(dict), createRow(no_createrow, newTransform.getClear()));
 }
 
-IHqlExpression *createINDictExpr(IErrorReceiver * errors, ECLlocation & location, IHqlExpression *expr, IHqlExpression *dict)
+IHqlExpression *createINDictExpr(IErrorReceiver & errorProcessor, ECLlocation & location, IHqlExpression *expr, IHqlExpression *dict)
 {
     OwnedHqlExpr record = getDictionarySearchRecord(dict->queryRecord());
-    TempTableTransformer transformer(errors, location, true);
+    TempTableTransformer transformer(errorProcessor, location, true);
     OwnedHqlExpr newTransform = transformer.createTempTableTransform(expr, record);
     return createBoolExpr(no_indict, createRow(no_createrow, newTransform.getClear()), LINK(dict));
 }
 
-IHqlExpression *createINDictRow(IErrorReceiver * errors, ECLlocation & location, IHqlExpression *row, IHqlExpression *dict)
+IHqlExpression *createINDictRow(IErrorReceiver & errorProcessor, ECLlocation & location, IHqlExpression *row, IHqlExpression *dict)
 {
     OwnedHqlExpr record = getDictionarySearchRecord(dict->queryRecord());
     Owned<ITypeInfo> rowType = makeRowType(record->getType());
@@ -5841,13 +5839,13 @@ IHqlExpression *createINDictRow(IErrorReceiver * errors, ECLlocation & location,
     return createBoolExpr(no_indict, castRow.getClear(), LINK(dict));
 }
 
-IHqlExpression * convertTempRowToCreateRow(IErrorReceiver * errors, ECLlocation & location, IHqlExpression * expr)
+IHqlExpression * convertTempRowToCreateRow(IErrorReceiver & errorProcessor, ECLlocation & location, IHqlExpression * expr)
 {
     IHqlExpression * oldValues = expr->queryChild(0);
     IHqlExpression * record = expr->queryChild(1);
     OwnedHqlExpr values = normalizeListCasts(oldValues); // ??? not used
+    TempTableTransformer transformer(errorProcessor, location);
 
-    TempTableTransformer transformer(errors, location);
     OwnedHqlExpr newTransform = transformer.createTempTableTransform(oldValues, record);
     HqlExprArray children;
     children.append(*LINK(newTransform));
@@ -5855,7 +5853,7 @@ IHqlExpression * convertTempRowToCreateRow(IErrorReceiver * errors, ECLlocation
     return expr->cloneAllAnnotations(ret);
 }
 
-static IHqlExpression * convertTempTableToInline(IErrorReceiver & errors, ECLlocation & location, IHqlExpression * expr)
+static IHqlExpression * convertTempTableToInline(IErrorReceiver & errorProcessor, ECLlocation & location, IHqlExpression * expr)
 {
     IHqlExpression * oldValues = expr->queryChild(0);
     IHqlExpression * record = expr->queryChild(1);
@@ -5868,7 +5866,7 @@ static IHqlExpression * convertTempTableToInline(IErrorReceiver & errors, ECLloc
     if ((valueOp != no_recordlist) && (valueOp != no_list))
         return LINK(expr);
 
-    TempTableTransformer transformer(&errors, location);
+    TempTableTransformer transformer(errorProcessor, location);
     HqlExprArray transforms;
     ForEachChild(idx, values)
     {
@@ -5889,7 +5887,7 @@ static IHqlExpression * convertTempTableToInline(IErrorReceiver & errors, ECLloc
                     else
                     {
                         VStringBuffer msg(HQLERR_FieldHasNoDefaultValue_Text, field->queryName()->str());
-                        errors.reportError(HQLERR_FieldHasNoDefaultValue, msg.str(), location.sourcePath->str(), location.lineno, location.column, location.position);
+                        errorProcessor.reportError(HQLERR_FieldHasNoDefaultValue, msg.str(), location.sourcePath->str(), location.lineno, location.column, location.position);
                     }
                 }
             }
@@ -6442,7 +6440,29 @@ void gatherGraphReferences(HqlExprCopyArray & graphs, IHqlExpression * value, bo
 
 //---------------------------------------------------------------------------
 
-IAtom * getWarningAction(unsigned errorCode, const HqlExprArray & overrides, unsigned first)
+ErrorSeverity getSeverity(IAtom * name)
+{
+    if (name == failAtom)
+        return SeverityFatal;
+    if (name == errorAtom)
+        return SeverityError;
+    if (name == warningAtom)
+        return SeverityWarning;
+    if (name == ignoreAtom)
+        return SeverityIgnore;
+    if (name == logAtom)
+        return SeverityInfo;
+    return SeverityUnknown;
+}
+
+static ErrorSeverity getCheckSeverity(IAtom * name)
+{
+    ErrorSeverity severity = getSeverity(name);
+    assertex(severity != SeverityUnknown);
+    return severity;
+}
+
+static ErrorSeverity getWarningAction(unsigned errorCode, const HqlExprArray & overrides, unsigned first, ErrorSeverity defaultSeverity)
 {
     //warnings are assumed to be infrequent, so don't worry about efficiency here.
     const unsigned max = overrides.ordinality();
@@ -6450,162 +6470,221 @@ IAtom * getWarningAction(unsigned errorCode, const HqlExprArray & overrides, uns
     {
         IHqlExpression & cur = overrides.item(i);
         if (matchesConstantValue(cur.queryChild(0), errorCode))
-            return cur.queryChild(1)->queryName();
+            return getCheckSeverity(cur.queryChild(1)->queryName());
     }
-    return defaultAtom;
+    return defaultSeverity;
 }
 
-WarningProcessor::WarningProcessor() 
-{ 
-    firstLocalOnWarning = 0; 
-    activeSymbol = NULL; 
+//---------------------------------------------------------------------------
+
+ErrorSeverityMapper::ErrorSeverityMapper(IErrorReceiver & _errorProcessor) : IndirectErrorReceiver(_errorProcessor)
+{
+    firstActiveMapping = 0;
+    activeSymbol = NULL;
 }
 
 
-void WarningProcessor::addWarning(IECLError * warning)
+bool ErrorSeverityMapper::addCommandLineMapping(const char * mapping)
 {
-    //warnings are assumed to be infrequent, so don't worry about efficiency here.
-    IAtom * action = getWarningAction(warning->errorCode(), localOnWarnings, firstLocalOnWarning);
+    if (!mapping)
+        return true;
 
-    if (action == defaultAtom)
-        appendUnique(possibleWarnings, warning);
-    else if (action == warningAtom)
-        appendUnique(warnings, warning);
-    else if (action == errorAtom)
+    unsigned len = strlen(mapping);
+    if (len == 0)
+        return true;
+
+    const char * equals = strchr(mapping, '=');
+    const char * value;
+    if (equals)
+        value = equals+1;
+    else if (mapping[len-1] == '+')
     {
-        allErrors.append(*changeErrorType(true, warning));
+        len--;
+        value = "error";
+    }
+    else if (mapping[len-1] == '-')
+    {
+        value = "ignore";
+        len--;
+    }
+    else
+        value = "error";
+
+    IAtom * action = createAtom(value);
+    if (getSeverity(action) == SeverityUnknown)
+    {
+        fprintf(stderr, "invalid warning severity '%s'\n", value);
+        return false;
+    }
+
+    if (isdigit(mapping[0]))
+    {
+        unsigned errorCode = atoi(mapping);
+        addOnWarning(errorCode, action);
+        return true;
     }
     else
     {
-        assertex(action == ignoreAtom);
+        fprintf(stderr, "mapping doesn't specify a valid warning code '%s'\n", mapping);
+        return false;
     }
 }
 
-void WarningProcessor::addGlobalOnWarning(unsigned code, IAtom * action)
+void ErrorSeverityMapper::addOnWarning(unsigned code, IAtom * action)
 {
-    globalOnWarnings.append(*createAttribute(onWarningAtom, getSizetConstant(code), createAttribute(action)));
+    severityMappings.append(*createAttribute(onWarningAtom, getSizetConstant(code), createAttribute(action)));
 }
 
-void WarningProcessor::addGlobalOnWarning(IHqlExpression * setMetaExpr)
+void ErrorSeverityMapper::addOnWarning(IHqlExpression * setMetaExpr)
 {
-    globalOnWarnings.append(*createAttribute(onWarningAtom, LINK(setMetaExpr->queryChild(1)), LINK(setMetaExpr->queryChild(2))));
+    severityMappings.append(*createAttribute(onWarningAtom, LINK(setMetaExpr->queryChild(1)), LINK(setMetaExpr->queryChild(2))));
 }
 
-void WarningProcessor::processMetaAnnotation(IHqlExpression * expr)
+unsigned ErrorSeverityMapper::processMetaAnnotation(IHqlExpression * expr)
 {
-    gatherMetaAttributes(localOnWarnings, onWarningAtom, expr);
+    unsigned prevMax = severityMappings.ordinality();
+    gatherMetaAttributes(severityMappings, onWarningAtom, expr);
+    return prevMax;
 }
 
-void WarningProcessor::processWarningAnnotation(IHqlExpression * expr)
+void ErrorSeverityMapper::restoreLocalOnWarnings(unsigned prevMax)
 {
-    //would be cleaner if each annotation defined an interface, and this was a dynamic cast
-    //but not sufficiently complicated to warrent it.
-    IECLError * error = static_cast<CHqlWarningAnnotation *>(expr)->queryWarning();
-    addWarning(error);
+    severityMappings.trunc(prevMax);
 }
 
-void WarningProcessor::pushSymbol(OnWarningState & saved, IHqlExpression * _symbol)
+void ErrorSeverityMapper::pushSymbol(ErrorSeverityMapperState & saved, IHqlExpression * _symbol)
 {
     saveState(saved);
     setSymbol(_symbol);
 }
 
-void WarningProcessor::saveState(OnWarningState & saved)
+void ErrorSeverityMapper::saveState(ErrorSeverityMapperState & saved) const
 {
-    saved.firstOnWarning = firstLocalOnWarning;
-    saved.onWarningMax = localOnWarnings.ordinality();
+    saved.firstActiveMapping = firstActiveMapping;
+    saved.maxMappings = severityMappings.ordinality();
     saved.symbol = activeSymbol;
 }
 
-void WarningProcessor::setSymbol(IHqlExpression * _symbol)
+void ErrorSeverityMapper::setSymbol(IHqlExpression * _symbol)
 {
-    firstLocalOnWarning = localOnWarnings.ordinality();
+    firstActiveMapping = severityMappings.ordinality();
     activeSymbol = _symbol;
 }
 
-void WarningProcessor::restoreState(const OnWarningState & saved)
+void ErrorSeverityMapper::restoreState(const ErrorSeverityMapperState & saved)
 {
-    while (localOnWarnings.ordinality() > saved.onWarningMax)
-        localOnWarnings.pop();
-    firstLocalOnWarning = saved.firstOnWarning;
+    severityMappings.trunc(saved.maxMappings);
+    firstActiveMapping = saved.firstActiveMapping;
     activeSymbol = saved.symbol;
 }
 
-void WarningProcessor::report(IErrorReceiver & errors)
+IECLError * ErrorSeverityMapper::mapError(IECLError * error)
 {
-    applyGlobalOnWarning();
-    combineSandboxWarnings();
-    if (allErrors.ordinality())
-        reportErrors(errors, allErrors);
-    else
-        reportErrors(errors, warnings);
+    //An error that is fatal cannot be mapped.
+    Owned<IECLError> mappedError = IndirectErrorReceiver::mapError(error);
+    if (!isFatal(mappedError))
+    {
+        //This takes precedence over mappings in the parent
+        ErrorSeverity newSeverity = getWarningAction(mappedError->errorCode(), severityMappings, firstActiveMapping, SeverityUnknown);
+        if (newSeverity != SeverityUnknown)
+            return mappedError->cloneSetSeverity(newSeverity);
+    }
+    return mappedError.getClear();
 }
 
-void WarningProcessor::report(IErrorReceiver * errors, IErrorReceiver * warnings, IECLError * warning)
-{
-    IAtom * action = getWarningAction(warning->errorCode(), localOnWarnings, firstLocalOnWarning);
+//---------------------------------------------------------------------------------------------------------------------
 
-    if (action == defaultAtom)
-        action = getWarningAction(warning->errorCode(), globalOnWarnings, 0);
+bool isGlobalOnWarning(IHqlExpression * expr)
+{
+    return ((expr->getOperator() == no_setmeta) && (expr->queryChild(0)->queryName() == onWarningAtom));
+}
 
-    if (action == defaultAtom)
-        action = warning->isError() ? errorAtom : warningAtom;
+//---------------------------------------------------------------------------
 
-    if ((action == warningAtom) || (action == defaultAtom))
+static HqlTransformerInfo globalOnWarningCollectorInfo("GlobalOnWarningCollector");
+class GlobalOnWarningCollector : public QuickHqlTransformer
+{
+public:
+    GlobalOnWarningCollector(ErrorSeverityMapper & _mapper) :
+        QuickHqlTransformer(globalOnWarningCollectorInfo, NULL), mapper(_mapper)
     {
-        if (warnings)
-            warnings->report(warning);
     }
-    else if (action == errorAtom)
+
+    virtual void doAnalyse(IHqlExpression * expr)
     {
-        Owned<IECLError> error = changeErrorType(true, warning);
-        if (errors)
-            errors->report(error);
-        else
-            throw error.getClear();
+        IHqlExpression * body = expr->queryBody();
+        if (isGlobalOnWarning(body))
+            mapper.addOnWarning(body);
+        QuickHqlTransformer::doAnalyse(body);
     }
-}
 
+protected:
+    ErrorSeverityMapper & mapper;
+};
 
-void WarningProcessor::combineSandboxWarnings()
+
+static HqlTransformerInfo warningCollectingTransformerInfo("WarningCollectingTransformer");
+class WarningCollectingTransformer : public QuickHqlTransformer
 {
-    StringBuffer s;
-    ForEachItemInRev(i, warnings)
-    {
-        IECLError & cur = warnings.item(i);
-        if (cur.errorCode() == WRN_DEFINITION_SANDBOXED)
-        {
-            if (s.length())
-                s.append(", ");
-            s.append(cur.getFilename());
-            warnings.remove(i);
-        }
-    }
-    if (s.length())
+public:
+    WarningCollectingTransformer(IErrorReceiver & _errs) :
+        QuickHqlTransformer(warningCollectingTransformerInfo, &_errs), mapper(_errs)
     {
-        s.insert(0, "The following definitions are sandboxed: ");
-        warnings.append(* createECLWarning(WRN_DEFINITION_SANDBOXED, s.str(), NULL, 0, 0, 0));
     }
-}
 
-void WarningProcessor::applyGlobalOnWarning()
-{
-    ForEachItemIn(i, possibleWarnings)
+    virtual void doAnalyse(IHqlExpression * expr)
     {
-        IECLError & cur = possibleWarnings.item(i);
-        IAtom * action = getWarningAction(cur.errorCode(), globalOnWarnings, 0);
-        if (action == defaultAtom || action == warningAtom)
+        switch (expr->getAnnotationKind())
         {
-            if (cur.isError())
-                appendUnique(allErrors, &cur);
-            else
-                appendUnique(warnings, &cur);
+        case annotate_meta:
+            {
+                unsigned max = mapper.processMetaAnnotation(expr);
+                QuickHqlTransformer::doAnalyse(expr);
+                mapper.restoreLocalOnWarnings(max);
+                return;
+            }
+        case annotate_warning:
+            {
+                IECLError * error = static_cast<CHqlWarningAnnotation *>(expr)->queryWarning();
+                Owned<IECLError> mappedError = mapper.mapError(error);
+                mapper.report(mappedError);
+                break;
+            }
+        case annotate_symbol:
+            {
+                ErrorSeverityMapper::SymbolScope saved(mapper, expr);
+                QuickHqlTransformer::doAnalyse(expr);
+                return;
+            }
         }
-        else if (action == errorAtom)
-            allErrors.append(*changeErrorType(true, &cur));
+        QuickHqlTransformer::doAnalyse(expr);
     }
+
+protected:
+    ErrorSeverityMapper mapper;
+};
+
+
+void gatherParseWarnings(IErrorReceiver * errs, IHqlExpression * expr)
+{
+    if (!errs || !expr)
+        return;
+
+    Owned<IErrorReceiver> deduper = createDedupingErrorReceiver(*errs);
+
+    //First collect any #ONWARNINGs held in the parsed expression tree
+    Owned<ErrorSeverityMapper> globalOnWarning = new ErrorSeverityMapper(*deduper);
+    GlobalOnWarningCollector globalCollector(*globalOnWarning);
+    globalCollector.analyse(expr);
+
+    //Now walk all expressions, outputting warnings and processing local onWarnings
+    WarningCollectingTransformer warningCollector(*globalOnWarning);
+    warningCollector.analyse(expr);
 }
 
+
+//---------------------------------------------------------------------------
+
 bool isActiveRow(IHqlExpression * expr)
 {
     switch (expr->getOperator())

+ 49 - 53
ecl/hql/hqlutil.hpp

@@ -458,10 +458,10 @@ extern HQL_API bool isNullList(IHqlExpression * expr);
 
 extern HQL_API IHqlExpression *getDictionaryKeyRecord(IHqlExpression *record);
 extern HQL_API IHqlExpression *getDictionarySearchRecord(IHqlExpression *record);
-extern HQL_API IHqlExpression * createSelectMapRow(IErrorReceiver * errors, ECLlocation & location, IHqlExpression * dict, IHqlExpression *values);
-extern HQL_API IHqlExpression * createINDictExpr(IErrorReceiver * errors, ECLlocation & location, IHqlExpression *expr, IHqlExpression *dict);
-extern HQL_API IHqlExpression *createINDictRow(IErrorReceiver * errors, ECLlocation & location, IHqlExpression *row, IHqlExpression *dict);
-extern HQL_API IHqlExpression * convertTempRowToCreateRow(IErrorReceiver * errors, ECLlocation & location, IHqlExpression * expr);
+extern HQL_API IHqlExpression * createSelectMapRow(IErrorReceiver & errorProcessor, ECLlocation & location, IHqlExpression * dict, IHqlExpression *values);
+extern HQL_API IHqlExpression * createINDictExpr(IErrorReceiver & errorProcessor, ECLlocation & location, IHqlExpression *expr, IHqlExpression *dict);
+extern HQL_API IHqlExpression *createINDictRow(IErrorReceiver & errorProcessor, ECLlocation & location, IHqlExpression *row, IHqlExpression *dict);
+extern HQL_API IHqlExpression * convertTempRowToCreateRow(IErrorReceiver & errorProcessor, ECLlocation & location, IHqlExpression * expr);
 extern HQL_API IHqlExpression * convertTempTableToInlineTable(IErrorReceiver & errors, ECLlocation & location, IHqlExpression * expr);
 extern HQL_API void setPayloadAttribute(HqlExprArray &args);
 
@@ -505,81 +505,76 @@ protected:
     bool streamingAllowed;
 };
 
-extern HQL_API IAtom * getWarningAction(unsigned errorCode, const HqlExprArray & overrides, unsigned first);
-class HQL_API WarningProcessor
+/*
+ *
+ *This class is used for processing the onWarningMappings.
+ *
+ * Global onWarnings are simple, and are just added to a class instance
+ * local onWarnings are
+ * - applied in a stack-wise manner, so should be removed when no longer processing inside them
+ * - only apply until the next defined symbol - to prevent them having an effect too far down the tree
+ *
+ * For this reason SymbolBlocks and Blocks are used to ensure those rules are followed
+ *
+ */
+class HQL_API ErrorSeverityMapper : public IndirectErrorReceiver
 {
 public:
-    struct OnWarningState
+    struct ErrorSeverityMapperState
     {
         IHqlExpression * symbol;
-        unsigned firstOnWarning;
-        unsigned onWarningMax;
+        unsigned firstActiveMapping;
+        unsigned maxMappings;
     };
 
-    struct OnWarningStateSymbolBlock
+    struct SymbolScope
     {
-        inline OnWarningStateSymbolBlock(WarningProcessor & _processor, IHqlExpression * _expr) : processor(_processor) { processor.pushSymbol(state, _expr); }
-        inline ~OnWarningStateSymbolBlock() { processor.popSymbol(state); }
+        inline SymbolScope(ErrorSeverityMapper & _processor, IHqlExpression * _expr) : processor(_processor) { processor.pushSymbol(state, _expr); }
+        inline ~SymbolScope() { processor.popSymbol(state); }
 
     private:
-        WarningProcessor & processor;
-        OnWarningState state;
+        ErrorSeverityMapper & processor;
+        ErrorSeverityMapperState state;
     };
 
-    struct OnWarningStateBlock
+    struct Scope
     {
-        inline OnWarningStateBlock(WarningProcessor & _processor) : processor(_processor) { processor.saveState(state); }
-        inline ~OnWarningStateBlock() { processor.restoreState(state); }
+        inline Scope(ErrorSeverityMapper & _processor) : processor(_processor) { processor.saveState(state); }
+        inline ~Scope() { processor.restoreState(state); }
 
     private:
-        WarningProcessor & processor;
-        OnWarningState state;
+        ErrorSeverityMapper & processor;
+        ErrorSeverityMapperState state;
     };
 
 public:
-    WarningProcessor();
-
-    void addGlobalOnWarning(unsigned code, IAtom * action);
-    void addGlobalOnWarning(IHqlExpression * setMetaExpr);
-    void addWarning(IECLError * warning);
-    inline void checkForGlobalOnWarning(IHqlExpression * expr)
-    {
-        if ((expr->getOperator() == no_setmeta) && (expr->queryChild(0)->queryName() == onWarningAtom))
-            addGlobalOnWarning(expr);
-    }
-    void processMetaAnnotation(IHqlExpression * expr);
-    void processWarningAnnotation(IHqlExpression * expr);
-    void pushSymbol(OnWarningState & saved, IHqlExpression * _symbol);
-    void popSymbol(const OnWarningState & saved) { restoreState(saved); }
-    void saveState(OnWarningState & saved);
+    ErrorSeverityMapper(IErrorReceiver & errorProcessor);
+
+    virtual IECLError * mapError(IECLError * error);
+
+    bool addCommandLineMapping(const char * mapping);
+    void addOnWarning(unsigned code, IAtom * action);
+    void addOnWarning(IHqlExpression * setMetaExpr);
+    unsigned processMetaAnnotation(IHqlExpression * expr);
+    void pushSymbol(ErrorSeverityMapperState & saved, IHqlExpression * _symbol);
+    void popSymbol(const ErrorSeverityMapperState & saved) { restoreState(saved); }
+    void restoreLocalOnWarnings(unsigned prevMax);
+    void saveState(ErrorSeverityMapperState & saved) const;
     void setSymbol(IHqlExpression * _symbol);
-    void restoreState(const OnWarningState & saved);
-    void report(IErrorReceiver & errors);
-    void report(IErrorReceiver * errors, IErrorReceiver * warnings, IECLError * warning);   // process warning now.
+    void restoreState(const ErrorSeverityMapperState & saved);
 
-    inline void appendUnique(IECLErrorArray & list, IECLError * search)
-    {
-        if (!list.contains(*search))
-            list.append(*LINK(search));
-    }
-    inline unsigned numErrors() const { return allErrors.ordinality(); }
     inline IHqlExpression * queryActiveSymbol() { return activeSymbol; }
 
-
-protected:
-    void combineSandboxWarnings();
-    void applyGlobalOnWarning();
+private:
+    ErrorSeverityMapper(const ErrorSeverityMapper &); // prevent this being called
 
 protected:
     IHqlExpression * activeSymbol;
-    IECLErrorArray possibleWarnings;
-    IECLErrorArray warnings;
-    IECLErrorArray allErrors;
-    HqlExprArray globalOnWarnings;
-    HqlExprArray localOnWarnings;
-    unsigned firstLocalOnWarning;
+    HqlExprArray severityMappings;
+    unsigned firstActiveMapping;
 };
 
+extern HQL_API bool isGlobalOnWarning(IHqlExpression * expr);
 
 extern HQL_API IHqlExpression * queryDefaultMaxRecordLengthExpr();
 extern HQL_API IHqlExpression * getFixedSizeAttr(unsigned size);
@@ -730,5 +725,6 @@ protected:
 };
 
 extern HQL_API bool joinHasRightOnlyHardMatch(IHqlExpression * expr, bool allowSlidingMatch);
+extern HQL_API void gatherParseWarnings(IErrorReceiver * errs, IHqlExpression * expr);
 
 #endif

+ 4 - 4
ecl/hql/hqlvalid.cpp

@@ -129,7 +129,7 @@ IHqlExpression * checkCreateConcreteModule(IErrorReceiver * errors, IHqlExpressi
     return createDelayedScope(check.getClear());
 }
 
-void reportAbstractModule(IErrorReceiver * errors, IHqlExpression * expr, const ECLlocation & errpos)
+void reportAbstractModule(IErrorReceiver & errors, IHqlExpression * expr, const ECLlocation & errpos)
 {
     IHqlScope * scope = expr->queryScope();
     StringBuffer fieldText;
@@ -151,11 +151,11 @@ void reportAbstractModule(IErrorReceiver * errors, IHqlExpression * expr, const
     }
 
     if (fieldText.length())
-        reportError(errors, ERR_ABSTRACT_MODULE, errpos, "Cannot use an abstract MODULE in this context (%s undefined)", fieldText.str());
+        reportError(&errors, ERR_ABSTRACT_MODULE, errpos, "Cannot use an abstract MODULE in this context (%s undefined)", fieldText.str());
     else if (expr->hasAttribute(interfaceAtom))
-        reportError(errors, ERR_ABSTRACT_MODULE, errpos, "Cannot use an abstract MODULE in this context (INTERFACE must be instantiated)");
+        reportError(&errors, ERR_ABSTRACT_MODULE, errpos, "Cannot use an abstract MODULE in this context (INTERFACE must be instantiated)");
     else
-        reportError(errors, ERR_ABSTRACT_MODULE, errpos, "Cannot use an abstract MODULE in this context");
+        reportError(&errors, ERR_ABSTRACT_MODULE, errpos, "Cannot use an abstract MODULE in this context");
 }
 
 IHqlExpression * checkCreateConcreteModule(IErrorReceiver * errors, IHqlExpression * expr, const IHqlExpression * locationExpr)

+ 1 - 1
ecl/hql/hqlvalid.hpp

@@ -20,7 +20,7 @@
 #include "hqlexpr.hpp"
 
 //Checking functions
-extern HQL_API void reportAbstractModule(IErrorReceiver * errors, IHqlExpression * expr, const ECLlocation & errpos);
+extern HQL_API void reportAbstractModule(IErrorReceiver & errorProcessor, IHqlExpression * expr, const ECLlocation & errpos);
 extern HQL_API IHqlExpression * checkCreateConcreteModule(IErrorReceiver * errors, IHqlExpression * expr, const ECLlocation & errpos);
 extern HQL_API IHqlExpression * checkCreateConcreteModule(IErrorReceiver * errors, IHqlExpression * expr, const IHqlExpression * locationExpr);
 extern HQL_API IHqlExpression * createLocationAttr(ISourcePath * filename, int lineno, int column, int position);

+ 25 - 21
ecl/hql/hqlwuerr.cpp

@@ -43,31 +43,39 @@ void WorkUnitErrorReceiver::initializeError(IWUException * exception, int errNo,
     exception->setTimeStamp(NULL);
 }
 
-void WorkUnitErrorReceiver::reportError(int errNo, const char *msg, const char * filename, int lineno, int column, int pos)
+IECLError * WorkUnitErrorReceiver::mapError(IECLError * error)
 {
-    Owned<IWUException> exception = wu->createException();
-    exception->setSeverity(ExceptionSeverityError);
-    initializeError(exception, errNo, msg, filename, lineno, column, pos);
+    return LINK(error);
 }
 
 void WorkUnitErrorReceiver::report(IECLError* eclError)
 {
+    WUExceptionSeverity wuSeverity = ExceptionSeverityInformation;
+    ErrorSeverity severity = eclError->getSeverity();
+
+    switch (severity)
+    {
+    case SeverityIgnore:
+        return;
+    case SeverityInfo:
+        break;
+    case SeverityWarning:
+        wuSeverity = ExceptionSeverityWarning;
+        break;
+    case SeverityError:
+    case SeverityFatal:
+        wuSeverity = ExceptionSeverityError;
+        break;
+    }
+
     Owned<IWUException> exception = wu->createException();
-    if (!eclError->isError())
-        exception->setSeverity(ExceptionSeverityWarning);
+    exception->setSeverity(wuSeverity);
 
     StringBuffer msg;
     initializeError(exception, eclError->errorCode(), eclError->errorMessage(msg).str(), 
                     eclError->getFilename(), eclError->getLine(), eclError->getColumn(), eclError->getPosition());
 }
 
-void WorkUnitErrorReceiver::reportWarning(int warnNo, const char *msg, const char * filename, int lineno, int column, int pos)
-{
-    Owned<IWUException> exception = wu->createException();
-    exception->setSeverity(ExceptionSeverityWarning);
-    initializeError(exception, warnNo, msg, filename, lineno, column, pos);
-}
-
 size32_t WorkUnitErrorReceiver::errCount()
 {
     unsigned count = 0;
@@ -95,21 +103,17 @@ public:
     CompoundErrorReceiver(IErrorReceiver * _primary, IErrorReceiver * _secondary) { primary.set(_primary); secondary.set(_secondary); }
     IMPLEMENT_IINTERFACE;
 
-    virtual void reportError(int errNo, const char *msg, const char * filename, int lineno, int column, int pos)
+    virtual IECLError * mapError(IECLError * error)
     {
-        primary->reportError(errNo, msg, filename, lineno, column, pos);
-        secondary->reportError(errNo, msg, filename, lineno, column, pos);
+        Owned<IECLError> mappedError = primary->mapError(error);
+        assertex(mappedError == error); // should not expect any mapping below a compound.
+        return mappedError.getClear();
     }
     virtual void report(IECLError* err)
     {
         primary->report(err);
         secondary->report(err);
     }
-    virtual void reportWarning(int warnNo, const char *msg, const char * filename, int lineno, int column, int pos)
-    {
-        primary->reportWarning(warnNo, msg, filename, lineno, column, pos);
-        secondary->reportWarning(warnNo, msg, filename, lineno, column, pos);
-    }
     virtual size32_t errCount()    { return primary->errCount(); }
     virtual size32_t warnCount()       { return primary->warnCount(); }
 

+ 1 - 2
ecl/hql/hqlwuerr.hpp

@@ -26,9 +26,8 @@ public:
     WorkUnitErrorReceiver(IWorkUnit * _wu, const char * _component) { wu.set(_wu); component.set(_component); }
     IMPLEMENT_IINTERFACE;
 
-    virtual void reportError(int errNo, const char *msg, const char * filename, int lineno, int column, int pos);
+    virtual IECLError * mapError(IECLError * error);
     virtual void report(IECLError*);
-    virtual void reportWarning(int warnNo, const char *msg, const char * filename, int lineno, int column, int pos);
     virtual size32_t errCount();
     virtual size32_t warnCount();
 

+ 0 - 2
ecl/hqlcpp/hqlcerrors.hpp

@@ -271,8 +271,6 @@
 #define HQLERR_OnceCannotAccessStored           4618
 #define HQLERR_ThorCombineOnlyLocal             4619
 
-#define HQLERR_ErrorAlreadyReported             4799            // special case...
-
 //Internal errors....
 #define HQLERR_NoClearOnLocalDataset            4800
 #define HQLERR_NoCreateLocalDataset             4801

+ 1 - 1
ecl/hqlcpp/hqlckey.cpp

@@ -710,7 +710,7 @@ void KeyedJoinInfo::buildTransformBody(BuildCtx & ctx, IHqlExpression * transfor
             newTransform.setown(expandDatasetReferences(newTransform, expandedKey));
     }
 
-    newTransform.setown(optimizeHqlExpression(newTransform, HOOfold|HOOcompoundproject));
+    newTransform.setown(optimizeHqlExpression(translator.queryErrorProcessor(), newTransform, HOOfold|HOOcompoundproject));
     newTransform.setown(foldHqlExpression(newTransform));
 
     BoundRow * selfCursor = translator.buildTransformCursors(ctx, newTransform, expr->queryChild(0), joinDataset, expr, joinSeq);

+ 14 - 8
ecl/hqlcpp/hqlcpp.cpp

@@ -1358,6 +1358,12 @@ IHqlCppInstance * createCppInstance(IWorkUnit *wu, const char * wupathname)
 
 HqlCppTranslator::HqlCppTranslator(IErrorReceiver * _errors, const char * _soName, IHqlCppInstance * _code, ClusterType _targetClusterType, ICodegenContextCallback *_ctxCallback) : ctxCallback(_ctxCallback)
 {
+    //Insert a couple of warning mapping layers - one for global #onwarnigns, and another for local : onwarning
+    globalOnWarnings.setown(new ErrorSeverityMapper(*_errors));
+    localOnWarnings.setown(new ErrorSeverityMapper((IErrorReceiver &)*globalOnWarnings)); // horrible: cast required, otherwise copy constructor is called!
+
+    //Ensure that any errors reported within the code generator automatically abort compiling immediately
+    errorProcessor.setown(createAbortingErrorReceiver(*localOnWarnings));
     targetClusterType = _targetClusterType;
     {
         CriticalBlock block(*systemCS);
@@ -1395,7 +1401,6 @@ HqlCppTranslator::HqlCppTranslator(IErrorReceiver * _errors, const char * _soNam
     #endif
         }
     }
-    errors = _errors;
     hints = 0;
     litno = 0;
     soName.set(_soName);
@@ -1837,7 +1842,7 @@ void HqlCppTranslator::postProcessOptions()
         options.resourceConditionalActions = true;
 
     //Probably best to ignore this warning. - possibly configure it based on some other option
-    queryWarningProcessor().addGlobalOnWarning(HQLWRN_FoldRemoveKeyed, ignoreAtom);
+    globalOnWarnings->addOnWarning(HQLWRN_FoldRemoveKeyed, ignoreAtom);
 
     //Ensure the settings for the following options are always present in the workunit
     wu()->setDebugValueInt("expandPersistInputDependencies",options.expandPersistInputDependencies,true);
@@ -2046,11 +2051,11 @@ void HqlCppTranslator::doReportWarning(IHqlExpression * location, unsigned id, c
     if (!location)
         location = queryActiveActivityLocation();
     if (location)
-        warnError.setown(createECLError(false, id, msg, location->querySourcePath()->str(), location->getStartLine(), location->getStartColumn(), 0));
+        warnError.setown(createECLError(SeverityWarning, id, msg, location->querySourcePath()->str(), location->getStartLine(), location->getStartColumn(), 0));
     else
-        warnError.setown(createECLError(false, id, msg, NULL, 0, 0, 0));
+        warnError.setown(createECLError(SeverityWarning, id, msg, NULL, 0, 0, 0));
 
-    warningProcessor.report(NULL, errors, warnError);
+    errorProcessor->report(warnError);
 }
 
 void HqlCppTranslator::reportWarning(IHqlExpression * location, unsigned id, const char * msg, ...)
@@ -2133,7 +2138,7 @@ IHqlExpression * HqlCppTranslator::queryActiveActivityLocation() const
 void HqlCppTranslator::ThrowStringException(int code,const char *format, ...)
 {
     IHqlExpression * location = queryActiveActivityLocation();
-    if (errors && location)
+    if (errorProcessor && location)
     {
         StringBuffer errorMsg;
         va_list args;
@@ -2158,9 +2163,10 @@ void HqlCppTranslator::reportErrorDirect(IHqlExpression * location, int code,con
         loc.extractLocationAttr(location);
         if (alwaysAbort)
             throw createECLError(code, msg, loc.sourcePath->str(), loc.lineno, loc.column, loc.position);
-        errors->reportError(code, msg, loc.sourcePath->str(), loc.lineno, loc.column, loc.position);
+        errorProcessor->reportError(code, msg, loc.sourcePath->str(), loc.lineno, loc.column, loc.position);
     }
     else
+//        errorProcessor->reportError(code, msg, NULL, 0, 0, 0);
         throw MakeStringExceptionDirect(code, msg);
 }
 
@@ -12083,7 +12089,7 @@ IHqlExpression * HqlCppTranslator::getIndexedElementPointer(IHqlExpression * sou
 IHqlExpression * HqlCppTranslator::needFunction(IIdAtom * name)
 {
     assertex(name);
-    HqlDummyLookupContext dummyctx(errors);
+    HqlDummyLookupContext dummyctx(errorProcessor);
     return internalScope->lookupSymbol(name, LSFsharedOK, dummyctx);
 }
 

+ 6 - 5
ecl/hqlcpp/hqlcpp.ipp

@@ -939,14 +939,14 @@ public:
 
     unsigned getOptimizeFlags() const;
     unsigned getSourceAggregateOptimizeFlags() const;
-    inline void addGlobalOnWarning(IHqlExpression * setMetaExpr) { warningProcessor.addGlobalOnWarning(setMetaExpr); }
+    void addGlobalOnWarning(IHqlExpression * setMetaExpr);
 
     ClusterType getTargetClusterType() const { return targetClusterType; }
     inline bool targetRoxie() const { return targetClusterType == RoxieCluster; }
     inline bool targetHThor() const { return targetClusterType == HThorCluster; }
     inline bool targetThor() const { return isThorCluster(targetClusterType); }
-    inline IErrorReceiver * queryErrors() { return errors; }
-    inline WarningProcessor & queryWarningProcessor() { return warningProcessor; }
+    inline IErrorReceiver & queryErrorProcessor() { return *errorProcessor; }
+    inline ErrorSeverityMapper & queryLocalOnWarningMapper() { return *localOnWarnings; }
 
     void pushMemberFunction(MemberFunction & func);
     void popMemberFunction();
@@ -1903,7 +1903,9 @@ protected:
     ExprExprMap         physicalIndexCache;
     unsigned            litno;
     StringAttr          soName;
-    IErrorReceiver *    errors;
+    Owned<ErrorSeverityMapper> globalOnWarnings;
+    Owned<ErrorSeverityMapper> localOnWarnings;
+    Linked<IErrorReceiver> errorProcessor;
     HqlCppOptions       options;
     HqlCppDerived       derived;
     bool                checkedEmbeddedCpp;
@@ -1956,7 +1958,6 @@ protected:
     HqlExprArray activityExprStack;             //only used for improving the error reporting
     PointerArray recordIndexCache;
     Owned<ITimeReporter> timeReporter;
-    WarningProcessor warningProcessor;
     CIArrayOf<SourceFieldUsage> trackedSources;
 };
 

+ 1 - 1
ecl/hqlcpp/hqlcppds.cpp

@@ -1680,7 +1680,7 @@ IHqlExpression * HqlCppTranslator::getResourcedChildGraph(BuildCtx & ctx, IHqlEx
     {
         unsigned time = msTick();
         traceExpression("BeforeOptimizeSub", resourced);
-        resourced.setown(optimizeHqlExpression(resourced, getOptimizeFlags()|HOOcompoundproject));
+        resourced.setown(optimizeHqlExpression(queryErrorProcessor(), resourced, getOptimizeFlags()|HOOcompoundproject));
         traceExpression("AfterOptimizeSub", resourced);
         updateTimer("workunit;optimize graph", msTick()-time);
     }

+ 7 - 7
ecl/hqlcpp/hqlcpputil.cpp

@@ -278,7 +278,7 @@ IHqlExpression * addExpressionModifier(IHqlExpression * expr, typemod_t modifier
 
 
 
-static void expandFieldNames(StringBuffer & out, IHqlExpression * record, StringBuffer & prefix, const char * sep, IHqlExpression * formatFunc)
+static void expandFieldNames(IErrorReceiver & errorProcessor, StringBuffer & out, IHqlExpression * record, StringBuffer & prefix, const char * sep, IHqlExpression * formatFunc)
 {
     ForEachChild(i, record)
     {
@@ -286,10 +286,10 @@ static void expandFieldNames(StringBuffer & out, IHqlExpression * record, String
         switch (cur->getOperator())
         {
         case no_record:
-            expandFieldNames(out, cur, prefix, sep, formatFunc);
+            expandFieldNames(errorProcessor, out, cur, prefix, sep, formatFunc);
             break;
         case no_ifblock:
-            expandFieldNames(out, cur->queryChild(1), prefix, sep, formatFunc);
+            expandFieldNames(errorProcessor, out, cur->queryChild(1), prefix, sep, formatFunc);
             break;
         case no_field:
             {
@@ -300,7 +300,7 @@ static void expandFieldNames(StringBuffer & out, IHqlExpression * record, String
                     HqlExprArray args;
                     args.append(*createConstant(lowerName.str()));
                     OwnedHqlExpr bound = createBoundFunction(NULL, formatFunc, args, NULL, true);
-                    OwnedHqlExpr folded = foldHqlExpression(bound, NULL, HFOthrowerror|HFOfoldimpure|HFOforcefold);
+                    OwnedHqlExpr folded = foldHqlExpression(errorProcessor, bound, NULL, HFOthrowerror|HFOfoldimpure|HFOforcefold);
                     assertex(folded->queryValue());
                     lowerName.clear();
                     getStringValue(lowerName, folded);
@@ -313,7 +313,7 @@ static void expandFieldNames(StringBuffer & out, IHqlExpression * record, String
                     {
                         unsigned len = prefix.length();
                         prefix.append(lowerName).append(".");
-                        expandFieldNames(out, cur->queryRecord(), prefix, sep, formatFunc);
+                        expandFieldNames(errorProcessor, out, cur->queryRecord(), prefix, sep, formatFunc);
                         prefix.setLength(len);
                         break;
                     }
@@ -331,10 +331,10 @@ static void expandFieldNames(StringBuffer & out, IHqlExpression * record, String
     }
 }
 
-void expandFieldNames(StringBuffer & out, IHqlExpression * record, const char * sep, IHqlExpression * formatFunc)
+void expandFieldNames(IErrorReceiver & errorProcessor, StringBuffer & out, IHqlExpression * record, const char * sep, IHqlExpression * formatFunc)
 {
     StringBuffer prefix;
-    expandFieldNames(out, record, prefix, sep, formatFunc);
+    expandFieldNames(errorProcessor, out, record, prefix, sep, formatFunc);
 }
 
 

+ 1 - 1
ecl/hqlcpp/hqlcpputil.hpp

@@ -43,7 +43,7 @@ extern ITypeInfo * makeRowReferenceType(const CHqlBoundExpr & bound);
 
 extern IHqlExpression * addMemberSelector(IHqlExpression * expr, IHqlExpression * selector);
 extern IHqlExpression * addExpressionModifier(IHqlExpression * expr, typemod_t modifier, IInterface * extra=NULL);
-extern void expandFieldNames(StringBuffer & out, IHqlExpression * record, const char * sep, IHqlExpression * formatFunc);
+extern void expandFieldNames(IErrorReceiver & errorProcessor, StringBuffer & out, IHqlExpression * record, const char * sep, IHqlExpression * formatFunc);
 extern IHqlExpression * ensurePositiveOrZeroInt64(IHqlExpression * expr);
 
 extern void getOutputLibraryName(SCMStringBuffer & libraryName, IConstWorkUnit * wu);

+ 11 - 13
ecl/hqlcpp/hqlhtcpp.cpp

@@ -957,17 +957,15 @@ void TransformBuilder::doTransform(BuildCtx & ctx, IHqlExpression * transform, B
     IHqlExpression * body = transform->queryBody(true);
     if (transform != body)
     {
+        ErrorSeverityMapper::Scope saved(translator.queryLocalOnWarningMapper());
         switch (transform->getAnnotationKind())
         {
         case annotate_meta:
-            translator.queryWarningProcessor().processMetaAnnotation(transform);
+            translator.queryLocalOnWarningMapper().processMetaAnnotation(transform);
             break;
         case annotate_symbol:
-            {
-                WarningProcessor::OnWarningStateSymbolBlock saved(translator.queryWarningProcessor(), transform);
-                doTransform(ctx, body, self);
-                return;
-            }
+            translator.queryLocalOnWarningMapper().setSymbol(transform);
+            break;
         }
         doTransform(ctx, body, self);
         return;
@@ -6089,7 +6087,7 @@ IReferenceSelector * HqlCppTranslator::buildReference(BuildCtx & ctx, IHqlExpres
 ABoundActivity * HqlCppTranslator::buildActivity(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
 {
     checkAbort();
-    WarningProcessor::OnWarningStateBlock saved(warningProcessor);
+    ErrorSeverityMapper::Scope saved(*localOnWarnings);
 
     //Process any annotations first - but still pass the original expr to the doBuildActivtyXXX functions.
     IHqlExpression * cur = expr;
@@ -6102,7 +6100,7 @@ ABoundActivity * HqlCppTranslator::buildActivity(BuildCtx & ctx, IHqlExpression
         switch (cur->getAnnotationKind())
         {
         case annotate_meta:
-            warningProcessor.processMetaAnnotation(cur);
+            localOnWarnings->processMetaAnnotation(cur);  // state restored by OnWarningStateBlock
             break;
         case annotate_symbol:
             {
@@ -6122,7 +6120,7 @@ ABoundActivity * HqlCppTranslator::buildActivity(BuildCtx & ctx, IHqlExpression
                     }
                 }
 #endif
-                warningProcessor.setSymbol(cur);
+                localOnWarnings->setSymbol(cur);
                 break;
             }
         }
@@ -6715,7 +6713,7 @@ ABoundActivity * HqlCppTranslator::buildCachedActivity(BuildCtx & ctx, IHqlExpre
 
 void HqlCppTranslator::buildRootActivity(BuildCtx & ctx, IHqlExpression * expr)
 {
-    WarningProcessor::OnWarningStateBlock saved(warningProcessor);
+    ErrorSeverityMapper::Scope saved(*localOnWarnings);
     ::Release(buildCachedActivity(ctx, expr, true));
 }
 
@@ -9118,7 +9116,7 @@ IHqlExpression * HqlCppTranslator::optimizeGraphPostResource(IHqlExpression * ex
     {
         unsigned time = msTick();
         traceExpression("BeforeOptimize2", resourced);
-        resourced.setown(optimizeHqlExpression(resourced, getOptimizeFlags()|HOOcompoundproject));
+        resourced.setown(optimizeHqlExpression(queryErrorProcessor(), resourced, getOptimizeFlags()|HOOcompoundproject));
         traceExpression("AfterOptimize2", resourced);
         updateTimer("workunit;optimize graph", msTick()-time);
     }
@@ -9149,7 +9147,7 @@ IHqlExpression * HqlCppTranslator::getResourcedGraph(IHqlExpression * expr, IHql
     if (options.optimizeGraph)
     {
         unsigned time = msTick();
-        resourced.setown(optimizeHqlExpression(resourced, optFlags|HOOfiltersharedproject));
+        resourced.setown(optimizeHqlExpression(queryErrorProcessor(), resourced, optFlags|HOOfiltersharedproject));
         //have the following on an "aggressive fold" option?  If no_selects extract constants it can be quite impressive (jholt22.hql)
         //resourced.setown(foldHqlExpression(resourced));
         updateTimer("workunit;optimize graph", msTick()-time);
@@ -9373,7 +9371,7 @@ void HqlCppTranslator::buildCsvParameters(BuildCtx & subctx, IHqlExpression * cs
             {
                 StringBuffer comma;
                 expandDefaultString(comma, separator, ",");
-                expandFieldNames(names, record, comma.str(), queryAttributeChild(headerAttr, formatAtom, 0));
+                expandFieldNames(queryErrorProcessor(), names, record, comma.str(), queryAttributeChild(headerAttr, formatAtom, 0));
                 expandDefaultString(names, terminator, "\n");
             }
             OwnedHqlExpr namesExpr = createConstant(names.str());

+ 1 - 1
ecl/hqlcpp/hqliter.cpp

@@ -147,7 +147,7 @@ void TransformSequenceBuilder::buildSequence(BuildCtx & ctx, BuildCtx * declarec
             }
             OwnedHqlExpr test = getInverse(cond);
             if (translator.queryOptions().foldFilter)
-                test.setown(foldScopedHqlExpression(expr->queryChild(0)->queryNormalizedSelector(), test));
+                test.setown(foldScopedHqlExpression(translator.queryErrorProcessor(), expr->queryChild(0)->queryNormalizedSelector(), test));
             if (translator.queryOptions().spotCSE)
                 test.setown(spotScalarCSE(test));
             translator.buildFilteredReturn(ctx, test, failedFilterValue);

+ 5 - 5
ecl/hqlcpp/hqlresource.cpp

@@ -1840,10 +1840,10 @@ IHqlExpression * ResourcerInfo::wrapRowOwn(IHqlExpression * expr)
 
 //---------------------------------------------------------------------------
 
-EclResourcer::EclResourcer(IErrorReceiver * _errors, IConstWorkUnit * _wu, ClusterType _targetClusterType, unsigned _clusterSize, const HqlCppOptions & _translatorOptions)
+EclResourcer::EclResourcer(IErrorReceiver & _errors, IConstWorkUnit * _wu, ClusterType _targetClusterType, unsigned _clusterSize, const HqlCppOptions & _translatorOptions)
 { 
     wu.set(_wu);
-    errors = _errors;
+    errors = &_errors;
     lockTransformMutex(); 
     targetClusterType = _targetClusterType; 
     clusterSize = _clusterSize ? _clusterSize : FIXED_CLUSTER_SIZE;
@@ -5188,7 +5188,7 @@ IHqlExpression * resourceThorGraph(HqlCppTranslator & translator, IHqlExpression
 {
     HqlExprArray transformed;
     {
-        EclResourcer resourcer(translator.queryErrors(), translator.wu(), targetClusterType, clusterSize, translator.queryOptions());
+        EclResourcer resourcer(translator.queryErrorProcessor(), translator.wu(), targetClusterType, clusterSize, translator.queryOptions());
         if (graphIdExpr)
             resourcer.setNewChildQuery(graphIdExpr, 0);
 
@@ -5206,7 +5206,7 @@ static IHqlExpression * doResourceGraph(HqlCppTranslator & translator, HqlExprCo
     HqlExprArray transformed;
     unsigned totalResults;
     {
-        EclResourcer resourcer(translator.queryErrors(), translator.wu(), targetClusterType, clusterSize, translator.queryOptions());
+        EclResourcer resourcer(translator.queryErrorProcessor(), translator.wu(), targetClusterType, clusterSize, translator.queryOptions());
         if (isChild)
             resourcer.setChildQuery(true);
         resourcer.setNewChildQuery(graphIdExpr, numResults);
@@ -5254,7 +5254,7 @@ IHqlExpression * resourceRemoteGraph(HqlCppTranslator & translator, IHqlExpressi
 {
     HqlExprArray transformed;
     {
-        EclResourcer resourcer(translator.queryErrors(), translator.wu(), targetClusterType, clusterSize, translator.queryOptions());
+        EclResourcer resourcer(translator.queryErrorProcessor(), translator.wu(), targetClusterType, clusterSize, translator.queryOptions());
 
         resourcer.resourceRemoteGraph(expr, transformed);
     }

+ 1 - 1
ecl/hqlcpp/hqlresource.ipp

@@ -351,7 +351,7 @@ class EclResourcer
 {
     friend class SelectHoistTransformer;
 public:
-    EclResourcer(IErrorReceiver * _errors, IConstWorkUnit * _wu, ClusterType _targetClusterType, unsigned _clusterSize, const HqlCppOptions & _translatorOptions);
+    EclResourcer(IErrorReceiver & _errors, IConstWorkUnit * _wu, ClusterType _targetClusterType, unsigned _clusterSize, const HqlCppOptions & _translatorOptions);
     ~EclResourcer();
 
     void resourceGraph(IHqlExpression * expr, HqlExprArray & transformed);

+ 25 - 19
ecl/hqlcpp/hqlsource.cpp

@@ -67,6 +67,11 @@ inline bool needToSerializeRecord(IHqlExpression * mode)
 
 //---------------------------------------------------------------------------
 
+void HqlCppTranslator::addGlobalOnWarning(IHqlExpression * setMetaExpr)
+{
+    globalOnWarnings->addOnWarning(setMetaExpr);
+}
+
 unsigned HqlCppTranslator::getSourceAggregateOptimizeFlags() const
 {
     return getOptimizeFlags()|HOOfold|HOOinsidecompound;
@@ -855,14 +860,15 @@ void SourceBuilder::analyse(IHqlExpression * expr)
         switch (expr->getAnnotationKind())
         {
         case annotate_meta:
-            translator.queryWarningProcessor().processMetaAnnotation(expr);
+            //the onwarning state will be restored by the scope held in HqlCppTranslator::buildActivity
+            translator.localOnWarnings->processMetaAnnotation(expr);
             break;
         case annotate_location:
             instance->addLocationAttribute(expr);
             break;
         case annotate_symbol:
-            instance->addNameAttribute(expr);
             //don't clear onWarnings when we hit a symbol because the warnings within a compound activity aren't generated at the correct point
+            instance->addNameAttribute(expr);
             break;
         }
         analyse(body);
@@ -1373,7 +1379,7 @@ void SourceBuilder::buildTransformElements(BuildCtx & ctx, IHqlExpression * expr
                     IHqlExpression * ds = expr->queryChild(0);
                     OwnedHqlExpr test = returnIfFilterFails ? getInverse(cond) : LINK(cond);
                     if (translator.queryOptions().foldFilter)
-                        test.setown(foldScopedHqlExpression(ds->queryNormalizedSelector(), test));
+                        test.setown(foldScopedHqlExpression(translator.queryErrorProcessor(), ds->queryNormalizedSelector(), test));
 
                     if (translator.options.spotCSE)
                         test.setown(spotScalarCSE(test, ds));
@@ -1780,6 +1786,7 @@ inline bool useDescriptiveGraphLabel(ThorActivityKind kind)
 ABoundActivity * SourceBuilder::buildActivity(BuildCtx & ctx, IHqlExpression * expr, ThorActivityKind _activityKind, const char *kind, ABoundActivity *input)
 {
     activityKind = _activityKind;
+
     translator.gatherActiveCursors(ctx, parentCursors);
 
     bool isSpill = tableExpr && tableExpr->hasAttribute(_spill_Atom);
@@ -1933,7 +1940,6 @@ ABoundActivity * SourceBuilder::buildActivity(BuildCtx & ctx, IHqlExpression * e
     instance->graphLabel.set(graphLabel.str());
 
     translator.buildActivityFramework(localInstance);
-
     translator.buildInstancePrefix(localInstance);
 
     analyseGraph(expr);
@@ -2884,7 +2890,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivityDiskRead(BuildCtx & ctx, IHqlE
         //Need to wrap a possible no_usertable, otherwise the localisation can go wrong.
         if (expr->getOperator() == no_table)
             transformed.setown(createDataset(no_compound_diskread, LINK(transformed)));
-        OwnedHqlExpr optimized = optimizeHqlExpression(transformed, optFlags);
+        OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, optFlags);
         traceExpression("after disk optimize", optimized);
         return doBuildActivityDiskRead(ctx, optimized);
     }
@@ -2893,7 +2899,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivityDiskRead(BuildCtx & ctx, IHqlE
     if (expr->getOperator() == no_table)
         optimized.set(expr);
     else
-        optimized.setown(optimizeHqlExpression(expr, optFlags));
+        optimized.setown(optimizeHqlExpression(queryErrorProcessor(), expr, optFlags));
 
     if (optimized != expr)
         return buildActivity(ctx, optimized, false);
@@ -2972,7 +2978,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivityDiskNormalize(BuildCtx & ctx,
         transformed.setown(buildTableWithoutVirtuals(info.fieldInfo, expr));
 
     unsigned optFlags = (options.foldOptimized ? HOOfold : 0);
-    OwnedHqlExpr optimized = optimizeHqlExpression(transformed, optFlags);
+    OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, optFlags);
     if (optimized != expr)
         return buildActivity(ctx, optimized, false);
 
@@ -3127,7 +3133,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivityDiskAggregate(BuildCtx & ctx,
     LinkedHqlExpr transformed = expr;
     if (info.recordHasVirtualsOrDeserialize())
         transformed.setown(buildTableWithoutVirtuals(info.fieldInfo, expr));
-    transformed.setown(optimizeHqlExpression(transformed, getSourceAggregateOptimizeFlags()));
+    transformed.setown(optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags()));
 
     if (transformed != expr)
         return buildActivity(ctx, transformed, false);
@@ -3204,7 +3210,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivityDiskGroupAggregate(BuildCtx &
     LinkedHqlExpr transformed = expr;
     if (info.recordHasVirtualsOrDeserialize())
         transformed.setown(buildTableWithoutVirtuals(info.fieldInfo, expr));
-    transformed.setown(optimizeHqlExpression(transformed, getSourceAggregateOptimizeFlags()));
+    transformed.setown(optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags()));
 
     if (transformed != expr)
         return buildActivity(ctx, transformed, false);
@@ -3279,7 +3285,7 @@ void ChildNormalizeBuilder::buildTransform(IHqlExpression * expr)
 ABoundActivity * HqlCppTranslator::doBuildActivityChildNormalize(BuildCtx & ctx, IHqlExpression * expr)
 {
     ChildNormalizeBuilder info(*this, NULL, NULL);
-    OwnedHqlExpr optimized = optimizeHqlExpression(expr, HOOfold);
+    OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), expr, HOOfold);
 
     if (optimized != expr)
         return buildActivity(ctx, optimized, false);
@@ -3336,7 +3342,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivityChildAggregate(BuildCtx & ctx,
 {
     ChildAggregateBuilder info(*this, NULL, NULL);
 
-    OwnedHqlExpr transformed = optimizeHqlExpression(expr, getSourceAggregateOptimizeFlags());
+    OwnedHqlExpr transformed = optimizeHqlExpression(queryErrorProcessor(), expr, getSourceAggregateOptimizeFlags());
     if (transformed != expr)
         return buildActivity(ctx, transformed, false);
 
@@ -3399,7 +3405,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivityChildGroupAggregate(BuildCtx &
 {
     ChildGroupAggregateBuilder info(*this, NULL, NULL);
 
-    OwnedHqlExpr transformed = optimizeHqlExpression(expr, getSourceAggregateOptimizeFlags());
+    OwnedHqlExpr transformed = optimizeHqlExpression(queryErrorProcessor(), expr, getSourceAggregateOptimizeFlags());
     if (transformed != expr)
         return buildActivity(ctx, transformed, false);
 
@@ -3456,7 +3462,7 @@ void ChildThroughNormalizeBuilder::buildTransform(IHqlExpression * expr)
 
 ABoundActivity * HqlCppTranslator::doBuildActivityCompoundSelectNew(BuildCtx & ctx, IHqlExpression * expr)
 {
-    OwnedHqlExpr optimized = optimizeHqlExpression(expr, HOOfold);
+    OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), expr, HOOfold);
     if (optimized->getOperator() == no_null)
         return buildCachedActivity(ctx, optimized);
 
@@ -6390,7 +6396,7 @@ void NewIndexReadBuilder::buildTransform(IHqlExpression * expr)
 ABoundActivity * HqlCppTranslator::doBuildActivityIndexRead(BuildCtx & ctx, IHqlExpression * expr)
 {
     OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
-    OwnedHqlExpr optimized = optimizeHqlExpression(transformed, HOOfold);
+    OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, HOOfold);
 
     IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
     //If the filter is false, then it may get reduced to a NULL operation!
@@ -6467,7 +6473,7 @@ void IndexNormalizeBuilder::buildTransform(IHqlExpression * expr)
 ABoundActivity * HqlCppTranslator::doBuildActivityIndexNormalize(BuildCtx & ctx, IHqlExpression * expr)
 {
     OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
-    OwnedHqlExpr optimized = optimizeHqlExpression(transformed, HOOfold);
+    OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, HOOfold);
     traceExpression("after optimize", optimized);
 
     IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
@@ -6635,7 +6641,7 @@ void IndexCountBuilder::buildTransform(IHqlExpression * expr)
 ABoundActivity * HqlCppTranslator::doBuildActivityIndexAggregate(BuildCtx & ctx, IHqlExpression * expr)
 {
     OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
-    OwnedHqlExpr optimized = optimizeHqlExpression(transformed, getSourceAggregateOptimizeFlags());
+    OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags());
 
     IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
     if (!tableExpr)
@@ -6797,7 +6803,7 @@ void IndexGroupAggregateBuilder::buildTransform(IHqlExpression * expr)
 ABoundActivity * HqlCppTranslator::doBuildActivityIndexGroupAggregate(BuildCtx & ctx, IHqlExpression * expr)
 {
     OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
-    OwnedHqlExpr optimized = optimizeHqlExpression(transformed, getSourceAggregateOptimizeFlags());
+    OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags());
 
     IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
     if (!tableExpr)
@@ -7237,13 +7243,13 @@ ABoundActivity * HqlCppTranslator::doBuildActivityFetch(BuildCtx & ctx, IHqlExpr
         OwnedHqlExpr null = createDataset(no_anon, LINK(fetchRhs->queryRecord()));
         OwnedHqlExpr simple = replaceFetchInput(expr, null, no_right);
         OwnedHqlExpr transformed = replaceExpression(simple, tableExpr, projected);
-        OwnedHqlExpr optSimple = optimizeHqlExpression(transformed, optFlags);
+        OwnedHqlExpr optSimple = optimizeHqlExpression(queryErrorProcessor(), transformed, optFlags);
         OwnedHqlExpr optimized = replaceFetchInput(optSimple, fetchRhs, no_right);
         return doBuildActivityFetch(ctx, optimized);
     }
     if (getProjectCount(expr) > 1)
     {
-        OwnedHqlExpr optimized = optimizeHqlExpression(expr, optFlags);
+        OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), expr, optFlags);
         return doBuildActivityFetch(ctx, optimized);
     }
 

+ 1 - 1
ecl/hqlcpp/hqltcppc.cpp

@@ -2340,7 +2340,7 @@ void CBitfieldInfo::setColumn(HqlCppTranslator & translator, BuildCtx & ctx, IRe
     if (bitOffset > 0)
         newValue.setown(createValue(no_lshift, LINK(storageType), newValue.getClear(), getSizetConstant(bitOffset)));
     if (newValue->isConstant())
-        newValue.setown(foldHqlExpression(newValue, 0, 0));
+        newValue.setown(foldHqlExpression(translator.queryErrorProcessor(), newValue));
     OwnedHqlExpr final = createValue(no_bor, LINK(storageType), oldValue, newValue.getClear());
 
     CHqlBoundTarget boundTarget;

+ 39 - 84
ecl/hqlcpp/hqlttcpp.cpp

@@ -8988,8 +8988,8 @@ Note:
   */
 
 static HqlTransformerInfo hqlScopeTaggerInfo("HqlScopeTagger");
-HqlScopeTagger::HqlScopeTagger(IErrorReceiver * _errors)
-: ScopedDependentTransformer(hqlScopeTaggerInfo), errors(_errors)
+HqlScopeTagger::HqlScopeTagger(IErrorReceiver & _errors, ErrorSeverityMapper & _errorMapper)
+: ScopedDependentTransformer(hqlScopeTaggerInfo), errors(_errors), errorMapper(_errorMapper)
 {
 }
 
@@ -9051,7 +9051,7 @@ void HqlScopeTagger::checkActiveRow(IHqlExpression * expr)
         getECL(expr, exprText);
         elideString(exprText, 20);
         VStringBuffer msg("ROW(%s) - dataset argument is not in scope.  Did you mean dataset[1]?", exprText.str());
-        reportError(msg);
+        reportError(msg, SeverityFatal);
     }
 }
 
@@ -9082,7 +9082,7 @@ void HqlScopeTagger::reportSelectorError(IHqlExpression * selector, IHqlExpressi
             getExprIdentifier(datasetName, selector).str());
     }
 
-    reportError(msg);
+    reportError(msg, SeverityFatal);
 }
 
 
@@ -9100,7 +9100,7 @@ IHqlExpression * HqlScopeTagger::transformSelect(IHqlExpression * expr)
             case no_right:
                 StringBuffer exprText, datasetName;
                 VStringBuffer msg("%s - %s not in scope, possibly passed into a global/workflow definition", getECL(expr, exprText), getExprIdentifier(datasetName, ds).str());
-                reportError(msg);
+                reportError(msg, SeverityFatal);
                 break;
             }
         }
@@ -9114,7 +9114,7 @@ IHqlExpression * HqlScopeTagger::transformSelect(IHqlExpression * expr)
         {
             StringBuffer exprText;
             VStringBuffer msg("dictionary %s must be explicitly NORMALIZED", getECL(expr, exprText));
-            reportError(msg, false);
+            reportError(msg, SeverityFatal);
         }
         else if (expr->isDataset())
         {
@@ -9122,7 +9122,7 @@ IHqlExpression * HqlScopeTagger::transformSelect(IHqlExpression * expr)
             {
                 StringBuffer exprText;
                 VStringBuffer msg("dataset %s may not be supported without using NORMALIZE", getECL(expr, exprText));
-                reportError(msg, true);
+                reportError(msg, SeverityWarning);
             }
         }
         else
@@ -9199,7 +9199,7 @@ IHqlExpression * HqlScopeTagger::transformNewDataset(IHqlExpression * expr, bool
             {
                 StringBuffer exprText;
                 VStringBuffer msg("%s - Need to use active(dataset) to refer to the current row of an active dataset", getECL(expr, exprText));
-                reportError(msg, false);
+                reportError(msg, SeverityFatal);
             }
         }
         return transformed.getClear();
@@ -9211,7 +9211,7 @@ IHqlExpression * HqlScopeTagger::transformNewDataset(IHqlExpression * expr, bool
         {
             StringBuffer exprText;
             VStringBuffer msg("%s - Need to use active(dataset) to refer to the current row of an active dataset", getECL(expr, exprText));
-            reportError(msg);
+            reportError(msg, SeverityFatal);
         }
 
         return ensureActiveRow(transformed->queryNormalizedSelector());
@@ -9319,7 +9319,7 @@ IHqlExpression * HqlScopeTagger::transformWithin(IHqlExpression * dataset, IHqlE
     {
         StringBuffer exprText;
         VStringBuffer msg("%s - dataset filtered by WITHIN is too complex", getECL(dataset, exprText));
-        reportError(msg);
+        reportError(msg, SeverityFatal);
         return transform(dataset);
     }
 
@@ -9343,7 +9343,7 @@ IHqlExpression * HqlScopeTagger::transformRelated(IHqlExpression * expr)
     {
         StringBuffer exprText;
         VStringBuffer msg("dataset \"%s\" used in WITHIN is not in scope", getECL(scope, exprText));
-        reportError(msg);
+        reportError(msg, SeverityFatal);
     }
 
     //Check the ds is a table
@@ -9352,7 +9352,7 @@ IHqlExpression * HqlScopeTagger::transformRelated(IHqlExpression * expr)
     {
         StringBuffer exprText;
         VStringBuffer msg("dataset \"%s\" used as parameter to WITHIN is too complex", getECL(expr, exprText));
-        reportError(msg);
+        reportError(msg, SeverityFatal);
     }
 
     return transformWithin(ds, scope->queryNormalizedSelector());
@@ -9367,19 +9367,23 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
         switch (expr->getAnnotationKind())
         {
         case annotate_meta:
-            collector.processMetaAnnotation(expr);
+            {
+                unsigned max = errorMapper.processMetaAnnotation(expr);
+                OwnedHqlExpr transformedBody = transform(body);
+                errorMapper.restoreLocalOnWarnings(max);
+                if (body == transformedBody)
+                    return LINK(expr);
+                return expr->cloneAnnotation(transformedBody);
+            }
             break;
         case annotate_symbol:
             {
-                WarningProcessor::OnWarningState saved;
-                collector.pushSymbol(saved, expr);
+                ErrorSeverityMapper::SymbolScope saved(errorMapper, expr);
                 OwnedHqlExpr transformedBody = transform(body);
-                collector.popSymbol(saved);
                 if (body == transformedBody)
                     return LINK(expr);
                 return expr->cloneAnnotation(transformedBody);
             }
-            break;
         case annotate_location:
             {
                 break;
@@ -9391,7 +9395,6 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
         return expr->cloneAnnotation(transformedBody);
     }
 
-    collector.checkForGlobalOnWarning(expr);
     switch (expr->getOperator())
     {
     case no_left:
@@ -9425,7 +9428,7 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
             {
                 StringBuffer exprText;
                 VStringBuffer msg("dataset %s mistakenly interpreted as a datarow, possibly due to missing dataset() in parameter type", getECL(ds, exprText));
-                reportError(msg);
+                reportError(msg, SeverityFatal);
             }
             return transformAmbiguousChildren(expr);
         }
@@ -9453,7 +9456,7 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
             {
                 StringBuffer exprText;
                 VStringBuffer msg("dataset expression (%s) assigned to field '%s' with type row", getECL(rhs, exprText), lhs->queryChild(1)->queryName()->str());
-                reportError(msg.str());
+                reportError(msg.str(), SeverityFatal);
             }
             if (rhs == newRhs)
                 return LINK(expr);
@@ -9469,7 +9472,7 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
         {
             OwnedHqlExpr transformed = Parent::createTransformed(expr);
             if (transformed->queryChild(0)->isDataset())
-                reportError("PROJECT() row argument resolved to a dataset.  Missing DATASET() from parameter type?");
+                reportError("PROJECT() row argument resolved to a dataset.  Missing DATASET() from parameter type?", SeverityFatal);
             return transformed.getClear();
         }
     case no_merge:
@@ -9493,7 +9496,7 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
                 {
                     if (sorts.item(i).isAttribute())
                     {
-                        reportError(HQLWRN_MergeBadSortOrder_Text, true);
+                        reportError(HQLWRN_MergeBadSortOrder_Text, SeverityWarning);
                         sorts.remove(i);
                     }
                 }
@@ -9507,22 +9510,15 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
 }
 
 
-void HqlScopeTagger::reportWarnings()
-{
-    if (errors)
-        collector.report(*errors);
-}
-
-
-void HqlScopeTagger::reportError(const char * msg, bool warning)
+void HqlScopeTagger::reportError(const char * msg, ErrorSeverity severity)
 {
-    IHqlExpression * location = collector.queryActiveSymbol();
+    IHqlExpression * location = errorMapper.queryActiveSymbol();
     //Make this an error when we are confident...
     int startLine= location ? location->getStartLine() : 0;
     int startColumn = location ? location->getStartColumn() : 0;
     ISourcePath * sourcePath = location ? location->querySourcePath() : NULL;
-    Owned<IECLError> err = createECLError(!warning, ERR_ASSERT_WRONGSCOPING, msg, sourcePath->str(), startLine, startColumn, 0);
-    collector.report(NULL, errors, err);        // will throw immediately if it is an error.
+    Owned<IECLError> err = createECLError(severity, ERR_ASSERT_WRONGSCOPING, msg, sourcePath->str(), startLine, startColumn, 0);
+    errors.report(err);        // will throw immediately if it is an error.
 }
 
 
@@ -10540,7 +10536,7 @@ HqlTreeNormalizer::HqlTreeNormalizer(HqlCppTranslator & _translator) : NewHqlTra
     options.constantFoldNormalize = translatorOptions.constantFoldNormalize;
     options.allowActivityForKeyedJoin = translatorOptions.allowActivityForKeyedJoin;
     options.implicitSubSort = translatorOptions.implicitBuildIndexSubSort;
-    errors = translator.queryErrors();
+    errorProcessor = &translator.queryErrorProcessor();
     nextSequenceValue = 1;
 }
 
@@ -11016,57 +11012,17 @@ IHqlExpression * HqlTreeNormalizer::transformMap(IHqlExpression * expr)
     return elseExpr.getClear();
 }
 
-class AbortingErrorReceiver : extends CInterface, implements IErrorReceiver
-{
-public:
-    AbortingErrorReceiver(IErrorReceiver * _errors)
-    {
-        errors = _errors ? _errors : &defaultReporter;
-    }
-    IMPLEMENT_IINTERFACE
-
-    virtual void reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int pos)
-    {
-        errors->reportError(errNo, msg, filename, lineno, column, pos);
-        throw MakeStringException(HQLERR_ErrorAlreadyReported, "%s", "");
-    }
-    virtual void report(IECLError* error)
-    {
-        errors->report(error);
-        throw MakeStringException(HQLERR_ErrorAlreadyReported, "%s", "");
-    }
-    virtual void reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
-    {
-        errors->reportWarning(warnNo, msg, filename, lineno, column, pos);
-    }
-    virtual size32_t errCount()
-    {
-        return errors->errCount();
-    }
-    virtual size32_t warnCount()
-    {
-        return errors->warnCount();
-    }
-
-protected:
-    IErrorReceiver * errors;
-    ThrowingErrorReceiver defaultReporter;
-};
-
-
 IHqlExpression * HqlTreeNormalizer::transformTempRow(IHqlExpression * expr)
 {
     ECLlocation dummyLocation(0, 0, 0, NULL);
-    AbortingErrorReceiver errorReporter(errors);
-    OwnedHqlExpr createRow = convertTempRowToCreateRow(&errorReporter, dummyLocation, expr);
+    OwnedHqlExpr createRow = convertTempRowToCreateRow(translator.queryErrorProcessor(), dummyLocation, expr);
     return transform(createRow);
 }
 
 IHqlExpression * HqlTreeNormalizer::transformTempTable(IHqlExpression * expr)
 {
     ECLlocation dummyLocation(0, 0, 0, NULL);
-    AbortingErrorReceiver errorReporter(errors);
-    OwnedHqlExpr inlineTable = convertTempTableToInlineTable(errorReporter, dummyLocation, expr);
+    OwnedHqlExpr inlineTable = convertTempTableToInlineTable(translator.queryErrorProcessor(), dummyLocation, expr);
     if (expr != inlineTable)
         return transform(inlineTable);
 
@@ -12188,7 +12144,7 @@ IHqlExpression * HqlTreeNormalizer::createTransformedBody(IHqlExpression * expr)
         {
             IHqlExpression * child = expr->queryChild(0);
             OwnedHqlExpr ret = transform(child);
-            OwnedHqlExpr folded  = foldHqlExpression(ret, NULL, HFOforcefold);
+            OwnedHqlExpr folded  = foldHqlExpression(translator.queryErrorProcessor(), ret, NULL, HFOforcefold);
             if (!folded->isConstant())
             {
                 StringBuffer s;
@@ -12201,7 +12157,7 @@ IHqlExpression * HqlTreeNormalizer::createTransformedBody(IHqlExpression * expr)
         {
             ECLlocation errpos;
             errpos.extractLocationAttr(expr->queryChild(1));
-            reportAbstractModule(translator.queryErrors(), expr->queryChild(0), errpos);
+            reportAbstractModule(translator.queryErrorProcessor(), expr->queryChild(0), errpos);
             throw MakeStringException(HQLERR_ErrorAlreadyReported, "%s", "");
         }
     case no_pat_instance:
@@ -12374,7 +12330,7 @@ IHqlExpression * HqlTreeNormalizer::createTransformedBody(IHqlExpression * expr)
                 IHqlExpression * module = oldFuncdef->queryChild(1);
                 ECLlocation errpos(module);
                 //errpos.extractLocationAttr(expr->queryChild(1));
-                reportAbstractModule(translator.queryErrors(), module, errpos);
+                reportAbstractModule(translator.queryErrorProcessor(), module, errpos);
                 throw MakeStringException(HQLERR_ErrorAlreadyReported, "%s", "");
             }
             assertex(oldFuncdef->getOperator() == no_funcdef);
@@ -12586,12 +12542,11 @@ void normalizeHqlTree(HqlCppTranslator & translator, HqlExprArray & exprs)
 
     {
         unsigned time = msTick();
-        HqlScopeTagger normalizer(translator.queryErrors());
+        HqlScopeTagger normalizer(translator.queryErrorProcessor(), translator.queryLocalOnWarningMapper());
         HqlExprArray transformed;
         normalizer.transformRoot(exprs, transformed);
         replaceArray(exprs, transformed);
         translator.updateTimer("workunit;tree transform: normalize.scope", msTick()-time);
-        normalizer.reportWarnings();
     }
 
     if (translator.queryOptions().normalizeLocations)
@@ -12833,7 +12788,7 @@ bool HqlCppTranslator::transformGraphForGeneration(HqlQueryContext & query, Work
     //Don't change the engine if libraries are involved, otherwise things will get very confused.
 
     unsigned timeCall = msTick();
-    expandDelayedFunctionCalls(queryErrors(), exprs);
+    expandDelayedFunctionCalls(&queryErrorProcessor(), exprs);
     updateTimer("workunit;tree transform: expand delayed calls", msTick()-timeCall);
 
 
@@ -12884,7 +12839,7 @@ bool HqlCppTranslator::transformGraphForGeneration(HqlQueryContext & query, Work
         if (options.globalFoldOptions != (unsigned)-1)
             foldOptions = options.globalFoldOptions;
 
-        foldHqlExpression(folded, exprs, foldOptions);
+        foldHqlExpression(queryErrorProcessor(), folded, exprs, foldOptions);
         replaceArray(exprs, folded);
         updateTimer("workunit;tree transform: global fold", msTick()-startTime);
     }
@@ -12896,7 +12851,7 @@ bool HqlCppTranslator::transformGraphForGeneration(HqlQueryContext & query, Work
     {
         unsigned startTime = msTick();
         HqlExprArray folded;
-        optimizeHqlExpression(folded, exprs, HOOfold);
+        optimizeHqlExpression(queryErrorProcessor(), folded, exprs, HOOfold);
         replaceArray(exprs, folded);
         updateTimer("workunit;tree transform: global optimize", msTick()-startTime);
     }

+ 5 - 7
ecl/hqlcpp/hqlttcpp.ipp

@@ -1027,13 +1027,11 @@ class HqlScopeTagger : public ScopedDependentTransformer
 {
     typedef ScopedDependentTransformer Parent;
 public:
-    HqlScopeTagger(IErrorReceiver * _errors);
+    HqlScopeTagger(IErrorReceiver & _errors, ErrorSeverityMapper & _errorMapper);
 
     virtual IHqlExpression * createTransformed(IHqlExpression * expr);
     virtual ANewTransformInfo * createTransformInfo(IHqlExpression * expr);
 
-    void reportWarnings();
-
 protected:
     void checkActiveRow(IHqlExpression * expr);
     IHqlExpression * transformSelect(IHqlExpression * expr);
@@ -1047,12 +1045,12 @@ protected:
     IHqlExpression * transformWithin(IHqlExpression * dataset, IHqlExpression * scope);
 
     bool isValidNormalizeSelector(IHqlExpression * expr);
-    void reportError(const char * msg, bool warning = false);
+    void reportError(const char * msg, ErrorSeverity severity);
     void reportSelectorError(IHqlExpression * selector, IHqlExpression * expr);
 
 protected:
-    IErrorReceiver * errors;
-    WarningProcessor collector;
+    IErrorReceiver & errors;
+    ErrorSeverityMapper & errorMapper;
 };
 
 //---------------------------------------------------------------------------
@@ -1202,7 +1200,7 @@ protected:
 
 protected:
     HqlCppTranslator & translator;
-    IErrorReceiver * errors;
+    IErrorReceiver * errorProcessor;
 
     HqlExprArray forwardReferences;
     HqlExprArray defines;

+ 24 - 0
ecl/regress/issue9556.ecl

@@ -0,0 +1,24 @@
+/*##############################################################################
+
+    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.
+############################################################################## */
+
+r1 := { unsigned id; };
+r2 := { dataset(r1) ds; };
+ds := DATASET('x', r2, thor);
+
+#onwarning (2131, ignore);
+x := NOFOLD(ds).ds;
+output(x);

+ 10 - 0
ecl/regress/issue9556a.eclxml

@@ -0,0 +1,10 @@
+<Archive legacyImport="0"
+         legacyWhen="0">
+ <Query attributePath="_local_directory_.temp"/>
+ <OnWarning value="1006=ignore"/>
+ <Module key="_local_directory_" name="_local_directory_">
+  <Attribute key="temp" name="temp" sourcePath="temp.ecl">
+   case(0,&apos;default&apos;);&#10;&#10;&#10;
+  </Attribute>
+ </Module>
+</Archive>

+ 10 - 0
ecl/regress/issue9556b.eclxml

@@ -0,0 +1,10 @@
+<Archive legacyImport="0"
+         legacyWhen="0">
+ <Query attributePath="_local_directory_.temp"/>
+ <OnWarning value="1006=log"/>
+ <Module key="_local_directory_" name="_local_directory_">
+  <Attribute key="temp" name="temp" sourcePath="temp.ecl">
+   case(0,&apos;default&apos;);&#10;&#10;&#10;
+  </Attribute>
+ </Module>
+</Archive>

+ 10 - 0
ecl/regress/issue9556c.eclxml

@@ -0,0 +1,10 @@
+<Archive legacyImport="0"
+         legacyWhen="0">
+ <Query attributePath="_local_directory_.temp"/>
+ <OnWarning value="1006=error"/>
+ <Module key="_local_directory_" name="_local_directory_">
+  <Attribute key="temp" name="temp" sourcePath="temp.ecl">
+   case(0,&apos;default&apos;);&#10;&#10;&#10;
+  </Attribute>
+ </Module>
+</Archive>

+ 10 - 0
ecl/regress/issue9556d.eclxml

@@ -0,0 +1,10 @@
+<Archive legacyImport="0"
+         legacyWhen="0">
+ <Query attributePath="_local_directory_.temp"/>
+ <OnWarning value="1006-"/>
+ <Module key="_local_directory_" name="_local_directory_">
+  <Attribute key="temp" name="temp" sourcePath="temp.ecl">
+   case(0,&apos;default&apos;);&#10;&#10;&#10;
+  </Attribute>
+ </Module>
+</Archive>

+ 10 - 0
ecl/regress/issue9556e.eclxml

@@ -0,0 +1,10 @@
+<Archive legacyImport="0"
+         legacyWhen="0">
+ <Query attributePath="_local_directory_.temp"/>
+ <OnWarning value="1006+"/>
+ <Module key="_local_directory_" name="_local_directory_">
+  <Attribute key="temp" name="temp" sourcePath="temp.ecl">
+   case(0,&apos;default&apos;);&#10;&#10;&#10;
+  </Attribute>
+ </Module>
+</Archive>

+ 25 - 0
ecl/regress/issue9556f.eclxml

@@ -0,0 +1,25 @@
+<Archive>
+<!--
+
+    HPCC SYSTEMS software Copyright (C) 2014 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.
+-->
+ <OnWarning value="2131=ignore"/>
+ <Query>
+idRec := { unsigned id; };
+inRec := { unsigned id, dataset(idRec) ids; };
+d := DATASET('in', inRec, thor);
+output(SORT(d, id).ids);
+ </Query>
+</Archive>

+ 25 - 0
ecl/regress/issue9556g.eclxml

@@ -0,0 +1,25 @@
+<Archive>
+<!--
+
+    HPCC SYSTEMS software Copyright (C) 2014 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.
+-->
+ <OnWarning value="2131=error"/>
+ <Query>
+idRec := { unsigned id; };
+inRec := { unsigned id, dataset(idRec) ids; };
+d := DATASET('in', inRec, thor);
+output(SORT(d, id).ids);
+ </Query>
+</Archive>

+ 32 - 0
ecl/regress/issue9556h.eclxml

@@ -0,0 +1,32 @@
+<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" flags="65536">
+export v1 := 'Hello';
+  </Attribute>
+  <Attribute name="v2" flags="65536">
+export v2 := 'World';
+  </Attribute>
+ </Module>
+ <Query>
+
+import common;
+output(common.v1 + ' ' + common.v2 + '!');
+
+ </Query>
+</Archive>

+ 27 - 0
ecl/regress/issue9556i.eclxml

@@ -0,0 +1,27 @@
+<Archive>
+<!--
+
+    HPCC SYSTEMS software Copyright (C) 2014 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.
+-->
+ <OnWarning value="2131=error"/>
+ <Query>
+//Command line maps it to an error, but #ONWARNING maps it to just log the information
+#ONWARNING(2131, LOG);
+idRec := { unsigned id; };
+inRec := { unsigned id, dataset(idRec) ids; };
+d := DATASET('in', inRec, thor);
+output(SORT(d, id).ids);
+ </Query>
+</Archive>

+ 29 - 0
ecl/regress/issue9556j.eclxml

@@ -0,0 +1,29 @@
+<Archive>
+<!--
+
+    HPCC SYSTEMS software Copyright (C) 2014 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.
+-->
+ <OnWarning value="2131=error"/>
+ <Query>
+//Command line maps it to an error, but #ONWARNING maps it to information
+//but local onwarning maps it back to an error!
+#ONWARNING(2131, LOG);
+idRec := { unsigned id; };
+inRec := { unsigned id, dataset(idRec) ids; };
+d := DATASET('in', inRec, thor);
+ids := SORT(d, id).ids : onwarning(2131, error);
+output(ids);
+ </Query>
+</Archive>

+ 28 - 0
ecl/regress/issue9556k.eclxml

@@ -0,0 +1,28 @@
+<Archive>
+<!--
+
+    HPCC SYSTEMS software Copyright (C) 2014 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.
+-->
+ <OnWarning value="2131=fail"/>
+ <Query>
+//Command line maps it to a fatal error, #ONWARNING and local onwarning try to map it back, but fail
+#ONWARNING(2131, LOG);
+idRec := { unsigned id; };
+inRec := { unsigned id, dataset(idRec) ids; };
+d := DATASET('in', inRec, thor);
+ids := SORT(d, id).ids : onwarning(2131, ignore);
+output(ids);
+ </Query>
+</Archive>

+ 27 - 0
ecl/regress/issue9556l_err.eclxml

@@ -0,0 +1,27 @@
+<Archive>
+<!--
+
+    HPCC SYSTEMS software Copyright (C) 2014 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.
+-->
+ <OnWarning value="2131=unknown"/>
+ <Query>
+//Test unknown severity
+idRec := { unsigned id; };
+inRec := { unsigned id, dataset(idRec) ids; };
+d := DATASET('in', inRec, thor);
+ids := SORT(d, id).ids : onwarning(2131, ignore);
+output(ids);
+ </Query>
+</Archive>

+ 27 - 0
ecl/regress/issue9556m_err.eclxml

@@ -0,0 +1,27 @@
+<Archive>
+<!--
+
+    HPCC SYSTEMS software Copyright (C) 2014 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.
+-->
+ <OnWarning value="unknown=ignore"/>
+ <Query>
+//Test unknown severity
+idRec := { unsigned id; };
+inRec := { unsigned id, dataset(idRec) ids; };
+d := DATASET('in', inRec, thor);
+ids := SORT(d, id).ids : onwarning(2131, ignore);
+output(ids);
+ </Query>
+</Archive>

+ 1 - 0
esp/services/ws_dfu/ws_dfuService.cpp

@@ -51,6 +51,7 @@
 #include "ws_dfuService.hpp"
 
 #include "hqlerror.hpp"
+#include "hqlexpr.hpp"
 #include "eclrtl.hpp"
 
 #define     Action_Delete           "Delete"

+ 1 - 0
esp/services/ws_workunits/ws_workunitsHelpers.cpp

@@ -28,6 +28,7 @@
 #include "wuwebview.hpp"
 #include "dllserver.hpp"
 #include "wujobq.hpp"
+#include "hqlexpr.hpp"
 
 #ifdef _USE_ZLIB
 #include "zcrypt.hpp"