src/compiler/CompileContext.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jan 06 13:52:21 2013 -0800 (2013-01-06)
changeset 256 3c184218462d
parent 252 1dee2330aa78
child 258 241d082d6d89
permissions -rw-r--r--
Initial implementation of module imports.
[email protected]
     1
/*
[email protected]
     2
 * Copyright (C) 2012 David Anderson
[email protected]
     3
 *
[email protected]
     4
 * This file is part of SourcePawn.
[email protected]
     5
 *
[email protected]
     6
 * SourcePawn is free software: you can redistribute it and/or modify it under
[email protected]
     7
 * the terms of the GNU General Public License as published by the Free
[email protected]
     8
 * Software Foundation, either version 3 of the License, or (at your option)
[email protected]
     9
 * any later version.
[email protected]
    10
 * 
[email protected]
    11
 * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
[email protected]
    12
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
[email protected]
    13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
[email protected]
    14
 *
[email protected]
    15
 * You should have received a copy of the GNU General Public License along with
[email protected]
    16
 * SourcePawn. If not, see http://www.gnu.org/licenses/.
[email protected]
    17
 */
[email protected]
    18
#include <stdio.h>
[email protected]
    19
#include <string.h>
[email protected]
    20
#include "../Zone.h"
[email protected]
    21
#include "../Interpreter.h"
[email protected]
    22
#include "../Packages.h"
[email protected]
    23
#include "../FileSystem.h"
[email protected]
    24
#include "../FixedArray.h"
[email protected]
    25
#include "../Vector.h"
[email protected]
    26
#include "Scanner.h"
[email protected]
    27
#include "CompileContext.h"
[email protected]
    28
#include "Parser.h"
[email protected]
    29
#include "NameBinding.h"
[email protected]
    30
#include "SemanticAnalysis.h"
[email protected]
    31
#include "../Spaces-inl.h"
[email protected]
    32
#include "../Heap-inl.h"
[email protected]
    33
[email protected]
    34
using namespace ke;
[email protected]
    35
[email protected]
    36
CompileContext::CompileContext(Zone *zone, const char *file)
[email protected]
    37
  : zone_(zone),
[email protected]
    38
    file_(file),
[email protected]
    39
    active_(NULL)
[email protected]
    40
{
[email protected]
    41
}
[email protected]
    42
[email protected]
    43
CompileContext::~CompileContext()
[email protected]
    44
{
[email protected]
    45
    for (size_t i = 0; i < units_.length(); i++)
[email protected]
    46
        units_[i]->destroy();
[email protected]
    47
}
[email protected]
    48
[email protected]
    49
bool
[email protected]
    50
CompileContext::initialize(Handle<Package> package, const char *name)
[email protected]
    51
{
[email protected]
    52
    size_t len = strlen(name);
[email protected]
    53
    AutoFree<char> path((char *)zone_->malloc(len + 1));
[email protected]
    54
    if (!*path)
[email protected]
    55
        return false;
[email protected]
    56
[email protected]
    57
    strcpy(*path, name);
[email protected]
    58
    if (len > 3 && strcmp(&name[len - 3], ".sp") == 0)
[email protected]
    59
        (*path)[len - 3] = '\0';
[email protected]
    60
[email protected]
    61
    Local<String> strname(zone_, zone_->makeSymbol(*path));
[email protected]
    62
    if (!strname)
[email protected]
    63
        return false;
[email protected]
    64
[email protected]
    65
    PathComponent p(new (zone_->pool()) ScopedRoot<String>(strname), NULL);
[email protected]
    66
[email protected]
    67
    Local<Importable> importable(zone_);
[email protected]
    68
    if (!zone_->packages()->findOrAdd(package, &p, importable.address()))
[email protected]
    69
        return false;
[email protected]
    70
[email protected]
    71
    // If we couldn't find anything on the filesystem to match, we error out
[email protected]
    72
    // early.
[email protected]
    73
    if (!importable) {
[email protected]
    74
        zone_->reportError(Message_CannotImportPath, *path);
[email protected]
    75
        return false;
[email protected]
    76
    }
[email protected]
    77
[email protected]
    78
    if (importable->isModule()) {
[email protected]
    79
        Local<Module> module(zone_, Module::cast(importable));
[email protected]
    80
        if (!add(module))
[email protected]
    81
            return true;
[email protected]
    82
    } else {
[email protected]
    83
        // nyi
[email protected]
    84
        assert(false);
[email protected]
    85
    }
[email protected]
    86
[email protected]
    87
    return true;
[email protected]
    88
}
[email protected]
    89
[email protected]
    90
char *
[email protected]
    91
CompileContext::loadSource(Handle<Module> module, size_t *lengthp)
[email protected]
    92
{
[email protected]
    93
    char *bytes = NULL;
[email protected]
    94
    size_t length;
[email protected]
    95
[email protected]
    96
    FILE *fp = fopen(module->path()->chars(), "rb");
[email protected]
    97
    if (!fp) {
[email protected]
    98
        reportError(SourcePosition(), Message_CantOpenFile);
[email protected]
    99
        return NULL;
[email protected]
   100
    }
[email protected]
   101
[email protected]
   102
    if (fseek(fp, 0, SEEK_END)) {
[email protected]
   103
        reportError(SourcePosition(), Message_ErrorSeekingFile);
[email protected]
   104
        fclose(fp);
[email protected]
   105
        return NULL;
[email protected]
   106
    }
[email protected]
   107
    long size = ftell(fp);
[email protected]
   108
    if (size < 0) {
[email protected]
   109
        reportError(SourcePosition(), Message_ErrorSeekingFile);
[email protected]
   110
        fclose(fp);
[email protected]
   111
        return NULL;
[email protected]
   112
    }
[email protected]
   113
    rewind(fp);
[email protected]
   114
    length = size_t(size);
[email protected]
   115
    bytes = new char[length + 1];
[email protected]
   116
    if (fread(bytes, 1, length, fp) != length) {
[email protected]
   117
        reportError(SourcePosition(), Message_ErrorReadingFile);
[email protected]
   118
        fclose(fp);
[email protected]
   119
        delete [] bytes;
[email protected]
   120
        return NULL;
[email protected]
   121
    }
[email protected]
   122
    fclose(fp);
[email protected]
   123
[email protected]
   124
    *lengthp = length;
[email protected]
   125
    return bytes;
[email protected]
   126
}
[email protected]
   127
[email protected]
   128
bool
[email protected]
   129
CompileContext::parse(TranslationUnit *unit)
[email protected]
   130
{
[email protected]
   131
    assert(!unit->tree_);
[email protected]
   132
[email protected]
   133
    size_t length;
[email protected]
   134
    char *source = loadSource(unit->module(), &length);
[email protected]
   135
    if (!source)
[email protected]
   136
        return false;
[email protected]
   137
[email protected]
   138
    Parser parser(ZONE(), *this, source, length);
[email protected]
   139
    if ((unit->tree_ = parser.parse()) == NULL)
[email protected]
   140
        return false;
[email protected]
   141
[email protected]
   142
    return true;
[email protected]
   143
}
[email protected]
   144
[email protected]
   145
bool
[email protected]
   146
CompileContext::evaluateImports(TranslationUnit *unit)
[email protected]
   147
{
[email protected]
   148
    PoolList<ImportStatement *> *imports = unit->tree()->imports();
[email protected]
   149
[email protected]
   150
    if (!imports->length())
[email protected]
   151
        return true;
[email protected]
   152
[email protected]
   153
    // We're allowed to use Handle<> here instead of ScopedRoot<> because
[email protected]
   154
    // we get the handle from ImportStatement which has a ScopedRoot<>.
[email protected]
   155
    Vector<Handle<Importable> > vec;
[email protected]
   156
[email protected]
   157
    for (size_t i = 0; i < imports->length(); i++) {
[email protected]
   158
        ImportStatement *import = imports->at(i);
[email protected]
   159
[email protected]
   160
        // Crawl the path until we find a valid file to load.
[email protected]
   161
        Local<Importable> obj(zone_);
[email protected]
   162
        Local<Package> package(zone_, unit->module()->parent());
[email protected]
   163
        if (!zone_->packages()->findOrAdd(package, import->path(), obj.address()))
[email protected]
   164
            return false;
[email protected]
   165
        if (!obj) {
[email protected]
   166
            PathComponent *path = import->path();
[email protected]
   167
            while (path->next)
[email protected]
   168
                path = path->next;
[email protected]
   169
            reportError(import->pos(), Message_CannotImportPath, path->name->chars());
[email protected]
   170
            return false;
[email protected]
   171
        }
[email protected]
   172
[email protected]
   173
        // If the object is a package, we will attempt to execute it
[email protected]
   174
        // immediately after resolving imports.
[email protected]
   175
        if (obj->isPackage()) {
[email protected]
   176
            assert(false);
[email protected]
   177
        } else {
[email protected]
   178
            Local<Module> module(zone_, Module::cast(obj));
[email protected]
   179
            if (!add(module))
[email protected]
   180
                return false;
[email protected]
   181
        }
[email protected]
   182
[email protected]
   183
        import->setSource(obj);
[email protected]
   184
        
[email protected]
   185
        // See if there are any duplicates. This is O(n^2), but we expect
[email protected]
   186
        // |n| to be small.
[email protected]
   187
        unsigned index = 0;
[email protected]
   188
        for (; index < vec.length(); index++) {
[email protected]
   189
            if (vec[index] == obj)
[email protected]
   190
                break;
[email protected]
   191
        }
[email protected]
   192
        if (index == vec.length() && !vec.append(import->source()))
[email protected]
   193
            return false;
[email protected]
   194
[email protected]
   195
        import->setImportIndex(index);
[email protected]
   196
    }
[email protected]
   197
[email protected]
   198
    if (!IsUint32MultiplySafe(vec.length(), 2)) {
[email protected]
   199
        zone_->reportAllocationOverflow();
[email protected]
   200
        return false;
[email protected]
   201
    }
[email protected]
   202
[email protected]
   203
    // Create an array of the import and paths.
[email protected]
   204
    Local<FixedArray> importables(zone_, FixedArray::New(zone_, vec.length() * 2, Heap::Tenure_Default));
[email protected]
   205
    if (!importables)
[email protected]
   206
        return false;
[email protected]
   207
[email protected]
   208
    for (unsigned i = 0; i < vec.length(); i++) {
[email protected]
   209
        importables->set(zone_, i * 2, vec[i]);
[email protected]
   210
[email protected]
   211
        unsigned count = 0;
[email protected]
   212
        PathComponent *path = imports->at(i)->path();
[email protected]
   213
        for (PathComponent *iter = path; iter; iter = iter->next)
[email protected]
   214
            count++;
[email protected]
   215
[email protected]
   216
        Local<FixedArray> list(zone_, FixedArray::New(zone_, count, Heap::Tenure_Default));
[email protected]
   217
        if (!list)
[email protected]
   218
            return false;
[email protected]
   219
[email protected]
   220
        count = 0;
[email protected]
   221
        for (PathComponent *iter = path; iter; iter = iter->next, count++)
[email protected]
   222
            list->set(zone_, count, iter->name);
[email protected]
   223
[email protected]
   224
        importables->set(zone_, i * 2 + 1, list);
[email protected]
   225
    }
[email protected]
   226
[email protected]
   227
    unit->module()->setImports(importables);
[email protected]
   228
    return true;
[email protected]
   229
}
[email protected]
   230
[email protected]
   231
bool
[email protected]
   232
CompileContext::add(Handle<Module> module)
[email protected]
   233
{
[email protected]
   234
    if (module->compiled())
[email protected]
   235
        return true;
[email protected]
   236
[email protected]
   237
    TranslationUnit *tu = new (zone_->pool()) TranslationUnit(module);
[email protected]
   238
[email protected]
   239
    if (!unparsed_.append(tu) || !units_.append(tu))
[email protected]
   240
        return false;
[email protected]
   241
[email protected]
   242
    return true;
[email protected]
   243
}
[email protected]
   244
[email protected]
   245
bool
[email protected]
   246
CompileContext::propagateFailure()
[email protected]
   247
{
[email protected]
   248
    Vector<TranslationUnit *> worklist;
[email protected]
   249
    for (size_t i = 0; i < units_.length(); i++) {
[email protected]
   250
        if (units_[i]->failed() && !worklist.append(units_[i]))
[email protected]
   251
            return false;
[email protected]
   252
    }
[email protected]
   253
[email protected]
   254
    while (!worklist.empty()) {
[email protected]
   255
        TranslationUnit *unit = worklist.popCopy();
[email protected]
   256
        for (size_t i = 0; i < unit->dependents().length(); i++) {
[email protected]
   257
            TranslationUnit *other = unit->dependents().at(i);
[email protected]
   258
            if (other->failed())
[email protected]
   259
                continue;
[email protected]
   260
[email protected]
   261
            other->setDependencyFailed();
[email protected]
   262
            if (!worklist.append(other))
[email protected]
   263
                return false;
[email protected]
   264
        }
[email protected]
   265
    }
[email protected]
   266
[email protected]
   267
    return true;
[email protected]
   268
}
[email protected]
   269
[email protected]
   270
bool
[email protected]
   271
CompileContext::compile()
[email protected]
   272
{
[email protected]
   273
    // Phase 1. Parse all modules we're importing. This process may load new
[email protected]
   274
    // modules off disk, and add them to the parse queue.
[email protected]
   275
    while (!unparsed_.empty()) {
[email protected]
   276
        TranslationUnit *unit = unparsed_.popCopy();
[email protected]
   277
[email protected]
   278
        AutoEnterCompileContext enter(*this, unit);
[email protected]
   279
        if (!parse(unit))
[email protected]
   280
            continue;
[email protected]
   281
[email protected]
   282
        evaluateImports(unit);
[email protected]
   283
    }
[email protected]
   284
[email protected]
   285
    // Phase 2. Create scopes and symbol tables for every lexical region with
[email protected]
   286
    // a declaration. This phase excludes declarations created via imports.
[email protected]
   287
    for (size_t i = 0; i < units_.length(); i++) {
[email protected]
   288
        TranslationUnit *unit = units_[i];
[email protected]
   289
        if (unit->failed())
[email protected]
   290
            continue;
[email protected]
   291
[email protected]
   292
        PopulateNamesAndTypes(zone_, *this, unit);
[email protected]
   293
    }
[email protected]
   294
[email protected]
   295
    // Phase 3. Complete imports and bind all names.
[email protected]
   296
    for (size_t i = 0; i < units_.length(); i++) {
[email protected]
   297
        TranslationUnit *unit = units_[i];
[email protected]
   298
        if (unit->failed())
[email protected]
   299
            continue;
[email protected]
   300
[email protected]
   301
        BindNamesAndTypes(zone_, *this, unit);
[email protected]
   302
    }
[email protected]
   303
[email protected]
   304
    // Phase 4. Assign types to every public name in the module.
[email protected]
   305
    for (size_t i = 0; i < units_.length(); i++) {
[email protected]
   306
        TranslationUnit *unit = units_[i];
[email protected]
   307
        if (unit->failed())
[email protected]
   308
            continue;
[email protected]
   309
[email protected]
   310
    }
[email protected]
   311
[email protected]
   312
    // Intermediate phase. Decide which modules we should not perform
[email protected]
   313
    // semantic analysis on.
[email protected]
   314
    if (!propagateFailure())
[email protected]
   315
        return false;
[email protected]
   316
[email protected]
   317
    // Phase 4. Now we can finally perform SemA+bytecode compilation.
[email protected]
   318
    for (size_t i = 0; i < units_.length(); i++) {
[email protected]
   319
        TranslationUnit *unit = units_[i];
[email protected]
   320
        if (unit->failed())
[email protected]
   321
            continue;
[email protected]
   322
[email protected]
   323
        AutoEnterCompileContext enter(*this, unit);
[email protected]
   324
        SemanticAnalysis sema(zone_, *this, unit);
[email protected]
   325
        sema.analyze();
[email protected]
   326
    }
[email protected]
   327
[email protected]
   328
    // Phase 5. Run modules.
[email protected]
   329
    for (size_t i = 0; i < units_.length(); i++) {
[email protected]
   330
        TranslationUnit *unit = units_[i];
[email protected]
   331
        if (unit->failed())
[email protected]
   332
            break;
[email protected]
   333
[email protected]
   334
        InvokeArgs args;
[email protected]
   335
        if (!zone_->stack().pushModuleFrame(unit->module_, args))
[email protected]
   336
            assert(false);
[email protected]
   337
[email protected]
   338
        ke::LocalSlot slot;
[email protected]
   339
        if (!Interpret(zone_, NULL, &slot))
[email protected]
   340
            assert(false);
[email protected]
   341
    }
[email protected]
   342
[email protected]
   343
    if (Ke::IMessageReporter *reporter = zone_->errorReporter()) {
[email protected]
   344
        for (size_t i = 0; i < units_.length(); i++) {
[email protected]
   345
            TranslationUnit *unit = units_[i];
[email protected]
   346
[email protected]
   347
            // We don't explicitly report errors for dependency failures or OOM
[email protected]
   348
            // (OOM is reported separately (:TODO:) and dep failures are redundant.
[email protected]0
   349
            if (!unit->errors()->length())
[email protected]
   350
                continue;
[email protected]
   351
[email protected]
   352
            reporter->beginCompilationErrors(unit->module()->path()->chars());
[email protected]
   353
            for (size_t j = 0; j < unit->errors()->length(); j++) {
[email protected]
   354
                const CompileError &error = unit->errors()->at(j);
[email protected]
   355
                reporter->reportCompilationError(error.message, error.line, error.col);
[email protected]
   356
            }
[email protected]
   357
            reporter->endCompilationErrors();
[email protected]
   358
        }
[email protected]
   359
    }
[email protected]
   360
[email protected]
   361
    return !units_[0]->failed();
[email protected]
   362
}
[email protected]
   363
[email protected]
   364
void
[email protected]
   365
CompileContext::enter(TranslationUnit *unit)
[email protected]
   366
{
[email protected]
   367
    assert(!active_);
[email protected]
   368
    active_ = unit;
[email protected]
   369
}
[email protected]
   370
[email protected]
   371
void
[email protected]
   372
CompileContext::leave()
[email protected]
   373
{
[email protected]
   374
    assert(active_);
[email protected]
   375
    active_ = NULL;
[email protected]
   376
}
[email protected]
   377
[email protected]
   378
void
[email protected]
   379
CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap)
[email protected]
   380
{
[email protected]
   381
    const char *report = BuildErrorMessage(Messages[msg].format, ap);
[email protected]
   382
    if (!report) {
[email protected]
   383
        active_->setOutOfMemory();
[email protected]
   384
        return;
[email protected]
   385
    }
[email protected]
   386
[email protected]
   387
    active_->appendError(report, pos.line, pos.col);
[email protected]
   388
}
[email protected]
   389
[email protected]
   390
void
[email protected]
   391
CompileContext::reportError(const SourcePosition &pos, Message msg, ...)
[email protected]
   392
{
[email protected]
   393
    va_list ap;
[email protected]
   394
    va_start(ap, msg);
[email protected]
   395
    reportErrorVa(pos, msg, ap);
[email protected]
   396
    va_end(ap);
[email protected]
   397
}
[email protected]
   398
[email protected]
   399
void
[email protected]
   400
TranslationUnit::destroy()
dv[email protected]
   401
{
[email protected]
   402
    for (size_t i = 0; i < errors_.length(); i++)
[email protected]
   403
        FreeErrorMessage(errors_[i].message);
[email protected]
   404
}