Collect error messages per-translation unit.
Collect error messages per-translation unit.
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