Refactor compilation process around the new concept of packages.
authorDavid Anderson <dvander@alliedmods.net>
Tue Jan 01 15:34:07 2013 -0800 (2013-01-01)
changeset 251ca99a81745fe
parent 250 0998a43cc155
child 252 1dee2330aa78
Refactor compilation process around the new concept of packages.
AMBuildScript
include/keima.h
src/AMBuild.library
src/API.cpp
src/FileSystem.cpp
src/FileSystem.h
src/GlobalRoots.cpp
src/Interpreter.cpp
src/List.h
src/Messages.tbl
src/Modules.cpp
src/Modules.h
src/ObjectVisitor.h
src/Objects.h
src/Packages.cpp
src/Packages.h
src/Platform-Posix.cpp
src/Platform-Windows.cpp
src/Platform.h
src/Stack.cpp
src/Strings.h
src/Utility.h
src/Vector.h
src/Zone.cpp
src/Zone.h
src/compiler/AST.h
src/compiler/CompileContext.cpp
src/compiler/CompileContext.h
src/compiler/NameBinding.cpp
src/compiler/Parser.cpp
src/compiler/Scanner.cpp
src/compiler/SemanticAnalysis.cpp
src/compiler/SemanticAnalysis.h
src/jitcraft.vcxproj
src/jitcraft.vcxproj.filters
src/main.cpp
tests/basic/divide-by-zero.err
tests/basic/import-sysroot-all.sp
tests/basic/import-sysroot-select.sp
tests/shell.sp
     1.1 --- a/AMBuildScript	Sat Dec 29 00:55:38 2012 -0800
     1.2 +++ b/AMBuildScript	Tue Jan 01 15:34:07 2013 -0800
     1.3 @@ -68,8 +68,12 @@
     1.4  				self.compiler.AddToListVar('CXXFLAGS', '-Wno-invalid-offsetof')
     1.5  
     1.6  				# This would otherwise forbid ((x = y) == NULL) in clang apparently.
     1.7 -				if self.vendor == 'clang':
     1.8 +				if self.vendor == 'clang' and cxx.majorVersion > 1:
     1.9  					self.compiler.AddToListVar('CXXFLAGS', '-Wno-null-arithmetic')
    1.10 +				if self.vendor == 'clang' and \
    1.11 +				   cxx.majorVersion >= 3 and \
    1.12 +				   cxx.minorVersion >= 3:
    1.13 +					self.compiler.AddToListVar('CXXFLAGS', '-Wno-unused-private-field')
    1.14  
    1.15  				if (self.vendor == 'gcc' and cxx.majorVersion >= 4 and cxx.minorVersion >= 7) or \
    1.16  						(self.vendor == 'clang' and cxx.majorVersion >= 3):
     2.1 --- a/include/keima.h	Sat Dec 29 00:55:38 2012 -0800
     2.2 +++ b/include/keima.h	Tue Jan 01 15:34:07 2013 -0800
     2.3 @@ -35,6 +35,7 @@
     2.4  namespace Ke {
     2.5  
     2.6  class Function;
     2.7 +class Package;
     2.8  
     2.9  /*
    2.10   * A Handle is a safe pointer that holds an object reference, such that it
    2.11 @@ -251,6 +252,8 @@
    2.12  class KE_EXPORT String
    2.13  {
    2.14    public:
    2.15 +    static Local<String> NewAscii(const char *str);
    2.16 +
    2.17      // Returns the length of the string, in bytes.
    2.18      unsigned length();
    2.19  
    2.20 @@ -266,6 +269,9 @@
    2.21      // Returns the name of a function, which may be NULL. If not NULL, the
    2.22      // string is guaranteed to be interned.
    2.23      Local<String> name();
    2.24 +
    2.25 +    // Returns the package the function was created in.
    2.26 +    Local<Package> package();
    2.27  };
    2.28  
    2.29  // A pubvar is an ISourcePawnEngine-compatible structure that holds information
    2.30 @@ -278,14 +284,47 @@
    2.31      Local<String> name();
    2.32  };
    2.33  
    2.34 -// A module represents a single compiled file, and contains functions and
    2.35 -// global variables for that file (as well as exported types).
    2.36 -class KE_EXPORT Module
    2.37 +// A package is a collection of compiled files and possibly sub-packages.
    2.38 +// Internally, packages are used to implement the "import" statement. However,
    2.39 +// the host application can also create packages to organize related files,
    2.40 +// restrict import visibility, or implement hot swapping of loaded modules.
    2.41 +class KE_EXPORT Package
    2.42  {
    2.43    public:
    2.44 -    // Sets the native identity pointer, which is passed as the first argument
    2.45 -    // to natives.
    2.46 -    void setNativeIdentity(void *ptr);
    2.47 +    enum {
    2.48 +        Normal = 0,
    2.49 +
    2.50 +        // The package cannot be accessed from any import statement.
    2.51 +        Hidden = (1 << 0),
    2.52 +
    2.53 +        // Source files compiled in this package cannot import names in the
    2.54 +        // package.
    2.55 +        Jailed = (1 << 1)
    2.56 +    };
    2.57 +
    2.58 +    // Creates a package. The parent package may be NULL. The name can be NULL
    2.59 +    // as well. |path| must be a filesystem path, which will be normalized 
    2.60 +    // according to OS-specific rules.
    2.61 +    static Local<Package> New(Handle<Package> parent,
    2.62 +                              Handle<String> name,
    2.63 +                              const char *path,
    2.64 +                              unsigned flags);
    2.65 +
    2.66 +    // Returns the name of the package, which may be NULL. The string is
    2.67 +    // guaranteed to be interned.
    2.68 +    Local<String> name();
    2.69 +
    2.70 +    // Returns the full path of the package. The string is guaranteed to be
    2.71 +    // interned.
    2.72 +    Local<String> path();
    2.73 +
    2.74 +    // Sets the package's native identity. This is a host-application defined
    2.75 +    // value that is passed to native callbacks.  Packages created under this
    2.76 +    // one will automatically inherit this native identity.
    2.77 +    void setNativeIdentity(void *identity);
    2.78 +
    2.79 +    // Returns the package's native identity, or NULL if none was set.
    2.80 +    void *getNativeIdentity();
    2.81  };
    2.82  
    2.83  class Keima
    2.84 @@ -294,7 +333,7 @@
    2.85      /*
    2.86       * Initializes the Keima engine. This must be called exactly once before any
    2.87       * other Keima functions are called. After this, it is safe to use Keima
    2.88 -     * on the calling thread.
    2.89 +     * on the calling thread only. It is not safe to race on calling this.
    2.90       */
    2.91      static bool Initialize();
    2.92  
    2.93 @@ -304,10 +343,10 @@
    2.94      static void Shutdown();
    2.95  
    2.96      /*
    2.97 -     * Searches the call stack and returns true if the given module has any
    2.98 +     * Searches the call stack and returns true if the given package has any
    2.99       * active code running. This is an O(n) algorithm.
   2.100       */
   2.101 -    static bool IsInCallStack(Handle<Module> module);
   2.102 +    static bool IsInCallStack(Handle<Package> package);
   2.103  
   2.104      /*
   2.105       * Reclaim as much memory as possible. This pauses the calling thread
   2.106 @@ -351,6 +390,29 @@
   2.107  
   2.108      /* Sets the object that will listen for public functions. */
   2.109      static void SetPublicFunctionListener(IPublicFunctionListener *listener);
   2.110 +
   2.111 +    /*
   2.112 +     * Installs a system root folder. When an attempt to import locally fails,
   2.113 +     * the list of system roots are searched in the order they were installed.
   2.114 +     *
   2.115 +     * The given path must be absolute. It may contain a trailing slash.
   2.116 +     *
   2.117 +     * The name is an arbitrary, optional identifier that can be used to
   2.118 +     * build fully-qualified package identifiers.
   2.119 +     */
   2.120 +    static bool InstallSystemRoot(const char *path, const char *name);
   2.121 +
   2.122 +    /*
   2.123 +     * Compiles a source file into a package and runs any initializers it has.
   2.124 +     * The file name must be a file name only, rather than a path. It may
   2.125 +     * optionally end in ".sp". If no ".sp" is provided, it is added
   2.126 +     * automatically.
   2.127 +     *
   2.128 +     * Note that if the file name (sans ".sp" extension) does not match the
   2.129 +     * regular expression /^[A-Za-z_][A-Za-z0-9_]+$/ then it will not be
   2.130 +     * importable from other files.
   2.131 +     */
   2.132 +    static bool Compile(Handle<Package> package, const char *name);
   2.133  };
   2.134  
   2.135  /*
   2.136 @@ -464,11 +526,6 @@
   2.137      } u;
   2.138  };
   2.139  
   2.140 -/*
   2.141 - * Compiles a file and returns a Module.
   2.142 - */
   2.143 -extern bool Compile(const char *path);
   2.144 -
   2.145  class Internals
   2.146  {
   2.147      template <typename T> friend class Root;
     3.1 --- a/src/AMBuild.library	Sat Dec 29 00:55:38 2012 -0800
     3.2 +++ b/src/AMBuild.library	Tue Jan 01 15:34:07 2013 -0800
     3.3 @@ -41,6 +41,7 @@
     3.4  	'compiler/Symbols.cpp',
     3.5  	'Environments.cpp',
     3.6  	'Exception.cpp',
     3.7 +	'FileSystem.cpp',
     3.8  	'FixedArray.cpp',
     3.9  	'Functions.cpp',
    3.10  	'GlobalRoots.cpp',
    3.11 @@ -49,6 +50,7 @@
    3.12  	'Modules.cpp',
    3.13  	'NativeTable.cpp',
    3.14  	'Opcodes.cpp',
    3.15 +	'Packages.cpp',
    3.16  	'PoolAllocator.cpp',
    3.17  	'Reference.cpp',
    3.18  	'RootScopes.cpp',
     4.1 --- a/src/API.cpp	Sat Dec 29 00:55:38 2012 -0800
     4.2 +++ b/src/API.cpp	Tue Jan 01 15:34:07 2013 -0800
     4.3 @@ -28,6 +28,7 @@
     4.4  #include "Interpreter.h"
     4.5  #include "Stack.h"
     4.6  #include "Strings.h"
     4.7 +#include "Packages.h"
     4.8  #include "NativeTable.h"
     4.9  #include "Spaces-inl.h"
    4.10  #include "Heap-inl.h"
    4.11 @@ -76,32 +77,35 @@
    4.12  template <typename From, typename To> static inline To *
    4.13  Open(Ke::Handle<From> from)
    4.14  {
    4.15 +    if (!from)
    4.16 +        return NULL;
    4.17      return *reinterpret_cast<To **>(*from);
    4.18  }
    4.19  
    4.20  template <typename From, typename To> static inline To *
    4.21  Open(From *from)
    4.22  {
    4.23 +    if (!from)
    4.24 +        return NULL;
    4.25      return *reinterpret_cast<To **>(from);
    4.26  }
    4.27  
    4.28  template <typename From, typename To> static inline Ke::Local<To>
    4.29  ToLocal(From *from)
    4.30  {
    4.31 +    if (!from)
    4.32 +        return Ke::Local<To>();
    4.33      return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
    4.34  }
    4.35  
    4.36  bool
    4.37 -InternalCompile(const char *path)
    4.38 +InternalCompile(ke::Handle<ke::Package> package, const char *name)
    4.39  {
    4.40      PoolScope poolScope(ZONE()->pool());
    4.41      RootScope roots(ZONE());
    4.42 -    CompileContext cc(ZONE(), path);
    4.43 +    CompileContext cc(ZONE(), name);
    4.44  
    4.45 -    TranslationUnit *unit = new TranslationUnit();
    4.46 -    unit->path_ = path;
    4.47 -
    4.48 -    if (!cc.addTranslationUnit(unit))
    4.49 +    if (!cc.initialize(package, name))
    4.50          return false;
    4.51  
    4.52      if (!cc.compile())
    4.53 @@ -113,9 +117,10 @@
    4.54  // This is split out from InternalCompile so the RootScope doesn't conflict
    4.55  // with making a return handle.
    4.56  bool
    4.57 -Ke::Compile(const char *path)
    4.58 +Ke::Keima::Compile(Handle<Package> argPackage, const char *name)
    4.59  {
    4.60 -    return InternalCompile(path);
    4.61 +    ke::Local<ke::Package> package(ke::ZONE(), Open<Ke::Package, ke::Package>(argPackage));
    4.62 +    return InternalCompile(package, name);
    4.63  }
    4.64  
    4.65  void
    4.66 @@ -186,12 +191,14 @@
    4.67      ZONE()->globalRoots()->destroy(FromAPI(root));
    4.68  }
    4.69  
    4.70 +#if 0
    4.71  bool
    4.72 -Ke::Keima::IsInCallStack(Handle<Module> argModule)
    4.73 +Ke::Keima::IsInCallStack(Handle<Package> package)
    4.74  {
    4.75      ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(argModule));
    4.76      return ZONE()->stack().isInCallStack(module);
    4.77  }
    4.78 +#endif
    4.79  
    4.80  void
    4.81  Ke::Keima::CollectGarbage()
    4.82 @@ -206,10 +213,10 @@
    4.83  }
    4.84  
    4.85  void
    4.86 -Ke::Module::setNativeIdentity(void *identity)
    4.87 +Ke::Package::setNativeIdentity(void *identity)
    4.88  {
    4.89 -    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
    4.90 -    module->setNativeIdentity(identity);
    4.91 +    ke::Local<ke::Package> package(ke::ZONE(), Open<Ke::Package, ke::Package>(this));
    4.92 +    package->setNativeIdentity(identity);
    4.93  }
    4.94  
    4.95  unsigned
    4.96 @@ -233,6 +240,18 @@
    4.97      return ToLocal<ke::String, Ke::String>(fun->name());
    4.98  }
    4.99  
   4.100 +Ke::Local<Ke::Package>
   4.101 +Ke::Package::New(Handle<Package> argParent,
   4.102 +                 Handle<String> argName,
   4.103 +                 const char *path,
   4.104 +                 unsigned flags)
   4.105 +{
   4.106 +    ke::Local<ke::Package> parent(ke::ZONE(), Open<Ke::Package, ke::Package>(argParent));
   4.107 +    ke::Local<ke::String> name(ke::ZONE(), Open<Ke::String, ke::String>(argName));
   4.108 +    ke::Local<ke::Package> package(ke::ZONE(), ke::Package::New(ke::ZONE(), parent, path, name, flags));
   4.109 +    return ToLocal<ke::Package, Ke::Package>(package);
   4.110 +}
   4.111 +
   4.112  static inline const char *
   4.113  GetInvokeTypeName(Ke::Parameter::Type type)
   4.114  {
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/FileSystem.cpp	Tue Jan 01 15:34:07 2013 -0800
     5.3 @@ -0,0 +1,41 @@
     5.4 +/*
     5.5 + * Copyright (C) 2012 David Anderson
     5.6 + *
     5.7 + * This file is part of SourcePawn.
     5.8 + *
     5.9 + * SourcePawn is free software: you can redistribute it and/or modify it under
    5.10 + * the terms of the GNU General Public License as published by the Free
    5.11 + * Software Foundation, either version 3 of the License, or (at your option)
    5.12 + * any later version.
    5.13 + * 
    5.14 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    5.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    5.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License along with
    5.19 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
    5.20 + */
    5.21 +#include <string.h>
    5.22 +#include "Zone.h"
    5.23 +#include "FileSystem.h"
    5.24 +
    5.25 +bool
    5.26 +ke::JoinPaths(Zone *zone, AutoFree<char> &result, const char *base, const char *name)
    5.27 +{
    5.28 +    const char *sep = OS::PathSeparator();
    5.29 +
    5.30 +    size_t baselen = strlen(base);
    5.31 +    size_t namelen = strlen(name);
    5.32 +    size_t seplen = strlen(sep);
    5.33 +
    5.34 +    char *ptr = (char *)zone->malloc(baselen + seplen + namelen + 1);
    5.35 +    if (!ptr)
    5.36 +        return false;
    5.37 +
    5.38 +    strcpy(ptr, base);
    5.39 +    strcpy(ptr + baselen, sep);
    5.40 +    strcpy(ptr + baselen + seplen, name);
    5.41 +
    5.42 +    result = ptr;
    5.43 +    return true;
    5.44 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/FileSystem.h	Tue Jan 01 15:34:07 2013 -0800
     6.3 @@ -0,0 +1,32 @@
     6.4 +/*
     6.5 + * Copyright (C) 2012 David Anderson
     6.6 + *
     6.7 + * This file is part of SourcePawn.
     6.8 + *
     6.9 + * SourcePawn is free software: you can redistribute it and/or modify it under
    6.10 + * the terms of the GNU General Public License as published by the Free
    6.11 + * Software Foundation, either version 3 of the License, or (at your option)
    6.12 + * any later version.
    6.13 + * 
    6.14 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    6.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    6.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    6.17 + *
    6.18 + * You should have received a copy of the GNU General Public License along with
    6.19 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
    6.20 + */
    6.21 +#ifndef _include_sp2_filesystem_h_
    6.22 +#define _include_sp2_filesystem_h_
    6.23 +
    6.24 +#include "Utility.h"
    6.25 +
    6.26 +namespace ke {
    6.27 +
    6.28 +class Zone;
    6.29 +
    6.30 +// Joins a NULL terminated list of char pointers into a path.
    6.31 +bool JoinPaths(Zone *zone, AutoFree<char> &result, const char *base, const char *name);
    6.32 +
    6.33 +} // namespace ke
    6.34 +
    6.35 +#endif // _include_sp2_filesystem_h_
     7.1 --- a/src/GlobalRoots.cpp	Sat Dec 29 00:55:38 2012 -0800
     7.2 +++ b/src/GlobalRoots.cpp	Tue Jan 01 15:34:07 2013 -0800
     7.3 @@ -32,9 +32,9 @@
     7.4  {
     7.5      InlineList<HeapRoot>::iterator iter = roots_.begin();
     7.6      while (iter != roots_.end()) {
     7.7 -		HeapRoot *root = *iter;
     7.8 +        HeapRoot *root = *iter;
     7.9          iter = roots_.erase(iter);
    7.10 -		delete root;
    7.11 +        delete root;
    7.12      }
    7.13  }
    7.14  
     8.1 --- a/src/Interpreter.cpp	Sat Dec 29 00:55:38 2012 -0800
     8.2 +++ b/src/Interpreter.cpp	Tue Jan 01 15:34:07 2013 -0800
     8.3 @@ -27,6 +27,7 @@
     8.4  #include "Environments.h"
     8.5  #include "Structures.h"
     8.6  #include "NativeTable.h"
     8.7 +#include "Packages.h"
     8.8  #include "Heap-inl.h"
     8.9  
    8.10  using namespace ke;
    8.11 @@ -866,7 +867,7 @@
    8.12      top.sp--;
    8.13  
    8.14      int result;
    8.15 -    void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
    8.16 +    void *nativeIdentity = top.fp->code()->module()->parent()->getNativeIdentity();
    8.17      if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
    8.18          goto error;
    8.19  
    8.20 @@ -877,7 +878,7 @@
    8.21  
    8.22  case OP_BITCAST:
    8.23  {
    8.24 -    // Because the stack is a union, this is a no-ops.
    8.25 +    // Because the stack is a union, this is a no-op.
    8.26      break;
    8.27  }
    8.28  
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/List.h	Tue Jan 01 15:34:07 2013 -0800
     9.3 @@ -0,0 +1,119 @@
     9.4 +/* vim: set ts=4 sw=4 tw=99 et:
     9.5 + *
     9.6 + * Copyright (C) 2012 David Anderson
     9.7 + *
     9.8 + * This file is part of SourcePawn.
     9.9 + *
    9.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
    9.11 + * the terms of the GNU General Public License as published by the Free
    9.12 + * Software Foundation, either version 3 of the License, or (at your option)
    9.13 + * any later version.
    9.14 + * 
    9.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    9.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    9.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    9.18 + *
    9.19 + * You should have received a copy of the GNU General Public License along with
    9.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
    9.21 + */
    9.22 +#ifndef _include_sp2_list_h_
    9.23 +#define _include_sp2_list_h_
    9.24 +
    9.25 +#include "Objects.h"
    9.26 +#include "FixedArray.h"
    9.27 +#include "Zone.h"
    9.28 +#include "Heap-inl.h"
    9.29 +#include "Handles-inl.h"
    9.30 +
    9.31 +namespace ke {
    9.32 +
    9.33 +template <typename T>
    9.34 +class List : public Object
    9.35 +{
    9.36 +  public:
    9.37 +    static List *New(Zone *zone, Heap::Tenure tenure = Heap::Tenure_Default) {
    9.38 +        Local<List> list(zone, List::cast(zone->allocate(MapKind_List, sizeof(List), tenure)));
    9.39 +        if (!list)
    9.40 +            return NULL;
    9.41 +
    9.42 +        list->length_ = 0;
    9.43 +        list->array_ = NULL;
    9.44 +
    9.45 +        return list;
    9.46 +    }
    9.47 +
    9.48 +    bool append(Zone *zone, Handle<T> obj) {
    9.49 +        Local<List> list(zone, this);
    9.50 +        if (!Grow(zone, list, 1))
    9.51 +            return false;
    9.52 +
    9.53 +        list->array_->set(zone, list->length_, obj);
    9.54 +        list->length_++;
    9.55 +        return true;
    9.56 +    }
    9.57 +
    9.58 +    T *at(unsigned i) {
    9.59 +        return T::cast(array_->at(i));
    9.60 +    }
    9.61 +
    9.62 +    unsigned length() {
    9.63 +        return length_;
    9.64 +    }
    9.65 +
    9.66 +  private:
    9.67 +    static bool Grow(Zone *zone, Handle<List> list, unsigned amount) {
    9.68 +        if (!IsUint32AddSafe(list->length(), amount)) {
    9.69 +            zone->reportAllocationOverflow();
    9.70 +            return false;
    9.71 +        }
    9.72 +
    9.73 +        unsigned newlen = list->length() + amount;
    9.74 +        if (list->array_ && newlen < list->array_->length())
    9.75 +            return true;
    9.76 +
    9.77 +        unsigned maxsize = list->array_ ? list->array_->length() : 8;
    9.78 +        if (!IsUint32AddSafe(maxsize, amount)) {
    9.79 +            zone->reportAllocationOverflow();
    9.80 +            return false;
    9.81 +        }
    9.82 +
    9.83 +        while (newlen > maxsize) {
    9.84 +            if (!IsUint32MultiplySafe(maxsize, 2)) {
    9.85 +                zone->reportAllocationOverflow();
    9.86 +                return false;
    9.87 +            }
    9.88 +            maxsize *= 2;
    9.89 +        }
    9.90 +
    9.91 +        Local<FixedArray> array(zone, FixedArray::New(zone, maxsize, Heap::Tenure_Default));
    9.92 +        if (!array)
    9.93 +            return false;
    9.94 +
    9.95 +        for (unsigned i = 0; i < list->length_; i++)
    9.96 +            array->set(zone, i, list->array_->at(i));
    9.97 +
    9.98 +        list->array_ = array;
    9.99 +        return true;
   9.100 +    }
   9.101 +
   9.102 +  public:
   9.103 +
   9.104 +    // Begin GC descriptor.
   9.105 +    static inline size_t offsetOfArray() {
   9.106 +        return OFFSETOF(List, array_);
   9.107 +    }
   9.108 +    // End GC descriptor.
   9.109 +
   9.110 +    static inline List *cast(Object *obj) {
   9.111 +        assert(!obj || obj->is(MapKind_List));
   9.112 +        return reinterpret_cast<List *>(obj);
   9.113 +    }
   9.114 +
   9.115 +  private:
   9.116 +    unsigned length_;
   9.117 +    FixedArray *array_;
   9.118 +};
   9.119 +
   9.120 +} // namespace ke
   9.121 +
   9.122 +#endif // _include_sp2_list_h_
    10.1 --- a/src/Messages.tbl	Sat Dec 29 00:55:38 2012 -0800
    10.2 +++ b/src/Messages.tbl	Tue Jan 01 15:34:07 2013 -0800
    10.3 @@ -84,4 +84,5 @@
    10.4  MSG(InvalidConstOnFormal,           TypeError,              "const parameters must be arrays or structs")
    10.5  MSG(InvalidUncheckedCastFrom,       TypeError,              "cannot perform an unchecked cast on type '%s'")
    10.6  MSG(InvalidUncheckedCastTo,         TypeError,              "cannot perform an unchecked cast to type '%s'")
    10.7 -MSG(InvalidUnaryType,               TypeError,              "operator %s not defined for type '%s'")
    10.8 \ No newline at end of file
    10.9 +MSG(InvalidUnaryType,               TypeError,              "operator %s not defined for type '%s'")
   10.10 +MSG(CannotImportPath,               SyntaxError,            "could not find module or import '%s'")
   10.11 \ No newline at end of file
    11.1 --- a/src/Modules.cpp	Sat Dec 29 00:55:38 2012 -0800
    11.2 +++ b/src/Modules.cpp	Tue Jan 01 15:34:07 2013 -0800
    11.3 @@ -23,15 +23,18 @@
    11.4  using namespace ke;
    11.5  
    11.6  Module *
    11.7 -Module::New(Zone *zone)
    11.8 +Module::New(Zone *zone, Handle<Package> package, Handle<String> path, Handle<String> name)
    11.9  {
   11.10      Local<Module> module(zone, Module::cast(zone->allocate(MapKind_Module, sizeof(Module), Heap::Tenure_Old)));
   11.11      if (!module)
   11.12          return NULL;
   11.13  
   11.14 -    module->file_ = NULL;
   11.15 +    module->parent_ = package;
   11.16 +    module->path_ = path;
   11.17 +    module->name_ = name;
   11.18      module->globals_ = NULL;
   11.19      module->nativeIdentity_ = NULL;
   11.20      module->globals_ = NULL;
   11.21 +    module->unit_ = NULL;
   11.22      return module;
   11.23  }
    12.1 --- a/src/Modules.h	Sat Dec 29 00:55:38 2012 -0800
    12.2 +++ b/src/Modules.h	Tue Jan 01 15:34:07 2013 -0800
    12.3 @@ -1,19 +1,19 @@
    12.4  /*
    12.5   * Copyright (C) 2012 David Anderson
    12.6   *
    12.7 - * This file is part of JITCraft.
    12.8 + * This file is part of SourcePawn.
    12.9   *
   12.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   12.11 + * SourcePawn is free software: you can redistribute it and/or modify it under
   12.12   * the terms of the GNU General Public License as published by the Free
   12.13   * Software Foundation, either version 3 of the License, or (at your option)
   12.14   * any later version.
   12.15   * 
   12.16 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   12.17 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   12.18   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   12.19   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   12.20   *
   12.21   * You should have received a copy of the GNU General Public License along with
   12.22 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   12.23 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   12.24   */
   12.25  #ifndef _include_jc_module_h_
   12.26  #define _include_jc_module_h_
   12.27 @@ -21,25 +21,25 @@
   12.28  #include "Heap.h"
   12.29  #include "Code.h"
   12.30  #include "Functions.h"
   12.31 +#include "Packages.h"
   12.32  
   12.33  namespace ke {
   12.34  
   12.35  class Environment;
   12.36  class Struct;
   12.37 +class Package;
   12.38 +struct TranslationUnit;
   12.39  
   12.40 -class Module : public Object
   12.41 +class Module : public Importable
   12.42  {
   12.43 -    Barriered<String> file_;
   12.44      Barriered<Code> code_;
   12.45      Barriered<Struct> globals_;
   12.46      void *nativeIdentity_;
   12.47 +    TranslationUnit *unit_;
   12.48  
   12.49    public:
   12.50 -    static Module *New(Zone *zone);
   12.51 +    static Module *New(Zone *zone, Handle<Package> package, Handle<String> path, Handle<String> name);
   12.52      
   12.53 -    String *file() {
   12.54 -        return file_;
   12.55 -    }
   12.56      Code *code() {
   12.57          return code_;
   12.58      }
   12.59 @@ -47,9 +47,22 @@
   12.60          return globals_;
   12.61      }
   12.62  
   12.63 -    void setPath(Handle<String> path) {
   12.64 -        file_ = path;
   12.65 +    bool compiled() {
   12.66 +        return !!code_;
   12.67      }
   12.68 +
   12.69 +    // Modules are pre-created, and may have their intermediate compilation
   12.70 +    // data attached while they are being compiled.
   12.71 +    bool compiling() {
   12.72 +        return !!unit_;
   12.73 +    }
   12.74 +    TranslationUnit *translationUnit() {
   12.75 +        return unit_;
   12.76 +    }
   12.77 +    void setTranslationUnit(TranslationUnit *unit) {
   12.78 +        unit_ = unit;
   12.79 +    }
   12.80 +
   12.81      void setCode(Handle<Code> code) {
   12.82          code_ = code;
   12.83      }
   12.84 @@ -57,17 +70,7 @@
   12.85          globals_ = globals;
   12.86      }
   12.87  
   12.88 -    void *nativeIdentity() {
   12.89 -        return nativeIdentity_;
   12.90 -    }
   12.91 -    void setNativeIdentity(void *identity) {
   12.92 -        nativeIdentity_ = identity;
   12.93 -    }
   12.94 -
   12.95      // Begin GC Descriptor.
   12.96 -    static inline size_t offsetOfFile() {
   12.97 -        return OFFSETOF(Module, file_);
   12.98 -    }
   12.99      static inline size_t offsetOfCode() {
  12.100          return OFFSETOF(Module, code_);
  12.101      }
    13.1 --- a/src/ObjectVisitor.h	Sat Dec 29 00:55:38 2012 -0800
    13.2 +++ b/src/ObjectVisitor.h	Tue Jan 01 15:34:07 2013 -0800
    13.3 @@ -2,19 +2,19 @@
    13.4   *
    13.5   * Copyright (C) 2012 David Anderson
    13.6   *
    13.7 - * This file is part of JITCraft.
    13.8 + * This file is part of SourcePawn.
    13.9   *
   13.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   13.11 + * SourcePawn is free software: you can redistribute it and/or modify it under
   13.12   * the terms of the GNU General Public License as published by the Free
   13.13   * Software Foundation, either version 3 of the License, or (at your option)
   13.14   * any later version.
   13.15   * 
   13.16 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   13.17 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   13.18   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13.19   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   13.20   *
   13.21   * You should have received a copy of the GNU General Public License along with
   13.22 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   13.23 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   13.24   */
   13.25  #ifndef _include_jc_object_visitor_h_
   13.26  #define _include_jc_object_visitor_h_
   13.27 @@ -31,6 +31,8 @@
   13.28  #include "Environments.h"
   13.29  #include "Structures.h"
   13.30  #include "Box.h"
   13.31 +#include "Packages.h"
   13.32 +#include "List.h"
   13.33  
   13.34  namespace ke {
   13.35  
   13.36 @@ -113,13 +115,25 @@
   13.37          return sizeof(Reference);
   13.38      }
   13.39  
   13.40 +    void visitImportable(Object *obj) {
   13.41 +        visitField(obj, Package::offsetOfName());
   13.42 +        visitField(obj, Package::offsetOfParent());
   13.43 +        visitField(obj, Package::offsetOfPath());
   13.44 +    }
   13.45 +
   13.46      size_t iterateModule(Object *obj) {
   13.47 -        visitField(obj, Module::offsetOfFile());
   13.48 +        visitImportable(obj);
   13.49          visitField(obj, Module::offsetOfGlobals());
   13.50          visitField(obj, Module::offsetOfCode());
   13.51          return sizeof(Module);
   13.52      }
   13.53  
   13.54 +    size_t iteratePackage(Object *obj) {
   13.55 +        visitImportable(obj);
   13.56 +        visitField(obj, Package::offsetOfContents());
   13.57 +        return sizeof(Package);
   13.58 +    }
   13.59 +
   13.60      size_t iterateFunction(Object *obj) {
   13.61          visitField(obj, Function::offsetOfCode());
   13.62          visitField(obj, Function::offsetOfType());
   13.63 @@ -202,6 +216,11 @@
   13.64          return obj->objSize();
   13.65      }
   13.66  
   13.67 +    size_t iterateList(Object *obj) {
   13.68 +        visitField(obj, List<Object>::offsetOfArray());
   13.69 +        return sizeof(List<Object>);
   13.70 +    }
   13.71 +
   13.72    private:
   13.73      size_t iterateObject(Object *obj) {
   13.74          visitField(obj, Object::offsetOfMap());
   13.75 @@ -243,6 +262,9 @@
   13.76            case MapKind_Module:
   13.77              return iterateModule(obj);
   13.78  
   13.79 +          case MapKind_Package:
   13.80 +            return iteratePackage(obj);
   13.81 +
   13.82            case MapKind_Function:
   13.83              return iterateFunction(obj);
   13.84  
   13.85 @@ -264,6 +286,9 @@
   13.86            case MapKind_Struct:
   13.87              return iterateStruct(Struct::cast(obj));
   13.88  
   13.89 +          case MapKind_List:
   13.90 +            return iterateList(obj);
   13.91 +
   13.92            case MapKind_EnvironmentSlotDescriptorArray:
   13.93              return iterateEnvironmentSlotDescriptorArray(EnvironmentSlotDescriptorArray::cast(obj));
   13.94  
   13.95 @@ -335,6 +360,9 @@
   13.96        case MapKind_Module:
   13.97          return sizeof(Module);
   13.98  
   13.99 +      case MapKind_Package:
  13.100 +        return sizeof(Package);
  13.101 +
  13.102        case MapKind_Descriptor:
  13.103          return sizeof(Descriptor);
  13.104  
  13.105 @@ -356,6 +384,9 @@
  13.106        case MapKind_Box:
  13.107          return sizeof(Box);
  13.108  
  13.109 +      case MapKind_List:
  13.110 +        return sizeof(List<Object>);
  13.111 +
  13.112        case MapKind_Struct:
  13.113          return Struct::cast(obj)->objSize();
  13.114  
    14.1 --- a/src/Objects.h	Sat Dec 29 00:55:38 2012 -0800
    14.2 +++ b/src/Objects.h	Tue Jan 01 15:34:07 2013 -0800
    14.3 @@ -2,19 +2,19 @@
    14.4   *
    14.5   * Copyright (C) 2012 David Anderson
    14.6   *
    14.7 - * This file is part of JITCraft.
    14.8 + * This file is part of SourcePawn.
    14.9   *
   14.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   14.11 + * SourcePawn is free software: you can redistribute it and/or modify it under
   14.12   * the terms of the GNU General Public License as published by the Free
   14.13   * Software Foundation, either version 3 of the License, or (at your option)
   14.14   * any later version.
   14.15   * 
   14.16 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   14.17 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   14.18   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   14.19   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   14.20   *
   14.21   * You should have received a copy of the GNU General Public License along with
   14.22 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   14.23 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   14.24   */
   14.25  #ifndef _include_jitcraft_objects_h_
   14.26  #define _include_jitcraft_objects_h_
   14.27 @@ -57,6 +57,8 @@
   14.28      MapKind_Environment,
   14.29      MapKind_Descriptor,
   14.30      MapKind_Box,
   14.31 +    MapKind_Package,
   14.32 +    MapKind_List,
   14.33  
   14.34      // These do not have canonical maps.
   14.35      MapKind_Array,
   14.36 @@ -92,6 +94,10 @@
   14.37  
   14.38      inline void write(Zone *zone, Object **ptr, Object *value);
   14.39  
   14.40 +    static inline Object *cast(Object *obj) {
   14.41 +        return obj;
   14.42 +    }
   14.43 +
   14.44      static inline size_t offsetOfMap() {
   14.45          // Clang doesn't accept offsetof here and it's not clear why...
   14.46          return reinterpret_cast<size_t>(&((Object *)NULL)->map_);
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/Packages.cpp	Tue Jan 01 15:34:07 2013 -0800
    15.3 @@ -0,0 +1,219 @@
    15.4 +/*
    15.5 + * Copyright (C) 2012 David Anderson
    15.6 + *
    15.7 + * This file is part of SourcePawn.
    15.8 + *
    15.9 + * SourcePawn is free software: you can redistribute it and/or modify it under
   15.10 + * the terms of the GNU General Public License as published by the Free
   15.11 + * Software Foundation, either version 3 of the License, or (at your option)
   15.12 + * any later version.
   15.13 + * 
   15.14 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   15.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   15.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   15.17 + *
   15.18 + * You should have received a copy of the GNU General Public License along with
   15.19 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   15.20 + */
   15.21 +#include "Zone.h"
   15.22 +#include "Heap.h"
   15.23 +#include "Strings.h"
   15.24 +#include "Modules.h"
   15.25 +#include "Packages.h"
   15.26 +#include "FileSystem.h"
   15.27 +#include "List.h"
   15.28 +#include "Heap-inl.h"
   15.29 +#include "Handles-inl.h"
   15.30 +
   15.31 +using namespace ke;
   15.32 +
   15.33 +Package *
   15.34 +Package::NewNormalized(Zone *zone, Handle<Package> parent, Handle<String> path, Handle<String> name, unsigned flags)
   15.35 +{
   15.36 +    Local<Package> package(zone, Package::cast(zone->allocate(MapKind_Package, sizeof(Package), Heap::Tenure_Old)));
   15.37 +    if (!package)
   15.38 +        return NULL;
   15.39 +
   15.40 +    // :TODO: assert path, name are atoms.
   15.41 +
   15.42 +    package->flags_ = flags;
   15.43 +    package->name_ = name;
   15.44 +    package->parent_ = parent;
   15.45 +    package->path_ = path;
   15.46 +    package->nativeIdentity_ = parent ? parent->getNativeIdentity() : NULL;
   15.47 +
   15.48 +    return package;
   15.49 +}
   15.50 +
   15.51 +Package *
   15.52 +Package::New(Zone *zone, Handle<Package> parent, const char *path, Handle<String> name, unsigned flags)
   15.53 +{
   15.54 +    Local<String> strpath(zone, zone->makeSymbol(path));
   15.55 +    if (!strpath)
   15.56 +        return NULL;
   15.57 +
   15.58 +    return Package::NewNormalized(zone, parent, strpath, name, flags);
   15.59 +}
   15.60 +
   15.61 +bool
   15.62 +Package::add(Zone *zone, Handle<Importable> obj)
   15.63 +{
   15.64 +    Local<Package> pkg(zone, this);
   15.65 +
   15.66 +    assert(obj->parent() == pkg);
   15.67 +
   15.68 +    if (!pkg->contents_) {
   15.69 +        pkg->contents_ = List<Importable>::New(zone);
   15.70 +        if (!pkg->contents_)
   15.71 +            return false;
   15.72 +    }
   15.73 +
   15.74 +    if (!pkg->contents_->append(zone, obj))
   15.75 +        return false;
   15.76 +
   15.77 +    return true;
   15.78 +}
   15.79 +
   15.80 +Importable *
   15.81 +Package::import(Handle<String> name)
   15.82 +{
   15.83 +    if (!contents_)
   15.84 +        return NULL;
   15.85 +    
   15.86 +    for (unsigned i = 0; i < contents_->length(); i++) {
   15.87 +        Importable *obj = contents_->at(i);
   15.88 +        if (obj->isPackage() && Package::cast(obj)->name() == name)
   15.89 +            return obj;
   15.90 +        if (obj->isModule() && Module::cast(obj)->name() == name)
   15.91 +            return obj;
   15.92 +    }
   15.93 +
   15.94 +    return NULL;
   15.95 +}
   15.96 +
   15.97 +PackageCache::PackageCache(Zone *zone)
   15.98 +  : zone_(zone)
   15.99 +{
  15.100 +}
  15.101 +
  15.102 +bool
  15.103 +PackageCache::initialize()
  15.104 +{
  15.105 +    return true;
  15.106 +}
  15.107 +
  15.108 +void
  15.109 +PackageCache::accept(VirtualObjectVisitor *visitor)
  15.110 +{
  15.111 +    for (size_t i = 0; i < roots_.length(); i++)
  15.112 +        visitor->visit(roots_[i].address());
  15.113 +}
  15.114 +
  15.115 +bool
  15.116 +PackageCache::checkfs(Handle<Package> package, PathComponent *path, Importable **out)
  15.117 +{
  15.118 +    AutoFree<char> left(strdup(package->path()->chars()));
  15.119 +    AutoFree<char> right(strdup(path->name->chars()));
  15.120 +    AutoFree<char> result;
  15.121 +
  15.122 +    if (!JoinPaths(zone_, result, *left, *right))
  15.123 +        return false;
  15.124 +
  15.125 +    OS::PathType type = OS::InspectPath(*result);
  15.126 +    if (type == OS::Path_Folder) {
  15.127 +        // If there is a folder matching this path, create a new subpackage,
  15.128 +        // and then either return it (if this is the last link), or keep
  15.129 +        // trying to import the rest of the path.
  15.130 +        Local<String> strpath(zone_, zone_->makeSymbol(*result));
  15.131 +        Local<Package> subpackage(zone_, Package::NewNormalized(zone_, package, strpath, path->name, Package::Normal));
  15.132 +        if (!subpackage)
  15.133 +            return false;
  15.134 +        if (!path->next) {
  15.135 +            *out = subpackage;
  15.136 +            return true;
  15.137 +        }
  15.138 +        return import(subpackage, path->next, out);
  15.139 +    }
  15.140 +
  15.141 +    // Otherwise, look for a file ending in ".sp".
  15.142 +    AutoFree<char> filepath((char *)zone_->malloc(strlen(*result) + strlen(".sp") + 1));
  15.143 +    if (!*filepath)
  15.144 +        return false;
  15.145 +
  15.146 +    strcpy(*filepath, *result);
  15.147 +    strcat(*filepath, ".sp");
  15.148 +
  15.149 +    type = OS::InspectPath(*filepath);
  15.150 +    if (type != OS::Path_File)
  15.151 +        return true;
  15.152 +
  15.153 +    // Create a new, empty module.
  15.154 +    Local<String> strpath(zone_, zone_->makeSymbol(*filepath));
  15.155 +    if (!strpath)
  15.156 +        return false;
  15.157 +
  15.158 +    Local<Module> module(zone_, Module::New(zone_, package, strpath, path->name));
  15.159 +    if (!module || !package->add(zone_, module))
  15.160 +        return false;
  15.161 +
  15.162 +    *out = module;
  15.163 +    return true;
  15.164 +}
  15.165 +
  15.166 +bool
  15.167 +PackageCache::import(Handle<Package> package, PathComponent *path, Importable **out)
  15.168 +{
  15.169 +    // If the package is jailed, none of its imports are visible.
  15.170 +    if (package->jailed())
  15.171 +        return true;
  15.172 +
  15.173 +    Local<Importable> obj(zone_, package->import(path->name));
  15.174 +    if (!obj) {
  15.175 +        // We couldn't find anything. Try the file system.
  15.176 +        if (!checkfs(package, path, out))
  15.177 +            return false;
  15.178 +
  15.179 +        // checkfs will keep trying to import, so if it fails, we just
  15.180 +        // propagate up.
  15.181 +        return true;
  15.182 +    }
  15.183 +
  15.184 +    // If we found an existing module, or the path has no next link, then
  15.185 +    // we can't go any further.
  15.186 +    if (obj->is(MapKind_Module) || !path->next) {
  15.187 +        *out = obj;
  15.188 +        return true;
  15.189 +    }
  15.190 +
  15.191 +    Local<Package> subpackage(zone_, Package::cast(obj));
  15.192 +    return import(subpackage, path->next, out);
  15.193 +}
  15.194 +
  15.195 +bool
  15.196 +PackageCache::findOrAdd(Handle<Package> package, PathComponent *path, Importable **out)
  15.197 +{
  15.198 +    // Local rooters should have initialized this, but whatever.
  15.199 +    assert(*out == NULL);
  15.200 +
  15.201 +    // Try to import locally first.
  15.202 +    if (!import(package, path, out))
  15.203 +        return false;
  15.204 +    if (*out)
  15.205 +        return true;
  15.206 +
  15.207 +    // Otherwise, search system roots.
  15.208 +    Local<Package> root(zone_);
  15.209 +    for (size_t i = 0; i < roots_.length(); i++) {
  15.210 +        root = roots_[i];
  15.211 +        if (!import(root, path, out))
  15.212 +            return false;
  15.213 +        if (*out)
  15.214 +            return true;
  15.215 +    }
  15.216 +
  15.217 +    return true;
  15.218 +}
  15.219 +
  15.220 +PackageCache::~PackageCache()
  15.221 +{
  15.222 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/Packages.h	Tue Jan 01 15:34:07 2013 -0800
    16.3 @@ -0,0 +1,193 @@
    16.4 +/*
    16.5 + * Copyright (C) 2012 David Anderson
    16.6 + *
    16.7 + * This file is part of SourcePawn.
    16.8 + *
    16.9 + * SourcePawn is free software: you can redistribute it and/or modify it under
   16.10 + * the terms of the GNU General Public License as published by the Free
   16.11 + * Software Foundation, either version 3 of the License, or (at your option)
   16.12 + * any later version.
   16.13 + * 
   16.14 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   16.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   16.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   16.17 + *
   16.18 + * You should have received a copy of the GNU General Public License along with
   16.19 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   16.20 + */
   16.21 +#ifndef _include_sp2_packages_h_
   16.22 +#define _include_sp2_packages_h_
   16.23 +
   16.24 +#include "PoolAllocator.h"
   16.25 +#include "Objects.h"
   16.26 +#include "HashTable.h"
   16.27 +
   16.28 +namespace ke {
   16.29 +
   16.30 +class String;
   16.31 +class Module;
   16.32 +class Package;
   16.33 +class ImportStatement;
   16.34 +class VirtualObjectVisitor;
   16.35 +
   16.36 +template <typename T> class List;
   16.37 +
   16.38 +struct PathComponent : PoolObject
   16.39 +{
   16.40 +    PathComponent(ScopedRoot<String> *name, PathComponent *next)
   16.41 +      : name(*name),
   16.42 +        next(next)
   16.43 +    {
   16.44 +    }
   16.45 +    ScopedRoot<String> &name;
   16.46 +    PathComponent *next;
   16.47 +};
   16.48 +
   16.49 +class Importable : public Object
   16.50 +{
   16.51 +  public:
   16.52 +    Package *parent() {
   16.53 +        return parent_;
   16.54 +    }
   16.55 +    String *path() {
   16.56 +        return path_;
   16.57 +    }
   16.58 +    String *name() {
   16.59 +        return name_;
   16.60 +    }
   16.61 +
   16.62 +    bool isModule() {
   16.63 +        return is(MapKind_Module);
   16.64 +    }
   16.65 +    bool isPackage() {
   16.66 +        return is(MapKind_Package);
   16.67 +    }
   16.68 +
   16.69 +    static inline size_t offsetOfName() {
   16.70 +        return OFFSETOF(Importable, name_);
   16.71 +    }
   16.72 +    static inline size_t offsetOfParent() {
   16.73 +        return OFFSETOF(Importable, parent_);
   16.74 +    }
   16.75 +    static inline size_t offsetOfPath() {
   16.76 +        return OFFSETOF(Importable, path_);
   16.77 +    }
   16.78 +
   16.79 +    static inline Importable *cast(Object *obj) {
   16.80 +        assert(!obj || obj->is(MapKind_Module) || obj->is(MapKind_Package));
   16.81 +        return reinterpret_cast<Importable *>(obj);
   16.82 +    }
   16.83 +
   16.84 +  protected:
   16.85 +    Barriered<String> name_;
   16.86 +    Barriered<Package> parent_;
   16.87 +    Barriered<String> path_;
   16.88 +};
   16.89 +
   16.90 +// A package is a single folder in the file system, and contains any number of
   16.91 +// modules and sub-packages. The package hierarchy forms a tree. For simplicity
   16.92 +// the root of the tree is an anonymous package that contains no modules.
   16.93 +//
   16.94 +// Each package in the package hierarchy has two components of path information:
   16.95 +//   (1) Canonical path. This is a normalized path used to compute the paths of
   16.96 +//       modules.
   16.97 +//   (2) Name. This is the package's name as it would appear in a path
   16.98 +//       component. It is optional.
   16.99 +//
  16.100 +// Packages may be "hidden", meaning that even if they have names, their name
  16.101 +// is not accessible from any import statements. Packages may also be "jailed",
  16.102 +// meaning that other names in the package are not visible to each other.
  16.103 +//
  16.104 +// Packages are created in a few ways:
  16.105 +//
  16.106 +//   (1) System Roots. A system root is a default search location for imports,
  16.107 +//       and they are installed at the top-level of the hierarchy by the host
  16.108 +//       application. A system root has a unique top-level name and path.
  16.109 +//       System roots are always hidden.
  16.110 +//
  16.111 +//   (2) Imports. When importing, the package hierarchy may be extended as
  16.112 +//       new paths are discovered. Packages discovered this way are never
  16.113 +//       hidden or jailed.
  16.114 +//
  16.115 +//   (3) Via Package::New(), which creates an empty package. This can be used
  16.116 +//       to create custom packages.
  16.117 +class Package : public Importable
  16.118 +{
  16.119 +  public:
  16.120 +    enum {
  16.121 +        Normal = 0,
  16.122 +
  16.123 +        // These must match the flags in the public API for Package.
  16.124 +        Hidden = (1 << 0),
  16.125 +        Jailed = (1 << 1)
  16.126 +    };
  16.127 +
  16.128 +  public:
  16.129 +    static Package *NewNormalized(Zone *zone,
  16.130 +                                  Handle<Package> parent,
  16.131 +                                  Handle<String> path,
  16.132 +                                  Handle<String> name,
  16.133 +                                  unsigned flags);
  16.134 +    static Package *New(Zone *zone,
  16.135 +                        Handle<Package> parent,
  16.136 +                        const char *path,
  16.137 +                        Handle<String> name,
  16.138 +                        unsigned flags);
  16.139 +
  16.140 +    bool add(Zone *zone, Handle<Importable> component);
  16.141 +
  16.142 +    bool hidden() {
  16.143 +        return !!(flags_ & Package::Hidden);
  16.144 +    }
  16.145 +    bool jailed() {
  16.146 +        return !!(flags_ & Package::Jailed);
  16.147 +    }
  16.148 +
  16.149 +    void setNativeIdentity(void *identity) {
  16.150 +        nativeIdentity_ = identity;
  16.151 +    }
  16.152 +    void *getNativeIdentity() {
  16.153 +        return nativeIdentity_;
  16.154 +    }
  16.155 +    Importable *import(Handle<String> name);
  16.156 +
  16.157 +    // Begin GC descriptor.
  16.158 +    static inline size_t offsetOfContents() {
  16.159 +        return OFFSETOF(Package, contents_);
  16.160 +    }
  16.161 +    // End GC descriptor.
  16.162 +
  16.163 +    static inline Package *cast(Object *obj) {
  16.164 +        assert(!obj || obj->is(MapKind_Package));
  16.165 +        return reinterpret_cast<Package *>(obj);
  16.166 +    }
  16.167 +
  16.168 +  private:
  16.169 +    unsigned flags_;
  16.170 +    Barriered<List<Importable> > contents_;
  16.171 +    void *nativeIdentity_;
  16.172 +};
  16.173 +
  16.174 +class PackageCache
  16.175 +{
  16.176 +  public:
  16.177 +    PackageCache(Zone *zone);
  16.178 +    ~PackageCache();
  16.179 +    bool initialize();
  16.180 +
  16.181 +    bool findOrAdd(Handle<Package> package, PathComponent *path, Importable **out);
  16.182 +
  16.183 +    void accept(VirtualObjectVisitor *visitor);
  16.184 +
  16.185 +  private:
  16.186 +    bool import(Handle<Package> package, PathComponent *path, Importable **out);
  16.187 +    bool checkfs(Handle<Package> package, PathComponent *path, Importable **out);
  16.188 +
  16.189 +  private:
  16.190 +    Zone *zone_;
  16.191 +    Vector<Unbarriered<Package> > roots_;
  16.192 +};
  16.193 +
  16.194 +} // namespace ke
  16.195 +
  16.196 +#endif // _include_sp2_packages_h_
    17.1 --- a/src/Platform-Posix.cpp	Sat Dec 29 00:55:38 2012 -0800
    17.2 +++ b/src/Platform-Posix.cpp	Tue Jan 01 15:34:07 2013 -0800
    17.3 @@ -17,6 +17,9 @@
    17.4   * JITCraft. If not, see http://www.gnu.org/licenses/.
    17.5   */
    17.6  #include <sys/mman.h>
    17.7 +#include <limits.h>
    17.8 +#include <string.h>
    17.9 +#include <stdlib.h>
   17.10  #include "Platform.h"
   17.11  
   17.12  using namespace ke;
   17.13 @@ -99,3 +102,55 @@
   17.14      OS::UnmapMemory(address, size);
   17.15  }
   17.16  
   17.17 +bool
   17.18 +OS::GetAbsolutePath(const char *path, AutoFree<char> &chars)
   17.19 +{
   17.20 +    chars = (char *)calloc(PATH_MAX, sizeof(char));
   17.21 +    if (!*chars)
   17.22 +        return false;
   17.23 +
   17.24 +    char *ptr = realpath(path, *chars);
   17.25 +    if (!ptr)
   17.26 +        return false;
   17.27 +
   17.28 +    return ptr == *chars;
   17.29 +}
   17.30 +
   17.31 +bool
   17.32 +OS::SplitPath(const char *path, AutoFree<char> &base, AutoFree<char> &name)
   17.33 +{
   17.34 +    // dirname() and basename() pretty much suck.
   17.35 +    size_t len = strlen(path);
   17.36 +
   17.37 +    // Skip trailing slashes.
   17.38 +    while (len > 1 && (path[len - 1] == '/'))
   17.39 +        len--;
   17.40 +
   17.41 +    for (size_t i = len - 1; i < len; i--) {
   17.42 +        if (path[i] == '/') {
   17.43 +            name = (char *)calloc(len - i, sizeof(char));
   17.44 +            if (!*name)
   17.45 +                return false;
   17.46 +
   17.47 +            strcpy(*name, &path[i + 1]);
   17.48 +
   17.49 +            base = (char *)calloc(i + 1, sizeof(char));
   17.50 +            if (!*base)
   17.51 +                return false;
   17.52 +
   17.53 +            memcpy(*base, path, i);
   17.54 +            (*base)[i] = '\0';
   17.55 +            return true;
   17.56 +        }
   17.57 +    }
   17.58 +    
   17.59 +    // The path should have been absolute, which contains at least one separator.
   17.60 +    return false;
   17.61 +}
   17.62 +
   17.63 +const char *
   17.64 +OS::PathSeparator()
   17.65 +{
   17.66 +    return "/";
   17.67 +}
   17.68 +
    18.1 --- a/src/Platform-Windows.cpp	Sat Dec 29 00:55:38 2012 -0800
    18.2 +++ b/src/Platform-Windows.cpp	Tue Jan 01 15:34:07 2013 -0800
    18.3 @@ -17,9 +17,10 @@
    18.4   * SourcePawn. If not, see http://www.gnu.org/licenses/.
    18.5   */
    18.6  
    18.7 -// :TODO: move into utility-style include
    18.8  #define WIN32_LEAN_AND_MEAN
    18.9  #include <Windows.h>
   18.10 +#include <direct.h>
   18.11 +#include <sys/stat.h>
   18.12  #include "Platform.h"
   18.13  
   18.14  using namespace ke;
   18.15 @@ -109,3 +110,78 @@
   18.16  {
   18.17      OS::UnmapMemory(address, size);
   18.18  }
   18.19 +
   18.20 +bool
   18.21 +OS::GetAbsolutePath(const char *path, AutoFree<char> &chars)
   18.22 +{
   18.23 +    char try1[MAX_PATH];
   18.24 +    DWORD result = GetFullPathName(path, sizeof(try1), try1, NULL);
   18.25 +    if (result <= 0)
   18.26 +        return false;
   18.27 +
   18.28 +    // +1 because if result < MAX_PATH, it doesn't include the null terminator.
   18.29 +    chars = (char *)calloc(result + 1, sizeof(char));
   18.30 +    if (!*chars)
   18.31 +        return false;
   18.32 +
   18.33 +    if (result <= MAX_PATH) {
   18.34 +        strcpy(*chars, try1);
   18.35 +        return true;
   18.36 +    }
   18.37 +
   18.38 +    // We should get the same output on the next try.
   18.39 +    return GetFullPathName(path, result, *chars, NULL) == result - 1;
   18.40 +}
   18.41 +
   18.42 +bool
   18.43 +OS::SplitPath(const char *path, AutoFree<char> &base, AutoFree<char> &name)
   18.44 +{
   18.45 +    size_t len = strlen(path);
   18.46 +
   18.47 +    // Skip trailing slashes.
   18.48 +    while (len > 1 && (path[len - 1] == '/' || path[len - 1] == '\\'))
   18.49 +        len--;
   18.50 +
   18.51 +    for (size_t i = len - 1; i < len; i--) {
   18.52 +        if (path[i] == '\\' || path[i] == '/') {
   18.53 +            name = (char *)calloc(len - i, sizeof(char));
   18.54 +            if (!*name)
   18.55 +                return false;
   18.56 +
   18.57 +            strcpy(*name, &path[i + 1]);
   18.58 +
   18.59 +            base = (char *)calloc(i + 1, sizeof(char));
   18.60 +            if (!*base)
   18.61 +                return false;
   18.62 +
   18.63 +            memcpy(*base, path, i);
   18.64 +            (*base)[i] = '\0';
   18.65 +            return true;
   18.66 +        }
   18.67 +    }
   18.68 +    
   18.69 +    // The path should have been absolute, which contains at least one separator.
   18.70 +    return false;
   18.71 +}
   18.72 +
   18.73 +const char *
   18.74 +OS::PathSeparator()
   18.75 +{
   18.76 +    return "\\";
   18.77 +}
   18.78 +
   18.79 +OS::PathType
   18.80 +OS::InspectPath(const char *path)
   18.81 +{
   18.82 +    struct _stat s;
   18.83 +    int result = _stat(path, &s);
   18.84 +    if (result != 0)
   18.85 +        return OS::Path_Invalid;
   18.86 +
   18.87 +    if (s.st_mode & _S_IFDIR)
   18.88 +        return OS::Path_Folder;
   18.89 +    if (s.st_mode & _S_IFREG)
   18.90 +        return OS::Path_File;
   18.91 +
   18.92 +    return OS::Path_Invalid;
   18.93 +}
    19.1 --- a/src/Platform.h	Sat Dec 29 00:55:38 2012 -0800
    19.2 +++ b/src/Platform.h	Tue Jan 01 15:34:07 2013 -0800
    19.3 @@ -2,19 +2,19 @@
    19.4   *
    19.5   * Copyright (C) 2012 David Anderson
    19.6   *
    19.7 - * This file is part of JITCraft.
    19.8 + * This file is part of SourcePawn.
    19.9   *
   19.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   19.11 + * SourcePawn is free software: you can redistribute it and/or modify it under
   19.12   * the terms of the GNU General Public License as published by the Free
   19.13   * Software Foundation, either version 3 of the License, or (at your option)
   19.14   * any later version.
   19.15   * 
   19.16 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   19.17 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   19.18   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   19.19   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   19.20   *
   19.21   * You should have received a copy of the GNU General Public License along with
   19.22 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   19.23 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   19.24   */
   19.25  #ifndef _include_jitcraft_platform_h_
   19.26  #define _include_jitcraft_platform_h_
   19.27 @@ -72,10 +72,28 @@
   19.28          }
   19.29      };
   19.30  
   19.31 +    enum PathType {
   19.32 +        Path_Invalid,
   19.33 +        Path_File,
   19.34 +        Path_Folder
   19.35 +    };
   19.36 +
   19.37 +    PathType InspectPath(const char *path);
   19.38 +
   19.39 +    // Converts a relative path into an absolute path, based on the current
   19.40 +    // working directory.
   19.41 +    bool GetAbsolutePath(const char *path, AutoFree<char> &chars);
   19.42 +
   19.43 +    // Splits a path into its constituent base folder and file. The path must
   19.44 +    // be an absolute path.
   19.45 +    bool SplitPath(const char *path, AutoFree<char> &base, AutoFree<char> &name);
   19.46 +
   19.47      // MapAlignedMemory is guaranteed to return zeroed memory.
   19.48      AlignableMapping MapAlignedMemory(size_t amount, size_t alignment, MapMode mode);
   19.49      void UnmapAlignedMemory(Address address, size_t size);
   19.50  
   19.51 +    const char *PathSeparator();
   19.52 +
   19.53      // The default alignment of memory returned via MapMemory().
   19.54      // :TODO: better ifdefs
   19.55  #ifdef _MSC_VER
    20.1 --- a/src/Stack.cpp	Sat Dec 29 00:55:38 2012 -0800
    20.2 +++ b/src/Stack.cpp	Tue Jan 01 15:34:07 2013 -0800
    20.3 @@ -328,8 +328,8 @@
    20.4  {
    20.5      if (fp_->isNative())
    20.6          return "<native>";
    20.7 -    return fp_->code()->module()->file()
    20.8 -           ? fp_->code()->module()->file()->chars()
    20.9 +    return fp_->code()->module()->path()
   20.10 +           ? fp_->code()->module()->path()->chars()
   20.11             : "(anonymous)";
   20.12  }
   20.13  
    21.1 --- a/src/Strings.h	Sat Dec 29 00:55:38 2012 -0800
    21.2 +++ b/src/Strings.h	Tue Jan 01 15:34:07 2013 -0800
    21.3 @@ -38,6 +38,9 @@
    21.4      char *chars() {
    21.5          return reinterpret_cast<char *>(this + 1);
    21.6      }
    21.7 +    char *chars(Zone *zone) {
    21.8 +        return chars();
    21.9 +    }
   21.10      size_t objSize() {
   21.11          return SizeFor(length());
   21.12      }
    22.1 --- a/src/Utility.h	Sat Dec 29 00:55:38 2012 -0800
    22.2 +++ b/src/Utility.h	Tue Jan 01 15:34:07 2013 -0800
    22.3 @@ -21,6 +21,7 @@
    22.4  
    22.5  #include <assert.h>
    22.6  #include <stddef.h>
    22.7 +#include <stdlib.h>
    22.8  #include "../include/keima_util.h"
    22.9  #ifdef _MSC_VER
   22.10  # include <intrin.h>
   22.11 @@ -47,28 +48,33 @@
   22.12  static const size_t kGB = 1024 * kMB;
   22.13  
   22.14  template <typename T>
   22.15 -class AutoVec
   22.16 +class AutoFree
   22.17  {
   22.18      T *t_;
   22.19  
   22.20    public:
   22.21 -    AutoVec()
   22.22 +    AutoFree()
   22.23        : t_(NULL)
   22.24      {
   22.25      }
   22.26 -    AutoVec(T *t)
   22.27 +    AutoFree(T *t)
   22.28        : t_(t)
   22.29      {
   22.30      }
   22.31 -    ~AutoVec() {
   22.32 -        delete [] t_;
   22.33 +    ~AutoFree() {
   22.34 +        free(t_);
   22.35      }
   22.36 -    operator T *() {
   22.37 +    T *take() {
   22.38 +        T *t = t_;
   22.39 +        t_ = NULL;
   22.40 +        return t;
   22.41 +    }
   22.42 +    T *operator *() const {
   22.43          return t_;
   22.44      }
   22.45      void operator =(T *t) {
   22.46          if (t_)
   22.47 -            delete [] t_;
   22.48 +            free(t_);
   22.49          t_ = t;
   22.50      }
   22.51  };
   22.52 @@ -116,11 +122,11 @@
   22.53  static inline uint32
   22.54  HashInt32(int32 a)
   22.55  {
   22.56 -    a = (a ^ 61) ^ (a >> 16);
   22.57 -    a = a + (a << 3);
   22.58 -    a = a ^ (a >> 4);
   22.59 -    a = a * 0x27d4eb2d;
   22.60 -    a = a ^ (a >> 15);
   22.61 +    a = (a ^ 61) ^ (a >> 16);
   22.62 +    a = a + (a << 3);
   22.63 +    a = a ^ (a >> 4);
   22.64 +    a = a * 0x27d4eb2d;
   22.65 +    a = a ^ (a >> 15);
   22.66      return a;
   22.67  }
   22.68  
   22.69 @@ -128,12 +134,12 @@
   22.70  static inline uint32
   22.71  HashInt64(int64 key)
   22.72  {
   22.73 -  key = (~key) + (key << 18); // key = (key << 18) - key - 1;
   22.74 -  key = key ^ (uint64(key) >> 31);
   22.75 -  key = key * 21; // key = (key + (key << 2)) + (key << 4);
   22.76 -  key = key ^ (uint64(key) >> 11);
   22.77 -  key = key + (key << 6);
   22.78 -  key = key ^ (uint64(key) >> 22);
   22.79 +  key = (~key) + (key << 18); // key = (key << 18) - key - 1;
   22.80 +  key = key ^ (uint64(key) >> 31);
   22.81 +  key = key * 21; // key = (key + (key << 2)) + (key << 4);
   22.82 +  key = key ^ (uint64(key) >> 11);
   22.83 +  key = key + (key << 6);
   22.84 +  key = key ^ (uint64(key) >> 22);
   22.85    return uint32(key);
   22.86  }
   22.87  
   22.88 @@ -161,11 +167,11 @@
   22.89  # endif
   22.90      return rval;
   22.91  #else
   22.92 -	size_t bit;
   22.93 -	asm("bsr %1, %0\n"
   22.94 -		: "=r" (bit)
   22.95 -		: "rm" (number));
   22.96 -	return bit;
   22.97 +    size_t bit;
   22.98 +    asm("bsr %1, %0\n"
   22.99 +        : "=r" (bit)
  22.100 +        : "rm" (number));
  22.101 +    return bit;
  22.102  #endif
  22.103  }
  22.104  
  22.105 @@ -183,11 +189,11 @@
  22.106  # endif
  22.107      return rval;
  22.108  #else
  22.109 -	size_t bit;
  22.110 -	asm("bsf %1, %0\n"
  22.111 -		: "=r" (bit)
  22.112 -		: "rm" (number));
  22.113 -	return bit;
  22.114 +    size_t bit;
  22.115 +    asm("bsf %1, %0\n"
  22.116 +        : "=r" (bit)
  22.117 +        : "rm" (number));
  22.118 +    return bit;
  22.119  #endif
  22.120  }
  22.121  
  22.122 @@ -253,7 +259,7 @@
  22.123  #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
  22.124  #define STATIC_ASSERT(cond) extern int static_assert_f(int a[(cond) ? 1 : -1])
  22.125  
  22.126 -#define IS_ALIGNED(addr, alignment)	(!(uintptr_t(addr) & ((alignment) - 1)))
  22.127 +#define IS_ALIGNED(addr, alignment)    (!(uintptr_t(addr) & ((alignment) - 1)))
  22.128  
  22.129  template <typename T>
  22.130  static inline bool
    23.1 --- a/src/Vector.h	Sat Dec 29 00:55:38 2012 -0800
    23.2 +++ b/src/Vector.h	Tue Jan 01 15:34:07 2013 -0800
    23.3 @@ -106,8 +106,7 @@
    23.4          }
    23.5          if (maxsize == 0)
    23.6              maxsize = 8;
    23.7 -        while (nitems + needed > maxsize)
    23.8 -        {
    23.9 +        while (nitems + needed > maxsize) {
   23.10              if (!IsUintPtrMultiplySafe(maxsize, 2)) {
   23.11                  this->reportAllocationOverflow();
   23.12                  return false;
   23.13 @@ -117,8 +116,7 @@
   23.14          T* newdata = (T*)this->malloc(sizeof(T) * maxsize);
   23.15          if (newdata == NULL)
   23.16              return false;
   23.17 -        for (size_t i = 0; i < nitems; i++)
   23.18 -        {
   23.19 +        for (size_t i = 0; i < nitems; i++) {
   23.20              new (&newdata[i]) T(data[i]);
   23.21              data[i].~T();
   23.22          }
    24.1 --- a/src/Zone.cpp	Sat Dec 29 00:55:38 2012 -0800
    24.2 +++ b/src/Zone.cpp	Tue Jan 01 15:34:07 2013 -0800
    24.3 @@ -24,6 +24,7 @@
    24.4  #include "AllocatorPolicies.h"
    24.5  #include "Array.h"
    24.6  #include "NativeTable.h"
    24.7 +#include "Packages.h"
    24.8  #include "Spaces-inl.h"
    24.9  #include "Heap-inl.h"
   24.10  
   24.11 @@ -39,6 +40,8 @@
   24.12      types_(NULL),
   24.13      symbols_(NULL),
   24.14      globalRoots_(NULL),
   24.15 +    nativeTable_(NULL),
   24.16 +    packages_(NULL),
   24.17      lastLocalRoot_(NULL),
   24.18      specialRoots_(NULL),
   24.19      hasPendingException_(false),
   24.20 @@ -48,10 +51,11 @@
   24.21  
   24.22  Zone::~Zone()
   24.23  {
   24.24 +    delete nativeTable_;
   24.25      delete types_;
   24.26 -    delete nativeTable_;
   24.27 +    delete symbols_;
   24.28 +    delete packages_;
   24.29      delete globalRoots_;
   24.30 -    delete symbols_;
   24.31  }
   24.32  
   24.33  bool
   24.34 @@ -74,6 +78,10 @@
   24.35      if (!nativeTable_ || !nativeTable_->initialize())
   24.36          return false;
   24.37  
   24.38 +    packages_ = new PackageCache(this);
   24.39 +    if (!packages_ || !packages_->initialize())
   24.40 +        return false;
   24.41 +
   24.42      MapKind maps[] =
   24.43      {
   24.44          MapKind_Type,
   24.45 @@ -95,6 +103,8 @@
   24.46          MapKind_Native,
   24.47          MapKind_Descriptor,
   24.48          MapKind_Box,
   24.49 +        MapKind_List,
   24.50 +        MapKind_Package,
   24.51          MapKind_FreeRegion,
   24.52          MapKind_EnvironmentSlotDescriptorArray
   24.53      };
   24.54 @@ -176,6 +186,7 @@
   24.55      globalRoots_->accept(visitor);
   24.56      rootScopes_.accept(visitor);
   24.57      nativeTable_->accept(visitor);
   24.58 +    packages_->accept(visitor);
   24.59  
   24.60      stack_.accept(visitor);
   24.61  }
   24.62 @@ -326,6 +337,24 @@
   24.63      publicFunctionListener_ = listener;
   24.64  }
   24.65  
   24.66 +void *
   24.67 +Zone::malloc(size_t size)
   24.68 +{
   24.69 +    void *ptr = ::malloc(size);
   24.70 +    if (!ptr)
   24.71 +        reportOutOfMemory();
   24.72 +    return ptr;
   24.73 +}
   24.74 +
   24.75 +void *
   24.76 +Zone::realloc(void *ptr, size_t size)
   24.77 +{
   24.78 +    ptr = ::realloc(ptr, size);
   24.79 +    if (!ptr)
   24.80 +        reportOutOfMemory();
   24.81 +    return ptr;
   24.82 +}
   24.83 +
   24.84  AutoRooted::AutoRooted(Zone *zone)
   24.85    : zone_(zone),
   24.86      prev_(*zone->lastSpecialRoot())
    25.1 --- a/src/Zone.h	Sat Dec 29 00:55:38 2012 -0800
    25.2 +++ b/src/Zone.h	Tue Jan 01 15:34:07 2013 -0800
    25.3 @@ -38,6 +38,7 @@
    25.4  class ArrayMap;
    25.5  class Exception;
    25.6  class NativeTable;
    25.7 +class PackageCache;
    25.8  
    25.9  class Zone
   25.10  {
   25.11 @@ -54,6 +55,7 @@
   25.12      StringPool *symbols_;
   25.13      GlobalRoots *globalRoots_;
   25.14      NativeTable *nativeTable_;
   25.15 +    PackageCache *packages_;
   25.16  
   25.17      // Root list.
   25.18      Local<Object> *lastLocalRoot_;
   25.19 @@ -129,6 +131,9 @@
   25.20      NativeTable *nativeTable() {
   25.21          return nativeTable_;
   25.22      }
   25.23 +    PackageCache *packages() {
   25.24 +        return packages_;
   25.25 +    }
   25.26  
   25.27      String *makeSymbol(const char *string, size_t length);
   25.28      String *makeSymbol(const char *string);
   25.29 @@ -150,6 +155,10 @@
   25.30      void setPublicFunctionListener(Ke::IPublicFunctionListener *listener);
   25.31      void registerPublic(Handle<Function> fun);
   25.32      void unregisterPublic(Handle<Function> fun);
   25.33 +
   25.34 +    // Helpers that report OOM.
   25.35 +    void *malloc(size_t size);
   25.36 +    void *realloc(void *ptr, size_t size);
   25.37  };
   25.38  
   25.39  // In a multi-threaded system, this would be a TLS variable.
    26.1 --- a/src/compiler/AST.h	Sat Dec 29 00:55:38 2012 -0800
    26.2 +++ b/src/compiler/AST.h	Tue Jan 01 15:34:07 2013 -0800
    26.3 @@ -28,6 +28,7 @@
    26.4  namespace ke {
    26.5  
    26.6  class Scope;
    26.7 +struct PathComponent;
    26.8  
    26.9  #define ASTKINDS(_)             \
   26.10      _(VariableDeclaration)      \
   26.11 @@ -58,7 +59,7 @@
   26.12      _(StructureStatement)       \
   26.13      _(SwitchStatement)          \
   26.14      _(ArrayLiteral)             \
   26.15 -	_(ImportStatement)
   26.16 +    _(ImportStatement)
   26.17  
   26.18  // Forward declarations.
   26.19  #define _(name) class name;
   26.20 @@ -1104,9 +1105,9 @@
   26.21  class ImportStatement : public Statement
   26.22  {
   26.23    public:
   26.24 -    ImportStatement(const SourcePosition &pos, NameList *names, TokenKind suffix)
   26.25 +    ImportStatement(const SourcePosition &pos, PathComponent *path, TokenKind suffix)
   26.26        : Statement(pos),
   26.27 -        names_(names),
   26.28 +        path_(path),
   26.29          suffix_(suffix),
   26.30          source_(NULL)
   26.31      {
   26.32 @@ -1114,8 +1115,8 @@
   26.33  
   26.34      DECLARE_NODE(ImportStatement);
   26.35  
   26.36 -    NameList *path() const {
   26.37 -        return names_;
   26.38 +    PathComponent *path() const {
   26.39 +        return path_;
   26.40      }
   26.41      void setImportSource(TranslationUnit *unit) {
   26.42          source_ = unit;
   26.43 @@ -1126,13 +1127,9 @@
   26.44      TokenKind suffix() const {
   26.45          return suffix_;
   26.46      }
   26.47 -    Handle<String> name() const {
   26.48 -        assert(suffix() != TOK_STAR);
   26.49 -        return *names_->at(names_->length() - 1);
   26.50 -    }
   26.51  
   26.52    private:
   26.53 -    NameList *names_;
   26.54 +    PathComponent *path_;
   26.55      TokenKind suffix_;
   26.56      TranslationUnit *source_;
   26.57  };
    27.1 --- a/src/compiler/CompileContext.cpp	Sat Dec 29 00:55:38 2012 -0800
    27.2 +++ b/src/compiler/CompileContext.cpp	Tue Jan 01 15:34:07 2013 -0800
    27.3 @@ -1,23 +1,25 @@
    27.4  /*
    27.5   * Copyright (C) 2012 David Anderson
    27.6   *
    27.7 - * This file is part of JITCraft.
    27.8 + * This file is part of SourcePawn.
    27.9   *
   27.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   27.11 + * SourcePawn is free software: you can redistribute it and/or modify it under
   27.12   * the terms of the GNU General Public License as published by the Free
   27.13   * Software Foundation, either version 3 of the License, or (at your option)
   27.14   * any later version.
   27.15   * 
   27.16 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   27.17 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   27.18   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   27.19   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   27.20   *
   27.21   * You should have received a copy of the GNU General Public License along with
   27.22 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   27.23 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   27.24   */
   27.25  #include <stdio.h>
   27.26  #include "../Zone.h"
   27.27  #include "../Interpreter.h"
   27.28 +#include "../Packages.h"
   27.29 +#include "../FileSystem.h"
   27.30  #include "Scanner.h"
   27.31  #include "CompileContext.h"
   27.32  #include "Parser.h"
   27.33 @@ -38,28 +40,57 @@
   27.34  CompileContext::~CompileContext()
   27.35  {
   27.36      for (size_t i = 0; i < units_.length(); i++)
   27.37 -        delete units_[i];
   27.38 +        units_[i]->destroy();
   27.39  }
   27.40  
   27.41  bool
   27.42 -CompileContext::addTranslationUnit(TranslationUnit *unit)
   27.43 +CompileContext::initialize(Handle<Package> package, const char *name)
   27.44  {
   27.45 -    if (!units_.append(unit))
   27.46 +    size_t len = strlen(name);
   27.47 +    AutoFree<char> path((char *)zone_->malloc(len + 1));
   27.48 +    if (!*path)
   27.49 +        return false;
   27.50 +
   27.51 +    strcpy(*path, name);
   27.52 +    if (len > 3 && strcmp(&name[len - 3], ".sp") == 0)
   27.53 +        (*path)[len - 3] = '\0';
   27.54 +
   27.55 +    Local<String> strname(zone_, zone_->makeSymbol(*path));
   27.56 +    if (!strname)
   27.57          return false;
   27.58  
   27.59 -    if (!unparsed_.append(unit))
   27.60 +    PathComponent p(new ScopedRoot<String>(strname), NULL);
   27.61 +
   27.62 +    Local<Importable> importable(zone_);
   27.63 +    if (!zone_->packages()->findOrAdd(package, &p, importable.address()))
   27.64 +        return false;
   27.65 +
   27.66 +    // If we couldn't find anything on the filesystem to match, we error out
   27.67 +    // early.
   27.68 +    if (!importable) {
   27.69 +        zone_->reportError(Message_CannotImportPath, *path);
   27.70          return false;
   27.71 +    }
   27.72 +
   27.73 +    if (importable->isModule()) {
   27.74 +        Local<Module> module(zone_, Module::cast(importable));
   27.75 +        if (!add(module))
   27.76 +            return true;
   27.77 +    } else {
   27.78 +        // nyi
   27.79 +        assert(false);
   27.80 +    }
   27.81  
   27.82      return true;
   27.83  }
   27.84  
   27.85  char *
   27.86 -CompileContext::loadSource(const char *file, size_t *lengthp)
   27.87 +CompileContext::loadSource(Handle<Module> module, size_t *lengthp)
   27.88  {
   27.89      char *bytes = NULL;
   27.90      size_t length;
   27.91  
   27.92 -    FILE *fp = fopen(file, "rb");
   27.93 +    FILE *fp = fopen(module->path()->chars(), "rb");
   27.94      if (!fp) {
   27.95          reportError(SourcePosition(), Message_CantOpenFile);
   27.96          return NULL;
   27.97 @@ -94,12 +125,10 @@
   27.98  bool
   27.99  CompileContext::parse(TranslationUnit *unit)
  27.100  {
  27.101 -    AutoEnterCompileContext enter(*this, unit);
  27.102 -
  27.103      assert(!unit->tree_);
  27.104  
  27.105      size_t length;
  27.106 -    char *source = loadSource(unit->path_, &length);
  27.107 +    char *source = loadSource(unit->module(), &length);
  27.108      if (!source)
  27.109          return false;
  27.110  
  27.111 @@ -110,26 +139,53 @@
  27.112      return true;
  27.113  }
  27.114  
  27.115 -void
  27.116 +bool
  27.117  CompileContext::evaluateImports(TranslationUnit *unit)
  27.118  {
  27.119 -    if (units_.length() > 1)
  27.120 -        return;
  27.121 +    PoolList<ImportStatement *> *imports = unit->tree()->imports();
  27.122 +
  27.123 +    for (size_t i = 0; i < imports->length(); i++) {
  27.124 +        ImportStatement *import = imports->at(i);
  27.125 +
  27.126 +        // Step 1. Crawl the path until we find a valid file to load.
  27.127 +        Local<Importable> obj(zone_);
  27.128 +        Local<Package> package(zone_, unit->module()->parent());
  27.129 +        if (!zone_->packages()->findOrAdd(package, import->path(), obj.address()))
  27.130 +            return false;
  27.131 +        if (!obj) {
  27.132 +            PathComponent *path = import->path();
  27.133 +            while (path->next)
  27.134 +                path = path->next;
  27.135 +            reportError(import->pos(), Message_CannotImportPath, path->name->chars());
  27.136 +            return false;
  27.137 +        }
  27.138  
  27.139 -#if 0
  27.140 -    // For now we hardcode this...
  27.141 -    TranslationUnit *u2 = new (ZONE()->pool()) TranslationUnit();
  27.142 -    u2->path_ = "C:\\Users\\dvander\\jitcraft\\jitcraft-2\\src\\Debug\\wizard.sp";
  27.143 +        // If the object is a package, we will attempt to execute it
  27.144 +        // immediately after resolving imports.
  27.145 +        if (obj->isPackage()) {
  27.146 +            assert(false);
  27.147 +        } else {
  27.148 +            Local<Module> module(zone_, Module::cast(obj));
  27.149 +            if (!add(module))
  27.150 +                return false;
  27.151 +        }
  27.152 +    }
  27.153  
  27.154 -    ImportStatement *stmt = unit->tree()->imports()->at(0)->toImportStatement();
  27.155 -    stmt->setImportSource(u2);
  27.156 +    return true;
  27.157 +}
  27.158  
  27.159 -    if (!u2->dependents_.append(unit))
  27.160 +bool
  27.161 +CompileContext::add(Handle<Module> module)
  27.162 +{
  27.163 +    if (module->compiled())
  27.164 +        return true;
  27.165 +
  27.166 +    TranslationUnit *tu = new (zone_->pool()) TranslationUnit(module);
  27.167 +
  27.168 +    if (!unparsed_.append(tu) || !units_.append(tu))
  27.169          return false;
  27.170  
  27.171 -    if (!addTranslationUnit(u2))
  27.172 -        return false;
  27.173 -#endif
  27.174 +    return true;
  27.175  }
  27.176  
  27.177  bool
  27.178 @@ -165,6 +221,7 @@
  27.179      while (!unparsed_.empty()) {
  27.180          TranslationUnit *unit = unparsed_.popCopy();
  27.181  
  27.182 +        AutoEnterCompileContext enter(*this, unit);
  27.183          if (!parse(unit))
  27.184              continue;
  27.185  
  27.186 @@ -238,7 +295,7 @@
  27.187              if (!unit->errors()->length())
  27.188                  continue;
  27.189  
  27.190 -            reporter->beginCompilationErrors(unit->path_);
  27.191 +            reporter->beginCompilationErrors(unit->module()->path()->chars());
  27.192              for (size_t j = 0; j < unit->errors()->length(); j++) {
  27.193                  const CompileError &error = unit->errors()->at(j);
  27.194                  reporter->reportCompilationError(error.message, error.line, error.col);
  27.195 @@ -285,7 +342,8 @@
  27.196      va_end(ap);
  27.197  }
  27.198  
  27.199 -TranslationUnit::~TranslationUnit()
  27.200 +void
  27.201 +TranslationUnit::destroy()
  27.202  {
  27.203      for (size_t i = 0; i < errors_.length(); i++)
  27.204          FreeErrorMessage(errors_[i].message);
    28.1 --- a/src/compiler/CompileContext.h	Sat Dec 29 00:55:38 2012 -0800
    28.2 +++ b/src/compiler/CompileContext.h	Tue Jan 01 15:34:07 2013 -0800
    28.3 @@ -1,19 +1,19 @@
    28.4  /*
    28.5   * Copyright (C) 2012 David Anderson
    28.6   *
    28.7 - * This file is part of JITCraft.
    28.8 + * This file is part of SourcePawn.
    28.9   *
   28.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   28.11 + * SourcePawn is free software: you can redistribute it and/or modify it under
   28.12   * the terms of the GNU General Public License as published by the Free
   28.13   * Software Foundation, either version 3 of the License, or (at your option)
   28.14   * any later version.
   28.15   * 
   28.16 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   28.17 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   28.18   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   28.19   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   28.20   *
   28.21   * You should have received a copy of the GNU General Public License along with
   28.22 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   28.23 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   28.24   */
   28.25  #ifndef _include_jitcraft_compile_context_h_
   28.26  #define _include_jitcraft_compile_context_h_
   28.27 @@ -24,6 +24,7 @@
   28.28  #include "../PoolAllocator.h"
   28.29  #include "../Handles.h"
   28.30  #include "../Modules.h"
   28.31 +#include "../Packages.h"
   28.32  
   28.33  namespace ke {
   28.34  
   28.35 @@ -54,20 +55,21 @@
   28.36      const char *message;
   28.37  };
   28.38  
   28.39 -struct TranslationUnit
   28.40 +struct TranslationUnit : public PoolObject
   28.41  {
   28.42 -    TranslationUnit()
   28.43 +    TranslationUnit(Handle<Module> module)
   28.44        : tree_(NULL),
   28.45          importScope_(NULL),
   28.46          globalScope_(NULL),
   28.47 +        module_(module),
   28.48          oom_(false),
   28.49          dependencyFailed_(false)
   28.50      {
   28.51      }
   28.52 -    ~TranslationUnit();
   28.53 +    
   28.54 +    void destroy();
   28.55  
   28.56      ParseTree *tree_;
   28.57 -    const char *path_;
   28.58      PoolList<TranslationUnit *> dependents_;
   28.59      ImportScope *importScope_;
   28.60      GlobalScope *globalScope_;
   28.61 @@ -98,6 +100,9 @@
   28.62      GlobalScope *globalScope() const {
   28.63          return globalScope_;
   28.64      }
   28.65 +    Handle<Module> module() {
   28.66 +        return module_;
   28.67 +    }
   28.68  
   28.69      void setDependencyFailed() {
   28.70          dependencyFailed_ = true;
   28.71 @@ -127,16 +132,17 @@
   28.72      TranslationUnit *active_;
   28.73  
   28.74    private:
   28.75 -    char *loadSource(const char *file, size_t *length);
   28.76 +    char *loadSource(Handle<Module> module, size_t *length);
   28.77      bool parse(TranslationUnit *unit);
   28.78 -    void evaluateImports(TranslationUnit *unit);
   28.79 +    bool evaluateImports(TranslationUnit *unit);
   28.80      bool propagateFailure();
   28.81 +    bool add(Handle<Module> module);
   28.82  
   28.83    public:
   28.84      CompileContext(Zone *zone, const char *file);
   28.85      ~CompileContext();
   28.86  
   28.87 -    bool addTranslationUnit(TranslationUnit *unit);
   28.88 +    bool initialize(Handle<Package> package, const char *name);
   28.89      bool compile();
   28.90      void enter(TranslationUnit *unit);
   28.91      void leave();
    29.1 --- a/src/compiler/NameBinding.cpp	Sat Dec 29 00:55:38 2012 -0800
    29.2 +++ b/src/compiler/NameBinding.cpp	Tue Jan 01 15:34:07 2013 -0800
    29.3 @@ -746,6 +746,8 @@
    29.4              // Import every name.
    29.5              assert(false);
    29.6          } else {
    29.7 +            assert(false);
    29.8 +#if 0
    29.9              GlobalScope *other = node->source()->globalScope();
   29.10              Symbol *sym = other->findPublic(node->name());
   29.11              if (!sym) {
   29.12 @@ -753,6 +755,7 @@
   29.13                  return;
   29.14              }
   29.15              link_->scope()->addSymbol(sym);
   29.16 +#endif
   29.17          }
   29.18      }
   29.19  
    30.1 --- a/src/compiler/Parser.cpp	Sat Dec 29 00:55:38 2012 -0800
    30.2 +++ b/src/compiler/Parser.cpp	Tue Jan 01 15:34:07 2013 -0800
    30.3 @@ -221,11 +221,11 @@
    30.4  bool
    30.5  Parser::fullTypeAndName(Expression **type, String **namep, DeclKind kind)
    30.6  {
    30.7 -    // Declaration:
    30.8 -    //   NewDecl ::= Type Ident
    30.9 -    //   OldDecl ::= Label? (Ident | "...")
   30.10 -    //   Type    ::= Ident
   30.11 -    //   Label   ::= Ident ":"
   30.12 +    //   decl    ::= newdecl | olddecl
   30.13 +    //   newdecl ::= Type Ident
   30.14 +    //   olddecl ::= Label? (Ident | "...")
   30.15 +    //   type    ::= Ident
   30.16 +    //   label   ::= Ident ":"
   30.17      //
   30.18      if (match(TOK_LABEL)) {
   30.19          // We something of the form:
   30.20 @@ -650,6 +650,7 @@
   30.21  Statement *
   30.22  Parser::while_()
   30.23  {
   30.24 +    // while ::= "while" "(" expr ")" statement
   30.25      SourcePosition pos = scanner_.begin();
   30.26      scanner_.scan();
   30.27  
   30.28 @@ -677,14 +678,11 @@
   30.29  Statement *
   30.30  Parser::do_()
   30.31  {
   30.32 +    // do ::= "do" block "while" "(" expr ")"
   30.33      SourcePosition pos = scanner_.begin();
   30.34      scanner_.scan();
   30.35  
   30.36 -    Statement *body;
   30.37 -    if (scanner_.peek() == TOK_LBRACE)
   30.38 -        body = block();
   30.39 -    else
   30.40 -        body = localStatement();
   30.41 +    Statement *body = block();
   30.42      if (!body)
   30.43          return NULL;
   30.44  
   30.45 @@ -705,6 +703,10 @@
   30.46  Statement *
   30.47  Parser::switch_()
   30.48  {
   30.49 +    // switch ::= "switch" "(" expr ")" "{" case* defaultcase? "}"
   30.50 +    // case ::= "case" casevals ":" statement
   30.51 +    // defaultcase ::= "default" ":" statement
   30.52 +    //
   30.53      expect(TOK_SWITCH);
   30.54  
   30.55      SourcePosition pos = scanner_.begin();
   30.56 @@ -796,6 +798,12 @@
   30.57  Statement *
   30.58  Parser::forStatement()
   30.59  {
   30.60 +    // for ::= "for" "(" forinit? ";" forcond? ";" forstep ")" statement
   30.61 +    // forint ::= "new" vardecl |
   30.62 +    //            exprstmt
   30.63 +    // forcond ::= expr
   30.64 +    // forstep ::= exprstmt
   30.65 +    //
   30.66      SourcePosition pos = scanner_.begin();
   30.67      scanner_.scan();
   30.68      if (!expect(TOK_LPAREN))
   30.69 @@ -844,6 +852,8 @@
   30.70  ExpressionList *
   30.71  Parser::dimensions()
   30.72  {
   30.73 +    // dimensions ::= ("[" expr? "]")*
   30.74 +
   30.75      ExpressionList *postDimensions = new (pool_) ExpressionList();
   30.76      while (match(TOK_LBRACKET)) {
   30.77          Expression *dim = NULL;
   30.78 @@ -863,9 +873,11 @@
   30.79  VariableDeclaration *
   30.80  Parser::var(TypeQualifiers qual)
   30.81  {
   30.82 +    // vardecl ::= decl ("=" expr)?
   30.83 +
   30.84      Expression *type;
   30.85      Local<String> name(zone_);
   30.86 -    
   30.87 +
   30.88      if (!typeAndName(&type, name.ref()))
   30.89          return NULL;
   30.90  
   30.91 @@ -900,6 +912,8 @@
   30.92  Statement *
   30.93  Parser::vars(TypeQualifiers qual)
   30.94  {
   30.95 +    // localvars ::= ("new" | "const" | "decl") vardecl ("," vardecl)*
   30.96 +    // globalvars ::= ("public" | "const" | "new" | "public" "const") vardecl
   30.97      VariableDeclaration *decl = var(qual);
   30.98      if (!decl)
   30.99          return NULL;
  30.100 @@ -926,6 +940,9 @@
  30.101  Statement *
  30.102  Parser::returnStatement()
  30.103  {
  30.104 +    // return ::= "return" term |
  30.105 +    //            "return" "expr"
  30.106 +
  30.107      SourcePosition pos = scanner_.begin();
  30.108      if (!expect(TOK_RETURN))
  30.109          return NULL;
  30.110 @@ -946,6 +963,7 @@
  30.111  Statement *
  30.112  Parser::expressionStatement()
  30.113  {
  30.114 +    // exprstmt ::= expr
  30.115      Expression *left = assignment();
  30.116      if (!left)
  30.117          return NULL;
  30.118 @@ -956,6 +974,8 @@
  30.119  Statement *
  30.120  Parser::block()
  30.121  {
  30.122 +    // block ::= "{" statement* "}"
  30.123 +
  30.124      if (!expect(TOK_LBRACE))
  30.125          return NULL;
  30.126  
  30.127 @@ -977,8 +997,11 @@
  30.128  Statement *
  30.129  Parser::if_()
  30.130  {
  30.131 +    // if ::= "if" "(" expr ")" statement elseif* else?
  30.132 +    // elseif ::= "elseif" "(" expr ")" statement
  30.133 +    // else ::= "else" statement
  30.134      expect(TOK_IF);
  30.135 -    
  30.136 +  
  30.137      SourcePosition pos = scanner_.begin();
  30.138      if (!expect(TOK_LPAREN))
  30.139          return NULL;
  30.140 @@ -1033,6 +1056,10 @@
  30.141  Statement *
  30.142  Parser::localStatement()
  30.143  {
  30.144 +    // statement ::= stmt term
  30.145 +    // stmt ::= do | for | if | while | struct | enum |
  30.146 +    //          localvars | return | switch | break | continue
  30.147 +
  30.148      Statement *statement = NULL;
  30.149  
  30.150      // Statements which must be followed by a semicolon will break out of the
  30.151 @@ -1115,6 +1142,10 @@
  30.152  Statement *
  30.153  Parser::struct_()
  30.154  {
  30.155 +    // struct ::= "struct" name { struct_fields }
  30.156 +    // struct_fields ::= struct_field |
  30.157 +    //                   struct_field struct_fields
  30.158 +    // struct_field ::= label? name term
  30.159      expect(TOK_STRUCT);
  30.160  
  30.161      Local<String> name(zone_, expectName());
  30.162 @@ -1160,6 +1191,10 @@
  30.163  Statement *
  30.164  Parser::enum_()
  30.165  {
  30.166 +    // enum ::= "enum" name? { enum_members? }
  30.167 +    // enum_members ::= enum_member ","? |
  30.168 +    //                  enum_member "," enum_members
  30.169 +    // enum_member ::= ident ("=" constexpr)?
  30.170      expect(TOK_ENUM);
  30.171  
  30.172      SourcePosition pos = scanner_.begin();
  30.173 @@ -1213,10 +1248,17 @@
  30.174  
  30.175      SourcePosition pos = scanner_.begin();
  30.176  
  30.177 +    // import       ::= import_path ("." "*")?
  30.178 +    // import_path  ::= name |
  30.179 +    //                  name "." import_path
  30.180 +
  30.181      Local<String> name(zone_, expectName());
  30.182 -    if (!name || !names->append(NewScopedRoot<String>(pool_, name)))
  30.183 +    if (!name)
  30.184          return NULL;
  30.185  
  30.186 +    PathComponent *root = new (pool_) PathComponent(NewScopedRoot<String>(pool_, name), NULL);
  30.187 +    PathComponent *current = root;
  30.188 +
  30.189      TokenKind suffix = TOK_NONE;
  30.190      while (match(TOK_DOT)) {
  30.191          if (match(TOK_STAR)) {
  30.192 @@ -1227,11 +1269,11 @@
  30.193          if ((name = expectName()) == NULL)
  30.194              return NULL;
  30.195  
  30.196 -        if (!names->append(NewScopedRoot<String>(pool_, name)))
  30.197 -            return NULL;
  30.198 +        current->next = new (pool_) PathComponent(NewScopedRoot<String>(pool_, name), NULL);
  30.199 +        current = current->next;
  30.200      }
  30.201  
  30.202 -    return new (pool_) ImportStatement(pos, names, suffix);
  30.203 +    return new (pool_) ImportStatement(pos, root, suffix);
  30.204  }
  30.205  
  30.206  Statement *
    31.1 --- a/src/compiler/Scanner.cpp	Sat Dec 29 00:55:38 2012 -0800
    31.2 +++ b/src/compiler/Scanner.cpp	Tue Jan 01 15:34:07 2013 -0800
    31.3 @@ -197,7 +197,7 @@
    31.4          return '\r';
    31.5        case 't':
    31.6          return '\t';
    31.7 -      case '\v':
    31.8 +      case 'v':
    31.9          return '\v';
   31.10  
   31.11        case 'x':
    32.1 --- a/src/compiler/SemanticAnalysis.cpp	Sat Dec 29 00:55:38 2012 -0800
    32.2 +++ b/src/compiler/SemanticAnalysis.cpp	Tue Jan 01 15:34:07 2013 -0800
    32.3 @@ -64,7 +64,6 @@
    32.4      unit_(unit),
    32.5      hir_(NULL),
    32.6      emitter_(pool_),
    32.7 -    module_(NULL),
    32.8      loop_(NULL)
    32.9  {
   32.10  }
   32.11 @@ -77,7 +76,6 @@
   32.12      hir_(NULL),
   32.13      scope_(parent->scope_),
   32.14      emitter_(pool_),
   32.15 -    module_(parent->module_),
   32.16      fun_(fun),
   32.17      loop_(NULL),
   32.18      control_(NULL)
   32.19 @@ -90,8 +88,6 @@
   32.20  {
   32.21      scope_ = unit_->globalScope();
   32.22  
   32.23 -    module_ = Module::New(zone_);
   32.24 -
   32.25      for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
   32.26          Statement *stmt = unit_->tree()->statements()->at(i);
   32.27          stmt->accept(this);
   32.28 @@ -100,19 +96,17 @@
   32.29      Local<Struct> globals(zone_, unit_->globalScope()->build(zone_));
   32.30      if (!globals)
   32.31          return;
   32.32 -    module_->setGlobals(globals);
   32.33 +    unit_->module()->setGlobals(globals);
   32.34  
   32.35      Local<Code> code(zone_, __ finish());
   32.36      if (!code)
   32.37          return;
   32.38 -    code->setModule(module_);
   32.39 -    module_->setCode(code);
   32.40 +    code->setModule(unit_->module());
   32.41 +    unit_->module()->setCode(code);
   32.42  
   32.43  #ifndef NDEBUG
   32.44  //    Disassemble(code, stdout);
   32.45  #endif
   32.46 -
   32.47 -    unit_->module_ = module_;
   32.48  }
   32.49  
   32.50  void
   32.51 @@ -187,7 +181,7 @@
   32.52      Local<Code> code(zone_, __ finish());
   32.53      if (!code)
   32.54          return NULL;
   32.55 -    code->setModule(module_);
   32.56 +    code->setModule(unit_->module());
   32.57  
   32.58      Local<Function> fun(zone_, Function::New(zone_, code, fun_, stmt->name(), stmt->pos()));
   32.59      if (!fun)
   32.60 @@ -909,7 +903,7 @@
   32.61      }
   32.62  
   32.63      // :TODO: remove
   32.64 -    assert(l == r);
   32.65 +    assert(*l == *r);
   32.66  
   32.67      return left->type();
   32.68  }
    33.1 --- a/src/compiler/SemanticAnalysis.h	Sat Dec 29 00:55:38 2012 -0800
    33.2 +++ b/src/compiler/SemanticAnalysis.h	Tue Jan 01 15:34:07 2013 -0800
    33.3 @@ -248,7 +248,6 @@
    33.4      HIR *hir_;
    33.5      Scope *scope_;
    33.6      BytecodeEmitter emitter_;
    33.7 -    ScopedRoot<Module> module_;
    33.8      ScopedRoot<FunctionType> fun_;
    33.9      LoopScope *loop_;
   33.10      ControlScope *control_;
    34.1 --- a/src/jitcraft.vcxproj	Sat Dec 29 00:55:38 2012 -0800
    34.2 +++ b/src/jitcraft.vcxproj	Tue Jan 01 15:34:07 2013 -0800
    34.3 @@ -23,16 +23,19 @@
    34.4    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    34.5      <ConfigurationType>Application</ConfigurationType>
    34.6      <UseDebugLibraries>true</UseDebugLibraries>
    34.7 -    <CharacterSet>Unicode</CharacterSet>
    34.8 +    <CharacterSet>MultiByte</CharacterSet>
    34.9 +    <PlatformToolset>v110</PlatformToolset>
   34.10    </PropertyGroup>
   34.11    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   34.12      <ConfigurationType>Application</ConfigurationType>
   34.13      <UseDebugLibraries>false</UseDebugLibraries>
   34.14      <WholeProgramOptimization>true</WholeProgramOptimization>
   34.15      <CharacterSet>Unicode</CharacterSet>
   34.16 +    <PlatformToolset>v110</PlatformToolset>
   34.17    </PropertyGroup>
   34.18    <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug - Library|Win32'">
   34.19      <ConfigurationType>StaticLibrary</ConfigurationType>
   34.20 +    <PlatformToolset>v110</PlatformToolset>
   34.21    </PropertyGroup>
   34.22    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   34.23    <ImportGroup Label="ExtensionSettings">
   34.24 @@ -60,7 +63,7 @@
   34.25        </PrecompiledHeader>
   34.26        <WarningLevel>Level3</WarningLevel>
   34.27        <Optimization>Disabled</Optimization>
   34.28 -      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions); _CRT_SECURE_NO_WARNINGS;KE_EXPORTING</PreprocessorDefinitions>
   34.29 +      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions); _CRT_SECURE_NO_WARNINGS;KE_EXPORTING;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE</PreprocessorDefinitions>
   34.30      </ClCompile>
   34.31      <Link>
   34.32        <SubSystem>Console</SubSystem>
   34.33 @@ -109,6 +112,7 @@
   34.34      <ClCompile Include="compiler\Symbols.cpp" />
   34.35      <ClCompile Include="Environments.cpp" />
   34.36      <ClCompile Include="Exception.cpp" />
   34.37 +    <ClCompile Include="FileSystem.cpp" />
   34.38      <ClCompile Include="FixedArray.cpp" />
   34.39      <ClCompile Include="Functions.cpp" />
   34.40      <ClCompile Include="GlobalRoots.cpp" />
   34.41 @@ -118,6 +122,7 @@
   34.42      <ClCompile Include="Modules.cpp" />
   34.43      <ClCompile Include="NativeTable.cpp" />
   34.44      <ClCompile Include="Opcodes.cpp" />
   34.45 +    <ClCompile Include="Packages.cpp" />
   34.46      <ClCompile Include="Platform-Windows.cpp" />
   34.47      <ClCompile Include="PoolAllocator.cpp" />
   34.48      <ClCompile Include="Reference.cpp" />
   34.49 @@ -152,6 +157,7 @@
   34.50      <ClInclude Include="compiler\Symbols.h" />
   34.51      <ClInclude Include="compiler\Token.h" />
   34.52      <ClInclude Include="Environments.h" />
   34.53 +    <ClInclude Include="FileSystem.h" />
   34.54      <ClInclude Include="FixedArray.h" />
   34.55      <ClInclude Include="Functions.h" />
   34.56      <ClInclude Include="GlobalRoots.h" />
   34.57 @@ -160,6 +166,7 @@
   34.58      <ClInclude Include="Heap-inl.h" />
   34.59      <ClInclude Include="InlineList.h" />
   34.60      <ClInclude Include="Interpreter.h" />
   34.61 +    <ClInclude Include="List.h" />
   34.62      <ClInclude Include="Messages.h" />
   34.63      <ClInclude Include="Modules.h" />
   34.64      <ClInclude Include="Heap.h" />
   34.65 @@ -167,6 +174,7 @@
   34.66      <ClInclude Include="Objects.h" />
   34.67      <ClInclude Include="ObjectVisitor.h" />
   34.68      <ClInclude Include="Opcodes.h" />
   34.69 +    <ClInclude Include="Packages.h" />
   34.70      <ClInclude Include="Platform.h" />
   34.71      <ClInclude Include="PoolAllocator.h" />
   34.72      <ClInclude Include="Handles.h" />
    35.1 --- a/src/jitcraft.vcxproj.filters	Sat Dec 29 00:55:38 2012 -0800
    35.2 +++ b/src/jitcraft.vcxproj.filters	Tue Jan 01 15:34:07 2013 -0800
    35.3 @@ -109,6 +109,12 @@
    35.4      <ClCompile Include="compiler\ConstantEvaluator.cpp">
    35.5        <Filter>Source Files\compiler</Filter>
    35.6      </ClCompile>
    35.7 +    <ClCompile Include="Packages.cpp">
    35.8 +      <Filter>Source Files</Filter>
    35.9 +    </ClCompile>
   35.10 +    <ClCompile Include="FileSystem.cpp">
   35.11 +      <Filter>Source Files</Filter>
   35.12 +    </ClCompile>
   35.13    </ItemGroup>
   35.14    <ItemGroup>
   35.15      <ClInclude Include="Handles-inl.h">
   35.16 @@ -273,6 +279,15 @@
   35.17      <ClInclude Include="VirtualObjectVisitor.h">
   35.18        <Filter>Header Files\vm</Filter>
   35.19      </ClInclude>
   35.20 +    <ClInclude Include="Packages.h">
   35.21 +      <Filter>Header Files\vm</Filter>
   35.22 +    </ClInclude>
   35.23 +    <ClInclude Include="FileSystem.h">
   35.24 +      <Filter>Header Files\vm</Filter>
   35.25 +    </ClInclude>
   35.26 +    <ClInclude Include="List.h">
   35.27 +      <Filter>Header Files\vm</Filter>
   35.28 +    </ClInclude>
   35.29    </ItemGroup>
   35.30    <ItemGroup>
   35.31      <None Include="Messages.tbl">
    36.1 --- a/src/main.cpp	Sat Dec 29 00:55:38 2012 -0800
    36.2 +++ b/src/main.cpp	Tue Jan 01 15:34:07 2013 -0800
    36.3 @@ -20,6 +20,14 @@
    36.4  #include <stdlib.h>
    36.5  #include <string.h>
    36.6  #include "../include/keima.h"
    36.7 +#include "Utility.h"
    36.8 +#include "Platform.h"
    36.9 +#ifdef WIN32
   36.10 +# include <Windows.h>
   36.11 +# include <direct.h>
   36.12 +#else
   36.13 +# include <unistd.h>
   36.14 +#endif
   36.15  
   36.16  using namespace Ke;
   36.17  
   36.18 @@ -34,11 +42,22 @@
   36.19  
   36.20          IStackFrameIterator *iter = Keima::NewStackFrameIterator();
   36.21          unsigned index = 0;
   36.22 +
   36.23 +        const char *filename = iter->source();
   36.24 +        if (!filename)
   36.25 +            filename = "<anonymous>";
   36.26 +        if (const char *tail = strrchr(filename, '/'))
   36.27 +            filename = tail + 1;
   36.28 +#ifdef WIN32
   36.29 +        if (const char *tail = strrchr(filename, '\\'))
   36.30 +            filename = tail + 1;
   36.31 +#endif
   36.32 +
   36.33          while (!iter->done() && index < 10) {
   36.34              fprintf(stderr, "[%d] %s (%s line %d)\n",
   36.35                      index,
   36.36                      iter->function(),
   36.37 -                    iter->source(),
   36.38 +                    filename,
   36.39                      iter->lineNumber());
   36.40              iter->prev();
   36.41              index++;
   36.42 @@ -107,6 +126,14 @@
   36.43      if (!Keima::Initialize())
   36.44          return 1;
   36.45  
   36.46 +    ke::AutoFree<char> fullpath;
   36.47 +    if (!ke::OS::GetAbsolutePath(argv[1], fullpath))
   36.48 +        return 1;
   36.49 +
   36.50 +    ke::AutoFree<char> path, name;
   36.51 +    if (!ke::OS::SplitPath(*fullpath, path, name))
   36.52 +        return 1;
   36.53 +
   36.54      int rval = 0;
   36.55  
   36.56      Keima::InstallMessageReporter(&s_Reporter);
   36.57 @@ -115,7 +142,13 @@
   36.58          Keima::SetPublicFunctionListener(&entry);
   36.59  
   36.60          HandleScope scope;
   36.61 -        if (!Compile(argv[1])) {
   36.62 +        Local<Package> package = Package::New(Handle<Package>(), Handle<String>(), *path, Package::Normal);
   36.63 +        if (!package) {
   36.64 +            rval = 1;
   36.65 +            break;
   36.66 +        }
   36.67 +
   36.68 +        if (!Keima::Compile(package, *name)) {
   36.69              rval = 1;
   36.70              break;
   36.71          }
    37.1 --- a/tests/basic/divide-by-zero.err	Sat Dec 29 00:55:38 2012 -0800
    37.2 +++ b/tests/basic/divide-by-zero.err	Tue Jan 01 15:34:07 2013 -0800
    37.3 @@ -1,3 +1,3 @@
    37.4  Uncaught exception: integer divide by zero
    37.5 -[0] f ((anonymous) line 1)
    37.6 -[1] main ((anonymous) line 3)
    37.7 +[0] f (divide-by-zero.sp line 1)
    37.8 +[1] main (divide-by-zero.sp line 3)
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/tests/basic/import-sysroot-all.sp	Tue Jan 01 15:34:07 2013 -0800
    38.3 @@ -0,0 +1,9 @@
    38.4 +import shell.*;
    38.5 +
    38.6 +public main()
    38.7 +{
    38.8 +    PrintNum(5);
    38.9 +    PrintString(" is ");
   38.10 +    PrintFloat(5.0);
   38.11 +}
   38.12 +
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/tests/basic/import-sysroot-select.sp	Tue Jan 01 15:34:07 2013 -0800
    39.3 @@ -0,0 +1,11 @@
    39.4 +import shell;
    39.5 +import shell;
    39.6 +import shell;
    39.7 +
    39.8 +public main()
    39.9 +{
   39.10 +    shell.PrintNum(5);
   39.11 +    shell.PrintString(" is ");
   39.12 +    shell.PrintFloat(5.0);
   39.13 +}
   39.14 +
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/tests/shell.sp	Tue Jan 01 15:34:07 2013 -0800
    40.3 @@ -0,0 +1,5 @@
    40.4 +native PrintNum(num);
    40.5 +
    40.6 +native PrintString(const char:text[]);
    40.7 +
    40.8 +native PrintFloat(float:f);