Collect error messages per-translation unit.
authorDavid Anderson <dvander@alliedmods.net>
Sat Dec 29 00:55:38 2012 -0800 (2012-12-29)
changeset 2500998a43cc155
parent 249 82b1f8bc93a9
child 251 ca99a81745fe
Collect error messages per-translation unit.
src/API.cpp
src/Zone.cpp
src/Zone.h
src/compiler/CompileContext.cpp
src/compiler/CompileContext.h
src/compiler/NameBinding.cpp
src/compiler/NameBinding.h
     1.1 --- a/src/API.cpp	Sat Dec 29 00:12:27 2012 -0800
     1.2 +++ b/src/API.cpp	Sat Dec 29 00:55:38 2012 -0800
     1.3 @@ -98,7 +98,7 @@
     1.4      RootScope roots(ZONE());
     1.5      CompileContext cc(ZONE(), path);
     1.6  
     1.7 -    TranslationUnit *unit = new (ZONE()->pool()) TranslationUnit();
     1.8 +    TranslationUnit *unit = new TranslationUnit();
     1.9      unit->path_ = path;
    1.10  
    1.11      if (!cc.addTranslationUnit(unit))
     2.1 --- a/src/Zone.cpp	Sat Dec 29 00:12:27 2012 -0800
     2.2 +++ b/src/Zone.cpp	Sat Dec 29 00:55:38 2012 -0800
     2.3 @@ -226,8 +226,8 @@
     2.4  # define VA_COPY(to, from)  va_copy(to, from)
     2.5  #endif
     2.6  
     2.7 -static char *
     2.8 -BuildErrorMessage(const char *format, va_list ap)
     2.9 +char *
    2.10 +ke::BuildErrorMessage(const char *format, va_list ap)
    2.11  {
    2.12      va_list use;
    2.13      VA_COPY(use, ap);
    2.14 @@ -264,6 +264,12 @@
    2.15  }
    2.16  
    2.17  void
    2.18 +ke::FreeErrorMessage(const char *message)
    2.19 +{
    2.20 +    free((void *)message);
    2.21 +}
    2.22 +
    2.23 +void
    2.24  Zone::reportErrorVA(Message message, va_list ap)
    2.25  {
    2.26      char *report = BuildErrorMessage(Messages[message].format, ap);
    2.27 @@ -281,40 +287,7 @@
    2.28  
    2.29      hasPendingException_ = true;
    2.30  
    2.31 -    free(report);
    2.32 -}
    2.33 -
    2.34 -void
    2.35 -Zone::beginCompilationErrors(const char *file)
    2.36 -{
    2.37 -    if (reporter_)
    2.38 -        reporter_->beginCompilationErrors(file);
    2.39 -}
    2.40 -
    2.41 -void
    2.42 -Zone::reportCompilationError(Message message, unsigned line, unsigned col, va_list ap)
    2.43 -{
    2.44 -    char *report = BuildErrorMessage(Messages[message].format, ap);
    2.45 -    if (!report) {
    2.46 -        reportOutOfMemory();
    2.47 -        return;
    2.48 -    }
    2.49 -
    2.50 -    if (reporter_) {
    2.51 -        // Reporters can re-enter. When we start having actual exception
    2.52 -        // objects that can be caught and inspected, this code will have to
    2.53 -        // save and restore the exception state.
    2.54 -        reporter_->reportCompilationError(report, line, col);
    2.55 -    }
    2.56 -
    2.57 -    free(report);
    2.58 -}
    2.59 -
    2.60 -void
    2.61 -Zone::endCompilationErrors()
    2.62 -{
    2.63 -    if (reporter_)
    2.64 -        reporter_->endCompilationErrors();
    2.65 +    FreeErrorMessage(report);
    2.66  }
    2.67  
    2.68  void
     3.1 --- a/src/Zone.h	Sat Dec 29 00:12:27 2012 -0800
     3.2 +++ b/src/Zone.h	Sat Dec 29 00:55:38 2012 -0800
     3.3 @@ -140,9 +140,9 @@
     3.4      bool hasPendingException();
     3.5      void clearPendingException();
     3.6      void installErrorReporter(Ke::IMessageReporter *reporter);
     3.7 -    void beginCompilationErrors(const char *file);
     3.8 -    void reportCompilationError(Message message, unsigned line, unsigned col, va_list ap);
     3.9 -    void endCompilationErrors();
    3.10 +    Ke::IMessageReporter *errorReporter() {
    3.11 +        return reporter_;
    3.12 +    }
    3.13  
    3.14      void accept(VirtualObjectVisitor *visitor);
    3.15      void sweepWeakRoots();
    3.16 @@ -156,6 +156,10 @@
    3.17  // In the interest of simplicity, we are single-threaded for now.
    3.18  extern Zone *SingleThreadedZone;
    3.19  
    3.20 +// Exposed for the compiler.
    3.21 +char *BuildErrorMessage(const char *format, va_list ap);
    3.22 +void FreeErrorMessage(const char *message);
    3.23 +
    3.24  static inline Zone *ZONE()
    3.25  {
    3.26      return SingleThreadedZone;
     4.1 --- a/src/compiler/CompileContext.cpp	Sat Dec 29 00:12:27 2012 -0800
     4.2 +++ b/src/compiler/CompileContext.cpp	Sat Dec 29 00:55:38 2012 -0800
     4.3 @@ -30,15 +30,15 @@
     4.4  
     4.5  CompileContext::CompileContext(Zone *zone, const char *file)
     4.6    : zone_(zone),
     4.7 -    failures_(0),
     4.8 -    file_(file)
     4.9 +    file_(file),
    4.10 +    active_(NULL)
    4.11  {
    4.12  }
    4.13  
    4.14  CompileContext::~CompileContext()
    4.15  {
    4.16 -    if (failures_)
    4.17 -        zone_->endCompilationErrors();
    4.18 +    for (size_t i = 0; i < units_.length(); i++)
    4.19 +        delete units_[i];
    4.20  }
    4.21  
    4.22  bool
    4.23 @@ -94,6 +94,8 @@
    4.24  bool
    4.25  CompileContext::parse(TranslationUnit *unit)
    4.26  {
    4.27 +    AutoEnterCompileContext enter(*this, unit);
    4.28 +
    4.29      assert(!unit->tree_);
    4.30  
    4.31      size_t length;
    4.32 @@ -108,11 +110,11 @@
    4.33      return true;
    4.34  }
    4.35  
    4.36 -bool
    4.37 +void
    4.38  CompileContext::evaluateImports(TranslationUnit *unit)
    4.39  {
    4.40      if (units_.length() > 1)
    4.41 -        return true;
    4.42 +        return;
    4.43  
    4.44  #if 0
    4.45      // For now we hardcode this...
    4.46 @@ -128,8 +130,6 @@
    4.47      if (!addTranslationUnit(u2))
    4.48          return false;
    4.49  #endif
    4.50 -
    4.51 -    return true;
    4.52  }
    4.53  
    4.54  bool
    4.55 @@ -148,7 +148,7 @@
    4.56              if (other->failed())
    4.57                  continue;
    4.58  
    4.59 -            other->failed_ = true;
    4.60 +            other->setDependencyFailed();
    4.61              if (!worklist.append(other))
    4.62                  return false;
    4.63          }
    4.64 @@ -166,10 +166,9 @@
    4.65          TranslationUnit *unit = unparsed_.popCopy();
    4.66  
    4.67          if (!parse(unit))
    4.68 -            unit->failed_ = true;
    4.69 +            continue;
    4.70  
    4.71 -        if (!evaluateImports(unit))
    4.72 -            unit->failed_ = true;
    4.73 +        evaluateImports(unit);
    4.74      }
    4.75  
    4.76      // Phase 2. Create scopes and symbol tables for every lexical region with
    4.77 @@ -179,8 +178,7 @@
    4.78          if (unit->failed())
    4.79              continue;
    4.80  
    4.81 -        if (!PopulateNamesAndTypes(zone_, *this, unit))
    4.82 -            unit->failed_ = true;
    4.83 +        PopulateNamesAndTypes(zone_, *this, unit);
    4.84      }
    4.85  
    4.86      // Phase 3. Complete imports and bind all names.
    4.87 @@ -189,8 +187,7 @@
    4.88          if (unit->failed())
    4.89              continue;
    4.90  
    4.91 -        if (!BindNamesAndTypes(zone_, *this, unit))
    4.92 -            unit->failed_ = true;
    4.93 +        BindNamesAndTypes(zone_, *this, unit);
    4.94      }
    4.95  
    4.96      // Phase 4. Assign types to every public name in the module.
    4.97 @@ -206,62 +203,77 @@
    4.98      if (!propagateFailure())
    4.99          return false;
   4.100  
   4.101 -    // Phase 4. Perform full semantic analysis on each module.
   4.102 +    // Phase 4. Now we can finally perform SemA+bytecode compilation.
   4.103      for (size_t i = 0; i < units_.length(); i++) {
   4.104          TranslationUnit *unit = units_[i];
   4.105          if (unit->failed())
   4.106              continue;
   4.107  
   4.108 -  
   4.109 -    }
   4.110 -
   4.111 -    // Intermediate phase. Propagate failure from semantic analysis.
   4.112 -    if (!propagateFailure())
   4.113 -        return false;
   4.114 -
   4.115 -    // Phase 5. Now we can finally perform bytecode compilation.
   4.116 -    for (size_t i = 0; i < units_.length(); i++) {
   4.117 -        TranslationUnit *unit = units_[i];
   4.118 -        if (unit->failed())
   4.119 -            continue;
   4.120 -
   4.121 +        AutoEnterCompileContext enter(*this, unit);
   4.122          SemanticAnalysis sema(zone_, *this, unit);
   4.123          sema.analyze();
   4.124      }
   4.125  
   4.126 -    // Phase 6. Run modules.
   4.127 +    // Phase 5. Run modules.
   4.128      for (size_t i = 0; i < units_.length(); i++) {
   4.129          TranslationUnit *unit = units_[i];
   4.130          if (unit->failed())
   4.131 -            continue;
   4.132 +            break;
   4.133  
   4.134          InvokeArgs args;
   4.135          if (!zone_->stack().pushModuleFrame(unit->module_, args))
   4.136              assert(false);
   4.137  
   4.138 -        if (failures_)
   4.139 -            return false;
   4.140 -
   4.141          ke::LocalSlot slot;
   4.142          if (!Interpret(zone_, NULL, &slot))
   4.143              assert(false);
   4.144      }
   4.145  
   4.146 -    if (failures_)
   4.147 -        return false;
   4.148 +    if (Ke::IMessageReporter *reporter = zone_->errorReporter()) {
   4.149 +        for (size_t i = 0; i < units_.length(); i++) {
   4.150 +            TranslationUnit *unit = units_[i];
   4.151 +
   4.152 +            // We don't explicitly report errors for dependency failures or OOM
   4.153 +            // (OOM is reported separately (:TODO:) and dep failures are redundant.
   4.154 +            if (!unit->errors()->length())
   4.155 +                continue;
   4.156  
   4.157 -    return true;
   4.158 +            reporter->beginCompilationErrors(unit->path_);
   4.159 +            for (size_t j = 0; j < unit->errors()->length(); j++) {
   4.160 +                const CompileError &error = unit->errors()->at(j);
   4.161 +                reporter->reportCompilationError(error.message, error.line, error.col);
   4.162 +            }
   4.163 +            reporter->endCompilationErrors();
   4.164 +        }
   4.165 +    }
   4.166 +
   4.167 +    return !units_[0]->failed();
   4.168 +}
   4.169 +
   4.170 +void
   4.171 +CompileContext::enter(TranslationUnit *unit)
   4.172 +{
   4.173 +    assert(!active_);
   4.174 +    active_ = unit;
   4.175 +}
   4.176 +
   4.177 +void
   4.178 +CompileContext::leave()
   4.179 +{
   4.180 +    assert(active_);
   4.181 +    active_ = NULL;
   4.182  }
   4.183  
   4.184  void
   4.185  CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap)
   4.186  {
   4.187 -    if (!failures_)
   4.188 -        zone_->beginCompilationErrors(file_);
   4.189 +    const char *report = BuildErrorMessage(Messages[msg].format, ap);
   4.190 +    if (!report) {
   4.191 +        active_->setOutOfMemory();
   4.192 +        return;
   4.193 +    }
   4.194  
   4.195 -    zone_->reportCompilationError(msg, pos.line, pos.col, ap);
   4.196 -
   4.197 -    failures_++;
   4.198 +    active_->appendError(report, pos.line, pos.col);
   4.199  }
   4.200  
   4.201  void
   4.202 @@ -272,3 +284,9 @@
   4.203      reportErrorVa(pos, msg, ap);
   4.204      va_end(ap);
   4.205  }
   4.206 +
   4.207 +TranslationUnit::~TranslationUnit()
   4.208 +{
   4.209 +    for (size_t i = 0; i < errors_.length(); i++)
   4.210 +        FreeErrorMessage(errors_[i].message);
   4.211 +}
     5.1 --- a/src/compiler/CompileContext.h	Sat Dec 29 00:12:27 2012 -0800
     5.2 +++ b/src/compiler/CompileContext.h	Sat Dec 29 00:55:38 2012 -0800
     5.3 @@ -36,19 +36,38 @@
     5.4  struct TranslationUnit;
     5.5  class ImportStatement;
     5.6  
     5.7 -struct TranslationUnit : public PoolObject
     5.8 +struct CompileError
     5.9 +{
    5.10 +    CompileError()
    5.11 +      : message(NULL)
    5.12 +    {
    5.13 +    }
    5.14 +    CompileError(unsigned line, unsigned col, const char *message)
    5.15 +      : line(line),
    5.16 +        col(col),
    5.17 +        message(message)
    5.18 +    {
    5.19 +    }
    5.20 +
    5.21 +    unsigned line;
    5.22 +    unsigned col;
    5.23 +    const char *message;
    5.24 +};
    5.25 +
    5.26 +struct TranslationUnit
    5.27  {
    5.28      TranslationUnit()
    5.29        : tree_(NULL),
    5.30 -        failed_(false),
    5.31          importScope_(NULL),
    5.32 -        globalScope_(NULL)
    5.33 +        globalScope_(NULL),
    5.34 +        oom_(false),
    5.35 +        dependencyFailed_(false)
    5.36      {
    5.37      }
    5.38 +    ~TranslationUnit();
    5.39  
    5.40      ParseTree *tree_;
    5.41      const char *path_;
    5.42 -    bool failed_;
    5.43      PoolList<TranslationUnit *> dependents_;
    5.44      ImportScope *importScope_;
    5.45      GlobalScope *globalScope_;
    5.46 @@ -61,7 +80,9 @@
    5.47          return dependents_;
    5.48      }
    5.49      bool failed() const {
    5.50 -        return failed_;
    5.51 +        return errors_.length() ||
    5.52 +               oom_ ||
    5.53 +               dependencyFailed_;
    5.54      }
    5.55      void setImportScope(ImportScope *scope) {
    5.56          assert(!importScope_);
    5.57 @@ -77,20 +98,38 @@
    5.58      GlobalScope *globalScope() const {
    5.59          return globalScope_;
    5.60      }
    5.61 +
    5.62 +    void setDependencyFailed() {
    5.63 +        dependencyFailed_ = true;
    5.64 +    }
    5.65 +    void setOutOfMemory() {
    5.66 +        oom_ = true;
    5.67 +    }
    5.68 +    void appendError(const char *report, unsigned line, unsigned col) {
    5.69 +        oom_ |= errors_.append(CompileError(line, col, report));
    5.70 +    }
    5.71 +    const Vector<CompileError> *errors() {
    5.72 +        return &errors_;
    5.73 +    }
    5.74 +
    5.75 +  private:
    5.76 +    bool oom_;
    5.77 +    bool dependencyFailed_;
    5.78 +    Vector<CompileError> errors_;
    5.79  };
    5.80  
    5.81  class CompileContext
    5.82  {
    5.83      Zone *zone_;
    5.84 -    unsigned failures_;
    5.85      const char *file_;
    5.86      Vector<TranslationUnit *> units_;
    5.87      Vector<TranslationUnit *> unparsed_;
    5.88 +    TranslationUnit *active_;
    5.89  
    5.90    private:
    5.91      char *loadSource(const char *file, size_t *length);
    5.92      bool parse(TranslationUnit *unit);
    5.93 -    bool evaluateImports(TranslationUnit *unit);
    5.94 +    void evaluateImports(TranslationUnit *unit);
    5.95      bool propagateFailure();
    5.96  
    5.97    public:
    5.98 @@ -99,15 +138,28 @@
    5.99  
   5.100      bool addTranslationUnit(TranslationUnit *unit);
   5.101      bool compile();
   5.102 +    void enter(TranslationUnit *unit);
   5.103 +    void leave();
   5.104  
   5.105      void reportErrorVa(const SourcePosition &pos, Message msg, va_list ap);
   5.106      void reportError(const SourcePosition &pos, Message msg, ...);
   5.107 +};
   5.108  
   5.109 -    unsigned failures() const {
   5.110 -        return failures_;
   5.111 +class AutoEnterCompileContext
   5.112 +{
   5.113 +    CompileContext &cc_;
   5.114 +
   5.115 +  public:
   5.116 +    AutoEnterCompileContext(CompileContext &cc, TranslationUnit *unit)
   5.117 +      : cc_(cc)
   5.118 +    {
   5.119 +      cc_.enter(unit);
   5.120 +    }
   5.121 +    ~AutoEnterCompileContext() {
   5.122 +      cc_.leave();
   5.123      }
   5.124  };
   5.125  
   5.126 -}
   5.127 +} // namespace ke
   5.128  
   5.129  #endif // _include_jitcraft_compile_context_h_
     6.1 --- a/src/compiler/NameBinding.cpp	Sat Dec 29 00:12:27 2012 -0800
     6.2 +++ b/src/compiler/NameBinding.cpp	Sat Dec 29 00:55:38 2012 -0800
     6.3 @@ -111,18 +111,18 @@
     6.4      {
     6.5      }
     6.6  
     6.7 -    bool analyze() {
     6.8 +    void analyze() {
     6.9          ImportScope *importScope = ImportScope::New(pool_);
    6.10          if (!importScope)
    6.11 -            return false;
    6.12 +            return;
    6.13  
    6.14          // At the import level, we declare system types.
    6.15          if (!declareSystemTypes(importScope))
    6.16 -            return false;
    6.17 +            return;
    6.18  
    6.19          GlobalScope *globalScope = GlobalScope::New(pool_, importScope);
    6.20          if (!globalScope)
    6.21 -            return false;
    6.22 +            return;
    6.23  
    6.24          unit_->setImportScope(importScope);
    6.25          unit_->setGlobalScope(globalScope);
    6.26 @@ -134,7 +134,7 @@
    6.27              stmt->accept(this);
    6.28          }
    6.29  
    6.30 -        return true;
    6.31 +        return;
    6.32      }
    6.33  
    6.34      bool declareSystemType(ImportScope *scope, const char *name, Handle<Type> type) {
    6.35 @@ -480,11 +480,12 @@
    6.36      FunctionScope *fun_;
    6.37  };
    6.38  
    6.39 -bool
    6.40 +void
    6.41  ke::PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
    6.42  {
    6.43 +    AutoEnterCompileContext enter(cc, unit);
    6.44      NamePopulator populator(zone, cc, unit);
    6.45 -    return populator.analyze();
    6.46 +    populator.analyze();
    6.47  }
    6.48  
    6.49  static const int INFER_ARRAY_SIZE = 0;
    6.50 @@ -534,7 +535,7 @@
    6.51      {
    6.52      }
    6.53  
    6.54 -    bool bind() {
    6.55 +    void bind() {
    6.56          // Start with the import scope, and collect all imported names.
    6.57          AutoLinkScope importScope(&link_, unit_->importScope());
    6.58  
    6.59 @@ -547,8 +548,6 @@
    6.60              Statement *stmt = unit_->tree()->statements()->at(i);
    6.61              stmt->accept(this);
    6.62          }
    6.63 -
    6.64 -        return true;
    6.65      }
    6.66  
    6.67      void visitVariableDeclaration(VariableDeclaration *node) {
    6.68 @@ -973,9 +972,10 @@
    6.69      AutoLinkScope *link_;
    6.70  };
    6.71  
    6.72 -bool
    6.73 +void
    6.74  ke::BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
    6.75  {
    6.76 +    AutoEnterCompileContext enter(cc, unit);
    6.77      NameBinder binder(zone, cc, unit);
    6.78 -    return binder.bind();
    6.79 +    binder.bind();
    6.80  }
     7.1 --- a/src/compiler/NameBinding.h	Sat Dec 29 00:12:27 2012 -0800
     7.2 +++ b/src/compiler/NameBinding.h	Sat Dec 29 00:55:38 2012 -0800
     7.3 @@ -30,10 +30,10 @@
     7.4  struct TranslationUnit;
     7.5  
     7.6  // Creates symbols and types for names that are global or can be derived from a global.
     7.7 -bool PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
     7.8 +void PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
     7.9  
    7.10  // Bind all outstanding names and finalize all unfinished types.
    7.11 -bool BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
    7.12 +void BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
    7.13  
    7.14  }
    7.15