diff -r b029d63565a2 -r c1ba166f3fc4 src/compiler/CompileContext.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/compiler/CompileContext.cpp Sat Nov 17 18:41:01 2012 -0800 @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2012 David Anderson + * + * This file is part of JITCraft. + * + * JITCraft is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * JITCraft. If not, see http://www.gnu.org/licenses/. + */ +#include +#include "../Zone.h" +#include "../Interpreter.h" +#include "Scanner.h" +#include "CompileContext.h" +#include "Parser.h" +#include "NameBinding.h" +#include "SemanticAnalysis.h" +#include "../Spaces-inl.h" +#include "../Heap-inl.h" + +using namespace ke; + +CompileContext::CompileContext(Zone *zone, const char *file) + : zone_(zone), + failures_(0), + file_(file) +{ +} + +CompileContext::~CompileContext() +{ + if (failures_) + zone_->endCompilationErrors(); +} + +bool +CompileContext::addTranslationUnit(TranslationUnit *unit) +{ + if (!units_.append(unit)) + return false; + + if (!unparsed_.append(unit)) + return false; + + return true; +} + +char * +CompileContext::loadSource(const char *file, size_t *lengthp) +{ + char *bytes = NULL; + size_t length; + + FILE *fp = fopen(file, "rb"); + if (!fp) { + reportError(SourcePosition(), Message_CantOpenFile); + return NULL; + } + + if (fseek(fp, 0, SEEK_END)) { + reportError(SourcePosition(), Message_ErrorSeekingFile); + fclose(fp); + return NULL; + } + long size = ftell(fp); + if (size < 0) { + reportError(SourcePosition(), Message_ErrorSeekingFile); + fclose(fp); + return NULL; + } + rewind(fp); + length = size_t(size); + bytes = new char[length + 1]; + if (fread(bytes, 1, length, fp) != length) { + reportError(SourcePosition(), Message_ErrorReadingFile); + fclose(fp); + delete [] bytes; + return NULL; + } + fclose(fp); + + *lengthp = length; + return bytes; +} + +bool +CompileContext::parse(TranslationUnit *unit) +{ + assert(!unit->tree_); + + size_t length; + char *source = loadSource(unit->path_.c_str(), &length); + if (!source) + return false; + + Parser parser(ZONE(), *this, source, length); + if ((unit->tree_ = parser.parse()) == NULL) + return false; + + return true; +} + +bool +CompileContext::evaluateImports(TranslationUnit *unit) +{ + if (units_.length() > 1) + return true; + +#if 0 + // For now we hardcode this... + TranslationUnit *u2 = new (ZONE()->pool()) TranslationUnit(); + u2->path_ = "C:\\Users\\dvander\\jitcraft\\jitcraft-2\\src\\Debug\\wizard.sp"; + + ImportStatement *stmt = unit->tree()->imports()->at(0)->toImportStatement(); + stmt->setImportSource(u2); + + if (!u2->dependents_.append(unit)) + return false; + + if (!addTranslationUnit(u2)) + return false; +#endif + + return true; +} + +bool +CompileContext::propagateFailure() +{ + Vector worklist; + for (size_t i = 0; i < units_.length(); i++) { + if (units_[i]->failed() && !worklist.append(units_[i])) + return false; + } + + while (!worklist.empty()) { + TranslationUnit *unit = worklist.popCopy(); + for (size_t i = 0; i < unit->dependents().length(); i++) { + TranslationUnit *other = unit->dependents().at(i); + if (other->failed()) + continue; + + other->failed_ = true; + if (!worklist.append(other)) + return false; + } + } + + return true; +} + +bool +CompileContext::compile() +{ + // Phase 1. Parse all modules we're importing. This process may load new + // modules off disk, and add them to the parse queue. + while (!unparsed_.empty()) { + TranslationUnit *unit = unparsed_.popCopy(); + + if (!parse(unit)) + unit->failed_ = true; + + if (!evaluateImports(unit)) + unit->failed_ = true; + } + + // Phase 2. Create scopes and symbol tables for every lexical region with + // a declaration. This phase excludes declarations created via imports. + for (size_t i = 0; i < units_.length(); i++) { + TranslationUnit *unit = units_[i]; + if (unit->failed()) + continue; + + if (!PopulateNamesAndTypes(zone_, *this, unit)) + unit->failed_ = true; + } + + // Phase 3. Complete imports and bind all names. + for (size_t i = 0; i < units_.length(); i++) { + TranslationUnit *unit = units_[i]; + if (unit->failed()) + continue; + + if (!BindNamesAndTypes(zone_, *this, unit)) + unit->failed_ = true; + } + + // Phase 4. Assign types to every public name in the module. + for (size_t i = 0; i < units_.length(); i++) { + TranslationUnit *unit = units_[i]; + if (unit->failed()) + continue; + + } + + // Intermediate phase. Decide which modules we should not perform + // semantic analysis on. + if (!propagateFailure()) + return false; + + // Phase 4. Perform full semantic analysis on each module. + for (size_t i = 0; i < units_.length(); i++) { + TranslationUnit *unit = units_[i]; + if (unit->failed()) + continue; + + + } + + // Intermediate phase. Propagate failure from semantic analysis. + if (!propagateFailure()) + return false; + + // Phase 5. Now we can finally perform bytecode compilation. + for (size_t i = 0; i < units_.length(); i++) { + TranslationUnit *unit = units_[i]; + if (unit->failed()) + continue; + + SemanticAnalysis sema(zone_, *this, unit); + sema.analyze(); + } + + // Phase 6. Run modules. + for (size_t i = 0; i < units_.length(); i++) { + TranslationUnit *unit = units_[i]; + if (unit->failed()) + continue; + + InvokeArgs args; + if (!zone_->stack().pushModuleFrame(unit->module_, args)) + assert(false); + + ke::LocalSlot slot; + if (!Interpret(zone_, NULL, &slot)) + assert(false); + } + + return true; +} + +void +CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap) +{ + if (!failures_) + zone_->beginCompilationErrors(file_); + + zone_->reportCompilationError(msg, pos.line, pos.col, ap); + + failures_++; +} + +void +CompileContext::reportError(const SourcePosition &pos, Message msg, ...) +{ + va_list ap; + va_start(ap, msg); + reportErrorVa(pos, msg, ap); + va_end(ap); +}