dvander@251: /* dvander@251: * Copyright (C) 2012 David Anderson dvander@251: * dvander@251: * This file is part of SourcePawn. dvander@251: * dvander@251: * SourcePawn is free software: you can redistribute it and/or modify it under dvander@251: * the terms of the GNU General Public License as published by the Free dvander@251: * Software Foundation, either version 3 of the License, or (at your option) dvander@251: * any later version. dvander@251: * dvander@251: * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY dvander@251: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@251: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@251: * dvander@251: * You should have received a copy of the GNU General Public License along with dvander@251: * SourcePawn. If not, see http://www.gnu.org/licenses/. dvander@251: */ dvander@251: #ifndef _include_sp2_packages_h_ dvander@251: #define _include_sp2_packages_h_ dvander@251: dvander@251: #include "PoolAllocator.h" dvander@251: #include "Objects.h" dvander@251: #include "HashTable.h" dvander@251: dvander@251: namespace ke { dvander@251: dvander@251: class String; dvander@251: class Module; dvander@251: class Package; dvander@251: class ImportStatement; dvander@251: class VirtualObjectVisitor; dvander@251: dvander@251: template class List; dvander@251: dvander@251: struct PathComponent : PoolObject dvander@251: { dvander@251: PathComponent(ScopedRoot *name, PathComponent *next) dvander@251: : name(*name), dvander@251: next(next) dvander@251: { dvander@251: } dvander@251: ScopedRoot &name; dvander@251: PathComponent *next; dvander@251: }; dvander@251: dvander@251: class Importable : public Object dvander@251: { dvander@251: public: dvander@251: Package *parent() { dvander@251: return parent_; dvander@251: } dvander@251: String *path() { dvander@251: return path_; dvander@251: } dvander@251: String *name() { dvander@251: return name_; dvander@251: } dvander@251: dvander@251: bool isModule() { dvander@251: return is(MapKind_Module); dvander@251: } dvander@251: bool isPackage() { dvander@251: return is(MapKind_Package); dvander@251: } dvander@251: dvander@251: static inline size_t offsetOfName() { dvander@251: return OFFSETOF(Importable, name_); dvander@251: } dvander@251: static inline size_t offsetOfParent() { dvander@251: return OFFSETOF(Importable, parent_); dvander@251: } dvander@251: static inline size_t offsetOfPath() { dvander@251: return OFFSETOF(Importable, path_); dvander@251: } dvander@251: dvander@251: static inline Importable *cast(Object *obj) { dvander@251: assert(!obj || obj->is(MapKind_Module) || obj->is(MapKind_Package)); dvander@251: return reinterpret_cast(obj); dvander@251: } dvander@251: dvander@251: protected: dvander@251: Barriered name_; dvander@251: Barriered parent_; dvander@251: Barriered path_; dvander@251: }; dvander@251: dvander@251: // A package is a single folder in the file system, and contains any number of dvander@251: // modules and sub-packages. The package hierarchy forms a tree. For simplicity dvander@251: // the root of the tree is an anonymous package that contains no modules. dvander@251: // dvander@251: // Each package in the package hierarchy has two components of path information: dvander@251: // (1) Canonical path. This is a normalized path used to compute the paths of dvander@251: // modules. dvander@251: // (2) Name. This is the package's name as it would appear in a path dvander@251: // component. It is optional. dvander@251: // dvander@251: // Packages may be "hidden", meaning that even if they have names, their name dvander@251: // is not accessible from any import statements. Packages may also be "jailed", dvander@251: // meaning that other names in the package are not visible to each other. dvander@251: // dvander@251: // Packages are created in a few ways: dvander@251: // dvander@251: // (1) System Roots. A system root is a default search location for imports, dvander@251: // and they are installed at the top-level of the hierarchy by the host dvander@251: // application. A system root has a unique top-level name and path. dvander@251: // System roots are always hidden. dvander@251: // dvander@251: // (2) Imports. When importing, the package hierarchy may be extended as dvander@251: // new paths are discovered. Packages discovered this way are never dvander@251: // hidden or jailed. dvander@251: // dvander@251: // (3) Via Package::New(), which creates an empty package. This can be used dvander@251: // to create custom packages. dvander@251: class Package : public Importable dvander@251: { dvander@251: public: dvander@251: enum { dvander@251: Normal = 0, dvander@251: dvander@251: // These must match the flags in the public API for Package. dvander@251: Hidden = (1 << 0), dvander@251: Jailed = (1 << 1) dvander@251: }; dvander@251: dvander@251: public: dvander@251: static Package *NewNormalized(Zone *zone, dvander@251: Handle parent, dvander@251: Handle path, dvander@251: Handle name, dvander@251: unsigned flags); dvander@251: static Package *New(Zone *zone, dvander@251: Handle parent, dvander@251: const char *path, dvander@251: Handle name, dvander@251: unsigned flags); dvander@251: dvander@251: bool add(Zone *zone, Handle component); dvander@251: dvander@251: bool hidden() { dvander@251: return !!(flags_ & Package::Hidden); dvander@251: } dvander@251: bool jailed() { dvander@251: return !!(flags_ & Package::Jailed); dvander@251: } dvander@251: dvander@251: void setNativeIdentity(void *identity) { dvander@251: nativeIdentity_ = identity; dvander@251: } dvander@251: void *getNativeIdentity() { dvander@251: return nativeIdentity_; dvander@251: } dvander@251: Importable *import(Handle name); dvander@251: dvander@251: // Begin GC descriptor. dvander@251: static inline size_t offsetOfContents() { dvander@251: return OFFSETOF(Package, contents_); dvander@251: } dvander@251: // End GC descriptor. dvander@251: dvander@251: static inline Package *cast(Object *obj) { dvander@251: assert(!obj || obj->is(MapKind_Package)); dvander@251: return reinterpret_cast(obj); dvander@251: } dvander@251: dvander@251: private: dvander@251: unsigned flags_; dvander@251: Barriered > contents_; dvander@251: void *nativeIdentity_; dvander@251: }; dvander@251: dvander@251: class PackageCache dvander@251: { dvander@251: public: dvander@251: PackageCache(Zone *zone); dvander@251: ~PackageCache(); dvander@251: bool initialize(); dvander@251: dvander@251: bool findOrAdd(Handle package, PathComponent *path, Importable **out); dvander@251: dvander@251: void accept(VirtualObjectVisitor *visitor); dvander@251: dvander@251: private: dvander@251: bool import(Handle package, PathComponent *path, Importable **out); dvander@251: bool checkfs(Handle package, PathComponent *path, Importable **out); dvander@251: dvander@251: private: dvander@251: Zone *zone_; dvander@251: Vector > roots_; dvander@251: }; dvander@251: dvander@251: } // namespace ke dvander@251: dvander@251: #endif // _include_sp2_packages_h_