Refactor compilation process around the new concept of packages.
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/.
23 #include "FileSystem.h"
26 #include "Handles-inl.h"
31 Package::NewNormalized(Zone *zone, Handle<Package> parent, Handle<String> path, Handle<String> name, unsigned flags)
33 Local<Package> package(zone, Package::cast(zone->allocate(MapKind_Package, sizeof(Package), Heap::Tenure_Old)));
37 // :TODO: assert path, name are atoms.
39 package->flags_ = flags;
40 package->name_ = name;
41 package->parent_ = parent;
42 package->path_ = path;
43 package->nativeIdentity_ = parent ? parent->getNativeIdentity() : NULL;
49 Package::New(Zone *zone, Handle<Package> parent, const char *path, Handle<String> name, unsigned flags)
51 Local<String> strpath(zone, zone->makeSymbol(path));
55 return Package::NewNormalized(zone, parent, strpath, name, flags);
59 Package::add(Zone *zone, Handle<Importable> obj)
61 Local<Package> pkg(zone, this);
63 assert(obj->parent() == pkg);
65 if (!pkg->contents_) {
66 pkg->contents_ = List<Importable>::New(zone);
71 if (!pkg->contents_->append(zone, obj))
78 Package::import(Handle<String> name)
83 for (unsigned i = 0; i < contents_->length(); i++) {
84 Importable *obj = contents_->at(i);
85 if (obj->isPackage() && Package::cast(obj)->name() == name)
87 if (obj->isModule() && Module::cast(obj)->name() == name)
94 PackageCache::PackageCache(Zone *zone)
100 PackageCache::initialize()
106 PackageCache::accept(VirtualObjectVisitor *visitor)
108 for (size_t i = 0; i < roots_.length(); i++)
109 visitor->visit(roots_[i].address());
113 PackageCache::checkfs(Handle<Package> package, PathComponent *path, Importable **out)
115 AutoFree<char> left(strdup(package->path()->chars()));
116 AutoFree<char> right(strdup(path->name->chars()));
117 AutoFree<char> result;
119 if (!JoinPaths(zone_, result, *left, *right))
122 OS::PathType type = OS::InspectPath(*result);
123 if (type == OS::Path_Folder) {
124 // If there is a folder matching this path, create a new subpackage,
125 // and then either return it (if this is the last link), or keep
126 // trying to import the rest of the path.
127 Local<String> strpath(zone_, zone_->makeSymbol(*result));
128 Local<Package> subpackage(zone_, Package::NewNormalized(zone_, package, strpath, path->name, Package::Normal));
135 return import(subpackage, path->next, out);
138 // Otherwise, look for a file ending in ".sp".
139 AutoFree<char> filepath((char *)zone_->malloc(strlen(*result) + strlen(".sp") + 1));
143 strcpy(*filepath, *result);
144 strcat(*filepath, ".sp");
146 type = OS::InspectPath(*filepath);
147 if (type != OS::Path_File)
150 // Create a new, empty module.
151 Local<String> strpath(zone_, zone_->makeSymbol(*filepath));
155 Local<Module> module(zone_, Module::New(zone_, package, strpath, path->name));
156 if (!module || !package->add(zone_, module))
164 PackageCache::import(Handle<Package> package, PathComponent *path, Importable **out)
166 // If the package is jailed, none of its imports are visible.
167 if (package->jailed())
170 Local<Importable> obj(zone_, package->import(path->name));
172 // We couldn't find anything. Try the file system.
173 if (!checkfs(package, path, out))
176 // checkfs will keep trying to import, so if it fails, we just
181 // If we found an existing module, or the path has no next link, then
182 // we can't go any further.
183 if (obj->is(MapKind_Module) || !path->next) {
188 Local<Package> subpackage(zone_, Package::cast(obj));
189 return import(subpackage, path->next, out);
193 PackageCache::findOrAdd(Handle<Package> package, PathComponent *path, Importable **out)
195 // Local rooters should have initialized this, but whatever.
196 assert(*out == NULL);
198 // Try to import locally first.
199 if (!import(package, path, out))
204 // Otherwise, search system roots.
205 Local<Package> root(zone_);
206 for (size_t i = 0; i < roots_.length(); i++) {
208 if (!import(root, path, out))
217 PackageCache::~PackageCache()