1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/compiler/CompileContext.cpp Sat Nov 17 18:41:01 2012 -0800
1.3 @@ -0,0 +1,268 @@
1.4 +/*
1.5 + * Copyright (C) 2012 David Anderson
1.6 + *
1.7 + * This file is part of JITCraft.
1.8 + *
1.9 + * JITCraft is free software: you can redistribute it and/or modify it under
1.10 + * the terms of the GNU General Public License as published by the Free
1.11 + * Software Foundation, either version 3 of the License, or (at your option)
1.12 + * any later version.
1.13 + *
1.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
1.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
1.17 + *
1.18 + * You should have received a copy of the GNU General Public License along with
1.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
1.20 + */
1.21 +#include <stdio.h>
1.22 +#include "../Zone.h"
1.23 +#include "../Interpreter.h"
1.24 +#include "Scanner.h"
1.25 +#include "CompileContext.h"
1.26 +#include "Parser.h"
1.27 +#include "NameBinding.h"
1.28 +#include "SemanticAnalysis.h"
1.29 +#include "../Spaces-inl.h"
1.30 +#include "../Heap-inl.h"
1.31 +
1.32 +using namespace ke;
1.33 +
1.34 +CompileContext::CompileContext(Zone *zone, const char *file)
1.35 + : zone_(zone),
1.36 + failures_(0),
1.37 + file_(file)
1.38 +{
1.39 +}
1.40 +
1.41 +CompileContext::~CompileContext()
1.42 +{
1.43 + if (failures_)
1.44 + zone_->endCompilationErrors();
1.45 +}
1.46 +
1.47 +bool
1.48 +CompileContext::addTranslationUnit(TranslationUnit *unit)
1.49 +{
1.50 + if (!units_.append(unit))
1.51 + return false;
1.52 +
1.53 + if (!unparsed_.append(unit))
1.54 + return false;
1.55 +
1.56 + return true;
1.57 +}
1.58 +
1.59 +char *
1.60 +CompileContext::loadSource(const char *file, size_t *lengthp)
1.61 +{
1.62 + char *bytes = NULL;
1.63 + size_t length;
1.64 +
1.65 + FILE *fp = fopen(file, "rb");
1.66 + if (!fp) {
1.67 + reportError(SourcePosition(), Message_CantOpenFile);
1.68 + return NULL;
1.69 + }
1.70 +
1.71 + if (fseek(fp, 0, SEEK_END)) {
1.72 + reportError(SourcePosition(), Message_ErrorSeekingFile);
1.73 + fclose(fp);
1.74 + return NULL;
1.75 + }
1.76 + long size = ftell(fp);
1.77 + if (size < 0) {
1.78 + reportError(SourcePosition(), Message_ErrorSeekingFile);
1.79 + fclose(fp);
1.80 + return NULL;
1.81 + }
1.82 + rewind(fp);
1.83 + length = size_t(size);
1.84 + bytes = new char[length + 1];
1.85 + if (fread(bytes, 1, length, fp) != length) {
1.86 + reportError(SourcePosition(), Message_ErrorReadingFile);
1.87 + fclose(fp);
1.88 + delete [] bytes;
1.89 + return NULL;
1.90 + }
1.91 + fclose(fp);
1.92 +
1.93 + *lengthp = length;
1.94 + return bytes;
1.95 +}
1.96 +
1.97 +bool
1.98 +CompileContext::parse(TranslationUnit *unit)
1.99 +{
1.100 + assert(!unit->tree_);
1.101 +
1.102 + size_t length;
1.103 + char *source = loadSource(unit->path_.c_str(), &length);
1.104 + if (!source)
1.105 + return false;
1.106 +
1.107 + Parser parser(ZONE(), *this, source, length);
1.108 + if ((unit->tree_ = parser.parse()) == NULL)
1.109 + return false;
1.110 +
1.111 + return true;
1.112 +}
1.113 +
1.114 +bool
1.115 +CompileContext::evaluateImports(TranslationUnit *unit)
1.116 +{
1.117 + if (units_.length() > 1)
1.118 + return true;
1.119 +
1.120 +#if 0
1.121 + // For now we hardcode this...
1.122 + TranslationUnit *u2 = new (ZONE()->pool()) TranslationUnit();
1.123 + u2->path_ = "C:\\Users\\dvander\\jitcraft\\jitcraft-2\\src\\Debug\\wizard.sp";
1.124 +
1.125 + ImportStatement *stmt = unit->tree()->imports()->at(0)->toImportStatement();
1.126 + stmt->setImportSource(u2);
1.127 +
1.128 + if (!u2->dependents_.append(unit))
1.129 + return false;
1.130 +
1.131 + if (!addTranslationUnit(u2))
1.132 + return false;
1.133 +#endif
1.134 +
1.135 + return true;
1.136 +}
1.137 +
1.138 +bool
1.139 +CompileContext::propagateFailure()
1.140 +{
1.141 + Vector<TranslationUnit *> worklist;
1.142 + for (size_t i = 0; i < units_.length(); i++) {
1.143 + if (units_[i]->failed() && !worklist.append(units_[i]))
1.144 + return false;
1.145 + }
1.146 +
1.147 + while (!worklist.empty()) {
1.148 + TranslationUnit *unit = worklist.popCopy();
1.149 + for (size_t i = 0; i < unit->dependents().length(); i++) {
1.150 + TranslationUnit *other = unit->dependents().at(i);
1.151 + if (other->failed())
1.152 + continue;
1.153 +
1.154 + other->failed_ = true;
1.155 + if (!worklist.append(other))
1.156 + return false;
1.157 + }
1.158 + }
1.159 +
1.160 + return true;
1.161 +}
1.162 +
1.163 +bool
1.164 +CompileContext::compile()
1.165 +{
1.166 + // Phase 1. Parse all modules we're importing. This process may load new
1.167 + // modules off disk, and add them to the parse queue.
1.168 + while (!unparsed_.empty()) {
1.169 + TranslationUnit *unit = unparsed_.popCopy();
1.170 +
1.171 + if (!parse(unit))
1.172 + unit->failed_ = true;
1.173 +
1.174 + if (!evaluateImports(unit))
1.175 + unit->failed_ = true;
1.176 + }
1.177 +
1.178 + // Phase 2. Create scopes and symbol tables for every lexical region with
1.179 + // a declaration. This phase excludes declarations created via imports.
1.180 + for (size_t i = 0; i < units_.length(); i++) {
1.181 + TranslationUnit *unit = units_[i];
1.182 + if (unit->failed())
1.183 + continue;
1.184 +
1.185 + if (!PopulateNamesAndTypes(zone_, *this, unit))
1.186 + unit->failed_ = true;
1.187 + }
1.188 +
1.189 + // Phase 3. Complete imports and bind all names.
1.190 + for (size_t i = 0; i < units_.length(); i++) {
1.191 + TranslationUnit *unit = units_[i];
1.192 + if (unit->failed())
1.193 + continue;
1.194 +
1.195 + if (!BindNamesAndTypes(zone_, *this, unit))
1.196 + unit->failed_ = true;
1.197 + }
1.198 +
1.199 + // Phase 4. Assign types to every public name in the module.
1.200 + for (size_t i = 0; i < units_.length(); i++) {
1.201 + TranslationUnit *unit = units_[i];
1.202 + if (unit->failed())
1.203 + continue;
1.204 +
1.205 + }
1.206 +
1.207 + // Intermediate phase. Decide which modules we should not perform
1.208 + // semantic analysis on.
1.209 + if (!propagateFailure())
1.210 + return false;
1.211 +
1.212 + // Phase 4. Perform full semantic analysis on each module.
1.213 + for (size_t i = 0; i < units_.length(); i++) {
1.214 + TranslationUnit *unit = units_[i];
1.215 + if (unit->failed())
1.216 + continue;
1.217 +
1.218 +
1.219 + }
1.220 +
1.221 + // Intermediate phase. Propagate failure from semantic analysis.
1.222 + if (!propagateFailure())
1.223 + return false;
1.224 +
1.225 + // Phase 5. Now we can finally perform bytecode compilation.
1.226 + for (size_t i = 0; i < units_.length(); i++) {
1.227 + TranslationUnit *unit = units_[i];
1.228 + if (unit->failed())
1.229 + continue;
1.230 +
1.231 + SemanticAnalysis sema(zone_, *this, unit);
1.232 + sema.analyze();
1.233 + }
1.234 +
1.235 + // Phase 6. Run modules.
1.236 + for (size_t i = 0; i < units_.length(); i++) {
1.237 + TranslationUnit *unit = units_[i];
1.238 + if (unit->failed())
1.239 + continue;
1.240 +
1.241 + InvokeArgs args;
1.242 + if (!zone_->stack().pushModuleFrame(unit->module_, args))
1.243 + assert(false);
1.244 +
1.245 + ke::LocalSlot slot;
1.246 + if (!Interpret(zone_, NULL, &slot))
1.247 + assert(false);
1.248 + }
1.249 +
1.250 + return true;
1.251 +}
1.252 +
1.253 +void
1.254 +CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap)
1.255 +{
1.256 + if (!failures_)
1.257 + zone_->beginCompilationErrors(file_);
1.258 +
1.259 + zone_->reportCompilationError(msg, pos.line, pos.col, ap);
1.260 +
1.261 + failures_++;
1.262 +}
1.263 +
1.264 +void
1.265 +CompileContext::reportError(const SourcePosition &pos, Message msg, ...)
1.266 +{
1.267 + va_list ap;
1.268 + va_start(ap, msg);
1.269 + reportErrorVa(pos, msg, ap);
1.270 + va_end(ap);
1.271 +}