Fixed type checking for multidimensional arrays.
2 * Copyright (C) 2012 David Anderson
4 * This file is part of SourcePawn.
6 * SourcePawn is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free
8 * Software Foundation, either version 3 of the License, or (at your option)
11 * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * SourcePawn. If not, see http://www.gnu.org/licenses/.
21 #include "../Interpreter.h"
22 #include "../Packages.h"
23 #include "../FileSystem.h"
24 #include "../FixedArray.h"
25 #include "../Vector.h"
27 #include "CompileContext.h"
29 #include "NameBinding.h"
30 #include "SemanticAnalysis.h"
31 #include "../Spaces-inl.h"
32 #include "../Heap-inl.h"
36 CompileContext::CompileContext(Zone *zone)
42 CompileContext::~CompileContext()
44 for (size_t i = 0; i < units_.length(); i++)
49 CompileContext::initialize(Handle<Package> package, const char *name)
51 size_t len = strlen(name);
52 AutoFree<char> path((char *)zone_->malloc(len + 1));
57 if (len > 3 && strcmp(&name[len - 3], ".sp") == 0)
58 (*path)[len - 3] = '\0';
60 Local<String> strname(zone_, zone_->makeSymbol(*path));
64 PathComponent p(new (zone_->pool()) ScopedRoot<String>(strname), NULL);
66 Local<Importable> importable(zone_);
67 if (!zone_->packages()->findOrAdd(package, &p, importable.address()))
70 // If we couldn't find anything on the filesystem to match, we error out
73 zone_->reportError(Message_CannotImportPath, *path);
77 if (importable->isModule()) {
78 Local<Module> module(zone_, Module::cast(importable));
90 CompileContext::loadSource(Handle<Module> module, size_t *lengthp)
95 FILE *fp = fopen(module->path()->chars(), "rb");
97 reportError(SourcePosition(), Message_CantOpenFile);
101 if (fseek(fp, 0, SEEK_END)) {
102 reportError(SourcePosition(), Message_ErrorSeekingFile);
106 long size = ftell(fp);
108 reportError(SourcePosition(), Message_ErrorSeekingFile);
113 length = size_t(size);
114 bytes = new char[length + 1];
115 if (fread(bytes, 1, length, fp) != length) {
116 reportError(SourcePosition(), Message_ErrorReadingFile);
128 CompileContext::parse(TranslationUnit *unit)
130 assert(!unit->tree_);
133 char *source = loadSource(unit->module(), &length);
137 Parser parser(ZONE(), *this, source, length);
138 if ((unit->tree_ = parser.parse()) == NULL)
145 CompileContext::evaluateImports(TranslationUnit *unit)
147 PoolList<ImportStatement *> *imports = unit->tree()->imports();
149 if (!imports->length())
152 // We're allowed to use Handle<> here instead of ScopedRoot<> because
153 // we get the handle from ImportStatement which has a ScopedRoot<>.
154 Vector<Handle<Importable> > vec;
156 for (size_t i = 0; i < imports->length(); i++) {
157 ImportStatement *import = imports->at(i);
159 // Crawl the path until we find a valid file to load.
160 Local<Importable> obj(zone_);
161 Local<Package> package(zone_, unit->module()->parent());
162 if (!zone_->packages()->findOrAdd(package, import->path(), obj.address()))
165 PathComponent *path = import->path();
168 reportError(import->pos(), Message_CannotImportPath, path->name->chars());
172 // If the object is a package, we will attempt to execute it
173 // immediately after resolving imports.
174 if (obj->isPackage()) {
177 Local<Module> module(zone_, Module::cast(obj));
182 import->setSource(obj);
184 // See if there are any duplicates. This is O(n^2), but we expect
187 for (; index < vec.length(); index++) {
188 if (vec[index] == obj)
191 if (index == vec.length() && !vec.append(import->source()))
194 import->setImportIndex(index);
197 if (!IsUint32MultiplySafe(vec.length(), 2)) {
198 zone_->reportAllocationOverflow();
202 // Create an array of the import and paths.
203 Local<FixedArray> importables(zone_, FixedArray::New(zone_, vec.length() * 2, Heap::Tenure_Default));
207 for (unsigned i = 0; i < vec.length(); i++) {
208 importables->set(zone_, i * 2, vec[i]);
211 PathComponent *path = imports->at(i)->path();
212 for (PathComponent *iter = path; iter; iter = iter->next)
215 Local<FixedArray> list(zone_, FixedArray::New(zone_, count, Heap::Tenure_Default));
220 for (PathComponent *iter = path; iter; iter = iter->next, count++)
221 list->set(zone_, count, iter->name);
223 importables->set(zone_, i * 2 + 1, list);
226 unit->module()->setImports(importables);
231 CompileContext::add(Handle<Module> module)
233 if (module->compiled() || module->translationUnit())
236 TranslationUnit *tu = new (zone_->pool()) TranslationUnit(module);
238 if (!unparsed_.append(tu) || !units_.append(tu))
241 module->setTranslationUnit(tu);
247 CompileContext::propagateFailure()
249 Vector<TranslationUnit *> worklist;
250 for (size_t i = 0; i < units_.length(); i++) {
251 if (units_[i]->failed() && !worklist.append(units_[i]))
255 while (!worklist.empty()) {
256 TranslationUnit *unit = worklist.popCopy();
257 for (size_t i = 0; i < unit->dependents().length(); i++) {
258 TranslationUnit *other = unit->dependents().at(i);
262 other->setDependencyFailed();
263 if (!worklist.append(other))
272 CompileContext::compile()
274 // Phase 1. Parse all modules we're importing. This process may load new
275 // modules off disk and add them to the parse queue.
276 while (!unparsed_.empty()) {
277 TranslationUnit *unit = unparsed_.popCopy();
279 AutoEnterCompileContext enter(*this, unit);
283 evaluateImports(unit);
286 // Phase 2. Create scopes and symbol tables for every lexical region with
287 // a declaration. This phase excludes declarations created via imports.
288 for (size_t i = 0; i < units_.length(); i++) {
289 TranslationUnit *unit = units_[i];
293 PopulateNamesAndTypes(zone_, *this, unit);
296 // Phase 3. Complete imports and bind all names.
297 for (size_t i = 0; i < units_.length(); i++) {
298 TranslationUnit *unit = units_[i];
302 BindGlobals(zone_, *this, unit);
307 BindNamesAndTypes(zone_, *this, unit);
310 // Phase 4. Now we can finally perform SemA+bytecode compilation.
311 for (size_t i = 0; i < units_.length(); i++) {
312 TranslationUnit *unit = units_[i];
316 AutoEnterCompileContext enter(*this, unit);
317 SemanticAnalysis sema(zone_, *this, unit);
321 // Phase 5. Run modules.
322 for (size_t i = 0; i < units_.length(); i++) {
323 TranslationUnit *unit = units_[i];
325 // Mark the unit as no longer being translated.
326 unit->module()->setTranslationUnit(NULL);
332 if (!zone_->stack().pushModuleFrame(unit->module_, args))
336 if (!Interpret(zone_, NULL, &slot))
340 if (Ke::IMessageReporter *reporter = zone_->errorReporter()) {
341 for (size_t i = 0; i < units_.length(); i++) {
342 TranslationUnit *unit = units_[i];
344 // We don't explicitly report errors for dependency failures or OOM
345 // (OOM is reported separately (:TODO:) and dep failures are redundant.
346 if (!unit->errors()->length())
349 reporter->beginCompilationErrors(unit->module()->path()->chars());
350 for (size_t j = 0; j < unit->errors()->length(); j++) {
351 const CompileError &error = unit->errors()->at(j);
352 reporter->reportCompilationError(error.message, error.line, error.col);
354 reporter->endCompilationErrors();
358 return !units_[0]->failed();
362 CompileContext::enter(TranslationUnit *unit)
369 CompileContext::leave()
376 CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap)
378 const char *report = BuildErrorMessage(Messages[msg].format, ap);
380 active_->setOutOfMemory();
384 active_->appendError(report, pos.line, pos.col);
388 CompileContext::reportError(const SourcePosition &pos, Message msg, ...)
392 reportErrorVa(pos, msg, ap);
397 TranslationUnit::destroy()
399 for (size_t i = 0; i < errors_.length(); i++)
400 FreeErrorMessage(errors_[i].message);