src/compiler/CompileContext.cpp
author David Anderson <dvander@alliedmods.net>
Sat Dec 29 00:55:38 2012 -0800 (2012-12-29)
changeset 250 0998a43cc155
parent 237 c77540a61905
child 251 ca99a81745fe
permissions -rw-r--r--
Collect error messages per-translation unit.
dvander@195
     1
/*
dvander@195
     2
 * Copyright (C) 2012 David Anderson
dvander@195
     3
 *
dvander@195
     4
 * This file is part of JITCraft.
dvander@195
     5
 *
dvander@195
     6
 * JITCraft is free software: you can redistribute it and/or modify it under
dvander@195
     7
 * the terms of the GNU General Public License as published by the Free
dvander@195
     8
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@195
     9
 * any later version.
dvander@195
    10
 * 
dvander@195
    11
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@195
    12
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@195
    13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@195
    14
 *
dvander@195
    15
 * You should have received a copy of the GNU General Public License along with
dvander@195
    16
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@195
    17
 */
dvander@195
    18
#include <stdio.h>
dvander@195
    19
#include "../Zone.h"
dvander@195
    20
#include "../Interpreter.h"
dvander@195
    21
#include "Scanner.h"
dvander@195
    22
#include "CompileContext.h"
dvander@195
    23
#include "Parser.h"
dvander@195
    24
#include "NameBinding.h"
dvander@195
    25
#include "SemanticAnalysis.h"
dvander@195
    26
#include "../Spaces-inl.h"
dvander@195
    27
#include "../Heap-inl.h"
dvander@195
    28
dvander@195
    29
using namespace ke;
dvander@195
    30
dvander@195
    31
CompileContext::CompileContext(Zone *zone, const char *file)
dvander@195
    32
  : zone_(zone),
dvander@250
    33
    file_(file),
dvander@250
    34
    active_(NULL)
dvander@195
    35
{
dvander@195
    36
}
dvander@195
    37
dvander@195
    38
CompileContext::~CompileContext()
dvander@195
    39
{
dvander@250
    40
    for (size_t i = 0; i < units_.length(); i++)
dvander@250
    41
        delete units_[i];
dvander@195
    42
}
dvander@195
    43
dvander@195
    44
bool
dvander@195
    45
CompileContext::addTranslationUnit(TranslationUnit *unit)
dvander@195
    46
{
dvander@195
    47
    if (!units_.append(unit))
dvander@195
    48
        return false;
dvander@195
    49
dvander@195
    50
    if (!unparsed_.append(unit))
dvander@195
    51
        return false;
dvander@195
    52
dvander@195
    53
    return true;
dvander@195
    54
}
dvander@195
    55
dvander@195
    56
char *
dvander@195
    57
CompileContext::loadSource(const char *file, size_t *lengthp)
dvander@195
    58
{
dvander@195
    59
    char *bytes = NULL;
dvander@195
    60
    size_t length;
dvander@195
    61
dvander@195
    62
    FILE *fp = fopen(file, "rb");
dvander@195
    63
    if (!fp) {
dvander@195
    64
        reportError(SourcePosition(), Message_CantOpenFile);
dvander@195
    65
        return NULL;
dvander@195
    66
    }
dvander@195
    67
dvander@195
    68
    if (fseek(fp, 0, SEEK_END)) {
dvander@195
    69
        reportError(SourcePosition(), Message_ErrorSeekingFile);
dvander@195
    70
        fclose(fp);
dvander@195
    71
        return NULL;
dvander@195
    72
    }
dvander@195
    73
    long size = ftell(fp);
dvander@195
    74
    if (size < 0) {
dvander@195
    75
        reportError(SourcePosition(), Message_ErrorSeekingFile);
dvander@195
    76
        fclose(fp);
dvander@195
    77
        return NULL;
dvander@195
    78
    }
dvander@195
    79
    rewind(fp);
dvander@195
    80
    length = size_t(size);
dvander@195
    81
    bytes = new char[length + 1];
dvander@195
    82
    if (fread(bytes, 1, length, fp) != length) {
dvander@195
    83
        reportError(SourcePosition(), Message_ErrorReadingFile);
dvander@195
    84
        fclose(fp);
dvander@195
    85
        delete [] bytes;
dvander@195
    86
        return NULL;
dvander@195
    87
    }
dvander@195
    88
    fclose(fp);
dvander@195
    89
dvander@195
    90
    *lengthp = length;
dvander@195
    91
    return bytes;
dvander@195
    92
}
dvander@195
    93
dvander@195
    94
bool
dvander@195
    95
CompileContext::parse(TranslationUnit *unit)
dvander@195
    96
{
dvander@250
    97
    AutoEnterCompileContext enter(*this, unit);
dvander@250
    98
dvander@195
    99
    assert(!unit->tree_);
dvander@195
   100
dvander@195
   101
    size_t length;
dvander@196
   102
    char *source = loadSource(unit->path_, &length);
dvander@195
   103
    if (!source)
dvander@195
   104
        return false;
dvander@195
   105
dvander@195
   106
    Parser parser(ZONE(), *this, source, length);
dvander@195
   107
    if ((unit->tree_ = parser.parse()) == NULL)
dvander@195
   108
        return false;
dvander@195
   109
dvander@195
   110
    return true;
dvander@195
   111
}
dvander@195
   112
dvander@250
   113
void
dvander@195
   114
CompileContext::evaluateImports(TranslationUnit *unit)
dvander@195
   115
{
dvander@195
   116
    if (units_.length() > 1)
dvander@250
   117
        return;
dvander@195
   118
dvander@195
   119
#if 0
dvander@195
   120
    // For now we hardcode this...
dvander@195
   121
    TranslationUnit *u2 = new (ZONE()->pool()) TranslationUnit();
dvander@195
   122
    u2->path_ = "C:\\Users\\dvander\\jitcraft\\jitcraft-2\\src\\Debug\\wizard.sp";
dvander@195
   123
dvander@195
   124
    ImportStatement *stmt = unit->tree()->imports()->at(0)->toImportStatement();
dvander@195
   125
    stmt->setImportSource(u2);
dvander@195
   126
dvander@195
   127
    if (!u2->dependents_.append(unit))
dvander@195
   128
        return false;
dvander@195
   129
dvander@195
   130
    if (!addTranslationUnit(u2))
dvander@195
   131
        return false;
dvander@195
   132
#endif
dvander@195
   133
}
dvander@195
   134
dvander@195
   135
bool
dvander@195
   136
CompileContext::propagateFailure()
dvander@195
   137
{
dvander@195
   138
    Vector<TranslationUnit *> worklist;
dvander@195
   139
    for (size_t i = 0; i < units_.length(); i++) {
dvander@195
   140
        if (units_[i]->failed() && !worklist.append(units_[i]))
dvander@195
   141
            return false;
dvander@195
   142
    }
dvander@195
   143
dvander@195
   144
    while (!worklist.empty()) {
dvander@195
   145
        TranslationUnit *unit = worklist.popCopy();
dvander@195
   146
        for (size_t i = 0; i < unit->dependents().length(); i++) {
dvander@195
   147
            TranslationUnit *other = unit->dependents().at(i);
dvander@195
   148
            if (other->failed())
dvander@195
   149
                continue;
dvander@195
   150
dvander@250
   151
            other->setDependencyFailed();
dvander@195
   152
            if (!worklist.append(other))
dvander@195
   153
                return false;
dvander@195
   154
        }
dvander@195
   155
    }
dvander@195
   156
dvander@195
   157
    return true;
dvander@195
   158
}
dvander@195
   159
dvander@195
   160
bool
dvander@195
   161
CompileContext::compile()
dvander@195
   162
{
dvander@195
   163
    // Phase 1. Parse all modules we're importing. This process may load new
dvander@195
   164
    // modules off disk, and add them to the parse queue.
dvander@195
   165
    while (!unparsed_.empty()) {
dvander@195
   166
        TranslationUnit *unit = unparsed_.popCopy();
dvander@195
   167
dvander@195
   168
        if (!parse(unit))
dvander@250
   169
            continue;
dvander@195
   170
dvander@250
   171
        evaluateImports(unit);
dvander@195
   172
    }
dvander@195
   173
dvander@195
   174
    // Phase 2. Create scopes and symbol tables for every lexical region with
dvander@195
   175
    // a declaration. This phase excludes declarations created via imports.
dvander@195
   176
    for (size_t i = 0; i < units_.length(); i++) {
dvander@195
   177
        TranslationUnit *unit = units_[i];
dvander@195
   178
        if (unit->failed())
dvander@195
   179
            continue;
dvander@195
   180
dvander@250
   181
        PopulateNamesAndTypes(zone_, *this, unit);
dvander@195
   182
    }
dvander@195
   183
dvander@195
   184
    // Phase 3. Complete imports and bind all names.
dvander@195
   185
    for (size_t i = 0; i < units_.length(); i++) {
dvander@195
   186
        TranslationUnit *unit = units_[i];
dvander@195
   187
        if (unit->failed())
dvander@195
   188
            continue;
dvander@195
   189
dvander@250
   190
        BindNamesAndTypes(zone_, *this, unit);
dvander@195
   191
    }
dvander@195
   192
dvander@195
   193
    // Phase 4. Assign types to every public name in the module.
dvander@195
   194
    for (size_t i = 0; i < units_.length(); i++) {
dvander@195
   195
        TranslationUnit *unit = units_[i];
dvander@195
   196
        if (unit->failed())
dvander@195
   197
            continue;
dvander@195
   198
dvander@195
   199
    }
dvander@195
   200
dvander@195
   201
    // Intermediate phase. Decide which modules we should not perform
dvander@195
   202
    // semantic analysis on.
dvander@195
   203
    if (!propagateFailure())
dvander@195
   204
        return false;
dvander@195
   205
dvander@250
   206
    // Phase 4. Now we can finally perform SemA+bytecode compilation.
dvander@195
   207
    for (size_t i = 0; i < units_.length(); i++) {
dvander@195
   208
        TranslationUnit *unit = units_[i];
dvander@195
   209
        if (unit->failed())
dvander@195
   210
            continue;
dvander@195
   211
dvander@250
   212
        AutoEnterCompileContext enter(*this, unit);
dvander@195
   213
        SemanticAnalysis sema(zone_, *this, unit);
dvander@195
   214
        sema.analyze();
dvander@195
   215
    }
dvander@195
   216
dvander@250
   217
    // Phase 5. Run modules.
dvander@195
   218
    for (size_t i = 0; i < units_.length(); i++) {
dvander@195
   219
        TranslationUnit *unit = units_[i];
dvander@195
   220
        if (unit->failed())
dvander@250
   221
            break;
dvander@195
   222
dvander@195
   223
        InvokeArgs args;
dvander@195
   224
        if (!zone_->stack().pushModuleFrame(unit->module_, args))
dvander@195
   225
            assert(false);
dvander@195
   226
dvander@195
   227
        ke::LocalSlot slot;
dvander@195
   228
        if (!Interpret(zone_, NULL, &slot))
dvander@195
   229
            assert(false);
dvander@195
   230
    }
dvander@195
   231
dvander@250
   232
    if (Ke::IMessageReporter *reporter = zone_->errorReporter()) {
dvander@250
   233
        for (size_t i = 0; i < units_.length(); i++) {
dvander@250
   234
            TranslationUnit *unit = units_[i];
dvander@250
   235
dvander@250
   236
            // We don't explicitly report errors for dependency failures or OOM
dvander@250
   237
            // (OOM is reported separately (:TODO:) and dep failures are redundant.
dvander@250
   238
            if (!unit->errors()->length())
dvander@250
   239
                continue;
dvander@237
   240
dvander@250
   241
            reporter->beginCompilationErrors(unit->path_);
dvander@250
   242
            for (size_t j = 0; j < unit->errors()->length(); j++) {
dvander@250
   243
                const CompileError &error = unit->errors()->at(j);
dvander@250
   244
                reporter->reportCompilationError(error.message, error.line, error.col);
dvander@250
   245
            }
dvander@250
   246
            reporter->endCompilationErrors();
dvander@250
   247
        }
dvander@250
   248
    }
dvander@250
   249
dvander@250
   250
    return !units_[0]->failed();
dvander@250
   251
}
dvander@250
   252
dvander@250
   253
void
dvander@250
   254
CompileContext::enter(TranslationUnit *unit)
dvander@250
   255
{
dvander@250
   256
    assert(!active_);
dvander@250
   257
    active_ = unit;
dvander@250
   258
}
dvander@250
   259
dvander@250
   260
void
dvander@250
   261
CompileContext::leave()
dvander@250
   262
{
dvander@250
   263
    assert(active_);
dvander@250
   264
    active_ = NULL;
dvander@195
   265
}
dvander@195
   266
dvander@195
   267
void
dvander@195
   268
CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap)
dvander@195
   269
{
dvander@250
   270
    const char *report = BuildErrorMessage(Messages[msg].format, ap);
dvander@250
   271
    if (!report) {
dvander@250
   272
        active_->setOutOfMemory();
dvander@250
   273
        return;
dvander@250
   274
    }
dvander@195
   275
dvander@250
   276
    active_->appendError(report, pos.line, pos.col);
dvander@195
   277
}
dvander@195
   278
dvander@195
   279
void
dvander@195
   280
CompileContext::reportError(const SourcePosition &pos, Message msg, ...)
dvander@195
   281
{
dvander@195
   282
    va_list ap;
dvander@195
   283
    va_start(ap, msg);
dvander@195
   284
    reportErrorVa(pos, msg, ap);
dvander@195
   285
    va_end(ap);
dvander@195
   286
}
dvander@250
   287
dvander@250
   288
TranslationUnit::~TranslationUnit()
dvander@250
   289
{
dvander@250
   290
    for (size_t i = 0; i < errors_.length(); i++)
dvander@250
   291
        FreeErrorMessage(errors_[i].message);
dvander@250
   292
}