Massive SemA/BC refactoring to support better type systems. Read on for more.
authorDavid Anderson <dvander@alliedmods.net>
Sat Nov 17 18:41:01 2012 -0800 (2012-11-17)
changeset 195c1ba166f3fc4
parent 194 b029d63565a2
child 196 9904633b1dfc
Massive SemA/BC refactoring to support better type systems. Read on for more.

The previous compiler had a simple pipeline, best outlined as:
(1) Parsing and name binding -> AST
(2) Storage allocation -> AST
(3) Semantic Analysis (SemA) -> AST
(4) Bytecode Compilation (BC) -> Code

This pipeline, unfortunately, had two problems. First, name binding cannot be performed in one pass if we wish to have multi-file support in the form of modules. Name binding must be two-pass.

Second, because SemA was only capable of annotating AST nodes with a single type, most coercion work had to be duplicated in the BC phase, as coercion was not explicit in the SemA output. This made introducing new type rules extremely difficult, and all but precluded concepts like operator overloading (or overloading at all).

This patch rewrites most of Keima's backend. Of interest are the following changes:
(1) CompileContext has been refactored around future multi-file support.
(2) Parsing no longer performs any name binding.
(3) The grammar for type-and-name has been changed from:
(Label | Identifier)? Identifier
to:
Type? Identifier
where:
Type ::= OldType | NewType
OldType ::= Label
NewType ::= Identifier (. NewType)*


Although we do not implement the full production for Type yet, this
distinction is important. A type identifier is now affixed to the AST
as an Expression (right now, always a NameProxy), so it can fully
participate in name binding.

(4) Immediately after parsing, the AST goes through a NamePopulation phase.
This phase creates Scope objects for every scope which declares a name,
and if those names are declaring types or functions, a Symbol is created
and entered into the scope. Symbols entirely replace the old BoundName
classes.

(5) After NamePopulation comes NameBinding. This phase performs three steps:
(a) Links Scope objects together, to form a tree.
(b) Binds any free name to an existing name in the scope chain.
(c) Creates and registers any Symbols for names which have not yet been
added to the scope (for example, local variables).

In accordance, all "allocation" and "binding" concepts have been removed
from Scopes, which are now lightweight container classes.

(6) SemA now generates bytecode for each statement in the AST. Expression
compilation is performed via a separate mechanism called HIR (High-level
Intermediate Representation). To analyze an expression, SemA will walk
the AST, and produce a HIR object for each node. HIR is typed, and SemA
may insert coercion nodes, or even expand an AST node into multiple HIR
nodes. The result of evaluating an expression in SemA is therefore the
the root of a HIR tree, which SemA then sends to the HIRTranslator, which
performs bytecode generation.

As before, SemA still performs full semantic analysis. However, not it
also produces each function's bytecode.

This split allows us to decompose potentially complex semantics into
a more fine-grained, AST-like structure, which can have very simple
code-generation logic. For example, (1.0 + 5) might look like:

HAdd(HFloat(1.0), HConvert(HInteger(5), <Float>))

As part of this decomposition, many opcodes have been removed. Rather than
using typed jumps, we now expand jumps into longer tests. For example:
jge.f <label>
becomes:
ge.f
cvt.f2b
jt <label>

This simplifies the pipeline, and JITs should be able to melt the added
work away.

HIR is not used at a statement level, and HIR does not have any concept
of control-flow.

(7) The old BytecodeCompiler has been removed, as its work is now split
between SemA and HIRTranslator.


In addition, some minor refactorings have taken place:

(1) Opcodes.tbl no longer hardcodes numbers (aaah).
(2) Type has been split into smaller, typed structs.
(3) BytecodeEmitter no longer relies on Pools or RootScopes.
(4) SemA is now responsible for variable/storage allocation.
(5) Native table are now global, rather than per-module. As such, native
declarations now result in a Native object (which still requires a
CALLNATIVE opcode), which is an index into the global table. Natives
must be bound globally. This is in preparation for module support.
(6) Publics are no longer tracked, but rather registered via a global
callback upon module load. This callback can be set by embedders. This
is in preparation for multi-file support.
(7) The BytecodeEmitter now performs Symbol allocations itself, and it
also generates Code objects itself, which removes a good deal of
complexity.

Finally, a test harness has been added. This harness is a python script which finds *.test files, recursively, in the tests folder. For each file it runs the corresponding .sp. The contents of the .test file must match stdout+stderr.
include/keima.h
include/keima_util.h
src/API.cpp
src/AST.h
src/BytecodeCompiler.cpp
src/BytecodeCompiler.h
src/BytecodeEmitter.cpp
src/BytecodeEmitter.h
src/Code.h
src/CompileContext.cpp
src/CompileContext.h
src/Environments.cpp
src/Functions.cpp
src/Functions.h
src/GlobalRoots.cpp
src/GlobalRoots.h
src/Handles.h
src/HashTable.h
src/Interpreter.cpp
src/Messages.tbl
src/Modules.cpp
src/Modules.h
src/NameBinding.cpp
src/NameBinding.h
src/NativeTable.cpp
src/NativeTable.h
src/ObjectVisitor.h
src/Objects.h
src/OldByCo.cpp
src/OldByCo.h
src/OldSema.cpp
src/OldSema.h
src/Opcodes.cpp
src/Opcodes.h
src/Opcodes.tbl
src/Parser.cpp
src/Parser.h
src/PoolAllocator.cpp
src/PoolAllocator.h
src/QualType.h
src/Reference.cpp
src/Reference.h
src/Scanner.cpp
src/Scanner.h
src/Scopes.cpp
src/Scopes.h
src/SemanticAnalysis.cpp
src/SemanticAnalysis.h
src/Stack.cpp
src/StringPool.h
src/Strings.h
src/Structures.cpp
src/Structures.h
src/Token.h
src/TypeManager.cpp
src/TypeManager.h
src/Types.cpp
src/Types.h
src/Utility.h
src/Vector.h
src/VirtualObjectVisitor.h
src/Zone.cpp
src/Zone.h
src/comment
src/compiler/AST.h
src/compiler/BytecodeEmitter.cpp
src/compiler/BytecodeEmitter.h
src/compiler/CompileContext.cpp
src/compiler/CompileContext.h
src/compiler/HIR.cpp
src/compiler/HIR.h
src/compiler/NameBinding.cpp
src/compiler/NameBinding.h
src/compiler/Parser.cpp
src/compiler/Parser.h
src/compiler/Scanner.cpp
src/compiler/Scanner.h
src/compiler/Scopes.cpp
src/compiler/Scopes.h
src/compiler/SemanticAnalysis.cpp
src/compiler/SemanticAnalysis.h
src/compiler/Symbols.cpp
src/compiler/Symbols.h
src/compiler/Token.h
src/jitcraft.vcxproj
src/main.cpp
tests/basic/floats.out
tests/basic/floats.sp
tests/display.py
tests/harness.py
tests/prototype/floats.sp
tests/test.py
     1.1 --- a/include/keima.h	Mon Sep 17 00:10:01 2012 -0700
     1.2 +++ b/include/keima.h	Sat Nov 17 18:41:01 2012 -0800
     1.3 @@ -43,6 +43,7 @@
     1.4  template <typename T>
     1.5  class Handle
     1.6  {
     1.7 +    template <typename S> friend class Root;
     1.8    protected:
     1.9      template <typename S> void typeCheck() {
    1.10          while (false) {
    1.11 @@ -111,46 +112,45 @@
    1.12  };
    1.13  
    1.14  /*
    1.15 - * A non-local variable that outlives HandleScopes. A Root is reference-
    1.16 - * counted. When its reference count reaches 0, the Root is removed.
    1.17 + * A non-local variable that outlives HandleScopes. Unlike Local, a Root
    1.18 + * actually represents a rooted location. Roots must be allocated and
    1.19 + * disposed, and assignment to a root changes its contained object, not
    1.20 + * the location of the object.
    1.21   */
    1.22  template <typename T>
    1.23 -class Root : public Handle<T>
    1.24 +class Root
    1.25  {
    1.26    public:
    1.27 -    Root<T>()
    1.28 -      : Handle<T>()
    1.29 +    Root()
    1.30 +      : root_(NULL)
    1.31      {
    1.32      }
    1.33  
    1.34 -    Root<T>(const Root<T> &other)
    1.35 -      : Handle<T>(reinterpret_cast<T *>(*other))
    1.36 +    Root(Handle<T> other)
    1.37 +      : root_(NULL)
    1.38      {
    1.39 -        incref();
    1.40 +        set(other);
    1.41      }
    1.42  
    1.43 -    explicit Root(ke::HeapRoot *obj)
    1.44 -      : Handle<T>(reinterpret_cast<T *>(obj))
    1.45 -    {
    1.46 -incref();
    1.47 +    inline ~Root();
    1.48 +
    1.49 +    operator const Handle<T>() const {
    1.50 +        return obj_;
    1.51      }
    1.52  
    1.53 -    static inline Root<T> New(Handle<T> other);
    1.54 -
    1.55 -    ~Root() {
    1.56 -        decref();
    1.57 +    bool operator ==(Handle<T> other) {
    1.58 +        return Handle<T>(*this) == other;
    1.59      }
    1.60 -
    1.61 -    Root<T> &operator =(const Root<T> &other) {
    1.62 -        decref();
    1.63 -        this->obj_ = other.obj_;
    1.64 -        incref();
    1.65 +    Root<T> &operator =(Handle<T> other) {
    1.66 +        set(other);
    1.67          return *this;
    1.68      }
    1.69  
    1.70    private:
    1.71 -    void incref();
    1.72 -    void decref();
    1.73 +    void set(Handle<T> other);
    1.74 +
    1.75 +    ke::HeapRoot *root_;
    1.76 +    Handle<T> obj_;
    1.77  };
    1.78  
    1.79  /*
    1.80 @@ -211,7 +211,8 @@
    1.81  class IStackFrameIterator
    1.82  {
    1.83    public:
    1.84 -    virtual ~IStackFrameIterator() { }
    1.85 +    virtual ~IStackFrameIterator() {
    1.86 +    }
    1.87  
    1.88      // Returns true if there are more frames, false otherwise.
    1.89      virtual bool done() = 0;
    1.90 @@ -232,6 +233,20 @@
    1.91      virtual void prev() = 0;
    1.92  };
    1.93  
    1.94 +// Listener interface for when public functions are registered or unregisted.
    1.95 +class IPublicFunctionListener
    1.96 +{
    1.97 +  public:
    1.98 +    virtual ~IPublicFunctionListener() {
    1.99 +    }
   1.100 +
   1.101 +    // Called when a public function becomes available to the runtime.
   1.102 +    virtual void registerPublic(Handle<Function> fun) = 0;
   1.103 +
   1.104 +    // Called when a public is no longer available to the runtime.
   1.105 +    virtual void unregisterPublic(Handle<Function> fun) = 0;
   1.106 +};
   1.107 +
   1.108  // A string is an immutable UTF8 buffer.
   1.109  class KE_EXPORT String
   1.110  {
   1.111 @@ -253,21 +268,6 @@
   1.112      Local<String> name();
   1.113  };
   1.114  
   1.115 -// A native is an ISourcePawnEngine-compatible function provided by C++.
   1.116 -class KE_EXPORT Native
   1.117 -{
   1.118 -  public:
   1.119 -    // Returns the name of a native, which is never NULL. The string is
   1.120 -    // guaranteed to be interned.
   1.121 -    Local<String> name();
   1.122 -
   1.123 -    // Returns the function pointer of the native.
   1.124 -    void *function();
   1.125 -
   1.126 -    // Sets the function pointer of the native.
   1.127 -    void bind(void *function);
   1.128 -};
   1.129 -
   1.130  // A pubvar is an ISourcePawnEngine-compatible structure that holds information
   1.131  // about public variables.
   1.132  class KE_EXPORT Pubvar
   1.133 @@ -283,21 +283,9 @@
   1.134  class KE_EXPORT Module
   1.135  {
   1.136    public:
   1.137 -    // Returns publics that are based on forwards.
   1.138 -    unsigned numPublics();
   1.139 -    Local<Function> getPublic(unsigned index);
   1.140 -
   1.141 -    // Returns natives.
   1.142 -    unsigned numNatives();
   1.143 -    Local<Native> getNative(unsigned index);
   1.144 -
   1.145      // Sets the native identity pointer, which is passed as the first argument
   1.146      // to natives.
   1.147      void setNativeIdentity(void *ptr);
   1.148 -
   1.149 -    // Returns the number of public variables.
   1.150 -    unsigned numPubvars();
   1.151 -    Local<Pubvar> getPubvar(unsigned index);
   1.152  };
   1.153  
   1.154  class Keima
   1.155 @@ -346,7 +334,23 @@
   1.156       */
   1.157      static void InstallMessageReporter(IMessageReporter *reporter);
   1.158  
   1.159 +    /* Returns a new stack frame iterator object. */
   1.160      static IStackFrameIterator *NewStackFrameIterator();
   1.161 +
   1.162 +    /*
   1.163 +     * Binds a native, by name, to an address. Natives are an ISPE1 concept
   1.164 +     * (originally from Pawn/Small's AMX API). In SourceMod 1, natives were
   1.165 +     * registered globally, but bound to plugins individually. We roughly
   1.166 +     * preserve that functionality here, by allowing host applications to
   1.167 +     * give us the name -> address mappings.
   1.168 +     *
   1.169 +     * Natives can be rebound or unbound any number of times. This function
   1.170 +     * fails if there is not enough memory.
   1.171 +     */
   1.172 +    static bool BindNative(const char *name, void *address);
   1.173 +
   1.174 +    /* Sets the object that will listen for public functions. */
   1.175 +    static void SetPublicFunctionListener(IPublicFunctionListener *listener);
   1.176  };
   1.177  
   1.178  /*
   1.179 @@ -470,38 +474,38 @@
   1.180      template <typename T> friend class Root;
   1.181  
   1.182    private:
   1.183 -    static ke::HeapRoot *NewHeapRoot(ke::Object **objp);
   1.184 -    static void IncRef(ke::HeapRoot *root);
   1.185 -    static void DecRef(ke::HeapRoot *root);
   1.186 +    static ke::HeapRoot *NewHeapRoot();
   1.187 +    static void Destroy(ke::HeapRoot *root);
   1.188  };
   1.189  
   1.190 -template <typename T> Root<T>
   1.191 -Root<T>::New(Handle<T> other)
   1.192 -{
   1.193 -    if (!other)
   1.194 -        return Root<T>();
   1.195 -    ke::Object **ptr = reinterpret_cast<ke::Object **>(*other);
   1.196 -    return Root<T>(Internals::NewHeapRoot(ptr));
   1.197 -}
   1.198 -
   1.199  template <typename T> void
   1.200 -Root<T>::incref()
   1.201 +Root<T>::set(Handle<T> other)
   1.202  {
   1.203 -    if (!*this)
   1.204 +    if (!other) {
   1.205 +        obj_ = other;
   1.206          return;
   1.207 -    ke::HeapRoot *ptr = reinterpret_cast<ke::HeapRoot *>(**this);
   1.208 -    Internals::IncRef(ptr);
   1.209 +    }
   1.210 +
   1.211 +    ke::Object **ptr = reinterpret_cast<ke::Object **>(*other);
   1.212 +    if (!root_) {
   1.213 +        root_ = Internals::NewHeapRoot();
   1.214 +        if (!root_)
   1.215 +            return;
   1.216 +    }
   1.217 +
   1.218 +    *reinterpret_cast<ke::Object **>(root_) = *ptr;
   1.219 +    obj_.obj_ = reinterpret_cast<T *>(root_);
   1.220  }
   1.221  
   1.222 -template <typename T> void
   1.223 -Root<T>::decref()
   1.224 +template <typename T>
   1.225 +Root<T>::~Root()
   1.226  {
   1.227 -    if (!*this)
   1.228 +    if (!root_)
   1.229          return;
   1.230 -    ke::HeapRoot *ptr = reinterpret_cast<ke::HeapRoot *>(**this);
   1.231 -    Internals::DecRef(ptr);
   1.232 +    Internals::Destroy(root_);
   1.233  }
   1.234  
   1.235 +
   1.236  }
   1.237  
   1.238  #endif // _include_sourcepawn2_api_h_
     2.1 --- a/include/keima_util.h	Mon Sep 17 00:10:01 2012 -0700
     2.2 +++ b/include/keima_util.h	Sat Nov 17 18:41:01 2012 -0800
     2.3 @@ -1,4 +1,5 @@
     2.4 -/*
     2.5 +/* vim: set ts=4 sw=4 tw=99 et:
     2.6 + *
     2.7   * Copyright (C) 2004-2012 David Anderson
     2.8   *
     2.9   * This file is part of SourcePawn.
    2.10 @@ -26,6 +27,23 @@
    2.11  # endif
    2.12  #endif
    2.13  
    2.14 +// 64-bit detection.
    2.15 +#if defined(_M_X64) || defined(__64bit__)
    2.16 +# define KE_64BIT
    2.17 +#endif
    2.18 +
    2.19 +// 32-bit detection.
    2.20 +#if defined(_M_IX86) || defined(__i386__)
    2.21 +# if defined KE_64BIT
    2.22 +#  error "Detected 32-bit and 64-bit!"
    2.23 +# endif
    2.24 +# define KE_32BIT
    2.25 +#endif
    2.26 +
    2.27 +#if !defined(KE_32BIT) && !defined(KE_64BIT)
    2.28 +# error "Could not detect CPU type"
    2.29 +#endif
    2.30 +
    2.31  #if !defined(KE_EXPORT)
    2.32  # define KE_EXPORT
    2.33  #endif
     3.1 --- a/src/API.cpp	Mon Sep 17 00:10:01 2012 -0700
     3.2 +++ b/src/API.cpp	Sat Nov 17 18:41:01 2012 -0800
     3.3 @@ -20,11 +20,7 @@
     3.4  #include "../include/keima.h"
     3.5  #include "Zone.h"
     3.6  #include "RootScopes.h"
     3.7 -#include "CompileContext.h"
     3.8 -#include "Parser.h"
     3.9 -#include "Scopes.h"
    3.10 -#include "SemanticAnalysis.h"
    3.11 -#include "BytecodeCompiler.h"
    3.12 +#include "compiler/CompileContext.h"
    3.13  #include "Modules.h"
    3.14  #include "GlobalRoots.h"
    3.15  #include "Reference.h"
    3.16 @@ -32,6 +28,7 @@
    3.17  #include "Interpreter.h"
    3.18  #include "Stack.h"
    3.19  #include "Strings.h"
    3.20 +#include "NativeTable.h"
    3.21  #include "Spaces-inl.h"
    3.22  #include "Heap-inl.h"
    3.23  
    3.24 @@ -94,76 +91,25 @@
    3.25      return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
    3.26  }
    3.27  
    3.28 -static ke::Module *
    3.29 -CompileFromSource(CompileContext &cc, const char *path, const char *stream, size_t length)
    3.30 -{
    3.31 -    Parser parser(ZONE(), cc, stream, length);
    3.32 -    ParseTree *tree = parser.parse();
    3.33 -    if (!tree)
    3.34 -        return NULL;
    3.35 -    tree->dump(stdout);
    3.36 -
    3.37 -    if (!Scope::Bind(cc, tree))
    3.38 -        return NULL;
    3.39 -
    3.40 -    SemanticAnalysis semantics(ZONE(), cc, tree);
    3.41 -    if (!semantics.analyze())
    3.42 -        return NULL;
    3.43 -
    3.44 -    Scope::Allocate(tree);
    3.45 -
    3.46 -    BytecodeCompiler compiler(ZONE(), tree, NULL);
    3.47 -    ke::Local<Module> module(ke::ZONE(), compiler.compile());
    3.48 -    if (!module)
    3.49 -        return NULL;
    3.50 -
    3.51 -    ke::InvokeArgs args;
    3.52 -    if (!ke::ZONE()->stack().pushModuleFrame(module, args))
    3.53 -        return NULL;
    3.54 -    if (!ke::Interpret(ke::ZONE(), NULL, NULL))
    3.55 -        return NULL;
    3.56 -
    3.57 -    return module;
    3.58 -}
    3.59 -
    3.60  ke::Module *
    3.61  InternalCompile(const char *path)
    3.62  {
    3.63 +    PoolScope poolScope(ZONE()->pool());
    3.64      RootScope roots(ZONE());
    3.65      CompileContext cc(ZONE(), path);
    3.66  
    3.67 -    char *bytes = NULL;
    3.68 -    size_t length;
    3.69 -    {
    3.70 -        FILE *fp = fopen(path, "rb");
    3.71 -        if (!fp) {
    3.72 -            cc.reportError(SourcePosition(), Message_CantOpenFile);
    3.73 -            return NULL;
    3.74 -        }
    3.75 +    TranslationUnit *unit = new (ZONE()->pool()) TranslationUnit();
    3.76 +    unit->path_ = path;
    3.77 +
    3.78 +    if (!cc.addTranslationUnit(unit))
    3.79 +        return NULL;
    3.80  
    3.81 -        if (fseek(fp, 0, SEEK_END)) {
    3.82 -            cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
    3.83 -            fclose(fp);
    3.84 -            return NULL;
    3.85 -        }
    3.86 -        long size = ftell(fp);
    3.87 -        if (size < 0) {
    3.88 -            cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
    3.89 -            fclose(fp);
    3.90 -            return NULL;
    3.91 -        }
    3.92 -        rewind(fp);
    3.93 -        length = size_t(size);
    3.94 -        bytes = new char[length + 1];
    3.95 -        if (fread(bytes, 1, length, fp) != length) {
    3.96 -            cc.reportError(SourcePosition(), Message_ErrorReadingFile);
    3.97 -            fclose(fp);
    3.98 -            delete [] bytes;
    3.99 -            return NULL;
   3.100 -        }
   3.101 -        fclose(fp);
   3.102 -    }
   3.103 +    if (!cc.compile())
   3.104 +        return NULL;
   3.105  
   3.106 +    return NULL;
   3.107 +
   3.108 +#if 0
   3.109      ke::Local<ke::Module> module(ZONE(),  CompileFromSource(cc, path, bytes, length));
   3.110      delete [] bytes;
   3.111      if (!module)
   3.112 @@ -175,6 +121,8 @@
   3.113  
   3.114      module->setPath(pathstr);
   3.115      return module;
   3.116 +#endif
   3.117 +    return NULL;
   3.118  }
   3.119  
   3.120  // This is split out from InternalCompile so the RootScope doesn't conflict
   3.121 @@ -238,10 +186,9 @@
   3.122  }
   3.123  
   3.124  ke::HeapRoot *
   3.125 -Ke::Internals::NewHeapRoot(ke::Object **ptr)
   3.126 +Ke::Internals::NewHeapRoot()
   3.127  {
   3.128 -    ke::Local<ke::Object> obj(ZONE(), *ptr);
   3.129 -    ke::HeapRoot *root = ke::ZONE()->globalRoots()->create(obj);
   3.130 +    ke::HeapRoot *root = ke::ZONE()->globalRoots()->create();
   3.131      if (!root)
   3.132          return NULL;
   3.133  
   3.134 @@ -250,15 +197,9 @@
   3.135  }
   3.136  
   3.137  void
   3.138 -Ke::Internals::IncRef(ke::HeapRoot *root)
   3.139 +Ke::Internals::Destroy(ke::HeapRoot *root)
   3.140  {
   3.141 -    ZONE()->globalRoots()->incref(FromAPI(root));
   3.142 -}
   3.143 -
   3.144 -void
   3.145 -Ke::Internals::DecRef(ke::HeapRoot *root)
   3.146 -{
   3.147 -    ZONE()->globalRoots()->decref(FromAPI(root));
   3.148 +    ZONE()->globalRoots()->destroy(FromAPI(root));
   3.149  }
   3.150  
   3.151  bool
   3.152 @@ -280,40 +221,6 @@
   3.153      ke::ZONE()->clearPendingException();
   3.154  }
   3.155  
   3.156 -unsigned
   3.157 -Ke::Module::numPublics()
   3.158 -{
   3.159 -    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   3.160 -    if (!module->publics())
   3.161 -        return 0;
   3.162 -    return module->publics()->length();
   3.163 -}
   3.164 -
   3.165 -Ke::Local<Ke::Function>
   3.166 -Ke::Module::getPublic(unsigned index)
   3.167 -{
   3.168 -    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   3.169 -    ke::Local<ke::Function> fun(ke::ZONE(), ke::Function::cast(module->publics()->at(index)));
   3.170 -    return ToLocal<ke::Function, Ke::Function>(fun);
   3.171 -}
   3.172 -
   3.173 -unsigned
   3.174 -Ke::Module::numNatives()
   3.175 -{
   3.176 -    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   3.177 -    if (!module->natives())
   3.178 -        return 0;
   3.179 -    return module->natives()->length();
   3.180 -}
   3.181 -
   3.182 -Ke::Local<Ke::Native>
   3.183 -Ke::Module::getNative(unsigned index)
   3.184 -{
   3.185 -    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   3.186 -    ke::Local<ke::Native> fun(ke::ZONE(), ke::Native::cast(module->natives()->at(index)));
   3.187 -    return ToLocal<ke::Native, Ke::Native>(fun);
   3.188 -}
   3.189 -
   3.190  void
   3.191  Ke::Module::setNativeIdentity(void *identity)
   3.192  {
   3.193 @@ -342,20 +249,6 @@
   3.194      return ToLocal<ke::String, Ke::String>(fun->name());
   3.195  }
   3.196  
   3.197 -Ke::Local<Ke::String>
   3.198 -Ke::Native::name()
   3.199 -{
   3.200 -    ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
   3.201 -    return ToLocal<ke::String, Ke::String>(native->name());
   3.202 -}
   3.203 -
   3.204 -void
   3.205 -Ke::Native::bind(void *function)
   3.206 -{
   3.207 -    ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
   3.208 -    native->bind(function);
   3.209 -}
   3.210 -
   3.211  static inline const char *
   3.212  GetInvokeTypeName(Ke::Parameter::Type type)
   3.213  {
   3.214 @@ -535,3 +428,25 @@
   3.215      *retval = result.i32;
   3.216      return true;
   3.217  }
   3.218 +
   3.219 +bool
   3.220 +Ke::Keima::BindNative(const char *name, void *address)
   3.221 +{
   3.222 +    return ke::ZONE()->nativeTable()->bind(name, address);
   3.223 +}
   3.224 +
   3.225 +void
   3.226 +Ke::Keima::SetPublicFunctionListener(IPublicFunctionListener *listener)
   3.227 +{
   3.228 +    ke::ZONE()->setPublicFunctionListener(listener);
   3.229 +}
   3.230 +
   3.231 +void
   3.232 +Zone::registerPublic(ke::Handle<Function> fun)
   3.233 +{
   3.234 +    if (!publicFunctionListener_)
   3.235 +        return;
   3.236 +
   3.237 +    Ke::Local<Ke::Function> local = ToLocal<ke::Function, Ke::Function>(fun);
   3.238 +    publicFunctionListener_->registerPublic(local);
   3.239 +}
     4.1 --- a/src/AST.h	Mon Sep 17 00:10:01 2012 -0700
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,1171 +0,0 @@
     4.4 -/* vim: set ts=4 sw=4 tw=99 et:
     4.5 - *
     4.6 - * Copyright (C) 2012 David Anderson
     4.7 - *
     4.8 - * This file is part of SourcePawn.
     4.9 - *
    4.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
    4.11 - * the terms of the GNU General Public License as published by the Free
    4.12 - * Software Foundation, either version 3 of the License, or (at your option)
    4.13 - * any later version.
    4.14 - * 
    4.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    4.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    4.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    4.18 - *
    4.19 - * You should have received a copy of the GNU General Public License along with
    4.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
    4.21 - */
    4.22 -#ifndef _include_sourcepawn_ast_h_
    4.23 -#define _include_sourcepawn_ast_h_
    4.24 -
    4.25 -#include "PoolAllocator.h"
    4.26 -#include "Token.h"
    4.27 -#include "NameBinding.h"
    4.28 -#include "Vector.h"
    4.29 -
    4.30 -namespace ke {
    4.31 -
    4.32 -#define ASTKINDS(_)             \
    4.33 -    _(VariableDeclaration)      \
    4.34 -    _(ForStatement)             \
    4.35 -    _(ReturnStatement)          \
    4.36 -    _(IntegerLiteral)           \
    4.37 -    _(FloatLiteral)             \
    4.38 -    _(StringLiteral)            \
    4.39 -    _(BinaryExpression)         \
    4.40 -    _(BlockStatement)           \
    4.41 -    _(Assignment)               \
    4.42 -    _(NameProxy)                \
    4.43 -    _(ExpressionStatement)      \
    4.44 -    _(FunctionStatement)        \
    4.45 -    _(CallExpression)           \
    4.46 -    _(IfStatement)              \
    4.47 -    _(IndexExpression)          \
    4.48 -    _(FieldExpression)          \
    4.49 -    _(EnumStatement)            \
    4.50 -    _(WhileStatement)           \
    4.51 -    _(BreakStatement)           \
    4.52 -    _(ContinueStatement)        \
    4.53 -    _(FunctionTypeStatement)    \
    4.54 -    _(IncDecExpression)         \
    4.55 -    _(UnaryExpression)          \
    4.56 -    _(TernaryExpression)        \
    4.57 -    _(BooleanLiteral)           \
    4.58 -    _(StructureStatement)       \
    4.59 -    _(SwitchStatement)          \
    4.60 -    _(ArrayLiteral)
    4.61 -
    4.62 -// Forward declarations.
    4.63 -#define _(name) class name;
    4.64 -ASTKINDS(_)
    4.65 -#undef _
    4.66 -
    4.67 -class AstVisitor;
    4.68 -
    4.69 -// Interface for AST nodes.
    4.70 -class AstNode : public PoolObject
    4.71 -{
    4.72 -    SourcePosition pos_;
    4.73 -
    4.74 -  public:
    4.75 -    enum Kind {
    4.76 -#       define _(name) k##name,
    4.77 -        ASTKINDS(_)
    4.78 -#       undef _
    4.79 -        AstKind_Invalid
    4.80 -    };
    4.81 -
    4.82 -    AstNode(const SourcePosition &pos)
    4.83 -      : pos_(pos)
    4.84 -    {
    4.85 -    }
    4.86 -    
    4.87 -    virtual Kind kind() const = 0;
    4.88 -
    4.89 -#define _(name)     bool is##name() { return kind() == k##name; }                   \
    4.90 -                    name *to##name() { assert(is##name()); return (name *)this; }   \
    4.91 -                    name *as##name() { if (!is##name()) return NULL; return to##name(); }
    4.92 -    ASTKINDS(_)
    4.93 -#undef _
    4.94 -
    4.95 -    virtual void accept(AstVisitor *visitor) = 0;
    4.96 -
    4.97 -    const SourcePosition &pos() const {
    4.98 -        return pos_;
    4.99 -    }
   4.100 -};
   4.101 -
   4.102 -class AstVisitor
   4.103 -{
   4.104 -  public:
   4.105 -#define _(name) virtual void visit(name *node) = 0;
   4.106 -    ASTKINDS(_)
   4.107 -#undef _
   4.108 -};
   4.109 -
   4.110 -class Statement : public AstNode
   4.111 -{
   4.112 -  public:
   4.113 -    Statement(const SourcePosition &pos)
   4.114 -      : AstNode(pos)
   4.115 -    {
   4.116 -    }
   4.117 -};
   4.118 -
   4.119 -class Expression : public AstNode
   4.120 -{
   4.121 -    ScopedRoot<Type> type_;
   4.122 -
   4.123 -  public:
   4.124 -    Expression(const SourcePosition &pos)
   4.125 -      : AstNode(pos),
   4.126 -        type_(NULL)
   4.127 -    {
   4.128 -    }
   4.129 -
   4.130 -    void setType(Type *type) {
   4.131 -        type_ = type;
   4.132 -    }
   4.133 -    Type *type() const {
   4.134 -        return type_;
   4.135 -    }
   4.136 -};
   4.137 -
   4.138 -typedef PoolList<Statement *> StatementList;
   4.139 -typedef PoolList<Expression *> ExpressionList;
   4.140 -
   4.141 -class VariableDeclaration : public Statement
   4.142 -{
   4.143 -    Variable *variable_;
   4.144 -    Expression *initialization_;
   4.145 -    ExpressionList *postDimensions_;
   4.146 -    BoundName *type_;
   4.147 -    TokenKind declarator_;
   4.148 -
   4.149 -  public:
   4.150 -    VariableDeclaration(const SourcePosition &pos, TokenKind declarator, Variable *var,
   4.151 -                        BoundName *type, ExpressionList *postDimensions,
   4.152 -                        Expression *initialization)
   4.153 -      : Statement(pos),
   4.154 -        variable_(var),
   4.155 -        initialization_(initialization),
   4.156 -        postDimensions_(postDimensions),
   4.157 -        type_(type),
   4.158 -        declarator_(declarator)
   4.159 -    {
   4.160 -    }
   4.161 -
   4.162 -    BoundName *type() const {
   4.163 -        return type_;
   4.164 -    }
   4.165 -    Kind kind() const {
   4.166 -        return kVariableDeclaration;
   4.167 -    }
   4.168 -    Variable *variable() const {
   4.169 -        return variable_;
   4.170 -    }
   4.171 -    Expression *initialization() const {
   4.172 -        return initialization_;
   4.173 -    }
   4.174 -    ExpressionList *postDimensions() const {
   4.175 -        return postDimensions_;
   4.176 -    }
   4.177 -    void accept(AstVisitor *visitor) {
   4.178 -        visitor->visit(this);
   4.179 -    }
   4.180 -    TokenKind declarator() const {
   4.181 -        return declarator_;
   4.182 -    }
   4.183 -};
   4.184 -
   4.185 -class Parameter : public PoolObject
   4.186 -{
   4.187 -    Variable *variable_;
   4.188 -    BoundName *type_;
   4.189 -    bool reference_;
   4.190 -    bool const_;
   4.191 -    ExpressionList *dimensions_;
   4.192 -    Expression *initializer_;
   4.193 -
   4.194 -  public:
   4.195 -    Parameter(Variable *var, BoundName *type, bool reference, bool isConst,
   4.196 -              ExpressionList *dimensions, Expression *initializer)
   4.197 -      : variable_(var),
   4.198 -        type_(type),
   4.199 -        reference_(reference),
   4.200 -        const_(isConst),
   4.201 -        dimensions_(dimensions),
   4.202 -        initializer_(initializer)
   4.203 -    {
   4.204 -    }
   4.205 -
   4.206 -    BoundName *type() const {
   4.207 -        return type_;
   4.208 -    }
   4.209 -    Variable *variable() const {
   4.210 -        return variable_;
   4.211 -    }
   4.212 -    bool reference() const {
   4.213 -        return reference_;
   4.214 -    }
   4.215 -    ExpressionList *dimensions() const {
   4.216 -        return dimensions_;
   4.217 -    }
   4.218 -    bool isConst() const {
   4.219 -        return const_;
   4.220 -    }
   4.221 -    Expression *initializer() const {
   4.222 -        return initializer_;
   4.223 -    }
   4.224 -};
   4.225 -
   4.226 -class NameProxy : public Expression
   4.227 -{
   4.228 -    ScopedRoot<String> name_;
   4.229 -    BoundName *binding_;
   4.230 -
   4.231 -  public:
   4.232 -    NameProxy(const SourcePosition &pos, Handle<String> name, BoundName *binding)
   4.233 -      : Expression(pos),
   4.234 -        name_(name),
   4.235 -        binding_(binding)
   4.236 -    {
   4.237 -    }
   4.238 -
   4.239 -    Kind kind() const {
   4.240 -        return kNameProxy;
   4.241 -    }
   4.242 -    String *name() const {
   4.243 -        return name_;
   4.244 -    }
   4.245 -    void accept(AstVisitor *visitor) {
   4.246 -        visitor->visit(this);
   4.247 -    }
   4.248 -    BoundName *binding() const {
   4.249 -        return binding_;
   4.250 -    }
   4.251 -    void bind(BoundName *name) {
   4.252 -        assert(!binding());
   4.253 -        binding_ = name;
   4.254 -    }
   4.255 -};
   4.256 -
   4.257 -class BooleanLiteral : public Expression
   4.258 -{
   4.259 -    TokenKind token_;
   4.260 -
   4.261 -  public:
   4.262 -    BooleanLiteral(const SourcePosition &pos, TokenKind token)
   4.263 -      : Expression(pos),
   4.264 -        token_(token)
   4.265 -    {
   4.266 -    }
   4.267 -
   4.268 -    Kind kind() const {
   4.269 -        return kBooleanLiteral;
   4.270 -    }
   4.271 -    TokenKind token() const {
   4.272 -        return token_;
   4.273 -    }
   4.274 -    void accept(AstVisitor *visitor) {
   4.275 -        visitor->visit(this);
   4.276 -    }
   4.277 -};
   4.278 -
   4.279 -class IntegerLiteral : public Expression
   4.280 -{
   4.281 -    int value_;
   4.282 -
   4.283 -  public:
   4.284 -    IntegerLiteral(const SourcePosition &pos, int value)
   4.285 -      : Expression(pos),
   4.286 -        value_(value)
   4.287 -    {
   4.288 -    }
   4.289 -
   4.290 -    Kind kind() const {
   4.291 -        return kIntegerLiteral;
   4.292 -    }
   4.293 -    int value() const {
   4.294 -        return value_;
   4.295 -    }
   4.296 -    void accept(AstVisitor *visitor) {
   4.297 -        visitor->visit(this);
   4.298 -    }
   4.299 -};
   4.300 -
   4.301 -class FloatLiteral : public Expression
   4.302 -{
   4.303 -    double value_;
   4.304 -
   4.305 -  public:
   4.306 -    FloatLiteral(const SourcePosition &pos, double value)
   4.307 -      : Expression(pos),
   4.308 -        value_(value)
   4.309 -    {
   4.310 -    }
   4.311 -
   4.312 -    Kind kind() const {
   4.313 -        return kFloatLiteral;
   4.314 -    }
   4.315 -    double value() const {
   4.316 -        return value_;
   4.317 -    }
   4.318 -    void accept(AstVisitor *visitor) {
   4.319 -        visitor->visit(this);
   4.320 -    }
   4.321 -};
   4.322 -
   4.323 -class StringLiteral : public Expression
   4.324 -{
   4.325 -    ScopedRoot<ByteArray> string_;
   4.326 -
   4.327 -  public:
   4.328 -    StringLiteral(const SourcePosition &pos, ByteArray *array)
   4.329 -      : Expression(pos),
   4.330 -        string_(array)
   4.331 -    {
   4.332 -    }
   4.333 -
   4.334 -    Kind kind() const {
   4.335 -        return kStringLiteral;
   4.336 -    }
   4.337 -    ByteArray *string() const {
   4.338 -        return string_;
   4.339 -    }
   4.340 -    void accept(AstVisitor *visitor) {
   4.341 -        visitor->visit(this);
   4.342 -    }
   4.343 -};
   4.344 -
   4.345 -class ArrayLiteral : public Expression
   4.346 -{
   4.347 -    TokenKind token_;
   4.348 -    ExpressionList *expressions_;
   4.349 -
   4.350 -  public:
   4.351 -    ArrayLiteral(const SourcePosition &pos, TokenKind token, ExpressionList *expressions)
   4.352 -      : Expression(pos),
   4.353 -        token_(token),
   4.354 -        expressions_(expressions)
   4.355 -    {
   4.356 -    }
   4.357 -
   4.358 -    Kind kind() const {
   4.359 -        return kArrayLiteral;
   4.360 -    }
   4.361 -    TokenKind token() const {
   4.362 -        return token_;
   4.363 -    }
   4.364 -    ExpressionList *expressions() const {
   4.365 -        return expressions_;
   4.366 -    }
   4.367 -    bool isFixed() const {
   4.368 -        return token_ == TOK_LBRACE;
   4.369 -    }
   4.370 -    void accept(AstVisitor *visitor) {
   4.371 -        visitor->visit(this);
   4.372 -    }
   4.373 -};
   4.374 -
   4.375 -class UnaryExpression : public Expression
   4.376 -{
   4.377 -    Expression *expression_;
   4.378 -    TokenKind token_;
   4.379 -    BoundName *type_;
   4.380 -
   4.381 -  public:
   4.382 -    UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr)
   4.383 -      : Expression(pos),
   4.384 -        expression_(expr),
   4.385 -        token_(token)
   4.386 -    {
   4.387 -    }
   4.388 -
   4.389 -    UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr,
   4.390 -                    BoundName *type)
   4.391 -      : Expression(pos),
   4.392 -        expression_(expr),
   4.393 -        token_(token),
   4.394 -        type_(type)
   4.395 -    {
   4.396 -    }
   4.397 -
   4.398 -    Kind kind() const {
   4.399 -        return kUnaryExpression;
   4.400 -    }
   4.401 -    Expression *expression() const {
   4.402 -        return expression_;
   4.403 -    }
   4.404 -    TokenKind token() const {
   4.405 -        return token_;
   4.406 -    }
   4.407 -    BoundName *type() const {
   4.408 -        return type_;
   4.409 -    }
   4.410 -    void accept(AstVisitor *visitor) {
   4.411 -        visitor->visit(this);
   4.412 -    }
   4.413 -};
   4.414 -
   4.415 -class BinaryExpression : public Expression
   4.416 -{
   4.417 -    Expression *left_;
   4.418 -    Expression *right_;
   4.419 -    TokenKind token_;
   4.420 -
   4.421 -  public:
   4.422 -    BinaryExpression(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
   4.423 -      : Expression(pos),
   4.424 -        left_(left),
   4.425 -        right_(right),
   4.426 -        token_(token)
   4.427 -    {
   4.428 -    }
   4.429 -
   4.430 -    Kind kind() const {
   4.431 -        return kBinaryExpression;
   4.432 -    }
   4.433 -    Expression *left() const {
   4.434 -        return left_;
   4.435 -    }
   4.436 -    Expression *right() const {
   4.437 -        return right_;
   4.438 -    }
   4.439 -    TokenKind token() const {
   4.440 -        return token_;
   4.441 -    }
   4.442 -    void accept(AstVisitor *visitor) {
   4.443 -        visitor->visit(this);
   4.444 -    }
   4.445 -};
   4.446 -
   4.447 -class TernaryExpression : public Expression
   4.448 -{
   4.449 -    Expression *condition_;
   4.450 -    Expression *left_;
   4.451 -    Expression *right_;
   4.452 -
   4.453 -  public:
   4.454 -    TernaryExpression(const SourcePosition &pos, Expression *condition, Expression *left, Expression *right)
   4.455 -      : Expression(pos),
   4.456 -        condition_(condition),
   4.457 -        left_(left),
   4.458 -        right_(right)
   4.459 -    {
   4.460 -    }
   4.461 -
   4.462 -    Kind kind() const {
   4.463 -        return kTernaryExpression;
   4.464 -    }
   4.465 -    Expression *condition() const {
   4.466 -        return condition_;
   4.467 -    }
   4.468 -    Expression *left() const {
   4.469 -        return left_;
   4.470 -    }
   4.471 -    Expression *right() const {
   4.472 -        return right_;
   4.473 -    }
   4.474 -    void accept(AstVisitor *visitor) {
   4.475 -        visitor->visit(this);
   4.476 -    }
   4.477 -};
   4.478 -
   4.479 -class IndexExpression : public Expression
   4.480 -{
   4.481 -    Expression *left_;
   4.482 -    Expression *right_;
   4.483 -
   4.484 -  public:
   4.485 -    IndexExpression(const SourcePosition &pos, Expression *left, Expression *right)
   4.486 -      : Expression(pos),
   4.487 -        left_(left),
   4.488 -        right_(right)
   4.489 -    {
   4.490 -    }
   4.491 -
   4.492 -    Kind kind() const {
   4.493 -        return kIndexExpression;
   4.494 -    }
   4.495 -    Expression *left() const {
   4.496 -        return left_;
   4.497 -    }
   4.498 -    Expression *right() const {
   4.499 -        return right_;
   4.500 -    }
   4.501 -    void accept(AstVisitor *visitor) {
   4.502 -        visitor->visit(this);
   4.503 -    }
   4.504 -};
   4.505 -
   4.506 -class FieldExpression : public Expression
   4.507 -{
   4.508 -    Expression *left_;
   4.509 -    ScopedRoot<String> field_;
   4.510 -    unsigned fieldIndex_;
   4.511 -
   4.512 -  public:
   4.513 -    FieldExpression(const SourcePosition &pos, Expression *left, Handle<String> field)
   4.514 -      : Expression(pos),
   4.515 -        left_(left),
   4.516 -        field_(field),
   4.517 -        fieldIndex_(unsigned(-1))
   4.518 -    {
   4.519 -    }
   4.520 -
   4.521 -    Kind kind() const {
   4.522 -        return kFieldExpression;
   4.523 -    }
   4.524 -    Expression *left() const {
   4.525 -        return left_;
   4.526 -    }
   4.527 -    String *field() const {
   4.528 -        return field_;
   4.529 -    }
   4.530 -    void setFieldIndex(unsigned index) {
   4.531 -        assert(fieldIndex_ == unsigned(-1));
   4.532 -        fieldIndex_ = index;
   4.533 -    }
   4.534 -    unsigned fieldIndex() const {
   4.535 -        assert(fieldIndex_ != unsigned(-1));
   4.536 -        return fieldIndex_;
   4.537 -    }
   4.538 -    void accept(AstVisitor *visitor) {
   4.539 -        visitor->visit(this);
   4.540 -    }
   4.541 -};
   4.542 -
   4.543 -class CallExpression : public Expression
   4.544 -{
   4.545 -    Expression *callee_;
   4.546 -    ExpressionList *arguments_;
   4.547 -
   4.548 -  public:
   4.549 -    CallExpression(const SourcePosition &pos, Expression *callee, ExpressionList *arguments)
   4.550 -      : Expression(pos),
   4.551 -        callee_(callee),
   4.552 -        arguments_(arguments)
   4.553 -    {
   4.554 -    }
   4.555 -
   4.556 -    Kind kind() const {
   4.557 -        return kCallExpression;
   4.558 -    }
   4.559 -    Expression *callee() const {
   4.560 -        return callee_;
   4.561 -    }
   4.562 -    ExpressionList *arguments() const {
   4.563 -        return arguments_;
   4.564 -    }
   4.565 -    void accept(AstVisitor *visitor) {
   4.566 -        visitor->visit(this);
   4.567 -    }
   4.568 -};
   4.569 -
   4.570 -class ForStatement : public Statement
   4.571 -{
   4.572 -    Scope *scope_;
   4.573 -    Statement *initialization_;
   4.574 -    Expression *condition_;
   4.575 -    Statement *update_;
   4.576 -    Statement *body_;
   4.577 -
   4.578 -  public:
   4.579 -    ForStatement(const SourcePosition &pos, Scope *scope, Statement *initialization,
   4.580 -                 Expression *condition, Statement *update, Statement *body)
   4.581 -      : Statement(pos),
   4.582 -        scope_(scope),
   4.583 -        initialization_(initialization),
   4.584 -        condition_(condition),
   4.585 -        update_(update),
   4.586 -        body_(body)
   4.587 -    {
   4.588 -    }
   4.589 -
   4.590 -    Kind kind() const {
   4.591 -        return kForStatement;
   4.592 -    }
   4.593 -    Statement *initialization() const {
   4.594 -        return initialization_;
   4.595 -    }
   4.596 -    Scope *scope() const {
   4.597 -        return scope_;
   4.598 -    }
   4.599 -    Expression *condition() const {
   4.600 -        return condition_;
   4.601 -    }
   4.602 -    Statement *update() const {
   4.603 -        return update_;
   4.604 -    }
   4.605 -    Statement *body() const {
   4.606 -        return body_;
   4.607 -    }
   4.608 -    void accept(AstVisitor *visitor) {
   4.609 -        visitor->visit(this);
   4.610 -    }
   4.611 -};
   4.612 -
   4.613 -class WhileStatement : public Statement
   4.614 -{
   4.615 -    TokenKind token_;
   4.616 -    Expression *condition_;
   4.617 -    Statement *body_;
   4.618 -
   4.619 -  public:
   4.620 -    WhileStatement(const SourcePosition &pos, TokenKind kind, Expression *condition, Statement *body)
   4.621 -      : Statement(pos),
   4.622 -        token_(kind),
   4.623 -        condition_(condition),
   4.624 -        body_(body)
   4.625 -    {
   4.626 -    }
   4.627 -    
   4.628 -    Kind kind() const {
   4.629 -        return kWhileStatement;
   4.630 -    }
   4.631 -    TokenKind token() const {
   4.632 -        return token_;
   4.633 -    }
   4.634 -    Expression *condition() const {
   4.635 -        return condition_;
   4.636 -    }
   4.637 -    Statement *body() const {
   4.638 -        return body_;
   4.639 -    }
   4.640 -    void accept(AstVisitor *visitor) {
   4.641 -        visitor->visit(this);
   4.642 -    }
   4.643 -};
   4.644 -
   4.645 -class ReturnStatement : public Statement
   4.646 -{
   4.647 -    Expression *expression_;
   4.648 -
   4.649 -  public:
   4.650 -    ReturnStatement(const SourcePosition &pos, Expression *expression)
   4.651 -      : Statement(pos),
   4.652 -        expression_(expression)
   4.653 -    {
   4.654 -    }
   4.655 -
   4.656 -    Kind kind() const {
   4.657 -        return kReturnStatement;
   4.658 -    }
   4.659 -    Expression *expression() const {
   4.660 -        return expression_;
   4.661 -    }
   4.662 -    void accept(AstVisitor *visitor) {
   4.663 -        visitor->visit(this);
   4.664 -    }
   4.665 -};
   4.666 -
   4.667 -class BreakStatement : public Statement
   4.668 -{
   4.669 -  public:
   4.670 -    BreakStatement(const SourcePosition &pos)
   4.671 -      : Statement(pos)
   4.672 -    {
   4.673 -    }
   4.674 -
   4.675 -    Kind kind() const {
   4.676 -        return kBreakStatement;
   4.677 -    }
   4.678 -    void accept(AstVisitor *visitor) {
   4.679 -        visitor->visit(this);
   4.680 -    }
   4.681 -};
   4.682 -
   4.683 -class ContinueStatement : public Statement
   4.684 -{
   4.685 -  public:
   4.686 -    ContinueStatement(const SourcePosition &pos)
   4.687 -      : Statement(pos)
   4.688 -    {
   4.689 -    }
   4.690 -
   4.691 -    Kind kind() const {
   4.692 -        return kContinueStatement;
   4.693 -    }
   4.694 -    void accept(AstVisitor *visitor) {
   4.695 -        visitor->visit(this);
   4.696 -    }
   4.697 -};
   4.698 -
   4.699 -class Assignment : public Expression
   4.700 -{
   4.701 -    TokenKind token_;
   4.702 -    Expression *lvalue_;
   4.703 -    Expression *expression_;
   4.704 -
   4.705 -  public:
   4.706 -    Assignment(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
   4.707 -      : Expression(pos),
   4.708 -        token_(token),
   4.709 -        lvalue_(left),
   4.710 -        expression_(right)
   4.711 -    {
   4.712 -    }
   4.713 -
   4.714 -    Kind kind() const {
   4.715 -        return kAssignment;
   4.716 -    }
   4.717 -    TokenKind token() const {
   4.718 -        return token_;
   4.719 -    }
   4.720 -    Expression *lvalue() const {
   4.721 -        return lvalue_;
   4.722 -    }
   4.723 -    Expression *expression() const {
   4.724 -        return expression_;
   4.725 -    }
   4.726 -    void accept(AstVisitor *visitor) {
   4.727 -        visitor->visit(this);
   4.728 -    }
   4.729 -};
   4.730 -
   4.731 -class ExpressionStatement : public Statement
   4.732 -{
   4.733 -    Expression *expression_;
   4.734 -
   4.735 -  public:
   4.736 -    ExpressionStatement(Expression *expression)
   4.737 -      : Statement(expression->pos()),
   4.738 -        expression_(expression)
   4.739 -    {
   4.740 -    }
   4.741 -
   4.742 -    Kind kind() const {
   4.743 -        return kExpressionStatement;
   4.744 -    }
   4.745 -    Expression *expression() const {
   4.746 -        return expression_;
   4.747 -    }
   4.748 -    void accept(AstVisitor *visitor) {
   4.749 -        visitor->visit(this);
   4.750 -    }
   4.751 -};
   4.752 -
   4.753 -class BlockStatement : public Statement
   4.754 -{
   4.755 -    Scope *scope_;
   4.756 -    StatementList *statements_;
   4.757 -
   4.758 -  public:
   4.759 -    BlockStatement(const SourcePosition &pos, Scope *scope, StatementList *statements)
   4.760 -      : Statement(pos),
   4.761 -        scope_(scope),
   4.762 -        statements_(statements)
   4.763 -    {
   4.764 -    }
   4.765 -
   4.766 -    Kind kind() const {
   4.767 -        return kBlockStatement;
   4.768 -    }
   4.769 -    Scope *scope() const {
   4.770 -        return scope_;
   4.771 -    }
   4.772 -    StatementList *statements() const {
   4.773 -        return statements_;
   4.774 -    }
   4.775 -    void accept(AstVisitor *visitor) {
   4.776 -        visitor->visit(this);
   4.777 -    }
   4.778 -};
   4.779 -
   4.780 -typedef PoolList<Parameter *> ParameterList;
   4.781 -
   4.782 -class FunctionSignature
   4.783 -{
   4.784 -  public:
   4.785 -    FunctionSignature(BoundName *returnType, ExpressionList *returnDimensions, ParameterList *parameters)
   4.786 -      : returnType_(returnType),
   4.787 -        returnDimensions_(returnDimensions),
   4.788 -        parameters_(parameters)
   4.789 -    {
   4.790 -    }
   4.791 -
   4.792 -    BoundName *returnType() const {
   4.793 -        return returnType_;
   4.794 -    }
   4.795 -    ExpressionList *returnDimensions() const {
   4.796 -        return returnDimensions_;
   4.797 -    }
   4.798 -    ParameterList *parameters() const {
   4.799 -        return parameters_;
   4.800 -    }
   4.801 -
   4.802 -  private:
   4.803 -    BoundName *returnType_;
   4.804 -    ExpressionList *returnDimensions_;
   4.805 -    ParameterList *parameters_;
   4.806 -};
   4.807 -
   4.808 -class FunctionTypeStatement : public Statement
   4.809 -{
   4.810 -  public:
   4.811 -    FunctionTypeStatement(const SourcePosition &pos, NamedType *type, const FunctionSignature &signature)
   4.812 -      : Statement(pos),
   4.813 -        type_(type),
   4.814 -        signature_(signature)
   4.815 -    {
   4.816 -    }
   4.817 -
   4.818 -    Kind kind() const {
   4.819 -        return kFunctionTypeStatement;
   4.820 -    }
   4.821 -    NamedType *decl() const {
   4.822 -        return type_;
   4.823 -    }
   4.824 -    const FunctionSignature &signature() const {
   4.825 -        return signature_;
   4.826 -    }
   4.827 -    void accept(AstVisitor *visitor) {
   4.828 -        visitor->visit(this);
   4.829 -    }
   4.830 -
   4.831 -  private:
   4.832 -    NamedType *type_;
   4.833 -    FunctionSignature signature_;
   4.834 -};
   4.835 -
   4.836 -class FunctionStatement : public Statement
   4.837 -{
   4.838 -    Scope *scope_;
   4.839 -    NamedFunction *fun_;
   4.840 -    Statement *body_;
   4.841 -    FunctionSignature signature_;
   4.842 -    bool explicitReturn_;
   4.843 -
   4.844 -  public:
   4.845 -    FunctionStatement(const SourcePosition &pos, Scope *scope, NamedFunction *fun, Statement *body,
   4.846 -                      const FunctionSignature &signature, bool explicitReturn)
   4.847 -      : Statement(pos),
   4.848 -        scope_(scope),
   4.849 -        fun_(fun),
   4.850 -        body_(body),
   4.851 -        signature_(signature),
   4.852 -        explicitReturn_(explicitReturn)
   4.853 -    {
   4.854 -    }
   4.855 -
   4.856 -    Kind kind() const {
   4.857 -        return kFunctionStatement;
   4.858 -    }
   4.859 -    Scope *scope() const {
   4.860 -        return scope_;
   4.861 -    }
   4.862 -    NamedFunction *fun() const {
   4.863 -        return fun_;
   4.864 -    }
   4.865 -    Statement *body() const {
   4.866 -        return body_;
   4.867 -    }
   4.868 -    const FunctionSignature &signature() {
   4.869 -        return signature_;
   4.870 -    }
   4.871 -    void accept(AstVisitor *visitor) {
   4.872 -        visitor->visit(this);
   4.873 -    }
   4.874 -    bool hasExplicitReturn() const {
   4.875 -        return explicitReturn_;
   4.876 -    }
   4.877 -};
   4.878 -
   4.879 -class IfStatement : public Statement
   4.880 -{
   4.881 -    Expression *condition_;
   4.882 -    Statement *ifTrue_;
   4.883 -    Statement *ifFalse_;
   4.884 -
   4.885 -  public:
   4.886 -    IfStatement(const SourcePosition &pos, Expression *condition, Statement *ifTrue)
   4.887 -      : Statement(pos),
   4.888 -        condition_(condition),
   4.889 -        ifTrue_(ifTrue),
   4.890 -        ifFalse_(NULL)
   4.891 -    {
   4.892 -    }
   4.893 -
   4.894 -    Kind kind() const {
   4.895 -        return kIfStatement;
   4.896 -    }
   4.897 -    Expression *condition() const {
   4.898 -        return condition_;
   4.899 -    }
   4.900 -    Statement *ifTrue() const {
   4.901 -        return ifTrue_;
   4.902 -    }
   4.903 -    Statement *ifFalse() const {
   4.904 -        return ifFalse_;
   4.905 -    }
   4.906 -    void setIfFalse(Statement *ifFalse) {
   4.907 -        ifFalse_ = ifFalse;
   4.908 -    }
   4.909 -    void accept(AstVisitor *visitor) {
   4.910 -        visitor->visit(this);
   4.911 -    }
   4.912 -};
   4.913 -
   4.914 -class EnumStatement : public Statement
   4.915 -{
   4.916 -    ScopedRoot<String> name_;
   4.917 -    NamedType *type_;
   4.918 -
   4.919 -  public:
   4.920 -    struct Entry {
   4.921 -        NamedConstant *name;
   4.922 -        Expression *expr;
   4.923 -
   4.924 -        Entry(NamedConstant *name, Expression *expr)
   4.925 -          : name(name),
   4.926 -            expr(expr)
   4.927 -        {
   4.928 -        }
   4.929 -    };
   4.930 -
   4.931 -    typedef PoolList<Entry> EntryList;
   4.932 -
   4.933 -  public:
   4.934 -    EnumStatement(const SourcePosition &pos, NamedType *type, Handle<String> name, EntryList *entries)
   4.935 -      : Statement(pos),
   4.936 -        name_(name),
   4.937 -        type_(type),
   4.938 -        entries_(entries)
   4.939 -    {
   4.940 -    }
   4.941 -
   4.942 -    Kind kind() const {
   4.943 -        return kEnumStatement;
   4.944 -    }
   4.945 -    String *name() const {
   4.946 -        return name_;
   4.947 -    }
   4.948 -    EntryList *entries() const {
   4.949 -        return entries_;
   4.950 -    }
   4.951 -    NamedType *decl() const {
   4.952 -        return type_;
   4.953 -    }
   4.954 -    void accept(AstVisitor *visitor) {
   4.955 -        visitor->visit(this);
   4.956 -    }
   4.957 -
   4.958 -  private:
   4.959 -    EntryList *entries_;
   4.960 -};
   4.961 -
   4.962 -class IncDecExpression : public Expression
   4.963 -{
   4.964 -    TokenKind token_;
   4.965 -    Expression *expression_;
   4.966 -    bool postfix_;
   4.967 -
   4.968 -  public:
   4.969 -    IncDecExpression(const SourcePosition &pos, TokenKind token, Expression *expression, bool postfix)
   4.970 -      : Expression(pos),
   4.971 -        token_(token),
   4.972 -        expression_(expression),
   4.973 -        postfix_(postfix)
   4.974 -    {
   4.975 -    }
   4.976 -
   4.977 -    Kind kind() const {
   4.978 -        return kIncDecExpression;
   4.979 -    }
   4.980 -    TokenKind token() const {
   4.981 -        return token_;
   4.982 -    }
   4.983 -    Expression *expression() const {
   4.984 -        return expression_;
   4.985 -    }
   4.986 -    bool postfix() const {
   4.987 -        return postfix_;
   4.988 -    }
   4.989 -    void accept(AstVisitor *visitor) {
   4.990 -        visitor->visit(this);
   4.991 -    }
   4.992 -};
   4.993 -
   4.994 -class Case : public PoolObject
   4.995 -{
   4.996 -  public:
   4.997 -    Case(Expression *expression, ExpressionList *others, Statement *statement)
   4.998 -      : expression_(expression),
   4.999 -        others_(others),
  4.1000 -        statement_(statement)
  4.1001 -    {
  4.1002 -    }
  4.1003 -
  4.1004 -    Expression *expression() const {
  4.1005 -        return expression_;
  4.1006 -    }
  4.1007 -    PoolList<Expression *> *others() const {
  4.1008 -        return others_;
  4.1009 -    }
  4.1010 -    Statement *statement() const {
  4.1011 -        return statement_;
  4.1012 -    }
  4.1013 -
  4.1014 -  private:
  4.1015 -    Expression *expression_;
  4.1016 -    PoolList <Expression *> *others_;
  4.1017 -    Statement *statement_;
  4.1018 -};
  4.1019 -
  4.1020 -struct CaseValue
  4.1021 -{
  4.1022 -    BoxedPrimitive box;
  4.1023 -    size_t statement;
  4.1024 -
  4.1025 -    CaseValue(size_t statement)
  4.1026 -      : statement(statement)
  4.1027 -    {
  4.1028 -    }
  4.1029 -};
  4.1030 -
  4.1031 -typedef PoolList<CaseValue> CaseValueList;
  4.1032 -
  4.1033 -class SwitchStatement : public Statement
  4.1034 -{
  4.1035 -  public:
  4.1036 -    SwitchStatement(const SourcePosition &pos, Expression *expression, PoolList<Case *> *cases,
  4.1037 -                    Statement *def)
  4.1038 -      : Statement(pos),
  4.1039 -        expression_(expression),
  4.1040 -        cases_(cases),
  4.1041 -        default_(def),
  4.1042 -        table_(NULL)
  4.1043 -    {
  4.1044 -    }
  4.1045 -
  4.1046 -    Kind kind() const {
  4.1047 -        return kSwitchStatement;
  4.1048 -    }
  4.1049 -    Expression *expression() const {
  4.1050 -        return expression_;
  4.1051 -    }
  4.1052 -    PoolList<Case *> *cases() const {
  4.1053 -        return cases_;
  4.1054 -    }
  4.1055 -    Statement *defaultCase() const {
  4.1056 -        return default_;
  4.1057 -    }
  4.1058 -    void setCaseValueList(CaseValueList *list) {
  4.1059 -        table_ = list;
  4.1060 -    }
  4.1061 -    CaseValueList *caseValueList() const {
  4.1062 -        return table_;
  4.1063 -    }
  4.1064 -    void accept(AstVisitor *visitor) {
  4.1065 -        visitor->visit(this);
  4.1066 -    }
  4.1067 -
  4.1068 -  private:
  4.1069 -    Expression *expression_;
  4.1070 -    PoolList<Case *> *cases_;
  4.1071 -    Statement *default_;
  4.1072 -    CaseValueList *table_;
  4.1073 -};
  4.1074 -
  4.1075 -class StructureStatement : public Statement
  4.1076 -{
  4.1077 -  public:
  4.1078 -    class Field : public PoolObject
  4.1079 -    {
  4.1080 -        SourcePosition pos_;
  4.1081 -        BoundName *type_;
  4.1082 -        ScopedRoot<String> name_;
  4.1083 -        ExpressionList *dimensions_;
  4.1084 -
  4.1085 -      public:
  4.1086 -        Field(const SourcePosition &pos,
  4.1087 -              BoundName *type,
  4.1088 -              Handle<String> name,
  4.1089 -              ExpressionList *dimensions)
  4.1090 -          : pos_(pos),
  4.1091 -            type_(type),
  4.1092 -            name_(name),
  4.1093 -            dimensions_(dimensions)
  4.1094 -        {
  4.1095 -        }
  4.1096 -
  4.1097 -        const SourcePosition &pos() const {
  4.1098 -            return pos_;
  4.1099 -        }
  4.1100 -        BoundName *type() const {
  4.1101 -            return type_;
  4.1102 -        }
  4.1103 -        String *name() const {
  4.1104 -            return name_;
  4.1105 -        }
  4.1106 -        ExpressionList *dimensions() const {
  4.1107 -            return dimensions_;
  4.1108 -        }
  4.1109 -    };
  4.1110 -
  4.1111 -    typedef PoolList<StructureStatement::Field *> FieldList;
  4.1112 -
  4.1113 -  public:
  4.1114 -    StructureStatement(const SourcePosition &pos, NamedType *decl, FieldList *fields)
  4.1115 -      : Statement(pos),
  4.1116 -        decl_(decl),
  4.1117 -        fields_(fields)
  4.1118 -    {
  4.1119 -    }
  4.1120 -
  4.1121 -    Kind kind() const {
  4.1122 -        return kStructureStatement;
  4.1123 -    }
  4.1124 -    FieldList *fields() const {
  4.1125 -        return fields_;
  4.1126 -    }
  4.1127 -    NamedType *decl() const {
  4.1128 -        return decl_;
  4.1129 -    }
  4.1130 -    void accept(AstVisitor *visitor) {
  4.1131 -        visitor->visit(this);
  4.1132 -    }
  4.1133 -
  4.1134 -  private:
  4.1135 -    NamedType *decl_;
  4.1136 -    FieldList *fields_;
  4.1137 -};
  4.1138 -
  4.1139 -typedef StructureStatement::FieldList FieldList;
  4.1140 -
  4.1141 -class Scope;
  4.1142 -
  4.1143 -typedef PoolList<NameProxy *> NameProxyList;
  4.1144 -
  4.1145 -class ParseTree : public PoolObject
  4.1146 -{
  4.1147 -    StatementList *statements_;
  4.1148 -    Scope *scope_;
  4.1149 -    NameProxyList *unbound_;
  4.1150 -
  4.1151 -  public:
  4.1152 -    ParseTree(Scope *scope, StatementList *statements, NameProxyList *unbound)
  4.1153 -      : statements_(statements),
  4.1154 -        scope_(scope),
  4.1155 -        unbound_(unbound)
  4.1156 -    {
  4.1157 -    }
  4.1158 -
  4.1159 -    void dump(FILE *fp);
  4.1160 -
  4.1161 -    StatementList *statements() const {
  4.1162 -        return statements_;
  4.1163 -    }
  4.1164 -    Scope *scope() const {
  4.1165 -        return scope_;
  4.1166 -    }
  4.1167 -    NameProxyList *unbound() const {
  4.1168 -        return unbound_;
  4.1169 -    }
  4.1170 -};
  4.1171 -
  4.1172 -}
  4.1173 -
  4.1174 -#endif // _include_sourcepawn_ast_h_
     5.1 --- a/src/BytecodeCompiler.cpp	Mon Sep 17 00:10:01 2012 -0700
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,1576 +0,0 @@
     5.4 -/* vim: set ts=4 sw=4 tw=99 et:
     5.5 - *
     5.6 - * Copyright (C) 2012 David Anderson
     5.7 - *
     5.8 - * This file is part of JITCraft.
     5.9 - *
    5.10 - * JITCraft is free software: you can redistribute it and/or modify it under
    5.11 - * the terms of the GNU General Public License as published by the Free
    5.12 - * Software Foundation, either version 3 of the License, or (at your option)
    5.13 - * any later version.
    5.14 - * 
    5.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    5.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    5.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    5.18 - *
    5.19 - * You should have received a copy of the GNU General Public License along with
    5.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    5.21 - */
    5.22 -#include <string.h>
    5.23 -#include "BytecodeCompiler.h"
    5.24 -#include "Scopes.h"
    5.25 -#include "Modules.h"
    5.26 -#include "Types.h"
    5.27 -#include "Array.h"
    5.28 -#include "Strings.h"
    5.29 -#include "Zone.h"
    5.30 -#include "Environments.h"
    5.31 -#include "Box.h"
    5.32 -#include "Heap-inl.h"
    5.33 -
    5.34 -using namespace ke;
    5.35 -
    5.36 -typedef BytecodeEmitter::Label Label;
    5.37 -
    5.38 -#define __ emitter_.
    5.39 -
    5.40 -BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
    5.41 -  : zone_(zone),
    5.42 -    tree_(tree),
    5.43 -    emitter_(zone->pool()),
    5.44 -    locals_(NULL),
    5.45 -    scope_(NULL),
    5.46 -    moduleData_(module),
    5.47 -    loop_(NULL)
    5.48 -{
    5.49 -}
    5.50 -
    5.51 -static inline TokenKind
    5.52 -ToCompare(Expression *expr)
    5.53 -{
    5.54 -    if (expr->isBinaryExpression()) {
    5.55 -        BinaryExpression *b = expr->toBinaryExpression();
    5.56 -        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
    5.57 -            return b->token();
    5.58 -    } else if (expr->isUnaryExpression()) {
    5.59 -        UnaryExpression *u = expr->toUnaryExpression();
    5.60 -        if (u->token() == TOK_NOT)
    5.61 -            return TOK_NOT;
    5.62 -    }
    5.63 -    return TOK_EOF;
    5.64 -}
    5.65 -
    5.66 -static inline Opcode
    5.67 -CompareTokenToJump(TokenKind kind)
    5.68 -{
    5.69 -    switch (kind) {
    5.70 -      case TOK_EQUALS:
    5.71 -        return OP_JEQ;
    5.72 -      case TOK_NOTEQUALS:
    5.73 -        return OP_JNE;
    5.74 -      case TOK_GT:
    5.75 -        return OP_JG;
    5.76 -      case TOK_GE:
    5.77 -        return OP_JGE;
    5.78 -      case TOK_LT:
    5.79 -        return OP_JL;
    5.80 -      default:
    5.81 -        assert(kind == TOK_LE);
    5.82 -        return OP_JLE;
    5.83 -    }
    5.84 -}
    5.85 -
    5.86 -static inline Opcode
    5.87 -TokenToOpcode(TokenKind kind)
    5.88 -{
    5.89 -    switch (kind) {
    5.90 -      case TOK_PLUS:
    5.91 -        return OP_ADD;
    5.92 -      case TOK_MINUS:
    5.93 -        return OP_SUB;
    5.94 -      case TOK_STAR:
    5.95 -        return OP_MUL;
    5.96 -      case TOK_SLASH:
    5.97 -        return OP_DIV;
    5.98 -      case TOK_PERCENT:
    5.99 -        return OP_MOD;
   5.100 -      case TOK_SHR:
   5.101 -        return OP_SHR;
   5.102 -      case TOK_USHR:
   5.103 -        return OP_USHR;
   5.104 -      case TOK_SHL:
   5.105 -        return OP_SHL;
   5.106 -      case TOK_BITAND:
   5.107 -        return OP_BITAND;
   5.108 -      case TOK_BITOR:
   5.109 -        return OP_BITOR;
   5.110 -      case TOK_GT:
   5.111 -          return OP_GT;
   5.112 -      case TOK_GE:
   5.113 -          return OP_GE;
   5.114 -      case TOK_LT:
   5.115 -          return OP_LT;
   5.116 -      case TOK_LE:
   5.117 -          return OP_LE;
   5.118 -      case TOK_EQUALS:
   5.119 -          return OP_EQ;
   5.120 -      case TOK_NOTEQUALS:
   5.121 -          return OP_NE;
   5.122 -      default:
   5.123 -        assert(kind == TOK_BITXOR);
   5.124 -        return OP_BITXOR;
   5.125 -    }
   5.126 -}
   5.127 -
   5.128 -void
   5.129 -BytecodeCompiler::recordLifoSlot(Scope *scope)
   5.130 -{
   5.131 -    if (!scope)
   5.132 -        return;
   5.133 -
   5.134 -    if (Variable *var = scope->lifoSlot()) {
   5.135 -        locals_->set(zone_, var->slot(), var->type());
   5.136 -        __ savelifo(var->slot());
   5.137 -    }
   5.138 -}
   5.139 -
   5.140 -void
   5.141 -BytecodeCompiler::unwindTo(Scope *scope)
   5.142 -{
   5.143 -    // Note: we only need to unwind to the outermost scope's LIFO slot.
   5.144 -    Variable *var = NULL;
   5.145 -    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
   5.146 -        if (Variable *slot = current->lifoSlot())
   5.147 -            var = slot;
   5.148 -    }
   5.149 -
   5.150 -    if (var)
   5.151 -        __ unwindlifo(var->slot());
   5.152 -}
   5.153 -
   5.154 -void
   5.155 -BytecodeCompiler::visit(NameProxy *name)
   5.156 -{
   5.157 -    switch (name->binding()->kind()) {
   5.158 -      case BoundName::VARIABLE:
   5.159 -      {
   5.160 -        Variable *var = name->binding()->toVariable();
   5.161 -
   5.162 -        if (var->location() == Variable::STACK) {
   5.163 -            __ getlocal(var);
   5.164 -            assert(!name->type()->isReference());
   5.165 -        } else if (var->location() == Variable::ENVIRONMENT) {
   5.166 -            getEnvSlot(var);
   5.167 -        } else {
   5.168 -            assert(var->location() == Variable::PARAMETER);
   5.169 -            __ getarg(var);
   5.170 -
   5.171 -            // If this argument is actually a reference, dereference it now.
   5.172 -            if (var->type()->isReference())
   5.173 -                __ getref(var->type()->contained());
   5.174 -        }
   5.175 -        break;
   5.176 -      }
   5.177 -
   5.178 -      case BoundName::FUNCTION:
   5.179 -      {
   5.180 -        NamedFunction *fun = name->binding()->toNamedFunction();
   5.181 -        __ module();
   5.182 -        __ getmodule_fn(fun->slot());
   5.183 -        break;
   5.184 -      }
   5.185 -
   5.186 -      default:
   5.187 -      {
   5.188 -        NamedConstant *constant = name->binding()->toNamedConstant();
   5.189 -        __ int_(constant->value().toInt());
   5.190 -        break;
   5.191 -      }
   5.192 -    }
   5.193 -}
   5.194 -
   5.195 -void
   5.196 -BytecodeCompiler::visit(ExpressionStatement *node)
   5.197 -{
   5.198 -    // Expressions leave their value on the top of the stack, so we make sure
   5.199 -    // to balance the stack if they're used as a statement.
   5.200 -    node->expression()->accept(this);
   5.201 -    if (!node->expression()->type()->isVoid())
   5.202 -        __ pop();
   5.203 -}
   5.204 -
   5.205 -static inline bool
   5.206 -IsCompositeValueType(Type *type)
   5.207 -{
   5.208 -    return type->isStruct() ||
   5.209 -           (type->isArray() && type->isFixedLength());
   5.210 -}
   5.211 -
   5.212 -static inline Array *
   5.213 -StringLiteralToArray(Zone *zone, StringLiteral *node)
   5.214 -{
   5.215 -    Local<Type> type(zone, node->type());
   5.216 -    Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
   5.217 -    if (!map)
   5.218 -        return NULL;
   5.219 -
   5.220 -    return Array::NewString(zone,
   5.221 -                            map,
   5.222 -                            node->string()->raw(),
   5.223 -                            node->string()->length(),
   5.224 -                            Heap::Tenure_Old);
   5.225 -}
   5.226 -
   5.227 -void
   5.228 -BytecodeCompiler::visit(Assignment *node)
   5.229 -{
   5.230 -    Local<Type> left(zone_, node->type());
   5.231 -    Local<Type> right(zone_, node->expression()->type());
   5.232 -
   5.233 -    // The first step is three sub-steps:
   5.234 -    //
   5.235 -    //   (1) Bind the left-hand side.
   5.236 -    //   -- If a cumulative operation (+=, etc):
   5.237 -    //   (2) Save a copy of the binding on the stack.
   5.238 -    //   (3) Dereference the binding to get a value.
   5.239 -    //
   5.240 -    if (node->lvalue()->isNameProxy()) {
   5.241 -        NameProxy *proxy = node->lvalue()->toNameProxy();
   5.242 -        Variable *var = proxy->binding()->toVariable();
   5.243 -
   5.244 -        // We need to fetch the variable under the following circumstances:
   5.245 -        //  (1) The variable is a reference, since we'll store into the ref.
   5.246 -        //  (2) The variable is a fixed array, since we need to copy into it.
   5.247 -        //  (3) The variable is a struct, since we need to copy into it.
   5.248 -        if (var->type()->isReference() || IsCompositeValueType(var->type()))
   5.249 -            __ get(var);
   5.250 -
   5.251 -        // Get the value if needed.
   5.252 -        if (node->token() != TOK_ASSIGN) {
   5.253 -            // += etc is not allowed on arrays.
   5.254 -            assert(!var->type()->isArray());
   5.255 -
   5.256 -            if (var->location() == Variable::ENVIRONMENT)
   5.257 -                getEnvSlot(var);
   5.258 -
   5.259 -            if (var->type()->isReference()) {
   5.260 -                __ dup();
   5.261 -                __ getref(var->type()->contained());
   5.262 -            } else if (var->location() != Variable::ENVIRONMENT) {
   5.263 -                __ get(var);
   5.264 -            }
   5.265 -        }
   5.266 -    } else if (node->lvalue()->isFieldExpression()) {
   5.267 -        FieldExpression *expr = node->lvalue()->toFieldExpression();
   5.268 -        __ note_position(expr->pos());
   5.269 -
   5.270 -        expr->left()->accept(this);
   5.271 -
   5.272 -        if (node->token() != TOK_ASSIGN)
   5.273 -            __ dup();
   5.274 -
   5.275 -        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
   5.276 -            __ getfield(expr->fieldIndex(), left);
   5.277 -    } else {
   5.278 -        IndexExpression *index = node->lvalue()->toIndexExpression();
   5.279 -        __ note_position(index->pos());
   5.280 -
   5.281 -        index->left()->accept(this);
   5.282 -        index->right()->accept(this);
   5.283 -
   5.284 -        if (node->token() != TOK_ASSIGN)
   5.285 -            __ dup2();
   5.286 -
   5.287 -        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
   5.288 -            __ getelem(left);
   5.289 -    }
   5.290 -
   5.291 -    if (node->token() == TOK_ASSIGN) {
   5.292 -        // Special case: if the left-hand side is a string literal, we must
   5.293 -        // spawn a new copy (:TODO: something about const?)
   5.294 -        if (node->expression()->isStringLiteral() && !left->isFixedLength()) {
   5.295 -            Local<Array> string(zone_,
   5.296 -                    StringLiteralToArray(zone_, node->expression()->toStringLiteral()));
   5.297 -            if (!string)
   5.298 -                return;
   5.299 -
   5.300 -            Local<ArrayMap> arrayMap(zone_, ArrayMap::cast(string->map()));
   5.301 -            __ note_position(node->expression()->pos());
   5.302 -            __ int_(string->length());
   5.303 -            __ newarray(OP_NEWSIZED, arrayMap, Heap::Tenure_Default);
   5.304 -            __ object(string);
   5.305 -            __ copyarray();
   5.306 -        } else {
   5.307 -            node->expression()->accept(this);
   5.308 -        }
   5.309 -    } else {
   5.310 -        visitForALU(left, node->expression());
   5.311 -
   5.312 -        TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
   5.313 -        __ note_position(node->pos());
   5.314 -        __ binary(TokenToOpcode(alu));
   5.315 -    }
   5.316 -
   5.317 -    // Emit the store.
   5.318 -    if (left->isArray() && left->isFixedLength()) {
   5.319 -        // (x = y) returns the left-hand side; if |x| is a fixed-length array,
   5.320 -        // then |y| is as well, and we perform a deep copy.
   5.321 -        assert(right->isFixedLength());
   5.322 -        __ note_position(node->pos());
   5.323 -        __ copyarray();
   5.324 -    } else if (left->isStruct()) {
   5.325 -        // Structs have value semantics, so emit a full copy. We don't break
   5.326 -        // this down into u-ops, to avoid unnecessary bytecode explosion.
   5.327 -        assert(right->isStruct());
   5.328 -        __ note_position(node->pos());
   5.329 -        __ copystruct();
   5.330 -    } else if (node->lvalue()->isNameProxy()) {
   5.331 -        NameProxy *proxy = node->lvalue()->toNameProxy();
   5.332 -        Variable *var = proxy->binding()->toVariable();
   5.333 -
   5.334 -        if (var->type()->isReference())
   5.335 -            __ setref(var->type()->contained());
   5.336 -        else if (var->location() == Variable::ENVIRONMENT)
   5.337 -            setEnvSlot(var);
   5.338 -        else
   5.339 -            __ set(var);
   5.340 -    } else if (node->lvalue()->isFieldExpression()) {
   5.341 -        FieldExpression *expr = node->lvalue()->toFieldExpression();
   5.342 -        __ setfield(expr->fieldIndex(), left);
   5.343 -    } else {
   5.344 -        __ setelem(left);
   5.345 -    }
   5.346 -}
   5.347 -
   5.348 -void
   5.349 -BytecodeCompiler::visit(IncDecExpression *node)
   5.350 -{
   5.351 -    // In the postfix case, the logic looks like:
   5.352 -    //      (1) Bind       -> REF
   5.353 -    //      (2) Dup        -> REF REF
   5.354 -    //      (3) Fetch      -> REF VAL
   5.355 -    //      (4) Swap       -> VAL REF
   5.356 -    //      (5) Pick       -> VAL REF VAL
   5.357 -    //      (6) Add        -> VAL REF VAL+1
   5.358 -    //      (7) Store      -> VAL VAL+1
   5.359 -    //      (8) Drop       -> VAL
   5.360 -    //
   5.361 -    // In the prefix case, the logic looks like:
   5.362 -    //      (1) Bind       -> REF
   5.363 -    //      (2) Dup        -> REF REF
   5.364 -    //      (3) Fetch      -> REF VAL
   5.365 -    //      --
   5.366 -    //      --
   5.367 -    //      (6) Add        -> REF VAL+1
   5.368 -    //      (7) Store      -> VAL+1
   5.369 -    //      --
   5.370 -    //
   5.371 -    // This is squirrely enough such that we don't bother sharing too much
   5.372 -    // with the above.
   5.373 -    // 
   5.374 -    // Note: We simulate a "Pick" operation with a dup2+pop.
   5.375 -
   5.376 -    // This is steps (1) to (5).
   5.377 -    Expression *expr = node->expression();
   5.378 -    if (expr->isNameProxy()) {
   5.379 -        NameProxy *proxy = expr->toNameProxy();
   5.380 -        Variable *var = proxy->binding()->toVariable();
   5.381 -
   5.382 -        // Bind.
   5.383 -        if (var->location() == Variable::ENVIRONMENT)
   5.384 -            getEnvSlot(var);
   5.385 -        else if (var->type()->isReference() || var->type()->isArray())
   5.386 -            __ get(var);
   5.387 -
   5.388 -        // Dup and fetch.
   5.389 -        if (var->type()->isReference()) {
   5.390 -            __ dup();
   5.391 -            __ getref(node->type());
   5.392 -            if (node->postfix()) {
   5.393 -                __ swap();
   5.394 -                __ pick2();
   5.395 -            }
   5.396 -        } else {
   5.397 -            assert(!var->type()->isArray());
   5.398 -            if (var->location() != Variable::ENVIRONMENT)
   5.399 -                __ get(var);
   5.400 -            if (node->postfix())
   5.401 -                __ dup();
   5.402 -        }
   5.403 -    } else if (expr->isFieldExpression()) {
   5.404 -        FieldExpression *field = expr->toFieldExpression();
   5.405 -
   5.406 -        field->left()->accept(this);
   5.407 -        __ dup();
   5.408 -        __ getfield(field->fieldIndex(), field->type());
   5.409 -
   5.410 -        if (node->postfix()) {
   5.411 -            // The stack looks like this now:
   5.412 -            // OBJECT VALUE
   5.413 -            __ swap();          // VALUE OBJECT
   5.414 -            __ pick2();         // VALUE OBJECT VALUE
   5.415 -        }
   5.416 -    } else {
   5.417 -        IndexExpression *index = expr->toIndexExpression();
   5.418 -        __ note_position(index->pos());
   5.419 -
   5.420 -        index->left()->accept(this);
   5.421 -        index->right()->accept(this);
   5.422 -
   5.423 -        assert(!node->type()->isArray());
   5.424 -        __ dup2();
   5.425 -        __ getelem(node->type());
   5.426 -
   5.427 -        if (node->postfix()) {
   5.428 -            // The stack looks like this now:
   5.429 -            // ARRAY INDEX VALUE
   5.430 -            //
   5.431 -            // So we must use a PICK operation to rotate the stack into position.
   5.432 -            __ roll3();         // INDEX VALUE ARRAY
   5.433 -            __ roll3();         // VALUE ARRAY INDEX
   5.434 -            __ pick3();         // VALUE ARRAY INDEX VALUE
   5.435 -        }
   5.436 -    }
   5.437 -
   5.438 -    // Perform step (6).
   5.439 -    if (node->type()->isFloat()) {
   5.440 -        __ float_(1.0);
   5.441 -    } else {
   5.442 -        assert(node->type()->isInt32());
   5.443 -        __ int_(1);
   5.444 -    }
   5.445 -
   5.446 -    __ note_position(node->pos());
   5.447 -    if (node->token() == TOK_INCREMENT)
   5.448 -        __ binary(OP_ADD);
   5.449 -    else
   5.450 -        __ binary(OP_SUB);
   5.451 -
   5.452 -    // Perform step (7).
   5.453 -    if (expr->isNameProxy()) {
   5.454 -        NameProxy *proxy = expr->toNameProxy();
   5.455 -        Variable *var = proxy->binding()->toVariable();
   5.456 -
   5.457 -        if (var->type()->isReference())
   5.458 -            __ setref(node->type());
   5.459 -        else if (var->location() == Variable::ENVIRONMENT)
   5.460 -            setEnvSlot(var);
   5.461 -        else
   5.462 -            __ set(var);
   5.463 -    } else if (expr->isFieldExpression()) {
   5.464 -        FieldExpression *field = expr->toFieldExpression();
   5.465 -        __ setfield(field->fieldIndex(), field->type());
   5.466 -    } else {
   5.467 -        assert(expr->isIndexExpression());
   5.468 -        __ setelem(node->type());
   5.469 -    }
   5.470 -
   5.471 -    // Perform step (8).
   5.472 -    if (node->postfix())
   5.473 -        __ pop();
   5.474 -}
   5.475 -
   5.476 -void
   5.477 -BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   5.478 -{
   5.479 -    node->accept(this);
   5.480 -    if (needed->isFloat() && !node->type()->isFloat())
   5.481 -        __ cvt_i2f();
   5.482 -    else
   5.483 -        assert(needed->primitive() == node->type()->primitive());
   5.484 -}
   5.485 -
   5.486 -static inline Type *
   5.487 -GetCoercionType(TokenKind tok, Type *left, Type *right)
   5.488 -{
   5.489 -    if (left->isFloat())
   5.490 -        return left;
   5.491 -    return right;
   5.492 -}
   5.493 -
   5.494 -void
   5.495 -BytecodeCompiler::visit(UnaryExpression *node)
   5.496 -{
   5.497 -    Local<Type> out(zone_, ((Expression *)node)->type());
   5.498 -
   5.499 -    switch (node->token()) {
   5.500 -      case TOK_MINUS:
   5.501 -      {
   5.502 -        Local<Type> type(zone_, node->expression()->type());
   5.503 -        node->expression()->accept(this);
   5.504 -        
   5.505 -        if (out->isFloat())
   5.506 -            __ neg_f();
   5.507 -        else
   5.508 -            __ neg();
   5.509 -        break;
   5.510 -      }
   5.511 -
   5.512 -      case TOK_NOT:
   5.513 -      {
   5.514 -        Local<Type> type(zone_, node->expression()->type());
   5.515 -        node->expression()->accept(this);
   5.516 -        
   5.517 -        if (out->isFloat())
   5.518 -            __ not_f();
   5.519 -        else
   5.520 -            __ not_();
   5.521 -        break;
   5.522 -      }
   5.523 -
   5.524 -      case TOK_LABEL:
   5.525 -      {
   5.526 -        Local<Type> from(zone_, node->expression()->type());
   5.527 -
   5.528 -        node->expression()->accept(this);
   5.529 -        if (!from->isFloat() && out->isFloat())
   5.530 -            __ bits_f2i();
   5.531 -        else if (from->isFloat() && !out->isFloat())
   5.532 -            __ bits_i2f();
   5.533 -        break;
   5.534 -      }
   5.535 -
   5.536 -      case TOK_SIZEOF:
   5.537 -      {
   5.538 -        Local<Type> type(zone_, node->expression()->type());
   5.539 -        if (type->isFixedLength()) {
   5.540 -            __ int_(type->fixedLength());
   5.541 -        } else {
   5.542 -            node->expression()->accept(this);
   5.543 -            __ sizeof_();
   5.544 -        }
   5.545 -        break;
   5.546 -      }
   5.547 -
   5.548 -      default:
   5.549 -        assert(node->token() == TOK_TILDE);
   5.550 -        node->expression()->accept(this);
   5.551 -        __ bitnot();
   5.552 -        break;
   5.553 -    }
   5.554 -}
   5.555 -
   5.556 -void
   5.557 -BytecodeCompiler::visit(BinaryExpression *node)
   5.558 -{
   5.559 -    if (node->token() == TOK_AND || node->token() == TOK_OR) {
   5.560 -        Label success, failure, done;
   5.561 -        visitForTest(node, &success, &failure, &success);
   5.562 -        __ bind(&success);
   5.563 -        __ int_(1);
   5.564 -        __ drop(1);         // Otherwise, the stack depth will be +1 too much.
   5.565 -        __ jump(&done);
   5.566 -        __ bind(&failure);
   5.567 -        __ int_(0);
   5.568 -        __ bind(&done);
   5.569 -        return;
   5.570 -    }
   5.571 -
   5.572 -    Local<Type> leftType(zone_, node->left()->type());
   5.573 -    Local<Type> rightType(zone_, node->right()->type());
   5.574 -    Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
   5.575 -
   5.576 -    visitForALU(coerce, node->left());
   5.577 -    visitForALU(coerce, node->right());
   5.578 -
   5.579 -    Opcode op = TokenToOpcode(node->token());
   5.580 -    if (node->type()->isFloat())
   5.581 -        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
   5.582 -
   5.583 -    __ note_position(node->pos());
   5.584 -    __ binary(op);
   5.585 -}
   5.586 -
   5.587 -void
   5.588 -BytecodeCompiler::visit(IndexExpression *node)
   5.589 -{
   5.590 -    node->left()->accept(this);
   5.591 -    node->right()->accept(this);
   5.592 -    __ note_position(node->pos());
   5.593 -    __ getelem(node->type());
   5.594 -}
   5.595 -
   5.596 -void
   5.597 -BytecodeCompiler::visit(FieldExpression *node)
   5.598 -{
   5.599 -    node->left()->accept(this);
   5.600 -    __ getfield(node->fieldIndex(), node->type());
   5.601 -}
   5.602 -
   5.603 -void
   5.604 -BytecodeCompiler::visit(ReturnStatement *node)
   5.605 -{
   5.606 -    if (node->expression()) {
   5.607 -        node->expression()->accept(this);
   5.608 -        __ return_();
   5.609 -    } else {
   5.610 -        __ returnvoid();
   5.611 -    }
   5.612 -}
   5.613 -
   5.614 -void
   5.615 -BytecodeCompiler::visitForTest(Expression *expression,
   5.616 -                               Label *trueBranch,
   5.617 -                               Label *falseBranch,
   5.618 -                               Label *fallthrough)
   5.619 -{
   5.620 -    TokenKind token = ToCompare(expression);
   5.621 -    if (token == TOK_EOF || token == TOK_NOT) {
   5.622 -        if (token == TOK_EOF)
   5.623 -            expression->accept(this);
   5.624 -        else
   5.625 -            expression->toUnaryExpression()->expression()->accept(this);
   5.626 -        
   5.627 -        bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
   5.628 -
   5.629 -        Opcode op = jumpOnTrue ? OP_JT : OP_JF;
   5.630 -        if (expression->type()->isFloat())
   5.631 -            op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
   5.632 -
   5.633 -        if (fallthrough == falseBranch)
   5.634 -            __ j(op, trueBranch);
   5.635 -        else
   5.636 -            __ j(op, falseBranch); 
   5.637 -        return;
   5.638 -    }
   5.639 -
   5.640 -    BinaryExpression *binary = expression->toBinaryExpression();
   5.641 -
   5.642 -    if (token == TOK_AND || token == TOK_OR) {
   5.643 -        Label next;
   5.644 -        if (token == TOK_AND)
   5.645 -            visitForTest(binary->left(), &next, falseBranch, &next);
   5.646 -        else
   5.647 -            visitForTest(binary->left(), trueBranch, &next, &next);
   5.648 -        __ bind(&next);
   5.649 -        visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
   5.650 -        return;
   5.651 -    }
   5.652 -
   5.653 -    Opcode op = CompareTokenToJump(token);
   5.654 -    if (fallthrough == trueBranch)
   5.655 -        op = Invert(op);
   5.656 -
   5.657 -    Local<Type> leftType(zone_, binary->left()->type());
   5.658 -    Local<Type> rightType(zone_, binary->right()->type());
   5.659 -    Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
   5.660 -
   5.661 -    visitForALU(coerce, binary->left());
   5.662 -    visitForALU(coerce, binary->right());
   5.663 -    if (coerce->isFloat())
   5.664 -        op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
   5.665 -
   5.666 -    if (fallthrough == trueBranch)
   5.667 -        __ j(op, falseBranch);
   5.668 -    else
   5.669 -        __ j(op, trueBranch);
   5.670 -}
   5.671 -
   5.672 -void
   5.673 -BytecodeCompiler::visit(ForStatement *node)
   5.674 -{
   5.675 -    AutoEnterScope forScope(this, node->scope());
   5.676 -
   5.677 -    recordLifoSlot(node->scope());
   5.678 -
   5.679 -    Label join, update;
   5.680 -    LoopScope loop(scope_, &join, &update, &loop_);
   5.681 -
   5.682 -    if (node->initialization())
   5.683 -        node->initialization()->accept(this);
   5.684 -
   5.685 -    Label header, test;
   5.686 -    if (node->condition())
   5.687 -        __ jump(&test);
   5.688 -
   5.689 -    __ bind(&header);
   5.690 -    node->body()->accept(this);
   5.691 -
   5.692 -    __ bind(&update);
   5.693 -    if (node->update())
   5.694 -        node->update()->accept(this);
   5.695 -
   5.696 -    if (node->condition()) {
   5.697 -        __ bind(&test);
   5.698 -        visitForTest(node->condition(), &header, &join, &join);
   5.699 -    } else {
   5.700 -        __ jump(&header);
   5.701 -    }
   5.702 -
   5.703 -    __ bind(&join);
   5.704 -
   5.705 -    if (node->scope())
   5.706 -        unwindTo(node->scope()->enclosing());
   5.707 -    assert(__ stackDepth() == 0);
   5.708 -}
   5.709 -
   5.710 -void
   5.711 -BytecodeCompiler::visit(WhileStatement *node)
   5.712 -{
   5.713 -    Label header, join;
   5.714 -
   5.715 -    __ bind(&header);
   5.716 -
   5.717 -    LoopScope loop(scope_, &join, &header, &loop_);
   5.718 -
   5.719 -    if (node->token() == TOK_WHILE) {
   5.720 -        Label body;
   5.721 -
   5.722 -        visitForTest(node->condition(), &body, &join, &body);
   5.723 -        __ bind(&body);
   5.724 -        node->body()->accept(this);
   5.725 -        __ jump(&header);
   5.726 -    } else {
   5.727 -        node->body()->accept(this);
   5.728 -        visitForTest(node->condition(), &header, &join, &join);
   5.729 -    }
   5.730 -
   5.731 -    __ bind(&join);
   5.732 -}
   5.733 -
   5.734 -void
   5.735 -BytecodeCompiler::visit(BreakStatement *node)
   5.736 -{
   5.737 -    unwindTo(loop_->scope());
   5.738 -    __ jump(loop_->break_());
   5.739 -}
   5.740 -
   5.741 -void
   5.742 -BytecodeCompiler::visit(ContinueStatement *node)
   5.743 -{
   5.744 -    unwindTo(loop_->scope());
   5.745 -    __ jump(loop_->continue_());
   5.746 -}
   5.747 -
   5.748 -void
   5.749 -BytecodeCompiler::visit(BlockStatement *node)
   5.750 -{
   5.751 -    AutoEnterScope blockScope(this, node->scope());
   5.752 -
   5.753 -    recordLifoSlot(node->scope());
   5.754 -
   5.755 -    for (size_t i = 0; i < node->statements()->length(); i++) {
   5.756 -        Statement *statement = node->statements()->at(i);
   5.757 -        statement->accept(this);
   5.758 -        assert(__ stackDepth() == 0);
   5.759 -    }
   5.760 -
   5.761 -    // We don't bother emitting an "unwind" instruction for function scopes,
   5.762 -    // since this is taken care of by the calling convention.
   5.763 -    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
   5.764 -        unwindTo(node->scope()->enclosing());
   5.765 -}
   5.766 -
   5.767 -void
   5.768 -BytecodeCompiler::visit(IntegerLiteral *node)
   5.769 -{
   5.770 -    __ int_(node->value());
   5.771 -}
   5.772 -
   5.773 -void
   5.774 -BytecodeCompiler::visit(BooleanLiteral *node)
   5.775 -{
   5.776 -    if (node->token() == TOK_TRUE)
   5.777 -        __ true_();
   5.778 -    else
   5.779 -        __ false_();
   5.780 -}
   5.781 -
   5.782 -void
   5.783 -BytecodeCompiler::visit(FloatLiteral *node)
   5.784 -{
   5.785 -    __ float_((float)node->value());
   5.786 -}
   5.787 -
   5.788 -void
   5.789 -BytecodeCompiler::visit(StringLiteral *node)
   5.790 -{
   5.791 -    Local<Array> array(zone_, StringLiteralToArray(zone_, node));
   5.792 -    if (!array)
   5.793 -        return;
   5.794 -
   5.795 -    __ note_position(node->pos());
   5.796 -    __ object(array);
   5.797 -}
   5.798 -
   5.799 -void
   5.800 -BytecodeCompiler::getEnvSlot(Variable *var)
   5.801 -{
   5.802 -    assert(var->scope()->kind() == Scope::GLOBAL);
   5.803 -    __ getglobal(var);
   5.804 -}
   5.805 -
   5.806 -void
   5.807 -BytecodeCompiler::setEnvSlot(Variable *var)
   5.808 -{
   5.809 -    assert(var->scope()->kind() == Scope::GLOBAL);
   5.810 -    __ setglobal(var);
   5.811 -}
   5.812 -
   5.813 -static bool
   5.814 -FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
   5.815 -{
   5.816 -    Local<Array> string(zone);
   5.817 -    for (size_t i = 0; i < literal->expressions()->length(); i++) {
   5.818 -        Expression *expr = literal->expressions()->at(i);
   5.819 -        StringLiteral *lit = expr->toStringLiteral();
   5.820 -        if ((string = StringLiteralToArray(zone, lit)) == NULL)
   5.821 -            return false;
   5.822 -
   5.823 -        array->writeObject(zone, i, string);
   5.824 -
   5.825 -        if (string->length() > *maxsize)
   5.826 -            *maxsize = string->length();
   5.827 -
   5.828 -        assert(!array->type()->contained()->isFixedLength() ||
   5.829 -                array->type()->contained()->fixedLength() >= string->length());
   5.830 -    }
   5.831 -
   5.832 -    return true;
   5.833 -}
   5.834 -
   5.835 -static bool
   5.836 -FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
   5.837 -{
   5.838 -    assert(array->type()->fixedLength() == literal->expressions()->length());
   5.839 -
   5.840 -    for (size_t i = 0; i < literal->expressions()->length(); i++) {
   5.841 -        Expression *expr = literal->expressions()->at(i);
   5.842 -        if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
   5.843 -            array->writeInt32(i, lit->value());
   5.844 -            continue;
   5.845 -        }
   5.846 -        if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
   5.847 -            if (lit->token() == TOK_TRUE)
   5.848 -                array->writeInt32(i, 1);
   5.849 -            else
   5.850 -                array->writeInt32(i, 0);
   5.851 -            continue;
   5.852 -        }
   5.853 -        if (FloatLiteral *lit = expr->asFloatLiteral()) {
   5.854 -            array->writeFloat(i, lit->value());
   5.855 -            continue;
   5.856 -        }
   5.857 -
   5.858 -        // Unrecognized literal type.
   5.859 -        assert(false);
   5.860 -    }
   5.861 -
   5.862 -    return true;
   5.863 -}
   5.864 -
   5.865 -static bool
   5.866 -TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
   5.867 -                     unsigned *maxsize)
   5.868 -{
   5.869 -    assert(type->fixedLength() == literal->expressions()->length());
   5.870 -
   5.871 -    Local<Type> contained(zone, type->contained());
   5.872 -    if (contained->isCharArray())
   5.873 -        return FillArrayLiteral_String(zone, array, literal, maxsize);
   5.874 -
   5.875 -    if (!contained->isArray())
   5.876 -        return FillArrayLiteral_Primitive(zone, array, literal);
   5.877 -
   5.878 -    Local<Array> subarray(zone);
   5.879 -    for (size_t i = 0; i < literal->expressions()->length(); i++) {
   5.880 -        Expression *expr = literal->expressions()->at(i);
   5.881 -        subarray = Array::cast(array->readObject(i));
   5.882 -        if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
   5.883 -            return false;
   5.884 -    }
   5.885 -
   5.886 -    return true;
   5.887 -}
   5.888 -
   5.889 -static Array *
   5.890 -BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
   5.891 -{
   5.892 -    Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
   5.893 -    if (!root)
   5.894 -        return NULL;
   5.895 -
   5.896 -    // This should have allocated everything in the array, so all we need to
   5.897 -    // do is traverse down to the lowest levels and copy things.
   5.898 -    Local<Type> type(zone, map->type());
   5.899 -    if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
   5.900 -        return NULL;
   5.901 -
   5.902 -    return root;
   5.903 -}
   5.904 -
   5.905 -static inline bool
   5.906 -ArrayContainsCharBuffers(Type *type)
   5.907 -{
   5.908 -    if (type->contained()->isArray())
   5.909 -        return ArrayContainsCharBuffers(type->contained());
   5.910 -    return type->isCharArray();
   5.911 -}
   5.912 -
   5.913 -void
   5.914 -BytecodeCompiler::visit(VariableDeclaration *node)
   5.915 -{
   5.916 -    Variable *var = node->variable();
   5.917 -    
   5.918 -    Local<Type> type(zone_, var->type());
   5.919 -    if (type->isArray()) {
   5.920 -        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
   5.921 -        __ note_position(node->pos());
   5.922 -
   5.923 -        Local<Type> right(zone_);
   5.924 -        if (node->initialization())
   5.925 -            right = node->initialization()->type();
   5.926 -
   5.927 -        // There are a few methods for allocating, here:
   5.928 -        // (1) If the array is fixed,
   5.929 -        //    (a) Initializer not present,
   5.930 -        //              NEWFIXED
   5.931 -        //    (b) Left is const non-string:
   5.932 -        //              <nothing>
   5.933 -        //    (b) Otherwise:
   5.934 -        //              NEWFIXED
   5.935 -        //              COPYARRAY
   5.936 -        // (2) If the array is not fixed,
   5.937 -        //    (a) Initializer is not present,
   5.938 -        //              NEWEMPTY
   5.939 -        //    (b) Initializer is not a string literal,
   5.940 -        //        or left is const:
   5.941 -        //              <nothing>
   5.942 -        //    (c) Initializer is a string literal,
   5.943 -        //              NEWSIZED
   5.944 -        //              COPYARRAY
   5.945 -        //
   5.946 -
   5.947 -        Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
   5.948 -                              ? Heap::Tenure_Old
   5.949 -                              : Heap::Tenure_Default;
   5.950 -
   5.951 -        if (Expression *init = node->initialization()) {
   5.952 -            if (init->isArrayLiteral()) {
   5.953 -                unsigned maxsize = 0;
   5.954 -                Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
   5.955 -                if (!array)
   5.956 -                    return;
   5.957 -
   5.958 -                assert(type->isFixedLength());
   5.959 -
   5.960 -                if (type->isConst()) {
   5.961 -                    __ object(array);
   5.962 -                } else if (ArrayContainsCharBuffers(type)) {
   5.963 -                    // This array contains mutable char buffers, so
   5.964 -                    // unfortunately this gets a little more complicated. We
   5.965 -                    // compute the maximum size needed for the innermost
   5.966 -                    // string, which is similar to SP1. This means we can use
   5.967 -                    // CopyArray rather than individually emit opcodes to clone
   5.968 -                    // every string.
   5.969 -                    Local<Type> child(zone_, type);
   5.970 -                    for (size_t i = 0; i < type->levels() - 1; i++) {
   5.971 -                        __ int_(child->fixedLength());
   5.972 -                        child = child->contained();
   5.973 -                    }
   5.974 -                    __ int_(maxsize);
   5.975 -                    __ newarray(OP_NEWSIZED, map, tenure);
   5.976 -                    __ object(array);
   5.977 -                    __ copyarray();
   5.978 -                } else {
   5.979 -                    __ newarray(OP_NEWFIXED, map, tenure);
   5.980 -                    __ object(array);
   5.981 -                    __ copyarray();
   5.982 -                }
   5.983 -            } else if (type->isFixedLength()) {
   5.984 -                // Note in the case of:
   5.985 -                // const String:buffer[50] = "hello";
   5.986 -                //
   5.987 -                // We want to preserve sizeof(buffer) == 50.
   5.988 -                if (type->isConst() && !type->isCharArray()) {
   5.989 -                    init->accept(this);
   5.990 -                } else {
   5.991 -                    __ newarray(OP_NEWFIXED, map, tenure);
   5.992 -                    init->accept(this);
   5.993 -                    __ copyarray();
   5.994 -                }
   5.995 -            } else if (!type->isConst() && init->isStringLiteral()) {
   5.996 -                // This is a degenerate case of ArrayLiteral.
   5.997 -                __ int_(right->fixedLength());
   5.998 -                __ newarray(OP_NEWSIZED, map, tenure);
   5.999 -                init->accept(this);
  5.1000 -                __ copyarray();
  5.1001 -            } else if (type->isConst()) {
  5.1002 -                init->accept(this);
  5.1003 -            }
  5.1004 -        } else if (type->isFixedLength()) {
  5.1005 -            __ newarray(OP_NEWFIXED, map, tenure);
  5.1006 -        } else {
  5.1007 -            if (node->postDimensions()) {
  5.1008 -                for (size_t i = 0; i < node->postDimensions()->length(); i++) {
  5.1009 -                    Expression *expr = node->postDimensions()->at(i);
  5.1010 -                    if (expr)
  5.1011 -                        expr->accept(this);
  5.1012 -                    else
  5.1013 -                        __ int_(0);
  5.1014 -                }
  5.1015 -                __ newarray(OP_NEWSIZED, map, tenure);
  5.1016 -            } else {
  5.1017 -                __ newarray(OP_NEWEMPTY, map, tenure);
  5.1018 -            }
  5.1019 -        }
  5.1020 -    } else if (type->isStruct()) {
  5.1021 -        Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
  5.1022 -
  5.1023 -        // Because structs can contain arrays, any sort of composition
  5.1024 -        // triggers non-LIFO allocation. This is just for correctness.
  5.1025 -        // We could do better by:
  5.1026 -        //  (1) Limiting to structs that just (recursively) contain arrays,
  5.1027 -        //  (2) Swap Stack for Default tenure in Struct::New
  5.1028 -        //  (3) JIT analysis
  5.1029 -        if (var->scope()->kind() == Scope::GLOBAL)
  5.1030 -            __ newstruct(map, Heap::Tenure_Old);
  5.1031 -        else if (var->needsHeapAllocation() || map->composed())
  5.1032 -            __ newstruct(map, Heap::Tenure_Default);
  5.1033 -        else
  5.1034 -            __ newstruct(map, Heap::Tenure_Stack);
  5.1035 -    } else {
  5.1036 -        if (node->initialization()) {
  5.1037 -            node->initialization()->accept(this);
  5.1038 -        } else {
  5.1039 -            if (type->isInt32OrEnum() || type->isBool()) {
  5.1040 -                __ int_(0);
  5.1041 -            } else {
  5.1042 -                assert(type->isFloat());
  5.1043 -                __ float_(0);
  5.1044 -            }
  5.1045 -        }
  5.1046 -    }
  5.1047 -
  5.1048 -    if (var->location() == Variable::STACK) {
  5.1049 -        __ setlocal(var);
  5.1050 -        locals_->set(zone_, var->slot(), var->type());
  5.1051 -    } else {
  5.1052 -        assert(var->location() == Variable::ENVIRONMENT);
  5.1053 -        setEnvSlot(var);
  5.1054 -    }
  5.1055 -
  5.1056 -    __ pop();
  5.1057 -}
  5.1058 -
  5.1059 -void
  5.1060 -BytecodeCompiler::visit(CallExpression *node)
  5.1061 -{
  5.1062 -    Local<Type> funType(zone_, node->callee()->type());
  5.1063 -
  5.1064 -    // Sniff out natives, which have a specific opcode and are guaranteed to
  5.1065 -    // be called via name proxy.
  5.1066 -    NamedFunction *native = NULL;
  5.1067 -    if (funType->isNative())
  5.1068 -        native = node->callee()->toNameProxy()->binding()->toNamedFunction();
  5.1069 -
  5.1070 -    Local<Type> given(zone_);
  5.1071 -    for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
  5.1072 -        Expression *arg = node->arguments()->at(i);
  5.1073 -
  5.1074 -        given = arg->type();
  5.1075 -
  5.1076 -        // We need to compute a reference if the parameter was in the form:
  5.1077 -        //  f(&a)
  5.1078 -        // Note this form does not allow: f({})
  5.1079 -        // 
  5.1080 -        // We also need to compute references for all variadic native
  5.1081 -        // arguments, but arrays and references are already in the
  5.1082 -        // appropriate form.
  5.1083 -        bool mustPushReference = false;
  5.1084 -        if (i >= funType->parameters()->length()) {
  5.1085 -            assert(funType->isNative() && funType->isNativeVariadic());
  5.1086 -            mustPushReference = !given->isArray() && !given->isReference();
  5.1087 -        } else if (funType->parameterAt(i)->isReference()) {
  5.1088 -            mustPushReference = !given->isReference();
  5.1089 -        }
  5.1090 -
  5.1091 -        // If a native is passed to a native, it must only be one level deep.
  5.1092 -        assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
  5.1093 -
  5.1094 -        if (mustPushReference) {
  5.1095 -            if (arg->isNameProxy()) {
  5.1096 -                // :TODO: test with functions and globals
  5.1097 -                // Compute a reference to the name.
  5.1098 -                Variable *var = arg->toNameProxy()->binding()->toVariable();
  5.1099 -                __ note_position(node->pos());
  5.1100 -                __ newref(var);
  5.1101 -            } else if (arg->isFieldExpression()) {
  5.1102 -                FieldExpression *expr = arg->toFieldExpression();
  5.1103 -                expr->left()->accept(this);
  5.1104 -                __ note_position(expr->pos());
  5.1105 -                __ fieldref_lifo(expr->fieldIndex());
  5.1106 -            } else {
  5.1107 -                // We don't know how to, or can't, build a direct reference to
  5.1108 -                // this type. Make an indirect one, by taking the top of the
  5.1109 -                // stack and boxing it up.
  5.1110 -                arg->accept(this);
  5.1111 -                __ note_position(node->pos());
  5.1112 -                __ slotref_lifo();
  5.1113 -            }
  5.1114 -        } else {
  5.1115 -            arg->accept(this);
  5.1116 -        }
  5.1117 -    }
  5.1118 -
  5.1119 -    unsigned argc = node->arguments()->length();
  5.1120 -
  5.1121 -    // If there are missing arguments, then we're not done and have to push
  5.1122 -    // default parameters.
  5.1123 -    Local<Box> box(zone_);
  5.1124 -    Local<Array> array(zone_);
  5.1125 -    Local<ArrayMap> map(zone_);
  5.1126 -    for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
  5.1127 -        box = Box::cast(funType->defaults()->at(i));
  5.1128 -
  5.1129 -        if (box->type()->isPod()) {
  5.1130 -            if (box->type()->pod() == PrimitiveType_Int32)
  5.1131 -                __ int_(box->toInt32());
  5.1132 -            else if (box->type()->pod() == PrimitiveType_Float)
  5.1133 -                __ float_(box->toFloat());
  5.1134 -            else
  5.1135 -                assert(false);
  5.1136 -
  5.1137 -            if (funType->parameterAt(i)->isReference()) {
  5.1138 -                __ note_position(node->pos());
  5.1139 -                __ slotref_lifo();
  5.1140 -            }
  5.1141 -        } else {
  5.1142 -            assert(box->type()->isArray());
  5.1143 -
  5.1144 -            array = Array::cast(box->toObject());
  5.1145 -            if (funType->parameterAt(i)->isConst()) {
  5.1146 -                __ object(array);
  5.1147 -            } else {
  5.1148 -                // We need to copy the array since it's mutable. Note that
  5.1149 -                // although COPYARRAY returns its left-hand side, this may
  5.1150 -                // change in the future, we do the same thing and dupe the
  5.1151 -                // newly allocated array.
  5.1152 -                map = ArrayMap::cast(array->map());
  5.1153 -                
  5.1154 -                // Natives cannot escape array references, so we can allocate
  5.1155 -                // them on the LIFO stack.
  5.1156 -                if (funType->isNative())
  5.1157 -                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
  5.1158 -                else
  5.1159 -                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
  5.1160 -                __ dup();
  5.1161 -                __ object(array);
  5.1162 -                __ copyarray();
  5.1163 -                __ pop();
  5.1164 -            }
  5.1165 -        }
  5.1166 -
  5.1167 -        argc++;
  5.1168 -    }
  5.1169 -
  5.1170 -    __ note_position(node->pos());
  5.1171 -    if (native) {
  5.1172 -        __ callnative(native->slot(), argc);
  5.1173 -        __ drop(argc);
  5.1174 -    } else {
  5.1175 -        node->callee()->accept(this);
  5.1176 -        __ call(funType);
  5.1177 -        __ drop(argc + 1);
  5.1178 -    }
  5.1179 -}
  5.1180 -
  5.1181 -void
  5.1182 -BytecodeCompiler::visit(TernaryExpression *node)
  5.1183 -{
  5.1184 -    Label success, failure, join;
  5.1185 -
  5.1186 -    visitForTest(node->condition(), &success, &failure, &success);
  5.1187 -    __ bind(&success);
  5.1188 -    node->left()->accept(this);
  5.1189 -    __ drop(1);
  5.1190 -    __ jump(&join);
  5.1191 -    __ bind(&failure);
  5.1192 -    node->right()->accept(this);
  5.1193 -    __ bind(&join);
  5.1194 -}
  5.1195 -
  5.1196 -void
  5.1197 -BytecodeCompiler::visit(IfStatement *node)
  5.1198 -{
  5.1199 -    Label join;
  5.1200 -    if (!node->ifFalse()) {
  5.1201 -        Label success;
  5.1202 -
  5.1203 -        visitForTest(node->condition(), &success, &join, &success);
  5.1204 -        __ bind(&success);
  5.1205 -        node->ifTrue()->accept(this);
  5.1206 -    } else {
  5.1207 -        Label success, next;
  5.1208 -
  5.1209 -        visitForTest(node->condition(), &success, &next, &success);
  5.1210 -        __ bind(&success);
  5.1211 -        node->ifTrue()->accept(this);
  5.1212 -        __ jump(&join);
  5.1213 -        __ bind(&next);
  5.1214 -        node->ifFalse()->accept(this);
  5.1215 -    }
  5.1216 -
  5.1217 -    __ bind(&join);
  5.1218 -}
  5.1219 -
  5.1220 -bool
  5.1221 -BytecodeCompiler::tableswitch(SwitchStatement *node)
  5.1222 -{
  5.1223 -    CaseValueList *values = node->caseValueList();
  5.1224 -
  5.1225 -    if (values->length() < 3)
  5.1226 -        return false;
  5.1227 -
  5.1228 -    // Find the delta between the largest and smallest value.
  5.1229 -    int hi = values->at(values->length() - 1).box.toInt();
  5.1230 -    int lo = values->at(0).box.toInt();
  5.1231 -    assert(hi > lo);
  5.1232 -
  5.1233 -    unsigned tablesize = TableSwitchEntries(lo, hi);
  5.1234 -    if (tablesize > MAX_TABLESWITCH_ENTRIES)
  5.1235 -        return false;
  5.1236 -
  5.1237 -    Label def, join;
  5.1238 -
  5.1239 -    // Create the list of labels that each statement will bind to.
  5.1240 -    Label *labels = new Label[node->cases()->length()];
  5.1241 -
  5.1242 -    // Create the table of labels we'll use for each case.
  5.1243 -    Label **table = new Label *[tablesize];
  5.1244 -
  5.1245 -    // Link all cases, by default, to the default label.
  5.1246 -    for (size_t i = 0; i < tablesize; i++)
  5.1247 -        table[i] = &def;
  5.1248 -
  5.1249 -    // Now patch actual cases to their correct labels.
  5.1250 -    for (size_t i = 0; i < values->length(); i++) {
  5.1251 -        CaseValue &v = values->at(i);
  5.1252 -        assert(v.statement < node->cases()->length());
  5.1253 -
  5.1254 -        unsigned index = unsigned(v.box.toInt() - lo);
  5.1255 -        assert(index < tablesize);
  5.1256 -
  5.1257 -        table[index] = &labels[v.statement];
  5.1258 -    }
  5.1259 -
  5.1260 -    // Emit the tableswitch opcode and the jump table.
  5.1261 -    __ tableswitch(lo, hi, &def, table);
  5.1262 -
  5.1263 -    // We're done with the jump table now.
  5.1264 -    delete [] table;
  5.1265 -
  5.1266 -    // Emit each statement.
  5.1267 -    for (size_t i = 0; i < node->cases()->length(); i++) {
  5.1268 -        Statement *stmt = node->cases()->at(i)->statement();
  5.1269 -
  5.1270 -        __ bind(&labels[i]);
  5.1271 -        stmt->accept(this);
  5.1272 -        __ jump(&join);
  5.1273 -    }
  5.1274 -
  5.1275 -    // We're done with the statement labels.
  5.1276 -    delete [] labels;
  5.1277 -
  5.1278 -    // Emit the default case.
  5.1279 -    __ bind(&def);
  5.1280 -    if (node->defaultCase())
  5.1281 -        node->defaultCase()->accept(this);
  5.1282 -
  5.1283 -    __ bind(&join);
  5.1284 -
  5.1285 -    return true;
  5.1286 -}
  5.1287 -
  5.1288 -void
  5.1289 -BytecodeCompiler::visit(SwitchStatement *node)
  5.1290 -{
  5.1291 -    node->expression()->accept(this);
  5.1292 -
  5.1293 -    if (tableswitch(node))
  5.1294 -        return;
  5.1295 -
  5.1296 -    Label join;
  5.1297 -
  5.1298 -    for (size_t i = 0; i < node->cases()->length(); i++) {
  5.1299 -        Case *c = node->cases()->at(i);
  5.1300 -
  5.1301 -        Label success, fail;
  5.1302 -        if (c->others()) {
  5.1303 -            for (size_t j = 0; j < c->others()->length(); j++) {
  5.1304 -                Expression *expr = c->others()->at(j);
  5.1305 -
  5.1306 -                __ dup();
  5.1307 -                expr->accept(this);
  5.1308 -                __ j(OP_JEQ, &success);
  5.1309 -            }
  5.1310 -        }
  5.1311 -
  5.1312 -        // The final test.
  5.1313 -        __ dup();
  5.1314 -        c->expression()->accept(this);
  5.1315 -        __ j(OP_JNE, &fail);
  5.1316 -        __ bind(&success);
  5.1317 -        c->statement()->accept(this);
  5.1318 -        __ jump(&join);
  5.1319 -        __ bind(&fail);
  5.1320 -    }
  5.1321 -
  5.1322 -    if (node->defaultCase())
  5.1323 -        node->defaultCase()->accept(this);
  5.1324 -
  5.1325 -    __ pop();
  5.1326 -    __ bind(&join);
  5.1327 -}
  5.1328 -
  5.1329 -void
  5.1330 -BytecodeCompiler::visit(FunctionStatement *node)
  5.1331 -{
  5.1332 -    if (!node->fun()->used())
  5.1333 -        return;
  5.1334 -
  5.1335 -    if (node->fun()->isNative()) {
  5.1336 -        assert(!moduleData_->natives->at(node->fun()->slot()));
  5.1337 -
  5.1338 -        Local<Type> type(zone_, node->fun()->type());
  5.1339 -        Local<String> name(zone_, node->fun()->name());
  5.1340 -        Local<Native> native(zone_, Native::New(zone_, type, name));
  5.1341 -        if (!native)
  5.1342 -            return;
  5.1343 -
  5.1344 -        moduleData_->natives->set(zone_, node->fun()->slot(), native);
  5.1345 -        return;
  5.1346 -    }
  5.1347 -
  5.1348 -    // If the function has no body, then it's just a declaration.
  5.1349 -    if (!node->body()) {
  5.1350 -        assert(node->fun()->isForward() || node->fun()->isPublic());
  5.1351 -        return;
  5.1352 -    }
  5.1353 -
  5.1354 -    BytecodeCompiler child(zone_, tree_, moduleData_);
  5.1355 -    Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
  5.1356 -    if (!fun)
  5.1357 -        return;
  5.1358 -    
  5.1359 -    assert(!moduleData_->module->getFunction(node->fun()->slot()));
  5.1360 -    moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
  5.1361 -}
  5.1362 -
  5.1363 -void
  5.1364 -BytecodeCompiler::visit(FunctionTypeStatement *node)
  5.1365 -{
  5.1366 -}
  5.1367 -
  5.1368 -void
  5.1369 -BytecodeCompiler::visit(EnumStatement *node)
  5.1370 -{
  5.1371 -}
  5.1372 -
  5.1373 -void
  5.1374 -BytecodeCompiler::visit(StructureStatement *node)
  5.1375 -{
  5.1376 -}
  5.1377 -
  5.1378 -void
  5.1379 -BytecodeCompiler::visit(ArrayLiteral *node)
  5.1380 -{
  5.1381 -    // We shouldn't reach these; they're handled manually when initializing
  5.1382 -    // declared arrays.
  5.1383 -    assert(false);
  5.1384 -}
  5.1385 -
  5.1386 -Code *
  5.1387 -BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
  5.1388 -{
  5.1389 -    // STOP doubles as RETURNVOID.
  5.1390 -    __ stop();
  5.1391 -
  5.1392 -    if (__ oom() || zone_->hasPendingException())
  5.1393 -        return NULL;
  5.1394 -
  5.1395 -    Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
  5.1396 -    if (!bytes)
  5.1397 -        return NULL;
  5.1398 -    memcpy(bytes->raw(), __ buffer(), __ length());
  5.1399 -
  5.1400 -    for (size_t i = 0; i < scope->maxContainedLocals(); i++)
  5.1401 -        assert(locals_->at(i));
  5.1402 -
  5.1403 -    Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
  5.1404 -    if (!objects)
  5.1405 -        return NULL;
  5.1406 -
  5.1407 -    for (size_t i = 0; i < __ objects()->length(); i++)
  5.1408 -        objects->set(zone_, i, *(__ objects()->at(i)));
  5.1409 -
  5.1410 -    Local<ByteArray> safepoints(zone_);
  5.1411 -
  5.1412 -    // If any stack slots hold gc pointers at potential failure points in the
  5.1413 -    // bytecode, record them now. We do this by building a list of tuples;
  5.1414 -    // each tuple contains the pc offset, and a bitset containing which stack
  5.1415 -    // slots must be scanned by the gc.
  5.1416 -    if (__ oopRecords()->length()) {
  5.1417 -        size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
  5.1418 -        size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
  5.1419 -        safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
  5.1420 -        if (!safepoints)
  5.1421 -            return NULL;
  5.1422 -
  5.1423 -        Address cursor = safepoints->raw();
  5.1424 -        for (size_t i = 0; i < __ oopRecords()->length(); i++) {
  5.1425 -            OopRecord *record = __ oopRecords()->at(i);
  5.1426 -            assert(record->depth <= __ maxStackDepth());
  5.1427 -
  5.1428 -            *reinterpret_cast<unsigned *>(cursor) = record->offset;
  5.1429 -
  5.1430 -            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
  5.1431 -            for (unsigned i = 0; i < record->depth; i++)
  5.1432 -                bits[i / 8] |= (1 << (i % 8));
  5.1433 -
  5.1434 -            cursor += bytesPerSafepoint;
  5.1435 -        }
  5.1436 -
  5.1437 -        assert(cursor == safepoints->raw() + gcmapSize);
  5.1438 -    }
  5.1439 -
  5.1440 -    Local<ByteArray> sourcemap(zone_);
  5.1441 -    if (__ sourcemapLength()) {
  5.1442 -        sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
  5.1443 -        if (!sourcemap)
  5.1444 -            return NULL;
  5.1445 -
  5.1446 -        memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
  5.1447 -    }
  5.1448 -
  5.1449 -    Local<Code> code(zone_);
  5.1450 -
  5.1451 -    code = Code::New(zone_,
  5.1452 -                     bytes,
  5.1453 -                     locals_,
  5.1454 -                     objects,
  5.1455 -                     __ maxStackDepth(),
  5.1456 -                     moduleData_->module,
  5.1457 -                     safepoints,
  5.1458 -                     sourcemap,
  5.1459 -                     lineno);
  5.1460 -    return code;
  5.1461 -}
  5.1462 -
  5.1463 -Function *
  5.1464 -BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
  5.1465 -{
  5.1466 -    // Note: No need to record a life slot here, since it's part of the Frame.
  5.1467 -    AutoEnterScope functionScope(this, node->scope());
  5.1468 -
  5.1469 -    // Set the initial line, because line mappings are deltas.
  5.1470 -    __ setFirstLine(node->pos().line);
  5.1471 -    locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
  5.1472 -
  5.1473 -    node->body()->accept(this);
  5.1474 -
  5.1475 -    unsigned nargs = node->scope()->numArguments();
  5.1476 -    Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
  5.1477 -    if (!args)
  5.1478 -        return NULL;
  5.1479 -
  5.1480 -    for (size_t i = 0; i < node->scope()->numArguments(); i++)
  5.1481 -        args->set(zone_, i, node->scope()->getArgument(i)->type());
  5.1482 -
  5.1483 -
  5.1484 -    Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
  5.1485 -    if (!code)
  5.1486 -        return NULL;
  5.1487 -
  5.1488 -    Local<Type> type(zone_, node->fun()->type());
  5.1489 -    Local<String> name(zone_, node->fun()->name());
  5.1490 -    Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
  5.1491 -    if (!fun)
  5.1492 -        return NULL;
  5.1493 -
  5.1494 -    // If this function had a forward, export it as a named public.
  5.1495 -    if (node->fun()->isPublic()) {
  5.1496 -        assert(node->fun()->isPublic());
  5.1497 -        ScopedRoot<Function> root(fun);
  5.1498 -        if (!root)
  5.1499 -            return NULL;
  5.1500 -        if (!moduleData_->publics.append(root))
  5.1501 -            return NULL;
  5.1502 -    }
  5.1503 -
  5.1504 -#ifndef NDEBUG
  5.1505 -    Disassemble(code, stdout);
  5.1506 -#endif
  5.1507 -    
  5.1508 -    return fun;
  5.1509 -}
  5.1510 -
  5.1511 -Module *
  5.1512 -BytecodeCompiler::compile()
  5.1513 -{
  5.1514 -    AutoEnterScope scope(this, tree_->scope());
  5.1515 -
  5.1516 -    ModuleData moduleData;
  5.1517 -
  5.1518 -    moduleData_ = &moduleData;
  5.1519 -    moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
  5.1520 -
  5.1521 -    if (!moduleData_)
  5.1522 -        return NULL;
  5.1523 -    
  5.1524 -    moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
  5.1525 -    if (!moduleData_->natives)
  5.1526 -        return NULL;
  5.1527 -
  5.1528 -    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  5.1529 -        Statement *statement = tree_->statements()->at(i);
  5.1530 -        statement->accept(this);
  5.1531 -    }
  5.1532 -
  5.1533 -    if (zone_->hasPendingException())
  5.1534 -        return NULL;
  5.1535 -
  5.1536 -#ifndef NDEBUG
  5.1537 -    for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
  5.1538 -        assert(moduleData_->module->getFunction(i));
  5.1539 -    for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
  5.1540 -        assert(moduleData_->natives->at(i));
  5.1541 -#endif
  5.1542 -
  5.1543 -    if (moduleData_->publics.length()) {
  5.1544 -        Local<Function> fun(zone_);
  5.1545 -        Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
  5.1546 -                               Heap::Tenure_Old));
  5.1547 -        if (!list)
  5.1548 -            return NULL;
  5.1549 -
  5.1550 -        for (size_t i = 0; i < moduleData_->publics.length(); i++)
  5.1551 -            list->set(zone_, i, moduleData_->publics[i]);
  5.1552 -
  5.1553 -        moduleData_->module->setPublics(list);
  5.1554 -    }
  5.1555 -
  5.1556 -    moduleData_->module->setNatives(moduleData_->natives);
  5.1557 -
  5.1558 -    if (scope_->numEnvironmentVars()) {
  5.1559 -        Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
  5.1560 -        if (!globalMap)
  5.1561 -            return NULL;
  5.1562 -
  5.1563 -        Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
  5.1564 -        if (!environment)
  5.1565 -            return NULL;
  5.1566 -
  5.1567 -        moduleData_->module->setEnvironment(environment);
  5.1568 -    }
  5.1569 -
  5.1570 -    Local<Code> code(zone_, compileCode(tree_->scope(), 1));
  5.1571 -    if (!code)
  5.1572 -        return NULL;
  5.1573 -
  5.1574 -    Disassemble(code, stdout);
  5.1575 -
  5.1576 -    moduleData_->module->setCode(code);
  5.1577 -
  5.1578 -    return moduleData_->module;
  5.1579 -}
     6.1 --- a/src/BytecodeCompiler.h	Mon Sep 17 00:10:01 2012 -0700
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,159 +0,0 @@
     6.4 -/* vim: set ts=4 sw=4 tw=99 et:
     6.5 - *
     6.6 - * Copyright (C) 2012 David Anderson
     6.7 - *
     6.8 - * This file is part of JITCraft.
     6.9 - *
    6.10 - * JITCraft is free software: you can redistribute it and/or modify it under
    6.11 - * the terms of the GNU General Public License as published by the Free
    6.12 - * Software Foundation, either version 3 of the License, or (at your option)
    6.13 - * any later version.
    6.14 - * 
    6.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    6.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    6.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    6.18 - *
    6.19 - * You should have received a copy of the GNU General Public License along with
    6.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    6.21 - */
    6.22 -#ifndef _include_bytecode_compiler_h_
    6.23 -#define _include_bytecode_compiler_h_
    6.24 -
    6.25 -#include "AST.h"
    6.26 -#include "BytecodeEmitter.h"
    6.27 -#include "Functions.h"
    6.28 -
    6.29 -namespace ke {
    6.30 -
    6.31 -class Module;
    6.32 -class Array;
    6.33 -class ArrayMap;
    6.34 -
    6.35 -struct ModuleData
    6.36 -{
    6.37 -    ScopedRoot<Module> module;
    6.38 -    PoolList<ScopedRoot<Function> > publics;
    6.39 -    ScopedRoot<FixedArray> natives;
    6.40 -};
    6.41 -
    6.42 -class BytecodeCompiler : public AstVisitor
    6.43 -{
    6.44 -    Zone *zone_;
    6.45 -    ParseTree *tree_;
    6.46 -    BytecodeEmitter emitter_;
    6.47 -    ScopedRoot<FixedArray> locals_;
    6.48 -    Scope *scope_;
    6.49 -    ModuleData *moduleData_;
    6.50 -
    6.51 -    class LoopScope
    6.52 -    {
    6.53 -        Scope *scope_;
    6.54 -        BytecodeEmitter::Label *bk_;
    6.55 -        BytecodeEmitter::Label *ct_;
    6.56 -        LoopScope **prevp_;
    6.57 -        LoopScope *prev_;
    6.58 -
    6.59 -      public:
    6.60 -        LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
    6.61 -                  LoopScope **prevp)
    6.62 -          : scope_(scope),
    6.63 -            bk_(bk),
    6.64 -            ct_(ct),
    6.65 -            prevp_(prevp),
    6.66 -            prev_(*prevp)
    6.67 -        {
    6.68 -            *prevp_ = this;
    6.69 -        }
    6.70 -
    6.71 -        ~LoopScope()
    6.72 -        {
    6.73 -            *prevp_ = prev_;
    6.74 -        }
    6.75 -
    6.76 -        BytecodeEmitter::Label *break_() {
    6.77 -            return bk_;
    6.78 -        }
    6.79 -        BytecodeEmitter::Label *continue_() {
    6.80 -            return ct_;
    6.81 -        }
    6.82 -        Scope *scope() {
    6.83 -            return scope_;
    6.84 -        }
    6.85 -    };
    6.86 -
    6.87 -    LoopScope *loop_;
    6.88 -
    6.89 -  public:
    6.90 -    class AutoEnterScope
    6.91 -    {
    6.92 -        BytecodeCompiler *bc_;
    6.93 -        Scope *saved_;
    6.94 -
    6.95 -      public:
    6.96 -        AutoEnterScope(BytecodeCompiler *bc, Scope *scope)
    6.97 -          : bc_(bc),
    6.98 -            saved_(bc->scope_)
    6.99 -        {
   6.100 -            if (scope)
   6.101 -                bc->scope_ = scope;
   6.102 -        }
   6.103 -        ~AutoEnterScope() {
   6.104 -            bc_->scope_ = saved_;
   6.105 -        }
   6.106 -    };
   6.107 -
   6.108 -  private:
   6.109 -    void recordLifoSlot(Scope *scope);
   6.110 -    void unwindTo(Scope *scope);
   6.111 -    void visitForTest(Expression *expression,
   6.112 -                      BytecodeEmitter::Label *trueBranch,
   6.113 -                      BytecodeEmitter::Label *falseBranch,
   6.114 -                      BytecodeEmitter::Label *fallthrough);
   6.115 -    Code *compileCode(Scope *scope, unsigned lineno);
   6.116 -    Function *compileFunction(ModuleData *module, FunctionStatement *fun);
   6.117 -    void visitForALU(Type *needed, Expression *node);
   6.118 -
   6.119 -    void getEnvSlot(Variable *var);
   6.120 -    void setEnvSlot(Variable *var);
   6.121 -
   6.122 -    bool tableswitch(SwitchStatement *node);
   6.123 -
   6.124 -  public:
   6.125 -    BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
   6.126 -
   6.127 -    Module *compile();
   6.128 -
   6.129 -  public:
   6.130 -    void visit(NameProxy *name);
   6.131 -    void visit(Assignment *node);
   6.132 -    void visit(BinaryExpression *node);
   6.133 -    void visit(ReturnStatement *node);
   6.134 -    void visit(ForStatement *node);
   6.135 -    void visit(BlockStatement *node);
   6.136 -    void visit(VariableDeclaration *node);
   6.137 -    void visit(IntegerLiteral *node);
   6.138 -    void visit(BooleanLiteral *node);
   6.139 -    void visit(FloatLiteral *node);
   6.140 -    void visit(StringLiteral *node);
   6.141 -    void visit(ExpressionStatement *node);
   6.142 -    void visit(FunctionStatement *node);
   6.143 -    void visit(CallExpression *node);
   6.144 -    void visit(IfStatement *node);
   6.145 -    void visit(IndexExpression *node);
   6.146 -    void visit(EnumStatement *node);
   6.147 -    void visit(WhileStatement *node);
   6.148 -    void visit(BreakStatement *node);
   6.149 -    void visit(ContinueStatement *node);
   6.150 -    void visit(IncDecExpression *node);
   6.151 -    void visit(UnaryExpression *node);
   6.152 -    void visit(TernaryExpression *node);
   6.153 -    void visit(StructureStatement *node);
   6.154 -    void visit(FieldExpression *node);
   6.155 -    void visit(SwitchStatement *node);
   6.156 -    void visit(FunctionTypeStatement *node);
   6.157 -    void visit(ArrayLiteral *node);
   6.158 -};
   6.159 -
   6.160 -}
   6.161 -
   6.162 -#endif // _include_bytecode_generator_h_
     7.1 --- a/src/BytecodeEmitter.cpp	Mon Sep 17 00:10:01 2012 -0700
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,122 +0,0 @@
     7.4 -/* vim: set ts=4 sw=4 tw=99 et:
     7.5 - *
     7.6 - * Copyright (C) 2012 David Anderson
     7.7 - *
     7.8 - * This file is part of JITCraft.
     7.9 - *
    7.10 - * JITCraft is free software: you can redistribute it and/or modify it under
    7.11 - * the terms of the GNU General Public License as published by the Free
    7.12 - * Software Foundation, either version 3 of the License, or (at your option)
    7.13 - * any later version.
    7.14 - * 
    7.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    7.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    7.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    7.18 - *
    7.19 - * You should have received a copy of the GNU General Public License along with
    7.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    7.21 - */
    7.22 -#include <stdlib.h>
    7.23 -#include <string.h>
    7.24 -#include "BytecodeEmitter.h"
    7.25 -#include "Utility.h"
    7.26 -#include "Types.h"
    7.27 -#include "Zone.h"
    7.28 -#include "Spaces-inl.h"
    7.29 -#include "Heap-inl.h"
    7.30 -
    7.31 -using namespace ke;
    7.32 -
    7.33 -BytecodeEmitter::BytecodeEmitter(PoolAllocator &pool)
    7.34 -  : pool_(pool),
    7.35 -    buffer_(inline_buffer_),
    7.36 -    buffer_pos_(buffer_),
    7.37 -    buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
    7.38 -    oom_(false),
    7.39 -    maxStackDepth_(0)
    7.40 -{
    7.41 -    lastCodePosition_ = 0;
    7.42 -    firstLine_ = 1;
    7.43 -}
    7.44 -
    7.45 -bool
    7.46 -BytecodeEmitter::growBuffer(size_t nbytes)
    7.47 -{
    7.48 -    if (oom_) {
    7.49 -        buffer_pos_ = buffer_;
    7.50 -        return false;
    7.51 -    }
    7.52 -
    7.53 -    size_t newSize = size_t((buffer_end_ - buffer_) * 2);
    7.54 -    if (newSize >= MAX_LENGTH) {
    7.55 -        oom_ = true;
    7.56 -        buffer_pos_ = buffer_;
    7.57 -        ZONE()->reportOutOfMemory();
    7.58 -        return false;
    7.59 -    }
    7.60 -
    7.61 -    bytecode *newBuffer;
    7.62 -    if (buffer_ == inline_buffer_)
    7.63 -        newBuffer = (bytecode *)malloc(newSize);
    7.64 -    else
    7.65 -        newBuffer = (bytecode *)realloc(buffer_, newSize);
    7.66 -
    7.67 -    // If we can't allocate a buffer, reset the buffer to the start and set
    7.68 -    // a flag to indicate out-of-memory.
    7.69 -    if (!newBuffer) {
    7.70 -        oom_ = true;
    7.71 -        buffer_pos_ = buffer_;
    7.72 -        ZONE()->reportOutOfMemory();
    7.73 -        return false;
    7.74 -    }
    7.75 -
    7.76 -    if (buffer_ == inline_buffer_)
    7.77 -        memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
    7.78 -
    7.79 -    buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
    7.80 -    buffer_ = newBuffer;
    7.81 -    buffer_end_ = buffer_ + newSize;
    7.82 -    assert(buffer_pos_ + nbytes < buffer_end_);
    7.83 -
    7.84 -    return true;
    7.85 -}
    7.86 -
    7.87 -void
    7.88 -BytecodeEmitter::recordOops()
    7.89 -{
    7.90 -    OopRecord *record = new (pool_) OopRecord(oopMap_.length(), position());
    7.91 -
    7.92 -    record->slots = (bool *)pool_.allocate(record->depth);
    7.93 -    if (!record->slots) {
    7.94 -        oom_ = true;
    7.95 -        return;
    7.96 -    }
    7.97 -
    7.98 -    bool hadOops = false;
    7.99 -    for (size_t i = 0; i < oopMap_.length(); i++) {
   7.100 -        bool bit = oopMap_[i];
   7.101 -        record->slots[i] = bit;
   7.102 -        hadOops |= bit;
   7.103 -    }
   7.104 -
   7.105 -    if (!hadOops)
   7.106 -        return;
   7.107 -
   7.108 -    oom_ &= oopRecords_.append(record);
   7.109 -}
   7.110 -
   7.111 -void
   7.112 -BytecodeEmitter::note_position(const SourcePosition &pos)
   7.113 -{
   7.114 -    assert(pos.line > 0);
   7.115 -    assert(unsigned(pos.line) >= firstLine_);
   7.116 -
   7.117 -    unsigned lineDelta = unsigned(pos.line) - firstLine_;
   7.118 -    unsigned pcDelta = unsigned(position()) - lastCodePosition_;
   7.119 -
   7.120 -    sourcemap_.writeUint32(pcDelta);
   7.121 -    sourcemap_.writeUint32(lineDelta);
   7.122 -    sourcemap_.writeUint32(pos.col);
   7.123 -
   7.124 -    lastCodePosition_ = unsigned(position());
   7.125 -}
     8.1 --- a/src/BytecodeEmitter.h	Mon Sep 17 00:10:01 2012 -0700
     8.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.3 @@ -1,672 +0,0 @@
     8.4 -/* vim: set ts=4 sw=4 tw=99 et:
     8.5 - *
     8.6 - * Copyright (C) 2012 David Anderson
     8.7 - *
     8.8 - * This file is part of JITCraft.
     8.9 - *
    8.10 - * JITCraft is free software: you can redistribute it and/or modify it under
    8.11 - * the terms of the GNU General Public License as published by the Free
    8.12 - * Software Foundation, either version 3 of the License, or (at your option)
    8.13 - * any later version.
    8.14 - * 
    8.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    8.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    8.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    8.18 - *
    8.19 - * You should have received a copy of the GNU General Public License along with
    8.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    8.21 - */
    8.22 -#ifndef _include_bytecode_emitter_h_
    8.23 -#define _include_bytecode_emitter_h_
    8.24 -
    8.25 -#include <assert.h>
    8.26 -#include <limits.h>
    8.27 -#include "Opcodes.h"
    8.28 -#include "NameBinding.h"
    8.29 -#include "Handles.h"
    8.30 -#include "CompactBuffer.h"
    8.31 -#include "Array.h"
    8.32 -
    8.33 -namespace ke {
    8.34 -
    8.35 -class Type;
    8.36 -class Map;
    8.37 -class ArrayMap;
    8.38 -
    8.39 -typedef PoolList<ScopedRoot<Object> > ObjectList;
    8.40 -
    8.41 -struct OopRecord : public PoolObject
    8.42 -{
    8.43 -    unsigned depth;
    8.44 -    unsigned offset;
    8.45 -    bool *slots;
    8.46 -
    8.47 -    OopRecord(unsigned length, unsigned offset)
    8.48 -      : depth(length),
    8.49 -        offset(offset),
    8.50 -        slots(NULL)
    8.51 -    {
    8.52 -    }
    8.53 -};
    8.54 -
    8.55 -class BytecodeEmitter
    8.56 -{
    8.57 -  private:
    8.58 -    PoolAllocator &pool_;
    8.59 -
    8.60 -    bytecode *buffer_;
    8.61 -    bytecode *buffer_pos_;
    8.62 -    bytecode *buffer_end_;
    8.63 -    bytecode inline_buffer_[512];
    8.64 -    bool oom_;
    8.65 -    unsigned maxStackDepth_;
    8.66 -    ObjectList objects_;
    8.67 -    PoolList<bool> oopMap_;
    8.68 -    PoolList<OopRecord *> oopRecords_;
    8.69 -    CompactBufferWriter sourcemap_;
    8.70 -    unsigned lastCodePosition_;
    8.71 -    unsigned firstLine_;
    8.72 -
    8.73 -  private:
    8.74 -    // The maximum size of a code object must be such that the distance between
    8.75 -    // two instructions fits into a signed, 31-bit integer. This ensures that
    8.76 -    // all code-bounded buffers (like the number of object literals or
    8.77 -    // safepoints) does not need to be bounds checked. It also means we can add
    8.78 -    // any two offsets and be guaranteed that they don't overflow.
    8.79 -    static const size_t MAX_LENGTH = INT_MAX / 2;
    8.80 -
    8.81 -  private:
    8.82 -    bool growBuffer(size_t bytes);
    8.83 -
    8.84 -    // Checking the return value is not necessary, since the inline buffer is
    8.85 -    // used as a ballast.
    8.86 -    bool ensure(size_t bytes) {
    8.87 -        if (buffer_pos_ + bytes > buffer_end_)
    8.88 -            return growBuffer(bytes);
    8.89 -        return true;
    8.90 -    }
    8.91 -
    8.92 -    void writeUint8(unsigned value) {
    8.93 -        assert(value <= UCHAR_MAX);
    8.94 -        *buffer_pos_++ = value;
    8.95 -    }
    8.96 -    void writeFloat(float value) {
    8.97 -        *(float *)buffer_pos_ = value;
    8.98 -        buffer_pos_ += sizeof(float);
    8.99 -    }
   8.100 -    void writeInt32(int value) {
   8.101 -        *(int *)buffer_pos_ = value;
   8.102 -        buffer_pos_ += sizeof(int);
   8.103 -    }
   8.104 -    void writeUint32(unsigned value) {
   8.105 -        *(unsigned *)buffer_pos_ = value;
   8.106 -        buffer_pos_ += sizeof(unsigned);
   8.107 -    }
   8.108 -    void writeOp(Opcode op) {
   8.109 -        if (oom_)
   8.110 -            return;
   8.111 -
   8.112 -        writeUint8(op);
   8.113 -        for (int i = 0; i < OpcodeInfo[op].nuses; i++)
   8.114 -            oopMap_.pop();
   8.115 -        for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
   8.116 -            oopMap_.append(false);
   8.117 -        if (oopMap_.length() > maxStackDepth_)
   8.118 -            maxStackDepth_ = oopMap_.length();
   8.119 -    }
   8.120 -    void writeObject(Object *obj) {
   8.121 -        writeUint32(objects_.length());
   8.122 -        ScopedRoot<Object> root(obj);
   8.123 -        if (!objects_.append(root))
   8.124 -            oom_ = true;
   8.125 -    }
   8.126 -
   8.127 -    int position() const {
   8.128 -        assert(buffer_pos_ - buffer_ < INT_MAX / 2);
   8.129 -        return int(buffer_pos_ - buffer_);
   8.130 -    }
   8.131 -
   8.132 -  public:
   8.133 -    BytecodeEmitter(PoolAllocator &pool);
   8.134 -
   8.135 -    bytecode *buffer() const {
   8.136 -        return buffer_;
   8.137 -    }
   8.138 -    unsigned length() const {
   8.139 -        return unsigned(buffer_pos_ - buffer_);
   8.140 -    }
   8.141 -    bool oom() const {
   8.142 -        return oom_ || sourcemap_.oom();
   8.143 -    }
   8.144 -    unsigned stackDepth() const {
   8.145 -        return oopMap_.length();
   8.146 -    }
   8.147 -    unsigned maxStackDepth() const {
   8.148 -        return maxStackDepth_;
   8.149 -    }
   8.150 -    const ObjectList *objects() const {
   8.151 -        return &objects_;
   8.152 -    }
   8.153 -    PoolList<OopRecord *> *oopRecords() {
   8.154 -        return &oopRecords_;
   8.155 -    }
   8.156 -
   8.157 -    void drop(unsigned amt) {
   8.158 -        assert(amt <= stackDepth());
   8.159 -        for (unsigned i = 0; i < amt; i++)
   8.160 -            oopMap_.pop();
   8.161 -    }
   8.162 -
   8.163 -    void note_position(const SourcePosition &pos);
   8.164 -    uint8 *sourcemap() const {
   8.165 -        return sourcemap_.buffer();
   8.166 -    }
   8.167 -    size_t sourcemapLength() const {
   8.168 -        return sourcemap_.length();
   8.169 -    }
   8.170 -    void setFirstLine(unsigned line) {
   8.171 -        assert(!sourcemap_.length());
   8.172 -        firstLine_ = line;
   8.173 -    }
   8.174 -
   8.175 -  public:
   8.176 -    // A label represents a local control-flow target in the bytecode. A label
   8.177 -    // may be in three states:
   8.178 -    //
   8.179 -    // (1) Empty - the label is not used yet.
   8.180 -    // (2) Pending - the label has incoming jumps, but the actual location of
   8.181 -    //               is not yet known. The list of jumps is threaded through
   8.182 -    //               the four bytes reserved for each emitted jump target. In
   8.183 -    //               this case, the offset field is the location of the most
   8.184 -    //               recently emitted incoming jump.
   8.185 -    // (3) Bound   - the label's position has been pinned.
   8.186 -    //
   8.187 -    // A jump can be emitted to a label in any state. Binding a label
   8.188 -    // immediately backpatches all pending incoming jumps. A label must be
   8.189 -    // bound if it is used.
   8.190 -    class Label
   8.191 -    {
   8.192 -        int offset_ : 31;
   8.193 -        bool bound_ : 1;
   8.194 -
   8.195 -        void setOffset(int offset) {
   8.196 -            offset_ = offset;
   8.197 -            assert(offset_ == offset);
   8.198 -        }
   8.199 -
   8.200 -      public:
   8.201 -        static const int INVALID_OFFSET = -1;
   8.202 -
   8.203 -      public:
   8.204 -        Label()
   8.205 -          : offset_(INVALID_OFFSET),
   8.206 -            bound_(false)
   8.207 -        {
   8.208 -        }
   8.209 -        ~Label()
   8.210 -        {
   8.211 -            assert(bound_ || offset_ == INVALID_OFFSET);
   8.212 -        }
   8.213 -        
   8.214 -        bool bound() const {
   8.215 -            return bound_;
   8.216 -        }
   8.217 -        int offset() const {
   8.218 -            return offset_;
   8.219 -        }
   8.220 -        void bind(int offset) {
   8.221 -            assert(!bound_);
   8.222 -            setOffset(offset);
   8.223 -            bound_ = true;
   8.224 -        }
   8.225 -        int link(int offset) {
   8.226 -            assert(!bound_);
   8.227 -            int old = offset_;
   8.228 -            setOffset(offset);
   8.229 -            return old;
   8.230 -        }
   8.231 -    };
   8.232 -
   8.233 -  private:
   8.234 -    int patchJumpAt(int at, int to) {
   8.235 -        assert(at >= 0 && at < position());
   8.236 -        int old = *(int *)(buffer_ + at + 1);
   8.237 -        *(int *)(buffer_ + at + 1) = (to - at);
   8.238 -        return old;
   8.239 -    }
   8.240 -
   8.241 -    void singleByteOp(Opcode op) {
   8.242 -        assert(OpcodeInfo[op].length == 1);
   8.243 -        ensure(OpcodeInfo[op].length);
   8.244 -        writeOp(op);
   8.245 -    }
   8.246 -
   8.247 -    // Mark a stack slot as having an object pointer.
   8.248 -    void markOop(unsigned depth, bool oop = true) {
   8.249 -        if (oom_)
   8.250 -            return;
   8.251 -        oopMap_[oopMap_.length() - depth] = oop;
   8.252 -    }
   8.253 -    bool getOop(unsigned depth) {
   8.254 -        if (oom_)
   8.255 -            return false;
   8.256 -        return oopMap_[oopMap_.length() - depth];
   8.257 -    }
   8.258 -
   8.259 -    // Mark the current bytecode position as either re-entrant (meaning, it
   8.260 -    // can leave the interpreter or call to another function), or causing GC.
   8.261 -    // This will record which stack slots have objects and associate that
   8.262 -    // information with the current pc.
   8.263 -    void recordOops();
   8.264 -
   8.265 -  public:
   8.266 -    void int_(int value) {
   8.267 -        ensure(OP_INT);
   8.268 -        writeOp(OP_INT);
   8.269 -        writeInt32(value);
   8.270 -    }
   8.271 -    void return_() {
   8.272 -        ensure(OP_RETURN);
   8.273 -        writeOp(OP_RETURN);
   8.274 -    }
   8.275 -    void getlocal(Variable *var) {
   8.276 -        ensure(OP_GETLOCAL_LENGTH);
   8.277 -        writeOp(OP_GETLOCAL);
   8.278 -        writeUint32(var->slot());
   8.279 -
   8.280 -        if (var->type()->isTraceable())
   8.281 -            markOop(1);
   8.282 -    }
   8.283 -    void setlocal(Variable *var) {
   8.284 -        ensure(OP_SETLOCAL_LENGTH);
   8.285 -        writeOp(OP_SETLOCAL);
   8.286 -        writeUint32(var->slot());
   8.287 -
   8.288 -        if (var->type()->isTraceable())
   8.289 -            markOop(1);
   8.290 -    }
   8.291 -    void getarg(Variable *var) {
   8.292 -        ensure(OP_GETARG_LENGTH);
   8.293 -        writeOp(OP_GETARG);
   8.294 -        writeUint32(var->slot());
   8.295 -
   8.296 -        if (var->type()->isTraceable())
   8.297 -            markOop(1);
   8.298 -    }
   8.299 -    void setarg(Variable *var) {
   8.300 -        ensure(OP_SETARG_LENGTH);
   8.301 -        writeOp(OP_SETARG);
   8.302 -        writeUint32(var->slot());
   8.303 -
   8.304 -        if (var->type()->isTraceable())
   8.305 -            markOop(1);
   8.306 -    }
   8.307 -
   8.308 -    void j(Opcode op, Label *label) {
   8.309 -        // Since jumps can skip around the stream, do not try to do anything
   8.310 -        // in a potentially truncated state.
   8.311 -        if (oom())
   8.312 -            return;
   8.313 -
   8.314 -        assert(op >= OP_JL && op <= OP_JUMP);
   8.315 -        ensure(OP_JUMP_LENGTH);
   8.316 -
   8.317 -        if (label->bound()) {
   8.318 -            // We can immediately emit this jump.
   8.319 -            int distance = label->offset() - position();
   8.320 -            writeOp(op);
   8.321 -            writeInt32(distance);
   8.322 -        } else {
   8.323 -            // We can't emit this jump yet. Add a placeholder.
   8.324 -            int old = label->link(position());
   8.325 -            writeOp(op);
   8.326 -            writeInt32(old);
   8.327 -        }
   8.328 -    }
   8.329 -    void bind(Label *label) {
   8.330 -        if (oom())
   8.331 -            return;
   8.332 -
   8.333 -        assert(!label->bound());
   8.334 -
   8.335 -        int offset = label->offset();
   8.336 -        while (offset != Label::INVALID_OFFSET)
   8.337 -            offset = patchJumpAt(offset, position());
   8.338 -
   8.339 -        label->bind(position());
   8.340 -    }
   8.341 -    void jump(Label *label) {
   8.342 -        j(OP_JUMP, label);
   8.343 -    }
   8.344 -
   8.345 -    void binary(Opcode op) {
   8.346 -        singleByteOp(op);
   8.347 -    }
   8.348 -
   8.349 -    void pop() {
   8.350 -        singleByteOp(OP_POP);
   8.351 -    }
   8.352 -    void stop() {
   8.353 -        singleByteOp(OP_STOP);
   8.354 -    }
   8.355 -    void call(Handle<Type> fun) {
   8.356 -        recordOops();
   8.357 -        ensure(OP_CALL_LENGTH);
   8.358 -        writeOp(OP_CALL);
   8.359 -
   8.360 -        if (fun->returnType()->isVoid())
   8.361 -            drop(1);
   8.362 -        else if (fun->returnType()->isTraceable())
   8.363 -            markOop(1);
   8.364 -    }
   8.365 -    void callnative(unsigned index, unsigned argc) {
   8.366 -        recordOops();
   8.367 -        ensure(OP_CALLNATIVE_LENGTH);
   8.368 -        writeOp(OP_CALLNATIVE);
   8.369 -        writeUint32(index);
   8.370 -        writeUint32(argc);
   8.371 -    }
   8.372 -
   8.373 -    void getelem(Type *type) {
   8.374 -        singleByteOp(OP_GETELEM);
   8.375 -
   8.376 -        if (type->isTraceable())
   8.377 -            markOop(1);
   8.378 -    }
   8.379 -    void setelem(Type *type) {
   8.380 -        singleByteOp(OP_SETELEM);
   8.381 -    }
   8.382 -
   8.383 -    void getfield(unsigned index, Type *type) {
   8.384 -        ensure(OP_GETFIELD_LENGTH);
   8.385 -        writeOp(OP_GETFIELD);
   8.386 -        writeUint32(index);
   8.387 -
   8.388 -        if (type->isTraceable())
   8.389 -            markOop(1);
   8.390 -    }
   8.391 -    void setfield(unsigned index, Type *type) {
   8.392 -        ensure(OP_SETFIELD_LENGTH);
   8.393 -        writeOp(OP_SETFIELD);
   8.394 -        writeUint32(index);
   8.395 -
   8.396 -        if (type->isTraceable())
   8.397 -            markOop(1);
   8.398 -    }
   8.399 -
   8.400 -    void getglobal(Variable *var) {
   8.401 -        ensure(OP_GETGLOBAL_F_LENGTH);
   8.402 -        if (var->type()->isPrimitive()) {
   8.403 -            switch (var->type()->primitive()) {
   8.404 -              case PrimitiveType_Float:
   8.405 -                writeOp(OP_GETGLOBAL_F);
   8.406 -                break;
   8.407 -              default:
   8.408 -                assert(var->type()->primitive() == PrimitiveType_Int32);
   8.409 -                writeOp(OP_GETGLOBAL_I);
   8.410 -                break;
   8.411 -            }
   8.412 -        } else {
   8.413 -            writeOp(OP_GETGLOBAL_O);
   8.414 -            markOop(1);
   8.415 -        }
   8.416 -        writeUint32(var->slot());
   8.417 -    }
   8.418 -    void setglobal(Variable *var) {
   8.419 -        ensure(OP_SETGLOBAL_F_LENGTH);
   8.420 -        if (var->type()->isPrimitive()) {
   8.421 -            switch (var->type()->primitive()) {
   8.422 -              case PrimitiveType_Float:
   8.423 -                writeOp(OP_SETGLOBAL_F);
   8.424 -                break;
   8.425 -              default:
   8.426 -                assert(var->type()->primitive() == PrimitiveType_Int32);
   8.427 -                writeOp(OP_SETGLOBAL_I);
   8.428 -                break;
   8.429 -            }
   8.430 -        } else {
   8.431 -            writeOp(OP_SETGLOBAL_O);
   8.432 -        }
   8.433 -        writeUint32(var->slot());
   8.434 -    }
   8.435 -
   8.436 -    void float_(float value) {
   8.437 -        ensure(OP_FLOAT_LENGTH);
   8.438 -        writeOp(OP_FLOAT);
   8.439 -        writeFloat(value);
   8.440 -    }
   8.441 -    void cvt_i2f() {
   8.442 -        singleByteOp(OP_CVT_I2F);
   8.443 -    }
   8.444 -    void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
   8.445 -        assert(op == OP_NEWFIXED ||
   8.446 -               op == OP_NEWEMPTY ||
   8.447 -               op == OP_NEWSIZED);
   8.448 -
   8.449 -        recordOops();
   8.450 -        ensure(OpcodeInfo[op].length);
   8.451 -        writeOp(op);
   8.452 -        writeUint8(tenure);
   8.453 -        writeObject(map);
   8.454 -
   8.455 -        if (op == OP_NEWSIZED)
   8.456 -            drop(map->type()->levels());
   8.457 -
   8.458 -        markOop(1);
   8.459 -    }
   8.460 -    void newstruct(Handle<Map> map, Heap::Tenure tenure) {
   8.461 -        recordOops();
   8.462 -        ensure(OP_NEWSTRUCT_LENGTH);
   8.463 -        writeOp(OP_NEWSTRUCT);
   8.464 -        writeUint8(tenure);
   8.465 -        writeObject(map);
   8.466 -        markOop(1);
   8.467 -    }
   8.468 -    void savelifo(unsigned slot) {
   8.469 -        ensure(OP_SAVELIFO_LENGTH);
   8.470 -        writeOp(OP_SAVELIFO);
   8.471 -        writeUint32(slot);
   8.472 -    }
   8.473 -    void unwindlifo(unsigned slot) {
   8.474 -        ensure(OP_UNWINDLIFO_LENGTH);
   8.475 -        writeOp(OP_UNWINDLIFO);
   8.476 -        writeUint32(slot);
   8.477 -    }
   8.478 -    void newref(Variable *var) {
   8.479 -        recordOops();
   8.480 -        if (var->location() == Variable::STACK) {
   8.481 -            ensure(OP_VARREF_LIFO_LENGTH);
   8.482 -            writeOp(OP_VARREF_LIFO);
   8.483 -        } else {
   8.484 -            assert(var->location() == Variable::PARAMETER);
   8.485 -            ensure(OP_ARGREF_LIFO_LENGTH);
   8.486 -            writeOp(OP_ARGREF_LIFO);
   8.487 -        }
   8.488 -        writeUint32(var->slot());
   8.489 -        markOop(1);
   8.490 -    }
   8.491 -
   8.492 -    void slotref_lifo() {
   8.493 -        recordOops();
   8.494 -        singleByteOp(OP_SLOTREF_LIFO);
   8.495 -        markOop(1);
   8.496 -    }
   8.497 -    void fieldref_lifo(unsigned index) {
   8.498 -        recordOops();
   8.499 -        ensure(OP_FIELDREF_LIFO_LENGTH);
   8.500 -        writeOp(OP_FIELDREF_LIFO);
   8.501 -        writeUint32(index);
   8.502 -        markOop(1);
   8.503 -    }
   8.504 -    void getref(Type *type) {
   8.505 -        if (type->pod() == PrimitiveType_Int32) {
   8.506 -            singleByteOp(OP_GETREF_I);
   8.507 -        } else {
   8.508 -            assert(type->pod() == PrimitiveType_Float);
   8.509 -            singleByteOp(OP_GETREF_F);
   8.510 -        }
   8.511 -    }
   8.512 -    void setref(Type *type) {
   8.513 -        if (type->pod() == PrimitiveType_Int32) {
   8.514 -            singleByteOp(OP_SETREF_I);
   8.515 -        } else {
   8.516 -            assert(type->pod() == PrimitiveType_Float);
   8.517 -            singleByteOp(OP_SETREF_F);
   8.518 -        }
   8.519 -    }
   8.520 -    void object(Handle<Object> obj) {
   8.521 -        ensure(OP_OBJECT_LENGTH);
   8.522 -        writeOp(OP_OBJECT);
   8.523 -        writeObject(obj);
   8.524 -        markOop(1);
   8.525 -    }
   8.526 -    void copyarray() {
   8.527 -        singleByteOp(OP_COPYARRAY);
   8.528 -        markOop(1);
   8.529 -    }
   8.530 -    void copystruct() {
   8.531 -        singleByteOp(OP_COPYSTRUCT);
   8.532 -        markOop(1);
   8.533 -    }
   8.534 -    void sizeof_() {
   8.535 -        singleByteOp(OP_SIZEOF);
   8.536 -    }
   8.537 -
   8.538 -    void dup() {
   8.539 -        bool oop = getOop(1);
   8.540 -        singleByteOp(OP_DUP);
   8.541 -        markOop(1, oop);
   8.542 -    }
   8.543 -    void dup2() {
   8.544 -        bool oop2 = getOop(2);
   8.545 -        bool oop1 = getOop(1);
   8.546 -
   8.547 -        singleByteOp(OP_DUP2);
   8.548 -
   8.549 -        markOop(2, oop2);
   8.550 -        markOop(1, oop1);
   8.551 -    }
   8.552 -    void swap() {
   8.553 -        bool oop2 = getOop(2);
   8.554 -        bool oop1 = getOop(1);
   8.555 -
   8.556 -        singleByteOp(OP_SWAP);
   8.557 -
   8.558 -        markOop(2, oop1);
   8.559 -        markOop(1, oop2);
   8.560 -    }
   8.561 -    void roll3() {
   8.562 -        bool oop3 = getOop(3);
   8.563 -        bool oop2 = getOop(2);
   8.564 -        bool oop1 = getOop(1);
   8.565 -
   8.566 -        singleByteOp(OP_ROLL3);
   8.567 -
   8.568 -        markOop(3, oop2);
   8.569 -        markOop(2, oop1);
   8.570 -        markOop(1, oop3);
   8.571 -    }
   8.572 -    void pick2() {
   8.573 -        bool oop2 = getOop(2);
   8.574 -        bool oop1 = getOop(1);
   8.575 -
   8.576 -        singleByteOp(OP_PICK2);
   8.577 -
   8.578 -        markOop(3, oop2);
   8.579 -        markOop(2, oop1);
   8.580 -        markOop(1, oop2);
   8.581 -    }
   8.582 -    void pick3() {
   8.583 -        bool oop3 = getOop(3);
   8.584 -        bool oop2 = getOop(2);
   8.585 -        bool oop1 = getOop(1);
   8.586 -
   8.587 -        singleByteOp(OP_PICK3);
   8.588 -
   8.589 -        markOop(4, oop3);
   8.590 -        markOop(3, oop2);
   8.591 -        markOop(2, oop1);
   8.592 -        markOop(1, oop3);
   8.593 -    }
   8.594 -
   8.595 -    void returnvoid() {
   8.596 -        singleByteOp(OP_RETURNVOID);
   8.597 -    }
   8.598 -    void module() {
   8.599 -        singleByteOp(OP_MODULE);
   8.600 -        markOop(1);
   8.601 -    }
   8.602 -    void getmodule_fn(unsigned index) {
   8.603 -        ensure(OP_GETMODULE_FN_LENGTH);
   8.604 -        writeOp(OP_GETMODULE_FN);
   8.605 -        writeUint32(index);
   8.606 -        markOop(1);
   8.607 -    }
   8.608 -    void bitnot() {
   8.609 -        singleByteOp(OP_BITNOT);
   8.610 -    }
   8.611 -    void not_() {
   8.612 -        singleByteOp(OP_NOT);
   8.613 -    }
   8.614 -    void not_f() {
   8.615 -        singleByteOp(OP_NOT_F);
   8.616 -    }
   8.617 -    void neg() {
   8.618 -        singleByteOp(OP_NEG);
   8.619 -    }
   8.620 -    void neg_f() {
   8.621 -        singleByteOp(OP_NEG_F);
   8.622 -    }
   8.623 -    void bits_i2f() {
   8.624 -        singleByteOp(OP_BITS_I2F);
   8.625 -    }
   8.626 -    void bits_f2i() {
   8.627 -        singleByteOp(OP_BITS_F2I);
   8.628 -    }
   8.629 -    void true_() {
   8.630 -        singleByteOp(OP_TRUE);
   8.631 -    }
   8.632 -    void false_() {
   8.633 -        singleByteOp(OP_FALSE);
   8.634 -    }
   8.635 -
   8.636 -    void tableswitch(int low, int high, Label *def, Label **labels) {
   8.637 -        unsigned tablesize = TableSwitchEntries(low, high);
   8.638 -        assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
   8.639 -
   8.640 -        ensure(OP_TABLESWITCH_LENGTH);
   8.641 -        writeOp(OP_TABLESWITCH);
   8.642 -        writeInt32(low);
   8.643 -        writeInt32(high);
   8.644 -        jump(def);
   8.645 -
   8.646 -        // When labels are patched, we assume each position is a jump. Rather
   8.647 -        // than hack position offsets to make labels work without actual
   8.648 -        // incoming jumps, we emit a jump inline.
   8.649 -        for (unsigned i = 0; i < tablesize; i++)
   8.650 -            jump(labels[i]);
   8.651 -    }
   8.652 -
   8.653 -    // Helpers.
   8.654 -    void get(Variable *var) {
   8.655 -        if (var->location() == Variable::STACK) {
   8.656 -            getlocal(var);
   8.657 -        } else {
   8.658 -            assert(var->location() == Variable::PARAMETER);
   8.659 -            getarg(var);
   8.660 -        }
   8.661 -    }
   8.662 -    void set(Variable *var) {
   8.663 -        assert(!var->type()->isReference());
   8.664 -        if (var->location() == Variable::STACK) {
   8.665 -            setlocal(var);
   8.666 -        } else {
   8.667 -            assert(var->location() == Variable::PARAMETER);
   8.668 -            setarg(var);
   8.669 -        }
   8.670 -    }
   8.671 -};
   8.672 -
   8.673 -}
   8.674 -
   8.675 -#endif // _include_bytecode_emitter_h_
     9.1 --- a/src/Code.h	Mon Sep 17 00:10:01 2012 -0700
     9.2 +++ b/src/Code.h	Sat Nov 17 18:41:01 2012 -0800
     9.3 @@ -24,7 +24,6 @@
     9.4  #include "Heap.h"
     9.5  #include "Types.h"
     9.6  #include "FixedArray.h"
     9.7 -#include "Token.h"
     9.8  
     9.9  namespace ke {
    9.10  
    9.11 @@ -40,6 +39,7 @@
    9.12      Barriered<ByteArray> bytecode_;
    9.13      Barriered<FixedArray> locals_;
    9.14      Barriered<FixedArray> objects_;
    9.15 +    Barriered<FixedArray> strings_;
    9.16      Barriered<ByteArray> safepoints_;
    9.17      Barriered<ByteArray> sourcemap_;
    9.18      unsigned maxStackDepth_;
    9.19 @@ -52,9 +52,8 @@
    9.20  
    9.21    public:
    9.22      static Code *New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
    9.23 -                     Handle<FixedArray> objects, unsigned maxStackDepth, Handle<Module> module,
    9.24 -                     Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap,
    9.25 -                     unsigned lineNumber);
    9.26 +                     Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
    9.27 +                     Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap);
    9.28  
    9.29      Module *module() {
    9.30          return module_;
    9.31 @@ -83,8 +82,15 @@
    9.32      ByteArray *safepoints() {
    9.33          return safepoints_;
    9.34      }
    9.35 +    FixedArray *strings() {
    9.36 +        return strings_;
    9.37 +    }
    9.38      uint8 *safepointAt(unsigned pcOffset);
    9.39  
    9.40 +    void setModule(Handle<Module> module) {
    9.41 +        module_ = module;
    9.42 +    }
    9.43 +
    9.44      unsigned pcToOffset(bytecode *pc) {
    9.45          assert(pc >= start() && pc < start() + length());
    9.46          return unsigned(pc - start());
    9.47 @@ -108,6 +114,9 @@
    9.48      static inline size_t offsetOfObjects() {
    9.49          return OFFSETOF(Code, objects_);
    9.50      }
    9.51 +    static inline size_t offsetOfStrings() {
    9.52 +        return OFFSETOF(Code, strings_);
    9.53 +    }
    9.54      static inline size_t offsetOfSafepoints() {
    9.55          return OFFSETOF(Code, safepoints_);
    9.56      }
    10.1 --- a/src/CompileContext.cpp	Mon Sep 17 00:10:01 2012 -0700
    10.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.3 @@ -1,58 +0,0 @@
    10.4 -/*
    10.5 - * Copyright (C) 2012 David Anderson
    10.6 - *
    10.7 - * This file is part of JITCraft.
    10.8 - *
    10.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   10.10 - * the terms of the GNU General Public License as published by the Free
   10.11 - * Software Foundation, either version 3 of the License, or (at your option)
   10.12 - * any later version.
   10.13 - * 
   10.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   10.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   10.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   10.17 - *
   10.18 - * You should have received a copy of the GNU General Public License along with
   10.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   10.20 - */
   10.21 -#include <stdio.h>
   10.22 -#include "Scanner.h"
   10.23 -#include "CompileContext.h"
   10.24 -#include "Zone.h"
   10.25 -#include "Spaces-inl.h"
   10.26 -#include "Heap-inl.h"
   10.27 -
   10.28 -using namespace ke;
   10.29 -
   10.30 -CompileContext::CompileContext(Zone *zone, const char *file)
   10.31 -  : zone_(zone),
   10.32 -    failures_(0),
   10.33 -    file_(file)
   10.34 -{
   10.35 -}
   10.36 -
   10.37 -CompileContext::~CompileContext()
   10.38 -{
   10.39 -    if (failures_)
   10.40 -        zone_->endCompilationErrors();
   10.41 -}
   10.42 -
   10.43 -void
   10.44 -CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap)
   10.45 -{
   10.46 -    if (!failures_)
   10.47 -        zone_->beginCompilationErrors(file_);
   10.48 -
   10.49 -    zone_->reportCompilationError(msg, pos.line, pos.col, ap);
   10.50 -
   10.51 -    failures_++;
   10.52 -}
   10.53 -
   10.54 -void
   10.55 -CompileContext::reportError(const SourcePosition &pos, Message msg, ...)
   10.56 -{
   10.57 -    va_list ap;
   10.58 -    va_start(ap, msg);
   10.59 -    reportErrorVa(pos, msg, ap);
   10.60 -    va_end(ap);
   10.61 -}
    11.1 --- a/src/CompileContext.h	Mon Sep 17 00:10:01 2012 -0700
    11.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.3 @@ -1,49 +0,0 @@
    11.4 -/*
    11.5 - * Copyright (C) 2012 David Anderson
    11.6 - *
    11.7 - * This file is part of JITCraft.
    11.8 - *
    11.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   11.10 - * the terms of the GNU General Public License as published by the Free
   11.11 - * Software Foundation, either version 3 of the License, or (at your option)
   11.12 - * any later version.
   11.13 - * 
   11.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   11.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   11.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   11.17 - *
   11.18 - * You should have received a copy of the GNU General Public License along with
   11.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   11.20 - */
   11.21 -#ifndef _include_jitcraft_compile_context_h_
   11.22 -#define _include_jitcraft_compile_context_h_
   11.23 -
   11.24 -#include <stdarg.h>
   11.25 -#include "Messages.h"
   11.26 -
   11.27 -namespace ke {
   11.28 -
   11.29 -class Zone;
   11.30 -struct SourcePosition;
   11.31 -
   11.32 -class CompileContext
   11.33 -{
   11.34 -    Zone *zone_;
   11.35 -    unsigned failures_;
   11.36 -    const char *file_;
   11.37 -
   11.38 -  public:
   11.39 -    CompileContext(Zone *zone, const char *file);
   11.40 -    ~CompileContext();
   11.41 -
   11.42 -    void reportErrorVa(const SourcePosition &pos, Message msg, va_list ap);
   11.43 -    void reportError(const SourcePosition &pos, Message msg, ...);
   11.44 -
   11.45 -    unsigned failures() const {
   11.46 -        return failures_;
   11.47 -    }
   11.48 -};
   11.49 -
   11.50 -}
   11.51 -
   11.52 -#endif // _include_jitcraft_compile_context_h_
    12.1 --- a/src/Environments.cpp	Mon Sep 17 00:10:01 2012 -0700
    12.2 +++ b/src/Environments.cpp	Sat Nov 17 18:41:01 2012 -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  #include <string.h>
   12.26  #include "Utility.h"
   12.27 @@ -21,7 +21,7 @@
   12.28  #include "Structures.h"
   12.29  #include "FixedArray.h"
   12.30  #include "Zone.h"
   12.31 -#include "NameBinding.h"
   12.32 +#include "compiler/NameBinding.h"
   12.33  #include "Spaces-inl.h"
   12.34  #include "Heap-inl.h"
   12.35  
   12.36 @@ -59,6 +59,7 @@
   12.37      return env;
   12.38  }
   12.39  
   12.40 +#if 0
   12.41  EnvironmentMap *
   12.42  EnvironmentMap::New(Zone *zone, unsigned nvars, Variable **vars)
   12.43  {
   12.44 @@ -98,3 +99,4 @@
   12.45  
   12.46      return map;
   12.47  }
   12.48 +#endif
   12.49 \ No newline at end of file
    13.1 --- a/src/Functions.cpp	Mon Sep 17 00:10:01 2012 -0700
    13.2 +++ b/src/Functions.cpp	Sat Nov 17 18:41:01 2012 -0800
    13.3 @@ -23,7 +23,7 @@
    13.4  using namespace ke;
    13.5  
    13.6  Function *
    13.7 -Function::New(Zone *zone, Handle<Code> code, Handle<Type> type, Handle<String> name,
    13.8 +Function::New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
    13.9                const SourcePosition &pos)
   13.10  {
   13.11      Function *fun = Function::cast(zone->allocate(MapKind_Function, sizeof(Function), Heap::Tenure_Old));
   13.12 @@ -38,14 +38,13 @@
   13.13  }
   13.14  
   13.15  Native *
   13.16 -Native::New(Zone *zone, Handle<Type> type, Handle<String> name)
   13.17 +Native::New(Zone *zone, Handle<FunctionType> type, size_t index)
   13.18  {
   13.19      Native *fun = Native::cast(zone->allocate(MapKind_Native, sizeof(Native), Heap::Tenure_Old));
   13.20      if (!fun)
   13.21          return NULL;
   13.22  
   13.23      fun->type_ = type;
   13.24 -    fun->name_ = name;
   13.25 -    fun->function_ = NULL;
   13.26 +    fun->index_ = index;
   13.27      return fun;
   13.28  }
    14.1 --- a/src/Functions.h	Mon Sep 17 00:10:01 2012 -0700
    14.2 +++ b/src/Functions.h	Sat Nov 17 18:41:01 2012 -0800
    14.3 @@ -20,31 +20,30 @@
    14.4  
    14.5  #include "Heap.h"
    14.6  #include "Barriers.h"
    14.7 -#include "Token.h"
    14.8  #include "Types.h"
    14.9 +#include "Opcodes.h"
   14.10  
   14.11  namespace ke {
   14.12  
   14.13  class Code;
   14.14  class Module;
   14.15 -class Type;
   14.16  class String;
   14.17  
   14.18  class Function : public Object
   14.19  {
   14.20      Barriered<Code> code_;
   14.21 -    Barriered<Type> type_;
   14.22 +    Barriered<FunctionType> type_;
   14.23      Barriered<String> name_;
   14.24      SourcePosition pos_;
   14.25  
   14.26   public:
   14.27 -    static Function *New(Zone *zone, Handle<Code> code, Handle<Type> type, Handle<String> name,
   14.28 +    static Function *New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
   14.29                           const SourcePosition &pos);
   14.30  
   14.31      Code *code() const {
   14.32          return code_;
   14.33      }
   14.34 -    Type *type() const {
   14.35 +    FunctionType *type() const {
   14.36          return type_;
   14.37      }
   14.38      String *name() const {
   14.39 @@ -82,33 +81,25 @@
   14.40  // for earlier ISourcePawnEngine API compatibility.
   14.41  class Native : public Object
   14.42  {
   14.43 -    Barriered<Type> type_;
   14.44 -    Barriered<String> name_;
   14.45 -    void *function_;
   14.46 +    Barriered<FunctionType> type_;
   14.47 +
   14.48 +    // Index into the Zone's native table.
   14.49 +    size_t index_;
   14.50  
   14.51    public:
   14.52 -    static Native *New(Zone *zone, Handle<Type> type, Handle<String> name);
   14.53 +    static Native *New(Zone *zone, Handle<FunctionType> type, size_t index);
   14.54  
   14.55 -    void *function() {
   14.56 -        return function_;
   14.57 -    }
   14.58 -    Type *type() {
   14.59 +    FunctionType *type() {
   14.60          return type_;
   14.61      }
   14.62 -    String *name() {
   14.63 -        return name_;
   14.64 -    }
   14.65 -    void bind(void *function) {
   14.66 -        function_ = function;
   14.67 +    size_t index() const {
   14.68 +        return index_;
   14.69      }
   14.70  
   14.71      // Begin GC Descriptor.
   14.72      static inline size_t offsetOfType() {
   14.73          return OFFSETOF(Native, type_);
   14.74      }
   14.75 -    static inline size_t offsetOfName() {
   14.76 -        return OFFSETOF(Native, name_);
   14.77 -    }
   14.78      // End GC Descriptor.
   14.79  
   14.80      static inline Native *cast(Object *obj) {
    15.1 --- a/src/GlobalRoots.cpp	Mon Sep 17 00:10:01 2012 -0700
    15.2 +++ b/src/GlobalRoots.cpp	Sat Nov 17 18:41:01 2012 -0800
    15.3 @@ -52,7 +52,7 @@
    15.4  }
    15.5  
    15.6  HeapRoot *
    15.7 -GlobalRoots::create(Handle<Object> obj)
    15.8 +GlobalRoots::create()
    15.9  {
   15.10      HeapRoot *root = new HeapRoot();
   15.11      if (!root) {
   15.12 @@ -60,25 +60,15 @@
   15.13          return NULL;
   15.14      }
   15.15  
   15.16 -    root->obj = obj;
   15.17 -    root->refcount = 1;
   15.18 +    root->obj = NULL;
   15.19  
   15.20      roots_.append(root);
   15.21      return root;
   15.22  }
   15.23  
   15.24  void
   15.25 -GlobalRoots::incref(HeapRoot *root)
   15.26 +GlobalRoots::destroy(HeapRoot *root)
   15.27  {
   15.28 -    root->refcount++;
   15.29 +    roots_.remove(root);
   15.30 +    delete root;
   15.31  }
   15.32 -
   15.33 -void
   15.34 -GlobalRoots::decref(HeapRoot *root)
   15.35 -{
   15.36 -    assert(root->refcount > 0);
   15.37 -    if (--root->refcount == 0) {
   15.38 -        roots_.remove(root);
   15.39 -        delete root;
   15.40 -    }
   15.41 -}
    16.1 --- a/src/GlobalRoots.h	Mon Sep 17 00:10:01 2012 -0700
    16.2 +++ b/src/GlobalRoots.h	Sat Nov 17 18:41:01 2012 -0800
    16.3 @@ -33,7 +33,6 @@
    16.4  {
    16.5    public:
    16.6      Object *obj;
    16.7 -    intptr_t refcount;
    16.8  };
    16.9  
   16.10  class GlobalRoots
   16.11 @@ -46,11 +45,8 @@
   16.12  
   16.13      bool initialize();
   16.14  
   16.15 -    // The caller must immediately incref this.
   16.16 -    HeapRoot *create(Handle<Object> ptr);
   16.17 -
   16.18 -    void incref(HeapRoot *root);
   16.19 -    void decref(HeapRoot *root);
   16.20 +    HeapRoot *create();
   16.21 +    void destroy(HeapRoot *root);
   16.22  
   16.23      void accept(VirtualObjectVisitor *visitor);
   16.24  
    17.1 --- a/src/Handles.h	Mon Sep 17 00:10:01 2012 -0700
    17.2 +++ b/src/Handles.h	Sat Nov 17 18:41:01 2012 -0800
    17.3 @@ -29,6 +29,11 @@
    17.4  template <typename T> class Local;
    17.5  template <typename T> class ScopedRoot;
    17.6  
    17.7 +struct NullAddress
    17.8 +{
    17.9 +    static void * const Sentinel;
   17.10 +};
   17.11 +
   17.12  /*
   17.13   * Internal handles work differently from API handles. An API handle is a
   17.14   * root, whereas as an internal handle points to a rooted location. This
   17.15 @@ -40,6 +45,12 @@
   17.16  {
   17.17      T * const *thingp_;
   17.18  
   17.19 +  private:
   17.20 +    Handle()
   17.21 +      : thingp_(reinterpret_cast<T * const *>(&NullAddress::Sentinel))
   17.22 +    {
   17.23 +    }
   17.24 +
   17.25    public:
   17.26      Handle(const Handle &other) {
   17.27          thingp_ = other.address();
   17.28 @@ -51,6 +62,10 @@
   17.29      template <typename S> inline Handle(const Local<S> &local);
   17.30      template <typename S> inline Handle(const ScopedRoot<S> &root);
   17.31  
   17.32 +    static inline Handle Null() {
   17.33 +        return Handle();
   17.34 +    }
   17.35 +
   17.36    public:
   17.37      T *operator ->() {
   17.38          return *thingp_;
    18.1 --- a/src/HashTable.h	Mon Sep 17 00:10:01 2012 -0700
    18.2 +++ b/src/HashTable.h	Sat Nov 17 18:41:01 2012 -0800
    18.3 @@ -127,7 +127,7 @@
    18.4          { }
    18.5  
    18.6          Payload * operator ->() {
    18.7 -            return entry_->payload();
    18.8 +            return &entry_->payload();
    18.9          }
   18.10          Payload & operator *() {
   18.11              return entry_->payload();
   18.12 @@ -421,6 +421,8 @@
   18.13      };
   18.14  };
   18.15  
   18.16 +
   18.17 +
   18.18  }
   18.19  
   18.20  #endif // _INCLUDE_KEIMA_HASHTABLE_H_
    19.1 --- a/src/Interpreter.cpp	Mon Sep 17 00:10:01 2012 -0700
    19.2 +++ b/src/Interpreter.cpp	Sat Nov 17 18:41:01 2012 -0800
    19.3 @@ -26,6 +26,7 @@
    19.4  #include "Strings.h"
    19.5  #include "Environments.h"
    19.6  #include "Structures.h"
    19.7 +#include "NativeTable.h"
    19.8  #include "Heap-inl.h"
    19.9  
   19.10  using namespace ke;
   19.11 @@ -218,7 +219,16 @@
   19.12  static void
   19.13  GetField(Struct *obj, unsigned index, LocalSlot *vp)
   19.14  {
   19.15 -    Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
   19.16 +    StructType *type = StructType::cast(obj->map()->type());
   19.17 +    Descriptor *desc = Descriptor::cast(type->fields()->at(index));
   19.18 +    GetField(obj, desc, vp);
   19.19 +}
   19.20 +
   19.21 +static void
   19.22 +GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
   19.23 +{
   19.24 +    Local<StructType> type(zone, StructType::cast(obj->map()->type()));
   19.25 +    Local<Descriptor> desc(zone, type->lookupField(name, NULL));
   19.26      GetField(obj, desc, vp);
   19.27  }
   19.28  
   19.29 @@ -246,7 +256,16 @@
   19.30  static void
   19.31  SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
   19.32  {
   19.33 -    Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
   19.34 +    StructType *type = StructType::cast(obj->map()->type());
   19.35 +    Descriptor *desc = Descriptor::cast(type->fields()->at(index));
   19.36 +    SetField(zone, obj, desc, v);
   19.37 +}
   19.38 +
   19.39 +static void
   19.40 +SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
   19.41 +{
   19.42 +    Local<StructType> type(zone, StructType::cast(obj->map()->type()));
   19.43 +    Local<Descriptor> desc(zone, type->lookupField(name, NULL));
   19.44      SetField(zone, obj, desc, v);
   19.45  }
   19.46  
   19.47 @@ -257,7 +276,7 @@
   19.48  {
   19.49      assert(left->map()->type() == right->map()->type());
   19.50  
   19.51 -    Local<Type> type(zone, left->map()->type());
   19.52 +    Local<StructType> type(zone, StructType::cast(left->map()->type()));
   19.53      Local<Struct> leftStruct(zone);
   19.54      Local<Struct> rightStruct(zone);
   19.55      Local<Array> leftArray(zone);
   19.56 @@ -299,6 +318,13 @@
   19.57  {
   19.58      NativeArgs guard;
   19.59  
   19.60 +    void *address = zone->nativeTable()->address(native->index());
   19.61 +    if (!address) {
   19.62 +        Local<String> name(zone, zone->nativeTable()->name(native->index()));
   19.63 +        zone->reportError(Message_NativeNotBound, name->chars());
   19.64 +        return false;
   19.65 +    }
   19.66 +
   19.67      if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
   19.68          return false;
   19.69  
   19.70 @@ -308,7 +334,7 @@
   19.71      cells[0] = argc;
   19.72  
   19.73      // Pass the formal arguments.
   19.74 -    Local<Type> type(zone, native->type());
   19.75 +    Local<FunctionType> type(zone, native->type());
   19.76      Local<Type> param(zone);
   19.77      for (unsigned i = 0; i < type->parameters()->length(); i++) {
   19.78          param = type->parameterAt(i);
   19.79 @@ -338,7 +364,7 @@
   19.80      }
   19.81  
   19.82      typedef intptr_t (*INVOKE)(void *, intptr_t *);
   19.83 -    INVOKE invoke = (INVOKE)native->function();
   19.84 +    INVOKE invoke = (INVOKE)address;
   19.85      *result = invoke(identity, cells);
   19.86  
   19.87      return !zone->hasPendingException();
   19.88 @@ -399,42 +425,6 @@
   19.89      break;
   19.90  }
   19.91  
   19.92 -#define RELATIONAL_JUMP(op)                 \
   19.93 -    {                                       \
   19.94 -        int right = POP_I32(top);           \
   19.95 -        int left = POP_I32(top);            \
   19.96 -        if (left op right) {                \
   19.97 -            top.pc += READ_INT32(top.pc);   \
   19.98 -            continue;                       \
   19.99 -        }                                   \
  19.100 -    }
  19.101 -
  19.102 -case OP_JL:
  19.103 -    RELATIONAL_JUMP(<);
  19.104 -    break;
  19.105 -
  19.106 -case OP_JLE:
  19.107 -    RELATIONAL_JUMP(<=);
  19.108 -    break;
  19.109 -
  19.110 -case OP_JG:
  19.111 -    RELATIONAL_JUMP(>);
  19.112 -    break;
  19.113 -
  19.114 -case OP_JGE:
  19.115 -    RELATIONAL_JUMP(>=);
  19.116 -    break;
  19.117 -
  19.118 -case OP_JEQ:
  19.119 -    RELATIONAL_JUMP(==);
  19.120 -    break;
  19.121 -
  19.122 -case OP_JNE:
  19.123 -    RELATIONAL_JUMP(!=);
  19.124 -    break;
  19.125 -
  19.126 -#undef RELATIONAL_JUMP
  19.127 -
  19.128  case OP_JT:
  19.129  {
  19.130      int value = POP_I32(top);
  19.131 @@ -455,74 +445,22 @@
  19.132      break;
  19.133  }
  19.134  
  19.135 -#define RELATIONAL_JUMP_F(op)               \
  19.136 -    {                                       \
  19.137 -        float right = POP_F(top);           \
  19.138 -        float left = POP_F(top);            \
  19.139 -        if (left op right) {                \
  19.140 -            top.pc += READ_INT32(top.pc);   \
  19.141 -            continue;                       \
  19.142 -        }                                   \
  19.143 -    }
  19.144 -
  19.145 -case OP_JL_F:
  19.146 -    RELATIONAL_JUMP_F(<);
  19.147 -    break;
  19.148 -
  19.149 -case OP_JLE_F:
  19.150 -    RELATIONAL_JUMP_F(<=);
  19.151 -    break;
  19.152 -
  19.153 -case OP_JG_F:
  19.154 -    RELATIONAL_JUMP_F(>);
  19.155 -    break;
  19.156 -
  19.157 -case OP_JGE_F:
  19.158 -    RELATIONAL_JUMP_F(>=);
  19.159 -    break;
  19.160 -
  19.161 -case OP_JEQ_F:
  19.162 -    RELATIONAL_JUMP_F(==);
  19.163 -    break;
  19.164 -
  19.165 -case OP_JNE_F:
  19.166 -    RELATIONAL_JUMP_F(!=);
  19.167 -    break;
  19.168 -
  19.169 -case OP_JT_F:
  19.170 -{
  19.171 -    float value = POP_F(top);
  19.172 -    if (value) {
  19.173 -        top.pc += READ_INT32(top.pc);
  19.174 -        continue;
  19.175 -    }
  19.176 -    break;
  19.177 -}
  19.178 -
  19.179 -case OP_JF_F:
  19.180 -{
  19.181 -    float value = POP_F(top);
  19.182 -    if (!value) {
  19.183 -        top.pc += READ_INT32(top.pc);
  19.184 -        continue;
  19.185 -    }
  19.186 -    break;
  19.187 -}
  19.188 -
  19.189  case OP_JUMP:
  19.190      top.pc += READ_INT32(top.pc);
  19.191      continue;
  19.192  
  19.193  case OP_GETLOCAL:
  19.194  {
  19.195 -    int slot = READ_INT32(top.pc);
  19.196 +    unsigned slot = READ_UINT32(top.pc);
  19.197 +    assert(slot < top.fp->code()->nlocals());
  19.198      *top.sp++ = locals[slot];
  19.199      break;
  19.200  }
  19.201  
  19.202  case OP_SETLOCAL:
  19.203  {
  19.204 -    int slot = READ_INT32(top.pc);
  19.205 +    unsigned slot = READ_UINT32(top.pc);
  19.206 +    assert(slot < top.fp->code()->nlocals());
  19.207      locals[slot] = top.sp[-1];
  19.208      break;
  19.209  }
  19.210 @@ -756,7 +694,7 @@
  19.211  
  19.212  case OP_CALL:
  19.213  {
  19.214 -    Local<Function> newFun(zone, top.sp[-1].fun);
  19.215 +    Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
  19.216      top.sp--;
  19.217  
  19.218      if (!zone->stack().pushInlineFrame(newFun))
  19.219 @@ -911,15 +849,6 @@
  19.220      break;
  19.221  }
  19.222  
  19.223 -case OP_FIELDREF_LIFO:
  19.224 -{
  19.225 -    Local<Struct> obj(zone, Struct::cast(top.sp[-1].obj));
  19.226 -    top.sp[-1].obj = Reference::NewField(zone, obj, READ_UINT32(top.pc), Heap::Tenure_Stack);
  19.227 -    if (!top.sp[-1].obj)
  19.228 -        goto error;
  19.229 -    break;
  19.230 -}
  19.231 -
  19.232  case OP_GETREF_I:
  19.233  {
  19.234      top.sp[-1].i32 = top.sp[-1].ref->getInt();
  19.235 @@ -1014,14 +943,10 @@
  19.236  
  19.237  case OP_CALLNATIVE:
  19.238  {
  19.239 -    unsigned index = READ_UINT32(top.pc);
  19.240 -    unsigned argc = READ_UINT32(top.pc + 4);
  19.241 +    unsigned argc = READ_UINT32(top.pc);
  19.242  
  19.243 -    Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
  19.244 -    if (!native->function()) {
  19.245 -        zone->reportError(Message_NativeNotBound, native->name()->chars());
  19.246 -        goto error;
  19.247 -    }
  19.248 +    Local<Native> native(zone, Native::cast(top.sp[-1].obj));
  19.249 +    top.sp--;
  19.250  
  19.251      int result;
  19.252      void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
  19.253 @@ -1033,64 +958,6 @@
  19.254      break;
  19.255  }
  19.256  
  19.257 -case OP_MODULE:
  19.258 -{
  19.259 -    top.sp++;
  19.260 -    top.sp[-1].module = top.fp->code()->module();
  19.261 -    break;
  19.262 -}
  19.263 -
  19.264 -case OP_GETMODULE_FN:
  19.265 -{
  19.266 -    top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
  19.267 -    break;
  19.268 -}
  19.269 -
  19.270 -case OP_GETGLOBAL_I:
  19.271 -{
  19.272 -    unsigned slot = READ_UINT32(top.pc);
  19.273 -    top.sp++;
  19.274 -    top.sp[-1].i32 = top.fp->code()->module()->environment()->getInt32(slot);
  19.275 -    break;
  19.276 -}
  19.277 -
  19.278 -case OP_GETGLOBAL_F:
  19.279 -{
  19.280 -    unsigned slot = READ_UINT32(top.pc);
  19.281 -    top.sp++;
  19.282 -    top.sp[-1].f = top.fp->code()->module()->environment()->getFloat(slot);
  19.283 -    break;
  19.284 -}
  19.285 -
  19.286 -case OP_GETGLOBAL_O:
  19.287 -{
  19.288 -    unsigned slot = READ_UINT32(top.pc);
  19.289 -    top.sp++;
  19.290 -    top.sp[-1].obj = top.fp->code()->module()->environment()->getObject(slot);
  19.291 -    break;
  19.292 -}
  19.293 -
  19.294 -case OP_SETGLOBAL_I:
  19.295 -{
  19.296 -    unsigned slot = READ_UINT32(top.pc);
  19.297 -    top.fp->code()->module()->environment()->setInt32(slot, top.sp[-1].i32);
  19.298 -    break;
  19.299 -}
  19.300 -
  19.301 -case OP_SETGLOBAL_F:
  19.302 -{
  19.303 -    unsigned slot = READ_UINT32(top.pc);
  19.304 -    top.fp->code()->module()->environment()->setFloat(slot, top.sp[-1].f);
  19.305 -    break;
  19.306 -}
  19.307 -
  19.308 -case OP_SETGLOBAL_O:
  19.309 -{
  19.310 -    unsigned slot = READ_UINT32(top.pc);
  19.311 -    top.fp->code()->module()->environment()->setObject(slot, top.sp[-1].obj);
  19.312 -    break;
  19.313 -}
  19.314 -
  19.315  case OP_BITS_I2F:
  19.316  case OP_BITS_F2I:
  19.317  {
  19.318 @@ -1165,6 +1032,33 @@
  19.319      break;
  19.320  }
  19.321  
  19.322 +case OP_PUBLIC:
  19.323 +{
  19.324 +    Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
  19.325 +    zone->registerPublic(fun);
  19.326 +    top.sp--;
  19.327 +    break;
  19.328 +}
  19.329 +
  19.330 +case OP_SETGLOBAL:
  19.331 +{
  19.332 +    Local<Code> code(zone, top.fp->code());
  19.333 +    Local<Struct> obj(zone, code->module()->globals());
  19.334 +    Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
  19.335 +    SetGlobal(zone, obj, name, top.sp[-1]);
  19.336 +    break;
  19.337 +}
  19.338 +
  19.339 +case OP_GETGLOBAL:
  19.340 +{
  19.341 +    Local<Code> code(zone, top.fp->code());
  19.342 +    Local<Struct> obj(zone, code->module()->globals());
  19.343 +    Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
  19.344 +    GetGlobal(zone, obj, name, top.sp);
  19.345 +    top.sp++;
  19.346 +    break;
  19.347 +}
  19.348 +
  19.349  default:
  19.350      assert(false);
  19.351      return false;
    20.1 --- a/src/Messages.tbl	Mon Sep 17 00:10:01 2012 -0700
    20.2 +++ b/src/Messages.tbl	Sat Nov 17 18:41:01 2012 -0800
    20.3 @@ -61,7 +61,6 @@
    20.4  MSG(IdentifierNotFound,             SyntaxError,            "identifier '%s' could not be found")
    20.5  MSG(TypeMismatchDuringInvoke,       TypeError,              "incoming type '%s' does not match signature type '%s'")
    20.6  MSG(CannotInvokeReturnType,         SyntaxError,            "cannot invoke function with return type '%s'")
    20.7 -MSG(TypeNotFound,                   SyntaxError,            "type '%s' could not be found")
    20.8  MSG(IdentifierIsNotAType,           SyntaxError,            "identifier '%s' cannot be used as a type")
    20.9  MSG(TypeMismatch,                   TypeError,              "type mismatch (expected '%s', got '%s')")
   20.10  MSG(PropertyNotFound,               TypeError,              "property '%s' not found on type '%s'")
   20.11 @@ -80,4 +79,6 @@
   20.12  MSG(CannotComputeIndexRef,          SyntaxError,            "cannot use an array index as a reference")
   20.13  MSG(BadDynamicInitializer,          SyntaxError,            "dynamic length specified, but preceding array is empty")
   20.14  MSG(SizeofNeedsArray,               TypeError,              "sizeof requires an array")
   20.15 -
   20.16 +MSG(ImportsMustBeFirst,             SyntaxError,            "import statements must come before other statements")
   20.17 +MSG(ImportedNameAlreadyBound,       TypeError,              "imported name has already been bound")
   20.18 +MSG(CannotResolveImport,            TypeError,              "cannot resolve import %s")
   20.19 \ No newline at end of file
    21.1 --- a/src/Modules.cpp	Mon Sep 17 00:10:01 2012 -0700
    21.2 +++ b/src/Modules.cpp	Sat Nov 17 18:41:01 2012 -0800
    21.3 @@ -23,21 +23,15 @@
    21.4  using namespace ke;
    21.5  
    21.6  Module *
    21.7 -Module::New(Zone *zone, unsigned nfunctions)
    21.8 +Module::New(Zone *zone)
    21.9  {
   21.10      Local<Module> module(zone, Module::cast(zone->allocate(MapKind_Module, sizeof(Module), Heap::Tenure_Old)));
   21.11      if (!module)
   21.12          return NULL;
   21.13  
   21.14 -    Local<FixedArray> functions(zone, FixedArray::New(zone, nfunctions, Heap::Tenure_Old));
   21.15 -    if (!functions)
   21.16 -        return NULL;
   21.17 -
   21.18 -    module->functions_ = functions;
   21.19      module->file_ = NULL;
   21.20 -    module->publics_ = NULL;
   21.21 -    module->natives_ = NULL;
   21.22 -    module->environment_ = NULL;
   21.23 +    module->globals_ = NULL;
   21.24      module->nativeIdentity_ = NULL;
   21.25 +    module->globals_ = NULL;
   21.26      return module;
   21.27  }
    22.1 --- a/src/Modules.h	Mon Sep 17 00:10:01 2012 -0700
    22.2 +++ b/src/Modules.h	Sat Nov 17 18:41:01 2012 -0800
    22.3 @@ -25,60 +25,37 @@
    22.4  namespace ke {
    22.5  
    22.6  class Environment;
    22.7 +class Struct;
    22.8  
    22.9  class Module : public Object
   22.10  {
   22.11 -    Barriered<FixedArray> functions_;
   22.12 -    Barriered<FixedArray> publics_;
   22.13 -    Barriered<FixedArray> natives_;
   22.14      Barriered<String> file_;
   22.15 -    Barriered<Environment> environment_;
   22.16      Barriered<Code> code_;
   22.17 +    Barriered<Struct> globals_;
   22.18      void *nativeIdentity_;
   22.19  
   22.20    public:
   22.21 -    static Module *New(Zone *zone, unsigned nfunctions);
   22.22 -
   22.23 -    Function *getFunction(size_t i) {
   22.24 -        return Function::cast(functions_->at(i));
   22.25 -    }
   22.26 -    void setFunction(Zone *zone, size_t i, Function *fun) {
   22.27 -        assert(!functions_->at(i));
   22.28 -        assert(fun);
   22.29 -        functions_->set(zone, i, fun);
   22.30 -    }
   22.31 -
   22.32 -    FixedArray *publics() {
   22.33 -        return publics_;
   22.34 -    }
   22.35 -    FixedArray *natives() {
   22.36 -        return natives_;
   22.37 -    }
   22.38 +    static Module *New(Zone *zone);
   22.39 +    
   22.40      String *file() {
   22.41          return file_;
   22.42      }
   22.43 -    Environment *environment() {
   22.44 -        return environment_;
   22.45 -    }
   22.46      Code *code() {
   22.47          return code_;
   22.48      }
   22.49 -
   22.50 -    void setPublics(Handle<FixedArray> publics) {
   22.51 -        publics_ = publics;
   22.52 +    Struct *globals() {
   22.53 +        return globals_;
   22.54      }
   22.55 -    void setNatives(Handle<FixedArray> natives) {
   22.56 -        natives_ = natives;
   22.57 -    }
   22.58 +
   22.59      void setPath(Handle<String> path) {
   22.60          file_ = path;
   22.61      }
   22.62 -    void setEnvironment(Handle<Environment> environment) {
   22.63 -        environment_ = environment;
   22.64 -    }
   22.65      void setCode(Handle<Code> code) {
   22.66          code_ = code;
   22.67      }
   22.68 +    void setGlobals(Handle<Struct> globals) {
   22.69 +        globals_ = globals;
   22.70 +    }
   22.71  
   22.72      void *nativeIdentity() {
   22.73          return nativeIdentity_;
   22.74 @@ -88,24 +65,15 @@
   22.75      }
   22.76  
   22.77      // Begin GC Descriptor.
   22.78 -    static inline size_t offsetOfFunctions() {
   22.79 -        return OFFSETOF(Module, functions_);
   22.80 -    }
   22.81 -    static inline size_t offsetOfPublics() {
   22.82 -        return OFFSETOF(Module, publics_);
   22.83 -    }
   22.84 -    static inline size_t offsetOfNatives() {
   22.85 -        return OFFSETOF(Module, natives_);
   22.86 -    }
   22.87      static inline size_t offsetOfFile() {
   22.88          return OFFSETOF(Module, file_);
   22.89      }
   22.90 -    static inline size_t offsetOfEnvironment() {
   22.91 -        return OFFSETOF(Module, environment_);
   22.92 -    }
   22.93      static inline size_t offsetOfCode() {
   22.94          return OFFSETOF(Module, code_);
   22.95      }
   22.96 +    static inline size_t offsetOfGlobals() {
   22.97 +        return OFFSETOF(Module, globals_);
   22.98 +    }
   22.99      // End GC Descriptor.
  22.100  
  22.101      static inline Module *cast(Object *obj) {
    23.1 --- a/src/NameBinding.cpp	Mon Sep 17 00:10:01 2012 -0700
    23.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.3 @@ -1,57 +0,0 @@
    23.4 -/* vim: set ts=4 sw=4 tw=99 et:
    23.5 - *
    23.6 - * Copyright (C) 2012 David Anderson
    23.7 - *
    23.8 - * This file is part of SourcePawn.
    23.9 - *
   23.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   23.11 - * the terms of the GNU General Public License as published by the Free
   23.12 - * Software Foundation, either version 3 of the License, or (at your option)
   23.13 - * any later version.
   23.14 - * 
   23.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   23.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   23.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   23.18 - *
   23.19 - * You should have received a copy of the GNU General Public License along with
   23.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   23.21 - */
   23.22 -#include "NameBinding.h"
   23.23 -#include "Strings.h"
   23.24 -#include "Zone.h"
   23.25 -#include "Scopes.h"
   23.26 -#include "Spaces-inl.h"
   23.27 -#include "Heap-inl.h"
   23.28 -
   23.29 -using namespace ke;
   23.30 -
   23.31 -BoundName::BoundName(Scope *scope, Handle<String> name, const SourcePosition &pos)
   23.32 -  : scope_(scope),
   23.33 -    name_(name),
   23.34 -    type_(NULL),
   23.35 -    used_(false),
   23.36 -    pos_(pos)
   23.37 -{
   23.38 -}
   23.39 -
   23.40 -NamedFunction::NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos,
   23.41 -                             TokenKind token)
   23.42 -  : BoundName(scope, name, pos),
   23.43 -    token_(token),
   23.44 -    isVariadicNative_(false)
   23.45 -{
   23.46 -}
   23.47 -
   23.48 -Variable::Variable(Scope *scope, Handle<String> name, const SourcePosition &pos)
   23.49 -  : BoundName(scope, name, pos),
   23.50 -    location_(UNALLOCATED),
   23.51 -    public_(false)
   23.52 -{
   23.53 -}
   23.54 -
   23.55 -bool
   23.56 -Variable::needsHeapAllocation()
   23.57 -{
   23.58 -    return scope()->kind() == Scope::GLOBAL;
   23.59 -}
   23.60 -
    24.1 --- a/src/NameBinding.h	Mon Sep 17 00:10:01 2012 -0700
    24.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.3 @@ -1,257 +0,0 @@
    24.4 -/* vim: set ts=4 sw=4 tw=99 et:
    24.5 - *
    24.6 - * Copyright (C) 2012 David Anderson
    24.7 - *
    24.8 - * This file is part of SourcePawn.
    24.9 - *
   24.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   24.11 - * the terms of the GNU General Public License as published by the Free
   24.12 - * Software Foundation, either version 3 of the License, or (at your option)
   24.13 - * any later version.
   24.14 - * 
   24.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   24.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   24.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   24.18 - *
   24.19 - * You should have received a copy of the GNU General Public License along with
   24.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   24.21 - */
   24.22 -#ifndef _include_name_binding_h_
   24.23 -#define _include_name_binding_h_
   24.24 -
   24.25 -#include "PoolAllocator.h"
   24.26 -#include "Types.h"
   24.27 -#include "Scanner.h"
   24.28 -
   24.29 -namespace ke {
   24.30 -
   24.31 -class Variable;
   24.32 -class NamedFunction;
   24.33 -class Scope;
   24.34 -class Type;
   24.35 -class NamedConstant;
   24.36 -class NamedType;
   24.37 -class UnboundName;
   24.38 -class String;
   24.39 -
   24.40 -class BoundName : public PoolObject
   24.41 -{
   24.42 -    Scope *scope_;
   24.43 -    ScopedRoot<String> name_;
   24.44 -    ScopedRoot<Type> type_;
   24.45 -    bool used_;
   24.46 -
   24.47 -  protected:
   24.48 -    SourcePosition pos_;
   24.49 -
   24.50 -  public:
   24.51 -    enum Kind {
   24.52 -      VARIABLE,
   24.53 -      FUNCTION,
   24.54 -      CONSTANT,
   24.55 -      TYPE,
   24.56 -      UNBOUND
   24.57 -    };
   24.58 -
   24.59 -    BoundName(Scope *scope, Handle<String> name, const SourcePosition &pos);
   24.60 -
   24.61 -    virtual Kind kind() const = 0;
   24.62 -
   24.63 -    String *name() const {
   24.64 -        return name_;
   24.65 -    }
   24.66 -    Scope *scope() const {
   24.67 -        return scope_;
   24.68 -    }
   24.69 -    Variable *toVariable() {
   24.70 -        assert(kind() == VARIABLE);
   24.71 -        return reinterpret_cast<Variable *>(this);
   24.72 -    }
   24.73 -    NamedFunction *toNamedFunction() {
   24.74 -        assert(kind() == FUNCTION);
   24.75 -        return reinterpret_cast<NamedFunction *>(this);
   24.76 -    }
   24.77 -    NamedConstant *toNamedConstant() {
   24.78 -        assert(kind() == CONSTANT);
   24.79 -        return reinterpret_cast<NamedConstant *>(this);
   24.80 -    }
   24.81 -    NamedType *toNamedType() {
   24.82 -        assert(kind() == TYPE);
   24.83 -        return reinterpret_cast<NamedType *>(this);
   24.84 -    }
   24.85 -    Type *type() const {
   24.86 -        return type_;
   24.87 -    }
   24.88 -    void setType(Handle<Type> type) {
   24.89 -        type_ = type;
   24.90 -    }
   24.91 -    void setUsed() {
   24.92 -        used_ = true;
   24.93 -    }
   24.94 -    bool used() const {
   24.95 -        return used_;
   24.96 -    }
   24.97 -    const SourcePosition &pos() {
   24.98 -        return pos_;
   24.99 -    }
  24.100 -};
  24.101 -
  24.102 -class NamedFunction : public BoundName
  24.103 -{
  24.104 -    unsigned slot_;
  24.105 -    TokenKind token_;
  24.106 -    ScopedRoot<Type> forwardType_;
  24.107 -    bool isVariadicNative_;
  24.108 -    Vector<BoundName *, PoolAllocationPolicy> globals_;
  24.109 -
  24.110 -  public:
  24.111 -    NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos, TokenKind token);
  24.112 -
  24.113 -    Kind kind() const {
  24.114 -        return FUNCTION;
  24.115 -    }
  24.116 -    void allocate(unsigned slot) {
  24.117 -        slot_ = slot;
  24.118 -    }
  24.119 -    bool isForward() const {
  24.120 -        return token_ == TOK_FORWARD;
  24.121 -    }
  24.122 -    bool isPublic() const {
  24.123 -        return token_ == TOK_PUBLIC;
  24.124 -    }
  24.125 -    bool isNative() const {
  24.126 -        return token_ == TOK_NATIVE;
  24.127 -    }
  24.128 -    TokenKind token() const {
  24.129 -        return token_;
  24.130 -    }
  24.131 -    void setForwardType(Handle<Type> type) {
  24.132 -        forwardType_ = type;
  24.133 -    }
  24.134 -    Type *forwardType() {
  24.135 -        return forwardType_;
  24.136 -    }
  24.137 -    void setImplemented(const SourcePosition &at) {
  24.138 -        token_ = TOK_PUBLIC;
  24.139 -        pos_ = at;
  24.140 -    }
  24.141 -    void markNativeVariadic() {
  24.142 -        assert(token_ == TOK_NATIVE);
  24.143 -        isVariadicNative_ = true;
  24.144 -    }
  24.145 -    bool isNativeVariadic() {
  24.146 -        assert(token_ == TOK_NATIVE);
  24.147 -        return isVariadicNative_;
  24.148 -    }
  24.149 -    unsigned slot() const {
  24.150 -        return slot_;
  24.151 -    }
  24.152 -    bool addUsedGlobal(BoundName *name) {
  24.153 -        return globals_.append(name);
  24.154 -    }
  24.155 -    Vector<BoundName *, PoolAllocationPolicy> *usedGlobals() {
  24.156 -        return &globals_;
  24.157 -    }
  24.158 -};
  24.159 -
  24.160 -class NamedConstant : public BoundName
  24.161 -{
  24.162 -    BoxedPrimitive value_;
  24.163 -
  24.164 -  public:
  24.165 -    NamedConstant(Scope *scope, Handle<String> name, const SourcePosition &pos)
  24.166 -      : BoundName(scope, name, pos)
  24.167 -    {
  24.168 -    }
  24.169 -
  24.170 -    Kind kind() const {
  24.171 -        return CONSTANT;
  24.172 -    }
  24.173 -    void set(Handle<Type> type, const BoxedPrimitive &value) {
  24.174 -        value_ = value;
  24.175 -        setType(type);
  24.176 -    }
  24.177 -    BoxedPrimitive value() const {
  24.178 -        return value_;
  24.179 -    }
  24.180 -};
  24.181 -
  24.182 -class NamedType : public BoundName
  24.183 -{
  24.184 -  public:
  24.185 -    NamedType(Scope *scope, Handle<String> name, Handle<Type> type)
  24.186 -      : BoundName(scope, name, SourcePosition())
  24.187 -    {
  24.188 -        setType(type);
  24.189 -    }
  24.190 -
  24.191 -    NamedType(Scope *scope, Handle<String> name, const SourcePosition &pos)
  24.192 -      : BoundName(scope, name, pos)
  24.193 -    {
  24.194 -    }
  24.195 -
  24.196 -    Kind kind() const {
  24.197 -        return TYPE;
  24.198 -    }
  24.199 -};
  24.200 -
  24.201 -class UnboundName : public BoundName
  24.202 -{
  24.203 -  public:
  24.204 -    UnboundName(Scope *scope, Handle<String> name)
  24.205 -      : BoundName(scope, name, SourcePosition())
  24.206 -    {
  24.207 -    }
  24.208 -
  24.209 -    Kind kind() const {
  24.210 -        return UNBOUND;
  24.211 -    }
  24.212 -};
  24.213 -
  24.214 -class Variable : public BoundName
  24.215 -{
  24.216 -  public:
  24.217 -    enum Location {
  24.218 -        UNALLOCATED,
  24.219 -        STACK,
  24.220 -        PARAMETER,
  24.221 -        ENVIRONMENT
  24.222 -    };
  24.223 -
  24.224 -    Variable(Scope *scope, Handle<String> name, const SourcePosition &pos);
  24.225 -
  24.226 -    Kind kind() const {
  24.227 -        return VARIABLE;
  24.228 -    }
  24.229 -    bool unallocated() const {
  24.230 -        return location() == UNALLOCATED;
  24.231 -    }
  24.232 -    void allocate(Location location, unsigned slot) {
  24.233 -        location_ = location;
  24.234 -        slot_ = slot;
  24.235 -    }
  24.236 -    Location location() const {
  24.237 -        return location_;
  24.238 -    }
  24.239 -    unsigned slot() const {
  24.240 -        assert(!unallocated());
  24.241 -        return slot_;
  24.242 -    }
  24.243 -    void setPublic() {
  24.244 -        assert(!public_);
  24.245 -        public_ = true;
  24.246 -    }
  24.247 -    bool isPublic() const {
  24.248 -        return public_;
  24.249 -    }
  24.250 -    bool needsHeapAllocation();
  24.251 -
  24.252 -  private:
  24.253 -    Location location_;
  24.254 -    unsigned slot_;
  24.255 -    bool public_;
  24.256 -};
  24.257 -
  24.258 -}
  24.259 -
  24.260 -#endif // _include_name_binding_h_
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/NativeTable.cpp	Sat Nov 17 18:41:01 2012 -0800
    25.3 @@ -0,0 +1,96 @@
    25.4 +/* vim: set ts=4 sw=4 tw=99 et:
    25.5 + *
    25.6 + * Copyright (C) 2012 David Anderson
    25.7 + *
    25.8 + * This file is part of SourcePawn.
    25.9 + *
   25.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   25.11 + * the terms of the GNU General Public License as published by the Free
   25.12 + * Software Foundation, either version 3 of the License, or (at your option)
   25.13 + * any later version.
   25.14 + * 
   25.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   25.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   25.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   25.18 + *
   25.19 + * You should have received a copy of the GNU General Public License along with
   25.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   25.21 + */
   25.22 +#include "Zone.h"
   25.23 +#include "NativeTable.h"
   25.24 +#include "StringPool.h"
   25.25 +
   25.26 +using namespace ke;
   25.27 +
   25.28 +NativeTable::NativeTable(Zone *zone)
   25.29 +  : zone_(zone),
   25.30 +    nativeMap_(ZoneAllocatorPolicy())
   25.31 +{
   25.32 +}
   25.33 +
   25.34 +NativeTable::~NativeTable()
   25.35 +{
   25.36 +    for (size_t i = 0; i < natives_.length(); i++)
   25.37 +        delete natives_[i];
   25.38 +}
   25.39 +
   25.40 +bool
   25.41 +NativeTable::initialize()
   25.42 +{
   25.43 +    return nativeMap_.init(16);
   25.44 +}
   25.45 +
   25.46 +bool
   25.47 +NativeTable::add(Handle<String> name, size_t *indexp)
   25.48 +{
   25.49 +    // :TODO: assert no GC
   25.50 +    CharsAndLength key(name->chars(), name->length());
   25.51 +    NativeMap::Insert p = nativeMap_.findForAdd(key);
   25.52 +    if (p.found()) {
   25.53 +        *indexp = (*p)->index;
   25.54 +        return true;
   25.55 +    }
   25.56 +
   25.57 +    NativeInfo *info = new NativeInfo(name, NULL, natives_.length());
   25.58 +    if (!info || !natives_.append(info))
   25.59 +        return false;
   25.60 +
   25.61 +    if (!nativeMap_.add(p, info))
   25.62 +        return false;
   25.63 +
   25.64 +    *indexp = info->index;
   25.65 +
   25.66 +    return true;
   25.67 +}
   25.68 +
   25.69 +bool
   25.70 +NativeTable::bind(const char *name, void *address)
   25.71 +{
   25.72 +    CharsAndLength key(name, strlen(name));
   25.73 +    NativeMap::Insert p = nativeMap_.findForAdd(key);
   25.74 +    if (p.found()) {
   25.75 +        (*p)->address = address;
   25.76 +        return true;
   25.77 +    }
   25.78 +
   25.79 +    Local<String> str(zone_, zone_->symbols()->add(key.str(), key.length()));
   25.80 +    if (!str)
   25.81 +        return false;
   25.82 +
   25.83 +    // :TODO: assert no GC
   25.84 +    NativeInfo *info = new NativeInfo(str, address, natives_.length());
   25.85 +    if (!info || !natives_.append(info))
   25.86 +        return false;
   25.87 +
   25.88 +    if (!nativeMap_.add(p, info))
   25.89 +        return false;
   25.90 +
   25.91 +    return true;
   25.92 +}
   25.93 +
   25.94 +void
   25.95 +NativeTable::accept(VirtualObjectVisitor *visitor)
   25.96 +{
   25.97 +    for (size_t i = 0; i < natives_.length(); i++)
   25.98 +        visitor->visit(natives_[i]->name.address());
   25.99 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/NativeTable.h	Sat Nov 17 18:41:01 2012 -0800
    26.3 @@ -0,0 +1,89 @@
    26.4 +/* vim: set ts=4 sw=4 tw=99 et:
    26.5 + *
    26.6 + * Copyright (C) 2012 David Anderson
    26.7 + *
    26.8 + * This file is part of SourcePawn.
    26.9 + *
   26.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   26.11 + * the terms of the GNU General Public License as published by the Free
   26.12 + * Software Foundation, either version 3 of the License, or (at your option)
   26.13 + * any later version.
   26.14 + * 
   26.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   26.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   26.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   26.18 + *
   26.19 + * You should have received a copy of the GNU General Public License along with
   26.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   26.21 + */
   26.22 +#ifndef _include_sp2_native_table_h_
   26.23 +#define _include_sp2_native_table_h_
   26.24 +
   26.25 +#include "AllocatorPolicies.h"
   26.26 +#include "Strings.h"
   26.27 +#include "HashTable.h"
   26.28 +#include "Vector.h"
   26.29 +#include "VirtualObjectVisitor.h"
   26.30 +
   26.31 +namespace ke {
   26.32 +
   26.33 +class NativeTable
   26.34 +{
   26.35 +  public:
   26.36 +    NativeTable(Zone *zone);
   26.37 +    ~NativeTable();
   26.38 +
   26.39 +  private:
   26.40 +    struct NativeInfo {
   26.41 +        Unbarriered<String> name;
   26.42 +        void *address;
   26.43 +        size_t index;
   26.44 +
   26.45 +        NativeInfo(String *name, void *address, size_t index)
   26.46 +          : address(address),
   26.47 +            index(index)
   26.48 +        {
   26.49 +            this->name = name;
   26.50 +        }
   26.51 +    };
   26.52 +
   26.53 +    struct Policy
   26.54 +    {
   26.55 +        typedef NativeInfo * Payload;
   26.56 +
   26.57 +        static uint32 hash(const CharsAndLength &key) {
   26.58 +            return HashCharSequence(key.str(), key.length());
   26.59 +        }
   26.60 +        
   26.61 +        static bool matches(const CharsAndLength &key, NativeInfo *info) {
   26.62 +            if (info->name->length() != key.length())
   26.63 +                return false;
   26.64 +            return memcmp(info->name->chars(), key.str(), key.length() * sizeof(char)) == 0;
   26.65 +        }
   26.66 +    };
   26.67 +
   26.68 +    typedef HashTable<Policy, ZoneAllocatorPolicy> NativeMap;
   26.69 +
   26.70 +  public:
   26.71 +    bool initialize();
   26.72 +
   26.73 +    bool bind(const char *name, void *address);
   26.74 +    bool add(Handle<String> name, size_t *indexp);
   26.75 +    String *name(size_t index) const {
   26.76 +        return natives_[index]->name;
   26.77 +    }
   26.78 +    void *address(size_t index) const {
   26.79 +        return natives_[index]->address;
   26.80 +    }
   26.81 +
   26.82 +    void accept(VirtualObjectVisitor *visitor);
   26.83 +
   26.84 +  private:
   26.85 +    Zone *zone_;
   26.86 +    NativeMap nativeMap_;
   26.87 +    Vector<NativeInfo *> natives_;
   26.88 +};
   26.89 +
   26.90 +}
   26.91 +
   26.92 +#endif // _include_sp2_native_table_h_
    27.1 --- a/src/ObjectVisitor.h	Mon Sep 17 00:10:01 2012 -0700
    27.2 +++ b/src/ObjectVisitor.h	Sat Nov 17 18:41:01 2012 -0800
    27.3 @@ -47,13 +47,25 @@
    27.4  
    27.5      size_t iterateType(Object *obj) {
    27.6          visitField(obj, Type::offsetOfContained());
    27.7 -        visitField(obj, Type::offsetOfReturnType());
    27.8 -        visitField(obj, Type::offsetOfParameters());
    27.9 +        visitField(obj, Type::offsetOfName());
   27.10 +        return sizeof(Type);
   27.11 +    }
   27.12 +
   27.13 +    size_t iterateStructType(Object *obj) {
   27.14 +        visitField(obj, Type::offsetOfContained());
   27.15          visitField(obj, Type::offsetOfName());
   27.16 -        visitField(obj, Type::offsetOfFields());
   27.17 -        visitField(obj, Type::offsetOfDefaults());
   27.18 -        visitField(obj, Type::offsetOfNewMap());
   27.19 -        return sizeof(Type);
   27.20 +        visitField(obj, StructType::offsetOfFields());
   27.21 +        visitField(obj, StructType::offsetOfNewMap());
   27.22 +        return sizeof(StructType);
   27.23 +    }
   27.24 +
   27.25 +    size_t iterateFunctionType(Object *obj) {
   27.26 +        visitField(obj, Type::offsetOfContained());
   27.27 +        visitField(obj, Type::offsetOfName());
   27.28 +        visitField(obj, FunctionType::offsetOfReturnType());
   27.29 +        visitField(obj, FunctionType::offsetOfParameters());      
   27.30 +        visitField(obj, FunctionType::offsetOfDefaults());
   27.31 +        return sizeof(FunctionType);
   27.32      }
   27.33  
   27.34      size_t iterateFixedArray(FixedArray *array) {
   27.35 @@ -75,6 +87,7 @@
   27.36          visitField(obj, Code::offsetOfObjects());
   27.37          visitField(obj, Code::offsetOfSafepoints());
   27.38          visitField(obj, Code::offsetOfSourceMap());
   27.39 +        visitField(obj, Code::offsetOfStrings());
   27.40          return sizeof(Code);
   27.41      }
   27.42  
   27.43 @@ -84,11 +97,8 @@
   27.44      }
   27.45  
   27.46      size_t iterateModule(Object *obj) {
   27.47 -        visitField(obj, Module::offsetOfFunctions());
   27.48 -        visitField(obj, Module::offsetOfPublics());
   27.49 -        visitField(obj, Module::offsetOfNatives());
   27.50          visitField(obj, Module::offsetOfFile());
   27.51 -        visitField(obj, Module::offsetOfEnvironment());
   27.52 +        visitField(obj, Module::offsetOfGlobals());
   27.53          visitField(obj, Module::offsetOfCode());
   27.54          return sizeof(Module);
   27.55      }
   27.56 @@ -108,7 +118,6 @@
   27.57  
   27.58      size_t iterateNative(Object *obj) {
   27.59          visitField(obj, Native::offsetOfType());
   27.60 -        visitField(obj, Native::offsetOfName());
   27.61          return sizeof(Native);
   27.62      }
   27.63  
   27.64 @@ -182,6 +191,12 @@
   27.65            case MapKind_Type:
   27.66              return iterateType(obj);
   27.67  
   27.68 +          case MapKind_FunctionType:
   27.69 +            return iterateFunctionType(obj);
   27.70 +
   27.71 +          case MapKind_StructType:
   27.72 +            return iterateStructType(obj);
   27.73 +
   27.74            case MapKind_FixedArray:
   27.75              return iterateFixedArray(FixedArray::cast(obj));
   27.76  
   27.77 @@ -256,6 +271,12 @@
   27.78        case MapKind_Type:
   27.79          return sizeof(Type);
   27.80  
   27.81 +      case MapKind_FunctionType:
   27.82 +        return sizeof(FunctionType);
   27.83 +
   27.84 +      case MapKind_StructType:
   27.85 +        return sizeof(StructType);
   27.86 +
   27.87        case MapKind_FixedArray:
   27.88          return FixedArray::cast(obj)->objSize();
   27.89  
    28.1 --- a/src/Objects.h	Mon Sep 17 00:10:01 2012 -0700
    28.2 +++ b/src/Objects.h	Sat Nov 17 18:41:01 2012 -0800
    28.3 @@ -35,6 +35,8 @@
    28.4  {
    28.5      // Represents Type objects.
    28.6      MapKind_Type,
    28.7 +    MapKind_FunctionType,
    28.8 +    MapKind_StructType,
    28.9  
   28.10      // Represents basic data structures. When adding to this, don't forget
   28.11      // to update Zone::initialize(), or you'll get a NULL crash trying to
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/src/OldByCo.cpp	Sat Nov 17 18:41:01 2012 -0800
    29.3 @@ -0,0 +1,1585 @@
    29.4 +/* vim: set ts=4 sw=4 tw=99 et:
    29.5 + *
    29.6 + * Copyright (C) 2012 David Anderson
    29.7 + *
    29.8 + * This file is part of JITCraft.
    29.9 + *
   29.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   29.11 + * the terms of the GNU General Public License as published by the Free
   29.12 + * Software Foundation, either version 3 of the License, or (at your option)
   29.13 + * any later version.
   29.14 + * 
   29.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   29.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   29.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   29.18 + *
   29.19 + * You should have received a copy of the GNU General Public License along with
   29.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   29.21 + */
   29.22 +#include <string.h>
   29.23 +#include "../Modules.h"
   29.24 +#include "../Types.h"
   29.25 +#include "../Array.h"
   29.26 +#include "../Strings.h"
   29.27 +#include "../Zone.h"
   29.28 +#include "../Environments.h"
   29.29 +#include "../Box.h"
   29.30 +#include "../Heap-inl.h"
   29.31 +#include "BytecodeCompiler.h"
   29.32 +#include "Scopes.h"
   29.33 +
   29.34 +using namespace ke;
   29.35 +
   29.36 +typedef BytecodeEmitter::Label Label;
   29.37 +
   29.38 +#define __ emitter_.
   29.39 +
   29.40 +BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
   29.41 +  : zone_(zone),
   29.42 +    tree_(tree),
   29.43 +    emitter_(zone->pool()),
   29.44 +    locals_(NULL),
   29.45 +    scope_(NULL),
   29.46 +    moduleData_(module),
   29.47 +    loop_(NULL)
   29.48 +{
   29.49 +}
   29.50 +
   29.51 +static inline TokenKind
   29.52 +ToCompare(Expression *expr)
   29.53 +{
   29.54 +    if (expr->isBinaryExpression()) {
   29.55 +        BinaryExpression *b = expr->toBinaryExpression();
   29.56 +        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
   29.57 +            return b->token();
   29.58 +    } else if (expr->isUnaryExpression()) {
   29.59 +        UnaryExpression *u = expr->toUnaryExpression();
   29.60 +        if (u->token() == TOK_NOT)
   29.61 +            return TOK_NOT;
   29.62 +    }
   29.63 +    return TOK_EOF;
   29.64 +}
   29.65 +
   29.66 +static inline Opcode
   29.67 +CompareTokenToJump(TokenKind kind)
   29.68 +{
   29.69 +    switch (kind) {
   29.70 +      case TOK_EQUALS:
   29.71 +        return OP_JEQ;
   29.72 +      case TOK_NOTEQUALS:
   29.73 +        return OP_JNE;
   29.74 +      case TOK_GT:
   29.75 +        return OP_JG;
   29.76 +      case TOK_GE:
   29.77 +        return OP_JGE;
   29.78 +      case TOK_LT:
   29.79 +        return OP_JL;
   29.80 +      default:
   29.81 +        assert(kind == TOK_LE);
   29.82 +        return OP_JLE;
   29.83 +    }
   29.84 +}
   29.85 +
   29.86 +static inline Opcode
   29.87 +TokenToOpcode(TokenKind kind)
   29.88 +{
   29.89 +    switch (kind) {
   29.90 +      case TOK_PLUS:
   29.91 +        return OP_ADD;
   29.92 +      case TOK_MINUS:
   29.93 +        return OP_SUB;
   29.94 +      case TOK_STAR:
   29.95 +        return OP_MUL;
   29.96 +      case TOK_SLASH:
   29.97 +        return OP_DIV;
   29.98 +      case TOK_PERCENT:
   29.99 +        return OP_MOD;
  29.100 +      case TOK_SHR:
  29.101 +        return OP_SHR;
  29.102 +      case TOK_USHR:
  29.103 +        return OP_USHR;
  29.104 +      case TOK_SHL:
  29.105 +        return OP_SHL;
  29.106 +      case TOK_BITAND:
  29.107 +        return OP_BITAND;
  29.108 +      case TOK_BITOR:
  29.109 +        return OP_BITOR;
  29.110 +      case TOK_GT:
  29.111 +          return OP_GT;
  29.112 +      case TOK_GE:
  29.113 +          return OP_GE;
  29.114 +      case TOK_LT:
  29.115 +          return OP_LT;
  29.116 +      case TOK_LE:
  29.117 +          return OP_LE;
  29.118 +      case TOK_EQUALS:
  29.119 +          return OP_EQ;
  29.120 +      case TOK_NOTEQUALS:
  29.121 +          return OP_NE;
  29.122 +      default:
  29.123 +        assert(kind == TOK_BITXOR);
  29.124 +        return OP_BITXOR;
  29.125 +    }
  29.126 +}
  29.127 +
  29.128 +void
  29.129 +BytecodeCompiler::recordLifoSlot(Scope *scope)
  29.130 +{
  29.131 +    if (!scope)
  29.132 +        return;
  29.133 +
  29.134 +    if (Variable *var = scope->lifoSlot()) {
  29.135 +        locals_->set(zone_, var->slot(), var->type());
  29.136 +        __ savelifo(var->slot());
  29.137 +    }
  29.138 +}
  29.139 +
  29.140 +void
  29.141 +BytecodeCompiler::unwindTo(Scope *scope)
  29.142 +{
  29.143 +    // Note: we only need to unwind to the outermost scope's LIFO slot.
  29.144 +    Variable *var = NULL;
  29.145 +    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
  29.146 +        if (Variable *slot = current->lifoSlot())
  29.147 +            var = slot;
  29.148 +    }
  29.149 +
  29.150 +    if (var)
  29.151 +        __ unwindlifo(var->slot());
  29.152 +}
  29.153 +
  29.154 +void
  29.155 +BytecodeCompiler::visit(NameProxy *name)
  29.156 +{
  29.157 +    switch (name->binding()->kind()) {
  29.158 +      case BoundName::VARIABLE:
  29.159 +      {
  29.160 +        Variable *var = name->binding()->toVariable();
  29.161 +
  29.162 +        if (var->location() == Variable::STACK) {
  29.163 +            __ getlocal(var);
  29.164 +            assert(!name->type()->isReference());
  29.165 +        } else if (var->location() == Variable::ENVIRONMENT) {
  29.166 +            getEnvSlot(var);
  29.167 +        } else {
  29.168 +            assert(var->location() == Variable::PARAMETER);
  29.169 +            __ getarg(var);
  29.170 +
  29.171 +            // If this argument is actually a reference, dereference it now.
  29.172 +            if (var->type()->isReference())
  29.173 +                __ getref(var->type()->contained());
  29.174 +        }
  29.175 +        break;
  29.176 +      }
  29.177 +
  29.178 +      case BoundName::FUNCTION:
  29.179 +      {
  29.180 +        NamedFunction *fun = name->binding()->toNamedFunction();
  29.181 +        __ module();
  29.182 +        __ getmodule_fn(fun->slot());
  29.183 +        break;
  29.184 +      }
  29.185 +
  29.186 +      default:
  29.187 +      {
  29.188 +        NamedConstant *constant = name->binding()->toNamedConstant();
  29.189 +        __ int_(constant->value().toInt());
  29.190 +        break;
  29.191 +      }
  29.192 +    }
  29.193 +}
  29.194 +
  29.195 +void
  29.196 +BytecodeCompiler::visit(ExpressionStatement *node)
  29.197 +{
  29.198 +    // Expressions leave their value on the top of the stack, so we make sure
  29.199 +    // to balance the stack if they're used as a statement.
  29.200 +    node->expression()->accept(this);
  29.201 +    if (!node->expression()->type()->isVoid())
  29.202 +        __ pop();
  29.203 +}
  29.204 +
  29.205 +static inline bool
  29.206 +IsCompositeValueType(Type *type)
  29.207 +{
  29.208 +    return type->isStruct() ||
  29.209 +           (type->isArray() && type->isFixedLength());
  29.210 +}
  29.211 +
  29.212 +static inline Array *
  29.213 +StringLiteralToArray(Zone *zone, StringLiteral *node)
  29.214 +{
  29.215 +    Local<Type> type(zone, node->type());
  29.216 +    Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
  29.217 +    if (!map)
  29.218 +        return NULL;
  29.219 +
  29.220 +    return Array::NewString(zone,
  29.221 +                            map,
  29.222 +                            node->string()->raw(),
  29.223 +                            node->string()->length(),
  29.224 +                            Heap::Tenure_Old);
  29.225 +}
  29.226 +
  29.227 +void
  29.228 +BytecodeCompiler::visit(Assignment *node)
  29.229 +{
  29.230 +    Local<Type> left(zone_, node->type());
  29.231 +    Local<Type> right(zone_, node->expression()->type());
  29.232 +
  29.233 +    // The first step is three sub-steps:
  29.234 +    //
  29.235 +    //   (1) Bind the left-hand side.
  29.236 +    //   -- If a cumulative operation (+=, etc):
  29.237 +    //   (2) Save a copy of the binding on the stack.
  29.238 +    //   (3) Dereference the binding to get a value.
  29.239 +    //
  29.240 +    if (node->lvalue()->isNameProxy()) {
  29.241 +        NameProxy *proxy = node->lvalue()->toNameProxy();
  29.242 +        Variable *var = proxy->binding()->toVariable();
  29.243 +
  29.244 +        // We need to fetch the variable under the following circumstances:
  29.245 +        //  (1) The variable is a reference, since we'll store into the ref.
  29.246 +        //  (2) The variable is a fixed array, since we need to copy into it.
  29.247 +        //  (3) The variable is a struct, since we need to copy into it.
  29.248 +        if (var->type()->isReference() || IsCompositeValueType(var->type()))
  29.249 +            __ get(var);
  29.250 +
  29.251 +        // Get the value if needed.
  29.252 +        if (node->token() != TOK_ASSIGN) {
  29.253 +            // += etc is not allowed on arrays.
  29.254 +            assert(!var->type()->isArray());
  29.255 +
  29.256 +            if (var->location() == Variable::ENVIRONMENT)
  29.257 +                getEnvSlot(var);
  29.258 +
  29.259 +            if (var->type()->isReference()) {
  29.260 +                __ dup();
  29.261 +                __ getref(var->type()->contained());
  29.262 +            } else if (var->location() != Variable::ENVIRONMENT) {
  29.263 +                __ get(var);
  29.264 +            }
  29.265 +        }
  29.266 +    } else if (node->lvalue()->isFieldExpression()) {
  29.267 +        FieldExpression *expr = node->lvalue()->toFieldExpression();
  29.268 +        __ note_position(expr->pos());
  29.269 +
  29.270 +        expr->left()->accept(this);
  29.271 +
  29.272 +        if (node->token() != TOK_ASSIGN)
  29.273 +            __ dup();
  29.274 +
  29.275 +        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
  29.276 +            __ getfield(expr->fieldIndex(), left);
  29.277 +    } else {
  29.278 +        IndexExpression *index = node->lvalue()->toIndexExpression();
  29.279 +        __ note_position(index->pos());
  29.280 +
  29.281 +        index->left()->accept(this);
  29.282 +        index->right()->accept(this);
  29.283 +
  29.284 +        if (node->token() != TOK_ASSIGN)
  29.285 +            __ dup2();
  29.286 +
  29.287 +        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
  29.288 +            __ getelem(left);
  29.289 +    }
  29.290 +
  29.291 +    if (node->token() == TOK_ASSIGN) {
  29.292 +        // Special case: if the left-hand side is a string literal, we must
  29.293 +        // spawn a new copy (:TODO: something about const?)
  29.294 +        if (node->expression()->isStringLiteral() && !left->isFixedLength()) {
  29.295 +            Local<Array> string(zone_,
  29.296 +                    StringLiteralToArray(zone_, node->expression()->toStringLiteral()));
  29.297 +            if (!string)
  29.298 +                return;
  29.299 +
  29.300 +            Local<ArrayMap> arrayMap(zone_, ArrayMap::cast(string->map()));
  29.301 +            __ note_position(node->expression()->pos());
  29.302 +            __ int_(string->length());
  29.303 +            __ newarray(OP_NEWSIZED, arrayMap, Heap::Tenure_Default);
  29.304 +            __ object(string);
  29.305 +            __ copyarray();
  29.306 +        } else {
  29.307 +            node->expression()->accept(this);
  29.308 +        }
  29.309 +    } else {
  29.310 +        visitForALU(left, node->expression());
  29.311 +
  29.312 +        TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
  29.313 +        __ note_position(node->pos());
  29.314 +        __ binary(TokenToOpcode(alu));
  29.315 +    }
  29.316 +
  29.317 +    // Emit the store.
  29.318 +    if (left->isArray() && left->isFixedLength()) {
  29.319 +        // (x = y) returns the left-hand side; if |x| is a fixed-length array,
  29.320 +        // then |y| is as well, and we perform a deep copy.
  29.321 +        assert(right->isFixedLength());
  29.322 +        __ note_position(node->pos());
  29.323 +        __ copyarray();
  29.324 +    } else if (left->isStruct()) {
  29.325 +        // Structs have value semantics, so emit a full copy. We don't break
  29.326 +        // this down into u-ops, to avoid unnecessary bytecode explosion.
  29.327 +        assert(right->isStruct());
  29.328 +        __ note_position(node->pos());
  29.329 +        __ copystruct();
  29.330 +    } else if (node->lvalue()->isNameProxy()) {
  29.331 +        NameProxy *proxy = node->lvalue()->toNameProxy();
  29.332 +        Variable *var = proxy->binding()->toVariable();
  29.333 +
  29.334 +        if (var->type()->isReference())
  29.335 +            __ setref(var->type()->contained());
  29.336 +        else if (var->location() == Variable::ENVIRONMENT)
  29.337 +            setEnvSlot(var);
  29.338 +        else
  29.339 +            __ set(var);
  29.340 +    } else if (node->lvalue()->isFieldExpression()) {
  29.341 +        FieldExpression *expr = node->lvalue()->toFieldExpression();
  29.342 +        __ setfield(expr->fieldIndex(), left);
  29.343 +    } else {
  29.344 +        __ setelem(left);
  29.345 +    }
  29.346 +}
  29.347 +
  29.348 +void
  29.349 +BytecodeCompiler::visit(IncDecExpression *node)
  29.350 +{
  29.351 +    // In the postfix case, the logic looks like:
  29.352 +    //      (1) Bind       -> REF
  29.353 +    //      (2) Dup        -> REF REF
  29.354 +    //      (3) Fetch      -> REF VAL
  29.355 +    //      (4) Swap       -> VAL REF
  29.356 +    //      (5) Pick       -> VAL REF VAL
  29.357 +    //      (6) Add        -> VAL REF VAL+1
  29.358 +    //      (7) Store      -> VAL VAL+1
  29.359 +    //      (8) Drop       -> VAL
  29.360 +    //
  29.361 +    // In the prefix case, the logic looks like:
  29.362 +    //      (1) Bind       -> REF
  29.363 +    //      (2) Dup        -> REF REF
  29.364 +    //      (3) Fetch      -> REF VAL
  29.365 +    //      --
  29.366 +    //      --
  29.367 +    //      (6) Add        -> REF VAL+1
  29.368 +    //      (7) Store      -> VAL+1
  29.369 +    //      --
  29.370 +    //
  29.371 +    // This is squirrely enough such that we don't bother sharing too much
  29.372 +    // with the above.
  29.373 +    // 
  29.374 +    // Note: We simulate a "Pick" operation with a dup2+pop.
  29.375 +
  29.376 +    // This is steps (1) to (5).
  29.377 +    Expression *expr = node->expression();
  29.378 +    if (expr->isNameProxy()) {
  29.379 +        NameProxy *proxy = expr->toNameProxy();
  29.380 +        Variable *var = proxy->binding()->toVariable();
  29.381 +
  29.382 +        // Bind.
  29.383 +        if (var->location() == Variable::ENVIRONMENT)
  29.384 +            getEnvSlot(var);
  29.385 +        else if (var->type()->isReference() || var->type()->isArray())
  29.386 +            __ get(var);
  29.387 +
  29.388 +        // Dup and fetch.
  29.389 +        if (var->type()->isReference()) {
  29.390 +            __ dup();
  29.391 +            __ getref(node->type());
  29.392 +            if (node->postfix()) {
  29.393 +                __ swap();
  29.394 +                __ pick2();
  29.395 +            }
  29.396 +        } else {
  29.397 +            assert(!var->type()->isArray());
  29.398 +            if (var->location() != Variable::ENVIRONMENT)
  29.399 +                __ get(var);
  29.400 +            if (node->postfix())
  29.401 +                __ dup();
  29.402 +        }
  29.403 +    } else if (expr->isFieldExpression()) {
  29.404 +        FieldExpression *field = expr->toFieldExpression();
  29.405 +
  29.406 +        field->left()->accept(this);
  29.407 +        __ dup();
  29.408 +        __ getfield(field->fieldIndex(), field->type());
  29.409 +
  29.410 +        if (node->postfix()) {
  29.411 +            // The stack looks like this now:
  29.412 +            // OBJECT VALUE
  29.413 +            __ swap();          // VALUE OBJECT
  29.414 +            __ pick2();         // VALUE OBJECT VALUE
  29.415 +        }
  29.416 +    } else {
  29.417 +        IndexExpression *index = expr->toIndexExpression();
  29.418 +        __ note_position(index->pos());
  29.419 +
  29.420 +        index->left()->accept(this);
  29.421 +        index->right()->accept(this);
  29.422 +
  29.423 +        assert(!node->type()->isArray());
  29.424 +        __ dup2();
  29.425 +        __ getelem(node->type());
  29.426 +
  29.427 +        if (node->postfix()) {
  29.428 +            // The stack looks like this now:
  29.429 +            // ARRAY INDEX VALUE
  29.430 +            //
  29.431 +            // So we must use a PICK operation to rotate the stack into position.
  29.432 +            __ roll3();         // INDEX VALUE ARRAY
  29.433 +            __ roll3();         // VALUE ARRAY INDEX
  29.434 +            __ pick3();         // VALUE ARRAY INDEX VALUE
  29.435 +        }
  29.436 +    }
  29.437 +
  29.438 +    // Perform step (6).
  29.439 +    if (node->type()->isFloat()) {
  29.440 +        __ float_(1.0);
  29.441 +    } else {
  29.442 +        assert(node->type()->isInt32());
  29.443 +        __ int_(1);
  29.444 +    }
  29.445 +
  29.446 +    __ note_position(node->pos());
  29.447 +    if (node->token() == TOK_INCREMENT)
  29.448 +        __ binary(OP_ADD);
  29.449 +    else
  29.450 +        __ binary(OP_SUB);
  29.451 +
  29.452 +    // Perform step (7).
  29.453 +    if (expr->isNameProxy()) {
  29.454 +        NameProxy *proxy = expr->toNameProxy();
  29.455 +        Variable *var = proxy->binding()->toVariable();
  29.456 +
  29.457 +        if (var->type()->isReference())
  29.458 +            __ setref(node->type());
  29.459 +        else if (var->location() == Variable::ENVIRONMENT)
  29.460 +            setEnvSlot(var);
  29.461 +        else
  29.462 +            __ set(var);
  29.463 +    } else if (expr->isFieldExpression()) {
  29.464 +        FieldExpression *field = expr->toFieldExpression();
  29.465 +        __ setfield(field->fieldIndex(), field->type());
  29.466 +    } else {
  29.467 +        assert(expr->isIndexExpression());
  29.468 +        __ setelem(node->type());
  29.469 +    }
  29.470 +
  29.471 +    // Perform step (8).
  29.472 +    if (node->postfix())
  29.473 +        __ pop();
  29.474 +}
  29.475 +
  29.476 +void
  29.477 +BytecodeCompiler::visitForALU(Type *needed, Expression *node)
  29.478 +{
  29.479 +    node->accept(this);
  29.480 +    if (needed->isFloat() && !node->type()->isFloat())
  29.481 +        __ cvt_i2f();
  29.482 +    else
  29.483 +        assert(needed->primitive() == node->type()->primitive());
  29.484 +}
  29.485 +
  29.486 +static inline Type *
  29.487 +GetCoercionType(TokenKind tok, Type *left, Type *right)
  29.488 +{
  29.489 +    if (left->isFloat())
  29.490 +        return left;
  29.491 +    return right;
  29.492 +}
  29.493 +
  29.494 +void
  29.495 +BytecodeCompiler::visit(UnaryExpression *node)
  29.496 +{
  29.497 +    Local<Type> out(zone_, ((Expression *)node)->type());
  29.498 +
  29.499 +    switch (node->token()) {
  29.500 +      case TOK_MINUS:
  29.501 +      {
  29.502 +        Local<Type> type(zone_, node->expression()->type());
  29.503 +        node->expression()->accept(this);
  29.504 +        
  29.505 +        if (out->isFloat())
  29.506 +            __ neg_f();
  29.507 +        else
  29.508 +            __ neg();
  29.509 +        break;
  29.510 +      }
  29.511 +
  29.512 +      case TOK_NOT:
  29.513 +      {
  29.514 +        Local<Type> type(zone_, node->expression()->type());
  29.515 +        node->expression()->accept(this);
  29.516 +        
  29.517 +        if (out->isFloat())
  29.518 +            __ not_f();
  29.519 +        else
  29.520 +            __ not_();
  29.521 +        break;
  29.522 +      }
  29.523 +
  29.524 +      case TOK_LABEL:
  29.525 +      {
  29.526 +        Local<Type> from(zone_, node->expression()->type());
  29.527 +
  29.528 +        node->expression()->accept(this);
  29.529 +        if (!from->isFloat() && out->isFloat())
  29.530 +            __ bits_f2i();
  29.531 +        else if (from->isFloat() && !out->isFloat())
  29.532 +            __ bits_i2f();
  29.533 +        break;
  29.534 +      }
  29.535 +
  29.536 +      case TOK_SIZEOF:
  29.537 +      {
  29.538 +        Local<Type> type(zone_, node->expression()->type());
  29.539 +        if (type->isFixedLength()) {
  29.540 +            __ int_(type->fixedLength());
  29.541 +        } else {
  29.542 +            node->expression()->accept(this);
  29.543 +            __ sizeof_();
  29.544 +        }
  29.545 +        break;
  29.546 +      }
  29.547 +
  29.548 +      default:
  29.549 +        assert(node->token() == TOK_TILDE);
  29.550 +        node->expression()->accept(this);
  29.551 +        __ bitnot();
  29.552 +        break;
  29.553 +    }
  29.554 +}
  29.555 +
  29.556 +void
  29.557 +BytecodeCompiler::visit(BinaryExpression *node)
  29.558 +{
  29.559 +    if (node->token() == TOK_AND || node->token() == TOK_OR) {
  29.560 +        Label success, failure, done;
  29.561 +        visitForTest(node, &success, &failure, &success);
  29.562 +        __ bind(&success);
  29.563 +        __ int_(1);
  29.564 +        __ drop(1);         // Otherwise, the stack depth will be +1 too much.
  29.565 +        __ jump(&done);
  29.566 +        __ bind(&failure);
  29.567 +        __ int_(0);
  29.568 +        __ bind(&done);
  29.569 +        return;
  29.570 +    }
  29.571 +
  29.572 +    Local<Type> leftType(zone_, node->left()->type());
  29.573 +    Local<Type> rightType(zone_, node->right()->type());
  29.574 +    Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
  29.575 +
  29.576 +    visitForALU(coerce, node->left());
  29.577 +    visitForALU(coerce, node->right());
  29.578 +
  29.579 +    Opcode op = TokenToOpcode(node->token());
  29.580 +    if (node->type()->isFloat())
  29.581 +        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
  29.582 +
  29.583 +    __ note_position(node->pos());
  29.584 +    __ binary(op);
  29.585 +}
  29.586 +
  29.587 +void
  29.588 +BytecodeCompiler::visit(IndexExpression *node)
  29.589 +{
  29.590 +    node->left()->accept(this);
  29.591 +    node->right()->accept(this);
  29.592 +    __ note_position(node->pos());
  29.593 +    __ getelem(node->type());
  29.594 +}
  29.595 +
  29.596 +void
  29.597 +BytecodeCompiler::visit(FieldExpression *node)
  29.598 +{
  29.599 +    node->left()->accept(this);
  29.600 +    __ getfield(node->fieldIndex(), node->type());
  29.601 +}
  29.602 +
  29.603 +void
  29.604 +BytecodeCompiler::visit(ReturnStatement *node)
  29.605 +{
  29.606 +    if (node->expression()) {
  29.607 +        node->expression()->accept(this);
  29.608 +        __ return_();
  29.609 +    } else {
  29.610 +        __ returnvoid();
  29.611 +    }
  29.612 +}
  29.613 +
  29.614 +void
  29.615 +BytecodeCompiler::visitForTest(Expression *expression,
  29.616 +                               Label *trueBranch,
  29.617 +                               Label *falseBranch,
  29.618 +                               Label *fallthrough)
  29.619 +{
  29.620 +    TokenKind token = ToCompare(expression);
  29.621 +    if (token == TOK_EOF || token == TOK_NOT) {
  29.622 +        if (token == TOK_EOF)
  29.623 +            expression->accept(this);
  29.624 +        else
  29.625 +            expression->toUnaryExpression()->expression()->accept(this);
  29.626 +        
  29.627 +        bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
  29.628 +
  29.629 +        Opcode op = jumpOnTrue ? OP_JT : OP_JF;
  29.630 +        if (expression->type()->isFloat())
  29.631 +            op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
  29.632 +
  29.633 +        if (fallthrough == falseBranch)
  29.634 +            __ j(op, trueBranch);
  29.635 +        else
  29.636 +            __ j(op, falseBranch); 
  29.637 +        return;
  29.638 +    }
  29.639 +
  29.640 +    BinaryExpression *binary = expression->toBinaryExpression();
  29.641 +
  29.642 +    if (token == TOK_AND || token == TOK_OR) {
  29.643 +        Label next;
  29.644 +        if (token == TOK_AND)
  29.645 +            visitForTest(binary->left(), &next, falseBranch, &next);
  29.646 +        else
  29.647 +            visitForTest(binary->left(), trueBranch, &next, &next);
  29.648 +        __ bind(&next);
  29.649 +        visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
  29.650 +        return;
  29.651 +    }
  29.652 +
  29.653 +    Opcode op = CompareTokenToJump(token);
  29.654 +    if (fallthrough == trueBranch)
  29.655 +        op = Invert(op);
  29.656 +
  29.657 +    Local<Type> leftType(zone_, binary->left()->type());
  29.658 +    Local<Type> rightType(zone_, binary->right()->type());
  29.659 +    Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
  29.660 +
  29.661 +    visitForALU(coerce, binary->left());
  29.662 +    visitForALU(coerce, binary->right());
  29.663 +    if (coerce->isFloat())
  29.664 +        op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
  29.665 +
  29.666 +    if (fallthrough == trueBranch)
  29.667 +        __ j(op, falseBranch);
  29.668 +    else
  29.669 +        __ j(op, trueBranch);
  29.670 +}
  29.671 +
  29.672 +void
  29.673 +BytecodeCompiler::visit(ForStatement *node)
  29.674 +{
  29.675 +    AutoEnterScope forScope(this, node->scope());
  29.676 +
  29.677 +    recordLifoSlot(node->scope());
  29.678 +
  29.679 +    Label join, update;
  29.680 +    LoopScope loop(scope_, &join, &update, &loop_);
  29.681 +
  29.682 +    if (node->initialization())
  29.683 +        node->initialization()->accept(this);
  29.684 +
  29.685 +    Label header, test;
  29.686 +    if (node->condition())
  29.687 +        __ jump(&test);
  29.688 +
  29.689 +    __ bind(&header);
  29.690 +    node->body()->accept(this);
  29.691 +
  29.692 +    __ bind(&update);
  29.693 +    if (node->update())
  29.694 +        node->update()->accept(this);
  29.695 +
  29.696 +    if (node->condition()) {
  29.697 +        __ bind(&test);
  29.698 +        visitForTest(node->condition(), &header, &join, &join);
  29.699 +    } else {
  29.700 +        __ jump(&header);
  29.701 +    }
  29.702 +
  29.703 +    __ bind(&join);
  29.704 +
  29.705 +    if (node->scope())
  29.706 +        unwindTo(node->scope()->enclosing());
  29.707 +    assert(__ stackDepth() == 0);
  29.708 +}
  29.709 +
  29.710 +void
  29.711 +BytecodeCompiler::visit(WhileStatement *node)
  29.712 +{
  29.713 +    Label header, join;
  29.714 +
  29.715 +    __ bind(&header);
  29.716 +
  29.717 +    LoopScope loop(scope_, &join, &header, &loop_);
  29.718 +
  29.719 +    if (node->token() == TOK_WHILE) {
  29.720 +        Label body;
  29.721 +
  29.722 +        visitForTest(node->condition(), &body, &join, &body);
  29.723 +        __ bind(&body);
  29.724 +        node->body()->accept(this);
  29.725 +        __ jump(&header);
  29.726 +    } else {
  29.727 +        node->body()->accept(this);
  29.728 +        visitForTest(node->condition(), &header, &join, &join);
  29.729 +    }
  29.730 +
  29.731 +    __ bind(&join);
  29.732 +}
  29.733 +
  29.734 +void
  29.735 +BytecodeCompiler::visit(BreakStatement *node)
  29.736 +{
  29.737 +    unwindTo(loop_->scope());
  29.738 +    __ jump(loop_->break_());
  29.739 +}
  29.740 +
  29.741 +void
  29.742 +BytecodeCompiler::visit(ContinueStatement *node)
  29.743 +{
  29.744 +    unwindTo(loop_->scope());
  29.745 +    __ jump(loop_->continue_());
  29.746 +}
  29.747 +
  29.748 +void
  29.749 +BytecodeCompiler::visit(BlockStatement *node)
  29.750 +{
  29.751 +    AutoEnterScope blockScope(this, node->scope());
  29.752 +
  29.753 +    recordLifoSlot(node->scope());
  29.754 +
  29.755 +    for (size_t i = 0; i < node->statements()->length(); i++) {
  29.756 +        Statement *statement = node->statements()->at(i);
  29.757 +        statement->accept(this);
  29.758 +        assert(__ stackDepth() == 0);
  29.759 +    }
  29.760 +
  29.761 +    // We don't bother emitting an "unwind" instruction for function scopes,
  29.762 +    // since this is taken care of by the calling convention.
  29.763 +    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
  29.764 +        unwindTo(node->scope()->enclosing());
  29.765 +}
  29.766 +
  29.767 +void
  29.768 +BytecodeCompiler::visit(IntegerLiteral *node)
  29.769 +{
  29.770 +    __ int_(node->value());
  29.771 +}
  29.772 +
  29.773 +void
  29.774 +BytecodeCompiler::visit(BooleanLiteral *node)
  29.775 +{
  29.776 +    if (node->token() == TOK_TRUE)
  29.777 +        __ true_();
  29.778 +    else
  29.779 +        __ false_();
  29.780 +}
  29.781 +
  29.782 +void
  29.783 +BytecodeCompiler::visit(FloatLiteral *node)
  29.784 +{
  29.785 +    __ float_((float)node->value());
  29.786 +}
  29.787 +
  29.788 +void
  29.789 +BytecodeCompiler::visit(StringLiteral *node)
  29.790 +{
  29.791 +    Local<Array> array(zone_, StringLiteralToArray(zone_, node));
  29.792 +    if (!array)
  29.793 +        return;
  29.794 +
  29.795 +    __ note_position(node->pos());
  29.796 +    __ object(array);
  29.797 +}
  29.798 +
  29.799 +void
  29.800 +BytecodeCompiler::getEnvSlot(Variable *var)
  29.801 +{
  29.802 +    assert(var->scope()->kind() == Scope::GLOBAL);
  29.803 +    __ getglobal(var);
  29.804 +}
  29.805 +
  29.806 +void
  29.807 +BytecodeCompiler::setEnvSlot(Variable *var)
  29.808 +{
  29.809 +    assert(var->scope()->kind() == Scope::GLOBAL);
  29.810 +    __ setglobal(var);
  29.811 +}
  29.812 +
  29.813 +static bool
  29.814 +FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
  29.815 +{
  29.816 +    Local<Array> string(zone);
  29.817 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
  29.818 +        Expression *expr = literal->expressions()->at(i);
  29.819 +        StringLiteral *lit = expr->toStringLiteral();
  29.820 +        if ((string = StringLiteralToArray(zone, lit)) == NULL)
  29.821 +            return false;
  29.822 +
  29.823 +        array->writeObject(zone, i, string);
  29.824 +
  29.825 +        if (string->length() > *maxsize)
  29.826 +            *maxsize = string->length();
  29.827 +
  29.828 +        assert(!array->type()->contained()->isFixedLength() ||
  29.829 +                array->type()->contained()->fixedLength() >= string->length());
  29.830 +    }
  29.831 +
  29.832 +    return true;
  29.833 +}
  29.834 +
  29.835 +static bool
  29.836 +FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
  29.837 +{
  29.838 +    assert(array->type()->fixedLength() == literal->expressions()->length());
  29.839 +
  29.840 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
  29.841 +        Expression *expr = literal->expressions()->at(i);
  29.842 +        if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
  29.843 +            array->writeInt32(i, lit->value());
  29.844 +            continue;
  29.845 +        }
  29.846 +        if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
  29.847 +            if (lit->token() == TOK_TRUE)
  29.848 +                array->writeInt32(i, 1);
  29.849 +            else
  29.850 +                array->writeInt32(i, 0);
  29.851 +            continue;
  29.852 +        }
  29.853 +        if (FloatLiteral *lit = expr->asFloatLiteral()) {
  29.854 +            array->writeFloat(i, (float)lit->value());
  29.855 +            continue;
  29.856 +        }
  29.857 +
  29.858 +        // Unrecognized literal type.
  29.859 +        assert(false);
  29.860 +    }
  29.861 +
  29.862 +    return true;
  29.863 +}
  29.864 +
  29.865 +static bool
  29.866 +TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
  29.867 +                     unsigned *maxsize)
  29.868 +{
  29.869 +    assert(type->fixedLength() == literal->expressions()->length());
  29.870 +
  29.871 +    Local<Type> contained(zone, type->contained());
  29.872 +    if (contained->isCharArray())
  29.873 +        return FillArrayLiteral_String(zone, array, literal, maxsize);
  29.874 +
  29.875 +    if (!contained->isArray())
  29.876 +        return FillArrayLiteral_Primitive(zone, array, literal);
  29.877 +
  29.878 +    Local<Array> subarray(zone);
  29.879 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
  29.880 +        Expression *expr = literal->expressions()->at(i);
  29.881 +        subarray = Array::cast(array->readObject(i));
  29.882 +        if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
  29.883 +            return false;
  29.884 +    }
  29.885 +
  29.886 +    return true;
  29.887 +}
  29.888 +
  29.889 +static Array *
  29.890 +BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
  29.891 +{
  29.892 +    Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
  29.893 +    if (!root)
  29.894 +        return NULL;
  29.895 +
  29.896 +    // This should have allocated everything in the array, so all we need to
  29.897 +    // do is traverse down to the lowest levels and copy things.
  29.898 +    Local<Type> type(zone, map->type());
  29.899 +    if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
  29.900 +        return NULL;
  29.901 +
  29.902 +    return root;
  29.903 +}
  29.904 +
  29.905 +static inline bool
  29.906 +ArrayContainsCharBuffers(Type *type)
  29.907 +{
  29.908 +    if (type->contained()->isArray())
  29.909 +        return ArrayContainsCharBuffers(type->contained());
  29.910 +    return type->isCharArray();
  29.911 +}
  29.912 +
  29.913 +void
  29.914 +BytecodeCompiler::visit(VariableDeclaration *node)
  29.915 +{
  29.916 +    Variable *var = node->variable();
  29.917 +    
  29.918 +    Local<Type> type(zone_, var->type());
  29.919 +    if (type->isArray()) {
  29.920 +        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
  29.921 +        __ note_position(node->pos());
  29.922 +
  29.923 +        Local<Type> right(zone_);
  29.924 +        if (node->initialization())
  29.925 +            right = node->initialization()->type();
  29.926 +
  29.927 +        // There are a few methods for allocating, here:
  29.928 +        // (1) If the array is fixed,
  29.929 +        //    (a) Initializer not present,
  29.930 +        //              NEWFIXED
  29.931 +        //    (b) Left is const non-string:
  29.932 +        //              <nothing>
  29.933 +        //    (b) Otherwise:
  29.934 +        //              NEWFIXED
  29.935 +        //              COPYARRAY
  29.936 +        // (2) If the array is not fixed,
  29.937 +        //    (a) Initializer is not present,
  29.938 +        //              NEWEMPTY
  29.939 +        //    (b) Initializer is not a string literal,
  29.940 +        //        or left is const:
  29.941 +        //              <nothing>
  29.942 +        //    (c) Initializer is a string literal,
  29.943 +        //              NEWSIZED
  29.944 +        //              COPYARRAY
  29.945 +        //
  29.946 +
  29.947 +        Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
  29.948 +                              ? Heap::Tenure_Old
  29.949 +                              : Heap::Tenure_Default;
  29.950 +
  29.951 +        if (Expression *init = node->initialization()) {
  29.952 +            if (init->isArrayLiteral()) {
  29.953 +                unsigned maxsize = 0;
  29.954 +                Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
  29.955 +                if (!array)
  29.956 +                    return;
  29.957 +
  29.958 +                assert(type->isFixedLength());
  29.959 +
  29.960 +                if (type->isConst()) {
  29.961 +                    __ object(array);
  29.962 +                } else if (ArrayContainsCharBuffers(type)) {
  29.963 +                    // This array contains mutable char buffers, so
  29.964 +                    // unfortunately this gets a little more complicated. We
  29.965 +                    // compute the maximum size needed for the innermost
  29.966 +                    // string, which is similar to SP1. This means we can use
  29.967 +                    // CopyArray rather than individually emit opcodes to clone
  29.968 +                    // every string.
  29.969 +                    Local<Type> child(zone_, type);
  29.970 +                    for (size_t i = 0; i < type->levels() - 1; i++) {
  29.971 +                        __ int_(child->fixedLength());
  29.972 +                        child = child->contained();
  29.973 +                    }
  29.974 +                    __ int_(maxsize);
  29.975 +                    __ newarray(OP_NEWSIZED, map, tenure);
  29.976 +                    __ object(array);
  29.977 +                    __ copyarray();
  29.978 +                } else {
  29.979 +                    __ newarray(OP_NEWFIXED, map, tenure);
  29.980 +                    __ object(array);
  29.981 +                    __ copyarray();
  29.982 +                }
  29.983 +            } else if (type->isFixedLength()) {
  29.984 +                // Note in the case of:
  29.985 +                // const String:buffer[50] = "hello";
  29.986 +                //
  29.987 +                // We want to preserve sizeof(buffer) == 50.
  29.988 +                if (type->isConst() && !type->isCharArray()) {
  29.989 +                    init->accept(this);
  29.990 +                } else {
  29.991 +                    __ newarray(OP_NEWFIXED, map, tenure);
  29.992 +                    init->accept(this);
  29.993 +                    __ copyarray();
  29.994 +                }
  29.995 +            } else if (!type->isConst() && init->isStringLiteral()) {
  29.996 +                // This is a degenerate case of ArrayLiteral.
  29.997 +                __ int_(right->fixedLength());
  29.998 +                __ newarray(OP_NEWSIZED, map, tenure);
  29.999 +                init->accept(this);
 29.1000 +                __ copyarray();
 29.1001 +            } else if (type->isConst()) {
 29.1002 +                init->accept(this);
 29.1003 +            }
 29.1004 +        } else if (type->isFixedLength()) {
 29.1005 +            __ newarray(OP_NEWFIXED, map, tenure);
 29.1006 +        } else {
 29.1007 +#if 0
 29.1008 +            if (node->postDimensions()) {
 29.1009 +                for (size_t i = 0; i < node->postDimensions()->length(); i++) {
 29.1010 +                    Expression *expr = node->postDimensions()->at(i);
 29.1011 +                    if (expr)
 29.1012 +                        expr->accept(this);
 29.1013 +                    else
 29.1014 +                        __ int_(0);
 29.1015 +                }
 29.1016 +                __ newarray(OP_NEWSIZED, map, tenure);
 29.1017 +            } else {
 29.1018 +                __ newarray(OP_NEWEMPTY, map, tenure);
 29.1019 +            }
 29.1020 +#endif
 29.1021 +        }
 29.1022 +    } else if (type->isStruct()) {
 29.1023 +        Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
 29.1024 +
 29.1025 +        // Because structs can contain arrays, any sort of composition
 29.1026 +        // triggers non-LIFO allocation. This is just for correctness.
 29.1027 +        // We could do better by:
 29.1028 +        //  (1) Limiting to structs that just (recursively) contain arrays,
 29.1029 +        //  (2) Swap Stack for Default tenure in Struct::New
 29.1030 +        //  (3) JIT analysis
 29.1031 +        if (var->scope()->kind() == Scope::GLOBAL)
 29.1032 +            __ newstruct(map, Heap::Tenure_Old);
 29.1033 +        else if (var->needsHeapAllocation() || map->composed())
 29.1034 +            __ newstruct(map, Heap::Tenure_Default);
 29.1035 +        else
 29.1036 +            __ newstruct(map, Heap::Tenure_Stack);
 29.1037 +    } else {
 29.1038 +        if (node->initialization()) {
 29.1039 +            node->initialization()->accept(this);
 29.1040 +        } else {
 29.1041 +            if (type->isInt32OrEnum() || type->isBool()) {
 29.1042 +                __ int_(0);
 29.1043 +            } else {
 29.1044 +                assert(type->isFloat());
 29.1045 +                __ float_(0);
 29.1046 +            }
 29.1047 +        }
 29.1048 +    }
 29.1049 +
 29.1050 +    if (var->location() == Variable::STACK) {
 29.1051 +        __ setlocal(var);
 29.1052 +        locals_->set(zone_, var->slot(), var->type());
 29.1053 +    } else {
 29.1054 +        assert(var->location() == Variable::ENVIRONMENT);
 29.1055 +        setEnvSlot(var);
 29.1056 +    }
 29.1057 +
 29.1058 +    __ pop();
 29.1059 +}
 29.1060 +
 29.1061 +void
 29.1062 +BytecodeCompiler::visit(CallExpression *node)
 29.1063 +{
 29.1064 +#if 0
 29.1065 +    Local<Type> funType(zone_, node->callee()->type());
 29.1066 +
 29.1067 +    // Sniff out natives, which have a specific opcode and are guaranteed to
 29.1068 +    // be called via name proxy.
 29.1069 +    NamedFunction *native = NULL;
 29.1070 +    if (funType->isNative())
 29.1071 +        native = node->callee()->toNameProxy()->binding()->toNamedFunction();
 29.1072 +
 29.1073 +    Local<Type> given(zone_);
 29.1074 +    for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
 29.1075 +        Expression *arg = node->arguments()->at(i);
 29.1076 +
 29.1077 +        given = arg->type();
 29.1078 +
 29.1079 +        // We need to compute a reference if the parameter was in the form:
 29.1080 +        //  f(&a)
 29.1081 +        // Note this form does not allow: f({})
 29.1082 +        // 
 29.1083 +        // We also need to compute references for all variadic native
 29.1084 +        // arguments, but arrays and references are already in the
 29.1085 +        // appropriate form.
 29.1086 +        bool mustPushReference = false;
 29.1087 +        if (i >= funType->parameters()->length()) {
 29.1088 +            assert(funType->isNative() && funType->isNativeVariadic());
 29.1089 +            mustPushReference = !given->isArray() && !given->isReference();
 29.1090 +        } else if (funType->parameterAt(i)->isReference()) {
 29.1091 +            mustPushReference = !given->isReference();
 29.1092 +        }
 29.1093 +
 29.1094 +        // If a native is passed to a native, it must only be one level deep.
 29.1095 +        assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
 29.1096 +
 29.1097 +        if (mustPushReference) {
 29.1098 +            if (arg->isNameProxy()) {
 29.1099 +                // :TODO: test with functions and globals
 29.1100 +                // Compute a reference to the name.
 29.1101 +                Variable *var = arg->toNameProxy()->binding()->toVariable();
 29.1102 +                __ note_position(node->pos());
 29.1103 +                __ newref(var);
 29.1104 +            } else if (arg->isFieldExpression()) {
 29.1105 +                FieldExpression *expr = arg->toFieldExpression();
 29.1106 +                expr->left()->accept(this);
 29.1107 +                __ note_position(expr->pos());
 29.1108 +                __ fieldref_lifo(expr->fieldIndex());
 29.1109 +            } else {
 29.1110 +                // We don't know how to, or can't, build a direct reference to
 29.1111 +                // this type. Make an indirect one, by taking the top of the
 29.1112 +                // stack and boxing it up.
 29.1113 +                arg->accept(this);
 29.1114 +                __ note_position(node->pos());
 29.1115 +                __ slotref_lifo();
 29.1116 +            }
 29.1117 +        } else {
 29.1118 +            arg->accept(this);
 29.1119 +        }
 29.1120 +    }
 29.1121 +
 29.1122 +    unsigned argc = node->arguments()->length();
 29.1123 +
 29.1124 +    // If there are missing arguments, then we're not done and have to push
 29.1125 +    // default parameters.
 29.1126 +    Local<Box> box(zone_);
 29.1127 +    Local<Array> array(zone_);
 29.1128 +    Local<ArrayMap> map(zone_);
 29.1129 +    for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
 29.1130 +        box = Box::cast(funType->defaults()->at(i));
 29.1131 +
 29.1132 +        if (box->type()->isPod()) {
 29.1133 +            if (box->type()->pod() == PrimitiveType_Int32)
 29.1134 +                __ int_(box->toInt32());
 29.1135 +            else if (box->type()->pod() == PrimitiveType_Float)
 29.1136 +                __ float_(box->toFloat());
 29.1137 +            else
 29.1138 +                assert(false);
 29.1139 +
 29.1140 +            if (funType->parameterAt(i)->isReference()) {
 29.1141 +                __ note_position(node->pos());
 29.1142 +                __ slotref_lifo();
 29.1143 +            }
 29.1144 +        } else {
 29.1145 +            assert(box->type()->isArray());
 29.1146 +
 29.1147 +            array = Array::cast(box->toObject());
 29.1148 +            if (funType->parameterAt(i)->isConst()) {
 29.1149 +                __ object(array);
 29.1150 +            } else {
 29.1151 +                // We need to copy the array since it's mutable. Note that
 29.1152 +                // although COPYARRAY returns its left-hand side, this may
 29.1153 +                // change in the future, we do the same thing and dupe the
 29.1154 +                // newly allocated array.
 29.1155 +                map = ArrayMap::cast(array->map());
 29.1156 +                
 29.1157 +                // Natives cannot escape array references, so we can allocate
 29.1158 +                // them on the LIFO stack.
 29.1159 +                if (funType->isNative())
 29.1160 +                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
 29.1161 +                else
 29.1162 +                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
 29.1163 +                __ dup();
 29.1164 +                __ object(array);
 29.1165 +                __ copyarray();
 29.1166 +                __ pop();
 29.1167 +            }
 29.1168 +        }
 29.1169 +
 29.1170 +        argc++;
 29.1171 +    }
 29.1172 +
 29.1173 +    __ note_position(node->pos());
 29.1174 +    if (native) {
 29.1175 +        __ callnative(native->slot(), argc);
 29.1176 +        __ drop(argc);
 29.1177 +    } else {
 29.1178 +        node->callee()->accept(this);
 29.1179 +        __ call(funType);
 29.1180 +        __ drop(argc + 1);
 29.1181 +    }
 29.1182 +#endif
 29.1183 +}
 29.1184 +
 29.1185 +void
 29.1186 +BytecodeCompiler::visit(TernaryExpression *node)
 29.1187 +{
 29.1188 +    Label success, failure, join;
 29.1189 +
 29.1190 +    visitForTest(node->condition(), &success, &failure, &success);
 29.1191 +    __ bind(&success);
 29.1192 +    node->left()->accept(this);
 29.1193 +    __ drop(1);
 29.1194 +    __ jump(&join);
 29.1195 +    __ bind(&failure);
 29.1196 +    node->right()->accept(this);
 29.1197 +    __ bind(&join);
 29.1198 +}
 29.1199 +
 29.1200 +void
 29.1201 +BytecodeCompiler::visit(IfStatement *node)
 29.1202 +{
 29.1203 +    Label join;
 29.1204 +    if (!node->ifFalse()) {
 29.1205 +        Label success;
 29.1206 +
 29.1207 +        visitForTest(node->condition(), &success, &join, &success);
 29.1208 +        __ bind(&success);
 29.1209 +        node->ifTrue()->accept(this);
 29.1210 +    } else {
 29.1211 +        Label success, next;
 29.1212 +
 29.1213 +        visitForTest(node->condition(), &success, &next, &success);
 29.1214 +        __ bind(&success);
 29.1215 +        node->ifTrue()->accept(this);
 29.1216 +        __ jump(&join);
 29.1217 +        __ bind(&next);
 29.1218 +        node->ifFalse()->accept(this);
 29.1219 +    }
 29.1220 +
 29.1221 +    __ bind(&join);
 29.1222 +}
 29.1223 +
 29.1224 +bool
 29.1225 +BytecodeCompiler::tableswitch(SwitchStatement *node)
 29.1226 +{
 29.1227 +    CaseValueList *values = node->caseValueList();
 29.1228 +
 29.1229 +    if (values->length() < 3)
 29.1230 +        return false;
 29.1231 +
 29.1232 +    // Find the delta between the largest and smallest value.
 29.1233 +    int hi = values->at(values->length() - 1).box.toInt();
 29.1234 +    int lo = values->at(0).box.toInt();
 29.1235 +    assert(hi > lo);
 29.1236 +
 29.1237 +    unsigned tablesize = TableSwitchEntries(lo, hi);
 29.1238 +    if (tablesize > MAX_TABLESWITCH_ENTRIES)
 29.1239 +        return false;
 29.1240 +
 29.1241 +    Label def, join;
 29.1242 +
 29.1243 +    // Create the list of labels that each statement will bind to.
 29.1244 +    Label *labels = new Label[node->cases()->length()];
 29.1245 +
 29.1246 +    // Create the table of labels we'll use for each case.
 29.1247 +    Label **table = new Label *[tablesize];
 29.1248 +
 29.1249 +    // Link all cases, by default, to the default label.
 29.1250 +    for (size_t i = 0; i < tablesize; i++)
 29.1251 +        table[i] = &def;
 29.1252 +
 29.1253 +    // Now patch actual cases to their correct labels.
 29.1254 +    for (size_t i = 0; i < values->length(); i++) {
 29.1255 +        CaseValue &v = values->at(i);
 29.1256 +        assert(v.statement < node->cases()->length());
 29.1257 +
 29.1258 +        unsigned index = unsigned(v.box.toInt() - lo);
 29.1259 +        assert(index < tablesize);
 29.1260 +
 29.1261 +        table[index] = &labels[v.statement];
 29.1262 +    }
 29.1263 +
 29.1264 +    // Emit the tableswitch opcode and the jump table.
 29.1265 +    __ tableswitch(lo, hi, &def, table);
 29.1266 +
 29.1267 +    // We're done with the jump table now.
 29.1268 +    delete [] table;
 29.1269 +
 29.1270 +    // Emit each statement.
 29.1271 +    for (size_t i = 0; i < node->cases()->length(); i++) {
 29.1272 +        Statement *stmt = node->cases()->at(i)->statement();
 29.1273 +
 29.1274 +        __ bind(&labels[i]);
 29.1275 +        stmt->accept(this);
 29.1276 +        __ jump(&join);
 29.1277 +    }
 29.1278 +
 29.1279 +    // We're done with the statement labels.
 29.1280 +    delete [] labels;
 29.1281 +
 29.1282 +    // Emit the default case.
 29.1283 +    __ bind(&def);
 29.1284 +    if (node->defaultCase())
 29.1285 +        node->defaultCase()->accept(this);
 29.1286 +
 29.1287 +    __ bind(&join);
 29.1288 +
 29.1289 +    return true;
 29.1290 +}
 29.1291 +
 29.1292 +void
 29.1293 +BytecodeCompiler::visit(SwitchStatement *node)
 29.1294 +{
 29.1295 +    node->expression()->accept(this);
 29.1296 +
 29.1297 +    if (tableswitch(node))
 29.1298 +        return;
 29.1299 +
 29.1300 +    Label join;
 29.1301 +
 29.1302 +    for (size_t i = 0; i < node->cases()->length(); i++) {
 29.1303 +        Case *c = node->cases()->at(i);
 29.1304 +
 29.1305 +        Label success, fail;
 29.1306 +        if (c->others()) {
 29.1307 +            for (size_t j = 0; j < c->others()->length(); j++) {
 29.1308 +                Expression *expr = c->others()->at(j);
 29.1309 +
 29.1310 +                __ dup();
 29.1311 +                expr->accept(this);
 29.1312 +                __ j(OP_JEQ, &success);
 29.1313 +            }
 29.1314 +        }
 29.1315 +
 29.1316 +        // The final test.
 29.1317 +        __ dup();
 29.1318 +        c->expression()->accept(this);
 29.1319 +        __ j(OP_JNE, &fail);
 29.1320 +        __ bind(&success);
 29.1321 +        c->statement()->accept(this);
 29.1322 +        __ jump(&join);
 29.1323 +        __ bind(&fail);
 29.1324 +    }
 29.1325 +
 29.1326 +    if (node->defaultCase())
 29.1327 +        node->defaultCase()->accept(this);
 29.1328 +
 29.1329 +    __ pop();
 29.1330 +    __ bind(&join);
 29.1331 +}
 29.1332 +
 29.1333 +void
 29.1334 +BytecodeCompiler::visit(FunctionStatement *node)
 29.1335 +{
 29.1336 +    if (!node->fun()->used())
 29.1337 +        return;
 29.1338 +
 29.1339 +    if (node->fun()->isNative()) {
 29.1340 +        assert(!moduleData_->natives->at(node->fun()->slot()));
 29.1341 +
 29.1342 +        Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
 29.1343 +        Local<String> name(zone_, node->fun()->name());
 29.1344 +        Local<Native> native(zone_, Native::New(zone_, type, name));
 29.1345 +        if (!native)
 29.1346 +            return;
 29.1347 +
 29.1348 +        moduleData_->natives->set(zone_, node->fun()->slot(), native);
 29.1349 +        return;
 29.1350 +    }
 29.1351 +
 29.1352 +    // If the function has no body, then it's just a declaration.
 29.1353 +    if (!node->body()) {
 29.1354 +        assert(node->fun()->isForward() || node->fun()->isPublic());
 29.1355 +        return;
 29.1356 +    }
 29.1357 +
 29.1358 +    BytecodeCompiler child(zone_, tree_, moduleData_);
 29.1359 +    Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
 29.1360 +    if (!fun)
 29.1361 +        return;
 29.1362 +    
 29.1363 +    assert(!moduleData_->module->getFunction(node->fun()->slot()));
 29.1364 +    moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
 29.1365 +}
 29.1366 +
 29.1367 +void
 29.1368 +BytecodeCompiler::visit(FunctionTypeStatement *node)
 29.1369 +{
 29.1370 +}
 29.1371 +
 29.1372 +void
 29.1373 +BytecodeCompiler::visit(EnumStatement *node)
 29.1374 +{
 29.1375 +}
 29.1376 +
 29.1377 +void
 29.1378 +BytecodeCompiler::visit(StructureStatement *node)
 29.1379 +{
 29.1380 +}
 29.1381 +
 29.1382 +void
 29.1383 +BytecodeCompiler::visit(ArrayLiteral *node)
 29.1384 +{
 29.1385 +    // We shouldn't reach these; they're handled manually when initializing
 29.1386 +    // declared arrays.
 29.1387 +    assert(false);
 29.1388 +}
 29.1389 +
 29.1390 +void
 29.1391 +BytecodeCompiler::visit(ImportStatement *node)
 29.1392 +{
 29.1393 +}
 29.1394 +
 29.1395 +Code *
 29.1396 +BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
 29.1397 +{
 29.1398 +    // STOP doubles as RETURNVOID.
 29.1399 +    __ stop();
 29.1400 +
 29.1401 +    if (__ oom() || zone_->hasPendingException())
 29.1402 +        return NULL;
 29.1403 +
 29.1404 +    Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
 29.1405 +    if (!bytes)
 29.1406 +        return NULL;
 29.1407 +    memcpy(bytes->raw(), __ buffer(), __ length());
 29.1408 +
 29.1409 +    for (size_t i = 0; i < scope->maxContainedLocals(); i++)
 29.1410 +        assert(locals_->at(i));
 29.1411 +
 29.1412 +    Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
 29.1413 +    if (!objects)
 29.1414 +        return NULL;
 29.1415 +
 29.1416 +    for (size_t i = 0; i < __ objects()->length(); i++)
 29.1417 +        objects->set(zone_, i, *(__ objects()->at(i)));
 29.1418 +
 29.1419 +    Local<ByteArray> safepoints(zone_);
 29.1420 +
 29.1421 +    // If any stack slots hold gc pointers at potential failure points in the
 29.1422 +    // bytecode, record them now. We do this by building a list of tuples;
 29.1423 +    // each tuple contains the pc offset, and a bitset containing which stack
 29.1424 +    // slots must be scanned by the gc.
 29.1425 +    if (__ oopRecords()->length()) {
 29.1426 +        size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
 29.1427 +        size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
 29.1428 +        safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
 29.1429 +        if (!safepoints)
 29.1430 +            return NULL;
 29.1431 +
 29.1432 +        Address cursor = safepoints->raw();
 29.1433 +        for (size_t i = 0; i < __ oopRecords()->length(); i++) {
 29.1434 +            OopRecord *record = __ oopRecords()->at(i);
 29.1435 +            assert(record->depth <= __ maxStackDepth());
 29.1436 +
 29.1437 +            *reinterpret_cast<unsigned *>(cursor) = record->offset;
 29.1438 +
 29.1439 +            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
 29.1440 +            for (unsigned i = 0; i < record->depth; i++)
 29.1441 +                bits[i / 8] |= (1 << (i % 8));
 29.1442 +
 29.1443 +            cursor += bytesPerSafepoint;
 29.1444 +        }
 29.1445 +
 29.1446 +        assert(cursor == safepoints->raw() + gcmapSize);
 29.1447 +    }
 29.1448 +
 29.1449 +    Local<ByteArray> sourcemap(zone_);
 29.1450 +    if (__ sourcemapLength()) {
 29.1451 +        sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
 29.1452 +        if (!sourcemap)
 29.1453 +            return NULL;
 29.1454 +
 29.1455 +        memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
 29.1456 +    }
 29.1457 +
 29.1458 +    Local<Code> code(zone_);
 29.1459 +
 29.1460 +    code = Code::New(zone_,
 29.1461 +                     bytes,
 29.1462 +                     locals_,
 29.1463 +                     objects,
 29.1464 +                     __ maxStackDepth(),
 29.1465 +                     moduleData_->module,
 29.1466 +                     safepoints,
 29.1467 +                     sourcemap,
 29.1468 +                     lineno);
 29.1469 +    return code;
 29.1470 +}
 29.1471 +
 29.1472 +Function *
 29.1473 +BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
 29.1474 +{
 29.1475 +    // Note: No need to record a life slot here, since it's part of the Frame.
 29.1476 +    AutoEnterScope functionScope(this, node->scope());
 29.1477 +
 29.1478 +    // Set the initial line, because line mappings are deltas.
 29.1479 +    __ setFirstLine(node->pos().line);
 29.1480 +    locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
 29.1481 +
 29.1482 +    node->body()->accept(this);
 29.1483 +
 29.1484 +    unsigned nargs = node->scope()->numArguments();
 29.1485 +    Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
 29.1486 +    if (!args)
 29.1487 +        return NULL;
 29.1488 +
 29.1489 +    for (size_t i = 0; i < node->scope()->numArguments(); i++)
 29.1490 +        args->set(zone_, i, node->scope()->getArgument(i)->type());
 29.1491 +
 29.1492 +
 29.1493 +    Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
 29.1494 +    if (!code)
 29.1495 +        return NULL;
 29.1496 +
 29.1497 +    Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
 29.1498 +    Local<String> name(zone_, node->fun()->name());
 29.1499 +    Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
 29.1500 +    if (!fun)
 29.1501 +        return NULL;
 29.1502 +
 29.1503 +    // If this function had a forward, export it as a named public.
 29.1504 +    if (node->fun()->isPublic()) {
 29.1505 +        assert(node->fun()->isPublic());
 29.1506 +        ScopedRoot<Function> root(fun);
 29.1507 +        if (!root)
 29.1508 +            return NULL;
 29.1509 +        if (!moduleData_->publics.append(root))
 29.1510 +            return NULL;
 29.1511 +    }
 29.1512 +
 29.1513 +#ifndef NDEBUG
 29.1514 +    Disassemble(code, stdout);
 29.1515 +#endif
 29.1516 +    
 29.1517 +    return fun;
 29.1518 +}
 29.1519 +
 29.1520 +Module *
 29.1521 +BytecodeCompiler::compile()
 29.1522 +{
 29.1523 +    AutoEnterScope scope(this, tree_->globalScope());
 29.1524 +
 29.1525 +    ModuleData moduleData;
 29.1526 +
 29.1527 +    moduleData_ = &moduleData;
 29.1528 +    moduleData_->module = Module::New(zone_, tree_->globalScope()->numFunctions());
 29.1529 +
 29.1530 +    if (!moduleData_)
 29.1531 +        return NULL;
 29.1532 +    
 29.1533 +    moduleData_->natives = FixedArray::New(zone_, tree_->globalScope()->numNatives(), Heap::Tenure_Old);
 29.1534 +    if (!moduleData_->natives)
 29.1535 +        return NULL;
 29.1536 +
 29.1537 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
 29.1538 +        Statement *statement = tree_->statements()->at(i);
 29.1539 +        statement->accept(this);
 29.1540 +    }
 29.1541 +
 29.1542 +    if (zone_->hasPendingException())
 29.1543 +        return NULL;
 29.1544 +
 29.1545 +#ifndef NDEBUG
 29.1546 +    for (size_t i = 0; i < tree_->globalScope()->numFunctions(); i++)
 29.1547 +        assert(moduleData_->module->getFunction(i));
 29.1548 +    for (size_t i = 0; i < tree_->globalScope()->numNatives(); i++)
 29.1549 +        assert(moduleData_->natives->at(i));
 29.1550 +#endif
 29.1551 +
 29.1552 +    if (moduleData_->publics.length()) {
 29.1553 +        Local<Function> fun(zone_);
 29.1554 +        Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
 29.1555 +                               Heap::Tenure_Old));
 29.1556 +        if (!list)
 29.1557 +            return NULL;
 29.1558 +
 29.1559 +        for (size_t i = 0; i < moduleData_->publics.length(); i++)
 29.1560 +            list->set(zone_, i, moduleData_->publics[i]);
 29.1561 +
 29.1562 +        moduleData_->module->setPublics(list);
 29.1563 +    }
 29.1564 +
 29.1565 +    moduleData_->module->setNatives(moduleData_->natives);
 29.1566 +
 29.1567 +    if (scope_->numEnvironmentVars()) {
 29.1568 +        Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
 29.1569 +        if (!globalMap)
 29.1570 +            return NULL;
 29.1571 +
 29.1572 +        Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
 29.1573 +        if (!environment)
 29.1574 +            return NULL;
 29.1575 +
 29.1576 +        moduleData_->module->setEnvironment(environment);
 29.1577 +    }
 29.1578 +
 29.1579 +    Local<Code> code(zone_, compileCode(tree_->globalScope(), 1));
 29.1580 +    if (!code)
 29.1581 +        return NULL;
 29.1582 +
 29.1583 +    Disassemble(code, stdout);
 29.1584 +
 29.1585 +    moduleData_->module->setCode(code);
 29.1586 +
 29.1587 +    return moduleData_->module;
 29.1588 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/OldByCo.h	Sat Nov 17 18:41:01 2012 -0800
    30.3 @@ -0,0 +1,160 @@
    30.4 +/* vim: set ts=4 sw=4 tw=99 et:
    30.5 + *
    30.6 + * Copyright (C) 2012 David Anderson
    30.7 + *
    30.8 + * This file is part of JITCraft.
    30.9 + *
   30.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   30.11 + * the terms of the GNU General Public License as published by the Free
   30.12 + * Software Foundation, either version 3 of the License, or (at your option)
   30.13 + * any later version.
   30.14 + * 
   30.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   30.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   30.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   30.18 + *
   30.19 + * You should have received a copy of the GNU General Public License along with
   30.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   30.21 + */
   30.22 +#ifndef _include_bytecode_compiler_h_
   30.23 +#define _include_bytecode_compiler_h_
   30.24 +
   30.25 +#include "../Functions.h"
   30.26 +#include "AST.h"
   30.27 +#include "BytecodeEmitter.h"
   30.28 +
   30.29 +namespace ke {
   30.30 +
   30.31 +class Module;
   30.32 +class Array;
   30.33 +class ArrayMap;
   30.34 +
   30.35 +struct ModuleData
   30.36 +{
   30.37 +    ScopedRoot<Module> module;
   30.38 +    PoolList<ScopedRoot<Function> > publics;
   30.39 +    ScopedRoot<FixedArray> natives;
   30.40 +};
   30.41 +
   30.42 +class BytecodeCompiler : public AstVisitor
   30.43 +{
   30.44 +    Zone *zone_;
   30.45 +    ParseTree *tree_;
   30.46 +    BytecodeEmitter emitter_;
   30.47 +    ScopedRoot<FixedArray> locals_;
   30.48 +    Scope *scope_;
   30.49 +    ModuleData *moduleData_;
   30.50 +
   30.51 +    class LoopScope
   30.52 +    {
   30.53 +        Scope *scope_;
   30.54 +        BytecodeEmitter::Label *bk_;
   30.55 +        BytecodeEmitter::Label *ct_;
   30.56 +        LoopScope **prevp_;
   30.57 +        LoopScope *prev_;
   30.58 +
   30.59 +      public:
   30.60 +        LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
   30.61 +                  LoopScope **prevp)
   30.62 +          : scope_(scope),
   30.63 +            bk_(bk),
   30.64 +            ct_(ct),
   30.65 +            prevp_(prevp),
   30.66 +            prev_(*prevp)
   30.67 +        {
   30.68 +            *prevp_ = this;
   30.69 +        }
   30.70 +
   30.71 +        ~LoopScope()
   30.72 +        {
   30.73 +            *prevp_ = prev_;
   30.74 +        }
   30.75 +
   30.76 +        BytecodeEmitter::Label *break_() {
   30.77 +            return bk_;
   30.78 +        }
   30.79 +        BytecodeEmitter::Label *continue_() {
   30.80 +            return ct_;
   30.81 +        }
   30.82 +        Scope *scope() {
   30.83 +            return scope_;
   30.84 +        }
   30.85 +    };
   30.86 +
   30.87 +    LoopScope *loop_;
   30.88 +
   30.89 +  public:
   30.90 +    class AutoEnterScope
   30.91 +    {
   30.92 +        BytecodeCompiler *bc_;
   30.93 +        Scope *saved_;
   30.94 +
   30.95 +      public:
   30.96 +        AutoEnterScope(BytecodeCompiler *bc, Scope *scope)
   30.97 +          : bc_(bc),
   30.98 +            saved_(bc->scope_)
   30.99 +        {
  30.100 +            if (scope)
  30.101 +                bc->scope_ = scope;
  30.102 +        }
  30.103 +        ~AutoEnterScope() {
  30.104 +            bc_->scope_ = saved_;
  30.105 +        }
  30.106 +    };
  30.107 +
  30.108 +  private:
  30.109 +    void recordLifoSlot(Scope *scope);
  30.110 +    void unwindTo(Scope *scope);
  30.111 +    void visitForTest(Expression *expression,
  30.112 +                      BytecodeEmitter::Label *trueBranch,
  30.113 +                      BytecodeEmitter::Label *falseBranch,
  30.114 +                      BytecodeEmitter::Label *fallthrough);
  30.115 +    Code *compileCode(Scope *scope, unsigned lineno);
  30.116 +    Function *compileFunction(ModuleData *module, FunctionStatement *fun);
  30.117 +    void visitForALU(Type *needed, Expression *node);
  30.118 +
  30.119 +    void getEnvSlot(Variable *var);
  30.120 +    void setEnvSlot(Variable *var);
  30.121 +
  30.122 +    bool tableswitch(SwitchStatement *node);
  30.123 +
  30.124 +  public:
  30.125 +    BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
  30.126 +
  30.127 +    Module *compile();
  30.128 +
  30.129 +  public:
  30.130 +    void visit(NameProxy *name);
  30.131 +    void visit(Assignment *node);
  30.132 +    void visit(BinaryExpression *node);
  30.133 +    void visit(ReturnStatement *node);
  30.134 +    void visit(ForStatement *node);
  30.135 +    void visit(BlockStatement *node);
  30.136 +    void visit(VariableDeclaration *node);
  30.137 +    void visit(IntegerLiteral *node);
  30.138 +    void visit(BooleanLiteral *node);
  30.139 +    void visit(FloatLiteral *node);
  30.140 +    void visit(StringLiteral *node);
  30.141 +    void visit(ExpressionStatement *node);
  30.142 +    void visit(FunctionStatement *node);
  30.143 +    void visit(CallExpression *node);
  30.144 +    void visit(IfStatement *node);
  30.145 +    void visit(IndexExpression *node);
  30.146 +    void visit(EnumStatement *node);
  30.147 +    void visit(WhileStatement *node);
  30.148 +    void visit(BreakStatement *node);
  30.149 +    void visit(ContinueStatement *node);
  30.150 +    void visit(IncDecExpression *node);
  30.151 +    void visit(UnaryExpression *node);
  30.152 +    void visit(TernaryExpression *node);
  30.153 +    void visit(StructureStatement *node);
  30.154 +    void visit(FieldExpression *node);
  30.155 +    void visit(SwitchStatement *node);
  30.156 +    void visit(FunctionTypeStatement *node);
  30.157 +    void visit(ArrayLiteral *node);
  30.158 +    void visit(ImportStatement *node);
  30.159 +};
  30.160 +
  30.161 +}
  30.162 +
  30.163 +#endif // _include_bytecode_generator_h_
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/OldSema.cpp	Sat Nov 17 18:41:01 2012 -0800
    31.3 @@ -0,0 +1,1899 @@
    31.4 +/* vim: set ts=4 sw=4 tw=99 et:
    31.5 + *
    31.6 + * Copyright (C) 2012 David Anderson
    31.7 + *
    31.8 + * This file is part of JITCraft.
    31.9 + *
   31.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   31.11 + * the terms of the GNU General Public License as published by the Free
   31.12 + * Software Foundation, either version 3 of the License, or (at your option)
   31.13 + * any later version.
   31.14 + * 
   31.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   31.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   31.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   31.18 + *
   31.19 + * You should have received a copy of the GNU General Public License along with
   31.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   31.21 + */
   31.22 +#include <string.h>
   31.23 +#include "SemanticAnalysis.h"
   31.24 +#include "../Types.h"
   31.25 +#include "../Zone.h"
   31.26 +#include "../TypeManager.h"
   31.27 +#include "../Strings.h"
   31.28 +#include "../Box.h"
   31.29 +#include "../Array.h"
   31.30 +#include "../Heap-inl.h"
   31.31 +#include "Scopes.h"
   31.32 +#include "NameBinding.h"
   31.33 +
   31.34 +using namespace ke;
   31.35 +
   31.36 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
   31.37 +  : zone_(zone),
   31.38 +    cc_(cc),
   31.39 +    tree_(tree),
   31.40 +    scope_(NULL),
   31.41 +    loop_(NULL)
   31.42 +{
   31.43 +}
   31.44 +
   31.45 +bool
   31.46 +SemanticAnalysis::analyze()
   31.47 +{
   31.48 +    assert(false);
   31.49 +    return false;
   31.50 +}
   31.51 +
   31.52 +
   31.53 +#if 0
   31.54 +
   31.55 +static inline bool
   31.56 +IsPrimitiveType(Type *type, PrimitiveType primitive)
   31.57 +{
   31.58 +    if (!type)
   31.59 +        return false;
   31.60 +
   31.61 +    if (!type->isPrimitive())
   31.62 +        return false;
   31.63 +
   31.64 +    return primitive == type->primitive();
   31.65 +}
   31.66 +
   31.67 +static inline bool
   31.68 +EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
   31.69 +                        BoxedPrimitive *out)
   31.70 +{
   31.71 +    switch (kind) {
   31.72 +      case TOK_PLUS:
   31.73 +        *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
   31.74 +        return true;
   31.75 +
   31.76 +      case TOK_SHL:
   31.77 +        *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
   31.78 +        return true;
   31.79 +
   31.80 +      default:
   31.81 +        return false;
   31.82 +    }
   31.83 +}
   31.84 +
   31.85 +static inline bool
   31.86 +EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
   31.87 +{
   31.88 +  switch (kind) {
   31.89 +    case TOK_MINUS:
   31.90 +      *out = BoxedPrimitive::Int(-inner.toInt());
   31.91 +      return true;
   31.92 +
   31.93 +    default:
   31.94 +      return false;
   31.95 +  }
   31.96 +}
   31.97 +
   31.98 +static bool
   31.99 +EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
  31.100 +{
  31.101 +    switch (expression->kind()) {
  31.102 +      case AstNode::kBinaryExpression:
  31.103 +      {
  31.104 +        BoxedPrimitive left;
  31.105 +        BoxedPrimitive right;
  31.106 +        BinaryExpression *b = expression->toBinaryExpression();
  31.107 +        if (!EvaluateForConstant(b->left(), &left) ||
  31.108 +            !EvaluateForConstant(b->right(), &right))
  31.109 +        {
  31.110 +            return false;
  31.111 +        }
  31.112 +        return EvaluateBinaryOperation(b->token(), left, right, out);
  31.113 +      }
  31.114 +
  31.115 +      case AstNode::kUnaryExpression:
  31.116 +      {
  31.117 +        BoxedPrimitive inner;
  31.118 +        UnaryExpression *u = expression->toUnaryExpression();
  31.119 +        if (!EvaluateForConstant(u->expression(), &inner))
  31.120 +            return false;
  31.121 +        return EvaluateUnaryOperation(u->token(), inner, out);
  31.122 +      }
  31.123 +
  31.124 +      case AstNode::kNameProxy:
  31.125 +      {
  31.126 +        NameProxy *proxy = expression->toNameProxy();
  31.127 +        if (proxy->binding()->kind() != BoundName::CONSTANT)
  31.128 +            return false;
  31.129 +
  31.130 +        NamedConstant *c = proxy->binding()->toNamedConstant();
  31.131 +        if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
  31.132 +            return false;
  31.133 +
  31.134 +        *out = c->value();
  31.135 +        return true;
  31.136 +      }
  31.137 +
  31.138 +      case AstNode::kBooleanLiteral:
  31.139 +        *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
  31.140 +        return true;
  31.141 +
  31.142 +      case AstNode::kIntegerLiteral:
  31.143 +        *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
  31.144 +        return true;
  31.145 +
  31.146 +      default:
  31.147 +        return false;
  31.148 +    }
  31.149 +}
  31.150 +
  31.151 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
  31.152 +  : zone_(zone),
  31.153 +    cc_(cc),
  31.154 +    tree_(tree),
  31.155 +    scope_(NULL),
  31.156 +    loop_(NULL)
  31.157 +{
  31.158 +}
  31.159 +
  31.160 +bool
  31.161 +SemanticAnalysis::analyze()
  31.162 +{
  31.163 +    if (cc_.failures())
  31.164 +        return false;
  31.165 +
  31.166 +    scope_ = tree_->globalScope();
  31.167 +    assert(scope_->kind() == Scope::GLOBAL);
  31.168 +
  31.169 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  31.170 +        Statement *statement = tree_->statements()->at(i);
  31.171 +        if (statement->isFunctionStatement()) {
  31.172 +            FunctionStatement *funstmt = statement->toFunctionStatement();
  31.173 +            if (!preanalyze(funstmt))
  31.174 +                return false;
  31.175 +        } else if (statement->isEnumStatement()) {
  31.176 +            EnumStatement *enumstmt = statement->toEnumStatement();
  31.177 +
  31.178 +            // We pre-fill global enum types, since they may occur in function
  31.179 +            // signatures. This should probably be somewhere else...
  31.180 +            enumstmt->accept(this);
  31.181 +        } else if (statement->isStructureStatement()) {
  31.182 +            StructureStatement *node = statement->toStructureStatement();
  31.183 +            node->accept(this);
  31.184 +            if (!node->decl()->type())
  31.185 +                return false;
  31.186 +        } else if (statement->isFunctionTypeStatement()) {
  31.187 +            FunctionTypeStatement *node = statement->toFunctionTypeStatement();
  31.188 +            node->accept(this);
  31.189 +            if (!node->decl()->type())
  31.190 +                return false;
  31.191 +        }
  31.192 +    }
  31.193 +
  31.194 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  31.195 +        Statement *statement = tree_->statements()->at(i);
  31.196 +
  31.197 +        // We can't double-process these. Maybe put this check somewhere else.
  31.198 +        if (statement->isEnumStatement())
  31.199 +            continue;
  31.200 +
  31.201 +        statement->accept(this);
  31.202 +    }
  31.203 +
  31.204 +    if (!determineLiveFunctions())
  31.205 +        return false;
  31.206 +
  31.207 +    return !cc_.failures();
  31.208 +}
  31.209 +
  31.210 +bool
  31.211 +SemanticAnalysis::determineLiveFunctions()
  31.212 +{
  31.213 +    Vector<NamedFunction *> worklist;
  31.214 +
  31.215 +    // Add the root set.
  31.216 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  31.217 +        Statement *statement = tree_->statements()->at(i);
  31.218 +        if (!statement->isFunctionStatement())
  31.219 +            continue;
  31.220 +
  31.221 +        FunctionStatement *stmt = statement->toFunctionStatement();
  31.222 +        NamedFunction  *fun = stmt->fun();
  31.223 +        if (!fun->used())
  31.224 +            continue;
  31.225 +
  31.226 +        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
  31.227 +            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
  31.228 +
  31.229 +            // Names in these lists are always unused, however, we mark them
  31.230 +            // as used while inserting into the work queue, to avoid double-
  31.231 +            // insertion.
  31.232 +            if (name->used())
  31.233 +                continue;
  31.234 +
  31.235 +            if (!worklist.append(name))
  31.236 +                return false;
  31.237 +
  31.238 +            name->setUsed();
  31.239 +        }
  31.240 +    }
  31.241 +
  31.242 +    while (!worklist.empty()) {
  31.243 +        NamedFunction *fun = worklist.popCopy();
  31.244 +
  31.245 +        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
  31.246 +            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
  31.247 +            if (name->used())
  31.248 +                continue;
  31.249 +            if (!worklist.append(name))
  31.250 +                return false;
  31.251 +            name->setUsed();
  31.252 +        }
  31.253 +    }
  31.254 +
  31.255 +    return true;
  31.256 +}
  31.257 +
  31.258 +Type *
  31.259 +SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name)
  31.260 +{
  31.261 +    if (!name)
  31.262 +        return zone_->types()->getPrimitive(PrimitiveType_Int32);
  31.263 +
  31.264 +    if (name->kind() == BoundName::UNBOUND) {
  31.265 +        cc_.reportError(pos, Message_TypeNotFound, name->name()->chars());
  31.266 +        return NULL;
  31.267 +    }
  31.268 +
  31.269 +    if (name->kind() != BoundName::TYPE) {
  31.270 +        cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars());
  31.271 +        return NULL;
  31.272 +    }
  31.273 +
  31.274 +    if (!name->type())
  31.275 +        return NULL;
  31.276 +
  31.277 +    return name->type();
  31.278 +}
  31.279 +
  31.280 +Type *
  31.281 +SemanticAnalysis::visitAndApplyType(Expression *expression)
  31.282 +{
  31.283 +    expression->accept(this);
  31.284 +    return expression->type();
  31.285 +}
  31.286 +
  31.287 +Type *
  31.288 +SemanticAnalysis::visitForLoad(Expression *expression)
  31.289 +{
  31.290 +    Local<Type> type(zone_, visitAndApplyType(expression));
  31.291 +    if (!type)
  31.292 +        return NULL;
  31.293 +
  31.294 +    if (type->isReference()) {
  31.295 +        expression->setType(type->contained());
  31.296 +    } else if (expression->isCallExpression()) {
  31.297 +        if (type->isVoid()) {
  31.298 +            CallExpression *call = expression->toCallExpression();
  31.299 +            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
  31.300 +            return NULL;
  31.301 +        }
  31.302 +    }
  31.303 +
  31.304 +    return expression->type();
  31.305 +}
  31.306 +
  31.307 +void
  31.308 +SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type)
  31.309 +{
  31.310 +    const char *op = TokenNames[token];
  31.311 +    const char *name = GetTypeName(type);
  31.312 +
  31.313 +    cc_.reportError(node->pos(), Message_UnaryTypeError, op, name);
  31.314 +}
  31.315 +
  31.316 +void
  31.317 +SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
  31.318 +{
  31.319 +    const char *op = TokenNames[token];
  31.320 +    const char *leftName = GetTypeName(left);
  31.321 +    const char *rightName = GetTypeName(right);
  31.322 +
  31.323 +    cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName);
  31.324 +}
  31.325 +
  31.326 +Type *
  31.327 +SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
  31.328 +{
  31.329 +    if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
  31.330 +        (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
  31.331 +    {
  31.332 +        // If either side is a float, the other side must be a float or int.
  31.333 +        if (left->isFloat() || right->isFloat()) {
  31.334 +            Type *floatType = left->isFloat() ? left : right;
  31.335 +            Type *other = left->isFloat() ? right : left;
  31.336 +            if (other->isFloat() || other->isInt32())
  31.337 +                return floatType;
  31.338 +        }
  31.339 +    }
  31.340 +
  31.341 +    if (token == TOK_OR || token == TOK_AND) {
  31.342 +        if (!canTest(node, left) || !canTest(node, right))
  31.343 +            return NULL;
  31.344 +        return zone_->types()->getPrimitive(PrimitiveType_Bool);
  31.345 +    }
  31.346 +
  31.347 +    if (token >= TOK_EQUALS && token <= TOK_GE) {
  31.348 +        if ((left->isFloat() || left->isInt32()) &&
  31.349 +            (right->isFloat() || right->isInt32()))
  31.350 +        {
  31.351 +            return zone_->types()->getPrimitive(PrimitiveType_Bool);
  31.352 +        }
  31.353 +        binaryTypeError(node, token, left, right);
  31.354 +        return NULL;
  31.355 +    }
  31.356 +
  31.357 +    if (!left->isInt32() || !right->isInt32()) {
  31.358 +        binaryTypeError(node, token, left, right);
  31.359 +        return NULL;
  31.360 +    }
  31.361 +
  31.362 +    return left;
  31.363 +}
  31.364 +
  31.365 +bool
  31.366 +SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
  31.367 +{
  31.368 +    if (!type->isPrimitive() && !type->isEnum()) {
  31.369 +        cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
  31.370 +        return false;
  31.371 +    }
  31.372 +    return true;
  31.373 +}
  31.374 +
  31.375 +Type *
  31.376 +SemanticAnalysis::visitForLValue(Expression *expression)
  31.377 +{
  31.378 +    if (expression->isIndexExpression()) {
  31.379 +        Type *type = visitAndApplyType(expression);
  31.380 +        if (!type)
  31.381 +            return NULL;
  31.382 +
  31.383 +        // if (type->isConst()) {
  31.384 +        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  31.385 +        //     return NULL;
  31.386 +        // }
  31.387 +
  31.388 +        return type;
  31.389 +    }
  31.390 +
  31.391 +    if (expression->isFieldExpression()) {
  31.392 +        Type *type = visitAndApplyType(expression);
  31.393 +        if (!type)
  31.394 +            return NULL;
  31.395 +
  31.396 +        // if (expression->toFieldExpression()->left()->type()->isConst()) {
  31.397 +        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  31.398 +        //     return NULL;
  31.399 +        // }
  31.400 +
  31.401 +        return type;
  31.402 +    }
  31.403 +
  31.404 +    if (!expression->isNameProxy()) {
  31.405 +        cc_.reportError(expression->pos(), Message_ExpectedLValue);
  31.406 +        return NULL;
  31.407 +    }
  31.408 +
  31.409 +    NameProxy *proxy = expression->toNameProxy();
  31.410 +    if (!proxy->binding()->kind() == BoundName::VARIABLE) {
  31.411 +        cc_.reportError(expression->pos(), Message_ExpectedLValue);
  31.412 +        return NULL;
  31.413 +    }
  31.414 +
  31.415 +    Variable *var = proxy->binding()->toVariable();
  31.416 +    if (!var->type())
  31.417 +        return NULL;
  31.418 +
  31.419 +    if  (var->type()->isReference()) {
  31.420 +        if (var->type()->isConst()) {
  31.421 +            cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  31.422 +            return NULL;
  31.423 +        }
  31.424 +        return var->type()->contained();
  31.425 +    }
  31.426 +    return var->type();
  31.427 +}
  31.428 +
  31.429 +SemanticAnalysis::ControlStatus
  31.430 +SemanticAnalysis::visitForControl(Statement *statement)
  31.431 +{
  31.432 +    ControlScope scope(&control_);
  31.433 +    statement->accept(this);
  31.434 +    return scope.status();
  31.435 +}
  31.436 +
  31.437 +void
  31.438 +SemanticAnalysis::visit(NameProxy *name)
  31.439 +{
  31.440 +    BoundName *binding = name->binding();
  31.441 +
  31.442 +    if (binding->scope()->kind() == Scope::GLOBAL) {
  31.443 +        if (!function_ || function_->isPublic()) {
  31.444 +            // Whatever we're referencing must be kept alive no matter what.
  31.445 +            // As such, we simply mark it used, and don't do anything special.
  31.446 +            binding->setUsed();
  31.447 +        } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) {
  31.448 +            // Otherwise, we're inside a normal stock or function. Since we
  31.449 +            // don't really know if we've been used yet, we shouldn't
  31.450 +            // prematurely references as alive. Instead, we keep a list of
  31.451 +            // which names have been used, so we can mark them later if needed.
  31.452 +            //
  31.453 +            // Note that we skip this step if the binding is already in the
  31.454 +            // root set.
  31.455 +            if (!function_->addUsedGlobal(binding))
  31.456 +                return;
  31.457 +        }
  31.458 +    }
  31.459 +
  31.460 +    name->setType(binding->type());
  31.461 +}
  31.462 +
  31.463 +void
  31.464 +SemanticAnalysis::visit(Assignment *node)
  31.465 +{
  31.466 +    Local<Type> exprType(zone_, visitForLoad(node->expression()));
  31.467 +    if (!exprType)
  31.468 +        return ;
  31.469 +
  31.470 +    Local<Type> type(zone_, visitForLValue(node->lvalue()));
  31.471 +    if (!type)
  31.472 +        return;
  31.473 +
  31.474 +    if (node->token() != TOK_ASSIGN) {
  31.475 +        if (!typeCheckBinary(node, node->token(), type, exprType))
  31.476 +            return;
  31.477 +    }
  31.478 +
  31.479 +    if (!typeCheckAssignment(node->pos(), exprType, type, true))
  31.480 +        return;
  31.481 +
  31.482 +    node->setType(type);
  31.483 +}
  31.484 +
  31.485 +void
  31.486 +SemanticAnalysis::visit(IncDecExpression *node)
  31.487 +{
  31.488 +    Local<Type> type(zone_, visitForLValue(node->expression()));
  31.489 +    if (!type)
  31.490 +        return;
  31.491 +
  31.492 +    assert(!type->isReference());
  31.493 +
  31.494 +    if (!type->isInt32() && !type->isFloat()) {
  31.495 +        unaryTypeError(node, node->token(), type);
  31.496 +        return;
  31.497 +    }
  31.498 +
  31.499 +    node->setType(type);
  31.500 +}
  31.501 +
  31.502 +void
  31.503 +SemanticAnalysis::visit(UnaryExpression *node)
  31.504 +{
  31.505 +    Local<Type> type(zone_, visitForLoad(node->expression()));
  31.506 +    if (!type)
  31.507 +        return;
  31.508 +
  31.509 +    switch (node->token())
  31.510 +    {
  31.511 +      case TOK_NOT:
  31.512 +        if (!canTest(node->expression(), type))
  31.513 +            return;
  31.514 +        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
  31.515 +        if (!type)
  31.516 +            return;
  31.517 +        node->setType(type);
  31.518 +        break;
  31.519 +
  31.520 +      case TOK_MINUS:
  31.521 +        if (!type->isFloat() && !type->isInt32()) {
  31.522 +            unaryTypeError(node, node->token(), type);
  31.523 +            return;
  31.524 +        }
  31.525 +        node->setType(type);
  31.526 +        break;
  31.527 +
  31.528 +      case TOK_LABEL:
  31.529 +      {
  31.530 +        Local<Type> to(zone_, bindType(node->pos(), node->type()));
  31.531 +        if (!to)
  31.532 +            return;
  31.533 +
  31.534 +        if ((!type->isFloat() && !type->isInt32OrEnum()) ||
  31.535 +            (!to->isFloat() && !to->isInt32OrEnum()))
  31.536 +        {
  31.537 +            unaryTypeError(node, node->token(), type);
  31.538 +            return;
  31.539 +        }
  31.540 +
  31.541 +        node->setType(to);
  31.542 +        break;
  31.543 +      }
  31.544 +
  31.545 +      case TOK_SIZEOF:
  31.546 +      {
  31.547 +        if (!type->isArray()) {
  31.548 +            cc_.reportError(node->pos(), Message_SizeofNeedsArray);
  31.549 +            return;
  31.550 +        }
  31.551 +        node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
  31.552 +        break;
  31.553 +      }
  31.554 +
  31.555 +      default:
  31.556 +        assert(node->token() == TOK_TILDE);
  31.557 +        if (!type->isInt32()) {
  31.558 +            unaryTypeError(node, node->token(), type);
  31.559 +            return;
  31.560 +        }
  31.561 +        node->setType(type);
  31.562 +        break;
  31.563 +    }
  31.564 +}
  31.565 +
  31.566 +void
  31.567 +SemanticAnalysis::visit(TernaryExpression *node)
  31.568 +{
  31.569 +    Local<Type> type(zone_, visitForLoad(node->condition()));
  31.570 +    if (!type)
  31.571 +        return;
  31.572 +
  31.573 +    if (!canTest(node->condition(), type))
  31.574 +        return;
  31.575 +
  31.576 +    Local<Type> left(zone_, visitForLoad(node->left()));
  31.577 +    Local<Type> right(zone_, visitForLoad(node->right()));
  31.578 +    if (!left || !right)
  31.579 +        return;
  31.580 +
  31.581 +    if (left != right) {
  31.582 +        binaryTypeError(node, TOK_QMARK, left, right);
  31.583 +        return;
  31.584 +    }
  31.585 +}
  31.586 +
  31.587 +void
  31.588 +SemanticAnalysis::visit(BinaryExpression *node)
  31.589 +{
  31.590 +    Local<Type> left(zone_, visitForLoad(node->left()));
  31.591 +    Local<Type> right(zone_, visitForLoad(node->right()));
  31.592 +    if (!left || !right)
  31.593 +        return;
  31.594 +
  31.595 +    Local<Type> result(zone_, typeCheckBinary(node, node->token(), left, right));
  31.596 +    if (!result)
  31.597 +        return;
  31.598 +
  31.599 +    node->setType(result);
  31.600 +}
  31.601 +
  31.602 +void
  31.603 +SemanticAnalysis::visit(ReturnStatement *node)
  31.604 +{
  31.605 +    // Set this early, so if we error we don't get more errors.
  31.606 +    control_->returns(Returns_Always);
  31.607 +
  31.608 +    if (!node->expression()) {
  31.609 +        if (!function_->type()->returnType()->isVoid())
  31.610 +            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
  31.611 +        return;
  31.612 +    }
  31.613 +
  31.614 +    Local<Type> type(zone_, visitForLoad(node->expression()));
  31.615 +    if (!type)
  31.616 +        return;
  31.617 +
  31.618 +    Local<Type> returnType(zone_, function_->type()->returnType());
  31.619 +    if (!typeCheckAssignment(node->pos(), type, returnType, true))
  31.620 +        return;
  31.621 +}
  31.622 +
  31.623 +void
  31.624 +SemanticAnalysis::visit(ForStatement *node)
  31.625 +{
  31.626 +    LoopScope loop(&loop_);
  31.627 +
  31.628 +    if (node->scope())
  31.629 +        scope_ = node->scope();
  31.630 +
  31.631 +    if (node->initialization())
  31.632 +        node->initialization()->accept(this);
  31.633 +
  31.634 +    if (node->condition()) {
  31.635 +        Local<Type> type(zone_, visitForLoad(node->condition()));
  31.636 +        if (!type || !canTest(node->condition(), type)) {
  31.637 +            return;
  31.638 +        }
  31.639 +    }
  31.640 +
  31.641 +    if (node->update())
  31.642 +        node->update()->accept(this);
  31.643 +
  31.644 +    ControlStatus status = visitForControl(node->body());
  31.645 +
  31.646 +    // If there is a condition, we treat this like a while loop. Otherwise,
  31.647 +    // join point is only reachable if the loop contains a break. The
  31.648 +    // termination status doesn't tell us anything yet.
  31.649 +    if (node->condition() || loop.breaks())
  31.650 +        control_->merge(status, ControlStatus(false, Returns_Never));
  31.651 +    else
  31.652 +        control_->terminate(status.returns());
  31.653 +
  31.654 +    if (node->scope())
  31.655 +        scope_ = scope_->enclosing();
  31.656 +}
  31.657 +
  31.658 +void 
  31.659 +SemanticAnalysis::visit(WhileStatement *node)
  31.660 +{
  31.661 +    LoopScope loop(&loop_);
  31.662 +
  31.663 +    Local<Type> type(zone_, visitForLoad(node->condition()));
  31.664 +    if (!type || !canTest(node->condition(), type)) {
  31.665 +        return;
  31.666 +    }
  31.667 +
  31.668 +    ControlStatus status = visitForControl(node->body());
  31.669 +
  31.670 +    // Detect loops that will always have a fork in the control-flow graph.
  31.671 +    // This will be a |while| loop, or a |do-while| loop whose body does
  31.672 +    // not terminate.
  31.673 +    //
  31.674 +    // For now, we treat these as an |if| regardless of the direction the
  31.675 +    // branch can take. That means the control-flow is always conditional.
  31.676 +    if (node->token() == TOK_WHILE ||
  31.677 +        !status.terminates() ||
  31.678 +        loop.breaks())
  31.679 +    {
  31.680 +        control_->merge(status, ControlStatus(false, Returns_Never));
  31.681 +    } else {
  31.682 +        // At this point, we've got a do-while loop with a |return| or
  31.683 +        // |continue|, meaning that the rest of the block is unreachable.
  31.684 +        control_->terminate(status.returns());
  31.685 +    }
  31.686 +}
  31.687 +
  31.688 +void
  31.689 +SemanticAnalysis::visit(BlockStatement *node)
  31.690 +{
  31.691 +    if (node->scope())
  31.692 +        scope_ = node->scope();
  31.693 +    for (size_t i = 0; i < node->statements()->length(); i++) {
  31.694 +        Statement *statement = node->statements()->at(i);
  31.695 +        statement->accept(this);
  31.696 +    }
  31.697 +    if (node->scope())
  31.698 +        scope_ = scope_->enclosing();
  31.699 +}
  31.700 +
  31.701 +static inline bool
  31.702 +IsScalarString(Type *type)
  31.703 +{
  31.704 +    if (type->isPrimitive() && type->primitive() == PrimitiveType_Char)
  31.705 +        return true;
  31.706 +    if (type->isReference())
  31.707 +        return IsScalarString(type->contained());
  31.708 +    return false;
  31.709 +}
  31.710 +
  31.711 +static const int INFER_ARRAY_SIZE = 0;
  31.712 +static const int EVAL_ARRAY_SIZE = -1;
  31.713 +static const int DYNAMIC_ARRAY_SIZE = -2;
  31.714 +
  31.715 +bool
  31.716 +SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH])
  31.717 +{
  31.718 +    bool hadEmptySize = false;
  31.719 +
  31.720 +    for (size_t i = 0; i < exprs->length(); i++) {
  31.721 +        Expression *expr = exprs->at(i);
  31.722 +        if (!expr) {
  31.723 +            dims[i] = INFER_ARRAY_SIZE;
  31.724 +            hadEmptySize = true;
  31.725 +            continue;
  31.726 +        }
  31.727 +
  31.728 +        BoxedPrimitive box;
  31.729 +        if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
  31.730 +            int size = box.toInt();
  31.731 +            if (size <= 0) {
  31.732 +                cc_.reportError(expr->pos(), Message_BadArraySize);
  31.733 +                return false;
  31.734 +            }
  31.735 +
  31.736 +            dims[i] = size;
  31.737 +            continue;
  31.738 +        }
  31.739 +
  31.740 +        Local<Type> exprType(zone_, visitForLoad(expr));
  31.741 +        if (!exprType)
  31.742 +            return false;
  31.743 +
  31.744 +        if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
  31.745 +            cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
  31.746 +            return false;
  31.747 +        }
  31.748 +
  31.749 +        if (hadEmptySize) {
  31.750 +            cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
  31.751 +            return false;
  31.752 +        }
  31.753 +
  31.754 +        dims[i] = EVAL_ARRAY_SIZE;
  31.755 +    }
  31.756 +
  31.757 +    return true;
  31.758 +}
  31.759 +
  31.760 +bool
  31.761 +SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle<Type> contained,
  31.762 +                                         int dims[MAX_ARRAY_DEPTH],
  31.763 +                                         unsigned dimcount, unsigned level)
  31.764 +{
  31.765 +    if (dims[level] == EVAL_ARRAY_SIZE) {
  31.766 +        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
  31.767 +        return false;
  31.768 +    }
  31.769 +
  31.770 +    if (dims[level] == INFER_ARRAY_SIZE) {
  31.771 +        // Strings always become dynamic arrays.
  31.772 +        if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char))
  31.773 +            dims[level] = literal->expressions()->length();
  31.774 +    } else if (dims[level] == DYNAMIC_ARRAY_SIZE) {
  31.775 +        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
  31.776 +        return false;
  31.777 +    } else {
  31.778 +        if (literal->expressions()->length() != unsigned(dims[level])) {
  31.779 +            cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1);
  31.780 +            return false;
  31.781 +        }
  31.782 +    }
  31.783 +
  31.784 +    if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) {
  31.785 +        for (size_t i = 0; i < literal->expressions()->length(); i++) {
  31.786 +            Expression *expr = literal->expressions()->at(i);
  31.787 +            if (!expr->isStringLiteral()) {
  31.788 +                cc_.reportError(expr->pos(), Message_ExpectedStringLiteral);
  31.789 +                return false;
  31.790 +            }
  31.791 +
  31.792 +            StringLiteral *lit = expr->toStringLiteral();
  31.793 +            if (dims[level + 1] > 0 &&
  31.794 +                unsigned(dims[level]) < lit->string()->length())
  31.795 +            {
  31.796 +                cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2);
  31.797 +                return false;
  31.798 +            }
  31.799 +            if (!visitAndApplyType(lit))
  31.800 +                return false;
  31.801 +        }
  31.802 +    } else if (level == dimcount - 1) {
  31.803 +        Local<Type> type(zone_);
  31.804 +        for (size_t i = 0; i < literal->expressions()->length(); i++) {
  31.805 +            Expression *expr = literal->expressions()->at(i);
  31.806 +            if (expr->isArrayLiteral()) {
  31.807 +                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
  31.808 +                return false;
  31.809 +            }
  31.810 +
  31.811 +            if ((type = visitAndApplyType(expr)) == NULL)
  31.812 +                return false;
  31.813 +
  31.814 +            if (!typeCheckAssignment(expr->pos(), type, contained, true))
  31.815 +                return false;
  31.816 +        }
  31.817 +    } else {
  31.818 +        for (size_t i = 0; i < literal->expressions()->length(); i++) {
  31.819 +            Expression *expr = literal->expressions()->at(i);
  31.820 +            if (!expr->isArrayLiteral()) {
  31.821 +                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
  31.822 +                return false;
  31.823 +            }
  31.824 +
  31.825 +            assert(expr->toArrayLiteral()->isFixed());
  31.826 +
  31.827 +            if (!inferFixedArrayLiteral(expr->toArrayLiteral(),
  31.828 +                                        contained,
  31.829 +                                        dims,
  31.830 +                                        dimcount,
  31.831 +                                        level + 1))
  31.832 +            {
  31.833 +                return false;
  31.834 +            }
  31.835 +        }
  31.836 +    }
  31.837 +
  31.838 +    return true;
  31.839 +}
  31.840 +
  31.841 +void
  31.842 +SemanticAnalysis::visit(VariableDeclaration *node)
  31.843 +{
  31.844 +    Local<Type> type(zone_, bindType(node->pos(), node->type()));
  31.845 +    if (!type)
  31.846 +        return;
  31.847 +
  31.848 +#if 0
  31.849 +    if (node->postDimensions() || type->isArray()) {
  31.850 +        // The type could be an array type, so sum the type and postDimensions
  31.851 +        // together.
  31.852 +        unsigned dimcount = node->postDimensions()->length();
  31.853 +        if (type->isArray())
  31.854 +            dimcount += type->levels();
  31.855 +        if (dimcount > MAX_ARRAY_DEPTH) {
  31.856 +            cc_.reportError(node->pos(), Message_MaximumArrayDepth);
  31.857 +            return;
  31.858 +        }
  31.859 +
  31.860 +        // Take an initial guess at the array dimension sizes.
  31.861 +        int dims[MAX_ARRAY_DEPTH];
  31.862 +        if (!evaluateDimensions(node->postDimensions(), dims))
  31.863 +            return;
  31.864 +
  31.865 +        // Now add in the type's array dimensions.
  31.866 +        Local<Type> contained(zone_, type);
  31.867 +        for (size_t i = node->postDimensions()->length(); i < dimcount; i++) {
  31.868 +            if (type->isFixedLength())
  31.869 +                dims[i] = type->fixedLength();
  31.870 +            else
  31.871 +                dims[i] = DYNAMIC_ARRAY_SIZE;
  31.872 +            contained = contained->contained();
  31.873 +        }
  31.874 +
  31.875 +        Expression *initializer = node->initialization();
  31.876 +        if (initializer &&
  31.877 +            initializer->isArrayLiteral() &&
  31.878 +            initializer->toArrayLiteral()->isFixed())
  31.879 +        {
  31.880 +            // Fixed array initializers are special; we use them to infer any
  31.881 +            // missing information in the original array. We do not evaluate
  31.882 +            // the array initializer as an expression.
  31.883 +            if (!inferFixedArrayLiteral(initializer->toArrayLiteral(),
  31.884 +                                        contained,
  31.885 +                                        dims,
  31.886 +                                        dimcount,
  31.887 +                                        0))
  31.888 +            {
  31.889 +                return;
  31.890 +            }
  31.891 +            initializer = NULL;
  31.892 +        }
  31.893 +
  31.894 +        // We now have enough information to build the actual array type.
  31.895 +        // Start from the original dimcount, not the one computed for
  31.896 +        // initializers.
  31.897 +        for (size_t i = node->postDimensions()->length() - 1;
  31.898 +             i < node->postDimensions()->length();
  31.899 +             i--)
  31.900 +        {
  31.901 +            int size = dims[i] > 0
  31.902 +                       ? dims[i]
  31.903 +                       : Type::DYNAMIC_ARRAY_SIZE;
  31.904 +
  31.905 +            type = zone_->types()->newArray(type, size, false);
  31.906 +            if (!type)
  31.907 +                return;
  31.908 +        }
  31.909 +
  31.910 +        // Finally, if we had a non-fixed initializer, make sure it type
  31.911 +        // checks. 
  31.912 +        if (initializer) {
  31.913 +            Local<Type> right(zone_, visitForLoad(initializer));
  31.914 +            if (!right)
  31.915 +                return;
  31.916 +
  31.917 +            if (!typeCheckAssignment(node->pos(), right, type, true))
  31.918 +                return;
  31.919 +        }
  31.920 +    } else {
  31.921 +        if (node->initialization()) {
  31.922 +            Local<Type> right(zone_, visitForLoad(node->initialization()));
  31.923 +            if (!right)
  31.924 +                return;
  31.925 +            if (!typeCheckAssignment(node->pos(), right, type, true))
  31.926 +                return;
  31.927 +        }
  31.928 +
  31.929 +        if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) {
  31.930 +            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
  31.931 +            return;
  31.932 +        }
  31.933 +    }
  31.934 +#endif
  31.935 +
  31.936 +#if 0
  31.937 +    // If this variable is stack allocated, we could use the LIFO heap
  31.938 +    // to allocate it. If that's the case, make sure to reserve a slot
  31.939 +    // so we can unwind the LIFO heap at the end of this scope.
  31.940 +    if (!node->variable()->needsHeapAllocation()) {
  31.941 +        if (type->isArray() || type->isStruct())
  31.942 +            scope_->setUsesLifoHeap();
  31.943 +    }
  31.944 +
  31.945 +    node->variable()->setType(type);
  31.946 +#endif
  31.947 +}
  31.948 +
  31.949 +void
  31.950 +SemanticAnalysis::visit(IntegerLiteral *node)
  31.951 +{
  31.952 +    node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
  31.953 +}
  31.954 +
  31.955 +void
  31.956 +SemanticAnalysis::visit(BooleanLiteral *node)
  31.957 +{
  31.958 +    node->setType(zone_->types()->getPrimitive(PrimitiveType_Bool));
  31.959 +}
  31.960 +
  31.961 +void
  31.962 +SemanticAnalysis::visit(ExpressionStatement *node)
  31.963 +{
  31.964 +    visitAndApplyType(node->expression());
  31.965 +}
  31.966 +
  31.967 +Box *
  31.968 +SemanticAnalysis::evaluateDefaultParameter(Handle<Type> type, Parameter *parameter)
  31.969 +{
  31.970 +    Local<Type> given(zone_, visitForLoad(parameter->initializer()));
  31.971 +
  31.972 +    BoxedPrimitive prim;
  31.973 +    if (EvaluateForConstant(parameter->initializer(), &prim)) {
  31.974 +        if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
  31.975 +            return NULL;
  31.976 +
  31.977 +        if (prim.type() == PrimitiveType_Int32)
  31.978 +            return Box::New(zone_, given, prim.toInt());
  31.979 +        return Box::New(zone_, given, prim.toFloat());
  31.980 +    } else if (parameter->initializer()->isStringLiteral()) {
  31.981 +        StringLiteral *literal = parameter->initializer()->toStringLiteral();
  31.982 +
  31.983 +        if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
  31.984 +            return NULL;
  31.985 +
  31.986 +        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, given));
  31.987 +        if (!map)
  31.988 +            return NULL;
  31.989 +
  31.990 +        Local<Array> array(zone_,
  31.991 +            Array::NewString(zone_,
  31.992 +                             map,
  31.993 +                             literal->string()->raw(),
  31.994 +                             literal->string()->length(),
  31.995 +                             Heap::Tenure_Old));
  31.996 +        if (!array)
  31.997 +            return NULL;
  31.998 +
  31.999 +        return Box::NewObj(zone_, given, array, Heap::Tenure_Old);
 31.1000 +    }
 31.1001 +
 31.1002 +    cc_.reportError(parameter->initializer()->pos(), Message_MustBeConstant);
 31.1003 +    return NULL;
 31.1004 +}
 31.1005 +
 31.1006 +bool
 31.1007 +SemanticAnalysis::buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
 31.1008 +                                    FixedArray **argsp, FixedArray **defaultsp)
 31.1009 +{
 31.1010 +    Local<FixedArray> args(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
 31.1011 +    if (!args)
 31.1012 +        return false;
 31.1013 +
 31.1014 +    Local<FixedArray> defaults(zone_);
 31.1015 +
 31.1016 +    // Apply types to arguments.
 31.1017 +    for (size_t i = 0; i < sig.parameters()->length(); i++) {
 31.1018 +        Parameter *parameter = sig.parameters()->at(i);
 31.1019 +        
 31.1020 +#if 0
 31.1021 +        Local<Type> type(zone_, bindType(parameter->variable()->pos(), parameter->type()));
 31.1022 +        if (!type)
 31.1023 +            return false;
 31.1024 +
 31.1025 +        if (parameter->reference()) {
 31.1026 +            if (parameter->dimensions()) {
 31.1027 +                cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference);
 31.1028 +                return false;
 31.1029 +            }
 31.1030 +
 31.1031 +            if (type->isStruct()) {
 31.1032 +                cc_.reportError(parameter->variable()->pos(), Message_StructCantBeReference);
 31.1033 +                return false;
 31.1034 +            }
 31.1035 +
 31.1036 +            type = zone_->types()->getReference(type, parameter->isConst());
 31.1037 +            if (!type)
 31.1038 +                return false;
 31.1039 +        } else if (parameter->dimensions()) {
 31.1040 +            type = buildArrayType(type, parameter->dimensions(), parameter->isConst());
 31.1041 +            if (!type)
 31.1042 +                return false;
 31.1043 +
 31.1044 +            if (kind == TOK_NATIVE && type->levels() > 1) {
 31.1045 +                cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
 31.1046 +                return false;
 31.1047 +            }
 31.1048 +        }
 31.1049 +
 31.1050 +        if (IsScalarString(type)) {
 31.1051 +            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
 31.1052 +            return false;
 31.1053 +        }
 31.1054 +
 31.1055 +        args->set(zone_, i, type);
 31.1056 +        parameter->variable()->setType(type);
 31.1057 +
 31.1058 +        if (parameter->initializer()) {
 31.1059 +            if (!defaults) {
 31.1060 +                defaults = FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old);
 31.1061 +                if (!defaults)
 31.1062 +                    return false;
 31.1063 +            }
 31.1064 +
 31.1065 +            Local<Box> box(zone_, evaluateDefaultParameter(type, parameter));
 31.1066 +            if (!box)
 31.1067 +                return false;
 31.1068 +
 31.1069 +            defaults->set(zone_, i, box);
 31.1070 +        }
 31.1071 +#endif
 31.1072 +    }
 31.1073 +
 31.1074 +    *argsp = args;
 31.1075 +    *defaultsp = defaults;
 31.1076 +
 31.1077 +    return true;
 31.1078 +}
 31.1079 +
 31.1080 +void
 31.1081 +SemanticAnalysis::visit(FunctionTypeStatement *node)
 31.1082 +{
 31.1083 +    if (node->decl()->type())
 31.1084 +        return;
 31.1085 +
 31.1086 +    Local<FixedArray> args(zone_);
 31.1087 +    Local<FixedArray> defaults(zone_);
 31.1088 +
 31.1089 +    const FunctionSignature &sig= node->signature();
 31.1090 +    if (!buildFunctionArgs(node,
 31.1091 +                           TOK_STOCK,
 31.1092 +                           sig,
 31.1093 +                           args.address(),
 31.1094 +                           defaults.address()))
 31.1095 +    {
 31.1096 +        return;
 31.1097 +    }
 31.1098 +
 31.1099 +#if 0
 31.1100 +    Local<Type> returnType(zone_);
 31.1101 +    if (sig.returnType())
 31.1102 +        returnType = bindType(node->pos(), sig.returnType());
 31.1103 +    else
 31.1104 +        returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
 31.1105 +
 31.1106 +    if (!returnType)
 31.1107 +        return;
 31.1108 +
 31.1109 +    Local<Type> funtype(zone_, zone_->types()->newFunction(returnType, args, defaults));
 31.1110 +    if (!funtype)
 31.1111 +        return;
 31.1112 +
 31.1113 +    node->decl()->setType(funtype);
 31.1114 +#endif
 31.1115 +}
 31.1116 +
 31.1117 +Type *
 31.1118 +SemanticAnalysis::buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst)
 31.1119 +{
 31.1120 +    Local<Type> arrayType(zone_, type);
 31.1121 +
 31.1122 +    unsigned dimcount = dimensions->length();
 31.1123 +    if (type->isArray())
 31.1124 +        dimcount += type->levels();
 31.1125 +
 31.1126 +    if (dimcount > MAX_ARRAY_DEPTH) {
 31.1127 +        cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(),
 31.1128 +                        Message_MaximumArrayDepth);
 31.1129 +        return false;
 31.1130 +    }
 31.1131 +
 31.1132 +    // Note: constness is sort of bogus. Fix this sometime.
 31.1133 +    for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) {
 31.1134 +        Expression *expr = dimensions->at(i);
 31.1135 +        if (!expr) {
 31.1136 +            arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst);
 31.1137 +            if (!arrayType)
 31.1138 +                return NULL;
 31.1139 +
 31.1140 +            continue;
 31.1141 +        }
 31.1142 +
 31.1143 +        BoxedPrimitive box;
 31.1144 +        if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
 31.1145 +            cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
 31.1146 +            return NULL;
 31.1147 +        }
 31.1148 +
 31.1149 +        if (box.toInt() <= 0) {
 31.1150 +            cc_.reportError(expr->pos(), Message_BadArraySize);
 31.1151 +            return NULL;
 31.1152 +        }
 31.1153 +
 31.1154 +        arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst);
 31.1155 +        if (!arrayType)
 31.1156 +            return NULL;
 31.1157 +    }
 31.1158 +
 31.1159 +    return arrayType;
 31.1160 +}
 31.1161 +
 31.1162 +bool
 31.1163 +SemanticAnalysis::preanalyze(FunctionStatement *node)
 31.1164 +{
 31.1165 +    Local<FixedArray> args(zone_);
 31.1166 +    Local<FixedArray> defaults(zone_);
 31.1167 +
 31.1168 +    const FunctionSignature &sig = node->signature();
 31.1169 +    if (!buildFunctionArgs(node,
 31.1170 +                           node->fun()->token(),
 31.1171 +                           sig,
 31.1172 +                           args.address(),
 31.1173 +                           defaults.address()))
 31.1174 +    {
 31.1175 +        return false;
 31.1176 +    }
 31.1177 +
 31.1178 +#if 0
 31.1179 +    Local<Type> returnType(zone_);
 31.1180 +    if (sig.returnType() ||
 31.1181 +        node->hasExplicitReturn() ||
 31.1182 +        node->fun()->isNative())
 31.1183 +    {
 31.1184 +        returnType = bindType(node->pos(), sig.returnType());
 31.1185 +    } else {
 31.1186 +        returnType = zone_->types()->getVoid();
 31.1187 +    }
 31.1188 +    if (!returnType)
 31.1189 +        return false;
 31.1190 +
 31.1191 +    if (sig.returnDimensions()) {
 31.1192 +        returnType = buildArrayType(returnType, sig.returnDimensions(), false);
 31.1193 +        if (!returnType)
 31.1194 +            return false;
 31.1195 +    }
 31.1196 +
 31.1197 +    if (IsScalarString(returnType)) {
 31.1198 +        cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
 31.1199 +        return false;
 31.1200 +    }
 31.1201 +
 31.1202 +    Local<Type> funtype(zone_);
 31.1203 +    if (node->fun()->isNative())
 31.1204 +        funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic());
 31.1205 +    else
 31.1206 +        funtype = zone_->types()->newFunction(returnType, args, defaults);
 31.1207 +    if (!funtype)
 31.1208 +        return false;
 31.1209 +    
 31.1210 +    // If the function already has a type, it was forward declared before, and
 31.1211 +    // now this is our chance to type check the second declaration.
 31.1212 +    if (node->fun()->type()) {
 31.1213 +        Local<Type> forward(zone_, node->fun()->type());
 31.1214 +        if (!Type::Compare(funtype, forward)) {
 31.1215 +            cc_.reportError(node->pos(), Message_ForwardDeclareMismatches);
 31.1216 +            return false;
 31.1217 +        }
 31.1218 +        node->fun()->setForwardType(forward);
 31.1219 +    }
 31.1220 +
 31.1221 +    node->fun()->setType(funtype);
 31.1222 +#endif
 31.1223 +
 31.1224 +    return true;
 31.1225 +}
 31.1226 +
 31.1227 +void
 31.1228 +SemanticAnalysis::visit(FunctionStatement *node)
 31.1229 +{
 31.1230 +    function_ = node->fun();
 31.1231 +    scope_ = node->scope();
 31.1232 +
 31.1233 +    ControlScope control(&control_);
 31.1234 +    if (node->body()) {
 31.1235 +        node->body()->accept(this);
 31.1236 +
 31.1237 +        ControlStatus status = control.status();
 31.1238 +        if (status.returns() == Returns_Sometimes) {
 31.1239 +            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
 31.1240 +        } else if (status.returns() == Returns_Never) {
 31.1241 +            if (!function_->type()->returnType()->isVoid())
 31.1242 +                cc_.reportError(node->pos(), Message_MissingReturnValue);
 31.1243 +        }
 31.1244 +    }
 31.1245 +
 31.1246 +    scope_ = NULL;
 31.1247 +    function_ = NULL;
 31.1248 +}
 31.1249 +
 31.1250 +void
 31.1251 +SemanticAnalysis::typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given)
 31.1252 +{
 31.1253 +    cc_.reportError(pos, Message_TypeMismatch,
 31.1254 +                    GetTypeName(actual),
 31.1255 +                    GetTypeName(given));
 31.1256 +}
 31.1257 +
 31.1258 +bool
 31.1259 +SemanticAnalysis::typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> argGiven,
 31.1260 +                                           Handle<Type> argActual, bool forAssign)
 31.1261 +{
 31.1262 +    Local<Type> actual(zone_, argActual);
 31.1263 +    Local<Type> given(zone_, argGiven);
 31.1264 +
 31.1265 +    if (!given->isArray()) {
 31.1266 +        cc_.reportError(pos, Message_ExpectedArray);
 31.1267 +        return false;
 31.1268 +    }
 31.1269 +    if (given->levels() != actual->levels()) {
 31.1270 +        cc_.reportError(pos, Message_ArrayDimensionsMismatch);
 31.1271 +        return false;
 31.1272 +    }
 31.1273 +
 31.1274 +    unsigned level = 1;
 31.1275 +    while (given->isArray()) {
 31.1276 +        if (actual->isFixedLength()) {
 31.1277 +            if (forAssign) {
 31.1278 +                if (!given->isFixedLength()) {
 31.1279 +                    cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 31.1280 +                    return false;
 31.1281 +                }
 31.1282 +
 31.1283 +                if (actual->isCharArray()) {
 31.1284 +                    // String assignment can have a truncated |given|.
 31.1285 +                    if (given->fixedLength() > actual->fixedLength()) {
 31.1286 +                        cc_.reportError(pos, Message_ArrayAssignmentTooBig);
 31.1287 +                        return false;
 31.1288 +                    }
 31.1289 +                } else {
 31.1290 +                    if (given->fixedLength() != actual->fixedLength()) {
 31.1291 +                        cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 31.1292 +                        return false;
 31.1293 +                    }
 31.1294 +                }
 31.1295 +            }
 31.1296 +        } else if (given->isFixedLength()) {
 31.1297 +            // We do not allow assignments in the form:
 31.1298 +            //    [][] = [][Y]
 31.1299 +            //
 31.1300 +            // Otherwise, the following code could break the size guarantees
 31.1301 +            // of the right-hand side:
 31.1302 +            //
 31.1303 +            //   new x[][5];
 31.1304 +            //   new y[][];
 31.1305 +            //   new z[3];
 31.1306 +            //
 31.1307 +            //   y = x;
 31.1308 +            //   y[0] = z;
 31.1309 +            //   
 31.1310 +            // Now |x[0]| contains a 4-length array.
 31.1311 +            if (level > 1) {
 31.1312 +                cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 31.1313 +                return false;
 31.1314 +            }
 31.1315 +        }
 31.1316 +        given = given->contained();
 31.1317 +        actual = actual->contained();
 31.1318 +        level++;
 31.1319 +    }
 31.1320 +
 31.1321 +    return typeCheckAssignment(pos, given, actual, forAssign);
 31.1322 +}
 31.1323 +
 31.1324 +bool
 31.1325 +SemanticAnalysis::typeCheckAssignment(const SourcePosition &pos, Handle<Type> argGiven,
 31.1326 +                                      Handle<Type> argActual, bool forAssign)
 31.1327 +{
 31.1328 +    Local<Type> actual(zone_, argActual);
 31.1329 +    Local<Type> given(zone_, argGiven);
 31.1330 +
 31.1331 +    if (actual->isArray())
 31.1332 +        return typeCheckArrayAssignment(pos, given, actual, forAssign);
 31.1333 +
 31.1334 +    if (given->isArray()) {
 31.1335 +        cc_.reportError(pos, Message_CannotAssignArrayToScalar);
 31.1336 +        return false;
 31.1337 +    }
 31.1338 +
 31.1339 +    // The given type may not have been dereferenced.
 31.1340 +    if (given->isReference())
 31.1341 +        given = given->contained();
 31.1342 +    if (actual->isReference())
 31.1343 +        actual = actual->contained();
 31.1344 +
 31.1345 +    // We coerce unchecked to a few things.
 31.1346 +    if (actual->isUnchecked() || given->isUnchecked()) {
 31.1347 +        Type *check = actual->isUnchecked() ? given : actual;
 31.1348 +        if (check->isUnchecked() ||
 31.1349 +            check->isEnum() ||
 31.1350 +            check->isInt32() ||
 31.1351 +            check->isBool() ||
 31.1352 +            check->isFloat())
 31.1353 +        {
 31.1354 +            return true;
 31.1355 +        }
 31.1356 +        typeMismatch(pos, actual, given);
 31.1357 +        return false;
 31.1358 +    }
 31.1359 +
 31.1360 +    if (given->isFunction() && actual->isFunction()) {
 31.1361 +        if (!Type::Compare(given, actual)) {
 31.1362 +            typeMismatch(pos, actual, given);
 31.1363 +            return false;
 31.1364 +        }
 31.1365 +        return true;
 31.1366 +    }
 31.1367 +
 31.1368 +    if (actual->isEnum()) {
 31.1369 +        if (!given->isEnum() || actual != given) {
 31.1370 +            typeMismatch(pos, actual, given);
 31.1371 +            return false;
 31.1372 +        }
 31.1373 +        return true;
 31.1374 +    }
 31.1375 +
 31.1376 +    if (actual->isStruct()) {
 31.1377 +        if (!given->isStruct() || actual != given) {
 31.1378 +            typeMismatch(pos, actual, given);
 31.1379 +            return false;
 31.1380 +        }
 31.1381 +        return true;
 31.1382 +    }
 31.1383 +
 31.1384 +    if (given->isEnum() || given->isFunction() || given->isStruct()) {
 31.1385 +        typeMismatch(pos, actual, given);
 31.1386 +        return false;
 31.1387 +    }
 31.1388 +
 31.1389 +    // This coercion is trivial.
 31.1390 +    if (given->isBool() && actual->isInt32())
 31.1391 +        return true;
 31.1392 +
 31.1393 +    if (given->primitive() != actual->primitive()) {
 31.1394 +        typeMismatch(pos, actual, given);
 31.1395 +        return false;
 31.1396 +    }
 31.1397 +
 31.1398 +    return true;
 31.1399 +}
 31.1400 +
 31.1401 +bool
 31.1402 +SemanticAnalysis::typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual)
 31.1403 +{
 31.1404 +    return typeCheckAssignment(node->pos(), given, actual, false);
 31.1405 +}
 31.1406 +
 31.1407 +bool
 31.1408 +SemanticAnalysis::checkArgumentCount(Handle<Type> type, unsigned actual)
 31.1409 +{
 31.1410 +    if (type->parameters()->length() == actual)
 31.1411 +        return true;
 31.1412 +
 31.1413 +    if (actual > type->parameters()->length()) {
 31.1414 +        if (!type->isNative() || !type->isNativeVariadic())
 31.1415 +            return false;
 31.1416 +        return true;
 31.1417 +    }
 31.1418 +
 31.1419 +    if (!type->defaults())
 31.1420 +        return false;
 31.1421 +
 31.1422 +    // Missing arguments. See if there's a default argument for each missing
 31.1423 +    // actual.
 31.1424 +    for (unsigned i = actual; i < type->parameters()->length(); i++) {
 31.1425 +        if (!type->defaults()->at(i))
 31.1426 +            return false;
 31.1427 +    }
 31.1428 +
 31.1429 +    return true;
 31.1430 +}
 31.1431 +
 31.1432 +void
 31.1433 +SemanticAnalysis::visit(CallExpression *node)
 31.1434 +{
 31.1435 +    Local<Type> type(zone_, visitForLoad(node->callee()));
 31.1436 +    if (!type)
 31.1437 +        return;
 31.1438 +
 31.1439 +    if (!type->isFunction()) {
 31.1440 +        cc_.reportError(node->pos(), Message_CalleeNotFunction);
 31.1441 +        return;
 31.1442 +    }
 31.1443 +
 31.1444 +    if (!checkArgumentCount(type, node->arguments()->length())) {
 31.1445 +        cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
 31.1446 +        return;
 31.1447 +    }
 31.1448 +
 31.1449 +    // NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
 31.1450 +    // if (fun->isForward()) {
 31.1451 +    //     cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
 31.1452 +    //     return;
 31.1453 +    // }
 31.1454 +
 31.1455 +    for (unsigned i = 0; i < node->arguments()->length(); i++) {
 31.1456 +        // Note: we don't compute references unless the callee needs a
 31.1457 +        // reference type.
 31.1458 +        Expression *expression = node->arguments()->at(i);
 31.1459 +        Local<Type> given(zone_, visitAndApplyType(expression));
 31.1460 +        if (!given)
 31.1461 +            return;
 31.1462 +
 31.1463 +        // Since we skip a load, check for a call expression that returns void.
 31.1464 +        if (given->isVoid()) {
 31.1465 +            assert(expression->isCallExpression());
 31.1466 +            CallExpression *call = expression->toCallExpression();
 31.1467 +            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
 31.1468 +            return;
 31.1469 +        }
 31.1470 +        
 31.1471 +        bool mustComputeReference;
 31.1472 +        if (i >= type->parameters()->length()) {
 31.1473 +            // Special handling for natives. Arguments past the formal must
 31.1474 +            // always have references computed. However, arrays are already
 31.1475 +            // references for natives.  
 31.1476 +            assert(type->isNative() && type->isNativeVariadic());
 31.1477 +            mustComputeReference = !given->isReference() && !given->isArray();
 31.1478 +        } else {
 31.1479 +            Local<Type> actual(zone_, type->parameterAt(i));
 31.1480 +
 31.1481 +            if (expression->isIndexExpression()) {
 31.1482 +                // Disabled until we can make it work.
 31.1483 +#if 0
 31.1484 +                if (actual->isArray()) {
 31.1485 +                    // We special case the ability to pass x[y] into x[], which
 31.1486 +                    // creates an array slice. We only do this if we know the
 31.1487 +                    // assignment would otherwise not type-check.
 31.1488 +                    IndexExpression *index = expression->toIndexExpression();
 31.1489 +                    if (index->left()->type()->levels() == actual->levels())
 31.1490 +                        given = index->left()->type();
 31.1491 +                } else
 31.1492 +#endif
 31.1493 +                if (actual->isReference()) {
 31.1494 +                    cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
 31.1495 +                    return;
 31.1496 +                }
 31.1497 +            }
 31.1498 +
 31.1499 +            if (!typeCheckParameter(expression, given, actual))
 31.1500 +                return;
 31.1501 +            mustComputeReference = actual->isReference() && !given->isReference();
 31.1502 +        }
 31.1503 +
 31.1504 +        // If the actual is a reference, and the given is not, we'll need to
 31.1505 +        // compute a reference, which may be allocated on the stack.
 31.1506 +        if (mustComputeReference)
 31.1507 +            scope_->setUsesLifoHeap();
 31.1508 +    }
 31.1509 +
 31.1510 +    node->setType(type->returnType());
 31.1511 +}
 31.1512 +
 31.1513 +void
 31.1514 +SemanticAnalysis::ControlScope::inherit(const ControlStatus &other)
 31.1515 +{
 31.1516 +    if (other.returns() < status().returns())
 31.1517 +        return;
 31.1518 +
 31.1519 +    if (other.terminates())
 31.1520 +        terminate(other.returns());
 31.1521 +    else
 31.1522 +        returns(other.returns());
 31.1523 +}
 31.1524 +
 31.1525 +void
 31.1526 +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
 31.1527 +{
 31.1528 +    // If both sides terminate in a return, we consider this a return as well.
 31.1529 +    if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
 31.1530 +        terminate(Returns_Always);
 31.1531 +        return;
 31.1532 +    }
 31.1533 +
 31.1534 +    ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
 31.1535 +                          ? Returns_Never
 31.1536 +                          : Returns_Sometimes;
 31.1537 +
 31.1538 +    if (left.terminates() && right.terminates())
 31.1539 +        terminate(status);
 31.1540 +    else
 31.1541 +        returns(status);
 31.1542 +}
 31.1543 +
 31.1544 +void
 31.1545 +SemanticAnalysis::visit(IfStatement *node)
 31.1546 +{
 31.1547 +    Local<Type> type(zone_, visitForLoad(node->condition()));
 31.1548 +    if (!type)
 31.1549 +        return;
 31.1550 +
 31.1551 +    if (!canTest(node, type))
 31.1552 +        return;
 31.1553 +
 31.1554 +    ControlStatus trueBranch = visitForControl(node->ifTrue());
 31.1555 +    ControlStatus falseBranch = ControlStatus(false, Returns_Never);
 31.1556 +
 31.1557 +    if (node->ifFalse())
 31.1558 +        falseBranch = visitForControl(node->ifFalse());
 31.1559 +
 31.1560 +    control_->merge(trueBranch, falseBranch);
 31.1561 +}
 31.1562 +
 31.1563 +void
 31.1564 +SemanticAnalysis::visit(IndexExpression *node)
 31.1565 +{
 31.1566 +    Local<Type> left(zone_, visitForLoad(node->left()));
 31.1567 +    Local<Type> right(zone_, visitForLoad(node->right()));
 31.1568 +
 31.1569 +    if (!left || !right)
 31.1570 +        return;
 31.1571 +
 31.1572 +    if (!right->isInt32() && !right->isEnum()) {
 31.1573 +        cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger);
 31.1574 +        return;
 31.1575 +    }
 31.1576 +    if (!left->isArray()) {
 31.1577 +        cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
 31.1578 +        return;
 31.1579 +    }
 31.1580 +
 31.1581 +    // Note: char arrays are automatically up-casted to return an int32.
 31.1582 +    if (left->isCharArray())
 31.1583 +        node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
 31.1584 +    else
 31.1585 +        node->setType(left->contained());
 31.1586 +}
 31.1587 +
 31.1588 +void
 31.1589 +SemanticAnalysis::visit(FieldExpression *node)
 31.1590 +{
 31.1591 +    Local<Type> left(zone_, visitForLoad(node->left()));
 31.1592 +    if (!left)
 31.1593 +        return;
 31.1594 +
 31.1595 +    if (!left->isStruct()) {
 31.1596 +        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
 31.1597 +                        GetTypeName(left));
 31.1598 +        return;
 31.1599 +    }
 31.1600 +
 31.1601 +    Local<String> field(zone_, node->field());
 31.1602 +
 31.1603 +    unsigned offset;
 31.1604 +    Local<Descriptor> desc(zone_, left->lookupField(field, &offset));
 31.1605 +    if (!desc) {
 31.1606 +        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
 31.1607 +                        GetTypeName(left));
 31.1608 +        return;
 31.1609 +    }
 31.1610 +
 31.1611 +    node->setFieldIndex(offset);
 31.1612 +    node->setType(desc->type());
 31.1613 +}
 31.1614 +
 31.1615 +void
 31.1616 +SemanticAnalysis::visit(EnumStatement *node)
 31.1617 +{
 31.1618 +    Local<String> name(zone_, node->name());
 31.1619 +    Local<Type> type(zone_);
 31.1620 +    if (name)
 31.1621 +        type = zone_->types()->newEnum(name);
 31.1622 +    else
 31.1623 +        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
 31.1624 +
 31.1625 +    if (!type)
 31.1626 +        return;
 31.1627 +
 31.1628 +    if (node->decl())
 31.1629 +        node->decl()->setType(type);
 31.1630 +
 31.1631 +    int value = 0;
 31.1632 +    for (size_t i = 0; i < node->entries()->length(); i++) {
 31.1633 +        EnumStatement::Entry &entry = node->entries()->at(i);
 31.1634 +
 31.1635 +        BoxedPrimitive box = BoxedPrimitive::Int(value);
 31.1636 +        if (entry.expr) {
 31.1637 +            entry.expr->accept(this);
 31.1638 +            if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
 31.1639 +                cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
 31.1640 +                return;
 31.1641 +            }
 31.1642 +
 31.1643 +            assert(box.type() == PrimitiveType_Int32);
 31.1644 +            value = box.toInt();
 31.1645 +        }
 31.1646 +
 31.1647 +#if 0
 31.1648 +        entry.name->set(type, box);
 31.1649 +#endif
 31.1650 +        value++;
 31.1651 +    }
 31.1652 +}
 31.1653 +
 31.1654 +static int
 31.1655 +SortCaseIntValues(const void *p1, const void *p2)
 31.1656 +{
 31.1657 +    CaseValue *v1 = (CaseValue *)p1;
 31.1658 +    CaseValue *v2 = (CaseValue *)p2;
 31.1659 +
 31.1660 +    return v1->box.toInt() - v2->box.toInt();
 31.1661 +}
 31.1662 +
 31.1663 +void
 31.1664 +SemanticAnalysis::visit(SwitchStatement *node)
 31.1665 +{
 31.1666 +    Local<Type> caseType(zone_, visitForLoad(node->expression()));
 31.1667 +    if (!caseType)
 31.1668 +        return;
 31.1669 +
 31.1670 +    if (!caseType->isEnum() && !caseType->isInt32()) {
 31.1671 +        cc_.reportError(node->pos(), Message_CaseMustBeInteger);
 31.1672 +        return;
 31.1673 +    }
 31.1674 +
 31.1675 +    PoolList<CaseValue> *values = new (zone_->pool()) PoolList<CaseValue>();
 31.1676 +    ControlStatus status = ControlStatus(false, Returns_Never);
 31.1677 +
 31.1678 +    Local<Type> check(zone_);
 31.1679 +    for (size_t i = 0; i < node->cases()->length(); i++) {
 31.1680 +        Case *c = node->cases()->at(i);
 31.1681 +
 31.1682 +        check = visitForLoad(c->expression());
 31.1683 +        if (!check)
 31.1684 +            return;
 31.1685 +
 31.1686 +        if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false))
 31.1687 +            return;
 31.1688 +
 31.1689 +        CaseValue v(i);
 31.1690 +        if (!EvaluateForConstant(c->expression(), &v.box)) {
 31.1691 +            cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant);
 31.1692 +            return;
 31.1693 +        }
 31.1694 +        if (!values->append(v))
 31.1695 +            return;
 31.1696 +
 31.1697 +        if (c->others()) {
 31.1698 +            for (size_t j = 0; j < c->others()->length(); j++) {
 31.1699 +                Expression *expr = c->others()->at(j);
 31.1700 +                check = visitForLoad(expr);
 31.1701 +                if (!check)
 31.1702 +                    return;
 31.1703 +
 31.1704 +                if (!typeCheckAssignment(expr->pos(), check, caseType, false))
 31.1705 +                    return;
 31.1706 +
 31.1707 +                CaseValue v(i);
 31.1708 +                if (!EvaluateForConstant(expr, &v.box)) {
 31.1709 +                    cc_.reportError(expr->pos(), Message_CaseMustBeConstant);
 31.1710 +                    return;
 31.1711 +                }
 31.1712 +                if (!values->append(v))
 31.1713 +                    return;
 31.1714 +            }
 31.1715 +        }
 31.1716 +
 31.1717 +        ControlStatus latest = visitForControl(c->statement());
 31.1718 +
 31.1719 +        if (i != 0)
 31.1720 +            control_->merge(status, latest);
 31.1721 +
 31.1722 +        status = latest;
 31.1723 +    }
 31.1724 +
 31.1725 +    if (node->defaultCase()) {
 31.1726 +        ControlStatus latest = visitForControl(node->defaultCase());
 31.1727 +
 31.1728 +        if (node->cases()->length()) {
 31.1729 +            // If we had any other cases, we must merge.
 31.1730 +            control_->merge(status, latest);
 31.1731 +        } else {
 31.1732 +            // Otherwise, control-flow always flows through here.
 31.1733 +            control_->inherit(latest);
 31.1734 +        }
 31.1735 +    } else if (node->cases()->length()) {
 31.1736 +        control_->merge(status, ControlStatus(false, Returns_Never));
 31.1737 +    }
 31.1738 +
 31.1739 +    if (values->length() > 1) {
 31.1740 +        qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues);
 31.1741 +
 31.1742 +        for (size_t i = 1; i < values->length(); i++) {
 31.1743 +            CaseValue &prev = values->at(i - 1);
 31.1744 +            CaseValue &cur = values->at(i);
 31.1745 +            if (prev.box.toInt() == cur.box.toInt()) {
 31.1746 +                cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue);
 31.1747 +                return;
 31.1748 +            }
 31.1749 +        }
 31.1750 +    }
 31.1751 +
 31.1752 +    node->setCaseValueList(values);
 31.1753 +}
 31.1754 +
 31.1755 +void
 31.1756 +SemanticAnalysis::visit(StructureStatement *node)
 31.1757 +{
 31.1758 +#if 0
 31.1759 +    // If this node already has a type, it was pre-analyzed, so skip it.
 31.1760 +    if (node->decl()->type())
 31.1761 +        return;
 31.1762 +
 31.1763 +    FieldList *fields = node->fields();
 31.1764 +    Local<FixedArray> desctable(zone_, FixedArray::New(zone_, fields->length(), Heap::Tenure_Old));
 31.1765 +    if (!desctable)
 31.1766 +        return;
 31.1767 +
 31.1768 +    Vector<unsigned> composedList;
 31.1769 +    StructureBufferBuilder builder;
 31.1770 +
 31.1771 +    Local<Type> type(zone_);
 31.1772 +    Local<String> name(zone_);
 31.1773 +    Local<Descriptor> desc(zone_);
 31.1774 +    for (size_t i = 0; i < fields->length(); i++) {
 31.1775 +        StructureStatement::Field *field = fields->at(i);
 31.1776 +
 31.1777 +        type = bindType(field->pos(), field->type());
 31.1778 +        if (!type)
 31.1779 +            return;
 31.1780 +
 31.1781 +        if (field->dimensions()) {
 31.1782 +            type = buildArrayType(type, field->dimensions(), false);
 31.1783 +            if (!type)
 31.1784 +                return;
 31.1785 +
 31.1786 +            if (!ArrayMap::Attach(zone_, type))
 31.1787 +                return;
 31.1788 +        }
 31.1789 +
 31.1790 +        if (IsScalarString(type)) {
 31.1791 +            cc_.reportError(field->pos(), Message_CannotDeclareStringCell);
 31.1792 +            return;
 31.1793 +        }
 31.1794 +
 31.1795 +        unsigned offset;
 31.1796 +        if (!builder.add(type, &offset))
 31.1797 +            return;
 31.1798 +
 31.1799 +        name = field->name();
 31.1800 +        desc = Descriptor::New(zone_, name, type, offset);
 31.1801 +        if (!desc)
 31.1802 +            return;
 31.1803 +
 31.1804 +        desctable->set(zone_, i, desc);
 31.1805 +
 31.1806 +        if (type->isStruct() || type->isArray()) {
 31.1807 +            if (!composedList.append(i))
 31.1808 +                return;
 31.1809 +        }
 31.1810 +    }
 31.1811 +
 31.1812 +    Local<FixedArray> composed(zone_);
 31.1813 +    if (composedList.length()) {
 31.1814 +        composed = FixedArray::New(zone_, composedList.length(), Heap::Tenure_Old);
 31.1815 +        if (!composed)
 31.1816 +            return;
 31.1817 +
 31.1818 +        for (unsigned i = 0; i < composedList.length(); i++)
 31.1819 +            composed->set(zone_, i, desctable->at(i));
 31.1820 +    }
 31.1821 +
 31.1822 +    Local<StructMap> map(zone_, StructMap::New(zone_, builder, composed));
 31.1823 +    if (!map)
 31.1824 +        return;
 31.1825 +
 31.1826 +    name = node->decl()->name();
 31.1827 +    type = zone_->types()->newStruct(name, desctable, map);
 31.1828 +    if (!type)
 31.1829 +        return;
 31.1830 +
 31.1831 +    map->setType(type);
 31.1832 +    node->decl()->setType(type);
 31.1833 +#endif
 31.1834 +}
 31.1835 +
 31.1836 +void
 31.1837 +SemanticAnalysis::visit(StringLiteral *node)
 31.1838 +{
 31.1839 +    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char));
 31.1840 +    if (!type)
 31.1841 +        return;
 31.1842 +
 31.1843 +    type = Type::NewArray(zone_, type, node->string()->length() + 1, true);
 31.1844 +    if (!type)
 31.1845 +        return;
 31.1846 +
 31.1847 +    node->setType(type);
 31.1848 +}
 31.1849 +
 31.1850 +void
 31.1851 +SemanticAnalysis::visit(FloatLiteral *node)
 31.1852 +{
 31.1853 +    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
 31.1854 +    if (!type)
 31.1855 +        return;
 31.1856 +
 31.1857 +    node->setType(type);
 31.1858 +}
 31.1859 +
 31.1860 +void
 31.1861 +SemanticAnalysis::visit(BreakStatement *node)
 31.1862 +{
 31.1863 +    if (!loop_) {
 31.1864 +        cc_.reportError(node->pos(), Message_BreakOutsideLoop);
 31.1865 +        return;
 31.1866 +    }
 31.1867 +
 31.1868 +    // Note: ignore breaks that occur in unreachable control-flow.
 31.1869 +    if (!control_->status().terminates())
 31.1870 +        loop_->addBreak();
 31.1871 +
 31.1872 +    control_->terminate(Returns_Never);
 31.1873 +}
 31.1874 +
 31.1875 +void
 31.1876 +SemanticAnalysis::visit(ContinueStatement *node)
 31.1877 +{
 31.1878 +    if (!loop_) {
 31.1879 +        cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
 31.1880 +        return;
 31.1881 +    }
 31.1882 +
 31.1883 +    // Note: ignore continues that occur in unreachable control-flow.
 31.1884 +    if (!control_->status().terminates())
 31.1885 +        loop_->addContinue();
 31.1886 +
 31.1887 +    control_->terminate(Returns_Never);
 31.1888 +}
 31.1889 +
 31.1890 +void
 31.1891 +SemanticAnalysis::visit(ArrayLiteral *node)
 31.1892 +{
 31.1893 +    // We should never visit this.
 31.1894 +    cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral);
 31.1895 +}
 31.1896 +
 31.1897 +void
 31.1898 +SemanticAnalysis::visit(ImportStatement *node)
 31.1899 +{
 31.1900 +}
 31.1901 +
 31.1902 +#endif
 31.1903 \ No newline at end of file
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/src/OldSema.h	Sat Nov 17 18:41:01 2012 -0800
    32.3 @@ -0,0 +1,237 @@
    32.4 +/* vim: set ts=4 sw=4 tw=99 et:
    32.5 + *
    32.6 + * Copyright (C) 2012 David Anderson
    32.7 + *
    32.8 + * This file is part of JITCraft.
    32.9 + *
   32.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   32.11 + * the terms of the GNU General Public License as published by the Free
   32.12 + * Software Foundation, either version 3 of the License, or (at your option)
   32.13 + * any later version.
   32.14 + * 
   32.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   32.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   32.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   32.18 + *
   32.19 + * You should have received a copy of the GNU General Public License along with
   32.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   32.21 + */
   32.22 +#ifndef _include_semantic_analysis_h_
   32.23 +#define _include_semantic_analysis_h_
   32.24 +
   32.25 +#include <assert.h>
   32.26 +#include "AST.h"
   32.27 +#include "../Types.h"
   32.28 +
   32.29 +namespace ke {
   32.30 +
   32.31 +class Box;
   32.32 +
   32.33 +class SemanticAnalysis : public AstVisitor
   32.34 +{
   32.35 +    Zone *zone_;
   32.36 +    CompileContext &cc_;
   32.37 +    ParseTree *tree_;
   32.38 +    Scope *scope_;
   32.39 +    NamedFunction *function_;
   32.40 +
   32.41 +    enum ReturnStatus
   32.42 +    {
   32.43 +        Returns_Never,
   32.44 +        Returns_Sometimes,
   32.45 +        Returns_Always
   32.46 +    };
   32.47 +
   32.48 +    // Tuple that describes whether a path terminates control flow, and
   32.49 +    // if it is guaranteed to end in a return.
   32.50 +    class ControlStatus
   32.51 +    {
   32.52 +        bool terminates_;
   32.53 +        ReturnStatus returns_;
   32.54 +
   32.55 +      public:
   32.56 +        ControlStatus(bool terminates, ReturnStatus returns)
   32.57 +          : terminates_(terminates),
   32.58 +            returns_(returns)
   32.59 +        {
   32.60 +        }
   32.61 +
   32.62 +        bool terminates() const {
   32.63 +            return terminates_;
   32.64 +        }
   32.65 +        ReturnStatus returns() const {
   32.66 +            return returns_;
   32.67 +        }
   32.68 +    };
   32.69 +
   32.70 +    // Used to keep track of terminating control flow and return statements
   32.71 +    // inside control structures.
   32.72 +    class ControlScope
   32.73 +    {
   32.74 +        ReturnStatus returns_;
   32.75 +        ControlScope **prevp_;
   32.76 +        ControlScope *prev_;
   32.77 +        bool terminates_;
   32.78 +
   32.79 +      public:
   32.80 +        ControlScope(ControlScope **prev)
   32.81 +          : returns_(Returns_Never),
   32.82 +            prevp_(prev),
   32.83 +            prev_(*prev),
   32.84 +            terminates_(false)
   32.85 +        {
   32.86 +            *prevp_ = this;
   32.87 +        }
   32.88 +
   32.89 +        ControlStatus status() const {
   32.90 +            return ControlStatus(terminates_, returns_);
   32.91 +        }
   32.92 +
   32.93 +        // We allow multiple terminators, but only the first one takes effect.
   32.94 +        // For example, |break; continue;| is legal but the continue is
   32.95 +        // unreachable.
   32.96 +        void returns(ReturnStatus status) {
   32.97 +            if (terminates_)
   32.98 +                return;
   32.99 +            if (status > returns_)
  32.100 +                returns_ = status;
  32.101 +        }
  32.102 +        void terminate(ReturnStatus status) {
  32.103 +            if (terminates_)
  32.104 +                return;
  32.105 +            terminates_ = true;
  32.106 +            returns_ = status;
  32.107 +        }
  32.108 +        void merge(const ControlStatus &left, const ControlStatus &right);
  32.109 +        void inherit(const ControlStatus &other);
  32.110 +
  32.111 +        ~ControlScope()
  32.112 +        {
  32.113 +            *prevp_ = prev_;
  32.114 +        }
  32.115 +    };
  32.116 +
  32.117 +    class LoopScope
  32.118 +    {
  32.119 +        LoopScope **prevp_;
  32.120 +        LoopScope *prev_;
  32.121 +        unsigned breaks_;
  32.122 +        unsigned continues_;
  32.123 +
  32.124 +      public:
  32.125 +        LoopScope(LoopScope **prev)
  32.126 +          : prevp_(prev),
  32.127 +            prev_(*prev),
  32.128 +            breaks_(0),
  32.129 +            continues_(0)
  32.130 +        {
  32.131 +            *prevp_ = this;
  32.132 +        }
  32.133 +
  32.134 +        ~LoopScope()
  32.135 +        {
  32.136 +            *prevp_ = prev_;
  32.137 +        }
  32.138 +
  32.139 +        void addBreak() {
  32.140 +            breaks_++;
  32.141 +        }
  32.142 +        void addContinue() {
  32.143 +            continues_++;
  32.144 +        }
  32.145 +        unsigned breaks() const {
  32.146 +            return breaks_;
  32.147 +        }
  32.148 +        unsigned continues() const {
  32.149 +            return continues_;
  32.150 +        }
  32.151 +    };
  32.152 +
  32.153 +    ControlScope *control_;
  32.154 +    LoopScope *loop_;
  32.155 +
  32.156 +  private:
  32.157 +    bool canTest(AstNode *node, Handle<Type> type);
  32.158 +    void typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given);
  32.159 +    void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
  32.160 +    void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
  32.161 +    Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
  32.162 +
  32.163 +    Type *bindType(const SourcePosition &pos, BoundName *name);
  32.164 +
  32.165 +    // These check if one type is compatible with another type, for various
  32.166 +    // purposes, like:
  32.167 +    //      return (expr) matches function return type
  32.168 +    //      call(a, b)    matches expected arg type
  32.169 +    //      a = b         matches declared type
  32.170 +    //
  32.171 +    bool typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
  32.172 +    bool typeCheckAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
  32.173 +    bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
  32.174 +
  32.175 +    Type *visitForLoad(Expression *expression);
  32.176 +    bool preanalyze(FunctionStatement *node);
  32.177 +    Type *visitForLValue(Expression *expression);
  32.178 +    Type *visitAndApplyType(Expression *expression);
  32.179 +    ControlStatus visitForControl(Statement *statement);
  32.180 +
  32.181 +    bool evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]);
  32.182 +    bool inferFixedArrayLiteral(ArrayLiteral *literal,
  32.183 +                                Handle<Type> type,
  32.184 +                                int dims[MAX_ARRAY_DEPTH],
  32.185 +                                unsigned dimcount,
  32.186 +                                unsigned level);
  32.187 +
  32.188 +    // Builds an array type used for parameters, returns, or field entries.
  32.189 +    Type *buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst);
  32.190 +
  32.191 +    Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
  32.192 +    bool checkArgumentCount(Handle<Type> type, unsigned actual);
  32.193 +    bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
  32.194 +                           FixedArray **args, FixedArray **defaults);
  32.195 +
  32.196 +    void markCallResultUsed(CallExpression *call);
  32.197 +
  32.198 +    bool determineLiveFunctions();
  32.199 +
  32.200 +  public:
  32.201 +    SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
  32.202 +    bool analyze();
  32.203 +
  32.204 +  public:
  32.205 +    void visit(NameProxy *name);
  32.206 +    void visit(Assignment *node);
  32.207 +    void visit(BinaryExpression *node);
  32.208 +    void visit(ReturnStatement *node);
  32.209 +    void visit(ForStatement *node);
  32.210 +    void visit(BlockStatement *node);
  32.211 +    void visit(VariableDeclaration *node);
  32.212 +    void visit(IntegerLiteral *node);
  32.213 +    void visit(ExpressionStatement *node);
  32.214 +    void visit(FunctionStatement *node);
  32.215 +    void visit(CallExpression *node);
  32.216 +    void visit(IfStatement *node);
  32.217 +    void visit(IndexExpression *node);
  32.218 +    void visit(EnumStatement *node);
  32.219 +    void visit(FloatLiteral *node);
  32.220 +    void visit(WhileStatement *node);
  32.221 +    void visit(BreakStatement *node);
  32.222 +    void visit(ContinueStatement *node);
  32.223 +    void visit(StringLiteral *node);
  32.224 +    void visit(IncDecExpression *node);
  32.225 +    void visit(UnaryExpression *node);
  32.226 +    void visit(TernaryExpression *node);
  32.227 +    void visit(BooleanLiteral *node);
  32.228 +    void visit(StructureStatement *node);
  32.229 +    void visit(FieldExpression *node);
  32.230 +    void visit(SwitchStatement *node);
  32.231 +    void visit(FunctionTypeStatement *node);
  32.232 +    void visit(ArrayLiteral *node);
  32.233 +    void visit(ImportStatement *node);
  32.234 +};
  32.235 +
  32.236 +const char *GetTypeName(Type *type);
  32.237 +
  32.238 +} // namespace ke
  32.239 +
  32.240 +#endif // _include_semantic_analysis_h_
    33.1 --- a/src/Opcodes.cpp	Mon Sep 17 00:10:01 2012 -0700
    33.2 +++ b/src/Opcodes.cpp	Sat Nov 17 18:41:01 2012 -0800
    33.3 @@ -31,7 +31,7 @@
    33.4  
    33.5  OpInfo ke::OpcodeInfo[] =
    33.6  {
    33.7 -#define OPDEF(name, number, text, length, uses, defs) \
    33.8 +#define OPDEF(name, text, length, uses, defs) \
    33.9      {text, length, uses, defs},
   33.10  #include "Opcodes.tbl"
   33.11  #undef OPDEF
   33.12 @@ -39,9 +39,8 @@
   33.13  
   33.14  Code *
   33.15  Code::New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
   33.16 -          Handle<FixedArray> objects, unsigned maxStackDepth, Handle<Module> module,
   33.17 -	      Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap,
   33.18 -          unsigned lineNumber)
   33.19 +          Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
   33.20 +          Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap)
   33.21  {
   33.22      Local<Code> code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old)));
   33.23      if (!code)
   33.24 @@ -51,10 +50,11 @@
   33.25      code->locals_ = locals;
   33.26      code->objects_ = objects;
   33.27      code->maxStackDepth_ = maxStackDepth;
   33.28 -    code->module_ = module;
   33.29 +    code->module_ = NULL;
   33.30      code->safepoints_ = safepoints;
   33.31      code->sourcemap_ = sourcemap;
   33.32 -    code->lineNumber_ = lineNumber;
   33.33 +    code->lineNumber_ = 0;
   33.34 +    code->strings_ = strings;
   33.35      return code;
   33.36  }
   33.37  
   33.38 @@ -85,7 +85,9 @@
   33.39             op == OP_VARREF_LIFO ||
   33.40             op == OP_ARGREF_LIFO ||
   33.41             op == OP_SLOTREF_LIFO ||
   33.42 -           op == OP_COPYARRAY);
   33.43 +           op == OP_COPYARRAY ||
   33.44 +           op == OP_CALLNATIVE ||
   33.45 +           op == OP_PUBLIC);
   33.46  #endif
   33.47  
   33.48      if (!safepoints_)
   33.49 @@ -133,12 +135,6 @@
   33.50  }
   33.51  
   33.52  // All jumps must be the same length.
   33.53 -STATIC_ASSERT(OP_JL_LENGTH == OP_JUMP_LENGTH);
   33.54 -STATIC_ASSERT(OP_JLE_LENGTH == OP_JUMP_LENGTH);
   33.55 -STATIC_ASSERT(OP_JG_LENGTH == OP_JUMP_LENGTH);
   33.56 -STATIC_ASSERT(OP_JGE_LENGTH == OP_JUMP_LENGTH);
   33.57 -STATIC_ASSERT(OP_JEQ_LENGTH == OP_JUMP_LENGTH);
   33.58 -STATIC_ASSERT(OP_JNE_LENGTH == OP_JUMP_LENGTH);
   33.59  STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH);
   33.60  STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH);
   33.61  
   33.62 @@ -187,7 +183,6 @@
   33.63            case OP_PICK2:
   33.64            case OP_PICK3:
   33.65            case OP_CALL:
   33.66 -          case OP_MODULE:
   33.67            case OP_LT:
   33.68            case OP_LE:
   33.69            case OP_GE:
   33.70 @@ -211,6 +206,7 @@
   33.71            case OP_TRUE:
   33.72            case OP_FALSE:
   33.73            case OP_SIZEOF:
   33.74 +          case OP_PUBLIC:
   33.75              break;
   33.76  
   33.77            case OP_STOP:
   33.78 @@ -225,22 +221,8 @@
   33.79              fprintf(fp, "%f", READ_FLOAT(pc));
   33.80              break;
   33.81  
   33.82 -          case OP_JL:
   33.83 -          case OP_JLE:
   33.84 -          case OP_JG:
   33.85 -          case OP_JGE:
   33.86 -          case OP_JEQ:
   33.87 -          case OP_JNE:
   33.88            case OP_JT:
   33.89            case OP_JF:
   33.90 -          case OP_JL_F:
   33.91 -          case OP_JLE_F:
   33.92 -          case OP_JG_F:
   33.93 -          case OP_JGE_F:
   33.94 -          case OP_JEQ_F:
   33.95 -          case OP_JNE_F:
   33.96 -          case OP_JT_F:
   33.97 -          case OP_JF_F:
   33.98            case OP_JUMP:
   33.99              fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc));
  33.100              break;
  33.101 @@ -283,22 +265,17 @@
  33.102            case OP_VARREF_LIFO:
  33.103            case OP_ARGREF_LIFO:
  33.104            case OP_OBJECT:
  33.105 -          case OP_GETMODULE_FN:
  33.106 -          case OP_GETGLOBAL_I:
  33.107 -          case OP_GETGLOBAL_F:
  33.108 -          case OP_GETGLOBAL_O:
  33.109 -          case OP_SETGLOBAL_I:
  33.110 -          case OP_SETGLOBAL_F:
  33.111 -          case OP_SETGLOBAL_O:
  33.112            case OP_GETFIELD:
  33.113            case OP_SETFIELD:
  33.114 -          case OP_FIELDREF_LIFO:
  33.115              fprintf(fp, "%u", READ_UINT32(pc));
  33.116              break;
  33.117  
  33.118            case OP_CALLNATIVE:
  33.119 -            fprintf(fp, "%u %u", READ_UINT32(pc), READ_UINT32(pc + 4));
  33.120 +          {
  33.121 +            unsigned argc = READ_UINT32(pc);
  33.122 +            fprintf(fp, " ; %u args", argc);
  33.123              break;
  33.124 +          }
  33.125  
  33.126            case OP_TABLESWITCH:
  33.127            {
  33.128 @@ -308,6 +285,14 @@
  33.129              break;
  33.130            }
  33.131  
  33.132 +          case OP_GETGLOBAL:
  33.133 +          case OP_SETGLOBAL:
  33.134 +          {
  33.135 +            unsigned index = READ_UINT32(pc);
  33.136 +            fprintf(fp, "%s", String::cast(code->strings()->at(index))->chars());
  33.137 +            break;
  33.138 +          }
  33.139 +
  33.140            default:
  33.141              // Unknown opcode!
  33.142              assert(false);
    34.1 --- a/src/Opcodes.h	Mon Sep 17 00:10:01 2012 -0700
    34.2 +++ b/src/Opcodes.h	Sat Nov 17 18:41:01 2012 -0800
    34.3 @@ -23,17 +23,35 @@
    34.4  #include <stdio.h>
    34.5  
    34.6  namespace ke {
    34.7 +    
    34.8 +struct SourcePosition
    34.9 +{
   34.10 +    int line;
   34.11 +    int col;
   34.12 +
   34.13 +    SourcePosition()
   34.14 +      : line(-1),
   34.15 +        col(-1)
   34.16 +    {
   34.17 +    }
   34.18 +
   34.19 +    SourcePosition(unsigned line, unsigned col)
   34.20 +      : line(line),
   34.21 +        col(col)
   34.22 +    {
   34.23 +    }
   34.24 +};
   34.25  
   34.26  enum Opcode
   34.27  {
   34.28 -#define OPDEF(name, number, text, length, uses, defs)   \
   34.29 -    name = number,
   34.30 +#define OPDEF(name, text, length, uses, defs)   \
   34.31 +    name,
   34.32  #include "Opcodes.tbl"
   34.33  #undef OPDEF
   34.34      OPCODES_TOTAL
   34.35  };
   34.36  
   34.37 -#define OPDEF(name, number, text, length, uses, defs)   \
   34.38 +#define OPDEF(name, text, length, uses, defs)   \
   34.39  static const unsigned name##_LENGTH = length;
   34.40  #include "Opcodes.tbl"
   34.41  #undef OPDEF
   34.42 @@ -50,26 +68,6 @@
   34.43  
   34.44  extern OpInfo OpcodeInfo[];
   34.45  
   34.46 -static inline Opcode
   34.47 -Invert(Opcode op)
   34.48 -{
   34.49 -    switch (op) {
   34.50 -      case OP_JEQ:
   34.51 -        return OP_JNE;
   34.52 -      case OP_JNE:
   34.53 -        return OP_JEQ;
   34.54 -      case OP_JG:
   34.55 -        return OP_JLE;
   34.56 -      case OP_JGE:
   34.57 -        return OP_JL;
   34.58 -      case OP_JL:
   34.59 -        return OP_JGE;
   34.60 -      default:
   34.61 -        assert(op == OP_JLE);
   34.62 -        return OP_JG;
   34.63 -    }
   34.64 -}
   34.65 -
   34.66  static const unsigned MAX_TABLESWITCH_ENTRIES = 256;
   34.67  
   34.68  static inline unsigned
    35.1 --- a/src/Opcodes.tbl	Mon Sep 17 00:10:01 2012 -0700
    35.2 +++ b/src/Opcodes.tbl	Sat Nov 17 18:41:01 2012 -0800
    35.3 @@ -17,7 +17,7 @@
    35.4   * JITCraft. If not, see http://www.gnu.org/licenses/.
    35.5   */
    35.6  // Opcode macros:
    35.7 -//  NAME            NUMBER      TEXT                LENGTH  USES  DEFS   
    35.8 +//  NAME                TEXT            LENGTH  USES  DEFS   
    35.9  //
   35.10  // Type suffixes:
   35.11  //  I = 32-bit integer
   35.12 @@ -25,83 +25,62 @@
   35.13  //  O = object reference
   35.14  
   35.15  // No operation.
   35.16 -OPDEF(OP_NOP,           0,          "nop",          1,      0,  0)
   35.17 +OPDEF(OP_NOP,           "nop",          1,      0,  0)
   35.18  
   35.19  // Pushes a signed integer immediate onto the stack.
   35.20 -OPDEF(OP_INT,           1,          "int",          5,      0,  1)    
   35.21 +OPDEF(OP_INT,           "int",          5,      0,  1)    
   35.22  
   35.23  // Returns from the current routine, propagating the value at the top of the
   35.24  // stack to the caller.
   35.25 -OPDEF(OP_RETURN,        2,          "return",       1,      1,  0)
   35.26 -
   35.27 -// Stack transitions for these comparison ops:
   35.28 -// rhs = pop()
   35.29 -// lhs = pop()
   35.30 -// if (lhs COMPARE rhs)
   35.31 -//    goto target (immediate, relative to the beginning of the jump instruction)
   35.32 -OPDEF(OP_JL,            3,          "jl",           5,      2,  0)
   35.33 -OPDEF(OP_JLE,           4,          "jle",          5,      2,  0)
   35.34 -OPDEF(OP_JG,            5,          "jg",           5,      2,  0)
   35.35 -OPDEF(OP_JGE,           6,          "jge",          5,      2,  0)
   35.36 -OPDEF(OP_JEQ,           7,          "jeq",          5,      2,  0)
   35.37 -OPDEF(OP_JNE,           8,          "jne",          5,      2,  0)
   35.38 +OPDEF(OP_RETURN,        "return",       1,      1,  0)
   35.39  
   35.40  // value = pop()
   35.41  // if (value == [true, false])
   35.42  //    goto target
   35.43 -OPDEF(OP_JT,            9,          "jt",           5,      1,  0)
   35.44 -OPDEF(OP_JF,            10,         "jf",           5,      1,  0)
   35.45 -
   35.46 -OPDEF(OP_JL_F,          11,         "jl.f",         5,      2,  0)
   35.47 -OPDEF(OP_JLE_F,         12,         "jle.f",        5,      2,  0)
   35.48 -OPDEF(OP_JG_F,          13,         "jg.f",         5,      2,  0)
   35.49 -OPDEF(OP_JGE_F,         14,         "jge.f",        5,      2,  0)
   35.50 -OPDEF(OP_JEQ_F,         15,         "jeq.f",        5,      2,  0)
   35.51 -OPDEF(OP_JNE_F,         16,         "jne.f",        5,      2,  0)
   35.52 -OPDEF(OP_JT_F,          17,         "jt.f",         5,      1,  0)
   35.53 -OPDEF(OP_JF_F,          18,         "jf.f",         5,      1,  0)
   35.54 +OPDEF(OP_JT,            "jt",           5,      1,  0)
   35.55 +OPDEF(OP_JF,            "jf",           5,      1,  0)
   35.56  
   35.57  // Unconditional jump.
   35.58 -OPDEF(OP_JUMP,          19,         "jump",         5,      0,  0)
   35.59 +OPDEF(OP_JUMP,          "jump",         5,      0,  0)
   35.60  
   35.61  // Gets or sets the value of a local variable onto the stack. The local
   35.62  // variable is given by an immediate index.
   35.63 -OPDEF(OP_GETLOCAL,      20,         "getlocal",     5,      0,  1)
   35.64 -OPDEF(OP_SETLOCAL,      21,         "setlocal",     5,      1,  1)
   35.65 +OPDEF(OP_GETLOCAL,      "getlocal",     5,      0,  1)
   35.66 +OPDEF(OP_SETLOCAL,      "setlocal",     5,      1,  1)
   35.67  
   35.68  // Stack transitions for these binary operators:
   35.69  // rhs = pop()
   35.70  // lhs = pop()
   35.71  // push(lhs OP rhs)
   35.72 -OPDEF(OP_ADD,           22,         "add",          1,      2,  1)
   35.73 -OPDEF(OP_SUB,           23,         "sub",          1,      2,  1)
   35.74 -OPDEF(OP_MUL,           24,         "mul",          1,      2,  1)
   35.75 -OPDEF(OP_DIV,           25,         "div",          1,      2,  1)
   35.76 -OPDEF(OP_MOD,           26,         "mod",          1,      2,  1)
   35.77 +OPDEF(OP_ADD,           "add",          1,      2,  1)
   35.78 +OPDEF(OP_SUB,           "sub",          1,      2,  1)
   35.79 +OPDEF(OP_MUL,           "mul",          1,      2,  1)
   35.80 +OPDEF(OP_DIV,           "div",          1,      2,  1)
   35.81 +OPDEF(OP_MOD,           "mod",          1,      2,  1)
   35.82  
   35.83 -OPDEF(OP_LT,            27,         "lt",           1,      2,  1)
   35.84 -OPDEF(OP_LE,            28,         "le",           1,      2,  1)
   35.85 -OPDEF(OP_GE,            29,         "ge",           1,      2,  1)
   35.86 -OPDEF(OP_GT,            30,         "gt",           1,      2,  1)
   35.87 -OPDEF(OP_EQ,            31,         "eq",           1,      2,  1)
   35.88 -OPDEF(OP_NE,            32,         "ne",           1,      2,  1)
   35.89 +OPDEF(OP_LT,            "lt",           1,      2,  1)
   35.90 +OPDEF(OP_LE,            "le",           1,      2,  1)
   35.91 +OPDEF(OP_GE,            "ge",           1,      2,  1)
   35.92 +OPDEF(OP_GT,            "gt",           1,      2,  1)
   35.93 +OPDEF(OP_EQ,            "eq",           1,      2,  1)
   35.94 +OPDEF(OP_NE,            "ne",           1,      2,  1)
   35.95  
   35.96 -OPDEF(OP_NOT,           33,         "not",          1,      1,  1)
   35.97 -OPDEF(OP_NEG,           34,         "neg",          1,      1,  1)
   35.98 +OPDEF(OP_NOT,           "not",          1,      1,  1)
   35.99 +OPDEF(OP_NEG,           "neg",          1,      1,  1)
  35.100  
  35.101 -OPDEF(OP_POP,           35,         "pop",          1,      1,  0)
  35.102 +OPDEF(OP_POP,           "pop",          1,      1,  0)
  35.103  
  35.104  // Unconditional terminator placed at the end of code. If a function returns
  35.105  // void, this acts as a RETURNVOID. Otherwise, it must be unreachable.
  35.106 -OPDEF(OP_STOP,          36,         "stop",         1,      0,  0)
  35.107 +OPDEF(OP_STOP,          "stop",         1,      0,  0)
  35.108  
  35.109  // Call a function with N arguments. The target function must be the last item
  35.110  // on the stack.
  35.111 -OPDEF(OP_CALL,          37,         "call",         1,      -1, 1)
  35.112 +OPDEF(OP_CALL,          "call",         1,      -1, 1)
  35.113  
  35.114  // Similar to GET/LOCAL, except for arguments.
  35.115 -OPDEF(OP_GETARG,        38,         "getarg",       5,      0,  1)
  35.116 -OPDEF(OP_SETARG,        39,         "setarg",       5,      1,  1)
  35.117 +OPDEF(OP_GETARG,        "getarg",       5,      0,  1)
  35.118 +OPDEF(OP_SETARG,        "setarg",       5,      1,  1)
  35.119  
  35.120  // Allocates either:
  35.121  //   A fixed array, 
  35.122 @@ -113,83 +92,83 @@
  35.123  //
  35.124  // Format:
  35.125  //  [u8 op] [u8 tenure] [u32 index]
  35.126 -OPDEF(OP_NEWFIXED,      40,         "newfixed",     6,      0, 1)
  35.127 -OPDEF(OP_NEWEMPTY,      41,         "newempty",     6,      0, 1)
  35.128 -OPDEF(OP_NEWSIZED,      42,         "newsized",     6,     -1, 1)
  35.129 +OPDEF(OP_NEWFIXED,      "newfixed",     6,      0, 1)
  35.130 +OPDEF(OP_NEWEMPTY,      "newempty",     6,      0, 1)
  35.131 +OPDEF(OP_NEWSIZED,      "newsized",     6,     -1, 1)
  35.132  
  35.133  // Performs an array-to-array assignment.
  35.134  //   Left = pop()
  35.135  //   Right = pop()
  35.136  //   copy(Left, Right)
  35.137  //   push(Left)
  35.138 -OPDEF(OP_COPYARRAY,     43,         "arraycopy",    1,      2,  1)
  35.139 +OPDEF(OP_COPYARRAY,     "arraycopy",    1,      2,  1)
  35.140  
  35.141  // Reads or writes an integer element to an unsafe array.
  35.142  //  index = pop()
  35.143  //  ref = pop()
  35.144  //  ref[index]
  35.145  //
  35.146 -OPDEF(OP_GETELEM,       44,         "getelem",      1,      2,  1)
  35.147 -OPDEF(OP_SETELEM,       45,         "setelem",      1,      3,  1)
  35.148 +OPDEF(OP_GETELEM,       "getelem",      1,      2,  1)
  35.149 +OPDEF(OP_SETELEM,       "setelem",      1,      3,  1)
  35.150  
  35.151  // Pushes a 32-bit IEEE-754 floating point immediate onto the stack.
  35.152 -OPDEF(OP_FLOAT,         46,         "float",        5,      0,  1)
  35.153 +OPDEF(OP_FLOAT,         "float",        5,      0,  1)
  35.154  
  35.155  // Converts an integer to a 32-bit IEEE-754 floating point immediate.
  35.156 -OPDEF(OP_CVT_I2F,       47,         "cvt.i2f",      1,      1,  1)
  35.157 +OPDEF(OP_CVT_I2F,       "cvt.i2f",      1,      1,  1)
  35.158  
  35.159  // Stack transitions for these binary operators:
  35.160  // rhs = pop()
  35.161  // lhs = pop()
  35.162  // push(lhs OP rhs)
  35.163 -OPDEF(OP_ADD_F,         48,         "add.f",        1,      2,  1)
  35.164 -OPDEF(OP_SUB_F,         49,         "sub.f",        1,      2,  1)
  35.165 -OPDEF(OP_MUL_F,         50,         "mul.f",        1,      2,  1)
  35.166 -OPDEF(OP_DIV_F,         51,         "div.f",        1,      2,  1)
  35.167 +OPDEF(OP_ADD_F,         "add.f",        1,      2,  1)
  35.168 +OPDEF(OP_SUB_F,         "sub.f",        1,      2,  1)
  35.169 +OPDEF(OP_MUL_F,         "mul.f",        1,      2,  1)
  35.170 +OPDEF(OP_DIV_F,         "div.f",        1,      2,  1)
  35.171  
  35.172 -OPDEF(OP_LT_F,          52,         "lt.f",         1,      2,  1)
  35.173 -OPDEF(OP_LE_F,          53,         "le.f",         1,      2,  1)
  35.174 -OPDEF(OP_GE_F,          54,         "ge.f",         1,      2,  1)
  35.175 -OPDEF(OP_GT_F,          55,         "gt.f",         1,      2,  1)
  35.176 -OPDEF(OP_EQ_F,          56,         "eq.f",         1,      2,  1)
  35.177 -OPDEF(OP_NE_F,          57,         "ne.f",         1,      2,  1)
  35.178 +OPDEF(OP_LT_F,          "lt.f",         1,      2,  1)
  35.179 +OPDEF(OP_LE_F,          "le.f",         1,      2,  1)
  35.180 +OPDEF(OP_GE_F,          "ge.f",         1,      2,  1)
  35.181 +OPDEF(OP_GT_F,          "gt.f",         1,      2,  1)
  35.182 +OPDEF(OP_EQ_F,          "eq.f",         1,      2,  1)
  35.183 +OPDEF(OP_NE_F,          "ne.f",         1,      2,  1)
  35.184  
  35.185 -OPDEF(OP_NOT_F,         58,         "not.f",        1,      1,  1)
  35.186 -OPDEF(OP_NEG_F,         59,         "neg.f",        1,      1,  1)
  35.187 +OPDEF(OP_NOT_F,         "not.f",        1,      1,  1)
  35.188 +OPDEF(OP_NEG_F,         "neg.f",        1,      1,  1)
  35.189  
  35.190  // Bitwise operators.
  35.191 -OPDEF(OP_SHL,           60,         "shl",          1,      2,  1)
  35.192 -OPDEF(OP_SHR,           61,         "shr",          1,      2,  1)
  35.193 -OPDEF(OP_USHR,          62,         "ushr",         1,      2,  1)
  35.194 -OPDEF(OP_BITAND,        63,         "bitand",       1,      2,  1)
  35.195 -OPDEF(OP_BITOR,         64,         "bitor",        1,      2,  1)
  35.196 -OPDEF(OP_BITXOR,        65,         "bitxor",       1,      2,  1)
  35.197 -OPDEF(OP_BITNOT,        66,         "bitnot",       1,      1,  1)
  35.198 +OPDEF(OP_SHL,           "shl",          1,      2,  1)
  35.199 +OPDEF(OP_SHR,           "shr",          1,      2,  1)
  35.200 +OPDEF(OP_USHR,          "ushr",         1,      2,  1)
  35.201 +OPDEF(OP_BITAND,        "bitand",       1,      2,  1)
  35.202 +OPDEF(OP_BITOR,         "bitor",        1,      2,  1)
  35.203 +OPDEF(OP_BITXOR,        "bitxor",       1,      2,  1)
  35.204 +OPDEF(OP_BITNOT,        "bitnot",       1,      1,  1)
  35.205  
  35.206  // Saves or restores the position of the LIFO heap to/from a local slot.
  35.207 -OPDEF(OP_SAVELIFO,      67,         "savelifo",     5,      0,  0)
  35.208 -OPDEF(OP_UNWINDLIFO,    68,         "unwindlifo",   5,      0,  0)
  35.209 +OPDEF(OP_SAVELIFO,      "savelifo",     5,      0,  0)
  35.210 +OPDEF(OP_UNWINDLIFO,    "unwindlifo",   5,      0,  0)
  35.211  
  35.212  // Composes a variable reference to a stack slot or argument.
  35.213 -OPDEF(OP_VARREF_LIFO,   69,         "varref.lifo",  5,      0,  1)
  35.214 -OPDEF(OP_ARGREF_LIFO,   70,         "argref.lifo",  5,      0,  1)
  35.215 -OPDEF(OP_SLOTREF_LIFO,  71,         "slotref.lifo", 1,      1,  1)
  35.216 -OPDEF(OP_GETREF_I,      72,         "getref.i",     1,      1,  1)
  35.217 -OPDEF(OP_SETREF_I,      73,         "setref.i",     1,      2,  1)
  35.218 -OPDEF(OP_GETREF_F,      74,         "getref.f",     1,      1,  1)
  35.219 -OPDEF(OP_SETREF_F,      75,         "setref.f",     1,      2,  1)
  35.220 +OPDEF(OP_VARREF_LIFO,   "varref.lifo",  5,      0,  1)
  35.221 +OPDEF(OP_ARGREF_LIFO,   "argref.lifo",  5,      0,  1)
  35.222 +OPDEF(OP_SLOTREF_LIFO,  "slotref.lifo", 1,      1,  1)
  35.223 +OPDEF(OP_GETREF_I,      "getref.i",     1,      1,  1)
  35.224 +OPDEF(OP_SETREF_I,      "setref.i",     1,      2,  1)
  35.225 +OPDEF(OP_GETREF_F,      "getref.f",     1,      1,  1)
  35.226 +OPDEF(OP_SETREF_F,      "setref.f",     1,      2,  1)
  35.227  
  35.228  // Pushes an object reference onto the stack.
  35.229 -OPDEF(OP_OBJECT,        76,         "object",       5,      0,  1)
  35.230 +OPDEF(OP_OBJECT,        "object",       5,      0,  1)
  35.231  
  35.232  // Duplicates the top item on the stack.
  35.233 -OPDEF(OP_DUP,           77,         "dup",          1,      1,  2)
  35.234 +OPDEF(OP_DUP,           "dup",          1,      1,  2)
  35.235  
  35.236  // Duplicates the top two items on the stack.
  35.237 -OPDEF(OP_DUP2,          78,         "dup2",         1,      2,  4)
  35.238 +OPDEF(OP_DUP2,          "dup2",         1,      2,  4)
  35.239  
  35.240  // Swaps the two items at the top of the stack.
  35.241 -OPDEF(OP_SWAP,          79,         "swap",         1,      2,  2)
  35.242 +OPDEF(OP_SWAP,          "swap",         1,      2,  2)
  35.243  
  35.244  // Roll operation is the same as Forth. It steals a value on the stack,
  35.245  // shifting all stack values down, and then places the stolen value back at
  35.246 @@ -199,77 +178,68 @@
  35.247  //  sp[-3] = sp[-2]
  35.248  //  sp[-2] = sp[-1]
  35.249  //  sp[-1] = p
  35.250 -OPDEF(OP_ROLL3,         80,         "roll3",        1,      3, 3)
  35.251 +OPDEF(OP_ROLL3,         "roll3",        1,      3, 3)
  35.252  
  35.253  // Pick operation is the same as Forth. It pushes a copy of a slot at a
  35.254  // specific depth.
  35.255  //
  35.256  // push(sp[-n])
  35.257 -OPDEF(OP_PICK2,         81,         "pick2",        1,      2, 3)
  35.258 -OPDEF(OP_PICK3,         82,         "pick3",        1,      3, 4)
  35.259 +OPDEF(OP_PICK2,         "pick2",        1,      2, 3)
  35.260 +OPDEF(OP_PICK3,         "pick3",        1,      3, 4)
  35.261  
  35.262  // Calls a native function. During the course of calling a native, arguments
  35.263  // on the stack are re-pushed to match the cell-based native calling
  35.264  // convention expected by ISourcePawnEngine.
  35.265  //
  35.266  // Unlike the normal CALL instruction, natives take truly variadic arguments
  35.267 -// and so we must specify the number of arguments. The format is:
  35.268 +// and so we must specify the number of arguments.
  35.269  //
  35.270 -// [u8 Opcode] [u32 Index] [u32 ArgCount]
  35.271 +// [u8 Opcode] [u32 ArgCount]
  35.272  //
  35.273 -OPDEF(OP_CALLNATIVE,    83,         "callnative",   9,      -1, 1)
  35.274 +OPDEF(OP_CALLNATIVE,    "callnative",   5,     -1, 1)
  35.275  
  35.276  // Returns from a function that does return a value.
  35.277 -OPDEF(OP_RETURNVOID,    84,         "returnvoid",   1,      0, 0)
  35.278 -
  35.279 -// Loads the module of the running function.
  35.280 -OPDEF(OP_MODULE,        85,         "module",       1,      0, 1)
  35.281 +OPDEF(OP_RETURNVOID,    "returnvoid",   1,      0, 0)
  35.282  
  35.283 -// Loads a function from a module object. The operand is the slot number
  35.284 -// in the module.
  35.285 -OPDEF(OP_GETMODULE_FN,  86,         "getmodule.fn", 5,      1, 1)
  35.286 -
  35.287 -// Opcodes for accessing an environment slot in the global scope.
  35.288 -OPDEF(OP_SETGLOBAL_I,   87,         "setglobal.i",  5,      1, 1)
  35.289 -OPDEF(OP_SETGLOBAL_F,   88,         "setglobal.f",  5,      1, 1)
  35.290 -OPDEF(OP_SETGLOBAL_O,   89,         "setglobal.o",  5,      1, 1)
  35.291 -OPDEF(OP_GETGLOBAL_I,   90,         "getglobal.i",  5,      0, 1)
  35.292 -OPDEF(OP_GETGLOBAL_F,   91,         "getglobal.f",  5,      0, 1)
  35.293 -OPDEF(OP_GETGLOBAL_O,   92,         "getglobal.o",  5,      0, 1)
  35.294 +// Opcodes for accessing an environment slot in the global scope. The index
  35.295 +// maps into the code object's string table, and represents the name of the
  35.296 +// global variable.
  35.297 +OPDEF(OP_SETGLOBAL,     "setglobal",    5,      1, 1)
  35.298 +OPDEF(OP_GETGLOBAL,     "getglobal",    5,      0, 1)
  35.299  
  35.300  // Reinterprets a 32-bit integer as a float, or vice-versa.
  35.301 -OPDEF(OP_BITS_I2F,      93,         "bits.i2f",     1,      1, 1)
  35.302 -OPDEF(OP_BITS_F2I,      94,         "bits.f2i",     1,      1, 1)
  35.303 +OPDEF(OP_BITS_I2F,      "bits.i2f",     1,      1, 1)
  35.304 +OPDEF(OP_BITS_F2I,      "bits.f2i",     1,      1, 1)
  35.305  
  35.306  // Pushes a boolean value.
  35.307 -OPDEF(OP_TRUE,          95,         "true",         1,      0, 1)
  35.308 -OPDEF(OP_FALSE,         96,         "false",        1,      0, 1)
  35.309 +OPDEF(OP_TRUE,          "true",         1,      0, 1)
  35.310 +OPDEF(OP_FALSE,         "false",        1,      0, 1)
  35.311  
  35.312  // Allocate a struct. The HeapTenure is stored as a byte following pc. The
  35.313  // StructMap to use is specified as an index into the script's Map table.
  35.314  //
  35.315  // Format:
  35.316  //  [u8 op] [u8 tenure] [u32 index]
  35.317 -OPDEF(OP_NEWSTRUCT,     97,         "newstruct",    6,      0, 1)
  35.318 +OPDEF(OP_NEWSTRUCT,     "newstruct",    6,      0, 1)
  35.319  
  35.320  // Performs a struct-to-struct assignment.
  35.321  //   Left = pop()
  35.322  //   Right = pop()
  35.323  //   copy(Left, Right)
  35.324  //   push(Left)
  35.325 -OPDEF(OP_COPYSTRUCT,    98,         "structcopy",   1,      2, 1)
  35.326 +OPDEF(OP_COPYSTRUCT,    "structcopy",   1,      2, 1)
  35.327  
  35.328  // Sets or gets a property in a struct. The index of the field is specified as
  35.329  // a 32-bit integer. Note that these opcodes follow a new style of deriving
  35.330  // their types at runtime.
  35.331 -OPDEF(OP_GETFIELD,      99,         "getfield",     5,      1, 1)
  35.332 -OPDEF(OP_SETFIELD,      100,        "setfield",     5,      2, 1)
  35.333 -
  35.334 -OPDEF(OP_FIELDREF_LIFO, 101,        "fieldref.lifo", 5,     1, 1)
  35.335 +OPDEF(OP_GETFIELD,      "getfield",     5,      1, 1)
  35.336 +OPDEF(OP_SETFIELD,      "setfield",     5,      2, 1)
  35.337  
  35.338  // Table-based jump.
  35.339  // [u8 op] [i32 low] [i32 high] [u32 jump] [u32 jumps...]
  35.340 -OPDEF(OP_TABLESWITCH,   102,        "tableswitch",  9,      1, 0)
  35.341 +OPDEF(OP_TABLESWITCH,   "tableswitch",  9,      1, 0)
  35.342  
  35.343 -OPDEF(OP_SIZEOF,        103,        "sizeof",       1,      1, 1)
  35.344 +OPDEF(OP_SIZEOF,        "sizeof",       1,      1, 1)
  35.345  
  35.346 +// Registers a function as a publicly exported name.
  35.347 +OPDEF(OP_PUBLIC,        "public",       1,      1, 0)
  35.348 \ No newline at end of file
    36.1 --- a/src/Parser.cpp	Mon Sep 17 00:10:01 2012 -0700
    36.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.3 @@ -1,1846 +0,0 @@
    36.4 -/* vim: set ts=4 sw=4 tw=99 et:
    36.5 - *
    36.6 - * Copyright (C) 2012 David Anderson
    36.7 - *
    36.8 - * This file is part of SourcePawn.
    36.9 - *
   36.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   36.11 - * the terms of the GNU General Public License as published by the Free
   36.12 - * Software Foundation, either version 3 of the License, or (at your option)
   36.13 - * any later version.
   36.14 - * 
   36.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   36.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   36.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   36.18 - *
   36.19 - * You should have received a copy of the GNU General Public License along with
   36.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   36.21 - */
   36.22 -#include <string.h>
   36.23 -#include "Zone.h"
   36.24 -#include "Parser.h"
   36.25 -#include "FixedArray.h"
   36.26 -#include "Heap.h"
   36.27 -#include "Strings.h"
   36.28 -#include "TypeManager.h"
   36.29 -#include "Heap-inl.h"
   36.30 -
   36.31 -using namespace ke;
   36.32 -
   36.33 -Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length)
   36.34 -  : zone_(zone),
   36.35 -    cc_(cc),
   36.36 -    pool_(zone_->pool()),
   36.37 -    scanner_(cc, stream, length),
   36.38 -    scope_(NULL),
   36.39 -    unbound_(NULL)
   36.40 -{
   36.41 -    unbound_ = new (pool_) PoolList<NameProxy *>();
   36.42 -}
   36.43 -
   36.44 -bool
   36.45 -Parser::peek(TokenKind kind)
   36.46 -{
   36.47 -    return scanner_.peek() == kind;
   36.48 -}
   36.49 -
   36.50 -bool
   36.51 -Parser::match(TokenKind kind)
   36.52 -{
   36.53 -    if (!peek(kind))
   36.54 -        return false;
   36.55 -    scanner_.scan();
   36.56 -    return true;
   36.57 -}
   36.58 -
   36.59 -bool
   36.60 -Parser::matchSemicolon()
   36.61 -{
   36.62 -    return expect(TOK_SEMICOLON);
   36.63 -}
   36.64 -
   36.65 -bool
   36.66 -Parser::expect(TokenKind kind)
   36.67 -{
   36.68 -    TokenKind got = scanner_.scan();
   36.69 -    if (got == kind)
   36.70 -        return true;
   36.71 -    cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]);
   36.72 -    return false;
   36.73 -}
   36.74 -
   36.75 -Scope *
   36.76 -Parser::enterScope(Scope::Kind kind)
   36.77 -{
   36.78 -    scope_ = new (pool_) Scope(pool_, kind, scope_);
   36.79 -    if (!scope_->initialize())
   36.80 -        return NULL;
   36.81 -    return scope_;
   36.82 -}
   36.83 -
   36.84 -NameProxy *
   36.85 -Parser::bind(Handle<String> name)
   36.86 -{
   36.87 -    BoundName *bound = scope_->lookup(name);
   36.88 -    NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), name, bound);
   36.89 -    if (!bound && !unbound_->append(proxy))
   36.90 -        return NULL;
   36.91 -    return proxy;
   36.92 -}
   36.93 -
   36.94 -BoundName *
   36.95 -Parser::bindType(Handle<String> name)
   36.96 -{
   36.97 -    if (BoundName *binding = scope_->lookup(name))
   36.98 -        return binding;
   36.99 -
  36.100 -    return new (pool_) UnboundName(scope_, name);
  36.101 -}
  36.102 -
  36.103 -bool
  36.104 -Parser::matchName(String **name, TokenKind kind)
  36.105 -{
  36.106 -    assert(kind == TOK_NAME || kind == TOK_LABEL);
  36.107 -    *name = NULL;
  36.108 -    if (!match(kind))
  36.109 -        return false;
  36.110 -    *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
  36.111 -    return true;
  36.112 -}
  36.113 -
  36.114 -String *
  36.115 -Parser::expectName()
  36.116 -{
  36.117 -    if (!expect(TOK_NAME))
  36.118 -        return NULL;
  36.119 -    return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
  36.120 -}
  36.121 -
  36.122 -void
  36.123 -Parser::redeclarationError(BoundName *other)
  36.124 -{
  36.125 -    cc_.reportError(scanner_.begin(), Message_RedeclaredName, other->name()->chars(),
  36.126 -                    other->pos().line, other->pos().col);
  36.127 -}
  36.128 -
  36.129 -Expression *
  36.130 -Parser::primitive()
  36.131 -{
  36.132 -    TokenKind kind = scanner_.peek();
  36.133 -    switch (kind) {
  36.134 -      case TOK_FLOAT_LITERAL:
  36.135 -      {
  36.136 -        scanner_.scan();
  36.137 -        double value = Scanner::ParseDouble(scanner_.literal());
  36.138 -        return new (pool_) FloatLiteral(scanner_.begin(), value);
  36.139 -      }
  36.140 -
  36.141 -      case TOK_HEX_LITERAL:
  36.142 -      {
  36.143 -        scanner_.scan();
  36.144 -        int value = strtol(scanner_.literal(), NULL, 16);
  36.145 -        return new (pool_) IntegerLiteral(scanner_.begin(), value);
  36.146 -      }
  36.147 -
  36.148 -      case TOK_INTEGER_LITERAL:
  36.149 -      {
  36.150 -        scanner_.scan();
  36.151 -        int value = atoi(scanner_.literal());
  36.152 -        return new (pool_) IntegerLiteral(scanner_.begin(), value);
  36.153 -      }
  36.154 -
  36.155 -      case TOK_TRUE:
  36.156 -      case TOK_FALSE:
  36.157 -        scanner_.scan();
  36.158 -        return new (pool_) BooleanLiteral(scanner_.begin(), kind);
  36.159 -
  36.160 -      case TOK_STRING_LITERAL:
  36.161 -      {
  36.162 -        scanner_.scan();
  36.163 -        Local<ByteArray> array(zone_, ByteArray::New(zone_, scanner_.literal_length() + 1));
  36.164 -        if (!array)
  36.165 -            return NULL;
  36.166 -        memcpy(array->raw(), scanner_.literal(), scanner_.literal_length() + 1);
  36.167 -        return new (pool_) StringLiteral(scanner_.begin(), array);
  36.168 -      }
  36.169 -
  36.170 -      default:
  36.171 -      {
  36.172 -        if (kind != TOK_ERROR)
  36.173 -            cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]);
  36.174 -        return NULL;
  36.175 -      }
  36.176 -    }
  36.177 -}
  36.178 -
  36.179 -Expression *
  36.180 -Parser::arrayLiteral(TokenKind kind)
  36.181 -{
  36.182 -    assert(kind == TOK_LBRACE || kind == TOK_LBRACKET);
  36.183 -
  36.184 -    TokenKind close = (kind == TOK_LBRACE)
  36.185 -                      ? TOK_RBRACE
  36.186 -                      : TOK_RBRACKET;
  36.187 -
  36.188 -    SourcePosition pos = scanner_.begin();
  36.189 -
  36.190 -    ExpressionList *list = new (pool_) ExpressionList();
  36.191 -    do {
  36.192 -        if (match(close))
  36.193 -            break;
  36.194 -
  36.195 -        Expression *expr = NULL;
  36.196 -        if (kind == TOK_LBRACE) {
  36.197 -            if (peek(TOK_LBRACE))
  36.198 -                expr = arrayLiteral(TOK_LBRACE);
  36.199 -            else
  36.200 -                expr = primitive();
  36.201 -        } else {
  36.202 -            expr = expression();
  36.203 -        }
  36.204 -        if (!expr)
  36.205 -            return NULL;
  36.206 -
  36.207 -        if (!list->append(expr))
  36.208 -            return NULL;
  36.209 -
  36.210 -        if (!match(TOK_COMMA)) {
  36.211 -            if (!expect(close))
  36.212 -                return NULL;
  36.213 -            break;
  36.214 -        }
  36.215 -    } while (true);
  36.216 -
  36.217 -    return new (pool_) ArrayLiteral(pos, kind, list);
  36.218 -}
  36.219 -
  36.220 -Expression *
  36.221 -Parser::prefix()
  36.222 -{
  36.223 -    switch (scanner_.peek()) {
  36.224 -      case TOK_LPAREN:
  36.225 -      {
  36.226 -        scanner_.scan();
  36.227 -        Expression *expr = expression();
  36.228 -        if (!expr)
  36.229 -            return NULL;
  36.230 -        if (!expect(TOK_RPAREN))
  36.231 -            return NULL;
  36.232 -        return expr;
  36.233 -      }
  36.234 -
  36.235 -      case TOK_NAME:
  36.236 -      {
  36.237 -        Local<String> name(zone_, expectName());
  36.238 -        if (!name)
  36.239 -            return NULL;
  36.240 -        return bind(name);
  36.241 -      }
  36.242 -
  36.243 -      default:
  36.244 -        return primitive();
  36.245 -    }
  36.246 -}
  36.247 -
  36.248 -Expression *
  36.249 -Parser::call(Expression *callee)
  36.250 -{
  36.251 -    ExpressionList *arguments = new (pool_) ExpressionList();
  36.252 -
  36.253 -    SourcePosition pos = scanner_.begin();
  36.254 -    expect(TOK_LPAREN);
  36.255 -    
  36.256 -    if (!match(TOK_RPAREN)) {
  36.257 -        while (true) {
  36.258 -            Expression *expr = expression();
  36.259 -            if (!expr)
  36.260 -                return NULL;
  36.261 -
  36.262 -            if (!arguments->append(expr))
  36.263 -                return NULL;
  36.264 -
  36.265 -            if (!match(TOK_COMMA))
  36.266 -                break;
  36.267 -        }
  36.268 -
  36.269 -        if (!expect(TOK_RPAREN))
  36.270 -            return NULL;
  36.271 -    }
  36.272 -
  36.273 -    return new (pool_) CallExpression(pos, callee, arguments);
  36.274 -}
  36.275 -
  36.276 -Expression *
  36.277 -Parser::index(Expression *left)
  36.278 -{
  36.279 -    expect(TOK_LBRACKET);
  36.280 -    
  36.281 -    SourcePosition pos = scanner_.begin();
  36.282 -    Expression *expr = expression();
  36.283 -    if (!expr)
  36.284 -        return NULL;
  36.285 -
  36.286 -    if (!expect(TOK_RBRACKET))
  36.287 -        return NULL;
  36.288 -
  36.289 -    return new (pool_) IndexExpression(pos, left, expr);
  36.290 -}
  36.291 -
  36.292 -Expression *
  36.293 -Parser::field(Expression *left)
  36.294 -{
  36.295 -    expect(TOK_DOT);
  36.296 -
  36.297 -    SourcePosition pos = scanner_.begin();
  36.298 -    Local<String> name(zone_, expectName());
  36.299 -    if (!name)
  36.300 -        return NULL;
  36.301 -
  36.302 -    return new (pool_) FieldExpression(pos, left, name);
  36.303 -}
  36.304 -
  36.305 -Expression *
  36.306 -Parser::primary()
  36.307 -{
  36.308 -    Expression *expr = prefix();
  36.309 -    if (!expr)
  36.310 -        return NULL;
  36.311 -
  36.312 -    for (;;) {
  36.313 -        switch (scanner_.peek()) {
  36.314 -          case TOK_LPAREN:
  36.315 -            if ((expr = call(expr)) == NULL)
  36.316 -                return NULL;
  36.317 -            break;
  36.318 -
  36.319 -          case TOK_LBRACKET:
  36.320 -            if ((expr = index(expr)) == NULL)
  36.321 -                return NULL;
  36.322 -            break;
  36.323 -
  36.324 -          case TOK_DOT:
  36.325 -            if ((expr = field(expr)) == NULL)
  36.326 -                return NULL;
  36.327 -            break;
  36.328 -
  36.329 -          default:
  36.330 -            return expr;
  36.331 -        }
  36.332 -    }
  36.333 -}
  36.334 -
  36.335 -Expression *
  36.336 -Parser::unary()
  36.337 -{
  36.338 -    TokenKind token = scanner_.peek();
  36.339 -
  36.340 -    SourcePosition pos = scanner_.begin();
  36.341 -    switch (token) {
  36.342 -      case TOK_INCREMENT:
  36.343 -      case TOK_DECREMENT:
  36.344 -      {
  36.345 -        scanner_.scan();
  36.346 -        Expression *expr = unary();
  36.347 -        if (!expr)
  36.348 -            return NULL;
  36.349 -        return new (pool_) IncDecExpression(pos, token, expr, false);
  36.350 -      }
  36.351 -
  36.352 -      case TOK_MINUS:
  36.353 -      case TOK_NOT:
  36.354 -      case TOK_TILDE:
  36.355 -      {
  36.356 -        scanner_.scan();
  36.357 -        Expression *expr = unary();
  36.358 -        if (!expr)
  36.359 -            return NULL;
  36.360 -        return new (pool_) UnaryExpression(pos, token, expr);
  36.361 -      }
  36.362 -
  36.363 -      case TOK_SIZEOF:
  36.364 -      {
  36.365 -        scanner_.scan();
  36.366 -        if (!expect(TOK_LPAREN))
  36.367 -            return NULL;
  36.368 -        Expression *expr = unary();
  36.369 -        if (!expr)
  36.370 -            return NULL;
  36.371 -        if (!expect(TOK_RPAREN))
  36.372 -            return NULL;
  36.373 -        return new (pool_) UnaryExpression(pos, token, expr);
  36.374 -      }
  36.375 -
  36.376 -      case TOK_LABEL:
  36.377 -      {
  36.378 -        scanner_.scan();
  36.379 -        Local<String> tag(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
  36.380 -        if (!tag)
  36.381 -            return NULL;
  36.382 -
  36.383 -        BoundName *type = NULL;
  36.384 -        if (tag)
  36.385 -            type = bindType(tag);
  36.386 -
  36.387 -        Expression *expr = unary();
  36.388 -        if (!expr)
  36.389 -            return NULL;
  36.390 -
  36.391 -        return new (pool_) UnaryExpression(pos, TOK_LABEL, expr, type);
  36.392 -      }
  36.393 -
  36.394 -      default:
  36.395 -        break;
  36.396 -    }
  36.397 -
  36.398 -    Expression *expr = primary();
  36.399 -
  36.400 -    token = scanner_.peek();
  36.401 -    if (token == TOK_INCREMENT || token == TOK_DECREMENT) {
  36.402 -        scanner_.scan();
  36.403 -        return new (pool_) IncDecExpression(pos, token, expr, true);
  36.404 -    }
  36.405 -
  36.406 -    return expr;
  36.407 -}
  36.408 -
  36.409 -Expression *
  36.410 -Parser::multiplication()
  36.411 -{
  36.412 -    Expression *left = unary();
  36.413 -    do {
  36.414 -        if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT))
  36.415 -            break;
  36.416 -        SourcePosition pos = scanner_.begin();
  36.417 -        TokenKind kind = scanner_.last();
  36.418 -        Expression *right = unary();
  36.419 -        if (!right)
  36.420 -            return NULL;
  36.421 -        left = new (pool_) BinaryExpression(pos, kind, left, right);
  36.422 -    } while (left);
  36.423 -    return left;
  36.424 -}
  36.425 -
  36.426 -Expression *
  36.427 -Parser::addition()
  36.428 -{
  36.429 -    Expression *left = multiplication();
  36.430 -    while (left) {
  36.431 -        if (!match(TOK_PLUS) && !match(TOK_MINUS))
  36.432 -            break;
  36.433 -        SourcePosition pos = scanner_.begin();
  36.434 -        TokenKind kind = scanner_.last();
  36.435 -        Expression *right = multiplication();
  36.436 -        if (!right)
  36.437 -            return NULL;
  36.438 -        left = new (pool_) BinaryExpression(pos, kind, left, right);
  36.439 -    }
  36.440 -    return left;
  36.441 -}
  36.442 -
  36.443 -Expression *
  36.444 -Parser::shift()
  36.445 -{
  36.446 -    Expression *left = addition();
  36.447 -    while (left) {
  36.448 -        if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR))
  36.449 -            break;
  36.450 -        SourcePosition pos = scanner_.begin();
  36.451 -        TokenKind kind = scanner_.last();
  36.452 -        Expression *right = addition();
  36.453 -        if (!right)
  36.454 -            return NULL;
  36.455 -        left = new (pool_) BinaryExpression(pos, kind, left, right);
  36.456 -    }
  36.457 -    return left;
  36.458 -}
  36.459 -
  36.460 -Expression *
  36.461 -Parser::bitand_()
  36.462 -{
  36.463 -    Expression *left = shift();
  36.464 -    while (left) {
  36.465 -        if (!match(TOK_BITAND))
  36.466 -            break;
  36.467 -        SourcePosition pos = scanner_.begin();
  36.468 -        Expression *right = shift();
  36.469 -        if (!right)
  36.470 -            return NULL;
  36.471 -        left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right);
  36.472 -    }
  36.473 -    return left;
  36.474 -}
  36.475 -
  36.476 -Expression *
  36.477 -Parser::bitxor()
  36.478 -{
  36.479 -    Expression *left = bitand_();
  36.480 -    while (left) {
  36.481 -        if (!match(TOK_BITXOR))
  36.482 -            break;
  36.483 -        SourcePosition pos = scanner_.begin();
  36.484 -        Expression *right = shift();
  36.485 -        if (!right)
  36.486 -            return NULL;
  36.487 -        left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right);
  36.488 -    }
  36.489 -    return left;
  36.490 -}
  36.491 -
  36.492 -Expression *
  36.493 -Parser::bitor_()
  36.494 -{
  36.495 -    Expression *left = bitxor();
  36.496 -    while (left) {
  36.497 -        if (!match(TOK_BITOR))
  36.498 -            break;
  36.499 -        SourcePosition pos = scanner_.begin();
  36.500 -        Expression *right = bitxor();
  36.501 -        if (!right)
  36.502 -            return NULL;
  36.503 -        left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right);
  36.504 -    }
  36.505 -    return left;
  36.506 -}
  36.507 -
  36.508 -Expression *
  36.509 -Parser::relational()
  36.510 -{
  36.511 -    Expression *left = bitor_();
  36.512 -    while (left) {
  36.513 -        TokenKind kind = scanner_.peek();
  36.514 -        if (kind < TOK_LT || kind > TOK_GE)
  36.515 -            break;
  36.516 -        scanner_.scan();
  36.517 -        SourcePosition pos = scanner_.begin();
  36.518 -        Expression *right = shift();
  36.519 -        if (!right)
  36.520 -            return NULL;
  36.521 -        left = new (pool_) BinaryExpression(pos, kind, left, right);
  36.522 -    }
  36.523 -    return left;
  36.524 -}
  36.525 -
  36.526 -Expression *
  36.527 -Parser::equals()
  36.528 -{
  36.529 -    Expression *left = relational();
  36.530 -    while (left) {
  36.531 -        if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS))
  36.532 -            break;
  36.533 -        TokenKind kind = scanner_.last();
  36.534 -        SourcePosition pos = scanner_.begin();
  36.535 -        Expression *right = relational();
  36.536 -        if (!right)
  36.537 -            return NULL;
  36.538 -        left = new (pool_) BinaryExpression(pos, kind, left, right);
  36.539 -    }
  36.540 -    return left;
  36.541 -}
  36.542 -
  36.543 -Expression *
  36.544 -Parser::and_()
  36.545 -{
  36.546 -    Expression *left = equals();
  36.547 -    while (left) {
  36.548 -        if (!match(TOK_AND))
  36.549 -            break;
  36.550 -        SourcePosition pos = scanner_.begin();
  36.551 -        Expression *right = equals();
  36.552 -        if (!right)
  36.553 -            return NULL;
  36.554 -        left = new (pool_) BinaryExpression(pos, TOK_AND, left, right);
  36.555 -    }
  36.556 -    return left;
  36.557 -}
  36.558 -
  36.559 -Expression *
  36.560 -Parser::or_()
  36.561 -{
  36.562 -    Expression *left = and_();
  36.563 -    while (left) {
  36.564 -        if (!match(TOK_OR))
  36.565 -            break;
  36.566 -        SourcePosition pos = scanner_.begin();
  36.567 -        Expression *right = and_();
  36.568 -        if (!right)
  36.569 -            return NULL;
  36.570 -        left = new (pool_) BinaryExpression(pos, TOK_OR, left, right);
  36.571 -    }
  36.572 -    return left;
  36.573 -}
  36.574 -
  36.575 -Expression *
  36.576 -Parser::ternary()
  36.577 -{
  36.578 -    Expression *cond = or_();
  36.579 -    if (!cond)
  36.580 -        return NULL;
  36.581 -    
  36.582 -    if (!match(TOK_QMARK))
  36.583 -        return cond;
  36.584 -
  36.585 -    Expression *left;
  36.586 -    SourcePosition pos = scanner_.begin();
  36.587 -    AutoAllowTags<false> disableTags(scanner_);
  36.588 -    {
  36.589 -        if ((left = expression()) == NULL)
  36.590 -            return NULL;
  36.591 -    }
  36.592 -
  36.593 -    if (!expect(TOK_COLON))
  36.594 -        return NULL;
  36.595 -
  36.596 -    Expression *right = expression();
  36.597 -    if (!right)
  36.598 -        return NULL;
  36.599 -
  36.600 -    return new (pool_) TernaryExpression(pos, cond, left, right);
  36.601 -}
  36.602 -
  36.603 -Expression *
  36.604 -Parser::assignment()
  36.605 -{
  36.606 -    Expression *left = ternary();
  36.607 -    while (left) {
  36.608 -        TokenKind token = scanner_.peek();
  36.609 -        if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL))
  36.610 -            break;
  36.611 -        scanner_.scan();
  36.612 -        SourcePosition pos = scanner_.begin();
  36.613 -        Expression *expr = ternary();
  36.614 -        if (!expr)
  36.615 -            return NULL;
  36.616 -
  36.617 -        left = new (pool_) Assignment(pos, token, left, expr);
  36.618 -    }
  36.619 -    return left;
  36.620 -}
  36.621 -
  36.622 -Expression *
  36.623 -Parser::expression()
  36.624 -{
  36.625 -    return assignment();
  36.626 -}
  36.627 -
  36.628 -Statement *
  36.629 -Parser::while_()
  36.630 -{
  36.631 -    SourcePosition pos = scanner_.begin();
  36.632 -    scanner_.scan();
  36.633 -
  36.634 -    if (!expect(TOK_LPAREN))
  36.635 -        return NULL;
  36.636 -
  36.637 -    Expression *condition = expression();
  36.638 -    if (!condition)
  36.639 -        return NULL;
  36.640 -
  36.641 -    if (!expect(TOK_RPAREN))
  36.642 -        return NULL;
  36.643 -
  36.644 -    // Inside a loop, we force the creation of a scope object. Normally, we
  36.645 -    // will cull scopes if they have no variables. However inside a loop,
  36.646 -    // function calls that take references may compute a LIFO object, and to
  36.647 -    // avoid temporarily leaking many such objects, we ensure that a scope
  36.648 -    // is present so a LIFO slot can be allocated.
  36.649 -    if (!enterScope(Scope::BLOCK))
  36.650 -        return NULL;
  36.651 -
  36.652 -    Statement *body;
  36.653 -    if (scanner_.peek() == TOK_LBRACE)
  36.654 -        body = block(scope_);
  36.655 -    else
  36.656 -        body = localStatement();
  36.657 -    if (!body)
  36.658 -        return NULL;
  36.659 -
  36.660 -    scope_ = scope_->enclosing();
  36.661 -    return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body);
  36.662 -}
  36.663 -
  36.664 -Statement *
  36.665 -Parser::do_()
  36.666 -{
  36.667 -    SourcePosition pos = scanner_.begin();
  36.668 -    scanner_.scan();
  36.669 -
  36.670 -    // See the comment in ::while_() as to why we force a scope.
  36.671 -    if (!enterScope(Scope::BLOCK))
  36.672 -        return NULL;
  36.673 -
  36.674 -    Statement *body;
  36.675 -    if (scanner_.peek() == TOK_LBRACE)
  36.676 -        body = block(scope_);
  36.677 -    else
  36.678 -        body = localStatement();
  36.679 -    if (!body)
  36.680 -        return NULL;
  36.681 -
  36.682 -    scope_ = scope_->enclosing();
  36.683 -
  36.684 -    if (!expect(TOK_WHILE))
  36.685 -        return NULL;
  36.686 -
  36.687 -    if (!expect(TOK_LPAREN))
  36.688 -        return NULL;
  36.689 -    Expression *condition = expression();
  36.690 -    if (!condition)
  36.691 -        return NULL;
  36.692 -    if (!expect(TOK_RPAREN))
  36.693 -        return NULL;
  36.694 -
  36.695 -    return new (pool_) WhileStatement(pos, TOK_DO, condition, body);
  36.696 -}
  36.697 -
  36.698 -Statement *
  36.699 -Parser::switch_()
  36.700 -{
  36.701 -    expect(TOK_SWITCH);
  36.702 -
  36.703 -    SourcePosition pos = scanner_.begin();
  36.704 -
  36.705 -    if (!expect(TOK_LPAREN))
  36.706 -        return NULL;
  36.707 -    Expression *expr = expression();
  36.708 -    if (!expr)
  36.709 -        return NULL;
  36.710 -    if (!expect(TOK_RPAREN))
  36.711 -        return NULL;
  36.712 -
  36.713 -    if (!expect(TOK_LBRACE))
  36.714 -        return NULL;
  36.715 -
  36.716 -    SourcePosition defaultPos;
  36.717 -    PoolList<Case *> *cases = new (pool_) PoolList<Case *>();
  36.718 -
  36.719 -    Statement *defaultCase = NULL;
  36.720 -
  36.721 -    while (!peek(TOK_RBRACE)) {
  36.722 -        Expression *expr = NULL;
  36.723 -        ExpressionList *others = NULL;
  36.724 -        if (match(TOK_DEFAULT)) {
  36.725 -            if (defaultCase) {
  36.726 -                cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch);
  36.727 -                return NULL;
  36.728 -            }
  36.729 -
  36.730 -            defaultPos = scanner_.begin();
  36.731 -        } else {
  36.732 -            if (defaultCase) {
  36.733 -                cc_.reportError(defaultPos, Message_DefaultMustBeLastCase);
  36.734 -                return NULL;
  36.735 -            }
  36.736 -
  36.737 -            if (!expect(TOK_CASE))
  36.738 -                return NULL;
  36.739 -
  36.740 -            // A limitation in the grammar is that |case <NAME>:| will be
  36.741 -            // detected as a label.
  36.742 -            AutoAllowTags<false> disableTags(scanner_);
  36.743 -
  36.744 -            if ((expr = expression()) == NULL)
  36.745 -                return NULL;
  36.746 -
  36.747 -            if (peek(TOK_COMMA)) {
  36.748 -                others = new (pool_) ExpressionList();
  36.749 -                while (match(TOK_COMMA)) {
  36.750 -                    Expression *other = expression();
  36.751 -                    if (!other)
  36.752 -                        return NULL;
  36.753 -                    if (!others->append(other))
  36.754 -                        return NULL;
  36.755 -                }
  36.756 -            }
  36.757 -        }
  36.758 -
  36.759 -        if (!expect(TOK_COLON))
  36.760 -            return NULL;
  36.761 -
  36.762 -        Statement *statement = localStatement();
  36.763 -        if (!statement)
  36.764 -            return NULL;
  36.765 -
  36.766 -        if (!peek(TOK_CASE) &&
  36.767 -            !peek(TOK_DEFAULT) &&
  36.768 -            !peek(TOK_RBRACE))
  36.769 -        {
  36.770 -            cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase);
  36.771 -            return NULL;
  36.772 -        }
  36.773 -
  36.774 -        if (expr) {
  36.775 -            Case *caze = new (pool_) Case(expr, others, statement);
  36.776 -            if (!cases->append(caze))
  36.777 -                return NULL;
  36.778 -        } else {
  36.779 -            defaultCase = statement;
  36.780 -        }
  36.781 -    }
  36.782 -
  36.783 -    if (!expect(TOK_RBRACE))
  36.784 -        return NULL;
  36.785 -
  36.786 -    return new (pool_) SwitchStatement(pos, expr, cases, defaultCase);
  36.787 -}
  36.788 -
  36.789 -Statement *
  36.790 -Parser::forStatement()
  36.791 -{
  36.792 -    SourcePosition pos = scanner_.begin();
  36.793 -    scanner_.scan();
  36.794 -    if (!expect(TOK_LPAREN))
  36.795 -        return NULL;
  36.796 -
  36.797 -    Statement *decl = NULL;
  36.798 -    if (!match(TOK_SEMICOLON)) {
  36.799 -        if (match(TOK_NEW)) {
  36.800 -            if (!enterScope(Scope::BLOCK))
  36.801 -                return NULL;
  36.802 -            if ((decl = vars(TOK_STOCK, TOK_NEW)) == NULL)
  36.803 -                return NULL;
  36.804 -        } else {
  36.805 -            if ((decl = expressionStatement()) == NULL)
  36.806 -                return NULL;
  36.807 -        }
  36.808 -        if (!expect(TOK_SEMICOLON))
  36.809 -            return NULL;
  36.810 -    }
  36.811 -
  36.812 -    Expression *condition = NULL;
  36.813 -    if (!match(TOK_SEMICOLON)) {
  36.814 -        if ((condition = expression()) == NULL)
  36.815 -            return NULL;
  36.816 -        if (!expect(TOK_SEMICOLON))
  36.817 -            return NULL;
  36.818 -    }
  36.819 -
  36.820 -    Statement *update = NULL;
  36.821 -    if (!match(TOK_RPAREN)) {
  36.822 -        if ((update = expressionStatement()) == NULL)
  36.823 -            return NULL;
  36.824 -        if (!expect(TOK_RPAREN))
  36.825 -            return NULL;
  36.826 -    }
  36.827 -
  36.828 -    // See the comment in ::while_() as to why we force a scope.
  36.829 -    if (!enterScope(Scope::BLOCK))
  36.830 -        return NULL;
  36.831 -
  36.832 -    Statement *body;
  36.833 -    if (scanner_.peek() == TOK_LBRACE)
  36.834 -        body = block(scope_);
  36.835 -    else
  36.836 -        body = localStatement();
  36.837 -    if (!body)
  36.838 -        return NULL;
  36.839 -
  36.840 -    scope_ = scope_->enclosing();
  36.841 -
  36.842 -    Scope *declScope = NULL;
  36.843 -    if (decl && (decl->isVariableDeclaration() || decl->isBlockStatement())) {
  36.844 -        declScope = scope_->unlinkIfEmpty();
  36.845 -        scope_ = scope_->enclosing();
  36.846 -    }
  36.847 -    return new (pool_) ForStatement(pos, declScope, decl, condition, update, body);
  36.848 -}
  36.849 -
  36.850 -ExpressionList *
  36.851 -Parser::dimensions()
  36.852 -{
  36.853 -    ExpressionList *postDimensions = new (pool_) ExpressionList();
  36.854 -    while (match(TOK_LBRACKET)) {
  36.855 -        Expression *dim = NULL;
  36.856 -        if (!match(TOK_RBRACKET)) {
  36.857 -            if ((dim = expression()) == NULL)
  36.858 -                return NULL;
  36.859 -            if (!expect(TOK_RBRACKET))
  36.860 -                return NULL;
  36.861 -        }
  36.862 -
  36.863 -        if (!postDimensions->append(dim))
  36.864 -            return NULL;
  36.865 -    }
  36.866 -    return postDimensions;
  36.867 -}
  36.868 -
  36.869 -VariableDeclaration *
  36.870 -Parser::var(TokenKind scope, TokenKind kind)
  36.871 -{
  36.872 -    Local<String> tag(zone_);
  36.873 -    if (matchName(tag.ref(), TOK_LABEL) && !tag)
  36.874 -        return NULL;
  36.875 -
  36.876 -    BoundName *type = NULL;
  36.877 -    if (tag)
  36.878 -        type = bindType(tag);
  36.879 -
  36.880 -    Local<String> name(zone_, expectName());
  36.881 -    if (!name)
  36.882 -        return NULL;
  36.883 -
  36.884 -    SourcePosition pos = scanner_.begin();
  36.885 -
  36.886 -    if (BoundName *other = scope_->localLookup(name)) {
  36.887 -        redeclarationError(other);
  36.888 -        return NULL;
  36.889 -    }
  36.890 -
  36.891 -    ExpressionList *postDimensions = NULL;
  36.892 -    if (peek(TOK_LBRACKET)) {
  36.893 -        if ((postDimensions = dimensions()) == NULL)
  36.894 -            return NULL;
  36.895 -    }
  36.896 -    
  36.897 -    Expression *expr = NULL;
  36.898 -    if (match(TOK_ASSIGN)) {
  36.899 -        switch (scanner_.peek()) {
  36.900 -          // Note: we don't support [] literals yet.
  36.901 -          case TOK_LBRACE:
  36.902 -            if ((expr = arrayLiteral(scanner_.scan())) == NULL)
  36.903 -                return NULL;
  36.904 -            break;
  36.905 -
  36.906 -          default:
  36.907 -            if ((expr = expression()) == NULL)
  36.908 -                return NULL;
  36.909 -            break;
  36.910 -        }
  36.911 -    }
  36.912 -
  36.913 -    Variable *var = scope_->declareVariable(name, pos);
  36.914 -    if (!var)
  36.915 -        return NULL;
  36.916 -
  36.917 -    if (scope == TOK_PUBLIC)
  36.918 -        var->setPublic();
  36.919 -
  36.920 -    return new (pool_) VariableDeclaration(var->pos(), kind, var, type, postDimensions, expr);
  36.921 -}
  36.922 -
  36.923 -Statement *
  36.924 -Parser::vars(TokenKind scope, TokenKind kind)
  36.925 -{
  36.926 -    VariableDeclaration *decl = var(scope, kind);
  36.927 -    if (!decl)
  36.928 -        return NULL;
  36.929 -
  36.930 -    if (!peek(TOK_COMMA))
  36.931 -        return decl;
  36.932 -
  36.933 -    StatementList *statements = new (pool_) StatementList();
  36.934 -    if (!statements->append(decl))
  36.935 -        return NULL;
  36.936 -
  36.937 -    while (match(TOK_COMMA)) {
  36.938 -        Statement *decl = var(scope, kind);
  36.939 -        if (!decl)
  36.940 -            return NULL;
  36.941 -        if (!statements->append(decl))
  36.942 -            return NULL;
  36.943 -    }
  36.944 -
  36.945 -    // Create a fake-o block with no scope to create a statement list.
  36.946 -    return new (pool_) BlockStatement(decl->pos(), NULL, statements);
  36.947 -}
  36.948 -
  36.949 -Statement *
  36.950 -Parser::returnStatement()
  36.951 -{
  36.952 -    SourcePosition pos = scanner_.begin();
  36.953 -    if (!expect(TOK_RETURN))
  36.954 -        return NULL;
  36.955 -
  36.956 -    Expression *expr = NULL;
  36.957 -    if (scanner_.peek() != TOK_SEMICOLON) {
  36.958 -        if ((expr = expression()) == NULL)
  36.959 -            return NULL;
  36.960 -
  36.961 -        // We only care about non-void returns when determining whether a
  36.962 -        // tagless function is non-void.
  36.963 -        encounteredReturn_ = true;
  36.964 -    }
  36.965 -
  36.966 -    return new (pool_) ReturnStatement(pos, expr);
  36.967 -}
  36.968 -
  36.969 -Statement *
  36.970 -Parser::expressionStatement()
  36.971 -{
  36.972 -    Expression *left = assignment();
  36.973 -    if (!left)
  36.974 -        return NULL;
  36.975 -
  36.976 -    return new (pool_) ExpressionStatement(left);
  36.977 -}
  36.978 -
  36.979 -Statement *
  36.980 -Parser::block(Scope *scope)
  36.981 -{
  36.982 -    if (!expect(TOK_LBRACE))
  36.983 -        return NULL;
  36.984 -
  36.985 -    SourcePosition pos = scanner_.begin();
  36.986 -    if (!scope && !enterScope(Scope::BLOCK))
  36.987 -        return NULL;
  36.988 -
  36.989 -    StatementList *statements = new (pool_) StatementList();
  36.990 -    while (!match(TOK_RBRACE)) {
  36.991 -        Statement *statement = localStatement();
  36.992 -        if (statement == NULL)
  36.993 -            return NULL;
  36.994 -        if (!statements->append(statement))
  36.995 -            return NULL;
  36.996 -    }
  36.997 -
  36.998 -    if (!scope) {
  36.999 -    	scope = scope_->unlinkIfEmpty();
 36.1000 -        scope_ = scope_->enclosing();
 36.1001 -    }
 36.1002 -    BlockStatement *block = new (pool_) BlockStatement(pos, scope, statements);
 36.1003 -    return block;
 36.1004 -}
 36.1005 -
 36.1006 -Statement *
 36.1007 -Parser::if_()
 36.1008 -{
 36.1009 -    expect(TOK_IF);
 36.1010 -    
 36.1011 -    SourcePosition pos = scanner_.begin();
 36.1012 -    if (!expect(TOK_LPAREN))
 36.1013 -        return NULL;
 36.1014 -
 36.1015 -    Expression *cond = expression();
 36.1016 -    if (!cond)
 36.1017 -        return NULL;
 36.1018 -
 36.1019 -    if (!expect(TOK_RPAREN))
 36.1020 -        return NULL;
 36.1021 -
 36.1022 -    Statement *ifTrue = localStatement();
 36.1023 -    if (!ifTrue)
 36.1024 -        return NULL;
 36.1025 -
 36.1026 -    IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue);
 36.1027 -
 36.1028 -    IfStatement *last = outer;
 36.1029 -    while (match(TOK_ELSE)) {
 36.1030 -        if (!match(TOK_IF)) {
 36.1031 -            Statement *ifFalse = localStatement();
 36.1032 -            if (!ifFalse)
 36.1033 -                return NULL;
 36.1034 -
 36.1035 -            last->setIfFalse(ifFalse);
 36.1036 -            break;
 36.1037 -        }
 36.1038 -
 36.1039 -        SourcePosition pos = scanner_.begin();
 36.1040 -        if (!expect(TOK_LPAREN))
 36.1041 -            return NULL;
 36.1042 -
 36.1043 -        Expression *otherCond = expression();
 36.1044 -        if (!otherCond)
 36.1045 -            return NULL;
 36.1046 -
 36.1047 -        if (!expect(TOK_RPAREN))
 36.1048 -            return NULL;
 36.1049 -
 36.1050 -        Statement *otherIfTrue = localStatement();
 36.1051 -        if (!otherIfTrue)
 36.1052 -            return NULL;
 36.1053 -
 36.1054 -        IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue);
 36.1055 -        last->setIfFalse(inner);
 36.1056 -        last = inner;
 36.1057 -    }
 36.1058 -
 36.1059 -    return outer;
 36.1060 -}
 36.1061 -
 36.1062 -Statement *
 36.1063 -Parser::localStatement()
 36.1064 -{
 36.1065 -    Statement *statement = NULL;
 36.1066 -
 36.1067 -    // Statements which must be followed by a semicolon will break out of the
 36.1068 -    // switch. If they may end in BlockStatements, they'll immediately return.
 36.1069 -
 36.1070 -    TokenKind kind = scanner_.peek();
 36.1071 -    switch (kind) {
 36.1072 -      case TOK_CONST:
 36.1073 -      case TOK_NEW:
 36.1074 -        scanner_.scan();
 36.1075 -        if ((statement = vars(TOK_STOCK, kind)) == NULL)
 36.1076 -          return NULL;
 36.1077 -        break;
 36.1078 -
 36.1079 -      case TOK_FOR:
 36.1080 -        return forStatement();
 36.1081 -
 36.1082 -      case TOK_WHILE:
 36.1083 -        return while_();
 36.1084 -
 36.1085 -      case TOK_BREAK:
 36.1086 -        scanner_.scan();
 36.1087 -        statement = new (pool_) BreakStatement(scanner_.begin());
 36.1088 -        break;
 36.1089 -
 36.1090 -      case TOK_CONTINUE:
 36.1091 -        scanner_.scan();
 36.1092 -        statement = new (pool_) ContinueStatement(scanner_.begin());
 36.1093 -        break;
 36.1094 -
 36.1095 -      case TOK_DO:
 36.1096 -        if ((statement = do_()) == NULL)
 36.1097 -            return NULL;
 36.1098 -        break;
 36.1099 -
 36.1100 -      case TOK_RETURN:
 36.1101 -        if ((statement = returnStatement()) == NULL)
 36.1102 -          return NULL;
 36.1103 -        break;
 36.1104 -
 36.1105 -      case TOK_ENUM:
 36.1106 -        if ((statement = enum_()) == NULL)
 36.1107 -          return NULL;
 36.1108 -        break;
 36.1109 -
 36.1110 -      case TOK_STRUCT:
 36.1111 -        if ((statement = struct_()) == NULL)
 36.1112 -          return NULL;
 36.1113 -        break;
 36.1114 -
 36.1115 -      case TOK_SWITCH:
 36.1116 -        return switch_();
 36.1117 -
 36.1118 -      case TOK_IF:
 36.1119 -        return if_();
 36.1120 -
 36.1121 -      case TOK_LBRACE:
 36.1122 -        return block();
 36.1123 -
 36.1124 -      default:
 36.1125 -        break;
 36.1126 -    }
 36.1127 -
 36.1128 -    if (!statement) {
 36.1129 -        if ((statement = expressionStatement()) == NULL)
 36.1130 -            return NULL;
 36.1131 -    }
 36.1132 -
 36.1133 -    if (!expect(TOK_SEMICOLON))
 36.1134 -        return NULL;
 36.1135 -
 36.1136 -    return statement;
 36.1137 -}
 36.1138 -
 36.1139 -Statement *
 36.1140 -Parser::struct_()
 36.1141 -{
 36.1142 -    expect(TOK_STRUCT);
 36.1143 -
 36.1144 -    Local<String> name(zone_, expectName());
 36.1145 -    if (!name)
 36.1146 -        return NULL;
 36.1147 -
 36.1148 -    SourcePosition pos = scanner_.begin();
 36.1149 -
 36.1150 -    if (BoundName *other = scope_->localLookup(name)) {
 36.1151 -        redeclarationError(other);
 36.1152 -        return NULL;
 36.1153 -    }
 36.1154 -
 36.1155 -    NamedType *type;
 36.1156 -    if ((type = scope_->declareType(name, scanner_.begin())) == NULL)
 36.1157 -        return NULL;
 36.1158 -
 36.1159 -    if (!expect(TOK_LBRACE))
 36.1160 -        return NULL;
 36.1161 -
 36.1162 -    FieldList *fields = new (pool_) FieldList();
 36.1163 -
 36.1164 -    while (!peek(TOK_RBRACE)) {
 36.1165 -        if (matchName(name.ref(), TOK_LABEL) && !name)
 36.1166 -            return NULL;
 36.1167 -
 36.1168 -        BoundName *type = NULL;
 36.1169 -        if (name) {
 36.1170 -            if ((type = bindType(name)) == NULL)
 36.1171 -                return NULL;
 36.1172 -        }
 36.1173 -
 36.1174 -        name = expectName();
 36.1175 -        if (!name)
 36.1176 -            return NULL;
 36.1177 -
 36.1178 -        SourcePosition pos = scanner_.begin();
 36.1179 -
 36.1180 -        ExpressionList *postDimensions = NULL;
 36.1181 -        if (peek(TOK_LBRACKET)) {
 36.1182 -            if ((postDimensions = dimensions()) == NULL)
 36.1183 -                return NULL;
 36.1184 -        }
 36.1185 -
 36.1186 -        if (!matchSemicolon())
 36.1187 -            return NULL;
 36.1188 -
 36.1189 -        StructureStatement::Field *field =
 36.1190 -            new (pool_) StructureStatement::Field(pos, type, name, postDimensions);
 36.1191 -        if (!field || !fields->append(field))
 36.1192 -            return NULL;
 36.1193 -    }
 36.1194 -
 36.1195 -    if (!expect(TOK_RBRACE))
 36.1196 -        return NULL;
 36.1197 -
 36.1198 -    if (fields->empty()) {
 36.1199 -        cc_.reportError(pos, Message_StructCantBeEmpty);
 36.1200 -        return NULL;
 36.1201 -    }
 36.1202 -
 36.1203 -    return new (pool_) StructureStatement(pos, type, fields);
 36.1204 -}
 36.1205 -
 36.1206 -Statement *
 36.1207 -Parser::enum_()
 36.1208 -{
 36.1209 -    expect(TOK_ENUM);
 36.1210 -
 36.1211 -    NamedType *type = NULL;
 36.1212 -    SourcePosition pos = scanner_.begin();
 36.1213 -
 36.1214 -    Local<String> name(zone_);
 36.1215 -    if (matchName(name.ref())) {
 36.1216 -        if (!name)
 36.1217 -            return NULL;
 36.1218 -
 36.1219 -        if (BoundName *other = scope_->localLookup(name)) {
 36.1220 -            redeclarationError(other);
 36.1221 -            return NULL;
 36.1222 -        }
 36.1223 -
 36.1224 -        if ((type = scope_->declareType(name, scanner_.begin())) == NULL)
 36.1225 -            return NULL;
 36.1226 -    }
 36.1227 -
 36.1228 -    EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList();
 36.1229 -
 36.1230 -    if (!expect(TOK_LBRACE))
 36.1231 -        return NULL;
 36.1232 -
 36.1233 -    do {
 36.1234 -        if (scanner_.peek() == TOK_RBRACE)
 36.1235 -            break;
 36.1236 -
 36.1237 -        Local<String> name(zone_, expectName());
 36.1238 -        if (!name)
 36.1239 -            return NULL;
 36.1240 -
 36.1241 -        if (BoundName *other = scope_->localLookup(name)) {
 36.1242 -            redeclarationError(other);
 36.1243 -            return NULL;
 36.1244 -        }
 36.1245 -
 36.1246 -        NamedConstant *constant = scope_->declareConstant(name, scanner_.begin());
 36.1247 -        if (!constant)
 36.1248 -            return NULL;
 36.1249 -
 36.1250 -        Expression *expr = NULL;
 36.1251 -        if (match(TOK_ASSIGN)) {
 36.1252 -            if ((expr = expression()) == NULL)
 36.1253 -                return NULL;
 36.1254 -        }
 36.1255 -
 36.1256 -        if (!entries->append(EnumStatement::Entry(constant, expr)))
 36.1257 -            return NULL;
 36.1258 -    } while (match(TOK_COMMA));
 36.1259 -    if (!expect(TOK_RBRACE))
 36.1260 -        return NULL;
 36.1261 -
 36.1262 -    return new (pool_) EnumStatement(pos, type, name, entries);
 36.1263 -}
 36.1264 -
 36.1265 -Statement *
 36.1266 -Parser::function(TokenKind token)
 36.1267 -{
 36.1268 -    Local<String> returnTag(zone_);
 36.1269 -    if (token == TOK_LABEL) {
 36.1270 -        returnTag = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
 36.1271 -        if (!returnTag)
 36.1272 -            return NULL;
 36.1273 -
 36.1274 -        token = TOK_STOCK;
 36.1275 -    } else {
 36.1276 -        if (peek(TOK_LABEL)) {
 36.1277 -            if (matchName(returnTag.ref(), TOK_LABEL) && !returnTag)
 36.1278 -                return NULL;
 36.1279 -        } else if (peek(TOK_NAME)) {
 36.1280 -            // Peek for a type that has no :
 36.1281 -            returnTag = expectName();
 36.1282 -            if (!returnTag)
 36.1283 -                return NULL;
 36.1284 -        }
 36.1285 -    }
 36.1286 -
 36.1287 -    Local<String> name(zone_);
 36.1288 -    ExpressionList *returnDimensions = NULL;
 36.1289 -
 36.1290 -    bool allowArrayReturns = token != TOK_NATIVE &&
 36.1291 -                             token != TOK_PUBLIC &&
 36.1292 -                             token != TOK_FORWARD;
 36.1293 -
 36.1294 -    if (allowArrayReturns && peek(TOK_LBRACKET)) {
 36.1295 -        if ((returnDimensions = dimensions()) == NULL)
 36.1296 -            return NULL;
 36.1297 -        if ((name = expectName()) == NULL)
 36.1298 -            return NULL;
 36.1299 -    } else if (peek(TOK_NAME)) {
 36.1300 -        if ((name = expectName()) == NULL)
 36.1301 -            return NULL;
 36.1302 -    } else {
 36.1303 -        // We predicted |type name|, but just got |name| instead.
 36.1304 -        name = returnTag;
 36.1305 -        returnTag = NULL;
 36.1306 -    }
 36.1307 -
 36.1308 -    BoundName *returnType = NULL;
 36.1309 -    if (returnTag)
 36.1310 -        returnType = bindType(returnTag);
 36.1311 -
 36.1312 -    SourcePosition pos = scanner_.begin();
 36.1313 -
 36.1314 -    // The function name goes into the outer (global) scope.
 36.1315 -    assert(!scope_->enclosing());
 36.1316 -
 36.1317 -    NamedType *type = NULL;
 36.1318 -    NamedFunction *fun = NULL;
 36.1319 -    if (BoundName *other = scope_->localLookup(name)) {
 36.1320 -        // We allow a redeclaration if the new type is a public, and the old
 36.1321 -        // type was a forward. However, the forward must come first.
 36.1322 -        if (token == TOK_TYPEDEF || other->kind() != BoundName::FUNCTION) {
 36.1323 -            redeclarationError(other);
 36.1324 -            return NULL;
 36.1325 -        }
 36.1326 -
 36.1327 -        fun = other->toNamedFunction();
 36.1328 -        if (!fun->isForward() || token != TOK_PUBLIC) {
 36.1329 -            redeclarationError(other);
 36.1330 -            return NULL;
 36.1331 -        }
 36.1332 -        
 36.1333 -        // We've got the same name, but the original is a forward, so let it
 36.1334 -        // slide and re-use the original declaration.
 36.1335 -        fun->setImplemented(scanner_.begin());
 36.1336 -    } else if (token == TOK_TYPEDEF) {
 36.1337 -        type = scope_->declareType(name, scanner_.begin());
 36.1338 -        if (!type)
 36.1339 -            return NULL;
 36.1340 -    } else {
 36.1341 -        fun = scope_->declareFunction(name, scanner_.begin(), token);
 36.1342 -        if (!fun)
 36.1343 -            return NULL;
 36.1344 -    }
 36.1345 -
 36.1346 -    if (fun && fun->isPublic())
 36.1347 -        fun->setUsed();
 36.1348 -
 36.1349 -    Scope *scope = enterScope(Scope::FUNCTION);
 36.1350 -    if (!scope)
 36.1351 -        return NULL;
 36.1352 -
 36.1353 -    ParameterList *parameters = new (pool_) ParameterList();
 36.1354 -
 36.1355 -    if (!expect(TOK_LPAREN))
 36.1356 -        return NULL;
 36.1357 -
 36.1358 -    if (!match(TOK_RPAREN)) {
 36.1359 -        while (true) {
 36.1360 -            bool isConst = match(TOK_CONST);
 36.1361 -            bool ref = match(TOK_AMPERSAND);
 36.1362 -
 36.1363 -            SourcePosition begin = scanner_.begin();
 36.1364 -            Local<String> tag(zone_);
 36.1365 -            if (matchName(tag.ref(), TOK_LABEL) && !tag)
 36.1366 -                return NULL;
 36.1367 -
 36.1368 -            BoundName *type = NULL;
 36.1369 -            if (tag)
 36.1370 -                type = bindType(tag);
 36.1371 -
 36.1372 -            if (match(TOK_ELLIPSES)) {
 36.1373 -                if (isConst || ref) {
 36.1374 -                    cc_.reportError(begin, Message_InvalidVarArgs);
 36.1375 -                    return NULL;
 36.1376 -                }
 36.1377 -
 36.1378 -                if (token != TOK_NATIVE) {
 36.1379 -                    cc_.reportError(begin, Message_VarArgsOutsideNative);
 36.1380 -                    return NULL;
 36.1381 -                }
 36.1382 -
 36.1383 -                fun->markNativeVariadic();
 36.1384 -                break;
 36.1385 -            }
 36.1386 -
 36.1387 -            Local<String> name(zone_, expectName());
 36.1388 -            if (!name)
 36.1389 -                return NULL;
 36.1390 -
 36.1391 -            if (BoundName *other = scope_->localLookup(name)) {
 36.1392 -                redeclarationError(other);
 36.1393 -                return NULL;
 36.1394 -            }
 36.1395 -            Variable *arg = scope_->declareArgument(name, scanner_.begin());
 36.1396 -            if (!arg)
 36.1397 -                return NULL;
 36.1398 -
 36.1399 -            // Look for dimensions.
 36.1400 -            ExpressionList *postDimensions = NULL;
 36.1401 -            if (peek(TOK_LBRACKET)) {
 36.1402 -                if ((postDimensions = dimensions()) == NULL)
 36.1403 -                    return NULL;
 36.1404 -            }
 36.1405 -
 36.1406 -            Expression *expr = NULL;
 36.1407 -            if (match(TOK_ASSIGN)) {
 36.1408 -                if ((expr = expression()) == NULL)
 36.1409 -                    return NULL;
 36.1410 -            }
 36.1411 -
 36.1412 -            Parameter *parameter = new (pool_) Parameter(arg, type, ref, isConst, postDimensions,
 36.1413 -                                                         expr);
 36.1414 -            if (!parameters->append(parameter))
 36.1415 -                return NULL;
 36.1416 -
 36.1417 -            if (!match(TOK_COMMA))
 36.1418 -                break;
 36.1419 -        }
 36.1420 -        if (!expect(TOK_RPAREN))
 36.1421 -            return NULL;
 36.1422 -    }
 36.1423 -
 36.1424 -    encounteredReturn_ = false;
 36.1425 -
 36.1426 -    Statement *body = NULL;
 36.1427 -    if (token != TOK_FORWARD && token != TOK_NATIVE && token != TOK_TYPEDEF) {
 36.1428 -        body = block();
 36.1429 -        if (!body)
 36.1430 -            return NULL;
 36.1431 -    }
 36.1432 -
 36.1433 -    scope_ = scope_->enclosing();
 36.1434 -
 36.1435 -    FunctionSignature signature(returnType, returnDimensions, parameters);
 36.1436 -    if (token == TOK_TYPEDEF)
 36.1437 -        return new (pool_) FunctionTypeStatement(pos, type, signature);
 36.1438 -
 36.1439 -    return new (pool_) FunctionStatement(pos, scope, fun, body, signature, encounteredReturn_);
 36.1440 -}
 36.1441 -
 36.1442 -static inline bool
 36.1443 -DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, Handle<Type> type)
 36.1444 -{
 36.1445 -    Local<String> tag(zone, zone->makeSymbol(name));
 36.1446 -    if (!tag)
 36.1447 -        return false;
 36.1448 -
 36.1449 -    return !!scope->declareType(tag, type);
 36.1450 -}
 36.1451 -
 36.1452 -static inline bool
 36.1453 -DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, PrimitiveType type)
 36.1454 -{
 36.1455 -    Local<Type> primitive(zone, zone->types()->getPrimitive(type));
 36.1456 -    assert(primitive);
 36.1457 -    return DeclareIntrinsicType(zone, scope, name, primitive);
 36.1458 -}
 36.1459 -
 36.1460 -bool
 36.1461 -Parser::setupIntrinsics()
 36.1462 -{
 36.1463 -    if (!DeclareIntrinsicType(zone_, scope_, "Float", PrimitiveType_Float))
 36.1464 -        return false;
 36.1465 -    if (!DeclareIntrinsicType(zone_, scope_, "_", PrimitiveType_Int32))
 36.1466 -        return false;
 36.1467 -    if (!DeclareIntrinsicType(zone_, scope_, "bool", PrimitiveType_Bool))
 36.1468 -        return false;
 36.1469 -    if (!DeclareIntrinsicType(zone_, scope_, "String", PrimitiveType_Char))
 36.1470 -        return false;
 36.1471 -
 36.1472 -    Local<Type> unchecked(zone_, zone_->types()->getUnchecked());
 36.1473 -    if (!DeclareIntrinsicType(zone_, scope_, "unchecked", unchecked))
 36.1474 -        return false;
 36.1475 -
 36.1476 -    Local<Type> voidType(zone_, zone_->types()->getVoid());
 36.1477 -    if (!DeclareIntrinsicType(zone_, scope_, "void", voidType))
 36.1478 -        return false;
 36.1479 -
 36.1480 -    Local<Type> intType(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
 36.1481 -    if (!DeclareIntrinsicType(zone_, scope_, "int", intType))
 36.1482 -        return false;
 36.1483 -
 36.1484 -    return true;
 36.1485 -}
 36.1486 -
 36.1487 -ParseTree *
 36.1488 -Parser::parse()
 36.1489 -{
 36.1490 -    StatementList *statements = new (pool_) StatementList();
 36.1491 -
 36.1492 -    if (!enterScope(Scope::GLOBAL))
 36.1493 -        return NULL;
 36.1494 -
 36.1495 -    if (!setupIntrinsics())
 36.1496 -        return NULL;
 36.1497 -
 36.1498 -    for (;;) {
 36.1499 -        Statement *statement = NULL;
 36.1500 -
 36.1501 -        TokenKind kind = scanner_.peek();
 36.1502 -        switch (kind) {
 36.1503 -          case TOK_ERROR:
 36.1504 -            return NULL;
 36.1505 -
 36.1506 -          case TOK_EOF:
 36.1507 -            break;
 36.1508 -
 36.1509 -          case TOK_NAME:
 36.1510 -            if ((statement = function(TOK_NAME)) == NULL)
 36.1511 -                return NULL;
 36.1512 -            break;
 36.1513 -
 36.1514 -          case TOK_FORWARD:
 36.1515 -          case TOK_PUBLIC:
 36.1516 -          case TOK_NATIVE:
 36.1517 -          case TOK_STOCK:
 36.1518 -          case TOK_LABEL:
 36.1519 -          case TOK_TYPEDEF:
 36.1520 -          {
 36.1521 -            scanner_.scan();
 36.1522 -            if (kind == TOK_PUBLIC && peek(TOK_CONST)) {
 36.1523 -                if ((statement = var(TOK_PUBLIC, scanner_.scan())) == NULL)
 36.1524 -                    return NULL;
 36.1525 -                if (!matchSemicolon())
 36.1526 -                    return NULL;
 36.1527 -            } else {
 36.1528 -                if ((statement = function(kind)) == NULL)
 36.1529 -                    return NULL;
 36.1530 -                if ((kind == TOK_FORWARD || kind == TOK_NATIVE || kind == TOK_TYPEDEF) && !matchSemicolon())
 36.1531 -                    return NULL;
 36.1532 -            }
 36.1533 -            break;
 36.1534 -          }
 36.1535 -
 36.1536 -          case TOK_CONST:
 36.1537 -          case TOK_NEW:
 36.1538 -          {
 36.1539 -            // Note: at global scope, we don't accept comma-delimited
 36.1540 -            // declarations yet, to see if we can get away with forcing
 36.1541 -            // a nicer top-level style.
 36.1542 -            scanner_.scan();
 36.1543 -            if ((statement = var(TOK_STOCK, kind)) == NULL)
 36.1544 -                return NULL;
 36.1545 -            if (!matchSemicolon())
 36.1546 -                return NULL;
 36.1547 -            break;
 36.1548 -          }
 36.1549 -
 36.1550 -          case TOK_ENUM:
 36.1551 -            if ((statement = enum_()) == NULL)
 36.1552 -                return NULL;
 36.1553 -            if (!matchSemicolon())
 36.1554 -                return NULL;
 36.1555 -            break;
 36.1556 -
 36.1557 -          case TOK_STRUCT:
 36.1558 -            if ((statement = struct_()) == NULL)
 36.1559 -                return NULL;
 36.1560 -            if (!matchSemicolon())
 36.1561 -                return NULL;
 36.1562 -            break;
 36.1563 -
 36.1564 -          default:
 36.1565 -            cc_.reportError(scanner_.begin(), Message_ExpectedGlobal);
 36.1566 -            return NULL;
 36.1567 -        }
 36.1568 -
 36.1569 -        if (!statement)
 36.1570 -            break;
 36.1571 -
 36.1572 -        if (!statements->append(statement))
 36.1573 -            return NULL;
 36.1574 -    }
 36.1575 -
 36.1576 -    return new (pool_) ParseTree(scope_, statements, unbound_);
 36.1577 -}
 36.1578 -
 36.1579 -class AstPrinter : public AstVisitor
 36.1580 -{
 36.1581 -    FILE *fp_;
 36.1582 -    size_t level_;
 36.1583 -
 36.1584 -  private:
 36.1585 -    void prefix() {
 36.1586 -        for (size_t i = 0; i < level_; i++)
 36.1587 -            fprintf(fp_, "  ");
 36.1588 -    }
 36.1589 -    void indent() {
 36.1590 -        level_++;
 36.1591 -    }
 36.1592 -    void unindent() {
 36.1593 -        level_--;
 36.1594 -    }
 36.1595 -
 36.1596 -  public:
 36.1597 -    AstPrinter(FILE *fp)
 36.1598 -      : fp_(fp),
 36.1599 -        level_(0)
 36.1600 -    {
 36.1601 -    }
 36.1602 -
 36.1603 -    void dump(const FunctionSignature &sig) {
 36.1604 -        prefix();
 36.1605 -        fprintf(fp_, "%s", sig.returnType()
 36.1606 -                           ? sig.returnType()->name()->chars()
 36.1607 -                           : "_");
 36.1608 -        if (sig.returnDimensions()) {
 36.1609 -            for (size_t i = 0; i < sig.returnDimensions()->length(); i++)
 36.1610 -                fprintf(fp_, "[]");
 36.1611 -        }
 36.1612 -        fprintf(fp_, "()\n");
 36.1613 -    }
 36.1614 -    void visit(NameProxy *name) {
 36.1615 -        prefix();
 36.1616 -        fprintf(fp_, "[ NameProxy (%s)%s\n", name->name()->chars(),
 36.1617 -                (name->binding() ? "" : " unbound"));
 36.1618 -    }
 36.1619 -    void visit(CallExpression *node) {
 36.1620 -        prefix();
 36.1621 -        fprintf(fp_, "[ CallExpression\n");
 36.1622 -        indent();
 36.1623 -        node->callee()->accept(this);
 36.1624 -        for (size_t i = 0; i < node->arguments()->length(); i++)
 36.1625 -            node->arguments()->at(i)->accept(this);
 36.1626 -        unindent();
 36.1627 -    }
 36.1628 -    void visit(FunctionTypeStatement *node) {
 36.1629 -        prefix();
 36.1630 -        fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->decl()->name()->chars());
 36.1631 -        indent();
 36.1632 -        dump(node->signature());
 36.1633 -        unindent();
 36.1634 -    }
 36.1635 -    void visit(FunctionStatement *node) {
 36.1636 -        prefix();
 36.1637 -        fprintf(fp_, "[ FunctionStatement (%s)\n", node->fun()->name()->chars());
 36.1638 -        indent();
 36.1639 -        dump(node->signature());
 36.1640 -        if (node->body())
 36.1641 -            node->body()->accept(this);
 36.1642 -        unindent();
 36.1643 -    }
 36.1644 -    void visit(ExpressionStatement *node) {
 36.1645 -        prefix();
 36.1646 -        fprintf(fp_, "[ ExpressionStatement\n");
 36.1647 -        indent();
 36.1648 -        node->expression()->accept(this);
 36.1649 -        unindent();
 36.1650 -    }
 36.1651 -    void visit(Assignment *node) {
 36.1652 -        prefix();
 36.1653 -        fprintf(fp_, "[ Assignment\n");
 36.1654 -        indent();
 36.1655 -        node->lvalue()->accept(this);
 36.1656 -        node->expression()->accept(this);
 36.1657 -        unindent();
 36.1658 -    }
 36.1659 -    void visit(TernaryExpression *node) {
 36.1660 -        prefix();
 36.1661 -        fprintf(fp_, "[ TernaryExpression\n");
 36.1662 -        indent();
 36.1663 -        node->condition()->accept(this);
 36.1664 -        node->left()->accept(this);
 36.1665 -        node->right()->accept(this);
 36.1666 -        unindent();
 36.1667 -    }
 36.1668 -    void visit(BinaryExpression *node) {
 36.1669 -        prefix();
 36.1670 -        fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]);
 36.1671 -        indent();
 36.1672 -        node->left()->accept(this);
 36.1673 -        node->right()->accept(this);
 36.1674 -        unindent();
 36.1675 -    }
 36.1676 -    void visit(UnaryExpression *node) {
 36.1677 -        prefix();
 36.1678 -        fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]);
 36.1679 -        indent();
 36.1680 -        node->expression()->accept(this);
 36.1681 -        unindent();
 36.1682 -    }
 36.1683 -    void visit(ReturnStatement *node) {
 36.1684 -        prefix();
 36.1685 -        fprintf(fp_, "[ ReturnStatement\n");
 36.1686 -        indent();
 36.1687 -        if (node->expression())
 36.1688 -            node->expression()->accept(this);
 36.1689 -        unindent();
 36.1690 -    }
 36.1691 -    void visit(ForStatement *node) {
 36.1692 -        prefix();
 36.1693 -        fprintf(fp_, "[ ForStatement\n");
 36.1694 -        indent();
 36.1695 -        if (node->initialization())
 36.1696 -            node->initialization()->accept(this);
 36.1697 -        if (node->condition())
 36.1698 -            node->condition()->accept(this);
 36.1699 -        if (node->update())
 36.1700 -            node->update()->accept(this);
 36.1701 -        node->body()->accept(this);
 36.1702 -        unindent();
 36.1703 -    }
 36.1704 -    void visit(BlockStatement *node) {
 36.1705 -        prefix();
 36.1706 -        fprintf(fp_, "[ BlockStatement\n");
 36.1707 -        indent();
 36.1708 -        for (size_t i = 0; i < node->statements()->length(); i++)
 36.1709 -            node->statements()->at(i)->accept(this);
 36.1710 -        unindent();
 36.1711 -    }
 36.1712 -    void visit(VariableDeclaration *node) {
 36.1713 -        prefix();
 36.1714 -        fprintf(fp_, "[ VariableDeclaration (%s)\n", node->variable()->name()->chars());
 36.1715 -        indent();
 36.1716 -        if (node->initialization())
 36.1717 -            node->initialization()->accept(this);
 36.1718 -        unindent();
 36.1719 -    }
 36.1720 -    void visit(IntegerLiteral *node) {
 36.1721 -        prefix();
 36.1722 -        fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value());
 36.1723 -    }
 36.1724 -    void visit(BooleanLiteral *node) {
 36.1725 -        prefix();
 36.1726 -        fprintf(fp_, "[ BooleanLiteral (%s)\n",
 36.1727 -                (node->token() == TOK_TRUE) ? "true" : "false");
 36.1728 -    }
 36.1729 -    void visit(FloatLiteral *node) {
 36.1730 -        prefix();
 36.1731 -        fprintf(fp_, "[ FloatLiteral (%f)\n", node->value());
 36.1732 -    }
 36.1733 -    void visit(IfStatement *node) {
 36.1734 -        prefix();
 36.1735 -        fprintf(fp_, "[ IfStatement\n");
 36.1736 -        indent();
 36.1737 -        node->ifTrue()->accept(this);
 36.1738 -        if (node->ifFalse())
 36.1739 -            node->ifFalse()->accept(this);
 36.1740 -        unindent();
 36.1741 -    }
 36.1742 -    void visit(IndexExpression *node) {
 36.1743 -        prefix();
 36.1744 -        fprintf(fp_, "[ IndexExpression\n");
 36.1745 -        indent();
 36.1746 -        node->left()->accept(this);
 36.1747 -        node->right()->accept(this);
 36.1748 -        unindent();
 36.1749 -    }
 36.1750 -    void visit(EnumStatement *node) {
 36.1751 -        prefix();
 36.1752 -        fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : "<anonymous>");
 36.1753 -        indent();
 36.1754 -        for (size_t i = 0; i < node->entries()->length(); i++) {
 36.1755 -            prefix();
 36.1756 -            fprintf(fp_, "%s =\n", node->entries()->at(i).name->name()->chars());
 36.1757 -            if (node->entries()->at(i).expr) {
 36.1758 -                indent();
 36.1759 -                node->entries()->at(i).expr->accept(this);
 36.1760 -                unindent();
 36.1761 -            }
 36.1762 -        }
 36.1763 -        unindent();
 36.1764 -    }
 36.1765 -    void visit(WhileStatement *node) {
 36.1766 -        prefix();
 36.1767 -        fprintf(fp_, "[ WhileStatement (%s)\n",
 36.1768 -                (node->token() == TOK_DO) ? "do" : "while");
 36.1769 -        indent();
 36.1770 -        if (node->token() == TOK_DO) {
 36.1771 -            node->condition()->accept(this);
 36.1772 -            node->body()->accept(this);
 36.1773 -        } else {
 36.1774 -            node->condition()->accept(this);
 36.1775 -            node->body()->accept(this);
 36.1776 -        }
 36.1777 -        unindent();
 36.1778 -    }
 36.1779 -    void visit(BreakStatement *node) {
 36.1780 -        prefix();
 36.1781 -        fprintf(fp_, "[ BreakStatement\n");
 36.1782 -    }
 36.1783 -    void visit(ContinueStatement *node) {
 36.1784 -        prefix();
 36.1785 -        fprintf(fp_, "[ ContinueStatement\n");
 36.1786 -    }
 36.1787 -    void visit(StringLiteral *node) {
 36.1788 -        prefix();
 36.1789 -        fprintf(fp_, "[ StringLiteral\n");
 36.1790 -    }
 36.1791 -    void visit(IncDecExpression *node) {
 36.1792 -        prefix();
 36.1793 -        fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix());
 36.1794 -        indent();
 36.1795 -        node->expression()->accept(this);
 36.1796 -        unindent();
 36.1797 -    }
 36.1798 -    void visit(StructureStatement *node) {
 36.1799 -        prefix();
 36.1800 -        fprintf(fp_, "[ StructureStatement %s\n", node->decl()->name()->chars());
 36.1801 -    }
 36.1802 -    void visit(FieldExpression *node) {
 36.1803 -        prefix();
 36.1804 -        fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars());
 36.1805 -        indent();
 36.1806 -        node->left()->accept(this);
 36.1807 -        unindent();
 36.1808 -    }
 36.1809 -    void visit(SwitchStatement *node) {
 36.1810 -        prefix();
 36.1811 -        fprintf(fp_, "[ SwitchStatement\n");
 36.1812 -        indent();
 36.1813 -        node->expression()->accept(this);
 36.1814 -        for (size_t i = 0; i < node->cases()->length(); i++) {
 36.1815 -            Case *c = node->cases()->at(i);
 36.1816 -            c->expression()->accept(this);
 36.1817 -            if (c->others()) {
 36.1818 -                for (size_t j = 0; j < c->others()->length(); j++)
 36.1819 -                    c->others()->at(j)->accept(this);
 36.1820 -            }
 36.1821 -            indent();
 36.1822 -            c->statement()->accept(this);
 36.1823 -            unindent();
 36.1824 -        }
 36.1825 -        if (node->defaultCase())
 36.1826 -            node->defaultCase()->accept(this);
 36.1827 -        unindent();
 36.1828 -    }
 36.1829 -    void visit(ArrayLiteral *node) {
 36.1830 -        prefix();
 36.1831 -        fprintf(fp_, "[ ArrayLiteral\n");
 36.1832 -        indent();
 36.1833 -        for (size_t i = 0; i < node->expressions()->length(); i++) {
 36.1834 -            Expression *expr = node->expressions()->at(i);
 36.1835 -            indent();
 36.1836 -            expr->accept(this);
 36.1837 -            unindent();
 36.1838 -        }
 36.1839 -    }
 36.1840 -};
 36.1841 -
 36.1842 -void
 36.1843 -ParseTree::dump(FILE *fp)
 36.1844 -{
 36.1845 -    AstPrinter printer(fp);
 36.1846 -
 36.1847 -    for (size_t i = 0; i < statements_->length(); i++)
 36.1848 -        statements_->at(i)->accept(&printer);
 36.1849 -}
    37.1 --- a/src/Parser.h	Mon Sep 17 00:10:01 2012 -0700
    37.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.3 @@ -1,106 +0,0 @@
    37.4 -/* vim: set ts=4 sw=4 tw=99 et:
    37.5 - *
    37.6 - * Copyright (C) 2012 David Anderson
    37.7 - *
    37.8 - * This file is part of SourcePawn.
    37.9 - *
   37.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   37.11 - * the terms of the GNU General Public License as published by the Free
   37.12 - * Software Foundation, either version 3 of the License, or (at your option)
   37.13 - * any later version.
   37.14 - * 
   37.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   37.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   37.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   37.18 - *
   37.19 - * You should have received a copy of the GNU General Public License along with
   37.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   37.21 - */
   37.22 -#ifndef _include_jitcraft_parser_h_
   37.23 -#define _include_jitcraft_parser_h_
   37.24 -
   37.25 -#include <stdio.h>
   37.26 -#include "AST.h"
   37.27 -#include "Scanner.h"
   37.28 -#include "Scopes.h"
   37.29 -#include "Strings.h"
   37.30 -
   37.31 -namespace ke {
   37.32 -
   37.33 -class Parser
   37.34 -{
   37.35 -    Zone *zone_;
   37.36 -    CompileContext &cc_;
   37.37 -    PoolAllocator &pool_;
   37.38 -    Scanner scanner_;
   37.39 -    Scope *scope_;
   37.40 -    PoolList<NameProxy *> *unbound_;
   37.41 -    bool encounteredReturn_;
   37.42 -
   37.43 -  private:
   37.44 -    void redeclarationError(BoundName *name);
   37.45 -    bool peek(TokenKind kind);
   37.46 -    bool match(TokenKind kind);
   37.47 -    bool expect(TokenKind kind);
   37.48 -    bool matchSemicolon();
   37.49 -
   37.50 -    Scope *enterScope(Scope::Kind kind);
   37.51 -
   37.52 -
   37.53 -    VariableDeclaration *var(TokenKind scope, TokenKind kind);
   37.54 -    Statement *vars(TokenKind scope, TokenKind kind);
   37.55 -    bool matchName(String **name, TokenKind kind = TOK_NAME);
   37.56 -
   37.57 -    NameProxy *bind(Handle<String> name);
   37.58 -    BoundName *bindType(Handle<String> string);
   37.59 -
   37.60 -    ExpressionList *dimensions();
   37.61 -    String *expectName();
   37.62 -
   37.63 -    Expression *primitive();
   37.64 -    Expression *arrayLiteral(TokenKind kind);
   37.65 -    Expression *call(Expression *callee);
   37.66 -    Expression *field(Expression *left);
   37.67 -    Expression *index(Expression *left);
   37.68 -    Expression *prefix();
   37.69 -    Expression *primary();
   37.70 -    Expression *unary();
   37.71 -    Expression *multiplication();
   37.72 -    Expression *addition();
   37.73 -    Expression *shift();
   37.74 -    Expression *bitand_();
   37.75 -    Expression *bitxor();
   37.76 -    Expression *bitor_();
   37.77 -    Expression *relational();
   37.78 -    Expression *equals();
   37.79 -    Expression *and_();
   37.80 -    Expression *or_();
   37.81 -    Expression *ternary();
   37.82 -    Expression *assignment();
   37.83 -    Expression *expression();
   37.84 -
   37.85 -    Statement *switch_();
   37.86 -    Statement *struct_();
   37.87 -    Statement *enum_();
   37.88 -    Statement *if_();
   37.89 -    Statement *block(Scope *scope = NULL);
   37.90 -    Statement *function(TokenKind tok);
   37.91 -    Statement *expressionStatement();
   37.92 -    Statement *while_();
   37.93 -    Statement *do_();
   37.94 -    Statement *forStatement();
   37.95 -    Statement *localStatement();
   37.96 -    Statement *globalStatement();
   37.97 -    Statement *returnStatement();
   37.98 -
   37.99 -    bool setupIntrinsics();
  37.100 -
  37.101 -  public:
  37.102 -    Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length);
  37.103 -
  37.104 -    ParseTree *parse();
  37.105 -};
  37.106 -
  37.107 -}
  37.108 -
  37.109 -#endif // _include_jitcraft_parser_h_
    38.1 --- a/src/PoolAllocator.cpp	Mon Sep 17 00:10:01 2012 -0700
    38.2 +++ b/src/PoolAllocator.cpp	Sat Nov 17 18:41:01 2012 -0800
    38.3 @@ -122,7 +122,7 @@
    38.4  void *
    38.5  PoolAllocationPolicy::malloc(size_t bytes)
    38.6  {
    38.7 -    return ZONE()->pool().allocate(bytes);
    38.8 +    return ZONE()->pool().rawAllocate(bytes);
    38.9  }
   38.10  
   38.11  void
    39.1 --- a/src/PoolAllocator.h	Mon Sep 17 00:10:01 2012 -0700
    39.2 +++ b/src/PoolAllocator.h	Sat Nov 17 18:41:01 2012 -0800
    39.3 @@ -58,7 +58,7 @@
    39.4      PoolAllocator();
    39.5      ~PoolAllocator();
    39.6  
    39.7 -    void *allocate(size_t bytes) {
    39.8 +    void *rawAllocate(size_t bytes) {
    39.9          // Guarantee malloc alignment.
   39.10          size_t actualBytes = Align(bytes, kMallocAlignment);
   39.11          if (!last_ || (size_t(last_->end - last_->ptr) < actualBytes))
   39.12 @@ -68,6 +68,15 @@
   39.13          return ptr;
   39.14      }
   39.15  
   39.16 +    template <typename T>
   39.17 +    T *alloc(size_t count = 1) {
   39.18 +        void *ptr = rawAllocate(count * sizeof(T));
   39.19 +        if (!ptr)
   39.20 +            return NULL;
   39.21 +
   39.22 +        return reinterpret_cast<T *>(ptr);
   39.23 +    }
   39.24 +
   39.25      char *enter();
   39.26      void leave(char *position);
   39.27  };
   39.28 @@ -93,10 +102,10 @@
   39.29  {
   39.30    public:
   39.31      void *operator new(size_t size, PoolAllocator &pool) {
   39.32 -        return pool.allocate(size);
   39.33 +        return pool.rawAllocate(size);
   39.34      }
   39.35      void *operator new [](size_t size, PoolAllocator &pool) {
   39.36 -        return pool.allocate(size);
   39.37 +        return pool.rawAllocate(size);
   39.38      }
   39.39      
   39.40      // Using delete on pool-allocated objects is illegal.
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/src/QualType.h	Sat Nov 17 18:41:01 2012 -0800
    40.3 @@ -0,0 +1,51 @@
    40.4 +/* vim: set ts=4 sw=4 tw=99 et:
    40.5 + *
    40.6 + * Copyright (C) 2012 David Anderson
    40.7 + *
    40.8 + * This file is part of SourcePawn.
    40.9 + *
   40.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   40.11 + * the terms of the GNU General Public License as published by the Free
   40.12 + * Software Foundation, either version 3 of the License, or (at your option)
   40.13 + * any later version.
   40.14 + * 
   40.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   40.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   40.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   40.18 + *
   40.19 + * You should have received a copy of the GNU General Public License along with
   40.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   40.21 + */
   40.22 +#ifndef _include_sp2_qualtype_h_
   40.23 +#define _include_sp2_qualtype_h_
   40.24 +
   40.25 +#include "Objects.h"
   40.26 +
   40.27 +namespace ke {
   40.28 +
   40.29 +class Type;
   40.30 +
   40.31 +enum TypeQualifiers
   40.32 +{
   40.33 +    Qual_None   = 0,
   40.34 +    Qual_Const  = (1 << 0),
   40.35 +    Qual_Public = (1 << 1),
   40.36 +    Total_Qualifiers
   40.37 +};
   40.38 +
   40.39 +// A QualType is a fully-qualified type in the SP2 type system.
   40.40 +class QualType : public Object
   40.41 +{
   40.42 +  public:
   40.43 +    
   40.44 +
   40.45 +  private:
   40.46 +    union {
   40.47 +      Type *type_;
   40.48 +      uintptr_t flags_;
   40.49 +    };
   40.50 +};
   40.51 +
   40.52 +}
   40.53 +
   40.54 +#endif // _include_sp2_qualtype_h_
    41.1 --- a/src/Reference.cpp	Mon Sep 17 00:10:01 2012 -0700
    41.2 +++ b/src/Reference.cpp	Sat Nov 17 18:41:01 2012 -0800
    41.3 @@ -49,16 +49,3 @@
    41.4      return ref;
    41.5  }
    41.6  
    41.7 -Reference *
    41.8 -Reference::NewField(Zone *zone, Handle<Struct> obj, size_t index, Heap::Tenure tenure)
    41.9 -{
   41.10 -    Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
   41.11 -    if (!ref)
   41.12 -        return NULL;
   41.13 -
   41.14 -    Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
   41.15 -    ref->location_ = obj->ref(desc);
   41.16 -    ref->base_ = obj;
   41.17 -    return ref;
   41.18 -}
   41.19 -
    42.1 --- a/src/Reference.h	Mon Sep 17 00:10:01 2012 -0700
    42.2 +++ b/src/Reference.h	Sat Nov 17 18:41:01 2012 -0800
    42.3 @@ -40,7 +40,6 @@
    42.4    public:
    42.5      static Reference *NewStack(Zone *zone, void *location, Heap::Tenure tenure = Heap::Tenure_Default);
    42.6      static Reference *NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure = Heap::Tenure_Default);
    42.7 -    static Reference *NewField(Zone *zone, Handle<Struct> obj, size_t index, Heap::Tenure tenure = Heap::Tenure_Default);
    42.8  
    42.9      int getInt() {
   42.10          return *reinterpret_cast<int *>(location_);
    43.1 --- a/src/Scanner.cpp	Mon Sep 17 00:10:01 2012 -0700
    43.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.3 @@ -1,679 +0,0 @@
    43.4 -/* vim: set ts=4 sw=4 tw=99 et:
    43.5 - *
    43.6 - * Copyright (C) 2012 David Anderson
    43.7 - *
    43.8 - * This file is part of JITCraft.
    43.9 - *
   43.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   43.11 - * the terms of the GNU General Public License as published by the Free
   43.12 - * Software Foundation, either version 3 of the License, or (at your option)
   43.13 - * any later version.
   43.14 - * 
   43.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   43.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   43.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   43.18 - *
   43.19 - * You should have received a copy of the GNU General Public License along with
   43.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   43.21 - */
   43.22 -#include <assert.h>
   43.23 -#include <ctype.h>
   43.24 -#include <math.h>
   43.25 -#include <limits.h>
   43.26 -#include <string.h>
   43.27 -#include "Scanner.h"
   43.28 -#include "Utility.h"
   43.29 -
   43.30 -using namespace ke;
   43.31 -
   43.32 -const char *ke::TokenNames[] =
   43.33 -{
   43.34 -#define _(name, str) str,
   43.35 -    TOKENMAP(_)
   43.36 -#undef _
   43.37 -    NULL
   43.38 -};
   43.39 -
   43.40 -Scanner::Scanner(CompileContext &cc, const char *stream, size_t length)
   43.41 -  : cc_(cc),
   43.42 -    stream_(stream),
   43.43 -    length_(length),
   43.44 -    pushed_(false),
   43.45 -    allowTags_(true),
   43.46 -    saved_('\0'),
   43.47 -    pos_(stream_)
   43.48 -{
   43.49 -    cur_.line = 1;
   43.50 -    cur_.col = 1;
   43.51 -    last_ = cur_;
   43.52 -}
   43.53 -
   43.54 -char
   43.55 -Scanner::getChar()
   43.56 -{
   43.57 -    if (saved_ != '\0') {
   43.58 -        char temp = saved_;
   43.59 -        saved_ = '\0';
   43.60 -        return temp;
   43.61 -    }
   43.62 -    if (pos_ >= stream_ + length_)
   43.63 -        return '\0';
   43.64 -    last_.col = cur_.col++;
   43.65 -    return *pos_++;
   43.66 -}
   43.67 -
   43.68 -void
   43.69 -Scanner::putChar(char c)
   43.70 -{
   43.71 -    assert(saved_ == '\0');
   43.72 -    saved_ = c;
   43.73 -    cur_.col = last_.col;
   43.74 -}
   43.75 -
   43.76 -void
   43.77 -Scanner::calcNewLine(char c)
   43.78 -{
   43.79 -    cur_.line++;
   43.80 -    cur_.col = 1;
   43.81 -    last_ = cur_;
   43.82 -
   43.83 -    char o;
   43.84 -    if (c == '\r' && ((o = getChar()) != '\n'))
   43.85 -        putChar(o);
   43.86 -}
   43.87 -
   43.88 -void
   43.89 -Scanner::eatSingleLine()
   43.90 -{
   43.91 -    char c;
   43.92 -    while ((c = getChar()) != '\0') {
   43.93 -        if (c == '\n' || c == '\r') {
   43.94 -            calcNewLine(c);
   43.95 -            break;
   43.96 -        }
   43.97 -    }
   43.98 -}
   43.99 -
  43.100 -bool
  43.101 -Scanner::eatComment()
  43.102 -{
  43.103 -    char c;
  43.104 -
  43.105 -    while ((c = getChar()) != '\0') {
  43.106 -        while (c == '*') {
  43.107 -            c = getChar();
  43.108 -            if (c == '\0')
  43.109 -                return false;
  43.110 -            if (c == '/')
  43.111 -                return true;
  43.112 -        }
  43.113 -        if (c == '\r' || c == '\n')
  43.114 -            calcNewLine(c);
  43.115 -    }
  43.116 -
  43.117 -    return false;
  43.118 -}
  43.119 -
  43.120 -static inline bool
  43.121 -IsDigit(char c)
  43.122 -{
  43.123 -    return c >= '0' && c <= '9';
  43.124 -}
  43.125 -
  43.126 -// Based off the logic in sc2.c's ftoi()...
  43.127 -double
  43.128 -Scanner::ParseDouble(const char *string)
  43.129 -{
  43.130 -    const char *ptr = string;
  43.131 -
  43.132 -    double number = 0.0;
  43.133 -    while (IsDigit(*ptr)) {
  43.134 -        number = (number * 10) + (*ptr - '0');
  43.135 -        ptr++;
  43.136 -    }
  43.137 -
  43.138 -    assert(*ptr == '.');
  43.139 -    ptr++;
  43.140 -
  43.141 -    double fraction = 0.0;
  43.142 -    double multiplier = 1.0;
  43.143 -    while (IsDigit(*ptr)) {
  43.144 -        fraction = (fraction * 10) + (*ptr - '0');
  43.145 -        multiplier = multiplier / 10.0;
  43.146 -        ptr++;
  43.147 -    }
  43.148 -
  43.149 -    number += fraction * multiplier;
  43.150 -
  43.151 -    if (*ptr++ == 'e') {
  43.152 -        int sign = 1;
  43.153 -        if (*ptr == '-') {
  43.154 -            sign = -1;
  43.155 -            ptr++;
  43.156 -        }
  43.157 -
  43.158 -        int exponent = 0;
  43.159 -        while (IsDigit(*ptr)) {
  43.160 -            exponent = (exponent * 10) + (*ptr - '0');
  43.161 -            ptr++;
  43.162 -        }
  43.163 -
  43.164 -        multiplier = pow(10.0, exponent * sign);
  43.165 -        number *= multiplier;
  43.166 -    }
  43.167 -
  43.168 -    return number;
  43.169 -}
  43.170 -
  43.171 -static inline bool
  43.172 -IsHexDigit(char c)
  43.173 -{
  43.174 -    return IsDigit(c) ||
  43.175 -           (c >= 'a' && c <= 'f') ||
  43.176 -           (c >= 'A' && c <= 'F');
  43.177 -}
  43.178 -
  43.179 -// Based on the logic for litchar() in sc2.c.
  43.180 -int
  43.181 -Scanner::readEscapeCode()
  43.182 -{
  43.183 -    char c = getChar();
  43.184 -    if (c == '\\')
  43.185 -        return c;
  43.186 -
  43.187 -    switch (c) {
  43.188 -      case 'a':
  43.189 -        return '\a';
  43.190 -      case 'b':
  43.191 -        return '\b';
  43.192 -      case 'e':
  43.193 -        return 27;          // Apparently \e is non-standard.
  43.194 -      case 'f':
  43.195 -        return '\f';
  43.196 -      case 'n':
  43.197 -        return '\n';
  43.198 -      case 'r':
  43.199 -        return '\r';
  43.200 -      case 't':
  43.201 -        return '\t';
  43.202 -      case '\v':
  43.203 -        return '\v';
  43.204 -
  43.205 -      case 'x':
  43.206 -      {
  43.207 -          unsigned digits = 0;
  43.208 -          char r = 0;
  43.209 -  
  43.210 -          c = getChar();
  43.211 -          while (IsHexDigit(c) && digits < 2) {
  43.212 -              if (IsDigit(c))
  43.213 -                  c = (c << 4) + (c - '0');
  43.214 -              else
  43.215 -                  c = (c << 4) + (tolower(c) - 'a' + 10);
  43.216 -              digits++;
  43.217 -              c = getChar();
  43.218 -           }
  43.219 -                
  43.220 -          // Swallow a trailing ';'
  43.221 -          if (c != ';')
  43.222 -              putChar(c);
  43.223 -  
  43.224 -          return r;
  43.225 -      }
  43.226 -
  43.227 -      case '\'':
  43.228 -      case '\"':
  43.229 -      case '%':
  43.230 -        return c;
  43.231 -
  43.232 -      default:
  43.233 -      {
  43.234 -        if (IsDigit(c)) {
  43.235 -            // \ddd
  43.236 -            char r = 0;
  43.237 -            while (IsDigit(c)) {
  43.238 -                r = r * 10 + (c - '0');
  43.239 -                c = getChar();
  43.240 -            }
  43.241 -
  43.242 -            // Swallow a trailing ;
  43.243 -            if (c != ';')
  43.244 -                putChar(c);
  43.245 -
  43.246 -            return r;
  43.247 -        }
  43.248 -        cc_.reportError(begin(), Message_UnknownEscapeCode, c);
  43.249 -        return INT_MAX;
  43.250 -      }
  43.251 -    }
  43.252 -}
  43.253 -
  43.254 -TokenKind
  43.255 -Scanner::stringLiteral()
  43.256 -{
  43.257 -    literal_.clear();
  43.258 -
  43.259 -    for (;;) {
  43.260 -        char c = getChar();
  43.261 -        if (c == '\"')
  43.262 -            break;
  43.263 -        if (c == '\r' || c == '\n' || c == '\0') {
  43.264 -            cc_.reportError(begin(), Message_UnterminatedString);
  43.265 -            return TOK_ERROR;
  43.266 -        }
  43.267 -        if (c == '\\') {
  43.268 -            int code = readEscapeCode();
  43.269 -            if (code == INT_MAX)
  43.270 -                return TOK_ERROR;
  43.271 -            c = char(code);
  43.272 -        }
  43.273 -        if (!literal_.append(c))
  43.274 -            return TOK_ERROR;
  43.275 -    }
  43.276 -
  43.277 -    if (!literal_.append('\0'))
  43.278 -        return TOK_ERROR;
  43.279 -
  43.280 -    return TOK_STRING_LITERAL;
  43.281 -}
  43.282 -
  43.283 -TokenKind
  43.284 -Scanner::hexLiteral()
  43.285 -{
  43.286 -    literal_.clear();
  43.287 -
  43.288 -    char c;
  43.289 -    for (;;) {
  43.290 -        c = getChar();
  43.291 -        if (!IsHexDigit(c))
  43.292 -            break;
  43.293 -        if (!literal_.append(c))
  43.294 -            return TOK_ERROR;
  43.295 -    }
  43.296 -
  43.297 -    putChar(c);
  43.298 -
  43.299 -    if (!literal_.append('\0'))
  43.300 -        return TOK_ERROR;
  43.301 -    return TOK_HEX_LITERAL;
  43.302 -}
  43.303 -
  43.304 -TokenKind
  43.305 -Scanner::numberLiteral(char first)
  43.306 -{
  43.307 -    literal_.clear();
  43.308 -    if (!literal_.append(first))
  43.309 -        return TOK_ERROR;
  43.310 -
  43.311 -    char c;
  43.312 -    for (;;) {
  43.313 -        c = getChar();
  43.314 -        if (!IsDigit(c))
  43.315 -            break;
  43.316 -        if (!literal_.append(c))
  43.317 -            return TOK_ERROR;
  43.318 -    }
  43.319 -
  43.320 -    // Detect a hexadecimal string.
  43.321 -    if (literal_.length() == 1 &&
  43.322 -        literal_[0] == '0' &&
  43.323 -        (c == 'x' || c == 'X'))
  43.324 -    {
  43.325 -        return hexLiteral();
  43.326 -    }
  43.327 -
  43.328 -    if (c != '.') {
  43.329 -        putChar(c);
  43.330 -        if (!literal_.append('\0'))
  43.331 -            return TOK_ERROR;
  43.332 -        return TOK_INTEGER_LITERAL;
  43.333 -    }
  43.334 -    if (!literal_.append(c))
  43.335 -        return TOK_ERROR;
  43.336 -
  43.337 -    c = getChar();
  43.338 -    if (!IsDigit(c)) {
  43.339 -        cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
  43.340 -        return TOK_ERROR;
  43.341 -    }
  43.342 -    if (!literal_.append(c))
  43.343 -        return TOK_ERROR;
  43.344 -
  43.345 -    for (;;) {
  43.346 -        c = getChar();
  43.347 -        if (!IsDigit(c))
  43.348 -            break;
  43.349 -        if (!literal_.append(c))
  43.350 -            return TOK_ERROR;
  43.351 -    }
  43.352 -
  43.353 -    if (c != 'e') {
  43.354 -        putChar(c);
  43.355 -    } else {
  43.356 -        if (!literal_.append(c))
  43.357 -            return TOK_ERROR;
  43.358 -        c = getChar();
  43.359 -        if (c == '-') {
  43.360 -            if (!literal_.append(c))
  43.361 -                return TOK_ERROR;
  43.362 -            c = getChar();
  43.363 -        }
  43.364 -        if (!IsDigit(c)) {
  43.365 -            cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
  43.366 -            return TOK_ERROR;
  43.367 -        }
  43.368 -        if (!literal_.append(c))
  43.369 -            return TOK_ERROR;
  43.370 -        for (;;) {
  43.371 -            c = getChar();
  43.372 -            if (!IsDigit(c)) {
  43.373 -                putChar(c);
  43.374 -                break;
  43.375 -            }
  43.376 -            if (!literal_.append(c))
  43.377 -                return TOK_ERROR;
  43.378 -        }
  43.379 -    }
  43.380 -
  43.381 -    if (!literal_.append('\0'))
  43.382 -        return TOK_ERROR;
  43.383 -
  43.384 -    return TOK_FLOAT_LITERAL;
  43.385 -}
  43.386 -
  43.387 -static inline TokenKind
  43.388 -FindIdentifier(const char *str)
  43.389 -{
  43.390 -    if (!strcmp(str,  "new"))
  43.391 -        return TOK_NEW;
  43.392 -    if (!strcmp(str,  "for"))
  43.393 -        return TOK_FOR;
  43.394 -    if (!strcmp(str,  "return"))
  43.395 -        return TOK_RETURN;
  43.396 -    if (!strcmp(str,  "if"))
  43.397 -        return TOK_IF;
  43.398 -    if (!strcmp(str,  "else"))
  43.399 -        return TOK_ELSE;
  43.400 -    if (!strcmp(str,  "enum"))
  43.401 -        return TOK_ENUM;
  43.402 -    if (!strcmp(str,  "while"))
  43.403 -        return TOK_WHILE;
  43.404 -    if (!strcmp(str,  "do"))
  43.405 -        return TOK_DO;
  43.406 -    if (!strcmp(str,  "break"))
  43.407 -        return TOK_BREAK;
  43.408 -    if (!strcmp(str,  "continue"))
  43.409 -        return TOK_CONTINUE;
  43.410 -    if (!strcmp(str,  "forward"))
  43.411 -        return TOK_FORWARD;
  43.412 -    if (!strcmp(str,  "public"))
  43.413 -        return TOK_PUBLIC;
  43.414 -    if (!strcmp(str,  "const"))
  43.415 -        return TOK_CONST;
  43.416 -    if (!strcmp(str,  "native"))
  43.417 -        return TOK_NATIVE;
  43.418 -    if (!strcmp(str,  "stock"))
  43.419 -        return TOK_STOCK;
  43.420 -    if (!strcmp(str,  "true"))
  43.421 -        return TOK_TRUE;
  43.422 -    if (!strcmp(str,  "false"))
  43.423 -        return TOK_FALSE;
  43.424 -    if (!strcmp(str,  "struct"))
  43.425 -        return TOK_STRUCT;
  43.426 -    if (!strcmp(str,  "switch"))
  43.427 -        return TOK_SWITCH;
  43.428 -    if (!strcmp(str,  "case"))
  43.429 -        return TOK_CASE;
  43.430 -    if (!strcmp(str,  "default"))
  43.431 -        return TOK_DEFAULT;
  43.432 -    if (!strcmp(str,  "typedef"))
  43.433 -        return TOK_TYPEDEF;
  43.434 -    if (!strcmp(str,  "void"))
  43.435 -        return TOK_VOID;
  43.436 -    if (!strcmp(str,  "int"))
  43.437 -        return TOK_INT;
  43.438 -    if (!strcmp(str,  "sizeof"))
  43.439 -        return TOK_SIZEOF;
  43.440 -    return TOK_NONE;
  43.441 -}
  43.442 -
  43.443 -TokenKind
  43.444 -Scanner::identifier(char first)
  43.445 -{
  43.446 -    literal_.clear();
  43.447 -    if (!literal_.append(first))
  43.448 -        return TOK_ERROR;
  43.449 -
  43.450 -    char c;
  43.451 -    for (;;) {
  43.452 -        c = getChar();
  43.453 -        if (!isascii(c) || (!isalnum(c) && c != '_'))
  43.454 -            break;
  43.455 -        if (!literal_.append(c))
  43.456 -            return TOK_ERROR;
  43.457 -    }
  43.458 -    
  43.459 -    if (!literal_.append('\0'))
  43.460 -        return TOK_ERROR;
  43.461 -
  43.462 -    // Most keywords do not act as labels.
  43.463 -    TokenKind kind = FindIdentifier(literal());
  43.464 -    if (kind != TOK_NONE) {
  43.465 -        putChar(c);
  43.466 -        return kind;
  43.467 -    }
  43.468 -
  43.469 -    if (c == ':' && allowTags_)
  43.470 -        return TOK_LABEL;
  43.471 -
  43.472 -    putChar(c);
  43.473 -
  43.474 -    // _ is a special case which acts as a tag and a keyword.
  43.475 -    if (!strcmp(literal(), "_"))
  43.476 -        return TOK_UNDERSCORE;
  43.477 -
  43.478 -    return TOK_NAME;
  43.479 -}
  43.480 -
  43.481 -TokenKind
  43.482 -Scanner::next()
  43.483 -{
  43.484 -    assert(!pushed_);
  43.485 -
  43.486 -    for (;;) {
  43.487 -        begin_ = cur_;
  43.488 -
  43.489 -        char c = getChar();
  43.490 -        switch (c) {
  43.491 -          case '/':
  43.492 -          {
  43.493 -            c = getChar();
  43.494 -            if (c == '/') {
  43.495 -                eatSingleLine();
  43.496 -                break;
  43.497 -            }
  43.498 -            if (c == '*') {
  43.499 -                if (!eatComment()) {
  43.500 -                    cc_.reportError(begin(), Message_UnterminatedComment);
  43.501 -                    return TOK_ERROR;
  43.502 -                }
  43.503 -                break;
  43.504 -            }
  43.505 -            putChar(c);
  43.506 -            return TOK_SLASH;
  43.507 -          }
  43.508 -
  43.509 -          case '\n':
  43.510 -          case '\r':
  43.511 -            calcNewLine(c);
  43.512 -            break;
  43.513 -
  43.514 -          case ';': return TOK_SEMICOLON;
  43.515 -          case '{': return TOK_LBRACE;
  43.516 -          case '}': return TOK_RBRACE;
  43.517 -          case '(': return TOK_LPAREN;
  43.518 -          case ')': return TOK_RPAREN;
  43.519 -          case '[': return TOK_LBRACKET;
  43.520 -          case ']': return TOK_RBRACKET;
  43.521 -          case '~': return TOK_TILDE;
  43.522 -          case '?': return TOK_QMARK;
  43.523 -          case ':': return TOK_COLON;
  43.524 -
  43.525 -          case '.':
  43.526 -            c = getChar();
  43.527 -            if (c == '.') {
  43.528 -                c = getChar();
  43.529 -                if (c == '.')
  43.530 -                    return TOK_ELLIPSES;
  43.531 -                cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
  43.532 -                return TOK_ERROR;
  43.533 -            }
  43.534 -            putChar(c);
  43.535 -            return TOK_DOT;
  43.536 -
  43.537 -          case '*':
  43.538 -            c = getChar();
  43.539 -            if (c == '=')
  43.540 -                return TOK_ASSIGN_MUL;
  43.541 -            putChar(c);
  43.542 -            return TOK_STAR;
  43.543 -
  43.544 -          case '+':
  43.545 -            c = getChar();
  43.546 -            if (c == '=')
  43.547 -                return TOK_ASSIGN_ADD;
  43.548 -            if (c == '+')
  43.549 -                return TOK_INCREMENT;
  43.550 -            putChar(c);
  43.551 -            return TOK_PLUS;
  43.552 -
  43.553 -          case '&':
  43.554 -            c = getChar();
  43.555 -            if (c == '=')
  43.556 -                return TOK_ASSIGN_BITAND;
  43.557 -            if (c == '&')
  43.558 -                return TOK_AND;
  43.559 -            putChar(c);
  43.560 -            return TOK_BITAND;
  43.561 -
  43.562 -          case '|':
  43.563 -            c = getChar();
  43.564 -            if (c == '=')
  43.565 -                return TOK_ASSIGN_BITOR;
  43.566 -            if (c == '|')
  43.567 -                return TOK_OR;
  43.568 -            putChar(c);
  43.569 -            return TOK_BITOR;
  43.570 -
  43.571 -          case '^':
  43.572 -            c = getChar();
  43.573 -            if (c == '=')
  43.574 -                return TOK_ASSIGN_BITXOR;
  43.575 -            putChar(c);
  43.576 -            return TOK_BITXOR;
  43.577 -
  43.578 -          case '%':
  43.579 -            c = getChar();
  43.580 -            if (c == '=')
  43.581 -                return TOK_ASSIGN_MOD;
  43.582 -            putChar(c);
  43.583 -            return TOK_PERCENT;
  43.584 -
  43.585 -          case '-':
  43.586 -            c = getChar();
  43.587 -            if (c == '=')
  43.588 -                return TOK_ASSIGN_SUB;
  43.589 -            if (c == '-')
  43.590 -                return TOK_DECREMENT;
  43.591 -            putChar(c);
  43.592 -            return TOK_MINUS;
  43.593 -
  43.594 -          case ',': return TOK_COMMA;
  43.595 -          case '\0': return TOK_EOF;
  43.596 -
  43.597 -          case '!':
  43.598 -            c = getChar();
  43.599 -            if (c == '=')
  43.600 -                return TOK_NOTEQUALS;
  43.601 -            putChar(c);
  43.602 -            return TOK_NOT;
  43.603 -
  43.604 -          case '=':
  43.605 -            c = getChar();
  43.606 -            if (c == '=')
  43.607 -                return TOK_EQUALS;
  43.608 -            putChar(c);
  43.609 -            return TOK_ASSIGN;
  43.610 -
  43.611 -
  43.612 -          case '<':
  43.613 -            c = getChar();
  43.614 -            if (c == '=')
  43.615 -                return TOK_LE;
  43.616 -            if (c == '<') {
  43.617 -                c = getChar();
  43.618 -                if (c == '=')
  43.619 -                    return TOK_ASSIGN_SHL;
  43.620 -                putChar(c);
  43.621 -                return TOK_SHL;
  43.622 -            }
  43.623 -            putChar(c);
  43.624 -            return TOK_LT;
  43.625 -
  43.626 -          case '>':
  43.627 -            c = getChar();
  43.628 -            if (c == '=')
  43.629 -                return TOK_GE;
  43.630 -            if (c == '>') {
  43.631 -                c = getChar();
  43.632 -                if (c == '>') {
  43.633 -                    c = getChar();
  43.634 -                    if (c == '=')
  43.635 -                        return TOK_ASSIGN_USHR;
  43.636 -                    putChar(c);
  43.637 -                    return TOK_USHR;
  43.638 -                }
  43.639 -                return TOK_SHR;
  43.640 -            }
  43.641 -            putChar(c);
  43.642 -            return TOK_GT;
  43.643 -
  43.644 -          case ' ':
  43.645 -          case '\t':
  43.646 -          case '\f':
  43.647 -            break;
  43.648 -
  43.649 -          case '"':
  43.650 -            return stringLiteral();
  43.651 -
  43.652 -          default:
  43.653 -            if (c >= '0' && c <= '9')
  43.654 -                return numberLiteral(c);
  43.655 -            if (c == '_' || (isascii(c) && isalpha(c)))
  43.656 -                return identifier(c);
  43.657 -            cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
  43.658 -            return TOK_ERROR;
  43.659 -        }
  43.660 -    }
  43.661 -}
  43.662 -
  43.663 -TokenKind
  43.664 -Scanner::scan()
  43.665 -{
  43.666 -    if (pushed_) {
  43.667 -        pushed_ = false;
  43.668 -        return lastToken_;
  43.669 -    }
  43.670 -    lastToken_ = next();
  43.671 -    return lastToken_;
  43.672 -}
  43.673 -
  43.674 -TokenKind
  43.675 -Scanner::peek()
  43.676 -{
  43.677 -    if (pushed_)
  43.678 -        return lastToken_;
  43.679 -    scan();
  43.680 -    pushed_ = true;
  43.681 -    return lastToken_;
  43.682 -}
    44.1 --- a/src/Scanner.h	Mon Sep 17 00:10:01 2012 -0700
    44.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.3 @@ -1,114 +0,0 @@
    44.4 -/* vim: set ts=4 sw=4 tw=99 et:
    44.5 - *
    44.6 - * Copyright (C) 2012 David Anderson
    44.7 - *
    44.8 - * This file is part of SourcePawn.
    44.9 - *
   44.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   44.11 - * the terms of the GNU General Public License as published by the Free
   44.12 - * Software Foundation, either version 3 of the License, or (at your option)
   44.13 - * any later version.
   44.14 - * 
   44.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   44.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   44.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   44.18 - *
   44.19 - * You should have received a copy of the GNU General Public License along with
   44.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   44.21 - */
   44.22 -#ifndef _include_jitcraft_scanner_h_
   44.23 -#define _include_jitcraft_scanner_h_
   44.24 -
   44.25 -#include <string>
   44.26 -#include "Token.h"
   44.27 -#include "CompileContext.h"
   44.28 -#include "Vector.h"
   44.29 -
   44.30 -namespace ke {
   44.31 -
   44.32 -class Scanner
   44.33 -{
   44.34 -    template <bool Enabled>
   44.35 -    friend class AutoAllowTags;
   44.36 -
   44.37 -    CompileContext &cc_;
   44.38 -    const char *stream_;
   44.39 -    size_t length_;
   44.40 -    bool pushed_;
   44.41 -    bool allowTags_;
   44.42 -    char saved_;
   44.43 -    const char *pos_;
   44.44 -    Vector<char> literal_;
   44.45 -    TokenKind lastToken_;
   44.46 -    SourcePosition last_;
   44.47 -    SourcePosition cur_;
   44.48 -    SourcePosition begin_;
   44.49 -
   44.50 -  private:
   44.51 -    char getChar();
   44.52 -    void putChar(char c);
   44.53 -    void eatSingleLine();
   44.54 -    bool eatComment();
   44.55 -    void calcNewLine(char c);
   44.56 -    int readEscapeCode();
   44.57 -    TokenKind stringLiteral();
   44.58 -    TokenKind hexLiteral();
   44.59 -    TokenKind numberLiteral(char first);
   44.60 -    TokenKind identifier(char first);
   44.61 -
   44.62 -    TokenKind next();
   44.63 -
   44.64 -  public:
   44.65 -    Scanner(CompileContext &cc, const char *stream, size_t length);
   44.66 -
   44.67 -    static double ParseDouble(const char *string);
   44.68 -
   44.69 -    TokenKind scan();
   44.70 -    TokenKind peek();
   44.71 -    TokenKind last() const {
   44.72 -        return lastToken_;
   44.73 -    }
   44.74 -
   44.75 -    bool tagsEnabled() const {
   44.76 -        return allowTags_;
   44.77 -    }
   44.78 -    void setTagsEnabled(bool enabled) {
   44.79 -        allowTags_ = enabled;
   44.80 -    }
   44.81 -
   44.82 -    // Beginning source position of the last instruction.
   44.83 -    SourcePosition begin() const {
   44.84 -        return begin_;
   44.85 -    }
   44.86 -
   44.87 -    // Note: the literal may have embedded NUL characters.
   44.88 -    const char *literal() const {
   44.89 -        return literal_.buffer();
   44.90 -    }
   44.91 -    size_t literal_length() const {
   44.92 -        return literal_.length() - 1;
   44.93 -    }
   44.94 -};
   44.95 -
   44.96 -template <bool Enabled>
   44.97 -class AutoAllowTags
   44.98 -{
   44.99 -    Scanner &scanner_;
  44.100 -    bool prev_;
  44.101 -
  44.102 -  public:
  44.103 -    AutoAllowTags(Scanner &scanner)
  44.104 -      : scanner_(scanner),
  44.105 -        prev_(scanner_.tagsEnabled())
  44.106 -    {
  44.107 -        scanner_.setTagsEnabled(Enabled);
  44.108 -    }
  44.109 -    ~AutoAllowTags()
  44.110 -    {
  44.111 -        scanner_.setTagsEnabled(prev_);
  44.112 -    }
  44.113 -};
  44.114 -
  44.115 -} // namespace ke
  44.116 -
  44.117 -#endif // _include_jitcraft_scanner_h_
    45.1 --- a/src/Scopes.cpp	Mon Sep 17 00:10:01 2012 -0700
    45.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.3 @@ -1,289 +0,0 @@
    45.4 -/* vim: set ts=4 sw=4 tw=99 et:
    45.5 - *
    45.6 - * Copyright (C) 2012 David Anderson
    45.7 - *
    45.8 - * This file is part of JITCraft.
    45.9 - *
   45.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   45.11 - * the terms of the GNU General Public License as published by the Free
   45.12 - * Software Foundation, either version 3 of the License, or (at your option)
   45.13 - * any later version.
   45.14 - * 
   45.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   45.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   45.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   45.18 - *
   45.19 - * You should have received a copy of the GNU General Public License along with
   45.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   45.21 - */
   45.22 -#include "Scopes.h"
   45.23 -#include "Zone.h"
   45.24 -#include "Types.h"
   45.25 -#include "TypeManager.h"
   45.26 -#include "Strings.h"
   45.27 -#include "CompileContext.h"
   45.28 -#include "Environments.h"
   45.29 -#include "Spaces-inl.h"
   45.30 -#include "Heap-inl.h"
   45.31 -
   45.32 -using namespace ke;
   45.33 -
   45.34 -Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
   45.35 -  : pool_(pool),
   45.36 -    locals_(0),
   45.37 -    maxContainedLocals_(0),
   45.38 -    numFunctions_(0),
   45.39 -    numNatives_(0),
   45.40 -    lifoSlot_(NULL),
   45.41 -    kind_(kind),
   45.42 -    enclosing_(enclosing)
   45.43 -{
   45.44 -}
   45.45 -
   45.46 -bool
   45.47 -Scope::initialize()
   45.48 -{
   45.49 -    if (enclosing_ && !enclosing_->children_.append(this))
   45.50 -        return false;
   45.51 -    return true;
   45.52 -}
   45.53 -
   45.54 -void
   45.55 -Scope::unlink()
   45.56 -{
   45.57 -    assert(empty());
   45.58 -
   45.59 -    assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
   45.60 -    enclosing_->children_.pop();
   45.61 -
   45.62 -    // OOM here is swallowed and checked after compilation.
   45.63 -    // :TODO: make the above true.
   45.64 -    for (size_t i = 0; i < children_.length(); i++)
   45.65 -        enclosing_->children_.append(children_[i]);
   45.66 -}
   45.67 -
   45.68 -Scope *
   45.69 -Scope::unlinkIfEmpty()
   45.70 -{
   45.71 -    if (empty()) {
   45.72 -        unlink();
   45.73 -        return NULL;
   45.74 -    }
   45.75 -    return this;
   45.76 -}
   45.77 -
   45.78 -BoundName *
   45.79 -Scope::localLookup(Handle<String> name)
   45.80 -{
   45.81 -    for (size_t i = 0; i < names_.length(); i++) {
   45.82 -        if (names_[i]->name() == name)
   45.83 -            return names_[i];
   45.84 -    }
   45.85 -    return NULL;
   45.86 -}
   45.87 -
   45.88 -BoundName *
   45.89 -Scope::lookup(Handle<String> name)
   45.90 -{
   45.91 -    for (Scope *scope = this; scope; scope = scope->enclosing()) {
   45.92 -        if (BoundName *bound = scope->localLookup(name))
   45.93 -            return bound;
   45.94 -    }
   45.95 -    return NULL;
   45.96 -}
   45.97 -
   45.98 -Variable *
   45.99 -Scope::declareVariable(Handle<String> name, const SourcePosition &pos)
  45.100 -{
  45.101 -    assert(!localLookup(name));
  45.102 -    
  45.103 -    Variable *var = new (pool_) Variable(this, name, pos);
  45.104 -    if (!names_.append(var))
  45.105 -        return NULL;
  45.106 -    return var;
  45.107 -}
  45.108 -
  45.109 -Variable *
  45.110 -Scope::declareArgument(Handle<String> name, const SourcePosition &pos)
  45.111 -{
  45.112 -    assert(kind() == FUNCTION);
  45.113 -    Variable *var = declareVariable(name, pos);
  45.114 -    if (!names_.append(var))
  45.115 -        return NULL;
  45.116 -    if (!parameters_.append(var))
  45.117 -        return NULL;
  45.118 -    return var;
  45.119 -}
  45.120 -
  45.121 -NamedFunction *
  45.122 -Scope::declareFunction(Handle<String> name, const SourcePosition &pos, TokenKind token)
  45.123 -{
  45.124 -    assert(!localLookup(name));
  45.125 -    assert(kind() == GLOBAL);
  45.126 -
  45.127 -    NamedFunction *fun = new (pool_) NamedFunction(this, name, pos, token);
  45.128 -    if (!names_.append(fun))
  45.129 -        return NULL;
  45.130 -    return fun;
  45.131 -}
  45.132 -
  45.133 -NamedConstant *
  45.134 -Scope::declareConstant(Handle<String> name, const SourcePosition &pos)
  45.135 -{
  45.136 -    NamedConstant *constant = new (pool_) NamedConstant(this, name, pos);
  45.137 -    if (!names_.append(constant))
  45.138 -        return NULL;
  45.139 -    return constant;
  45.140 -}
  45.141 -
  45.142 -NamedType *
  45.143 -Scope::declareType(Handle<String> name, const SourcePosition &pos)
  45.144 -{
  45.145 -    NamedType *decl = new (pool_) NamedType(this, name, pos);
  45.146 -    if (!names_.append(decl))
  45.147 -        return NULL;
  45.148 -    return decl;
  45.149 -}
  45.150 -
  45.151 -NamedType *
  45.152 -Scope::declareType(Handle<String> name, Handle<Type> type)
  45.153 -{
  45.154 -    NamedType *decl = new (pool_) NamedType(this, name, type);
  45.155 -    if (!names_.append(decl))
  45.156 -        return NULL;
  45.157 -    return decl;
  45.158 -}
  45.159 -
  45.160 -void
  45.161 -Scope::allocateGlobals()
  45.162 -{
  45.163 -    assert(kind() == GLOBAL);
  45.164 -
  45.165 -    for (size_t i = 0; i < children_.length(); i++) {
  45.166 -        assert(children_[i]->kind() == FUNCTION);
  45.167 -        children_[i]->allocate();
  45.168 -    }
  45.169 -
  45.170 -    Local<Type> type(ZONE());
  45.171 -    for (size_t i = 0; i < names_.length(); i++) {
  45.172 -        BoundName *name = names_[i];
  45.173 -
  45.174 -        if (name->kind() == BoundName::FUNCTION) {
  45.175 -            NamedFunction *fun = name->toNamedFunction();
  45.176 -            if (!fun->used())
  45.177 -                continue;
  45.178 -
  45.179 -            if (fun->isNative())
  45.180 -                fun->allocate(numNatives_++);
  45.181 -            else
  45.182 -                fun->allocate(numFunctions_++);
  45.183 -        } else if (name->kind() == BoundName::VARIABLE) {
  45.184 -            allocate(name->toVariable());
  45.185 -        }
  45.186 -    }
  45.187 -}
  45.188 -
  45.189 -void
  45.190 -Scope::allocate(Variable *var)
  45.191 -{
  45.192 -    if (!var->unallocated())
  45.193 -        return;
  45.194 -
  45.195 -    if (kind() == GLOBAL) {
  45.196 -        var->allocate(Variable::ENVIRONMENT, envVars_.length());
  45.197 -        envVars_.append(var);
  45.198 -    } else {
  45.199 -        var->allocate(Variable::STACK, maxContainedLocals_ + locals_);
  45.200 -        locals_++;
  45.201 -    }
  45.202 -}
  45.203 -
  45.204 -void
  45.205 -Scope::allocate()
  45.206 -{
  45.207 -    maxContainedLocals_ = 0;
  45.208 -    for (size_t i = 0; i < children_.length(); i++) {
  45.209 -        Scope *scope = children_[i];
  45.210 -        scope->allocate();
  45.211 -        if (scope->maxContainedLocals() > maxContainedLocals_)
  45.212 -            maxContainedLocals_ = scope->maxContainedLocals();
  45.213 -    }
  45.214 -
  45.215 -    for (size_t i = 0; i < parameters_.length(); i++)
  45.216 -        parameters_[i]->allocate(Variable::PARAMETER, i);
  45.217 -
  45.218 -    if (lifoSlot_)
  45.219 -        allocate(lifoSlot_);
  45.220 -    for (size_t i = 0; i < names_.length(); i++) {
  45.221 -        if (names_[i]->kind() != BoundName::VARIABLE)
  45.222 -            continue;
  45.223 -
  45.224 -        allocate(names_[i]->toVariable());
  45.225 -    }
  45.226 -
  45.227 -    maxContainedLocals_ += locals_;
  45.228 -}
  45.229 -
  45.230 -bool
  45.231 -Scope::Bind(CompileContext &cc, ParseTree *tree)
  45.232 -{
  45.233 -    Local<String> name(ZONE());
  45.234 -    for (size_t i = 0; i < tree->unbound()->length(); i++) {
  45.235 -        NameProxy *proxy = tree->unbound()->at(i);
  45.236 -        name = proxy->name();
  45.237 -        BoundName *binding = tree->scope()->lookup(name);
  45.238 -
  45.239 -        if (!binding) {
  45.240 -            cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
  45.241 -            return false;
  45.242 -        }
  45.243 -
  45.244 -        // We only allow global functions to be late-bound.
  45.245 -        if (binding->kind() != BoundName::FUNCTION ||
  45.246 -            binding->scope()->kind() != Scope::GLOBAL)
  45.247 -        {
  45.248 -            cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
  45.249 -            return false;
  45.250 -        }
  45.251 -
  45.252 -        proxy->bind(binding);
  45.253 -
  45.254 -        // Find the function the proxy is defined in.
  45.255 -    }
  45.256 -    return true;
  45.257 -}
  45.258 -
  45.259 -void
  45.260 -Scope::Allocate(ParseTree *tree)
  45.261 -{
  45.262 -    tree->scope()->allocateGlobals();
  45.263 -}
  45.264 -
  45.265 -void
  45.266 -Scope::setUsesLifoHeap()
  45.267 -{
  45.268 -    // Only one lifo slot is needed per scope.
  45.269 -    if (lifoSlot_)
  45.270 -        return;
  45.271 -
  45.272 -    // If the parent of this scope is the function scope, then this is the
  45.273 -    // function's block scope, and the lifo slot is part of the Frame instead.
  45.274 -    // Note we can get a function scope here if we're making a temporary in a
  45.275 -    // function with no local variables.
  45.276 -    if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
  45.277 -        return;
  45.278 -
  45.279 -    Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
  45.280 -    if (!type)
  45.281 -        return;
  45.282 -
  45.283 -    Local<String> name(ZONE());
  45.284 -    lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
  45.285 -    lifoSlot_->setType(type);
  45.286 -}
  45.287 -
  45.288 -EnvironmentMap *
  45.289 -Scope::createEnvironmentMap(Zone *zone)
  45.290 -{
  45.291 -    return EnvironmentMap::New(zone, envVars_.length(), envVars_.buffer());
  45.292 -}
    46.1 --- a/src/Scopes.h	Mon Sep 17 00:10:01 2012 -0700
    46.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.3 @@ -1,120 +0,0 @@
    46.4 -/*
    46.5 - * Copyright (C) 2012 David Anderson
    46.6 - *
    46.7 - * This file is part of JITCraft.
    46.8 - *
    46.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   46.10 - * the terms of the GNU General Public License as published by the Free
   46.11 - * Software Foundation, either version 3 of the License, or (at your option)
   46.12 - * any later version.
   46.13 - * 
   46.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   46.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   46.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   46.17 - *
   46.18 - * You should have received a copy of the GNU General Public License along with
   46.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   46.20 - */
   46.21 -#ifndef _include_jitcraft_scopes_h_
   46.22 -#define _include_jitcraft_scopes_h_
   46.23 -
   46.24 -#include "PoolAllocator.h"
   46.25 -#include "AST.h"
   46.26 -#include "NameBinding.h"
   46.27 -#include "Structures.h"
   46.28 -
   46.29 -namespace ke {
   46.30 -
   46.31 -class CompileContext;
   46.32 -class EnvironmentMap;
   46.33 -
   46.34 -class Scope : public PoolObject
   46.35 -{
   46.36 -    PoolAllocator &pool_;
   46.37 -    PoolList<BoundName *> names_;
   46.38 -    PoolList<Scope *> children_;
   46.39 -    PoolList<Variable *> parameters_;
   46.40 -    unsigned locals_;
   46.41 -    unsigned maxContainedLocals_;
   46.42 -    unsigned numFunctions_;
   46.43 -    unsigned numNatives_;
   46.44 -    PoolList<Variable *> envVars_;
   46.45 -    Variable *lifoSlot_;
   46.46 -    
   46.47 -    bool empty() const {
   46.48 -        return names_.length() == 0;
   46.49 -    }
   46.50 -    void unlink();
   46.51 -
   46.52 -  public:
   46.53 -    enum Kind {
   46.54 -        GLOBAL,
   46.55 -        FUNCTION,
   46.56 -        BLOCK
   46.57 -    };
   46.58 -
   46.59 -  public:
   46.60 -    Scope(PoolAllocator &pool, Kind kind, Scope *enclosing);
   46.61 -    bool initialize();
   46.62 -
   46.63 -    Kind kind() const {
   46.64 -        return kind_;
   46.65 -    }
   46.66 -    Scope *enclosing() const {
   46.67 -        return enclosing_;
   46.68 -    }
   46.69 -    unsigned locals() const {
   46.70 -        return locals_;
   46.71 -    }
   46.72 -    unsigned maxContainedLocals() const {
   46.73 -        return maxContainedLocals_;
   46.74 -    }
   46.75 -    unsigned numFunctions() const {
   46.76 -        return numFunctions_;
   46.77 -    }
   46.78 -    unsigned numNatives() const {
   46.79 -        return numNatives_;
   46.80 -    }
   46.81 -    unsigned numArguments() const {
   46.82 -        return parameters_.length();
   46.83 -    }
   46.84 -    unsigned numEnvironmentVars() const {
   46.85 -        return envVars_.length();
   46.86 -    }
   46.87 -    Variable *getArgument(size_t index) {
   46.88 -        return parameters_[index];
   46.89 -    }
   46.90 -    Variable *lifoSlot() {
   46.91 -        return lifoSlot_;
   46.92 -    }
   46.93 -    void setUsesLifoHeap();
   46.94 -
   46.95 -    Scope *unlinkIfEmpty();
   46.96 -    BoundName *localLookup(Handle<String> name);
   46.97 -    BoundName *lookup(Handle<String> name);
   46.98 -
   46.99 -    NamedFunction *declareFunction(Handle<String> name, const SourcePosition &pos, TokenKind token);
  46.100 -    Variable *declareVariable(Handle<String> name, const SourcePosition &pos);
  46.101 -    Variable *declareArgument(Handle<String> name, const SourcePosition &pos);
  46.102 -    NamedConstant *declareConstant(Handle<String> name, const SourcePosition &pos);
  46.103 -    NamedType *declareType(Handle<String> name, const SourcePosition &pos);
  46.104 -    NamedType *declareType(Handle<String> name, Handle<Type> type);
  46.105 -
  46.106 -    EnvironmentMap *createEnvironmentMap(Zone *zone);
  46.107 -
  46.108 -    void allocate(Variable *var);
  46.109 -    void allocate();
  46.110 -    void allocateGlobals();
  46.111 -
  46.112 -  public:
  46.113 -    static bool Bind(CompileContext &cc, ParseTree *tree);
  46.114 -    static void Allocate(ParseTree *tree);
  46.115 -
  46.116 -  private:
  46.117 -    Kind kind_;
  46.118 -    Scope *enclosing_;
  46.119 -};
  46.120 -
  46.121 -}
  46.122 -
  46.123 -#endif // _include_jitcraft_scopes_h_
    47.1 --- a/src/SemanticAnalysis.cpp	Mon Sep 17 00:10:01 2012 -0700
    47.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.3 @@ -1,1887 +0,0 @@
    47.4 -/* vim: set ts=4 sw=4 tw=99 et:
    47.5 - *
    47.6 - * Copyright (C) 2012 David Anderson
    47.7 - *
    47.8 - * This file is part of JITCraft.
    47.9 - *
   47.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   47.11 - * the terms of the GNU General Public License as published by the Free
   47.12 - * Software Foundation, either version 3 of the License, or (at your option)
   47.13 - * any later version.
   47.14 - * 
   47.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   47.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   47.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   47.18 - *
   47.19 - * You should have received a copy of the GNU General Public License along with
   47.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   47.21 - */
   47.22 -#include <string.h>
   47.23 -#include "SemanticAnalysis.h"
   47.24 -#include "Types.h"
   47.25 -#include "Zone.h"
   47.26 -#include "TypeManager.h"
   47.27 -#include "Scopes.h"
   47.28 -#include "NameBinding.h"
   47.29 -#include "Strings.h"
   47.30 -#include "Box.h"
   47.31 -#include "Array.h"
   47.32 -#include "Heap-inl.h"
   47.33 -
   47.34 -using namespace ke;
   47.35 -
   47.36 -static inline bool
   47.37 -IsPrimitiveType(Type *type, PrimitiveType primitive)
   47.38 -{
   47.39 -    if (!type)
   47.40 -        return false;
   47.41 -
   47.42 -    if (!type->isPrimitive())
   47.43 -        return false;
   47.44 -
   47.45 -    return primitive == type->primitive();
   47.46 -}
   47.47 -
   47.48 -static inline bool
   47.49 -EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
   47.50 -                        BoxedPrimitive *out)
   47.51 -{
   47.52 -    switch (kind) {
   47.53 -      case TOK_PLUS:
   47.54 -        *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
   47.55 -        return true;
   47.56 -
   47.57 -      case TOK_SHL:
   47.58 -        *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
   47.59 -        return true;
   47.60 -
   47.61 -      default:
   47.62 -        return false;
   47.63 -    }
   47.64 -}
   47.65 -
   47.66 -static inline bool
   47.67 -EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
   47.68 -{
   47.69 -  switch (kind) {
   47.70 -    case TOK_MINUS:
   47.71 -      *out = BoxedPrimitive::Int(-inner.toInt());
   47.72 -      return true;
   47.73 -
   47.74 -    default:
   47.75 -      return false;
   47.76 -  }
   47.77 -}
   47.78 -
   47.79 -static bool
   47.80 -EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
   47.81 -{
   47.82 -    switch (expression->kind()) {
   47.83 -      case AstNode::kBinaryExpression:
   47.84 -      {
   47.85 -        BoxedPrimitive left;
   47.86 -        BoxedPrimitive right;
   47.87 -        BinaryExpression *b = expression->toBinaryExpression();
   47.88 -        if (!EvaluateForConstant(b->left(), &left) ||
   47.89 -            !EvaluateForConstant(b->right(), &right))
   47.90 -        {
   47.91 -            return false;
   47.92 -        }
   47.93 -        return EvaluateBinaryOperation(b->token(), left, right, out);
   47.94 -      }
   47.95 -
   47.96 -      case AstNode::kUnaryExpression:
   47.97 -      {
   47.98 -        BoxedPrimitive inner;
   47.99 -        UnaryExpression *u = expression->toUnaryExpression();
  47.100 -        if (!EvaluateForConstant(u->expression(), &inner))
  47.101 -            return false;
  47.102 -        return EvaluateUnaryOperation(u->token(), inner, out);
  47.103 -      }
  47.104 -
  47.105 -      case AstNode::kNameProxy:
  47.106 -      {
  47.107 -        NameProxy *proxy = expression->toNameProxy();
  47.108 -        if (proxy->binding()->kind() != BoundName::CONSTANT)
  47.109 -            return false;
  47.110 -
  47.111 -        NamedConstant *c = proxy->binding()->toNamedConstant();
  47.112 -        if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
  47.113 -            return false;
  47.114 -
  47.115 -        *out = c->value();
  47.116 -        return true;
  47.117 -      }
  47.118 -
  47.119 -      case AstNode::kBooleanLiteral:
  47.120 -        *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
  47.121 -        return true;
  47.122 -
  47.123 -      case AstNode::kIntegerLiteral:
  47.124 -        *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
  47.125 -        return true;
  47.126 -
  47.127 -      default:
  47.128 -        return false;
  47.129 -    }
  47.130 -}
  47.131 -
  47.132 -SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
  47.133 -  : zone_(zone),
  47.134 -    cc_(cc),
  47.135 -    tree_(tree),
  47.136 -    scope_(NULL),
  47.137 -    loop_(NULL)
  47.138 -{
  47.139 -}
  47.140 -
  47.141 -bool
  47.142 -SemanticAnalysis::analyze()
  47.143 -{
  47.144 -    if (cc_.failures())
  47.145 -        return false;
  47.146 -
  47.147 -    scope_ = tree_->scope();
  47.148 -
  47.149 -    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  47.150 -        Statement *statement = tree_->statements()->at(i);
  47.151 -        if (statement->isFunctionStatement()) {
  47.152 -            FunctionStatement *funstmt = statement->toFunctionStatement();
  47.153 -            if (!preanalyze(funstmt))
  47.154 -                return false;
  47.155 -        } else if (statement->isEnumStatement()) {
  47.156 -            EnumStatement *enumstmt = statement->toEnumStatement();
  47.157 -
  47.158 -            // We pre-fill global enum types, since they may occur in function
  47.159 -            // signatures. This should probably be somewhere else...
  47.160 -            enumstmt->accept(this);
  47.161 -        } else if (statement->isStructureStatement()) {
  47.162 -            StructureStatement *node = statement->toStructureStatement();
  47.163 -            node->accept(this);
  47.164 -            if (!node->decl()->type())
  47.165 -                return false;
  47.166 -        } else if (statement->isFunctionTypeStatement()) {
  47.167 -            FunctionTypeStatement *node = statement->toFunctionTypeStatement();
  47.168 -            node->accept(this);
  47.169 -            if (!node->decl()->type())
  47.170 -                return false;
  47.171 -        }
  47.172 -    }
  47.173 -
  47.174 -    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  47.175 -        Statement *statement = tree_->statements()->at(i);
  47.176 -
  47.177 -        // We can't double-process these. Maybe put this check somewhere else.
  47.178 -        if (statement->isEnumStatement())
  47.179 -            continue;
  47.180 -
  47.181 -        statement->accept(this);
  47.182 -    }
  47.183 -
  47.184 -    if (!determineLiveFunctions())
  47.185 -        return false;
  47.186 -
  47.187 -    return !cc_.failures();
  47.188 -}
  47.189 -
  47.190 -bool
  47.191 -SemanticAnalysis::determineLiveFunctions()
  47.192 -{
  47.193 -    Vector<NamedFunction *> worklist;
  47.194 -
  47.195 -    // Add the root set.
  47.196 -    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  47.197 -        Statement *statement = tree_->statements()->at(i);
  47.198 -        if (!statement->isFunctionStatement())
  47.199 -            continue;
  47.200 -
  47.201 -        FunctionStatement *stmt = statement->toFunctionStatement();
  47.202 -        NamedFunction  *fun = stmt->fun();
  47.203 -        if (!fun->used())
  47.204 -            continue;
  47.205 -
  47.206 -        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
  47.207 -            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
  47.208 -
  47.209 -            // Names in these lists are always unused, however, we mark them
  47.210 -            // as used while inserting into the work queue, to avoid double-
  47.211 -            // insertion.
  47.212 -            if (name->used())
  47.213 -                continue;
  47.214 -
  47.215 -            if (!worklist.append(name))
  47.216 -                return false;
  47.217 -
  47.218 -            name->setUsed();
  47.219 -        }
  47.220 -    }
  47.221 -
  47.222 -    while (!worklist.empty()) {
  47.223 -        NamedFunction *fun = worklist.popCopy();
  47.224 -
  47.225 -        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
  47.226 -            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
  47.227 -            if (name->used())
  47.228 -                continue;
  47.229 -            if (!worklist.append(name))
  47.230 -                return false;
  47.231 -            name->setUsed();
  47.232 -        }
  47.233 -    }
  47.234 -
  47.235 -    return true;
  47.236 -}
  47.237 -
  47.238 -Type *
  47.239 -SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name)
  47.240 -{
  47.241 -    if (!name)
  47.242 -        return zone_->types()->getPrimitive(PrimitiveType_Int32);
  47.243 -
  47.244 -    if (name->kind() == BoundName::UNBOUND) {
  47.245 -        cc_.reportError(pos, Message_TypeNotFound, name->name()->chars());
  47.246 -        return NULL;
  47.247 -    }
  47.248 -
  47.249 -    if (name->kind() != BoundName::TYPE) {
  47.250 -        cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars());
  47.251 -        return NULL;
  47.252 -    }
  47.253 -
  47.254 -    if (!name->type())
  47.255 -        return NULL;
  47.256 -
  47.257 -    return name->type();
  47.258 -}
  47.259 -
  47.260 -Type *
  47.261 -SemanticAnalysis::visitAndApplyType(Expression *expression)
  47.262 -{
  47.263 -    expression->accept(this);
  47.264 -    return expression->type();
  47.265 -}
  47.266 -
  47.267 -Type *
  47.268 -SemanticAnalysis::visitForLoad(Expression *expression)
  47.269 -{
  47.270 -    Local<Type> type(zone_, visitAndApplyType(expression));
  47.271 -    if (!type)
  47.272 -        return NULL;
  47.273 -
  47.274 -    if (type->isReference()) {
  47.275 -        expression->setType(type->contained());
  47.276 -    } else if (expression->isCallExpression()) {
  47.277 -        if (type->isVoid()) {
  47.278 -            CallExpression *call = expression->toCallExpression();
  47.279 -            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
  47.280 -            return NULL;
  47.281 -        }
  47.282 -    }
  47.283 -
  47.284 -    return expression->type();
  47.285 -}
  47.286 -
  47.287 -// :TODO: this leaks an interior pointer.
  47.288 -const char *
  47.289 -ke::GetTypeName(Type *type)
  47.290 -{
  47.291 -    if (type->isArray())
  47.292 -        return "array";
  47.293 -    if (type->isFunction())
  47.294 -        return "function";
  47.295 -    if (type->isVoid())
  47.296 -        return "void";
  47.297 -    if (type->isEnum() || type->isStruct())
  47.298 -        return type->name()->chars();
  47.299 -    if (type->isReference())
  47.300 -        type = type->contained();
  47.301 -    switch (type->primitive()) {
  47.302 -      case PrimitiveType_Bool:
  47.303 -        return "bool";
  47.304 -      case PrimitiveType_Char:
  47.305 -        return "String";
  47.306 -      case PrimitiveType_Int32:
  47.307 -        return "int";
  47.308 -      case PrimitiveType_Float:
  47.309 -        return "Float";
  47.310 -      default:
  47.311 -        return "<unknown>";
  47.312 -    }
  47.313 -}
  47.314 -
  47.315 -void
  47.316 -SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type)
  47.317 -{
  47.318 -    const char *op = TokenNames[token];
  47.319 -    const char *name = GetTypeName(type);
  47.320 -
  47.321 -    cc_.reportError(node->pos(), Message_UnaryTypeError, op, name);
  47.322 -}
  47.323 -
  47.324 -void
  47.325 -SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
  47.326 -{
  47.327 -    const char *op = TokenNames[token];
  47.328 -    const char *leftName = GetTypeName(left);
  47.329 -    const char *rightName = GetTypeName(right);
  47.330 -
  47.331 -    cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName);
  47.332 -}
  47.333 -
  47.334 -Type *
  47.335 -SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
  47.336 -{
  47.337 -    if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
  47.338 -        (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
  47.339 -    {
  47.340 -        // If either side is a float, the other side must be a float or int.
  47.341 -        if (left->isFloat() || right->isFloat()) {
  47.342 -            Type *floatType = left->isFloat() ? left : right;
  47.343 -            Type *other = left->isFloat() ? right : left;
  47.344 -            if (other->isFloat() || other->isInt32())
  47.345 -                return floatType;
  47.346 -        }
  47.347 -    }
  47.348 -
  47.349 -    if (token == TOK_OR || token == TOK_AND) {
  47.350 -        if (!canTest(node, left) || !canTest(node, right))
  47.351 -            return NULL;
  47.352 -        return zone_->types()->getPrimitive(PrimitiveType_Bool);
  47.353 -    }
  47.354 -
  47.355 -    if (token >= TOK_EQUALS && token <= TOK_GE) {
  47.356 -        if ((left->isFloat() || left->isInt32()) &&
  47.357 -            (right->isFloat() || right->isInt32()))
  47.358 -        {
  47.359 -            return zone_->types()->getPrimitive(PrimitiveType_Bool);
  47.360 -        }
  47.361 -        binaryTypeError(node, token, left, right);
  47.362 -        return NULL;
  47.363 -    }
  47.364 -
  47.365 -    if (!left->isInt32() || !right->isInt32()) {
  47.366 -        binaryTypeError(node, token, left, right);
  47.367 -        return NULL;
  47.368 -    }
  47.369 -
  47.370 -    return left;
  47.371 -}
  47.372 -
  47.373 -bool
  47.374 -SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
  47.375 -{
  47.376 -    if (!type->isPrimitive() && !type->isEnum()) {
  47.377 -        cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
  47.378 -        return false;
  47.379 -    }
  47.380 -    return true;
  47.381 -}
  47.382 -
  47.383 -Type *
  47.384 -SemanticAnalysis::visitForLValue(Expression *expression)
  47.385 -{
  47.386 -    if (expression->isIndexExpression()) {
  47.387 -        Type *type = visitAndApplyType(expression);
  47.388 -        if (!type)
  47.389 -            return NULL;
  47.390 -
  47.391 -        // if (type->isConst()) {
  47.392 -        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  47.393 -        //     return NULL;
  47.394 -        // }
  47.395 -
  47.396 -        return type;
  47.397 -    }
  47.398 -
  47.399 -    if (expression->isFieldExpression()) {
  47.400 -        Type *type = visitAndApplyType(expression);
  47.401 -        if (!type)
  47.402 -            return NULL;
  47.403 -
  47.404 -        // if (expression->toFieldExpression()->left()->type()->isConst()) {
  47.405 -        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  47.406 -        //     return NULL;
  47.407 -        // }
  47.408 -
  47.409 -        return type;
  47.410 -    }
  47.411 -
  47.412 -    if (!expression->isNameProxy()) {
  47.413 -        cc_.reportError(expression->pos(), Message_ExpectedLValue);
  47.414 -        return NULL;
  47.415 -    }
  47.416 -
  47.417 -    NameProxy *proxy = expression->toNameProxy();
  47.418 -    if (!proxy->binding()->kind() == BoundName::VARIABLE) {
  47.419 -        cc_.reportError(expression->pos(), Message_ExpectedLValue);
  47.420 -        return NULL;
  47.421 -    }
  47.422 -
  47.423 -    Variable *var = proxy->binding()->toVariable();
  47.424 -    if (!var->type())
  47.425 -        return NULL;
  47.426 -
  47.427 -    if  (var->type()->isReference()) {
  47.428 -        if (var->type()->isConst()) {
  47.429 -            cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  47.430 -            return NULL;
  47.431 -        }
  47.432 -        return var->type()->contained();
  47.433 -    }
  47.434 -    return var->type();
  47.435 -}
  47.436 -
  47.437 -SemanticAnalysis::ControlStatus
  47.438 -SemanticAnalysis::visitForControl(Statement *statement)
  47.439 -{
  47.440 -    ControlScope scope(&control_);
  47.441 -    statement->accept(this);
  47.442 -    return scope.status();
  47.443 -}
  47.444 -
  47.445 -void
  47.446 -SemanticAnalysis::visit(NameProxy *name)
  47.447 -{
  47.448 -    BoundName *binding = name->binding();
  47.449 -
  47.450 -    if (binding->scope()->kind() == Scope::GLOBAL) {
  47.451 -        if (!function_ || function_->isPublic()) {
  47.452 -            // Whatever we're referencing must be kept alive no matter what.
  47.453 -            // As such, we simply mark it used, and don't do anything special.
  47.454 -            binding->setUsed();
  47.455 -        } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) {
  47.456 -            // Otherwise, we're inside a normal stock or function. Since we
  47.457 -            // don't really know if we've been used yet, we shouldn't
  47.458 -            // prematurely references as alive. Instead, we keep a list of
  47.459 -            // which names have been used, so we can mark them later if needed.
  47.460 -            //
  47.461 -            // Note that we skip this step if the binding is already in the
  47.462 -            // root set.
  47.463 -            if (!function_->addUsedGlobal(binding))
  47.464 -                return;
  47.465 -        }
  47.466 -    }
  47.467 -
  47.468 -    name->setType(binding->type());
  47.469 -}
  47.470 -
  47.471 -void
  47.472 -SemanticAnalysis::visit(Assignment *node)
  47.473 -{
  47.474 -    Local<Type> exprType(zone_, visitForLoad(node->expression()));
  47.475 -    if (!exprType)
  47.476 -        return ;
  47.477 -
  47.478 -    Local<Type> type(zone_, visitForLValue(node->lvalue()));
  47.479 -    if (!type)
  47.480 -        return;
  47.481 -
  47.482 -    if (node->token() != TOK_ASSIGN) {
  47.483 -        if (!typeCheckBinary(node, node->token(), type, exprType))
  47.484 -            return;
  47.485 -    }
  47.486 -
  47.487 -    if (!typeCheckAssignment(node->pos(), exprType, type, true))
  47.488 -        return;
  47.489 -
  47.490 -    node->setType(type);
  47.491 -}
  47.492 -
  47.493 -void
  47.494 -SemanticAnalysis::visit(IncDecExpression *node)
  47.495 -{
  47.496 -    Local<Type> type(zone_, visitForLValue(node->expression()));
  47.497 -    if (!type)
  47.498 -        return;
  47.499 -
  47.500 -    assert(!type->isReference());
  47.501 -
  47.502 -    if (!type->isInt32() && !type->isFloat()) {
  47.503 -        unaryTypeError(node, node->token(), type);
  47.504 -        return;
  47.505 -    }
  47.506 -
  47.507 -    node->setType(type);
  47.508 -}
  47.509 -
  47.510 -void
  47.511 -SemanticAnalysis::visit(UnaryExpression *node)
  47.512 -{
  47.513 -    Local<Type> type(zone_, visitForLoad(node->expression()));
  47.514 -    if (!type)
  47.515 -        return;
  47.516 -
  47.517 -    switch (node->token())
  47.518 -    {
  47.519 -      case TOK_NOT:
  47.520 -        if (!canTest(node->expression(), type))
  47.521 -            return;
  47.522 -        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
  47.523 -        if (!type)
  47.524 -            return;
  47.525 -        node->setType(type);
  47.526 -        break;
  47.527 -
  47.528 -      case TOK_MINUS:
  47.529 -        if (!type->isFloat() && !type->isInt32()) {
  47.530 -            unaryTypeError(node, node->token(), type);
  47.531 -            return;
  47.532 -        }
  47.533 -        node->setType(type);
  47.534 -        break;
  47.535 -
  47.536 -      case TOK_LABEL:
  47.537 -      {
  47.538 -        Local<Type> to(zone_, bindType(node->pos(), node->type()));
  47.539 -        if (!to)
  47.540 -            return;
  47.541 -
  47.542 -        if ((!type->isFloat() && !type->isInt32OrEnum()) ||
  47.543 -            (!to->isFloat() && !to->isInt32OrEnum()))
  47.544 -        {
  47.545 -            unaryTypeError(node, node->token(), type);
  47.546 -            return;
  47.547 -        }
  47.548 -
  47.549 -        node->setType(to);
  47.550 -        break;
  47.551 -      }
  47.552 -
  47.553 -      case TOK_SIZEOF:
  47.554 -      {
  47.555 -        if (!type->isArray()) {
  47.556 -            cc_.reportError(node->pos(), Message_SizeofNeedsArray);
  47.557 -            return;
  47.558 -        }
  47.559 -        node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
  47.560 -        break;
  47.561 -      }
  47.562 -
  47.563 -      default:
  47.564 -        assert(node->token() == TOK_TILDE);
  47.565 -        if (!type->isInt32()) {
  47.566 -            unaryTypeError(node, node->token(), type);
  47.567 -            return;
  47.568 -        }
  47.569 -        node->setType(type);
  47.570 -        break;
  47.571 -    }
  47.572 -}
  47.573 -
  47.574 -void
  47.575 -SemanticAnalysis::visit(TernaryExpression *node)
  47.576 -{
  47.577 -    Local<Type> type(zone_, visitForLoad(node->condition()));
  47.578 -    if (!type)
  47.579 -        return;
  47.580 -
  47.581 -    if (!canTest(node->condition(), type))
  47.582 -        return;
  47.583 -
  47.584 -    Local<Type> left(zone_, visitForLoad(node->left()));
  47.585 -    Local<Type> right(zone_, visitForLoad(node->right()));
  47.586 -    if (!left || !right)
  47.587 -        return;
  47.588 -
  47.589 -    if (left != right) {
  47.590 -        binaryTypeError(node, TOK_QMARK, left, right);
  47.591 -        return;
  47.592 -    }
  47.593 -}
  47.594 -
  47.595 -void
  47.596 -SemanticAnalysis::visit(BinaryExpression *node)
  47.597 -{
  47.598 -    Local<Type> left(zone_, visitForLoad(node->left()));
  47.599 -    Local<Type> right(zone_, visitForLoad(node->right()));
  47.600 -    if (!left || !right)
  47.601 -        return;
  47.602 -
  47.603 -    Local<Type> result(zone_, typeCheckBinary(node, node->token(), left, right));
  47.604 -    if (!result)
  47.605 -        return;
  47.606 -
  47.607 -    node->setType(result);
  47.608 -}
  47.609 -
  47.610 -void
  47.611 -SemanticAnalysis::visit(ReturnStatement *node)
  47.612 -{
  47.613 -    // Set this early, so if we error we don't get more errors.
  47.614 -    control_->returns(Returns_Always);
  47.615 -
  47.616 -    if (!node->expression()) {
  47.617 -        if (!function_->type()->returnType()->isVoid())
  47.618 -            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
  47.619 -        return;
  47.620 -    }
  47.621 -
  47.622 -    Local<Type> type(zone_, visitForLoad(node->expression()));
  47.623 -    if (!type)
  47.624 -        return;
  47.625 -
  47.626 -    Local<Type> returnType(zone_, function_->type()->returnType());
  47.627 -    if (!typeCheckAssignment(node->pos(), type, returnType, true))
  47.628 -        return;
  47.629 -}
  47.630 -
  47.631 -void
  47.632 -SemanticAnalysis::visit(ForStatement *node)
  47.633 -{
  47.634 -    LoopScope loop(&loop_);
  47.635 -
  47.636 -    if (node->scope())
  47.637 -        scope_ = node->scope();
  47.638 -
  47.639 -    if (node->initialization())
  47.640 -        node->initialization()->accept(this);
  47.641 -
  47.642 -    if (node->condition()) {
  47.643 -        Local<Type> type(zone_, visitForLoad(node->condition()));
  47.644 -        if (!type || !canTest(node->condition(), type)) {
  47.645 -            return;
  47.646 -        }
  47.647 -    }
  47.648 -
  47.649 -    if (node->update())
  47.650 -        node->update()->accept(this);
  47.651 -
  47.652 -    ControlStatus status = visitForControl(node->body());
  47.653 -
  47.654 -    // If there is a condition, we treat this like a while loop. Otherwise,
  47.655 -    // join point is only reachable if the loop contains a break. The
  47.656 -    // termination status doesn't tell us anything yet.
  47.657 -    if (node->condition() || loop.breaks())
  47.658 -        control_->merge(status, ControlStatus(false, Returns_Never));
  47.659 -    else
  47.660 -        control_->terminate(status.returns());
  47.661 -
  47.662 -    if (node->scope())
  47.663 -        scope_ = scope_->enclosing();
  47.664 -}
  47.665 -
  47.666 -void 
  47.667 -SemanticAnalysis::visit(WhileStatement *node)
  47.668 -{
  47.669 -    LoopScope loop(&loop_);
  47.670 -
  47.671 -    Local<Type> type(zone_, visitForLoad(node->condition()));
  47.672 -    if (!type || !canTest(node->condition(), type)) {
  47.673 -        return;
  47.674 -    }
  47.675 -
  47.676 -    ControlStatus status = visitForControl(node->body());
  47.677 -
  47.678 -    // Detect loops that will always have a fork in the control-flow graph.
  47.679 -    // This will be a |while| loop, or a |do-while| loop whose body does
  47.680 -    // not terminate.
  47.681 -    //
  47.682 -    // For now, we treat these as an |if| regardless of the direction the
  47.683 -    // branch can take. That means the control-flow is always conditional.
  47.684 -    if (node->token() == TOK_WHILE ||
  47.685 -        !status.terminates() ||
  47.686 -        loop.breaks())
  47.687 -    {
  47.688 -        control_->merge(status, ControlStatus(false, Returns_Never));
  47.689 -    } else {
  47.690 -        // At this point, we've got a do-while loop with a |return| or
  47.691 -        // |continue|, meaning that the rest of the block is unreachable.
  47.692 -        control_->terminate(status.returns());
  47.693 -    }
  47.694 -}
  47.695 -
  47.696 -void
  47.697 -SemanticAnalysis::visit(BlockStatement *node)
  47.698 -{
  47.699 -    if (node->scope())
  47.700 -        scope_ = node->scope();
  47.701 -    for (size_t i = 0; i < node->statements()->length(); i++) {
  47.702 -        Statement *statement = node->statements()->at(i);
  47.703 -        statement->accept(this);
  47.704 -    }
  47.705 -    if (node->scope())
  47.706 -        scope_ = scope_->enclosing();
  47.707 -}
  47.708 -
  47.709 -static inline bool
  47.710 -IsScalarString(Type *type)
  47.711 -{
  47.712 -    if (type->isPrimitive() && type->primitive() == PrimitiveType_Char)
  47.713 -        return true;
  47.714 -    if (type->isReference())
  47.715 -        return IsScalarString(type->contained());
  47.716 -    return false;
  47.717 -}
  47.718 -
  47.719 -static const int INFER_ARRAY_SIZE = 0;
  47.720 -static const int EVAL_ARRAY_SIZE = -1;
  47.721 -static const int DYNAMIC_ARRAY_SIZE = -2;
  47.722 -
  47.723 -bool
  47.724 -SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH])
  47.725 -{
  47.726 -    bool hadEmptySize = false;
  47.727 -
  47.728 -    for (size_t i = 0; i < exprs->length(); i++) {
  47.729 -        Expression *expr = exprs->at(i);
  47.730 -        if (!expr) {
  47.731 -            dims[i] = INFER_ARRAY_SIZE;
  47.732 -            hadEmptySize = true;
  47.733 -            continue;
  47.734 -        }
  47.735 -
  47.736 -        BoxedPrimitive box;
  47.737 -        if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
  47.738 -            int size = box.toInt();
  47.739 -            if (size <= 0) {
  47.740 -                cc_.reportError(expr->pos(), Message_BadArraySize);
  47.741 -                return false;
  47.742 -            }
  47.743 -
  47.744 -            dims[i] = size;
  47.745 -            continue;
  47.746 -        }
  47.747 -
  47.748 -        Local<Type> exprType(zone_, visitForLoad(expr));
  47.749 -        if (!exprType)
  47.750 -            return false;
  47.751 -
  47.752 -        if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
  47.753 -            cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
  47.754 -            return false;
  47.755 -        }
  47.756 -
  47.757 -        if (hadEmptySize) {
  47.758 -            cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
  47.759 -            return false;
  47.760 -        }
  47.761 -
  47.762 -        dims[i] = EVAL_ARRAY_SIZE;
  47.763 -    }
  47.764 -
  47.765 -    return true;
  47.766 -}
  47.767 -
  47.768 -bool
  47.769 -SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle<Type> contained,
  47.770 -                                         int dims[MAX_ARRAY_DEPTH],
  47.771 -                                         unsigned dimcount, unsigned level)
  47.772 -{
  47.773 -    if (dims[level] == EVAL_ARRAY_SIZE) {
  47.774 -        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
  47.775 -        return false;
  47.776 -    }
  47.777 -
  47.778 -    if (dims[level] == INFER_ARRAY_SIZE) {
  47.779 -        // Strings always become dynamic arrays.
  47.780 -        if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char))
  47.781 -            dims[level] = literal->expressions()->length();
  47.782 -    } else if (dims[level] == DYNAMIC_ARRAY_SIZE) {
  47.783 -        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
  47.784 -        return false;
  47.785 -    } else {
  47.786 -        if (literal->expressions()->length() != unsigned(dims[level])) {
  47.787 -            cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1);
  47.788 -            return false;
  47.789 -        }
  47.790 -    }
  47.791 -
  47.792 -    if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) {
  47.793 -        for (size_t i = 0; i < literal->expressions()->length(); i++) {
  47.794 -            Expression *expr = literal->expressions()->at(i);
  47.795 -            if (!expr->isStringLiteral()) {
  47.796 -                cc_.reportError(expr->pos(), Message_ExpectedStringLiteral);
  47.797 -                return false;
  47.798 -            }
  47.799 -
  47.800 -            StringLiteral *lit = expr->toStringLiteral();
  47.801 -            if (dims[level + 1] > 0 &&
  47.802 -                unsigned(dims[level]) < lit->string()->length())
  47.803 -            {
  47.804 -                cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2);
  47.805 -                return false;
  47.806 -            }
  47.807 -            if (!visitAndApplyType(lit))
  47.808 -                return false;
  47.809 -        }
  47.810 -    } else if (level == dimcount - 1) {
  47.811 -        Local<Type> type(zone_);
  47.812 -        for (size_t i = 0; i < literal->expressions()->length(); i++) {
  47.813 -            Expression *expr = literal->expressions()->at(i);
  47.814 -            if (expr->isArrayLiteral()) {
  47.815 -                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
  47.816 -                return false;
  47.817 -            }
  47.818 -
  47.819 -            if ((type = visitAndApplyType(expr)) == NULL)
  47.820 -                return false;
  47.821 -
  47.822 -            if (!typeCheckAssignment(expr->pos(), type, contained, true))
  47.823 -                return false;
  47.824 -        }
  47.825 -    } else {
  47.826 -        for (size_t i = 0; i < literal->expressions()->length(); i++) {
  47.827 -            Expression *expr = literal->expressions()->at(i);
  47.828 -            if (!expr->isArrayLiteral()) {
  47.829 -                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
  47.830 -                return false;
  47.831 -            }
  47.832 -
  47.833 -            assert(expr->toArrayLiteral()->isFixed());
  47.834 -
  47.835 -            if (!inferFixedArrayLiteral(expr->toArrayLiteral(),
  47.836 -                                        contained,
  47.837 -                                        dims,
  47.838 -                                        dimcount,
  47.839 -                                        level + 1))
  47.840 -            {
  47.841 -                return false;
  47.842 -            }
  47.843 -        }
  47.844 -    }
  47.845 -
  47.846 -    return true;
  47.847 -}
  47.848 -
  47.849 -void
  47.850 -SemanticAnalysis::visit(VariableDeclaration *node)
  47.851 -{
  47.852 -    Local<Type> type(zone_, bindType(node->pos(), node->type()));
  47.853 -    if (!type)
  47.854 -        return;
  47.855 -
  47.856 -    if (node->postDimensions() || type->isArray()) {
  47.857 -        // The type could be an array type, so sum the type and postDimensions
  47.858 -        // together.
  47.859 -        unsigned dimcount = node->postDimensions()->length();
  47.860 -        if (type->isArray())
  47.861 -            dimcount += type->levels();
  47.862 -        if (dimcount > MAX_ARRAY_DEPTH) {
  47.863 -            cc_.reportError(node->pos(), Message_MaximumArrayDepth);
  47.864 -            return;
  47.865 -        }
  47.866 -
  47.867 -        // Take an initial guess at the array dimension sizes.
  47.868 -        int dims[MAX_ARRAY_DEPTH];
  47.869 -        if (!evaluateDimensions(node->postDimensions(), dims))
  47.870 -            return;
  47.871 -
  47.872 -        // Now add in the type's array dimensions.
  47.873 -        Local<Type> contained(zone_, type);
  47.874 -        for (size_t i = node->postDimensions()->length(); i < dimcount; i++) {
  47.875 -            if (type->isFixedLength())
  47.876 -                dims[i] = type->fixedLength();
  47.877 -            else
  47.878 -                dims[i] = DYNAMIC_ARRAY_SIZE;
  47.879 -            contained = contained->contained();
  47.880 -        }
  47.881 -
  47.882 -        Expression *initializer = node->initialization();
  47.883 -        if (initializer &&
  47.884 -            initializer->isArrayLiteral() &&
  47.885 -            initializer->toArrayLiteral()->isFixed())
  47.886 -        {
  47.887 -            // Fixed array initializers are special; we use them to infer any
  47.888 -            // missing information in the original array. We do not evaluate
  47.889 -            // the array initializer as an expression.
  47.890 -            if (!inferFixedArrayLiteral(initializer->toArrayLiteral(),
  47.891 -                                        contained,
  47.892 -                                        dims,
  47.893 -                                        dimcount,
  47.894 -                                        0))
  47.895 -            {
  47.896 -                return;
  47.897 -            }
  47.898 -            initializer = NULL;
  47.899 -        }
  47.900 -
  47.901 -        // We now have enough information to build the actual array type.
  47.902 -        // Start from the original dimcount, not the one computed for
  47.903 -        // initializers.
  47.904 -        for (size_t i = node->postDimensions()->length() - 1;
  47.905 -             i < node->postDimensions()->length();
  47.906 -             i--)
  47.907 -        {
  47.908 -            int size = dims[i] > 0
  47.909 -                       ? dims[i]
  47.910 -                       : Type::DYNAMIC_ARRAY_SIZE;
  47.911 -
  47.912 -            type = zone_->types()->newArray(type, size, false);
  47.913 -            if (!type)
  47.914 -                return;
  47.915 -        }
  47.916 -
  47.917 -        // Finally, if we had a non-fixed initializer, make sure it type
  47.918 -        // checks. 
  47.919 -        if (initializer) {
  47.920 -            Local<Type> right(zone_, visitForLoad(initializer));
  47.921 -            if (!right)
  47.922 -                return;
  47.923 -
  47.924 -            if (!typeCheckAssignment(node->pos(), right, type, true))
  47.925 -                return;
  47.926 -        }
  47.927 -    } else {
  47.928 -        if (node->initialization()) {
  47.929 -            Local<Type> right(zone_, visitForLoad(node->initialization()));
  47.930 -            if (!right)
  47.931 -                return;
  47.932 -            if (!typeCheckAssignment(node->pos(), right, type, true))
  47.933 -                return;
  47.934 -        }
  47.935 -
  47.936 -        if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) {
  47.937 -            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
  47.938 -            return;
  47.939 -        }
  47.940 -    }
  47.941 -
  47.942 -    // If this variable is stack allocated, we could use the LIFO heap
  47.943 -    // to allocate it. If that's the case, make sure to reserve a slot
  47.944 -    // so we can unwind the LIFO heap at the end of this scope.
  47.945 -    if (!node->variable()->needsHeapAllocation()) {
  47.946 -        if (type->isArray() || type->isStruct())
  47.947 -            scope_->setUsesLifoHeap();
  47.948 -    }
  47.949 -
  47.950 -    node->variable()->setType(type);
  47.951 -}
  47.952 -
  47.953 -void
  47.954 -SemanticAnalysis::visit(IntegerLiteral *node)
  47.955 -{
  47.956 -    node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
  47.957 -}
  47.958 -
  47.959 -void
  47.960 -SemanticAnalysis::visit(BooleanLiteral *node)
  47.961 -{
  47.962 -    node->setType(zone_->types()->getPrimitive(PrimitiveType_Bool));
  47.963 -}
  47.964 -
  47.965 -void
  47.966 -SemanticAnalysis::visit(ExpressionStatement *node)
  47.967 -{
  47.968 -    visitAndApplyType(node->expression());
  47.969 -}
  47.970 -
  47.971 -Box *
  47.972 -SemanticAnalysis::evaluateDefaultParameter(Handle<Type> type, Parameter *parameter)
  47.973 -{
  47.974 -    Local<Type> given(zone_, visitForLoad(parameter->initializer()));
  47.975 -
  47.976 -    BoxedPrimitive prim;
  47.977 -    if (EvaluateForConstant(parameter->initializer(), &prim)) {
  47.978 -        if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
  47.979 -            return NULL;
  47.980 -
  47.981 -        if (prim.type() == PrimitiveType_Int32)
  47.982 -            return Box::New(zone_, given, prim.toInt());
  47.983 -        return Box::New(zone_, given, prim.toFloat());
  47.984 -    } else if (parameter->initializer()->isStringLiteral()) {
  47.985 -        StringLiteral *literal = parameter->initializer()->toStringLiteral();
  47.986 -
  47.987 -        if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
  47.988 -            return NULL;
  47.989 -
  47.990 -        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, given));
  47.991 -        if (!map)
  47.992 -            return NULL;
  47.993 -
  47.994 -        Local<Array> array(zone_,
  47.995 -            Array::NewString(zone_,
  47.996 -                             map,
  47.997 -                             literal->string()->raw(),
  47.998 -                             literal->string()->length(),
  47.999 -                             Heap::Tenure_Old));
 47.1000 -        if (!array)
 47.1001 -            return NULL;
 47.1002 -
 47.1003 -        return Box::NewObj(zone_, given, array, Heap::Tenure_Old);
 47.1004 -    }
 47.1005 -
 47.1006 -    cc_.reportError(parameter->initializer()->pos(), Message_MustBeConstant);
 47.1007 -    return NULL;
 47.1008 -}
 47.1009 -
 47.1010 -bool
 47.1011 -SemanticAnalysis::buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
 47.1012 -                                    FixedArray **argsp, FixedArray **defaultsp)
 47.1013 -{
 47.1014 -    Local<FixedArray> args(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
 47.1015 -    if (!args)
 47.1016 -        return false;
 47.1017 -
 47.1018 -    Local<FixedArray> defaults(zone_);
 47.1019 -
 47.1020 -    // Apply types to arguments.
 47.1021 -    for (size_t i = 0; i < sig.parameters()->length(); i++) {
 47.1022 -        Parameter *parameter = sig.parameters()->at(i);
 47.1023 -        
 47.1024 -        Local<Type> type(zone_, bindType(parameter->variable()->pos(), parameter->type()));
 47.1025 -        if (!type)
 47.1026 -            return false;
 47.1027 -
 47.1028 -        if (parameter->reference()) {
 47.1029 -            if (parameter->dimensions()) {
 47.1030 -                cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference);
 47.1031 -                return false;
 47.1032 -            }
 47.1033 -
 47.1034 -            if (type->isStruct()) {
 47.1035 -                cc_.reportError(parameter->variable()->pos(), Message_StructCantBeReference);
 47.1036 -                return false;
 47.1037 -            }
 47.1038 -
 47.1039 -            type = zone_->types()->getReference(type, parameter->isConst());
 47.1040 -            if (!type)
 47.1041 -                return false;
 47.1042 -        } else if (parameter->dimensions()) {
 47.1043 -            type = buildArrayType(type, parameter->dimensions(), parameter->isConst());
 47.1044 -            if (!type)
 47.1045 -                return false;
 47.1046 -
 47.1047 -            if (kind == TOK_NATIVE && type->levels() > 1) {
 47.1048 -                cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
 47.1049 -                return false;
 47.1050 -            }
 47.1051 -        }
 47.1052 -
 47.1053 -        if (IsScalarString(type)) {
 47.1054 -            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
 47.1055 -            return false;
 47.1056 -        }
 47.1057 -
 47.1058 -        args->set(zone_, i, type);
 47.1059 -        parameter->variable()->setType(type);
 47.1060 -
 47.1061 -        if (parameter->initializer()) {
 47.1062 -            if (!defaults) {
 47.1063 -                defaults = FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old);
 47.1064 -                if (!defaults)
 47.1065 -                    return false;
 47.1066 -            }
 47.1067 -
 47.1068 -            Local<Box> box(zone_, evaluateDefaultParameter(type, parameter));
 47.1069 -            if (!box)
 47.1070 -                return false;
 47.1071 -
 47.1072 -            defaults->set(zone_, i, box);
 47.1073 -        }
 47.1074 -    }
 47.1075 -
 47.1076 -    *argsp = args;
 47.1077 -    *defaultsp = defaults;
 47.1078 -
 47.1079 -    return true;
 47.1080 -}
 47.1081 -
 47.1082 -void
 47.1083 -SemanticAnalysis::visit(FunctionTypeStatement *node)
 47.1084 -{
 47.1085 -    if (node->decl()->type())
 47.1086 -        return;
 47.1087 -
 47.1088 -    Local<FixedArray> args(zone_);
 47.1089 -    Local<FixedArray> defaults(zone_);
 47.1090 -
 47.1091 -    const FunctionSignature &sig= node->signature();
 47.1092 -    if (!buildFunctionArgs(node,
 47.1093 -                           TOK_STOCK,
 47.1094 -                           sig,
 47.1095 -                           args.address(),
 47.1096 -                           defaults.address()))
 47.1097 -    {
 47.1098 -        return;
 47.1099 -    }
 47.1100 -
 47.1101 -    Local<Type> returnType(zone_);
 47.1102 -    if (sig.returnType())
 47.1103 -        returnType = bindType(node->pos(), sig.returnType());
 47.1104 -    else
 47.1105 -        returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
 47.1106 -
 47.1107 -    if (!returnType)
 47.1108 -        return;
 47.1109 -
 47.1110 -    Local<Type> funtype(zone_, zone_->types()->newFunction(returnType, args, defaults));
 47.1111 -    if (!funtype)
 47.1112 -        return;
 47.1113 -
 47.1114 -    node->decl()->setType(funtype);
 47.1115 -}
 47.1116 -
 47.1117 -Type *
 47.1118 -SemanticAnalysis::buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst)
 47.1119 -{
 47.1120 -    Local<Type> arrayType(zone_, type);
 47.1121 -
 47.1122 -    unsigned dimcount = dimensions->length();
 47.1123 -    if (type->isArray())
 47.1124 -        dimcount += type->levels();
 47.1125 -
 47.1126 -    if (dimcount > MAX_ARRAY_DEPTH) {
 47.1127 -        cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(),
 47.1128 -                        Message_MaximumArrayDepth);
 47.1129 -        return false;
 47.1130 -    }
 47.1131 -
 47.1132 -    // Note: constness is sort of bogus. Fix this sometime.
 47.1133 -    for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) {
 47.1134 -        Expression *expr = dimensions->at(i);
 47.1135 -        if (!expr) {
 47.1136 -            arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst);
 47.1137 -            if (!arrayType)
 47.1138 -                return NULL;
 47.1139 -
 47.1140 -            continue;
 47.1141 -        }
 47.1142 -
 47.1143 -        BoxedPrimitive box;
 47.1144 -        if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
 47.1145 -            cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
 47.1146 -            return NULL;
 47.1147 -        }
 47.1148 -
 47.1149 -        if (box.toInt() <= 0) {
 47.1150 -            cc_.reportError(expr->pos(), Message_BadArraySize);
 47.1151 -            return NULL;
 47.1152 -        }
 47.1153 -
 47.1154 -        arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst);
 47.1155 -        if (!arrayType)
 47.1156 -            return NULL;
 47.1157 -    }
 47.1158 -
 47.1159 -    return arrayType;
 47.1160 -}
 47.1161 -
 47.1162 -bool
 47.1163 -SemanticAnalysis::preanalyze(FunctionStatement *node)
 47.1164 -{
 47.1165 -    Local<FixedArray> args(zone_);
 47.1166 -    Local<FixedArray> defaults(zone_);
 47.1167 -
 47.1168 -    const FunctionSignature &sig = node->signature();
 47.1169 -    if (!buildFunctionArgs(node,
 47.1170 -                           node->fun()->token(),
 47.1171 -                           sig,
 47.1172 -                           args.address(),
 47.1173 -                           defaults.address()))
 47.1174 -    {
 47.1175 -        return false;
 47.1176 -    }
 47.1177 -
 47.1178 -    Local<Type> returnType(zone_);
 47.1179 -    if (sig.returnType() ||
 47.1180 -        node->hasExplicitReturn() ||
 47.1181 -        node->fun()->isNative())
 47.1182 -    {
 47.1183 -        returnType = bindType(node->pos(), sig.returnType());
 47.1184 -    } else {
 47.1185 -        returnType = zone_->types()->getVoid();
 47.1186 -    }
 47.1187 -    if (!returnType)
 47.1188 -        return false;
 47.1189 -
 47.1190 -    if (sig.returnDimensions()) {
 47.1191 -        returnType = buildArrayType(returnType, sig.returnDimensions(), false);
 47.1192 -        if (!returnType)
 47.1193 -            return false;
 47.1194 -    }
 47.1195 -
 47.1196 -    if (IsScalarString(returnType)) {
 47.1197 -        cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
 47.1198 -        return false;
 47.1199 -    }
 47.1200 -
 47.1201 -    Local<Type> funtype(zone_);
 47.1202 -    if (node->fun()->isNative())
 47.1203 -        funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic());
 47.1204 -    else
 47.1205 -        funtype = zone_->types()->newFunction(returnType, args, defaults);
 47.1206 -    if (!funtype)
 47.1207 -        return false;
 47.1208 -    
 47.1209 -    // If the function already has a type, it was forward declared before, and
 47.1210 -    // now this is our chance to type check the second declaration.
 47.1211 -    if (node->fun()->type()) {
 47.1212 -        Local<Type> forward(zone_, node->fun()->type());
 47.1213 -        if (!Type::Compare(funtype, forward)) {
 47.1214 -            cc_.reportError(node->pos(), Message_ForwardDeclareMismatches);
 47.1215 -            return false;
 47.1216 -        }
 47.1217 -        node->fun()->setForwardType(forward);
 47.1218 -    }
 47.1219 -
 47.1220 -    node->fun()->setType(funtype);
 47.1221 -
 47.1222 -    return true;
 47.1223 -}
 47.1224 -
 47.1225 -void
 47.1226 -SemanticAnalysis::visit(FunctionStatement *node)
 47.1227 -{
 47.1228 -    function_ = node->fun();
 47.1229 -    scope_ = node->scope();
 47.1230 -
 47.1231 -    ControlScope control(&control_);
 47.1232 -    if (node->body()) {
 47.1233 -        node->body()->accept(this);
 47.1234 -
 47.1235 -        ControlStatus status = control.status();
 47.1236 -        if (status.returns() == Returns_Sometimes) {
 47.1237 -            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
 47.1238 -        } else if (status.returns() == Returns_Never) {
 47.1239 -            if (!function_->type()->returnType()->isVoid())
 47.1240 -                cc_.reportError(node->pos(), Message_MissingReturnValue);
 47.1241 -        }
 47.1242 -    }
 47.1243 -
 47.1244 -    scope_ = NULL;
 47.1245 -    function_ = NULL;
 47.1246 -}
 47.1247 -
 47.1248 -void
 47.1249 -SemanticAnalysis::typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given)
 47.1250 -{
 47.1251 -    cc_.reportError(pos, Message_TypeMismatch,
 47.1252 -                    GetTypeName(actual),
 47.1253 -                    GetTypeName(given));
 47.1254 -}
 47.1255 -
 47.1256 -bool
 47.1257 -SemanticAnalysis::typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> argGiven,
 47.1258 -                                           Handle<Type> argActual, bool forAssign)
 47.1259 -{
 47.1260 -    Local<Type> actual(zone_, argActual);
 47.1261 -    Local<Type> given(zone_, argGiven);
 47.1262 -
 47.1263 -    if (!given->isArray()) {
 47.1264 -        cc_.reportError(pos, Message_ExpectedArray);
 47.1265 -        return false;
 47.1266 -    }
 47.1267 -    if (given->levels() != actual->levels()) {
 47.1268 -        cc_.reportError(pos, Message_ArrayDimensionsMismatch);
 47.1269 -        return false;
 47.1270 -    }
 47.1271 -
 47.1272 -    unsigned level = 1;
 47.1273 -    while (given->isArray()) {
 47.1274 -        if (actual->isFixedLength()) {
 47.1275 -            if (forAssign) {
 47.1276 -                if (!given->isFixedLength()) {
 47.1277 -                    cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 47.1278 -                    return false;
 47.1279 -                }
 47.1280 -
 47.1281 -                if (actual->isCharArray()) {
 47.1282 -                    // String assignment can have a truncated |given|.
 47.1283 -                    if (given->fixedLength() > actual->fixedLength()) {
 47.1284 -                        cc_.reportError(pos, Message_ArrayAssignmentTooBig);
 47.1285 -                        return false;
 47.1286 -                    }
 47.1287 -                } else {
 47.1288 -                    if (given->fixedLength() != actual->fixedLength()) {
 47.1289 -                        cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 47.1290 -                        return false;
 47.1291 -                    }
 47.1292 -                }
 47.1293 -            }
 47.1294 -        } else if (given->isFixedLength()) {
 47.1295 -            // We do not allow assignments in the form:
 47.1296 -            //    [][] = [][Y]
 47.1297 -            //
 47.1298 -            // Otherwise, the following code could break the size guarantees
 47.1299 -            // of the right-hand side:
 47.1300 -            //
 47.1301 -            //   new x[][5];
 47.1302 -            //   new y[][];
 47.1303 -            //   new z[3];
 47.1304 -            //
 47.1305 -            //   y = x;
 47.1306 -            //   y[0] = z;
 47.1307 -            //   
 47.1308 -            // Now |x[0]| contains a 4-length array.
 47.1309 -            if (level > 1) {
 47.1310 -                cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 47.1311 -                return false;
 47.1312 -            }
 47.1313 -        }
 47.1314 -        given = given->contained();
 47.1315 -        actual = actual->contained();
 47.1316 -        level++;
 47.1317 -    }
 47.1318 -
 47.1319 -    return typeCheckAssignment(pos, given, actual, forAssign);
 47.1320 -}
 47.1321 -
 47.1322 -bool
 47.1323 -SemanticAnalysis::typeCheckAssignment(const SourcePosition &pos, Handle<Type> argGiven,
 47.1324 -                                      Handle<Type> argActual, bool forAssign)
 47.1325 -{
 47.1326 -    Local<Type> actual(zone_, argActual);
 47.1327 -    Local<Type> given(zone_, argGiven);
 47.1328 -
 47.1329 -    if (actual->isArray())
 47.1330 -        return typeCheckArrayAssignment(pos, given, actual, forAssign);
 47.1331 -
 47.1332 -    if (given->isArray()) {
 47.1333 -        cc_.reportError(pos, Message_CannotAssignArrayToScalar);
 47.1334 -        return false;
 47.1335 -    }
 47.1336 -
 47.1337 -    // The given type may not have been dereferenced.
 47.1338 -    if (given->isReference())
 47.1339 -        given = given->contained();
 47.1340 -    if (actual->isReference())
 47.1341 -        actual = actual->contained();
 47.1342 -
 47.1343 -    // We coerce unchecked to a few things.
 47.1344 -    if (actual->isUnchecked() || given->isUnchecked()) {
 47.1345 -        Type *check = actual->isUnchecked() ? given : actual;
 47.1346 -        if (check->isUnchecked() ||
 47.1347 -            check->isEnum() ||
 47.1348 -            check->isInt32() ||
 47.1349 -            check->isBool() ||
 47.1350 -            check->isFloat())
 47.1351 -        {
 47.1352 -            return true;
 47.1353 -        }
 47.1354 -        typeMismatch(pos, actual, given);
 47.1355 -        return false;
 47.1356 -    }
 47.1357 -
 47.1358 -    if (given->isFunction() && actual->isFunction()) {
 47.1359 -        if (!Type::Compare(given, actual)) {
 47.1360 -            typeMismatch(pos, actual, given);
 47.1361 -            return false;
 47.1362 -        }
 47.1363 -        return true;
 47.1364 -    }
 47.1365 -
 47.1366 -    if (actual->isEnum()) {
 47.1367 -        if (!given->isEnum() || actual != given) {
 47.1368 -            typeMismatch(pos, actual, given);
 47.1369 -            return false;
 47.1370 -        }
 47.1371 -        return true;
 47.1372 -    }
 47.1373 -
 47.1374 -    if (actual->isStruct()) {
 47.1375 -        if (!given->isStruct() || actual != given) {
 47.1376 -            typeMismatch(pos, actual, given);
 47.1377 -            return false;
 47.1378 -        }
 47.1379 -        return true;
 47.1380 -    }
 47.1381 -
 47.1382 -    if (given->isEnum() || given->isFunction() || given->isStruct()) {
 47.1383 -        typeMismatch(pos, actual, given);
 47.1384 -        return false;
 47.1385 -    }
 47.1386 -
 47.1387 -    // This coercion is trivial.
 47.1388 -    if (given->isBool() && actual->isInt32())
 47.1389 -        return true;
 47.1390 -
 47.1391 -    if (given->primitive() != actual->primitive()) {
 47.1392 -        typeMismatch(pos, actual, given);
 47.1393 -        return false;
 47.1394 -    }
 47.1395 -
 47.1396 -    return true;
 47.1397 -}
 47.1398 -
 47.1399 -bool
 47.1400 -SemanticAnalysis::typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual)
 47.1401 -{
 47.1402 -    return typeCheckAssignment(node->pos(), given, actual, false);
 47.1403 -}
 47.1404 -
 47.1405 -bool
 47.1406 -SemanticAnalysis::checkArgumentCount(Handle<Type> type, unsigned actual)
 47.1407 -{
 47.1408 -    if (type->parameters()->length() == actual)
 47.1409 -        return true;
 47.1410 -
 47.1411 -    if (actual > type->parameters()->length()) {
 47.1412 -        if (!type->isNative() || !type->isNativeVariadic())
 47.1413 -            return false;
 47.1414 -        return true;
 47.1415 -    }
 47.1416 -
 47.1417 -    if (!type->defaults())
 47.1418 -        return false;
 47.1419 -
 47.1420 -    // Missing arguments. See if there's a default argument for each missing
 47.1421 -    // actual.
 47.1422 -    for (unsigned i = actual; i < type->parameters()->length(); i++) {
 47.1423 -        if (!type->defaults()->at(i))
 47.1424 -            return false;
 47.1425 -    }
 47.1426 -
 47.1427 -    return true;
 47.1428 -}
 47.1429 -
 47.1430 -void
 47.1431 -SemanticAnalysis::visit(CallExpression *node)
 47.1432 -{
 47.1433 -    Local<Type> type(zone_, visitForLoad(node->callee()));
 47.1434 -    if (!type)
 47.1435 -        return;
 47.1436 -
 47.1437 -    if (!type->isFunction()) {
 47.1438 -        cc_.reportError(node->pos(), Message_CalleeNotFunction);
 47.1439 -        return;
 47.1440 -    }
 47.1441 -
 47.1442 -    if (!checkArgumentCount(type, node->arguments()->length())) {
 47.1443 -        cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
 47.1444 -        return;
 47.1445 -    }
 47.1446 -
 47.1447 -    // NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
 47.1448 -    // if (fun->isForward()) {
 47.1449 -    //     cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
 47.1450 -    //     return;
 47.1451 -    // }
 47.1452 -
 47.1453 -    for (unsigned i = 0; i < node->arguments()->length(); i++) {
 47.1454 -        // Note: we don't compute references unless the callee needs a
 47.1455 -        // reference type.
 47.1456 -        Expression *expression = node->arguments()->at(i);
 47.1457 -        Local<Type> given(zone_, visitAndApplyType(expression));
 47.1458 -        if (!given)
 47.1459 -            return;
 47.1460 -
 47.1461 -        // Since we skip a load, check for a call expression that returns void.
 47.1462 -        if (given->isVoid()) {
 47.1463 -            assert(expression->isCallExpression());
 47.1464 -            CallExpression *call = expression->toCallExpression();
 47.1465 -            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
 47.1466 -            return;
 47.1467 -        }
 47.1468 -        
 47.1469 -        bool mustComputeReference;
 47.1470 -        if (i >= type->parameters()->length()) {
 47.1471 -            // Special handling for natives. Arguments past the formal must
 47.1472 -            // always have references computed. However, arrays are already
 47.1473 -            // references for natives.  
 47.1474 -            assert(type->isNative() && type->isNativeVariadic());
 47.1475 -            mustComputeReference = !given->isReference() && !given->isArray();
 47.1476 -        } else {
 47.1477 -            Local<Type> actual(zone_, type->parameterAt(i));
 47.1478 -
 47.1479 -            if (expression->isIndexExpression()) {
 47.1480 -                // Disabled until we can make it work.
 47.1481 -#if 0
 47.1482 -                if (actual->isArray()) {
 47.1483 -                    // We special case the ability to pass x[y] into x[], which
 47.1484 -                    // creates an array slice. We only do this if we know the
 47.1485 -                    // assignment would otherwise not type-check.
 47.1486 -                    IndexExpression *index = expression->toIndexExpression();
 47.1487 -                    if (index->left()->type()->levels() == actual->levels())
 47.1488 -                        given = index->left()->type();
 47.1489 -                } else
 47.1490 -#endif
 47.1491 -                if (actual->isReference()) {
 47.1492 -                    cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
 47.1493 -                    return;
 47.1494 -                }
 47.1495 -            }
 47.1496 -
 47.1497 -            if (!typeCheckParameter(expression, given, actual))
 47.1498 -                return;
 47.1499 -            mustComputeReference = actual->isReference() && !given->isReference();
 47.1500 -        }
 47.1501 -
 47.1502 -        // If the actual is a reference, and the given is not, we'll need to
 47.1503 -        // compute a reference, which may be allocated on the stack.
 47.1504 -        if (mustComputeReference)
 47.1505 -            scope_->setUsesLifoHeap();
 47.1506 -    }
 47.1507 -
 47.1508 -    node->setType(type->returnType());
 47.1509 -}
 47.1510 -
 47.1511 -void
 47.1512 -SemanticAnalysis::ControlScope::inherit(const ControlStatus &other)
 47.1513 -{
 47.1514 -    if (other.returns() < status().returns())
 47.1515 -        return;
 47.1516 -
 47.1517 -    if (other.terminates())
 47.1518 -        terminate(other.returns());
 47.1519 -    else
 47.1520 -        returns(other.returns());
 47.1521 -}
 47.1522 -
 47.1523 -void
 47.1524 -SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
 47.1525 -{
 47.1526 -    // If both sides terminate in a return, we consider this a return as well.
 47.1527 -    if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
 47.1528 -        terminate(Returns_Always);
 47.1529 -        return;
 47.1530 -    }
 47.1531 -
 47.1532 -    ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
 47.1533 -                          ? Returns_Never
 47.1534 -                          : Returns_Sometimes;
 47.1535 -
 47.1536 -    if (left.terminates() && right.terminates())
 47.1537 -        terminate(status);
 47.1538 -    else
 47.1539 -        returns(status);
 47.1540 -}
 47.1541 -
 47.1542 -void
 47.1543 -SemanticAnalysis::visit(IfStatement *node)
 47.1544 -{
 47.1545 -    Local<Type> type(zone_, visitForLoad(node->condition()));
 47.1546 -    if (!type)
 47.1547 -        return;
 47.1548 -
 47.1549 -    if (!canTest(node, type))
 47.1550 -        return;
 47.1551 -
 47.1552 -    ControlStatus trueBranch = visitForControl(node->ifTrue());
 47.1553 -    ControlStatus falseBranch = ControlStatus(false, Returns_Never);
 47.1554 -
 47.1555 -    if (node->ifFalse())
 47.1556 -        falseBranch = visitForControl(node->ifFalse());
 47.1557 -
 47.1558 -    control_->merge(trueBranch, falseBranch);
 47.1559 -}
 47.1560 -
 47.1561 -void
 47.1562 -SemanticAnalysis::visit(IndexExpression *node)
 47.1563 -{
 47.1564 -    Local<Type> left(zone_, visitForLoad(node->left()));
 47.1565 -    Local<Type> right(zone_, visitForLoad(node->right()));
 47.1566 -
 47.1567 -    if (!left || !right)
 47.1568 -        return;
 47.1569 -
 47.1570 -    if (!right->isInt32() && !right->isEnum()) {
 47.1571 -        cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger);
 47.1572 -        return;
 47.1573 -    }
 47.1574 -    if (!left->isArray()) {
 47.1575 -        cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
 47.1576 -        return;
 47.1577 -    }
 47.1578 -
 47.1579 -    // Note: char arrays are automatically up-casted to return an int32.
 47.1580 -    if (left->isCharArray())
 47.1581 -        node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
 47.1582 -    else
 47.1583 -        node->setType(left->contained());
 47.1584 -}
 47.1585 -
 47.1586 -void
 47.1587 -SemanticAnalysis::visit(FieldExpression *node)
 47.1588 -{
 47.1589 -    Local<Type> left(zone_, visitForLoad(node->left()));
 47.1590 -    if (!left)
 47.1591 -        return;
 47.1592 -
 47.1593 -    if (!left->isStruct()) {
 47.1594 -        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
 47.1595 -                        GetTypeName(left));
 47.1596 -        return;
 47.1597 -    }
 47.1598 -
 47.1599 -    Local<String> field(zone_, node->field());
 47.1600 -
 47.1601 -    unsigned offset;
 47.1602 -    Local<Descriptor> desc(zone_, left->lookupField(field, &offset));
 47.1603 -    if (!desc) {
 47.1604 -        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
 47.1605 -                        GetTypeName(left));
 47.1606 -        return;
 47.1607 -    }
 47.1608 -
 47.1609 -    node->setFieldIndex(offset);
 47.1610 -    node->setType(desc->type());
 47.1611 -}
 47.1612 -
 47.1613 -void
 47.1614 -SemanticAnalysis::visit(EnumStatement *node)
 47.1615 -{
 47.1616 -    Local<String> name(zone_, node->name());
 47.1617 -    Local<Type> type(zone_);
 47.1618 -    if (name)
 47.1619 -        type = zone_->types()->newEnum(name);
 47.1620 -    else
 47.1621 -        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
 47.1622 -
 47.1623 -    if (!type)
 47.1624 -        return;
 47.1625 -
 47.1626 -    if (node->decl())
 47.1627 -        node->decl()->setType(type);
 47.1628 -
 47.1629 -    int value = 0;
 47.1630 -    for (size_t i = 0; i < node->entries()->length(); i++) {
 47.1631 -        EnumStatement::Entry &entry = node->entries()->at(i);
 47.1632 -
 47.1633 -        BoxedPrimitive box = BoxedPrimitive::Int(value);
 47.1634 -        if (entry.expr) {
 47.1635 -            entry.expr->accept(this);
 47.1636 -            if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
 47.1637 -                cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
 47.1638 -                return;
 47.1639 -            }
 47.1640 -
 47.1641 -            assert(box.type() == PrimitiveType_Int32);
 47.1642 -            value = box.toInt();
 47.1643 -        }
 47.1644 -
 47.1645 -        entry.name->set(type, box);
 47.1646 -        value++;
 47.1647 -    }
 47.1648 -}
 47.1649 -
 47.1650 -static int
 47.1651 -SortCaseIntValues(const void *p1, const void *p2)
 47.1652 -{
 47.1653 -    CaseValue *v1 = (CaseValue *)p1;
 47.1654 -    CaseValue *v2 = (CaseValue *)p2;
 47.1655 -
 47.1656 -    return v1->box.toInt() - v2->box.toInt();
 47.1657 -}
 47.1658 -
 47.1659 -void
 47.1660 -SemanticAnalysis::visit(SwitchStatement *node)
 47.1661 -{
 47.1662 -    Local<Type> caseType(zone_, visitForLoad(node->expression()));
 47.1663 -    if (!caseType)
 47.1664 -        return;
 47.1665 -
 47.1666 -    if (!caseType->isEnum() && !caseType->isInt32()) {
 47.1667 -        cc_.reportError(node->pos(), Message_CaseMustBeInteger);
 47.1668 -        return;
 47.1669 -    }
 47.1670 -
 47.1671 -    PoolList<CaseValue> *values = new (zone_->pool()) PoolList<CaseValue>();
 47.1672 -    ControlStatus status = ControlStatus(false, Returns_Never);
 47.1673 -
 47.1674 -    Local<Type> check(zone_);
 47.1675 -    for (size_t i = 0; i < node->cases()->length(); i++) {
 47.1676 -        Case *c = node->cases()->at(i);
 47.1677 -
 47.1678 -        check = visitForLoad(c->expression());
 47.1679 -        if (!check)
 47.1680 -            return;
 47.1681 -
 47.1682 -        if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false))
 47.1683 -            return;
 47.1684 -
 47.1685 -        CaseValue v(i);
 47.1686 -        if (!EvaluateForConstant(c->expression(), &v.box)) {
 47.1687 -            cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant);
 47.1688 -            return;
 47.1689 -        }
 47.1690 -        if (!values->append(v))
 47.1691 -            return;
 47.1692 -
 47.1693 -        if (c->others()) {
 47.1694 -            for (size_t j = 0; j < c->others()->length(); j++) {
 47.1695 -                Expression *expr = c->others()->at(j);
 47.1696 -                check = visitForLoad(expr);
 47.1697 -                if (!check)
 47.1698 -                    return;
 47.1699 -
 47.1700 -                if (!typeCheckAssignment(expr->pos(), check, caseType, false))
 47.1701 -                    return;
 47.1702 -
 47.1703 -                CaseValue v(i);
 47.1704 -                if (!EvaluateForConstant(expr, &v.box)) {
 47.1705 -                    cc_.reportError(expr->pos(), Message_CaseMustBeConstant);
 47.1706 -                    return;
 47.1707 -                }
 47.1708 -                if (!values->append(v))
 47.1709 -                    return;
 47.1710 -            }
 47.1711 -        }
 47.1712 -
 47.1713 -        ControlStatus latest = visitForControl(c->statement());
 47.1714 -
 47.1715 -        if (i != 0)
 47.1716 -            control_->merge(status, latest);
 47.1717 -
 47.1718 -        status = latest;
 47.1719 -    }
 47.1720 -
 47.1721 -    if (node->defaultCase()) {
 47.1722 -        ControlStatus latest = visitForControl(node->defaultCase());
 47.1723 -
 47.1724 -        if (node->cases()->length()) {
 47.1725 -            // If we had any other cases, we must merge.
 47.1726 -            control_->merge(status, latest);
 47.1727 -        } else {
 47.1728 -            // Otherwise, control-flow always flows through here.
 47.1729 -            control_->inherit(latest);
 47.1730 -        }
 47.1731 -    } else if (node->cases()->length()) {
 47.1732 -        control_->merge(status, ControlStatus(false, Returns_Never));
 47.1733 -    }
 47.1734 -
 47.1735 -    if (values->length() > 1) {
 47.1736 -        qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues);
 47.1737 -
 47.1738 -        for (size_t i = 1; i < values->length(); i++) {
 47.1739 -            CaseValue &prev = values->at(i - 1);
 47.1740 -            CaseValue &cur = values->at(i);
 47.1741 -            if (prev.box.toInt() == cur.box.toInt()) {
 47.1742 -                cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue);
 47.1743 -                return;
 47.1744 -            }
 47.1745 -        }
 47.1746 -    }
 47.1747 -
 47.1748 -    node->setCaseValueList(values);
 47.1749 -}
 47.1750 -
 47.1751 -void
 47.1752 -SemanticAnalysis::visit(StructureStatement *node)
 47.1753 -{
 47.1754 -    // If this node already has a type, it was pre-analyzed, so skip it.
 47.1755 -    if (node->decl()->type())
 47.1756 -        return;
 47.1757 -
 47.1758 -    FieldList *fields = node->fields();
 47.1759 -    Local<FixedArray> desctable(zone_, FixedArray::New(zone_, fields->length(), Heap::Tenure_Old));
 47.1760 -    if (!desctable)
 47.1761 -        return;
 47.1762 -
 47.1763 -    Vector<unsigned> composedList;
 47.1764 -    StructureBufferBuilder builder;
 47.1765 -
 47.1766 -    Local<Type> type(zone_);
 47.1767 -    Local<String> name(zone_);
 47.1768 -    Local<Descriptor> desc(zone_);
 47.1769 -    for (size_t i = 0; i < fields->length(); i++) {
 47.1770 -        StructureStatement::Field *field = fields->at(i);
 47.1771 -
 47.1772 -        type = bindType(field->pos(), field->type());
 47.1773 -        if (!type)
 47.1774 -            return;
 47.1775 -
 47.1776 -        if (field->dimensions()) {
 47.1777 -            type = buildArrayType(type, field->dimensions(), false);
 47.1778 -            if (!type)
 47.1779 -                return;
 47.1780 -
 47.1781 -            if (!ArrayMap::Attach(zone_, type))
 47.1782 -                return;
 47.1783 -        }
 47.1784 -
 47.1785 -        if (IsScalarString(type)) {
 47.1786 -            cc_.reportError(field->pos(), Message_CannotDeclareStringCell);
 47.1787 -            return;
 47.1788 -        }
 47.1789 -
 47.1790 -        unsigned offset;
 47.1791 -        if (!builder.add(type, &offset))
 47.1792 -            return;
 47.1793 -
 47.1794 -        name = field->name();
 47.1795 -        desc = Descriptor::New(zone_, name, type, offset);
 47.1796 -        if (!desc)
 47.1797 -            return;
 47.1798 -
 47.1799 -        desctable->set(zone_, i, desc);
 47.1800 -
 47.1801 -        if (type->isStruct() || type->isArray()) {
 47.1802 -            if (!composedList.append(i))
 47.1803 -                return;
 47.1804 -        }
 47.1805 -    }
 47.1806 -
 47.1807 -    Local<FixedArray> composed(zone_);
 47.1808 -    if (composedList.length()) {
 47.1809 -        composed = FixedArray::New(zone_, composedList.length(), Heap::Tenure_Old);
 47.1810 -        if (!composed)
 47.1811 -            return;
 47.1812 -
 47.1813 -        for (unsigned i = 0; i < composedList.length(); i++)
 47.1814 -            composed->set(zone_, i, desctable->at(i));
 47.1815 -    }
 47.1816 -
 47.1817 -    Local<StructMap> map(zone_, StructMap::New(zone_, builder, composed));
 47.1818 -    if (!map)
 47.1819 -        return;
 47.1820 -
 47.1821 -    name = node->decl()->name();
 47.1822 -    type = zone_->types()->newStruct(name, desctable, map);
 47.1823 -    if (!type)
 47.1824 -        return;
 47.1825 -
 47.1826 -    map->setType(type);
 47.1827 -    node->decl()->setType(type);
 47.1828 -}
 47.1829 -
 47.1830 -void
 47.1831 -SemanticAnalysis::visit(StringLiteral *node)
 47.1832 -{
 47.1833 -    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char));
 47.1834 -    if (!type)
 47.1835 -        return;
 47.1836 -
 47.1837 -    type = Type::NewArray(zone_, type, node->string()->length() + 1, true);
 47.1838 -    if (!type)
 47.1839 -        return;
 47.1840 -
 47.1841 -    node->setType(type);
 47.1842 -}
 47.1843 -
 47.1844 -void
 47.1845 -SemanticAnalysis::visit(FloatLiteral *node)
 47.1846 -{
 47.1847 -    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
 47.1848 -    if (!type)
 47.1849 -        return;
 47.1850 -
 47.1851 -    node->setType(type);
 47.1852 -}
 47.1853 -
 47.1854 -void
 47.1855 -SemanticAnalysis::visit(BreakStatement *node)
 47.1856 -{
 47.1857 -    if (!loop_) {
 47.1858 -        cc_.reportError(node->pos(), Message_BreakOutsideLoop);
 47.1859 -        return;
 47.1860 -    }
 47.1861 -
 47.1862 -    // Note: ignore breaks that occur in unreachable control-flow.
 47.1863 -    if (!control_->status().terminates())
 47.1864 -        loop_->addBreak();
 47.1865 -
 47.1866 -    control_->terminate(Returns_Never);
 47.1867 -}
 47.1868 -
 47.1869 -void
 47.1870 -SemanticAnalysis::visit(ContinueStatement *node)
 47.1871 -{
 47.1872 -    if (!loop_) {
 47.1873 -        cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
 47.1874 -        return;
 47.1875 -    }
 47.1876 -
 47.1877 -    // Note: ignore continues that occur in unreachable control-flow.
 47.1878 -    if (!control_->status().terminates())
 47.1879 -        loop_->addContinue();
 47.1880 -
 47.1881 -    control_->terminate(Returns_Never);
 47.1882 -}
 47.1883 -
 47.1884 -void
 47.1885 -SemanticAnalysis::visit(ArrayLiteral *node)
 47.1886 -{
 47.1887 -    // We should never visit this.
 47.1888 -    cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral);
 47.1889 -}
 47.1890 -
    48.1 --- a/src/SemanticAnalysis.h	Mon Sep 17 00:10:01 2012 -0700
    48.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.3 @@ -1,236 +0,0 @@
    48.4 -/* vim: set ts=4 sw=4 tw=99 et:
    48.5 - *
    48.6 - * Copyright (C) 2012 David Anderson
    48.7 - *
    48.8 - * This file is part of JITCraft.
    48.9 - *
   48.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   48.11 - * the terms of the GNU General Public License as published by the Free
   48.12 - * Software Foundation, either version 3 of the License, or (at your option)
   48.13 - * any later version.
   48.14 - * 
   48.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   48.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   48.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   48.18 - *
   48.19 - * You should have received a copy of the GNU General Public License along with
   48.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   48.21 - */
   48.22 -#ifndef _include_semantic_analysis_h_
   48.23 -#define _include_semantic_analysis_h_
   48.24 -
   48.25 -#include <assert.h>
   48.26 -#include "AST.h"
   48.27 -#include "Types.h"
   48.28 -
   48.29 -namespace ke {
   48.30 -
   48.31 -class Box;
   48.32 -
   48.33 -class SemanticAnalysis : public AstVisitor
   48.34 -{
   48.35 -    Zone *zone_;
   48.36 -    CompileContext &cc_;
   48.37 -    ParseTree *tree_;
   48.38 -    Scope *scope_;
   48.39 -    NamedFunction *function_;
   48.40 -
   48.41 -    enum ReturnStatus
   48.42 -    {
   48.43 -        Returns_Never,
   48.44 -        Returns_Sometimes,
   48.45 -        Returns_Always
   48.46 -    };
   48.47 -
   48.48 -    // Tuple that describes whether a path terminates control flow, and
   48.49 -    // if it is guaranteed to end in a return.
   48.50 -    class ControlStatus
   48.51 -    {
   48.52 -        bool terminates_;
   48.53 -        ReturnStatus returns_;
   48.54 -
   48.55 -      public:
   48.56 -        ControlStatus(bool terminates, ReturnStatus returns)
   48.57 -          : terminates_(terminates),
   48.58 -            returns_(returns)
   48.59 -        {
   48.60 -        }
   48.61 -
   48.62 -        bool terminates() const {
   48.63 -            return terminates_;
   48.64 -        }
   48.65 -        ReturnStatus returns() const {
   48.66 -            return returns_;
   48.67 -        }
   48.68 -    };
   48.69 -
   48.70 -    // Used to keep track of terminating control flow and return statements
   48.71 -    // inside control structures.
   48.72 -    class ControlScope
   48.73 -    {
   48.74 -        ReturnStatus returns_;
   48.75 -        ControlScope **prevp_;
   48.76 -        ControlScope *prev_;
   48.77 -        bool terminates_;
   48.78 -
   48.79 -      public:
   48.80 -        ControlScope(ControlScope **prev)
   48.81 -          : returns_(Returns_Never),
   48.82 -            prevp_(prev),
   48.83 -            prev_(*prev),
   48.84 -            terminates_(false)
   48.85 -        {
   48.86 -            *prevp_ = this;
   48.87 -        }
   48.88 -
   48.89 -        ControlStatus status() const {
   48.90 -            return ControlStatus(terminates_, returns_);
   48.91 -        }
   48.92 -
   48.93 -        // We allow multiple terminators, but only the first one takes effect.
   48.94 -        // For example, |break; continue;| is legal but the continue is
   48.95 -        // unreachable.
   48.96 -        void returns(ReturnStatus status) {
   48.97 -            if (terminates_)
   48.98 -                return;
   48.99 -            if (status > returns_)
  48.100 -                returns_ = status;
  48.101 -        }
  48.102 -        void terminate(ReturnStatus status) {
  48.103 -            if (terminates_)
  48.104 -                return;
  48.105 -            terminates_ = true;
  48.106 -            returns_ = status;
  48.107 -        }
  48.108 -        void merge(const ControlStatus &left, const ControlStatus &right);
  48.109 -        void inherit(const ControlStatus &other);
  48.110 -
  48.111 -        ~ControlScope()
  48.112 -        {
  48.113 -            *prevp_ = prev_;
  48.114 -        }
  48.115 -    };
  48.116 -
  48.117 -    class LoopScope
  48.118 -    {
  48.119 -        LoopScope **prevp_;
  48.120 -        LoopScope *prev_;
  48.121 -        unsigned breaks_;
  48.122 -        unsigned continues_;
  48.123 -
  48.124 -      public:
  48.125 -        LoopScope(LoopScope **prev)
  48.126 -          : prevp_(prev),
  48.127 -            prev_(*prev),
  48.128 -            breaks_(0),
  48.129 -            continues_(0)
  48.130 -        {
  48.131 -            *prevp_ = this;
  48.132 -        }
  48.133 -
  48.134 -        ~LoopScope()
  48.135 -        {
  48.136 -            *prevp_ = prev_;
  48.137 -        }
  48.138 -
  48.139 -        void addBreak() {
  48.140 -            breaks_++;
  48.141 -        }
  48.142 -        void addContinue() {
  48.143 -            continues_++;
  48.144 -        }
  48.145 -        unsigned breaks() const {
  48.146 -            return breaks_;
  48.147 -        }
  48.148 -        unsigned continues() const {
  48.149 -            return continues_;
  48.150 -        }
  48.151 -    };
  48.152 -
  48.153 -    ControlScope *control_;
  48.154 -    LoopScope *loop_;
  48.155 -
  48.156 -  private:
  48.157 -    bool canTest(AstNode *node, Handle<Type> type);
  48.158 -    void typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given);
  48.159 -    void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
  48.160 -    void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
  48.161 -    Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
  48.162 -
  48.163 -    Type *bindType(const SourcePosition &pos, BoundName *name);
  48.164 -
  48.165 -    // These check if one type is compatible with another type, for various
  48.166 -    // purposes, like:
  48.167 -    //      return (expr) matches function return type
  48.168 -    //      call(a, b)    matches expected arg type
  48.169 -    //      a = b         matches declared type
  48.170 -    //
  48.171 -    bool typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
  48.172 -    bool typeCheckAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
  48.173 -    bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
  48.174 -
  48.175 -    Type *visitForLoad(Expression *expression);
  48.176 -    bool preanalyze(FunctionStatement *node);
  48.177 -    Type *visitForLValue(Expression *expression);
  48.178 -    Type *visitAndApplyType(Expression *expression);
  48.179 -    ControlStatus visitForControl(Statement *statement);
  48.180 -
  48.181 -    bool evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]);
  48.182 -    bool inferFixedArrayLiteral(ArrayLiteral *literal,
  48.183 -                                Handle<Type> type,
  48.184 -                                int dims[MAX_ARRAY_DEPTH],
  48.185 -                                unsigned dimcount,
  48.186 -                                unsigned level);
  48.187 -
  48.188 -    // Builds an array type used for parameters, returns, or field entries.
  48.189 -    Type *buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst);
  48.190 -
  48.191 -    Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
  48.192 -    bool checkArgumentCount(Handle<Type> type, unsigned actual);
  48.193 -    bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
  48.194 -                           FixedArray **args, FixedArray **defaults);
  48.195 -
  48.196 -    void markCallResultUsed(CallExpression *call);
  48.197 -
  48.198 -    bool determineLiveFunctions();
  48.199 -
  48.200 -  public:
  48.201 -    SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
  48.202 -    bool analyze();
  48.203 -
  48.204 -  public:
  48.205 -    void visit(NameProxy *name);
  48.206 -    void visit(Assignment *node);
  48.207 -    void visit(BinaryExpression *node);
  48.208 -    void visit(ReturnStatement *node);
  48.209 -    void visit(ForStatement *node);
  48.210 -    void visit(BlockStatement *node);
  48.211 -    void visit(VariableDeclaration *node);
  48.212 -    void visit(IntegerLiteral *node);
  48.213 -    void visit(ExpressionStatement *node);
  48.214 -    void visit(FunctionStatement *node);
  48.215 -    void visit(CallExpression *node);
  48.216 -    void visit(IfStatement *node);
  48.217 -    void visit(IndexExpression *node);
  48.218 -    void visit(EnumStatement *node);
  48.219 -    void visit(FloatLiteral *node);
  48.220 -    void visit(WhileStatement *node);
  48.221 -    void visit(BreakStatement *node);
  48.222 -    void visit(ContinueStatement *node);
  48.223 -    void visit(StringLiteral *node);
  48.224 -    void visit(IncDecExpression *node);
  48.225 -    void visit(UnaryExpression *node);
  48.226 -    void visit(TernaryExpression *node);
  48.227 -    void visit(BooleanLiteral *node);
  48.228 -    void visit(StructureStatement *node);
  48.229 -    void visit(FieldExpression *node);
  48.230 -    void visit(SwitchStatement *node);
  48.231 -    void visit(FunctionTypeStatement *node);
  48.232 -    void visit(ArrayLiteral *node);
  48.233 -};
  48.234 -
  48.235 -const char *GetTypeName(Type *type);
  48.236 -
  48.237 -} // namespace ke
  48.238 -
  48.239 -#endif // _include_semantic_analysis_h_
    49.1 --- a/src/Stack.cpp	Mon Sep 17 00:10:01 2012 -0700
    49.2 +++ b/src/Stack.cpp	Sat Nov 17 18:41:01 2012 -0800
    49.3 @@ -23,6 +23,7 @@
    49.4  #include "Zone.h"
    49.5  #include "Strings.h"
    49.6  #include "Modules.h"
    49.7 +#include "NativeTable.h"
    49.8  #include "Heap-inl.h"
    49.9  
   49.10  using namespace ke;
   49.11 @@ -286,7 +287,7 @@
   49.12  StackIter::function() const
   49.13  {
   49.14      if (fp_->isNative())
   49.15 -        return fp_->native()->name()->chars();
   49.16 +        return ZONE()->nativeTable()->name(fp_->native()->index())->chars();
   49.17      if (Function *fun = fp_->maybeFun())
   49.18          return fun->name()->chars();
   49.19      return "<toplevel>";
    50.1 --- a/src/StringPool.h	Mon Sep 17 00:10:01 2012 -0700
    50.2 +++ b/src/StringPool.h	Sat Nov 17 18:41:01 2012 -0800
    50.3 @@ -1,19 +1,20 @@
    50.4 -/*
    50.5 +/* vim: set ts=4 sw=4 tw=99 et:
    50.6 + *
    50.7   * Copyright (C) 2012 David Anderson
    50.8   *
    50.9 - * This file is part of JITCraft.
   50.10 + * This file is part of SourcePawn.
   50.11   *
   50.12 - * JITCraft is free software: you can redistribute it and/or modify it under
   50.13 + * SourcePawn is free software: you can redistribute it and/or modify it under
   50.14   * the terms of the GNU General Public License as published by the Free
   50.15   * Software Foundation, either version 3 of the License, or (at your option)
   50.16   * any later version.
   50.17   * 
   50.18 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   50.19 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   50.20   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   50.21   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   50.22   *
   50.23   * You should have received a copy of the GNU General Public License along with
   50.24 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   50.25 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   50.26   */
   50.27  #ifndef _include_jitcraft_string_pool_h_
   50.28  #define _include_jitcraft_string_pool_h_
   50.29 @@ -31,25 +32,6 @@
   50.30  // Guarantee that strings with the same contents will map to one pointer. 
   50.31  class StringPool
   50.32  {
   50.33 -    class CharsAndLength {
   50.34 -        const char *str_;
   50.35 -        size_t length_;
   50.36 -
   50.37 -      public:
   50.38 -        CharsAndLength(const char *str, size_t length)
   50.39 -          : str_(str),
   50.40 -            length_(length)
   50.41 -        {
   50.42 -        }
   50.43 -
   50.44 -        const char *str() const {
   50.45 -            return str_;
   50.46 -        }
   50.47 -        size_t length() const {
   50.48 -            return length_;
   50.49 -        }
   50.50 -    };
   50.51 -
   50.52      struct Policy
   50.53      {
   50.54          typedef String * Payload;
    51.1 --- a/src/Strings.h	Mon Sep 17 00:10:01 2012 -0700
    51.2 +++ b/src/Strings.h	Sat Nov 17 18:41:01 2012 -0800
    51.3 @@ -52,6 +52,26 @@
    51.4      }
    51.5  };
    51.6  
    51.7 +class CharsAndLength
    51.8 +{
    51.9 +    const char *str_;
   51.10 +    size_t length_;
   51.11 +
   51.12 +  public:
   51.13 +    CharsAndLength(const char *str, size_t length)
   51.14 +        : str_(str),
   51.15 +        length_(length)
   51.16 +    {
   51.17 +    }
   51.18 +
   51.19 +    const char *str() const {
   51.20 +        return str_;
   51.21 +    }
   51.22 +    size_t length() const {
   51.23 +        return length_;
   51.24 +    }
   51.25 +};
   51.26 +
   51.27  }
   51.28  
   51.29  #endif // _include_jitcraft_string_h_
    52.1 --- a/src/Structures.cpp	Mon Sep 17 00:10:01 2012 -0700
    52.2 +++ b/src/Structures.cpp	Sat Nov 17 18:41:01 2012 -0800
    52.3 @@ -51,7 +51,7 @@
    52.4  }
    52.5  
    52.6  Descriptor *
    52.7 -Descriptor::New(Zone *zone, Handle<String> name, Handle<Type> type, unsigned offset)
    52.8 +Descriptor::New(Zone *zone, Handle<String> name, Handle<Type> type)
    52.9  {
   52.10      Local<Descriptor> desc(zone,
   52.11          Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old)));
   52.12 @@ -60,13 +60,31 @@
   52.13  
   52.14      desc->name_ = name;
   52.15      desc->type_ = type;
   52.16 -    desc->offset_ = offset;
   52.17 +    desc->offset_ = unsigned(-1);
   52.18      return desc;
   52.19  }
   52.20  
   52.21  StructMap *
   52.22 -StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<FixedArray> composed)
   52.23 +StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type)
   52.24  {
   52.25 +    Vector<unsigned> composedIndexes;
   52.26 +    for (size_t i = 0; i < type->fields()->length(); i++) {
   52.27 +        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
   52.28 +        if (desc->type()->isArray() || desc->type()->isStruct()) {
   52.29 +            if (!composedIndexes.append(i))
   52.30 +                return NULL;
   52.31 +        }
   52.32 +    }
   52.33 +
   52.34 +    Local<FixedArray> composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old));
   52.35 +    if (!composed)
   52.36 +        return NULL;
   52.37 +
   52.38 +    for (size_t i = 0; i < composedIndexes.length(); i++) {
   52.39 +        Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i]));
   52.40 +        composed->set(zone, i, desc);
   52.41 +    }
   52.42 +
   52.43      size_t bytesNeeded = sizeof(StructMap) +
   52.44                           (builder.traceableOffsetCount() * sizeof(unsigned));
   52.45  
   52.46 @@ -77,7 +95,7 @@
   52.47  
   52.48      map->structureSize_ = builder.structureSize();
   52.49      map->traceOffsetCount_ = builder.traceableOffsetCount();
   52.50 -    map->type_ = NULL;
   52.51 +    map->type_ = type;
   52.52      map->composed_ = composed;
   52.53      memcpy(const_cast<unsigned *>(map->traceOffsets()), builder.offsets(),
   52.54             sizeof(unsigned) * builder.traceableOffsetCount());
   52.55 @@ -107,14 +125,17 @@
   52.56              desc = Descriptor::cast(map->composed()->at(i));
   52.57  
   52.58              if (desc->type()->isStruct()) {
   52.59 -                childStructMap = StructMap::cast(desc->type()->newMap());
   52.60 +                childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap());
   52.61                  child = Struct::New(zone, childStructMap, tenure);
   52.62              } else if (desc->type()->isArray()) {
   52.63 +                assert(false);
   52.64 +#if 0
   52.65                  childArrayMap = ArrayMap::cast(desc->type()->newMap());
   52.66                  if (desc->type()->isFixedLength())
   52.67                      child = Array::NewFixed(zone, childArrayMap, tenure);
   52.68                  else
   52.69                      child = Array::NewEmpty(zone, childArrayMap, tenure);
   52.70 +#endif
   52.71              }
   52.72              if (!child)
   52.73                  return NULL;
    53.1 --- a/src/Structures.h	Mon Sep 17 00:10:01 2012 -0700
    53.2 +++ b/src/Structures.h	Sat Nov 17 18:41:01 2012 -0800
    53.3 @@ -29,6 +29,7 @@
    53.4  class Type;
    53.5  class String;
    53.6  class FixedArray;
    53.7 +class StructType;
    53.8  
    53.9  // When describing composite structures, the GC must be able to trace interior
   53.10  // references to Objects. To make this possible, maps that describe composite
   53.11 @@ -69,8 +70,7 @@
   53.12      unsigned offset_;
   53.13  
   53.14    public:
   53.15 -    static Descriptor *New(Zone *zone, Handle<String> name, Handle<Type> type,
   53.16 -                           unsigned offset);
   53.17 +    static Descriptor *New(Zone *zone, Handle<String> name, Handle<Type> type);
   53.18  
   53.19      String *name() {
   53.20          return name_;
   53.21 @@ -79,8 +79,13 @@
   53.22          return type_;
   53.23      }
   53.24      unsigned offset() {
   53.25 +        assert(offset_ != unsigned(-1));
   53.26          return offset_;
   53.27      }
   53.28 +    void setOffset(unsigned offset) {
   53.29 +        assert(offset_ == unsigned(-1));
   53.30 +        offset_ = offset;
   53.31 +    }
   53.32  
   53.33      // Begin GC descriptor.
   53.34      static inline size_t offsetOfName() {
   53.35 @@ -101,13 +106,13 @@
   53.36  {
   53.37      unsigned structureSize_;
   53.38      unsigned traceOffsetCount_;
   53.39 -    Barriered<Type> type_;
   53.40 +    Barriered<StructType> type_;
   53.41  
   53.42      // List of descriptors which must be allocated upon initialization.
   53.43      Barriered<FixedArray> composed_;
   53.44  
   53.45    public:
   53.46 -    static StructMap *New(Zone *zone, const StructureBufferBuilder &builder, Handle<FixedArray> composed);
   53.47 +    static StructMap *New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type);
   53.48  
   53.49      unsigned structureSize() {
   53.50          return structureSize_;
   53.51 @@ -121,14 +126,14 @@
   53.52      size_t objSize() {
   53.53          return sizeof(StructMap) + sizeof(unsigned) * traceOffsetCount();
   53.54      }
   53.55 -    Type *type() {
   53.56 +    StructType *type() {
   53.57          return type_;
   53.58      }
   53.59      FixedArray *composed() {
   53.60          return composed_;
   53.61      }
   53.62  
   53.63 -    void setType(Type *type) {
   53.64 +    void setType(StructType *type) {
   53.65          assert(!type_);
   53.66          type_ = type;
   53.67      }
    54.1 --- a/src/Token.h	Mon Sep 17 00:10:01 2012 -0700
    54.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.3 @@ -1,144 +0,0 @@
    54.4 -/* vim: set ts=4 sw=4 tw=99 et:
    54.5 - * 
    54.6 - * Copyright (C) 2012 David Anderson
    54.7 - *
    54.8 - * This file is part of SourcePawn.
    54.9 - *
   54.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   54.11 - * the terms of the GNU General Public License as published by the Free
   54.12 - * Software Foundation, either version 3 of the License, or (at your option)
   54.13 - * any later version.
   54.14 - * 
   54.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   54.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   54.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   54.18 - *
   54.19 - * You should have received a copy of the GNU General Public License along with
   54.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   54.21 - */
   54.22 -#ifndef _include_jitcraft_token_h_
   54.23 -#define _include_jitcraft_token_h_
   54.24 -
   54.25 -namespace ke {
   54.26 -
   54.27 -struct SourcePosition
   54.28 -{
   54.29 -    int line;
   54.30 -    int col;
   54.31 -
   54.32 -    SourcePosition()
   54.33 -      : line(-1),
   54.34 -        col(-1)
   54.35 -    {
   54.36 -    }
   54.37 -
   54.38 -    SourcePosition(unsigned line, unsigned col)
   54.39 -      : line(line),
   54.40 -        col(col)
   54.41 -    {
   54.42 -    }
   54.43 -};
   54.44 -
   54.45 -// List of tokens the scanner can recognize.
   54.46 -//
   54.47 -// Some restrictions:
   54.48 -//   * (ASSIGN_ADD - TOK_PLUS) must be the delta between an operator and its
   54.49 -//     op-and-assign equivalent.
   54.50 -#define TOKENMAP(_)                                     \
   54.51 -    _(NONE,               "<none>")                     \
   54.52 -    _(ERROR,              "<error>")                    \
   54.53 -    _(NEW,                "'new'")                      \
   54.54 -    _(FOR,                "'for'")                      \
   54.55 -    _(RETURN,             "'return'")                   \
   54.56 -    _(NAME,               "<name>")                     \
   54.57 -    _(INTEGER_LITERAL,    "<integer>")                  \
   54.58 -    _(HEX_LITERAL,        "<hex>")                      \
   54.59 -    _(FLOAT_LITERAL,      "<float>")                    \
   54.60 -    _(STRING_LITERAL,     "<string>")                   \
   54.61 -    _(IF,                 "<if>")                       \
   54.62 -    _(ELSE,               "<else>")                     \
   54.63 -    _(ENUM,               "<enum>")                     \
   54.64 -    _(LABEL,              "<label>")                    \
   54.65 -    _(WHILE,              "<while>")                    \
   54.66 -    _(DO,                 "<do>")                       \
   54.67 -    _(BREAK,              "<break>")                    \
   54.68 -    _(CONTINUE,           "<continue>")                 \
   54.69 -    _(FORWARD,            "<forward>")                  \
   54.70 -    _(PUBLIC,             "<public>")                   \
   54.71 -    _(CONST,              "<const>")                    \
   54.72 -    _(NATIVE,             "<native>")                   \
   54.73 -    _(STOCK,              "<stock>")                    \
   54.74 -    _(TRUE,               "<true>")                     \
   54.75 -    _(FALSE,              "<false>")                    \
   54.76 -    _(STRUCT,             "<struct>")                   \
   54.77 -    _(SWITCH,             "<switch>")                   \
   54.78 -    _(CASE,               "<case>")                     \
   54.79 -    _(DEFAULT,            "<default>")                  \
   54.80 -    _(TYPEDEF,            "<typedef>")                  \
   54.81 -    _(VOID,               "<void>")                     \
   54.82 -    _(INT,                "<int>")                      \
   54.83 -    _(SIZEOF,             "<sizeof>")                   \
   54.84 -    _(ELLIPSES,           "...")                        \
   54.85 -    _(PLUS,               "+")                          \
   54.86 -    _(MINUS,              "-")                          \
   54.87 -    _(STAR,               "*")                          \
   54.88 -    _(SLASH,              "/")                          \
   54.89 -    _(PERCENT,            "%")                          \
   54.90 -    _(AMPERSAND,          "&")                          \
   54.91 -    _(BITOR,              "|")                          \
   54.92 -    _(BITXOR,             "^")                          \
   54.93 -    _(SHR,                ">>")                         \
   54.94 -    _(USHR,               ">>>")                        \
   54.95 -    _(SHL,                "<<")                         \
   54.96 -    _(ASSIGN,             "=")                          \
   54.97 -    _(SEMICOLON,          ";")                          \
   54.98 -    _(LBRACE,             "{")                          \
   54.99 -    _(RBRACE,             "}")                          \
  54.100 -    _(LPAREN,             "(")                          \
  54.101 -    _(RPAREN,             ")")                          \
  54.102 -    _(LBRACKET,           "[")                          \
  54.103 -    _(RBRACKET,           "]")                          \
  54.104 -    _(ASSIGN_ADD,         "+=")                         \
  54.105 -    _(ASSIGN_SUB,         "-=")                         \
  54.106 -    _(ASSIGN_MUL,         "*=")                         \
  54.107 -    _(ASSIGN_DIV,         "/=")                         \
  54.108 -    _(ASSIGN_MOD,         "%=")                         \
  54.109 -    _(ASSIGN_BITAND,      "&=")                         \
  54.110 -    _(ASSIGN_BITOR,       "|=")                         \
  54.111 -    _(ASSIGN_BITXOR,      "^=")                         \
  54.112 -    _(ASSIGN_SHR,         ">>=")                        \
  54.113 -    _(ASSIGN_USHR,        ">>>=")                       \
  54.114 -    _(ASSIGN_SHL,         "<<=")                        \
  54.115 -    _(INCREMENT,          "++")                         \
  54.116 -    _(DECREMENT,          "--")                         \
  54.117 -    _(EQUALS,             "==")                         \
  54.118 -    _(NOTEQUALS,          "!=")                         \
  54.119 -    _(LT,                 "<")                          \
  54.120 -    _(LE,                 "<=")                         \
  54.121 -    _(GT,                 ">")                          \
  54.122 -    _(GE,                 ">=")                         \
  54.123 -    _(AND,                "&&")                         \
  54.124 -    _(OR,                 "||")                         \
  54.125 -    _(COMMA,              ",")                          \
  54.126 -    _(NOT,                "!")                          \
  54.127 -    _(TILDE,              "~")                          \
  54.128 -    _(QMARK,              "?")                          \
  54.129 -    _(COLON,              ":")                          \
  54.130 -    _(UNDERSCORE,         "_")                          \
  54.131 -    _(DOT,                ".")                          \
  54.132 -    _(EOF,                "<end-of-file>")
  54.133 -
  54.134 -enum TokenKind
  54.135 -{
  54.136 -#   define _(name, str) TOK_##name,
  54.137 -    TOKENMAP(_)
  54.138 -#   undef _
  54.139 -    TOK_BITAND = TOK_AMPERSAND,
  54.140 -    TOKENS_TOTAL
  54.141 -};
  54.142 -
  54.143 -extern const char *TokenNames[];
  54.144 -
  54.145 -} // namespace ke
  54.146 -
  54.147 -#endif //_include_jitcraft_token_h_
    55.1 --- a/src/TypeManager.cpp	Mon Sep 17 00:10:01 2012 -0700
    55.2 +++ b/src/TypeManager.cpp	Sat Nov 17 18:41:01 2012 -0800
    55.3 @@ -88,33 +88,11 @@
    55.4  }
    55.5  
    55.6  Type *
    55.7 -TypeManager::newFunction(Handle<Type> returnType, Handle<FixedArray> args,
    55.8 -                         Handle<FixedArray> defaults)
    55.9 -{
   55.10 -    // :TODO: cache this.
   55.11 -    return Type::NewFunction(zone_, returnType, args, defaults);
   55.12 -}
   55.13 -
   55.14 -Type *
   55.15 -TypeManager::newNative(Handle<Type> returnType, Handle<FixedArray> args,
   55.16 -                       Handle<FixedArray> defaults, bool variadic)
   55.17 -{
   55.18 -    // :TODO: cache this.
   55.19 -    return Type::NewNative(zone_, returnType, args, defaults, variadic);
   55.20 -}
   55.21 -
   55.22 -Type *
   55.23  TypeManager::newEnum(Handle<String> name)
   55.24  {
   55.25      return Type::NewEnum(zone_, name);
   55.26  }
   55.27  
   55.28 -Type *
   55.29 -TypeManager::newStruct(Handle<String> name, Handle<FixedArray> fields, Handle<Map> newMap)
   55.30 -{
   55.31 -    return Type::NewStruct(zone_, name, fields, newMap);
   55.32 -}
   55.33 -
   55.34  void
   55.35  TypeManager::accept(VirtualObjectVisitor *visitor)
   55.36  {
    56.1 --- a/src/TypeManager.h	Mon Sep 17 00:10:01 2012 -0700
    56.2 +++ b/src/TypeManager.h	Sat Nov 17 18:41:01 2012 -0800
    56.3 @@ -56,11 +56,6 @@
    56.4      Type *newArray(Handle<Type> contained, int elements, bool isConst);
    56.5      Type *newExternalArray(Handle<Type> contained);
    56.6      Type *newEnum(Handle<String> name);
    56.7 -    Type *newFunction(Handle<Type> returnType, Handle<FixedArray> args,
    56.8 -                      Handle<FixedArray> deafults);
    56.9 -    Type *newNative(Handle<Type> returnType, Handle<FixedArray> args,
   56.10 -                    Handle<FixedArray> defaults, bool variadic);
   56.11 -    Type *newStruct(Handle<String> name, Handle<FixedArray> fields, Handle<Map> newMap);
   56.12      
   56.13      void accept(VirtualObjectVisitor *visitor);
   56.14  };
    57.1 --- a/src/Types.cpp	Mon Sep 17 00:10:01 2012 -0700
    57.2 +++ b/src/Types.cpp	Sat Nov 17 18:41:01 2012 -0800
    57.3 @@ -34,11 +34,6 @@
    57.4  
    57.5      type->kind_ = VOID;
    57.6      type->contained_ = NULL;
    57.7 -    type->returnType_ = NULL;
    57.8 -    type->parameters_ = NULL;
    57.9 -    type->defaults_ = NULL;
   57.10 -    type->fields_ = NULL;
   57.11 -    type->newMap_ = NULL;
   57.12      return type;
   57.13  }
   57.14  
   57.15 @@ -51,11 +46,6 @@
   57.16  
   57.17      type->kind_ = UNCHECKED;
   57.18      type->contained_ = NULL;
   57.19 -    type->returnType_ = NULL;
   57.20 -    type->parameters_ = NULL;
   57.21 -    type->defaults_ = NULL;
   57.22 -    type->fields_ = NULL;
   57.23 -    type->newMap_ = NULL;
   57.24      return type;
   57.25  }
   57.26  
   57.27 @@ -69,12 +59,6 @@
   57.28      type->kind_ = PRIMITIVE;
   57.29      type->name_ = NULL;
   57.30      type->contained_ = NULL;
   57.31 -    type->returnType_ = NULL;
   57.32 -    type->parameters_ = NULL;
   57.33 -    type->defaults_ = NULL;
   57.34 -    type->fields_ = NULL;
   57.35 -    type->newMap_ = NULL;
   57.36 -    type->newMap_ = NULL;
   57.37      type->primitive_ = prim;
   57.38      return type;
   57.39  }
   57.40 @@ -89,11 +73,6 @@
   57.41      type->kind_ = ARRAY;
   57.42      type->name_ = NULL;
   57.43      type->contained_ = contained;
   57.44 -    type->returnType_ = NULL;
   57.45 -    type->parameters_ = NULL;
   57.46 -    type->defaults_ = NULL;
   57.47 -    type->fields_ = NULL;
   57.48 -    type->newMap_ = NULL;
   57.49      type->elements_ = elements;
   57.50      if (!contained->isArray())
   57.51          type->levels_ = 1;
   57.52 @@ -115,11 +94,6 @@
   57.53      type->kind_ = EXTERNAL_ARRAY;
   57.54      type->name_ = NULL;
   57.55      type->contained_ = contained;
   57.56 -    type->returnType_ = NULL;
   57.57 -    type->parameters_ = NULL;
   57.58 -    type->defaults_ = NULL;
   57.59 -    type->fields_ = NULL;
   57.60 -    type->newMap_ = NULL;
   57.61      type->elements_ = DYNAMIC_ARRAY_SIZE;
   57.62      type->levels_ = 1;
   57.63      type->const_ = false;
   57.64 @@ -136,35 +110,11 @@
   57.65      type->kind_ = REFERENCE;
   57.66      type->name_ = NULL;
   57.67      type->contained_ = contained;
   57.68 -    type->returnType_ = NULL;
   57.69 -    type->parameters_ = NULL;
   57.70 -    type->defaults_ = NULL;
   57.71 -    type->fields_ = NULL;
   57.72 -    type->newMap_ = NULL;
   57.73      type->const_ = isConst;
   57.74      return type;
   57.75  }
   57.76  
   57.77  Type *
   57.78 -Type::NewFunction(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
   57.79 -                  Handle<FixedArray> defaults)
   57.80 -{
   57.81 -    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   57.82 -    if (!type)
   57.83 -        return NULL;
   57.84 -
   57.85 -    type->kind_ = FUNCTION;
   57.86 -    type->name_ = NULL;
   57.87 -    type->contained_ = NULL;
   57.88 -    type->fields_ = NULL;
   57.89 -    type->newMap_ = NULL;
   57.90 -    type->returnType_ = returnType;
   57.91 -    type->parameters_ = parameters;
   57.92 -    type->defaults_ = defaults;
   57.93 -    return type;
   57.94 -}
   57.95 -
   57.96 -Type *
   57.97  Type::NewEnum(Zone *zone, Handle<String> name)
   57.98  {
   57.99      Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  57.100 @@ -174,32 +124,10 @@
  57.101      type->kind_ = ENUM;
  57.102      type->name_ = name;
  57.103      type->contained_ = NULL;
  57.104 -    type->returnType_ = NULL;
  57.105 -    type->parameters_ = NULL;
  57.106 -    type->defaults_ = NULL;
  57.107 -    type->fields_ = NULL;
  57.108 -    type->newMap_ = NULL;
  57.109      return type;
  57.110  }
  57.111  
  57.112 -Type *
  57.113 -Type::NewStruct(Zone *zone, Handle<String> name, Handle<FixedArray> fields, Handle<Map> newMap)
  57.114 -{
  57.115 -    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  57.116 -    if (!type)
  57.117 -        return NULL;
  57.118 -
  57.119 -    type->kind_ = STRUCT;
  57.120 -    type->name_ = name;
  57.121 -    type->contained_ = NULL;
  57.122 -    type->returnType_ = NULL;
  57.123 -    type->parameters_ = NULL;
  57.124 -    type->defaults_ = NULL;
  57.125 -    type->newMap_ = newMap;
  57.126 -    type->fields_ = fields;
  57.127 -    return type;
  57.128 -}
  57.129 -
  57.130 +#if 0
  57.131  Type *
  57.132  Type::NewNative(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
  57.133                  Handle<FixedArray> defaults, bool variadic)
  57.134 @@ -219,6 +147,7 @@
  57.135      type->variadicNative_ = variadic;
  57.136      return type;
  57.137  }
  57.138 +#endif
  57.139  
  57.140  bool
  57.141  Type::Compare(Type *left, Type *right)
  57.142 @@ -244,17 +173,19 @@
  57.143  
  57.144        case Type::FUNCTION:
  57.145        {
  57.146 -        if (!Compare(left->returnType(), right->returnType()))
  57.147 +        FunctionType *fleft = FunctionType::cast(left);
  57.148 +        FunctionType *fright = FunctionType::cast(right);
  57.149 +        if (!Compare(fleft->returnType(), fright->returnType()))
  57.150              return false;
  57.151 -        if (left->parameters()->length() != right->parameters()->length())
  57.152 -            return false;
  57.153 -        if (left->isNative() != right->isNative())
  57.154 +        if (fleft->parameters()->length() != fright->parameters()->length())
  57.155              return false;
  57.156 -        if (left->isNative() && (left->isNativeVariadic() != right->isNativeVariadic()))
  57.157 +        if (fleft->isNative() != fright->isNative())
  57.158 +            return false;
  57.159 +        if (fleft->isNative() && (fleft->isNativeVariadic() != fright->isNativeVariadic()))
  57.160              return false;
  57.161 -        for (unsigned i = 0; i < left->parameters()->length(); i++) {
  57.162 -            Type *leftparam = left->parameterAt(i);
  57.163 -            Type *rightparam = right->parameterAt(i);
  57.164 +        for (unsigned i = 0; i < fleft->parameters()->length(); i++) {
  57.165 +            Type *leftparam = fleft->parameterAt(i);
  57.166 +            Type *rightparam = fright->parameterAt(i);
  57.167              if (!Compare(leftparam, rightparam))
  57.168                  return false;
  57.169          }
  57.170 @@ -273,15 +204,50 @@
  57.171      }
  57.172  }
  57.173  
  57.174 -Descriptor *
  57.175 -Type::lookupField(Handle<String> name, unsigned *index)
  57.176 +
  57.177 +StructType *
  57.178 +StructType::New(Zone *zone, Handle<String> name, Handle<FixedArray> fields)
  57.179  {
  57.180 -    assert(isStruct());
  57.181 +    Local<StructType> type(zone, StructType::cast(zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old)));
  57.182 +    if (!type)
  57.183 +        return NULL;
  57.184 +
  57.185 +    type->kind_ = STRUCT;
  57.186 +    type->name_ = name;
  57.187 +    type->contained_ = NULL;
  57.188 +    type->newMap_ = NULL;
  57.189 +    type->fields_ = fields;
  57.190 +
  57.191 +    // Fill in field offsets.
  57.192 +    StructureBufferBuilder builder;
  57.193 +    Local<Type> fieldType(zone);
  57.194 +    for (size_t i = 0; i < fields->length(); i++) {
  57.195 +        Descriptor *desc = Descriptor::cast(fields->at(i));
  57.196 +        fieldType = desc->type();
  57.197  
  57.198 +        unsigned offset;
  57.199 +        if (!builder.add(fieldType, &offset))
  57.200 +            return NULL;
  57.201 +        desc->setOffset(offset);
  57.202 +    }
  57.203 +
  57.204 +    Local<StructMap> map(zone, StructMap::New(zone, builder, type));
  57.205 +    if (!map)
  57.206 +        return NULL;
  57.207 +
  57.208 +    type->newMap_ = map;
  57.209 +
  57.210 +    return type;
  57.211 +}
  57.212 +
  57.213 +Descriptor *
  57.214 +StructType::lookupField(Handle<String> name, unsigned *index)
  57.215 +{
  57.216      for (unsigned i = 0; i < fields_->length(); i++) {
  57.217          Descriptor *desc = Descriptor::cast(fields_->at(i));
  57.218          if (desc->name() == name) {
  57.219 -            *index = i;
  57.220 +            if (index)
  57.221 +                *index = i;
  57.222              return desc;
  57.223          }
  57.224      }
  57.225 @@ -289,3 +255,48 @@
  57.226      return NULL;
  57.227  }
  57.228  
  57.229 +FunctionType *
  57.230 +FunctionType::New(Zone *zone, TokenKind token)
  57.231 +{
  57.232 +    Local<FunctionType> type(zone, FunctionType::cast(zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old)));
  57.233 +    if (!type)
  57.234 +        return NULL;
  57.235 +
  57.236 +    type->kind_ = FUNCTION;
  57.237 +    type->name_ = NULL;
  57.238 +    type->contained_ = NULL;
  57.239 +    type->parameters_ = NULL;
  57.240 +    type->defaults_ = NULL;
  57.241 +    type->returnType_ = NULL;
  57.242 +    type->token_ = token;
  57.243 +    return type;
  57.244 +}
  57.245 +
  57.246 +// :TODO: this leaks an interior pointer.
  57.247 +const char *
  57.248 +ke::GetTypeName(Type *type)
  57.249 +{
  57.250 +    if (type->isArray())
  57.251 +        return "array";
  57.252 +    if (type->isFunction())
  57.253 +        return "function";
  57.254 +    if (type->isVoid())
  57.255 +        return "void";
  57.256 +    if (type->isEnum() || type->isStruct())
  57.257 +        return type->name()->chars();
  57.258 +    if (type->isReference())
  57.259 +        type = type->contained();
  57.260 +    switch (type->primitive()) {
  57.261 +      case PrimitiveType_Bool:
  57.262 +        return "bool";
  57.263 +      case PrimitiveType_Char:
  57.264 +        return "String";
  57.265 +      case PrimitiveType_Int32:
  57.266 +        return "int";
  57.267 +      case PrimitiveType_Float:
  57.268 +        return "Float";
  57.269 +      default:
  57.270 +        return "<unknown>";
  57.271 +    }
  57.272 +}
  57.273 +
    58.1 --- a/src/Types.h	Mon Sep 17 00:10:01 2012 -0700
    58.2 +++ b/src/Types.h	Sat Nov 17 18:41:01 2012 -0800
    58.3 @@ -22,11 +22,13 @@
    58.4  #include "Heap.h"
    58.5  #include "Barriers.h"
    58.6  #include "FixedArray.h"
    58.7 +#include "compiler/Token.h"
    58.8  
    58.9  namespace ke {
   58.10  
   58.11  class String;
   58.12  class Descriptor;
   58.13 +class StructMap;
   58.14  
   58.15  #define MAX_ARRAY_DEPTH     5
   58.16  
   58.17 @@ -59,6 +61,7 @@
   58.18  
   58.19  class Type : public Object
   58.20  {
   58.21 +  protected:
   58.22      enum Kind {
   58.23          // A primitive is a plain-old-data type.
   58.24          PRIMITIVE,
   58.25 @@ -74,9 +77,6 @@
   58.26          // A function type encapsulates a function signature.
   58.27          FUNCTION,
   58.28  
   58.29 -        // A native is a limited type of function used for system calls.
   58.30 -        NATIVE,
   58.31 -
   58.32          // Void is an internal type used to specify that a function returns no
   58.33          // value.
   58.34          VOID,
   58.35 @@ -108,17 +108,15 @@
   58.36      static Type *NewArray(Zone *zone, Handle<Type> contained, int elements, bool isConst);
   58.37      static Type *NewExternalArray(Zone *zone, Handle<Type> contained);
   58.38      static Type *NewReference(Zone *zone, Handle<Type> contained, bool isConst);
   58.39 -    static Type *NewFunction(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
   58.40 -                             Handle<FixedArray> defaults);
   58.41 -    static Type *NewNative(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
   58.42 -                           Handle<FixedArray> defaults, bool isVariadic);
   58.43      static Type *NewEnum(Zone *zone, Handle<String> name);
   58.44 -    static Type *NewStruct(Zone *zone, Handle<String> name, Handle<FixedArray> fields, Handle<Map> newMap);
   58.45  
   58.46      static bool Compare(Type *left, Type *right);
   58.47  
   58.48      static Type *cast(Object *obj) {
   58.49 -        assert(!obj || obj->is(MapKind_Type));
   58.50 +        assert(!obj ||
   58.51 +               obj->is(MapKind_Type) ||
   58.52 +               obj->is(MapKind_FunctionType) ||
   58.53 +               obj->is(MapKind_StructType));
   58.54          return (Type *)obj;
   58.55      }
   58.56  
   58.57 @@ -132,10 +130,7 @@
   58.58          return kind() == REFERENCE;
   58.59      }
   58.60      bool isFunction() {
   58.61 -        return kind() == FUNCTION || kind() == NATIVE;
   58.62 -    }
   58.63 -    bool isNative() {
   58.64 -        return kind() == NATIVE;
   58.65 +        return kind() == FUNCTION;
   58.66      }
   58.67      bool isVoid() {
   58.68          return kind() == VOID;
   58.69 @@ -146,10 +141,6 @@
   58.70      bool isStruct() {
   58.71          return kind() == STRUCT;
   58.72      }
   58.73 -    bool isNativeVariadic() {
   58.74 -        assert(isNative());
   58.75 -        return variadicNative_;
   58.76 -    }
   58.77      PrimitiveType primitive() {
   58.78          assert(isPrimitive());
   58.79          return primitive_;
   58.80 @@ -216,21 +207,6 @@
   58.81      bool isExternalArray() {
   58.82          return kind() == EXTERNAL_ARRAY;
   58.83      }
   58.84 -    Type *returnType() {
   58.85 -        assert(isFunction());
   58.86 -        return returnType_;
   58.87 -    }
   58.88 -    FixedArray *parameters() {
   58.89 -        assert(isFunction());
   58.90 -        return parameters_;
   58.91 -    }
   58.92 -    FixedArray *defaults() {
   58.93 -        assert(isFunction());
   58.94 -        return defaults_;
   58.95 -    }
   58.96 -    Type *parameterAt(size_t i) {
   58.97 -        return Type::cast(parameters()->at(i));
   58.98 -    }
   58.99      bool isTraceable() {
  58.100          return !isPrimitive();
  58.101      }
  58.102 @@ -248,47 +224,25 @@
  58.103          assert(isEnum() || isStruct());
  58.104          return name_;
  58.105      }
  58.106 -    FixedArray *fields() {
  58.107 -        assert(isStruct());
  58.108 -        return fields_;
  58.109 +
  58.110 +    Map *newMap() {
  58.111 +        assert(false);
  58.112 +        return NULL;
  58.113      }
  58.114 -    Descriptor *lookupField(Handle<String> name, unsigned *index);
  58.115 -
  58.116 -    // Objects of this type can be created with this cached map.
  58.117 -    Map *newMap() {
  58.118 -        assert(isStruct() || isArray());
  58.119 -        return newMap_;
  58.120 -    }
  58.121 -    void setNewMap(Map *map) {
  58.122 -        assert(!newMap());
  58.123 -        newMap_ = map;
  58.124 +    void setNewMap(void *p) {
  58.125 +        assert(false);
  58.126      }
  58.127  
  58.128      // GC Descriptor.
  58.129      static inline size_t offsetOfContained() {
  58.130          return OFFSETOF(Type, contained_);
  58.131      }
  58.132 -    static inline size_t offsetOfReturnType() {
  58.133 -        return OFFSETOF(Type, returnType_);
  58.134 -    }
  58.135 -    static inline size_t offsetOfParameters() {
  58.136 -        return OFFSETOF(Type, parameters_);
  58.137 -    }
  58.138      static inline size_t offsetOfName() {
  58.139          return OFFSETOF(Type, name_);
  58.140      }
  58.141 -    static inline size_t offsetOfFields() {
  58.142 -        return OFFSETOF(Type, fields_);
  58.143 -    }
  58.144 -    static inline size_t offsetOfNewMap() {
  58.145 -        return OFFSETOF(Type, newMap_);
  58.146 -    }
  58.147 -    static inline size_t offsetOfDefaults() {
  58.148 -        return OFFSETOF(Type, defaults_);
  58.149 -    }
  58.150      // End GC Descriptor.
  58.151  
  58.152 -  private:
  58.153 +  protected:
  58.154      Kind kind_;
  58.155      PrimitiveType primitive_;
  58.156  
  58.157 @@ -302,18 +256,116 @@
  58.158      // Arrays and references only.
  58.159      Barriered<Type> contained_;
  58.160  
  58.161 +    // Enums and structs only.
  58.162 +    Barriered<String> name_;
  58.163 +};
  58.164 +
  58.165 +class StructType : public Type
  58.166 +{
  58.167 +  public:
  58.168 +    static StructType *New(Zone *zone, Handle<String> name, Handle<FixedArray> fields);
  58.169 +
  58.170 +    FixedArray *fields() {
  58.171 +        assert(isStruct());
  58.172 +        return fields_;
  58.173 +    }
  58.174 +    Descriptor *lookupField(Handle<String> name, unsigned *index = NULL);
  58.175 +
  58.176 +    // Objects of this type can be created with this cached map.
  58.177 +    StructMap *newMap() {
  58.178 +        return newMap_;
  58.179 +    }
  58.180 +    void setNewMap(StructMap *map) {
  58.181 +        assert(!newMap());
  58.182 +        newMap_ = map;
  58.183 +    }
  58.184 +
  58.185 +    // GC Descriptor.
  58.186 +    static inline size_t offsetOfFields() {
  58.187 +        return OFFSETOF(StructType, fields_);
  58.188 +    }
  58.189 +    static inline size_t offsetOfNewMap() {
  58.190 +        return OFFSETOF(StructType, newMap_);
  58.191 +    }
  58.192 +    // End GC Descriptor.
  58.193 +
  58.194 +    static StructType *cast(Object *obj) {
  58.195 +        assert(!obj || obj->is(MapKind_StructType));
  58.196 +        return (StructType *)obj;
  58.197 +    }
  58.198 +
  58.199 +  private:
  58.200 +    // Structs only.
  58.201 +    Barriered<FixedArray> fields_;
  58.202 +    Barriered<StructMap> newMap_;
  58.203 +};
  58.204 +
  58.205 +class FunctionType : public Type
  58.206 +{
  58.207 +  public:
  58.208 +    static FunctionType *New(Zone *zone, TokenKind kind);
  58.209 +
  58.210 +    Type *parameterAt(size_t i) {
  58.211 +        return Type::cast(parameters()->at(i));
  58.212 +    }
  58.213 +    Type *returnType() {
  58.214 +        assert(isFunction());
  58.215 +        return returnType_;
  58.216 +    }
  58.217 +    FixedArray *parameters() {
  58.218 +        assert(isFunction());
  58.219 +        return parameters_;
  58.220 +    }
  58.221 +    FixedArray *defaults() {
  58.222 +        assert(isFunction());
  58.223 +        return defaults_;
  58.224 +    }
  58.225 +    bool isNative() {
  58.226 +        return token_ == TOK_NATIVE;
  58.227 +    }
  58.228 +    bool isForward() {
  58.229 +        return token_ == TOK_FORWARD;
  58.230 +    }
  58.231 +    bool isNativeVariadic() {
  58.232 +        assert(isNative());
  58.233 +        return variadicNative_;
  58.234 +    }
  58.235 +    void setReturnType(Handle<Type> returnType) {
  58.236 +        assert(!returnType_);
  58.237 +        returnType_ = returnType;
  58.238 +    }
  58.239 +    void setParameterTypes(Handle<FixedArray> types) {
  58.240 +        assert(!parameters_);
  58.241 +        parameters_ = types;
  58.242 +    }
  58.243 +    TokenKind token() {
  58.244 +        return token_;
  58.245 +    }
  58.246 +
  58.247 +    // GC Descriptor.
  58.248 +    static inline size_t offsetOfReturnType() {
  58.249 +        return OFFSETOF(FunctionType, returnType_);
  58.250 +    }
  58.251 +    static inline size_t offsetOfParameters() {
  58.252 +        return OFFSETOF(FunctionType, parameters_);
  58.253 +    }
  58.254 +    static inline size_t offsetOfDefaults() {
  58.255 +        return OFFSETOF(FunctionType, defaults_);
  58.256 +    }
  58.257 +    // End GC Descriptor.
  58.258 +
  58.259 +    static FunctionType *cast(Object *obj) {
  58.260 +        assert(!obj || obj->is(MapKind_FunctionType));
  58.261 +        return (FunctionType *)obj;
  58.262 +    }
  58.263 +
  58.264 +  private:
  58.265      // Functions only.
  58.266      Barriered<Type> returnType_;
  58.267      Barriered<FixedArray> parameters_;
  58.268      Barriered<FixedArray> defaults_;
  58.269 +    TokenKind token_;
  58.270      bool variadicNative_;
  58.271 -
  58.272 -    // Enums and structs only.
  58.273 -    Barriered<String> name_;
  58.274 -
  58.275 -    // Structs only.
  58.276 -    Barriered<FixedArray> fields_;
  58.277 -    Barriered<Map> newMap_;
  58.278  };
  58.279  
  58.280  class BoxedPrimitive
  58.281 @@ -351,6 +403,8 @@
  58.282      }
  58.283  };
  58.284  
  58.285 +const char *GetTypeName(Type *type);
  58.286 +
  58.287  }
  58.288  
  58.289  #endif // _include_jc_types_h_
    59.1 --- a/src/Utility.h	Mon Sep 17 00:10:01 2012 -0700
    59.2 +++ b/src/Utility.h	Sat Nov 17 18:41:01 2012 -0800
    59.3 @@ -37,6 +37,8 @@
    59.4  typedef uint8_t uint8;
    59.5  typedef int32_t int32;
    59.6  typedef uint32_t uint32;
    59.7 +typedef int64_t int64;
    59.8 +typedef uint64_t uint64;
    59.9  
   59.10  typedef uint8 * Address;
   59.11  
   59.12 @@ -110,6 +112,41 @@
   59.13      return hasher.result();
   59.14  }
   59.15  
   59.16 +// From http://burtleburtle.net/bob/hash/integer.html
   59.17 +static inline uint32
   59.18 +HashInt32(int32 a)
   59.19 +{
   59.20 +    a = (a ^ 61) ^ (a >> 16);
   59.21 +    a = a + (a << 3);
   59.22 +    a = a ^ (a >> 4);
   59.23 +    a = a * 0x27d4eb2d;
   59.24 +    a = a ^ (a >> 15);
   59.25 +    return a;
   59.26 +}
   59.27 +
   59.28 +// From http://www.cris.com/~Ttwang/tech/inthash.htm
   59.29 +static inline uint32
   59.30 +HashInt64(int64 key)
   59.31 +{
   59.32 +  key = (~key) + (key << 18); // key = (key << 18) - key - 1;
   59.33 +  key = key ^ (uint64(key) >> 31);
   59.34 +  key = key * 21; // key = (key + (key << 2)) + (key << 4);
   59.35 +  key = key ^ (uint64(key) >> 11);
   59.36 +  key = key + (key << 6);
   59.37 +  key = key ^ (uint64(key) >> 22);
   59.38 +  return uint32(key);
   59.39 +}
   59.40 +
   59.41 +static inline uint32
   59.42 +HashPointer(void *p)
   59.43 +{
   59.44 +#if defined(KE_32BIT)
   59.45 +    return HashInt32(reinterpret_cast<int32>(p));
   59.46 +#elif defined(KE_64BIT)
   59.47 +    return HashInt64(reinterpret_cast<int64>(p));
   59.48 +#endif
   59.49 +}
   59.50 +
   59.51  static inline size_t
   59.52  Log2(size_t number)
   59.53  {
    60.1 --- a/src/Vector.h	Mon Sep 17 00:10:01 2012 -0700
    60.2 +++ b/src/Vector.h	Sat Nov 17 18:41:01 2012 -0800
    60.3 @@ -47,6 +47,11 @@
    60.4          nitems++;
    60.5          return true;
    60.6      }
    60.7 +    void infallibleAppend(const T &item) {
    60.8 +        assert(GrowIfNeeded(1));
    60.9 +        new (&data[nitems]) T(item);
   60.10 +        nitems++;
   60.11 +    }
   60.12      T popCopy() {
   60.13          T t = at(length() - 1);
   60.14          pop();
   60.15 @@ -85,6 +90,13 @@
   60.16          return data;
   60.17      }
   60.18  
   60.19 +    bool ensure(size_t desired) {
   60.20 +        if (desired <= length())
   60.21 +            return true;
   60.22 +
   60.23 +        return GrowIfNeeded(desired - length());
   60.24 +    }
   60.25 +
   60.26    private:
   60.27      bool GrowIfNeeded(size_t needed)
   60.28      {
    61.1 --- a/src/VirtualObjectVisitor.h	Mon Sep 17 00:10:01 2012 -0700
    61.2 +++ b/src/VirtualObjectVisitor.h	Sat Nov 17 18:41:01 2012 -0800
    61.3 @@ -2,25 +2,26 @@
    61.4   *
    61.5   * Copyright (C) 2012 David Anderson
    61.6   *
    61.7 - * This file is part of JITCraft.
    61.8 + * This file is part of SourcePawn.
    61.9   *
   61.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   61.11 + * SourcePawn is free software: you can redistribute it and/or modify it under
   61.12   * the terms of the GNU General Public License as published by the Free
   61.13   * Software Foundation, either version 3 of the License, or (at your option)
   61.14   * any later version.
   61.15   * 
   61.16 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   61.17 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   61.18   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   61.19   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   61.20   *
   61.21   * You should have received a copy of the GNU General Public License along with
   61.22 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   61.23 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   61.24   */
   61.25  #ifndef _include_jc_virtual_object_visitor_h_
   61.26  #define _include_jc_virtual_object_visitor_h_
   61.27  
   61.28  namespace ke {
   61.29  
   61.30 +class Zone;
   61.31  class Object;
   61.32  
   61.33  class VirtualObjectVisitor
   61.34 @@ -29,6 +30,21 @@
   61.35      virtual void visit(Object **ptr) = 0;
   61.36  };
   61.37  
   61.38 +// This is a helper class for automatically rooting C++ objects that need
   61.39 +// special tracing. It is implemented in Zone.
   61.40 +class AutoRooted
   61.41 +{
   61.42 +  public:
   61.43 +    AutoRooted(Zone *zone);
   61.44 +    ~AutoRooted();
   61.45 +
   61.46 +    virtual void accept(VirtualObjectVisitor *visitor) = 0;
   61.47 +
   61.48 +  private:
   61.49 +    Zone *zone_;
   61.50 +    AutoRooted *prev_;
   61.51 +};
   61.52 +
   61.53  }
   61.54  
   61.55  #endif // _include_jc_virtual_object_visitor_h_
    62.1 --- a/src/Zone.cpp	Mon Sep 17 00:10:01 2012 -0700
    62.2 +++ b/src/Zone.cpp	Sat Nov 17 18:41:01 2012 -0800
    62.3 @@ -23,6 +23,7 @@
    62.4  #include "GlobalRoots.h"
    62.5  #include "AllocatorPolicies.h"
    62.6  #include "Array.h"
    62.7 +#include "NativeTable.h"
    62.8  #include "Spaces-inl.h"
    62.9  #include "Heap-inl.h"
   62.10  
   62.11 @@ -30,6 +31,8 @@
   62.12  
   62.13  Zone *ke::SingleThreadedZone;
   62.14  
   62.15 +void * const NullAddress::Sentinel = NULL;
   62.16 +
   62.17  Zone::Zone()
   62.18    : stack_(thisFromCtor()),
   62.19      heap_(thisFromCtor()),
   62.20 @@ -37,6 +40,7 @@
   62.21      symbols_(NULL),
   62.22      globalRoots_(NULL),
   62.23      lastLocalRoot_(NULL),
   62.24 +    specialRoots_(NULL),
   62.25      hasPendingException_(false),
   62.26      reporter_(NULL)
   62.27  {
   62.28 @@ -45,8 +49,9 @@
   62.29  Zone::~Zone()
   62.30  {
   62.31      delete types_;
   62.32 +    delete nativeTable_;
   62.33 +    delete globalRoots_;
   62.34      delete symbols_;
   62.35 -    delete globalRoots_;
   62.36  }
   62.37  
   62.38  bool
   62.39 @@ -65,9 +70,17 @@
   62.40      if (!globalRoots_ || !globalRoots_->initialize())
   62.41          return false;
   62.42  
   62.43 +    nativeTable_ = new NativeTable(this);
   62.44 +    if (!nativeTable_ || !nativeTable_->initialize())
   62.45 +        return false;
   62.46 +
   62.47      maps_[MapKind_Meta] = heap_.metaMap();
   62.48      if ((maps_[MapKind_Type] = allocateMap(MapKind_Type, sizeof(Map))) == NULL)
   62.49          return false;
   62.50 +    if ((maps_[MapKind_FunctionType] = allocateMap(MapKind_FunctionType, sizeof(Map))) == NULL)
   62.51 +        return false;
   62.52 +    if ((maps_[MapKind_StructType] = allocateMap(MapKind_StructType, sizeof(Map))) == NULL)
   62.53 +        return false;
   62.54      if ((maps_[MapKind_FixedArray] = allocateMap(MapKind_FixedArray, sizeof(Map))) == NULL)
   62.55          return false;
   62.56      if ((maps_[MapKind_ByteArray] = allocateMap(MapKind_ByteArray, sizeof(Map))) == NULL)
   62.57 @@ -118,9 +131,12 @@
   62.58          if (!type)
   62.59              return false;
   62.60  
   62.61 +        // :TODO:
   62.62 +#if 0
   62.63          externalGenericArrayMap_ = ArrayMap::Attach(this, type);
   62.64          if (!externalGenericArrayMap_)
   62.65              return false;
   62.66 +#endif
   62.67  
   62.68          type = types_->getPrimitive(PrimitiveType_Char);
   62.69          if (!type)
   62.70 @@ -130,9 +146,12 @@
   62.71          if (!type)
   62.72              return false;
   62.73  
   62.74 +        // :TODO:
   62.75 +#if 0
   62.76          externalCharArrayMap_ = ArrayMap::Attach(this, type);
   62.77          if (!externalCharArrayMap_)
   62.78              return false;
   62.79 +#endif
   62.80      }
   62.81  
   62.82      return true;
   62.83 @@ -166,6 +185,7 @@
   62.84  
   62.85      globalRoots_->accept(visitor);
   62.86      rootScopes_.accept(visitor);
   62.87 +    nativeTable_->accept(visitor);
   62.88  
   62.89      stack_.accept(visitor);
   62.90  }
   62.91 @@ -315,7 +335,13 @@
   62.92  void
   62.93  ZoneAllocatorPolicy::reportAllocationOverflow()
   62.94  {
   62.95 -    ZONE()->reportError(Message_AllocationOverflow);
   62.96 +    ZONE()->reportAllocationOverflow();
   62.97 +}
   62.98 +
   62.99 +void
  62.100 +Zone::reportAllocationOverflow()
  62.101 +{
  62.102 +    reportError(Message_AllocationOverflow);
  62.103  }
  62.104  
  62.105  void
  62.106 @@ -324,3 +350,20 @@
  62.107      hasPendingException_ = false;
  62.108  }
  62.109  
  62.110 +void
  62.111 +Zone::setPublicFunctionListener(Ke::IPublicFunctionListener *listener)
  62.112 +{
  62.113 +    publicFunctionListener_ = listener;
  62.114 +}
  62.115 +
  62.116 +AutoRooted::AutoRooted(Zone *zone)
  62.117 +  : zone_(zone),
  62.118 +    prev_(*zone->lastSpecialRoot())
  62.119 +{
  62.120 +    *zone->lastSpecialRoot() = this;
  62.121 +}
  62.122 +
  62.123 +AutoRooted::~AutoRooted()
  62.124 +{
  62.125 +    *zone_->lastSpecialRoot() = prev_;
  62.126 +}
    63.1 --- a/src/Zone.h	Mon Sep 17 00:10:01 2012 -0700
    63.2 +++ b/src/Zone.h	Sat Nov 17 18:41:01 2012 -0800
    63.3 @@ -37,6 +37,7 @@
    63.4  class GlobalRoots;
    63.5  class ArrayMap;
    63.6  class Exception;
    63.7 +class NativeTable;
    63.8  
    63.9  class Zone
   63.10  {
   63.11 @@ -52,15 +53,19 @@
   63.12      TypeManager *types_;
   63.13      StringPool *symbols_;
   63.14      GlobalRoots *globalRoots_;
   63.15 +    NativeTable *nativeTable_;
   63.16  
   63.17      // Root list.
   63.18      Local<Object> *lastLocalRoot_;
   63.19      RootScopeManager rootScopes_;
   63.20 +    AutoRooted *specialRoots_;
   63.21  
   63.22      // Exception stuff.
   63.23      bool hasPendingException_;
   63.24      Ke::IMessageReporter *reporter_;
   63.25  
   63.26 +    Ke::IPublicFunctionListener *publicFunctionListener_;
   63.27 +
   63.28    private:
   63.29      Zone *thisFromCtor() {
   63.30          return this;
   63.31 @@ -103,6 +108,9 @@
   63.32      TypeManager *types() const {
   63.33          return types_;
   63.34      }
   63.35 +    AutoRooted **lastSpecialRoot() {
   63.36 +        return &specialRoots_;
   63.37 +    }
   63.38      Local<Object> **lastLocalRoot() {
   63.39          return &lastLocalRoot_;
   63.40      }
   63.41 @@ -118,11 +126,15 @@
   63.42      GlobalRoots *globalRoots() {
   63.43          return globalRoots_;
   63.44      }
   63.45 +    NativeTable *nativeTable() {
   63.46 +        return nativeTable_;
   63.47 +    }
   63.48  
   63.49      String *makeSymbol(const char *string, size_t length);
   63.50      String *makeSymbol(const char *string);
   63.51  
   63.52      void reportOutOfMemory();
   63.53 +    void reportAllocationOverflow();
   63.54      void reportError(Message message, ...);
   63.55      void reportErrorVA(Message message, va_list ap);
   63.56      bool hasPendingException();
   63.57 @@ -133,6 +145,10 @@
   63.58      void endCompilationErrors();
   63.59  
   63.60      void accept(VirtualObjectVisitor *visitor);
   63.61 +
   63.62 +    void setPublicFunctionListener(Ke::IPublicFunctionListener *listener);
   63.63 +    void registerPublic(Handle<Function> fun);
   63.64 +    void unregisterPublic(Handle<Function> fun);
   63.65  };
   63.66  
   63.67  // In a multi-threaded system, this would be a TLS variable.
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/src/comment	Sat Nov 17 18:41:01 2012 -0800
    64.3 @@ -0,0 +1,101 @@
    64.4 +Massive refactoring to support better type systems. Read on for more.
    64.5 +
    64.6 +The previous compiler had a simple pipeline, best outlined as:
    64.7 +  (1) Parsing and name binding -> AST
    64.8 +  (2) Storage allocation -> AST
    64.9 +  (3) Semantic Analysis (SemA) -> AST
   64.10 +  (4) Bytecode Compilation (BC) -> Code
   64.11 +
   64.12 +This pipeline, unfortunately, had two problems. First, name binding cannot be performed in one pass if we wish to have multi-file support in the form of modules. Name binding must be two-pass. 
   64.13 +
   64.14 +Second, because SemA was only capable of annotating AST nodes with a single type, most coercion work had to be duplicated in the BC phase, as coercion was not explicit in the SemA output. This made introducing new type rules extremely difficult, and all but precluded concepts like operator overloading (or overloading at all).
   64.15 +
   64.16 +This patch rewrites most of Keima's backend. Of interest are the following changes:
   64.17 +  (1) CompileContext has been refactored around future multi-file support.
   64.18 +  (2) Parsing no longer performs any name binding.
   64.19 +  (3) The grammar for type-and-name has been changed from:
   64.20 +       (Label | Identifier)? Identifier
   64.21 +      to:
   64.22 +       Type? Identifier
   64.23 +      where:
   64.24 +       Type ::= OldType | NewType
   64.25 +       OldType ::= Label
   64.26 +       NewType ::= Identifier (. NewType)*
   64.27 +                
   64.28 +
   64.29 +      Although we do not implement the full production for Type yet, this
   64.30 +      distinction is important. A type identifier is now affixed to the AST
   64.31 +      as an Expression (right now, always a NameProxy), so it can fully
   64.32 +      participate in name binding.
   64.33 +
   64.34 +  (4) Immediately after parsing, the AST goes through a NamePopulation phase.
   64.35 +      This phase creates Scope objects for every scope which declares a name,
   64.36 +      and if those names are declaring types or functions, a Symbol is created
   64.37 +      and entered into the scope. Symbols entirely replace the old BoundName
   64.38 +      classes.
   64.39 +
   64.40 +  (5) After NamePopulation comes NameBinding. This phase performs three steps:
   64.41 +      (a) Links Scope objects together, to form a tree.
   64.42 +      (b) Binds any free name to an existing name in the scope chain.
   64.43 +      (c) Creates and registers any Symbols for names which have not yet been
   64.44 +          added to the scope (for example, local variables).
   64.45 +
   64.46 +      In accordance, all "allocation" and "binding" concepts have been removed
   64.47 +      from Scopes, which are now lightweight container classes.
   64.48 +
   64.49 +  (6) SemA now generates bytecode for each statement in the AST. Expression
   64.50 +      compilation is performed via a separate mechanism called HIR (High-level
   64.51 +      Intermediate Representation). To analyze an expression, SemA will walk
   64.52 +      the AST, and produce a HIR object for each node. HIR is typed, and SemA
   64.53 +      may insert coercion nodes, or even expand an AST node into multiple HIR
   64.54 +      nodes. The result of evaluating an expression in SemA is therefore the
   64.55 +      the root of a HIR tree, which SemA then sends to the HIRTranslator, which
   64.56 +      performs bytecode generation.
   64.57 +
   64.58 +      As before, SemA still performs full semantic analysis. However, not it
   64.59 +      also produces each function's bytecode.
   64.60 +
   64.61 +      This split allows us to decompose potentially complex semantics into
   64.62 +      a more fine-grained, AST-like structure, which can have very simple
   64.63 +      code-generation logic. For example, (1.0 + 5) might look like:
   64.64 +
   64.65 +         HAdd(HFloat(1.0), HConvert(HInteger(5), <Float>))
   64.66 +
   64.67 +      As part of this decomposition, many opcodes have been removed. Rather than
   64.68 +      using typed jumps, we now expand jumps into longer tests. For example:
   64.69 +         jge.f <label>
   64.70 +      becomes:
   64.71 +         ge.f
   64.72 +         cvt.f2b
   64.73 +         jt <label>
   64.74 +
   64.75 +      This simplifies the pipeline, and JITs should be able to melt the added
   64.76 +      work away.
   64.77 +
   64.78 +      HIR is not used at a statement level, and HIR does not have any concept
   64.79 +      of control-flow.
   64.80 +
   64.81 +  (7) The old BytecodeCompiler has been removed, as its work is now split
   64.82 +      between SemA and HIRTranslator.
   64.83 +
   64.84 +  
   64.85 +In addition, some minor refactorings have taken place:
   64.86 +
   64.87 +  (1) Opcodes.tbl no longer hardcodes numbers (aaah).
   64.88 +  (2) Type has been split into smaller, typed structs.
   64.89 +  (3) BytecodeEmitter no longer relies on Pools or RootScopes.
   64.90 +  (4) SemA is now responsible for variable/storage allocation.
   64.91 +  (5) Native table are now global, rather than per-module. As such, native
   64.92 +      declarations now result in a Native object (which still requires a
   64.93 +      CALLNATIVE opcode), which is an index into the global table. Natives
   64.94 +      must be bound globally. This is in preparation for module support.
   64.95 +  (6) Publics are no longer tracked, but rather registered via a global
   64.96 +      callback upon module load. This callback can be set by embedders. This
   64.97 +      is in preparation for multi-file support.
   64.98 +  (7) The BytecodeEmitter now performs Symbol allocations itself, and it
   64.99 +      also generates Code objects itself, which removes a good deal of
  64.100 +      complexity.
  64.101 +
  64.102 +Finally, a test harness has been added. This harness is a python script which finds *.test files, recursively, in the tests folder. For each file it runs the corresponding .sp. The contents of the .test file must match stdout+stderr.
  64.103 +
  64.104 +
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/src/compiler/AST.h	Sat Nov 17 18:41:01 2012 -0800
    65.3 @@ -0,0 +1,1155 @@
    65.4 +/* vim: set ts=4 sw=4 tw=99 et:
    65.5 + *
    65.6 + * Copyright (C) 2012 David Anderson
    65.7 + *
    65.8 + * This file is part of SourcePawn.
    65.9 + *
   65.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   65.11 + * the terms of the GNU General Public License as published by the Free
   65.12 + * Software Foundation, either version 3 of the License, or (at your option)
   65.13 + * any later version.
   65.14 + * 
   65.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   65.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   65.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   65.18 + *
   65.19 + * You should have received a copy of the GNU General Public License along with
   65.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   65.21 + */
   65.22 +#ifndef _include_sourcepawn_ast_h_
   65.23 +#define _include_sourcepawn_ast_h_
   65.24 +
   65.25 +#include "../PoolAllocator.h"
   65.26 +#include "../Vector.h"
   65.27 +#include "Token.h"
   65.28 +#include "NameBinding.h"
   65.29 +#include "Symbols.h"
   65.30 +#include "../QualType.h"
   65.31 +
   65.32 +namespace ke {
   65.33 +
   65.34 +class Scope;
   65.35 +
   65.36 +#define ASTKINDS(_)             \
   65.37 +    _(VariableDeclaration)      \
   65.38 +    _(ForStatement)             \
   65.39 +    _(ReturnStatement)          \
   65.40 +    _(IntegerLiteral)           \
   65.41 +    _(FloatLiteral)             \
   65.42 +    _(StringLiteral)            \
   65.43 +    _(BinaryExpression)         \
   65.44 +    _(BlockStatement)           \
   65.45 +    _(Assignment)               \
   65.46 +    _(NameProxy)                \
   65.47 +    _(ExpressionStatement)      \
   65.48 +    _(FunctionStatement)        \
   65.49 +    _(CallExpression)           \
   65.50 +    _(IfStatement)              \
   65.51 +    _(IndexExpression)          \
   65.52 +    _(FieldExpression)          \
   65.53 +    _(EnumStatement)            \
   65.54 +    _(WhileStatement)           \
   65.55 +    _(BreakStatement)           \
   65.56 +    _(ContinueStatement)        \
   65.57 +    _(FunctionTypeStatement)    \
   65.58 +    _(IncDecExpression)         \
   65.59 +    _(UnaryExpression)          \
   65.60 +    _(TernaryExpression)        \
   65.61 +    _(BooleanLiteral)           \
   65.62 +    _(StructureStatement)       \
   65.63 +    _(SwitchStatement)          \
   65.64 +    _(ArrayLiteral)             \
   65.65 +	_(ImportStatement)
   65.66 +
   65.67 +// Forward declarations.
   65.68 +#define _(name) class name;
   65.69 +ASTKINDS(_)
   65.70 +#undef _
   65.71 +
   65.72 +class AstVisitor;
   65.73 +
   65.74 +// Interface for AST nodes.
   65.75 +class AstNode : public PoolObject
   65.76 +{
   65.77 +    SourcePosition pos_;
   65.78 +
   65.79 +  public:
   65.80 +    enum Kind {
   65.81 +#       define _(name) k##name,
   65.82 +        ASTKINDS(_)
   65.83 +#       undef _
   65.84 +        AstKind_Invalid
   65.85 +    };
   65.86 +
   65.87 +    AstNode(const SourcePosition &pos)
   65.88 +      : pos_(pos)
   65.89 +    {
   65.90 +    }
   65.91 +    
   65.92 +    virtual Kind kind() const = 0;
   65.93 +
   65.94 +#define _(name)     bool is##name() { return kind() == k##name; }                   \
   65.95 +                    name *to##name() { assert(is##name()); return (name *)this; }   \
   65.96 +                    name *as##name() { if (!is##name()) return NULL; return to##name(); }
   65.97 +    ASTKINDS(_)
   65.98 +#undef _
   65.99 +
  65.100 +    virtual void accept(AstVisitor *visitor) = 0;
  65.101 +
  65.102 +    const SourcePosition &pos() const {
  65.103 +        return pos_;
  65.104 +    }
  65.105 +};
  65.106 +
  65.107 +#define DECLARE_NODE(type)                      \
  65.108 +    Kind kind() const {                         \
  65.109 +        return k##type;                         \
  65.110 +    }                                           \
  65.111 +    void accept(AstVisitor *visitor) {          \
  65.112 +        visitor->visit##type(this);             \
  65.113 +    }
  65.114 +
  65.115 +class AstVisitor
  65.116 +{
  65.117 +  public:
  65.118 +#define _(name) virtual void visit##name(name *node) { assert(false); }
  65.119 +    ASTKINDS(_)
  65.120 +#undef _
  65.121 +};
  65.122 +
  65.123 +class Statement : public AstNode
  65.124 +{
  65.125 +  public:
  65.126 +    Statement(const SourcePosition &pos)
  65.127 +      : AstNode(pos)
  65.128 +    {
  65.129 +    }
  65.130 +};
  65.131 +
  65.132 +class Expression : public AstNode
  65.133 +{
  65.134 +    ScopedRoot<Type> type_;
  65.135 +
  65.136 +  public:
  65.137 +    Expression(const SourcePosition &pos)
  65.138 +      : AstNode(pos),
  65.139 +        type_(NULL)
  65.140 +    {
  65.141 +    }
  65.142 +
  65.143 +    void setType(Type *type) {
  65.144 +        type_ = type;
  65.145 +    }
  65.146 +    Type *type() const {
  65.147 +        return type_;
  65.148 +    }
  65.149 +};
  65.150 +
  65.151 +typedef PoolList<Statement *> StatementList;
  65.152 +typedef PoolList<Expression *> ExpressionList;
  65.153 +
  65.154 +class VariableDeclaration : public Statement
  65.155 +{
  65.156 +    TypeQualifiers qual_;
  65.157 +    ScopedRoot<String> name_;
  65.158 +    Expression *initialization_;
  65.159 +    Expression *type_;
  65.160 +    VariableSymbol *sym_;
  65.161 +
  65.162 +  public:
  65.163 +    VariableDeclaration(const SourcePosition &pos, TypeQualifiers qual, Handle<String> name,
  65.164 +                        Expression *type, Expression *initialization)
  65.165 +      : Statement(pos),
  65.166 +        qual_(qual),
  65.167 +        name_(name),
  65.168 +        initialization_(initialization),
  65.169 +        type_(type),
  65.170 +        sym_(NULL)
  65.171 +    {
  65.172 +    }
  65.173 +
  65.174 +    DECLARE_NODE(VariableDeclaration);
  65.175 +
  65.176 +    Expression *initialization() const {
  65.177 +        return initialization_;
  65.178 +    }
  65.179 +    Handle<String> name() {
  65.180 +        return name_;
  65.181 +    }
  65.182 +    Expression *declType() const {
  65.183 +        return type_;
  65.184 +    }
  65.185 +    void setSymbol(VariableSymbol *sym) {
  65.186 +        assert(!sym_);
  65.187 +        sym_ = sym;
  65.188 +    }
  65.189 +    VariableSymbol *sym() const {
  65.190 +        return sym_;
  65.191 +    }
  65.192 +    Expression *type() const {
  65.193 +        return type_;
  65.194 +    }
  65.195 +};
  65.196 +
  65.197 +class Parameter : public PoolObject
  65.198 +{
  65.199 +    ScopedRoot<String> name_;
  65.200 +    Expression *type_;
  65.201 +    bool reference_;
  65.202 +    bool const_;
  65.203 +    Expression *initializer_;
  65.204 +    VariableSymbol *sym_;
  65.205 +    SourcePosition pos_;
  65.206 +
  65.207 +  public:
  65.208 +    Parameter(Handle<String> name, Expression *type, bool reference, bool isConst,
  65.209 +              Expression *initializer, const SourcePosition &pos)
  65.210 +      : name_(name),
  65.211 +        type_(type),
  65.212 +        reference_(reference),
  65.213 +        const_(isConst),
  65.214 +        initializer_(initializer),
  65.215 +        sym_(NULL),
  65.216 +        pos_(pos)
  65.217 +    {
  65.218 +    }
  65.219 +
  65.220 +    Expression *type() const {
  65.221 +        return type_;
  65.222 +    }
  65.223 +    Handle<String> name() const {
  65.224 +        return name_;
  65.225 +    }
  65.226 +    bool reference() const {
  65.227 +        return reference_;
  65.228 +    }
  65.229 +    bool isConst() const {
  65.230 +        return const_;
  65.231 +    }
  65.232 +    Expression *initializer() const {
  65.233 +        return initializer_;
  65.234 +    }
  65.235 +    void setSymbol(VariableSymbol *sym) {
  65.236 +        assert(!sym_);
  65.237 +        sym_ = sym;
  65.238 +    }
  65.239 +    VariableSymbol *sym() const {
  65.240 +        return sym_;
  65.241 +    }
  65.242 +    const SourcePosition &pos() const {
  65.243 +        return pos_;
  65.244 +    }
  65.245 +};
  65.246 +
  65.247 +class NameProxy : public Expression
  65.248 +{
  65.249 +    ScopedRoot<String> name_;
  65.250 +    Symbol *binding_;
  65.251 +
  65.252 +  public:
  65.253 +    NameProxy(const SourcePosition &pos, Handle<String> name)
  65.254 +      : Expression(pos),
  65.255 +        name_(name),
  65.256 +        binding_(NULL)
  65.257 +    {
  65.258 +    }
  65.259 +
  65.260 +    DECLARE_NODE(NameProxy);
  65.261 +    
  65.262 +    Handle<String> name() const {
  65.263 +        return name_;
  65.264 +    }
  65.265 +    Symbol *sym() const {
  65.266 +        return binding_;
  65.267 +    }
  65.268 +    void bind(Symbol *sym) {
  65.269 +        binding_ = sym;
  65.270 +    }
  65.271 +};
  65.272 +
  65.273 +class BooleanLiteral : public Expression
  65.274 +{
  65.275 +    TokenKind token_;
  65.276 +
  65.277 +  public:
  65.278 +    BooleanLiteral(const SourcePosition &pos, TokenKind token)
  65.279 +      : Expression(pos),
  65.280 +        token_(token)
  65.281 +    {
  65.282 +    }
  65.283 +
  65.284 +    DECLARE_NODE(BooleanLiteral);
  65.285 +    TokenKind token() const {
  65.286 +        return token_;
  65.287 +    }
  65.288 +};
  65.289 +
  65.290 +class IntegerLiteral : public Expression
  65.291 +{
  65.292 +    int value_;
  65.293 +
  65.294 +  public:
  65.295 +    IntegerLiteral(const SourcePosition &pos, int value)
  65.296 +      : Expression(pos),
  65.297 +        value_(value)
  65.298 +    {
  65.299 +    }
  65.300 +
  65.301 +    DECLARE_NODE(IntegerLiteral);
  65.302 +
  65.303 +    int value() const {
  65.304 +        return value_;
  65.305 +    }
  65.306 +};
  65.307 +
  65.308 +class FloatLiteral : public Expression
  65.309 +{
  65.310 +    double value_;
  65.311 +
  65.312 +  public:
  65.313 +    FloatLiteral(const SourcePosition &pos, double value)
  65.314 +      : Expression(pos),
  65.315 +        value_(value)
  65.316 +    {
  65.317 +    }
  65.318 +
  65.319 +    DECLARE_NODE(FloatLiteral);
  65.320 +
  65.321 +    double value() const {
  65.322 +        return value_;
  65.323 +    }
  65.324 +};
  65.325 +
  65.326 +class StringLiteral : public Expression
  65.327 +{
  65.328 +    ScopedRoot<ByteArray> string_;
  65.329 +
  65.330 +  public:
  65.331 +    StringLiteral(const SourcePosition &pos, ByteArray *array)
  65.332 +      : Expression(pos),
  65.333 +        string_(array)
  65.334 +    {
  65.335 +    }
  65.336 +
  65.337 +    DECLARE_NODE(StringLiteral);
  65.338 +
  65.339 +    ByteArray *string() const {
  65.340 +        return string_;
  65.341 +    }
  65.342 +};
  65.343 +
  65.344 +class ArrayLiteral : public Expression
  65.345 +{
  65.346 +    TokenKind token_;
  65.347 +    ExpressionList *expressions_;
  65.348 +
  65.349 +  public:
  65.350 +    ArrayLiteral(const SourcePosition &pos, TokenKind token, ExpressionList *expressions)
  65.351 +      : Expression(pos),
  65.352 +        token_(token),
  65.353 +        expressions_(expressions)
  65.354 +    {
  65.355 +    }
  65.356 +
  65.357 +    DECLARE_NODE(ArrayLiteral);
  65.358 +
  65.359 +    TokenKind token() const {
  65.360 +        return token_;
  65.361 +    }
  65.362 +    ExpressionList *expressions() const {
  65.363 +        return expressions_;
  65.364 +    }
  65.365 +    bool isFixed() const {
  65.366 +        return token_ == TOK_LBRACE;
  65.367 +    }
  65.368 +};
  65.369 +
  65.370 +class UnaryExpression : public Expression
  65.371 +{
  65.372 +    Expression *expression_;
  65.373 +    TokenKind token_;
  65.374 +    NameProxy *tag_;
  65.375 +
  65.376 +  public:
  65.377 +    UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr)
  65.378 +      : Expression(pos),
  65.379 +        expression_(expr),
  65.380 +        token_(token),
  65.381 +        tag_(NULL)
  65.382 +    {
  65.383 +    }
  65.384 +
  65.385 +    UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr,
  65.386 +                    NameProxy *tag)
  65.387 +      : Expression(pos),
  65.388 +        expression_(expr),
  65.389 +        token_(token),
  65.390 +        tag_(tag)
  65.391 +    {
  65.392 +    }
  65.393 +
  65.394 +    DECLARE_NODE(UnaryExpression);
  65.395 +
  65.396 +    Expression *expression() const {
  65.397 +        return expression_;
  65.398 +    }
  65.399 +    TokenKind token() const {
  65.400 +        return token_;
  65.401 +    }
  65.402 +    NameProxy *tag() const {
  65.403 +        return tag_;
  65.404 +    }
  65.405 +};
  65.406 +
  65.407 +class BinaryExpression : public Expression
  65.408 +{
  65.409 +    Expression *left_;
  65.410 +    Expression *right_;
  65.411 +    TokenKind token_;
  65.412 +
  65.413 +  public:
  65.414 +    BinaryExpression(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
  65.415 +      : Expression(pos),
  65.416 +        left_(left),
  65.417 +        right_(right),
  65.418 +        token_(token)
  65.419 +    {
  65.420 +    }
  65.421 +
  65.422 +    DECLARE_NODE(BinaryExpression);
  65.423 +
  65.424 +    Expression *left() const {
  65.425 +        return left_;
  65.426 +    }
  65.427 +    Expression *right() const {
  65.428 +        return right_;
  65.429 +    }
  65.430 +    TokenKind token() const {
  65.431 +        return token_;
  65.432 +    }
  65.433 +};
  65.434 +
  65.435 +class TernaryExpression : public Expression
  65.436 +{
  65.437 +    Expression *condition_;
  65.438 +    Expression *left_;
  65.439 +    Expression *right_;
  65.440 +
  65.441 +  public:
  65.442 +    TernaryExpression(const SourcePosition &pos, Expression *condition, Expression *left, Expression *right)
  65.443 +      : Expression(pos),
  65.444 +        condition_(condition),
  65.445 +        left_(left),
  65.446 +        right_(right)
  65.447 +    {
  65.448 +    }
  65.449 +
  65.450 +    DECLARE_NODE(TernaryExpression);
  65.451 +
  65.452 +    Expression *condition() const {
  65.453 +        return condition_;
  65.454 +    }
  65.455 +    Expression *left() const {
  65.456 +        return left_;
  65.457 +    }
  65.458 +    Expression *right() const {
  65.459 +        return right_;
  65.460 +    }
  65.461 +};
  65.462 +
  65.463 +class IndexExpression : public Expression
  65.464 +{
  65.465 +    Expression *left_;
  65.466 +    Expression *right_;
  65.467 +
  65.468 +  public:
  65.469 +    IndexExpression(const SourcePosition &pos, Expression *left, Expression *right)
  65.470 +      : Expression(pos),
  65.471 +        left_(left),
  65.472 +        right_(right)
  65.473 +    {
  65.474 +    }
  65.475 +
  65.476 +    DECLARE_NODE(IndexExpression);
  65.477 +
  65.478 +    Expression *left() const {
  65.479 +        return left_;
  65.480 +    }
  65.481 +    Expression *right() const {
  65.482 +        return right_;
  65.483 +    }
  65.484 +};
  65.485 +
  65.486 +class FieldExpression : public Expression
  65.487 +{
  65.488 +    Expression *left_;
  65.489 +    ScopedRoot<String> field_;
  65.490 +    unsigned fieldIndex_;
  65.491 +
  65.492 +  public:
  65.493 +    FieldExpression(const SourcePosition &pos, Expression *left, Handle<String> field)
  65.494 +      : Expression(pos),
  65.495 +        left_(left),
  65.496 +        field_(field),
  65.497 +        fieldIndex_(unsigned(-1))
  65.498 +    {
  65.499 +    }
  65.500 +
  65.501 +    DECLARE_NODE(FieldExpression);
  65.502 +
  65.503 +    Expression *left() const {
  65.504 +        return left_;
  65.505 +    }
  65.506 +    String *field() const {
  65.507 +        return field_;
  65.508 +    }
  65.509 +    void setFieldIndex(unsigned index) {
  65.510 +        assert(fieldIndex_ == unsigned(-1));
  65.511 +        fieldIndex_ = index;
  65.512 +    }
  65.513 +    unsigned fieldIndex() const {
  65.514 +        assert(fieldIndex_ != unsigned(-1));
  65.515 +        return fieldIndex_;
  65.516 +    }
  65.517 +};
  65.518 +
  65.519 +class CallExpression : public Expression
  65.520 +{
  65.521 +    Expression *callee_;
  65.522 +    ExpressionList *arguments_;
  65.523 +
  65.524 +  public:
  65.525 +    CallExpression(const SourcePosition &pos, Expression *callee, ExpressionList *arguments)
  65.526 +      : Expression(pos),
  65.527 +        callee_(callee),
  65.528 +        arguments_(arguments)
  65.529 +    {
  65.530 +    }
  65.531 +
  65.532 +    DECLARE_NODE(CallExpression);
  65.533 +
  65.534 +    Expression *callee() const {
  65.535 +        return callee_;
  65.536 +    }
  65.537 +    ExpressionList *arguments() const {
  65.538 +        return arguments_;
  65.539 +    }
  65.540 +};
  65.541 +
  65.542 +class ForStatement : public Statement
  65.543 +{
  65.544 +    Statement *initialization_;
  65.545 +    Expression *condition_;
  65.546 +    Statement *update_;
  65.547 +    Statement *body_;
  65.548 +    Scope *scope_;
  65.549 +
  65.550 +  public:
  65.551 +    ForStatement(const SourcePosition &pos, Statement *initialization,
  65.552 +                 Expression *condition, Statement *update, Statement *body)
  65.553 +      : Statement(pos),
  65.554 +        initialization_(initialization),
  65.555 +        condition_(condition),
  65.556 +        update_(update),
  65.557 +        body_(body),
  65.558 +        scope_(NULL)
  65.559 +    {
  65.560 +    }
  65.561 +
  65.562 +    DECLARE_NODE(ForStatement);
  65.563 +
  65.564 +    Statement *initialization() const {
  65.565 +        return initialization_;
  65.566 +    }
  65.567 +    Expression *condition() const {
  65.568 +        return condition_;
  65.569 +    }
  65.570 +    Statement *update() const {
  65.571 +        return update_;
  65.572 +    }
  65.573 +    Statement *body() const {
  65.574 +        return body_;
  65.575 +    }
  65.576 +    Scope *scope() const {
  65.577 +        return scope_;
  65.578 +    }
  65.579 +    void setScope(Scope *scope) {
  65.580 +        scope_ = scope;
  65.581 +    }
  65.582 +};
  65.583 +
  65.584 +class WhileStatement : public Statement
  65.585 +{
  65.586 +    TokenKind token_;
  65.587 +    Expression *condition_;
  65.588 +    Statement *body_;
  65.589 +
  65.590 +  public:
  65.591 +    WhileStatement(const SourcePosition &pos, TokenKind kind, Expression *condition, Statement *body)
  65.592 +      : Statement(pos),
  65.593 +        token_(kind),
  65.594 +        condition_(condition),
  65.595 +        body_(body)
  65.596 +    {
  65.597 +    }
  65.598 +    
  65.599 +    DECLARE_NODE(WhileStatement);
  65.600 +
  65.601 +    TokenKind token() const {
  65.602 +        return token_;
  65.603 +    }
  65.604 +    Expression *condition() const {
  65.605 +        return condition_;
  65.606 +    }
  65.607 +    Statement *body() const {
  65.608 +        return body_;
  65.609 +    }
  65.610 +};
  65.611 +
  65.612 +class ReturnStatement : public Statement
  65.613 +{
  65.614 +    Expression *expression_;
  65.615 +
  65.616 +  public:
  65.617 +    ReturnStatement(const SourcePosition &pos, Expression *expression)
  65.618 +      : Statement(pos),
  65.619 +        expression_(expression)
  65.620 +    {
  65.621 +    }
  65.622 +
  65.623 +    DECLARE_NODE(ReturnStatement);
  65.624 +
  65.625 +    Expression *expression() const {
  65.626 +        return expression_;
  65.627 +    }
  65.628 +};
  65.629 +
  65.630 +class BreakStatement : public Statement
  65.631 +{
  65.632 +  public:
  65.633 +    BreakStatement(const SourcePosition &pos)
  65.634 +      : Statement(pos)
  65.635 +    {
  65.636 +    }
  65.637 +
  65.638 +    DECLARE_NODE(BreakStatement);
  65.639 +};
  65.640 +
  65.641 +class ContinueStatement : public Statement
  65.642 +{
  65.643 +  public:
  65.644 +    ContinueStatement(const SourcePosition &pos)
  65.645 +      : Statement(pos)
  65.646 +    {
  65.647 +    }
  65.648 +
  65.649 +    DECLARE_NODE(ContinueStatement);
  65.650 +};
  65.651 +
  65.652 +class Assignment : public Expression
  65.653 +{
  65.654 +    TokenKind token_;
  65.655 +    Expression *lvalue_;
  65.656 +    Expression *expression_;
  65.657 +
  65.658 +  public:
  65.659 +    Assignment(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
  65.660 +      : Expression(pos),
  65.661 +        token_(token),
  65.662 +        lvalue_(left),
  65.663 +        expression_(right)
  65.664 +    {
  65.665 +    }
  65.666 +
  65.667 +    DECLARE_NODE(Assignment);
  65.668 +
  65.669 +    TokenKind token() const {
  65.670 +        return token_;
  65.671 +    }
  65.672 +    Expression *lvalue() const {
  65.673 +        return lvalue_;
  65.674 +    }
  65.675 +    Expression *expression() const {
  65.676 +        return expression_;
  65.677 +    }
  65.678 +};
  65.679 +
  65.680 +class ExpressionStatement : public Statement
  65.681 +{
  65.682 +    Expression *expression_;
  65.683 +
  65.684 +  public:
  65.685 +    ExpressionStatement(Expression *expression)
  65.686 +      : Statement(expression->pos()),
  65.687 +        expression_(expression)
  65.688 +    {
  65.689 +    }
  65.690 +
  65.691 +    DECLARE_NODE(ExpressionStatement);
  65.692 +
  65.693 +    Expression *expression() const {
  65.694 +        return expression_;
  65.695 +    }
  65.696 +};
  65.697 +
  65.698 +class BlockStatement : public Statement
  65.699 +{
  65.700 +    StatementList *statements_;
  65.701 +    Scope *scope_;
  65.702 +
  65.703 +  public:
  65.704 +    BlockStatement(const SourcePosition &pos, StatementList *statements)
  65.705 +      : Statement(pos),
  65.706 +        statements_(statements),
  65.707 +        scope_(NULL)
  65.708 +    {
  65.709 +    }
  65.710 +
  65.711 +    DECLARE_NODE(BlockStatement);
  65.712 +
  65.713 +    StatementList *statements() const {
  65.714 +        return statements_;
  65.715 +    }
  65.716 +    Scope *scope() const {
  65.717 +        return scope_;
  65.718 +    }
  65.719 +    void setScope(Scope *scope) {
  65.720 +        scope_ = scope;
  65.721 +    }
  65.722 +};
  65.723 +
  65.724 +typedef PoolList<Parameter *> ParameterList;
  65.725 +
  65.726 +class FunctionSignature
  65.727 +{
  65.728 +  public:
  65.729 +    FunctionSignature(Expression *returnType, ParameterList *parameters, bool variadic)
  65.730 +      : returnType_(returnType),
  65.731 +        parameters_(parameters),
  65.732 +        variadic_(variadic)
  65.733 +    {
  65.734 +    }
  65.735 +
  65.736 +    Expression *returnType() const {
  65.737 +        return returnType_;
  65.738 +    }
  65.739 +    ParameterList *parameters() const {
  65.740 +        return parameters_;
  65.741 +    }
  65.742 +    bool variadic() const {
  65.743 +        return variadic_;
  65.744 +    }
  65.745 +
  65.746 +  private:
  65.747 +    Expression *returnType_;
  65.748 +    ParameterList *parameters_;
  65.749 +    bool variadic_;
  65.750 +};
  65.751 +
  65.752 +class FunctionTypeStatement : public Statement
  65.753 +{
  65.754 +  public:
  65.755 +    FunctionTypeStatement(const SourcePosition &pos, Handle<String> name, const FunctionSignature &signature)
  65.756 +      : Statement(pos),
  65.757 +        name_(name),
  65.758 +        signature_(signature)
  65.759 +    {
  65.760 +    }
  65.761 +
  65.762 +    DECLARE_NODE(FunctionTypeStatement);
  65.763 +
  65.764 +    Handle<String> name() const {
  65.765 +        return name_;
  65.766 +    }
  65.767 +    const FunctionSignature &signature() const {
  65.768 +        return signature_;
  65.769 +    }
  65.770 +
  65.771 +  private:
  65.772 +    ScopedRoot<String> name_;
  65.773 +    FunctionSignature signature_;
  65.774 +    
  65.775 +};
  65.776 +
  65.777 +class FunctionStatement : public Statement
  65.778 +{
  65.779 +    ScopedRoot<String> name_;
  65.780 +    TokenKind kind_;
  65.781 +    Statement *body_;
  65.782 +    FunctionSignature signature_;
  65.783 +    bool explicitReturn_;
  65.784 +    FunctionSymbol *sym_;
  65.785 +    Scope *argScope_;
  65.786 +    Scope *varScope_;
  65.787 +
  65.788 +  public:
  65.789 +    FunctionStatement(const SourcePosition &pos, Handle<String> name, TokenKind kind,
  65.790 +                      Statement *body, const FunctionSignature &signature, bool explicitReturn)
  65.791 +      : Statement(pos),
  65.792 +        name_(name),
  65.793 +        kind_(kind),
  65.794 +        body_(body),
  65.795 +        signature_(signature),
  65.796 +        explicitReturn_(explicitReturn),
  65.797 +        sym_(NULL),
  65.798 +        argScope_(NULL),
  65.799 +        varScope_(NULL)
  65.800 +    {
  65.801 +    }
  65.802 +
  65.803 +    DECLARE_NODE(FunctionStatement);
  65.804 +
  65.805 +    Handle<String> name() const {
  65.806 +        return name_;
  65.807 +    }
  65.808 +    Statement *body() const {
  65.809 +        return body_;
  65.810 +    }
  65.811 +    const FunctionSignature &signature() {
  65.812 +        return signature_;
  65.813 +    }
  65.814 +    bool hasExplicitReturn() const {
  65.815 +        return explicitReturn_;
  65.816 +    }
  65.817 +    TokenKind token() const {
  65.818 +        return kind_;
  65.819 +    }
  65.820 +    void setSymbol(FunctionSymbol *sym) {
  65.821 +        assert(!sym_);
  65.822 +        sym_ = sym;
  65.823 +    }
  65.824 +    FunctionSymbol *sym() const {
  65.825 +        return sym_;
  65.826 +    }
  65.827 +    void setScopes(Scope *argScope, Scope *varScope) {
  65.828 +        argScope_ = argScope;
  65.829 +        varScope_ = varScope;
  65.830 +    }
  65.831 +    Scope *argScope() const {
  65.832 +        return argScope_;
  65.833 +    }
  65.834 +    Scope *varScope() const {
  65.835 +        return varScope_;
  65.836 +    }
  65.837 +};
  65.838 +
  65.839 +class IfStatement : public Statement
  65.840 +{
  65.841 +    Expression *condition_;
  65.842 +    Statement *ifTrue_;
  65.843 +    Statement *ifFalse_;
  65.844 +
  65.845 +  public:
  65.846 +    IfStatement(const SourcePosition &pos, Expression *condition, Statement *ifTrue)
  65.847 +      : Statement(pos),
  65.848 +        condition_(condition),
  65.849 +        ifTrue_(ifTrue),
  65.850 +        ifFalse_(NULL)
  65.851 +    {
  65.852 +    }
  65.853 +
  65.854 +    DECLARE_NODE(IfStatement);
  65.855 +
  65.856 +    Expression *condition() const {
  65.857 +        return condition_;
  65.858 +    }
  65.859 +    Statement *ifTrue() const {
  65.860 +        return ifTrue_;
  65.861 +    }
  65.862 +    Statement *ifFalse() const {
  65.863 +        return ifFalse_;
  65.864 +    }
  65.865 +    void setIfFalse(Statement *ifFalse) {
  65.866 +        ifFalse_ = ifFalse;
  65.867 +    }
  65.868 +};
  65.869 +
  65.870 +class EnumStatement : public Statement
  65.871 +{
  65.872 +    ScopedRoot<String> name_;
  65.873 +    TypeSymbol *sym_;
  65.874 +
  65.875 +  public:
  65.876 +    struct Entry {
  65.877 +        ScopedRoot<String> name;
  65.878 +        Expression *expr;
  65.879 +
  65.880 +        Entry(Handle<String> name, Expression *expr)
  65.881 +          : name(name),
  65.882 +            expr(expr)
  65.883 +        {
  65.884 +        }
  65.885 +    };
  65.886 +
  65.887 +    typedef PoolList<Entry> EntryList;
  65.888 +
  65.889 +  public:
  65.890 +    EnumStatement(const SourcePosition &pos, Handle<String> name, EntryList *entries)
  65.891 +      : Statement(pos),
  65.892 +        name_(name),
  65.893 +        entries_(entries),
  65.894 +        sym_(NULL)
  65.895 +    {
  65.896 +    }
  65.897 +
  65.898 +    DECLARE_NODE(EnumStatement);
  65.899 +
  65.900 +    String *name() const {
  65.901 +        return name_;
  65.902 +    }
  65.903 +    EntryList *entries() const {
  65.904 +        return entries_;
  65.905 +    }
  65.906 +    void setSymbol(TypeSymbol *sym) {
  65.907 +        assert(!sym_);
  65.908 +        sym_ = sym;
  65.909 +    }
  65.910 +    TypeSymbol *sym() const {
  65.911 +        return sym_;
  65.912 +    }
  65.913 +
  65.914 +  private:
  65.915 +    EntryList *entries_;
  65.916 +};
  65.917 +
  65.918 +class IncDecExpression : public Expression
  65.919 +{
  65.920 +    TokenKind token_;
  65.921 +    Expression *expression_;
  65.922 +    bool postfix_;
  65.923 +
  65.924 +  public:
  65.925 +    IncDecExpression(const SourcePosition &pos, TokenKind token, Expression *expression, bool postfix)
  65.926 +      : Expression(pos),
  65.927 +        token_(token),
  65.928 +        expression_(expression),
  65.929 +        postfix_(postfix)
  65.930 +    {
  65.931 +    }
  65.932 +
  65.933 +    DECLARE_NODE(IncDecExpression);
  65.934 +
  65.935 +    TokenKind token() const {
  65.936 +        return token_;
  65.937 +    }
  65.938 +    Expression *expression() const {
  65.939 +        return expression_;
  65.940 +    }
  65.941 +    bool postfix() const {
  65.942 +        return postfix_;
  65.943 +    }
  65.944 +};
  65.945 +
  65.946 +class Case : public PoolObject
  65.947 +{
  65.948 +  public:
  65.949 +    Case(Expression *expression, ExpressionList *others, Statement *statement)
  65.950 +      : expression_(expression),
  65.951 +        others_(others),
  65.952 +        statement_(statement)
  65.953 +    {
  65.954 +    }
  65.955 +
  65.956 +    Expression *expression() const {
  65.957 +        return expression_;
  65.958 +    }
  65.959 +    PoolList<Expression *> *others() const {
  65.960 +        return others_;
  65.961 +    }
  65.962 +    Statement *statement() const {
  65.963 +        return statement_;
  65.964 +    }
  65.965 +
  65.966 +  private:
  65.967 +    Expression *expression_;
  65.968 +    PoolList <Expression *> *others_;
  65.969 +    Statement *statement_;
  65.970 +};
  65.971 +
  65.972 +struct CaseValue
  65.973 +{
  65.974 +    BoxedPrimitive box;
  65.975 +    size_t statement;
  65.976 +
  65.977 +    CaseValue(size_t statement)
  65.978 +      : statement(statement)
  65.979 +    {
  65.980 +    }
  65.981 +};
  65.982 +
  65.983 +typedef PoolList<CaseValue> CaseValueList;
  65.984 +
  65.985 +class SwitchStatement : public Statement
  65.986 +{
  65.987 +  public:
  65.988 +    SwitchStatement(const SourcePosition &pos, Expression *expression, PoolList<Case *> *cases,
  65.989 +                    Statement *def)
  65.990 +      : Statement(pos),
  65.991 +        expression_(expression),
  65.992 +        cases_(cases),
  65.993 +        default_(def),
  65.994 +        table_(NULL)
  65.995 +    {
  65.996 +    }
  65.997 +
  65.998 +    DECLARE_NODE(SwitchStatement);
  65.999 +
 65.1000 +    Expression *expression() const {
 65.1001 +        return expression_;
 65.1002 +    }
 65.1003 +    PoolList<Case *> *cases() const {
 65.1004 +        return cases_;
 65.1005 +    }
 65.1006 +    Statement *defaultCase() const {
 65.1007 +        return default_;
 65.1008 +    }
 65.1009 +    void setCaseValueList(CaseValueList *list) {
 65.1010 +        table_ = list;
 65.1011 +    }
 65.1012 +    CaseValueList *caseValueList() const {
 65.1013 +        return table_;
 65.1014 +    }
 65.1015 +
 65.1016 +  private:
 65.1017 +    Expression *expression_;
 65.1018 +    PoolList<Case *> *cases_;
 65.1019 +    Statement *default_;
 65.1020 +    CaseValueList *table_;
 65.1021 +};
 65.1022 +
 65.1023 +class StructureStatement : public Statement
 65.1024 +{
 65.1025 +  public:
 65.1026 +    class Field : public PoolObject
 65.1027 +    {
 65.1028 +        SourcePosition pos_;
 65.1029 +        Expression *type_;
 65.1030 +        ScopedRoot<String> name_;
 65.1031 +
 65.1032 +      public:
 65.1033 +        Field(const SourcePosition &pos,
 65.1034 +              Expression *type,
 65.1035 +              Handle<String> name)
 65.1036 +          : pos_(pos),
 65.1037 +            type_(type),
 65.1038 +            name_(name)
 65.1039 +        {
 65.1040 +        }
 65.1041 +
 65.1042 +        const SourcePosition &pos() const {
 65.1043 +            return pos_;
 65.1044 +        }
 65.1045 +        Handle<String> name() const {
 65.1046 +            return name_;
 65.1047 +        }
 65.1048 +        Expression *type() const {
 65.1049 +            return type_;
 65.1050 +        }
 65.1051 +    };
 65.1052 +
 65.1053 +    typedef PoolList<StructureStatement::Field *> FieldList;
 65.1054 +
 65.1055 +  public:
 65.1056 +    StructureStatement(const SourcePosition &pos, Handle<String> name, FieldList *fields)
 65.1057 +      : Statement(pos),
 65.1058 +        name_(name),
 65.1059 +        fields_(fields),
 65.1060 +        sym_(NULL)
 65.1061 +    {
 65.1062 +    }
 65.1063 +
 65.1064 +    DECLARE_NODE(StructureStatement);
 65.1065 +
 65.1066 +    FieldList *fields() const {
 65.1067 +        return fields_;
 65.1068 +    }
 65.1069 +    Handle<String> name() const {
 65.1070 +        return name_;
 65.1071 +    }
 65.1072 +    void setSymbol(TypeSymbol *sym) {
 65.1073 +        assert(!sym_);
 65.1074 +        sym_ = sym;
 65.1075 +    }
 65.1076 +    TypeSymbol *sym() const {
 65.1077 +        return sym_;
 65.1078 +    }
 65.1079 +
 65.1080 +  private:
 65.1081 +    ScopedRoot<String> name_;
 65.1082 +    FieldList *fields_;
 65.1083 +    TypeSymbol *sym_;
 65.1084 +};
 65.1085 +
 65.1086 +typedef PoolList<ScopedRoot<String> *> NameList;
 65.1087 +
 65.1088 +class ImportStatement : public Statement
 65.1089 +{
 65.1090 +  public:
 65.1091 +    ImportStatement(const SourcePosition &pos, NameList *names, TokenKind suffix)
 65.1092 +      : Statement(pos),
 65.1093 +        names_(names),
 65.1094 +        suffix_(suffix),
 65.1095 +        source_(NULL)
 65.1096 +    {
 65.1097 +    }
 65.1098 +
 65.1099 +    DECLARE_NODE(ImportStatement);
 65.1100 +
 65.1101 +    NameList *path() const {
 65.1102 +        return names_;
 65.1103 +    }
 65.1104 +    void setImportSource(TranslationUnit *unit) {
 65.1105 +        source_ = unit;
 65.1106 +    }
 65.1107 +    TranslationUnit *source() const {
 65.1108 +        return source_;
 65.1109 +    }
 65.1110 +    TokenKind suffix() const {
 65.1111 +        return suffix_;
 65.1112 +    }
 65.1113 +    Handle<String> name() const {
 65.1114 +        assert(suffix() != TOK_STAR);
 65.1115 +        return *names_->at(names_->length() - 1);
 65.1116 +    }
 65.1117 +
 65.1118 +  private:
 65.1119 +    NameList *names_;
 65.1120 +    TokenKind suffix_;
 65.1121 +    TranslationUnit *source_;
 65.1122 +};
 65.1123 +
 65.1124 +typedef StructureStatement::FieldList FieldList;
 65.1125 +typedef PoolList<NameProxy *> NameProxyList;
 65.1126 +
 65.1127 +#undef DECLARE_NODE
 65.1128 +
 65.1129 +class ParseTree : public PoolObject
 65.1130 +{
 65.1131 +    StatementList *statements_;
 65.1132 +    NameProxyList *unbound_;
 65.1133 +    PoolList<ImportStatement *> *imports_;
 65.1134 +
 65.1135 +  public:
 65.1136 +    ParseTree(StatementList *statements, NameProxyList *unbound, PoolList<ImportStatement *> *imports)
 65.1137 +      : statements_(statements),
 65.1138 +        unbound_(unbound),
 65.1139 +        imports_(imports)
 65.1140 +    {
 65.1141 +    }
 65.1142 +
 65.1143 +    void dump(FILE *fp);
 65.1144 +
 65.1145 +    StatementList *statements() const {
 65.1146 +        return statements_;
 65.1147 +    }
 65.1148 +    NameProxyList *unbound() const {
 65.1149 +        return unbound_;
 65.1150 +    }
 65.1151 +    PoolList<ImportStatement *> *imports() const {
 65.1152 +        return imports_;
 65.1153 +    }
 65.1154 +};
 65.1155 +
 65.1156 +}
 65.1157 +
 65.1158 +#endif // _include_sourcepawn_ast_h_
    66.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    66.2 +++ b/src/compiler/BytecodeEmitter.cpp	Sat Nov 17 18:41:01 2012 -0800
    66.3 @@ -0,0 +1,344 @@
    66.4 +/* vim: set ts=4 sw=4 tw=99 et:
    66.5 + *
    66.6 + * Copyright (C) 2012 David Anderson
    66.7 + *
    66.8 + * This file is part of JITCraft.
    66.9 + *
   66.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   66.11 + * the terms of the GNU General Public License as published by the Free
   66.12 + * Software Foundation, either version 3 of the License, or (at your option)
   66.13 + * any later version.
   66.14 + * 
   66.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   66.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   66.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   66.18 + *
   66.19 + * You should have received a copy of the GNU General Public License along with
   66.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   66.21 + */
   66.22 +#include <stdlib.h>
   66.23 +#include <string.h>
   66.24 +#include "../Utility.h"
   66.25 +#include "../Types.h"
   66.26 +#include "../Zone.h"
   66.27 +#include "../Strings.h"
   66.28 +#include "../Zone.h"
   66.29 +#include "BytecodeEmitter.h"
   66.30 +#include "Symbols.h"
   66.31 +#include "Scopes.h"
   66.32 +#include "../Spaces-inl.h"
   66.33 +#include "../Heap-inl.h"
   66.34 +
   66.35 +using namespace ke;
   66.36 +
   66.37 +StringTable::StringTable()
   66.38 +  : set_(ZoneAllocatorPolicy()),
   66.39 +    initialized_(false)
   66.40 +{
   66.41 +}
   66.42 +
   66.43 +bool
   66.44 +StringTable::initialize()
   66.45 +{
   66.46 +    assert(!initialized_);
   66.47 +    initialized_ = true;
   66.48 +    if (!set_.init(16))
   66.49 +        return false;
   66.50 +    return true;
   66.51 +}
   66.52 +
   66.53 +bool
   66.54 +StringTable::add(Handle<String> name, unsigned *indexp)
   66.55 +{
   66.56 +    if (!initialized_ && !initialize())
   66.57 +        return false;
   66.58 +
   66.59 +    Set::Insert p = set_.findForAdd(*name);
   66.60 +    if (p.found()) {
   66.61 +        *indexp = p->index;
   66.62 +        return true;
   66.63 +    }
   66.64 +
   66.65 +    if (strings_.length() > INT_MAX) {
   66.66 +        ZONE()->reportAllocationOverflow();
   66.67 +        return false;
   66.68 +    }
   66.69 +
   66.70 +    Entry e(name, strings_.length());
   66.71 +    if (!strings_.append(e))
   66.72 +        return false;
   66.73 +
   66.74 +    if (!set_.add(p, e))
   66.75 +        return false;
   66.76 +
   66.77 +    *indexp = e.index;
   66.78 +
   66.79 +    return true;
   66.80 +}
   66.81 +
   66.82 +void
   66.83 +StringTable::accept(VirtualObjectVisitor *visitor)
   66.84 +{
   66.85 +    for (size_t i = 0; i < strings_.length(); i++)
   66.86 +        visitor->visit(reinterpret_cast<Object **>(&strings_[i].string));
   66.87 +}
   66.88 +
   66.89 +BytecodeEmitter::BytecodeEmitter(PoolAllocator &pool)
   66.90 +  : AutoRooted(ZONE()),
   66.91 +    pool_(pool),
   66.92 +    buffer_(inline_buffer_),
   66.93 +    buffer_pos_(buffer_),
   66.94 +    buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
   66.95 +    oom_(false),
   66.96 +    maxStackDepth_(0)
   66.97 +{
   66.98 +    lastCodePosition_ = 0;
   66.99 +    firstLine_ = 1;
  66.100 +}
  66.101 +
  66.102 +BytecodeEmitter::~BytecodeEmitter()
  66.103 +{
  66.104 +    for (size_t i = 0; i < oopRecords_.length(); i++)
  66.105 +        delete oopRecords_[i];
  66.106 +}
  66.107 +
  66.108 +void
  66.109 +BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
  66.110 +{
  66.111 +    for (size_t i = 0; i < objects_.length(); i++)
  66.112 +        visitor->visit(&objects_[i]);
  66.113 +
  66.114 +    strings_.accept(visitor);
  66.115 +}
  66.116 +
  66.117 +bool
  66.118 +BytecodeEmitter::growBuffer(size_t nbytes)
  66.119 +{
  66.120 +    if (oom_) {
  66.121 +        buffer_pos_ = buffer_;
  66.122 +        return false;
  66.123 +    }
  66.124 +
  66.125 +    size_t newSize = size_t((buffer_end_ - buffer_) * 2);
  66.126 +    if (newSize >= MAX_LENGTH) {
  66.127 +        oom_ = true;
  66.128 +        buffer_pos_ = buffer_;
  66.129 +        ZONE()->reportOutOfMemory();
  66.130 +        return false;
  66.131 +    }
  66.132 +
  66.133 +    bytecode *newBuffer;
  66.134 +    if (buffer_ == inline_buffer_)
  66.135 +        newBuffer = (bytecode *)malloc(newSize);
  66.136 +    else
  66.137 +        newBuffer = (bytecode *)realloc(buffer_, newSize);
  66.138 +
  66.139 +    // If we can't allocate a buffer, reset the buffer to the start and set
  66.140 +    // a flag to indicate out-of-memory.
  66.141 +    if (!newBuffer) {
  66.142 +        oom_ = true;
  66.143 +        buffer_pos_ = buffer_;
  66.144 +        ZONE()->reportOutOfMemory();
  66.145 +        return false;
  66.146 +    }
  66.147 +
  66.148 +    if (buffer_ == inline_buffer_)
  66.149 +        memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
  66.150 +
  66.151 +    buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
  66.152 +    buffer_ = newBuffer;
  66.153 +    buffer_end_ = buffer_ + newSize;
  66.154 +    assert(buffer_pos_ + nbytes < buffer_end_);
  66.155 +
  66.156 +    return true;
  66.157 +}
  66.158 +
  66.159 +void
  66.160 +BytecodeEmitter::recordOops()
  66.161 +{
  66.162 +    OopRecord *record = new OopRecord(oopMap_.length(), position());
  66.163 +
  66.164 +    if (!record->slots.ensure(record->depth)) {
  66.165 +        oom_ = true;
  66.166 +        return;
  66.167 +    }
  66.168 +
  66.169 +    bool hadOops = false;
  66.170 +    for (size_t i = 0; i < oopMap_.length(); i++) {
  66.171 +        bool bit = oopMap_[i];
  66.172 +        record->slots.infallibleAppend(bit);
  66.173 +        hadOops |= bit;
  66.174 +    }
  66.175 +
  66.176 +    if (!hadOops) {
  66.177 +        delete record;
  66.178 +        return;
  66.179 +    }
  66.180 +
  66.181 +    oom_ &= oopRecords_.append(record);
  66.182 +}
  66.183 +
  66.184 +void
  66.185 +BytecodeEmitter::note_position(const SourcePosition &pos)
  66.186 +{
  66.187 +    assert(pos.line > 0);
  66.188 +    assert(unsigned(pos.line) >= firstLine_);
  66.189 +
  66.190 +    unsigned lineDelta = unsigned(pos.line) - firstLine_;
  66.191 +    unsigned pcDelta = unsigned(position()) - lastCodePosition_;
  66.192 +
  66.193 +    sourcemap_.writeUint32(pcDelta);
  66.194 +    sourcemap_.writeUint32(lineDelta);
  66.195 +    sourcemap_.writeUint32(pos.col);
  66.196 +
  66.197 +    lastCodePosition_ = unsigned(position());
  66.198 +}
  66.199 +
  66.200 +void
  66.201 +BytecodeEmitter::getglobal(Symbol *sym)
  66.202 +{
  66.203 +    ensure(OP_GETGLOBAL_LENGTH);
  66.204 +    writeOp(OP_GETGLOBAL);
  66.205 +    writeUint32(addString(sym->name()));
  66.206 +    if (sym->type()->isTraceable())
  66.207 +        markOop(1);
  66.208 +}
  66.209 +void
  66.210 +BytecodeEmitter::setglobal(Symbol *sym)
  66.211 +{
  66.212 +    ensure(OP_SETGLOBAL_LENGTH);
  66.213 +    writeOp(OP_SETGLOBAL);
  66.214 +    writeUint32(addString(sym->name()));
  66.215 +    if (sym->type()->isTraceable())
  66.216 +        markOop(1);
  66.217 +}
  66.218 +
  66.219 +void
  66.220 +BytecodeEmitter::getlocal(VariableSymbol *var)
  66.221 +{
  66.222 +    ensure(OP_GETLOCAL_LENGTH);
  66.223 +    writeOp(OP_GETLOCAL);
  66.224 +    writeUint32(var->slot());
  66.225 +    if (var->type()->isTraceable())
  66.226 +        markOop(1);
  66.227 +}
  66.228 +
  66.229 +void
  66.230 +BytecodeEmitter::setlocal(VariableSymbol *var)
  66.231 +{
  66.232 +    ensure(OP_SETLOCAL_LENGTH);
  66.233 +    writeOp(OP_SETLOCAL);
  66.234 +    writeUint32(var->slot());
  66.235 +    if (var->type()->isTraceable())
  66.236 +        markOop(1);
  66.237 +}
  66.238 +
  66.239 +bool
  66.240 +BytecodeEmitter::allocate(VariableSymbol *sym)
  66.241 +{
  66.242 +    assert(sym->isVariable());
  66.243 +    assert(sym->scope()->kind() == Scope::BLOCK);
  66.244 +
  66.245 +    switch (sym->scope()->kind()) {
  66.246 +      case Scope::BLOCK:
  66.247 +      {
  66.248 +        // See overall comment on overflows.
  66.249 +        assert(locals_.length() < UINT_MAX);
  66.250 +        sym->allocate(VariableSymbol::Local, locals_.length());
  66.251 +        if (!locals_.append(sym))
  66.252 +            return false;
  66.253 +        break;
  66.254 +      }
  66.255 +
  66.256 +      default:
  66.257 +        assert(false);
  66.258 +        return false;
  66.259 +    }
  66.260 +
  66.261 +    return true;
  66.262 +}
  66.263 +
  66.264 +Code *
  66.265 +BytecodeEmitter::finish()
  66.266 +{
  66.267 +    stop();
  66.268 +
  66.269 +    Zone *zone = ZONE();
  66.270 +    if (oom() || zone->hasPendingException())
  66.271 +        return NULL;
  66.272 +
  66.273 +    Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
  66.274 +    if (!bytes)
  66.275 +        return NULL;
  66.276 +    memcpy(bytes->raw(), buffer(), length());
  66.277 +
  66.278 +    Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
  66.279 +    if (!objects)
  66.280 +        return NULL;
  66.281 +
  66.282 +    for (size_t i = 0; i < objects_.length(); i++)
  66.283 +        objects->set(zone, i, objects_[i]);
  66.284 +
  66.285 +    // If any stack slots hold gc pointers at potential failure points in the
  66.286 +    // bytecode, record them now. We do this by building a list of tuples;
  66.287 +    // each tuple contains the pc offset, and a bitset containing which stack
  66.288 +    // slots must be scanned by the gc.
  66.289 +    Local<ByteArray> safepoints(zone);
  66.290 +    if (oopRecords_.length()) {
  66.291 +        size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
  66.292 +        size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
  66.293 +        safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
  66.294 +        if (!safepoints)
  66.295 +            return NULL;
  66.296 +
  66.297 +        Address cursor = safepoints->raw();
  66.298 +        for (size_t i = 0; i < oopRecords_.length(); i++) {
  66.299 +            OopRecord *record = oopRecords_[i];
  66.300 +            assert(record->depth <= maxStackDepth());
  66.301 +
  66.302 +            *reinterpret_cast<unsigned *>(cursor) = record->offset;
  66.303 +
  66.304 +            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
  66.305 +            for (unsigned i = 0; i < record->depth; i++)
  66.306 +                bits[i / 8] |= (1 << (i % 8));
  66.307 +
  66.308 +            cursor += bytesPerSafepoint;
  66.309 +        }
  66.310 +
  66.311 +        assert(cursor == safepoints->raw() + gcmapSize);
  66.312 +    }
  66.313 +
  66.314 +    Local<ByteArray> sourcemap(zone);
  66.315 +    if (sourcemap_.length()) {
  66.316 +        sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
  66.317 +        if (!sourcemap)
  66.318 +            return NULL;
  66.319 +
  66.320 +        memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
  66.321 +    }
  66.322 +
  66.323 +    Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
  66.324 +    if (!strings)
  66.325 +        return NULL;
  66.326 +    for (size_t i = 0; i < strings_.stringCount(); i++)
  66.327 +        strings->set(zone, i, strings_.stringAt(i));
  66.328 +
  66.329 +    Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
  66.330 +    if (!locals)
  66.331 +        return NULL;
  66.332 +    for (size_t i = 0; i < locals_.length(); i++)
  66.333 +        locals->set(zone, i, locals_[i]->type());
  66.334 +
  66.335 +    Local<Code> code(zone);
  66.336 +
  66.337 +    code = Code::New(zone,
  66.338 +                     bytes,
  66.339 +                     locals,
  66.340 +                     objects,
  66.341 +                     strings,
  66.342 +                     maxStackDepth(),
  66.343 +                     safepoints,
  66.344 +                     sourcemap);
  66.345 +
  66.346 +    return code;
  66.347 +}
    67.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    67.2 +++ b/src/compiler/BytecodeEmitter.h	Sat Nov 17 18:41:01 2012 -0800
    67.3 @@ -0,0 +1,737 @@
    67.4 +/* vim: set ts=4 sw=4 tw=99 et:
    67.5 + *
    67.6 + * Copyright (C) 2012 David Anderson
    67.7 + *
    67.8 + * This file is part of JITCraft.
    67.9 + *
   67.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   67.11 + * the terms of the GNU General Public License as published by the Free
   67.12 + * Software Foundation, either version 3 of the License, or (at your option)
   67.13 + * any later version.
   67.14 + * 
   67.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   67.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   67.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   67.18 + *
   67.19 + * You should have received a copy of the GNU General Public License along with
   67.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   67.21 + */
   67.22 +#ifndef _include_bytecode_emitter_h_
   67.23 +#define _include_bytecode_emitter_h_
   67.24 +
   67.25 +#include <assert.h>
   67.26 +#include <limits.h>
   67.27 +#include "../Opcodes.h"
   67.28 +#include "../Handles.h"
   67.29 +#include "../CompactBuffer.h"
   67.30 +#include "../Array.h"
   67.31 +#include "../HashTable.h"
   67.32 +#include "../VirtualObjectVisitor.h"
   67.33 +
   67.34 +namespace ke {
   67.35 +
   67.36 +// An overarching note on overflows: Though we should use CheckedInt, we rely
   67.37 +// on a source-length cap covering all possible overflow checks. As long as
   67.38 +// the source length is capped to INT_MAX, the number of AST nodes will be
   67.39 +// strictly beneath that cap, and so to will most things generated by the
   67.40 +// AST. For example, local and argument counts, number of functions, fields
   67.41 +// in a struct, et cetera. Not everything can be covered by this cap: the
   67.42 +// stack depth, number of bytecodes for example. In these cases we explicitly
   67.43 +// test for overflow of INT_MAX and in other cases we assert.
   67.44 +//
   67.45 +// In the future, we should of course use a checked int wrapper.
   67.46 +
   67.47 +class Type;
   67.48 +class Map;
   67.49 +class ArrayMap;
   67.50 +class Symbol;
   67.51 +class VariableSymbol;
   67.52 +
   67.53 +struct OopRecord
   67.54 +{
   67.55 +    unsigned depth;
   67.56 +    unsigned offset;
   67.57 +    Vector<bool> slots;
   67.58 +
   67.59 +    OopRecord(unsigned length, unsigned offset)
   67.60 +      : depth(length),
   67.61 +        offset(offset)
   67.62 +    {
   67.63 +    }
   67.64 +};
   67.65 +
   67.66 +class StringTable
   67.67 +{
   67.68 +    struct Entry
   67.69 +    {
   67.70 +        String *string;
   67.71 +        unsigned index;
   67.72 +
   67.73 +        Entry()
   67.74 +          : string(NULL),
   67.75 +            index(0)
   67.76 +        {
   67.77 +        }
   67.78 +
   67.79 +        Entry(String *string, unsigned index)
   67.80 +          : string(string),
   67.81 +            index(index)
   67.82 +        {
   67.83 +        }
   67.84 +    };
   67.85 +
   67.86 +    struct Policy
   67.87 +    {
   67.88 +        typedef Entry Payload;
   67.89 +
   67.90 +        static uint32 hash(String *string) {
   67.91 +            return HashPointer(string);
   67.92 +        }
   67.93 +        
   67.94 +        static bool matches(String *key, Entry &e) {
   67.95 +            return key == e.string;
   67.96 +        }
   67.97 +    };
   67.98 +
   67.99 +    typedef HashTable<Policy, ZoneAllocatorPolicy> Set;
  67.100 +
  67.101 +  public:
  67.102 +    StringTable();
  67.103 +    bool initialize();
  67.104 +    void accept(VirtualObjectVisitor *visitor);
  67.105 +
  67.106 +    bool add(Handle<String> name, unsigned *indexp);
  67.107 +    size_t stringCount() const {
  67.108 +        return strings_.length();
  67.109 +    }
  67.110 +    String *stringAt(size_t i) const {
  67.111 +        return strings_[i].string;
  67.112 +    }
  67.113 +
  67.114 +  private:
  67.115 +    Set set_;
  67.116 +    Vector<Entry> strings_;
  67.117 +    bool initialized_;
  67.118 +};
  67.119 +
  67.120 +// The bytecode emitter assists in building Code objects, by emitting opcodes
  67.121 +// and tracking stack information. Since the SemA creates temporary pool/root
  67.122 +// scopes, we cannot use ScopedRoot or PoolObjects. Instead, BCE gets a
  67.123 +// special marking function.
  67.124 +class BytecodeEmitter : public AutoRooted
  67.125 +{
  67.126 +  private:
  67.127 +    PoolAllocator &pool_;
  67.128 +
  67.129 +    bytecode *buffer_;
  67.130 +    bytecode *buffer_pos_;
  67.131 +    bytecode *buffer_end_;
  67.132 +    bytecode inline_buffer_[512];
  67.133 +    bool oom_;
  67.134 +    unsigned maxStackDepth_;
  67.135 +    Vector<bool> oopMap_;
  67.136 +    Vector<OopRecord *> oopRecords_;
  67.137 +    CompactBufferWriter sourcemap_;
  67.138 +    unsigned lastCodePosition_;
  67.139 +    unsigned firstLine_;
  67.140 +    StringTable strings_;
  67.141 +    Vector<Symbol *> locals_;
  67.142 +    Vector<Object *> objects_;
  67.143 +
  67.144 +  private:
  67.145 +    // The maximum size of a code object must be such that the distance between
  67.146 +    // two instructions fits into a signed, 31-bit integer. This ensures that
  67.147 +    // all code-bounded buffers (like the number of object literals or
  67.148 +    // safepoints) does not need to be bounds checked. It also means we can add
  67.149 +    // any two offsets and be guaranteed that they don't overflow.
  67.150 +    static const size_t MAX_LENGTH = INT_MAX / 2;
  67.151 +
  67.152 +  private:
  67.153 +    bool growBuffer(size_t bytes);
  67.154 +
  67.155 +    // Checking the return value is not necessary, since the inline buffer is
  67.156 +    // used as a ballast.
  67.157 +    bool ensure(size_t bytes) {
  67.158 +        if (buffer_pos_ + bytes > buffer_end_)
  67.159 +            return growBuffer(bytes);
  67.160 +        return true;
  67.161 +    }
  67.162 +
  67.163 +    void writeUint8(unsigned value) {
  67.164 +        assert(value <= UCHAR_MAX);
  67.165 +        *buffer_pos_++ = value;
  67.166 +    }
  67.167 +    void writeFloat(float value) {
  67.168 +        *(float *)buffer_pos_ = value;
  67.169 +        buffer_pos_ += sizeof(float);
  67.170 +    }
  67.171 +    void writeInt32(int value) {
  67.172 +        *(int *)buffer_pos_ = value;
  67.173 +        buffer_pos_ += sizeof(int);
  67.174 +    }
  67.175 +    void writeUint32(unsigned value) {
  67.176 +        *(unsigned *)buffer_pos_ = value;
  67.177 +        buffer_pos_ += sizeof(unsigned);
  67.178 +    }
  67.179 +    void writeOp(Opcode op) {
  67.180 +        if (oom_)
  67.181 +            return;
  67.182 +
  67.183 +        writeUint8(op);
  67.184 +        for (int i = 0; i < OpcodeInfo[op].nuses; i++)
  67.185 +            oopMap_.pop();
  67.186 +        for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
  67.187 +            oopMap_.append(false);
  67.188 +        if (oopMap_.length() > maxStackDepth_)
  67.189 +            maxStackDepth_ = oopMap_.length();
  67.190 +    }
  67.191 +    void writeObject(Object *obj) {
  67.192 +        writeUint32(objects_.length());
  67.193 +        ScopedRoot<Object> root(obj);
  67.194 +        if (!objects_.append(root))
  67.195 +            oom_ = true;
  67.196 +    }
  67.197 +
  67.198 +    int position() const {
  67.199 +        assert(buffer_pos_ - buffer_ < INT_MAX / 2);
  67.200 +        return int(buffer_pos_ - buffer_);
  67.201 +    }
  67.202 +
  67.203 +  public:
  67.204 +    BytecodeEmitter(PoolAllocator &pool);
  67.205 +    ~BytecodeEmitter();
  67.206 +
  67.207 +    void accept(VirtualObjectVisitor *visitor);
  67.208 +
  67.209 +    bytecode *buffer() const {
  67.210 +        return buffer_;
  67.211 +    }
  67.212 +    unsigned length() const {
  67.213 +        return unsigned(buffer_pos_ - buffer_);
  67.214 +    }
  67.215 +    bool oom() const {
  67.216 +        return oom_ || sourcemap_.oom();
  67.217 +    }
  67.218 +    unsigned stackDepth() const {
  67.219 +        return oopMap_.length();
  67.220 +    }
  67.221 +    unsigned maxStackDepth() const {
  67.222 +        return maxStackDepth_;
  67.223 +    }
  67.224 +
  67.225 +    void drop(unsigned amt) {
  67.226 +        assert(amt <= stackDepth());
  67.227 +        for (unsigned i = 0; i < amt; i++)
  67.228 +            oopMap_.pop();
  67.229 +    }
  67.230 +
  67.231 +    void note_position(const SourcePosition &pos);
  67.232 +    void setFirstLine(unsigned line) {
  67.233 +        assert(!sourcemap_.length());
  67.234 +        firstLine_ = line;
  67.235 +    }
  67.236 +
  67.237 +  public:
  67.238 +    // A label represents a local control-flow target in the bytecode. A label
  67.239 +    // may be in three states:
  67.240 +    //
  67.241 +    // (1) Empty - the label is not used yet.
  67.242 +    // (2) Pending - the label has incoming jumps, but the actual location of
  67.243 +    //               is not yet known. The list of jumps is threaded through
  67.244 +    //               the four bytes reserved for each emitted jump target. In
  67.245 +    //               this case, the offset field is the location of the most
  67.246 +    //               recently emitted incoming jump.
  67.247 +    // (3) Bound   - the label's position has been pinned.
  67.248 +    //
  67.249 +    // A jump can be emitted to a label in any state. Binding a label
  67.250 +    // immediately backpatches all pending incoming jumps. A label must be
  67.251 +    // bound if it is used.
  67.252 +    class Label
  67.253 +    {
  67.254 +        int offset_ : 31;
  67.255 +        bool bound_ : 1;
  67.256 +
  67.257 +        void setOffset(int offset) {
  67.258 +            offset_ = offset;
  67.259 +            assert(offset_ == offset);
  67.260 +        }
  67.261 +
  67.262 +      public:
  67.263 +        static const int INVALID_OFFSET = -1;
  67.264 +
  67.265 +      public:
  67.266 +        Label()
  67.267 +          : offset_(INVALID_OFFSET),
  67.268 +            bound_(false)
  67.269 +        {
  67.270 +        }
  67.271 +        ~Label()
  67.272 +        {
  67.273 +            assert(bound_ || offset_ == INVALID_OFFSET);
  67.274 +        }
  67.275 +        
  67.276 +        bool bound() const {
  67.277 +            return bound_;
  67.278 +        }
  67.279 +        int offset() const {
  67.280 +            return offset_;
  67.281 +        }
  67.282 +        void bind(int offset) {
  67.283 +            assert(!bound_);
  67.284 +            setOffset(offset);
  67.285 +            bound_ = true;
  67.286 +        }
  67.287 +        int link(int offset) {
  67.288 +            assert(!bound_);
  67.289 +            int old = offset_;
  67.290 +            setOffset(offset);
  67.291 +            return old;
  67.292 +        }
  67.293 +    };
  67.294 +
  67.295 +  private:
  67.296 +    int patchJumpAt(int at, int to) {
  67.297 +        assert(at >= 0 && at < position());
  67.298 +        int old = *(int *)(buffer_ + at + 1);
  67.299 +        *(int *)(buffer_ + at + 1) = (to - at);
  67.300 +        return old;
  67.301 +    }
  67.302 +
  67.303 +    void singleByteOp(Opcode op) {
  67.304 +        assert(OpcodeInfo[op].length == 1);
  67.305 +        ensure(OpcodeInfo[op].length);
  67.306 +        writeOp(op);
  67.307 +    }
  67.308 +
  67.309 +    // Mark a stack slot as having an object pointer.
  67.310 +    void markOop(unsigned depth, bool oop = true) {
  67.311 +        if (oom_)
  67.312 +            return;
  67.313 +        oopMap_[oopMap_.length() - depth] = oop;
  67.314 +    }
  67.315 +    bool getOop(unsigned depth) {
  67.316 +        if (oom_)
  67.317 +            return false;
  67.318 +        return oopMap_[oopMap_.length() - depth];
  67.319 +    }
  67.320 +
  67.321 +    // Mark the current bytecode position as either re-entrant (meaning, it
  67.322 +    // can leave the interpreter or call to another function), or causing GC.
  67.323 +    // This will record which stack slots have objects and associate that
  67.324 +    // information with the current pc.
  67.325 +    void recordOops();
  67.326 +
  67.327 +  public:
  67.328 +    void int_(int value) {
  67.329 +        ensure(OP_INT);
  67.330 +        writeOp(OP_INT);
  67.331 +        writeInt32(value);
  67.332 +    }
  67.333 +    void return_() {
  67.334 +        ensure(OP_RETURN);
  67.335 +        writeOp(OP_RETURN);
  67.336 +    }
  67.337 +    void getlocal(VariableSymbol *var);
  67.338 +    void setlocal(VariableSymbol *var);
  67.339 +#if 0
  67.340 +    void getarg(Variable *var) {
  67.341 +        ensure(OP_GETARG_LENGTH);
  67.342 +        writeOp(OP_GETARG);
  67.343 +        writeUint32(var->slot());
  67.344 +
  67.345 +        if (var->type()->isTraceable())
  67.346 +            markOop(1);
  67.347 +    }
  67.348 +    void setarg(Variable *var) {
  67.349 +        ensure(OP_SETARG_LENGTH);
  67.350 +        writeOp(OP_SETARG);
  67.351 +        writeUint32(var->slot());
  67.352 +
  67.353 +        if (var->type()->isTraceable())
  67.354 +            markOop(1);
  67.355 +    }
  67.356 +#endif
  67.357 +
  67.358 +    void j(Opcode op, Label *label) {
  67.359 +        // Since jumps can skip around the stream, do not try to do anything
  67.360 +        // in a potentially truncated state.
  67.361 +        if (oom())
  67.362 +            return;
  67.363 +
  67.364 +        assert(op == OP_JT || op == OP_JF || op == OP_JUMP);
  67.365 +        ensure(OP_JUMP_LENGTH);
  67.366 +
  67.367 +        if (label->bound()) {
  67.368 +            // We can immediately emit this jump.
  67.369 +            int distance = label->offset() - position();
  67.370 +            writeOp(op);
  67.371 +            writeInt32(distance);
  67.372 +        } else {
  67.373 +            // We can't emit this jump yet. Add a placeholder.
  67.374 +            int old = label->link(position());
  67.375 +            writeOp(op);
  67.376 +            writeInt32(old);
  67.377 +        }
  67.378 +    }
  67.379 +    void bind(Label *label) {
  67.380 +        if (oom())
  67.381 +            return;
  67.382 +
  67.383 +        assert(!label->bound());
  67.384 +
  67.385 +        int offset = label->offset();
  67.386 +        while (offset != Label::INVALID_OFFSET)
  67.387 +            offset = patchJumpAt(offset, position());
  67.388 +
  67.389 +        label->bind(position());
  67.390 +    }
  67.391 +    void jump(Label *label) {
  67.392 +        j(OP_JUMP, label);
  67.393 +    }
  67.394 +
  67.395 +    void binary(Opcode op) {
  67.396 +        singleByteOp(op);
  67.397 +    }
  67.398 +    void unary(Opcode op) {
  67.399 +        singleByteOp(op);
  67.400 +    }
  67.401 +
  67.402 +    void pop() {
  67.403 +        singleByteOp(OP_POP);
  67.404 +    }
  67.405 +    void stop() {
  67.406 +        singleByteOp(OP_STOP);
  67.407 +    }
  67.408 +    void call(Handle<FunctionType> fun, unsigned argc) {
  67.409 +        recordOops();
  67.410 +
  67.411 +        if (fun->isNative()) {
  67.412 +            ensure(OP_CALLNATIVE_LENGTH);
  67.413 +            writeOp(OP_CALLNATIVE);
  67.414 +            writeUint32(argc);
  67.415 +            drop(argc + 1);
  67.416 +        } else {
  67.417 +            ensure(OP_CALL_LENGTH);
  67.418 +            writeOp(OP_CALL);
  67.419 +            drop(argc + 1);
  67.420 +
  67.421 +            if (fun->returnType()->isVoid())
  67.422 +                drop(1);
  67.423 +            else if (fun->returnType()->isTraceable())
  67.424 +                markOop(1);
  67.425 +        }
  67.426 +    }
  67.427 +
  67.428 +    void getelem(Type *type) {
  67.429 +        singleByteOp(OP_GETELEM);
  67.430 +
  67.431 +        if (type->isTraceable())
  67.432 +            markOop(1);
  67.433 +    }
  67.434 +    void setelem(Type *type) {
  67.435 +        singleByteOp(OP_SETELEM);
  67.436 +    }
  67.437 +
  67.438 +    void getfield(unsigned index, Type *type) {
  67.439 +        ensure(OP_GETFIELD_LENGTH);
  67.440 +        writeOp(OP_GETFIELD);
  67.441 +        writeUint32(index);
  67.442 +
  67.443 +        if (type->isTraceable())
  67.444 +            markOop(1);
  67.445 +    }
  67.446 +    void setfield(unsigned index, Type *type) {
  67.447 +        ensure(OP_SETFIELD_LENGTH);
  67.448 +        writeOp(OP_SETFIELD);
  67.449 +        writeUint32(index);
  67.450 +
  67.451 +        if (type->isTraceable())
  67.452 +            markOop(1);
  67.453 +    }
  67.454 +
  67.455 +#if 0
  67.456 +    void getglobal(Variable *var) {
  67.457 +        ensure(OP_GETGLOBAL_F_LENGTH);
  67.458 +        if (var->type()->isPrimitive()) {
  67.459 +            switch (var->type()->primitive()) {
  67.460 +              case PrimitiveType_Float:
  67.461 +                writeOp(OP_GETGLOBAL_F);
  67.462 +                break;
  67.463 +              default:
  67.464 +                assert(var->type()->primitive() == PrimitiveType_Int32);
  67.465 +                writeOp(OP_GETGLOBAL_I);
  67.466 +                break;
  67.467 +            }
  67.468 +        } else {
  67.469 +            writeOp(OP_GETGLOBAL_O);
  67.470 +            markOop(1);
  67.471 +        }
  67.472 +        writeUint32(var->slot());
  67.473 +    }
  67.474 +    void setglobal(Variable *var) {
  67.475 +        ensure(OP_SETGLOBAL_F_LENGTH);
  67.476 +        if (var->type()->isPrimitive()) {
  67.477 +            switch (var->type()->primitive()) {
  67.478 +              case PrimitiveType_Float:
  67.479 +                writeOp(OP_SETGLOBAL_F);
  67.480 +                break;
  67.481 +              default:
  67.482 +                assert(var->type()->primitive() == PrimitiveType_Int32);
  67.483 +                writeOp(OP_SETGLOBAL_I);
  67.484 +                break;
  67.485 +            }
  67.486 +        } else {
  67.487 +            writeOp(OP_SETGLOBAL_O);
  67.488 +        }
  67.489 +        writeUint32(var->slot());
  67.490 +    }
  67.491 +#endif
  67.492 +
  67.493 +    void float_(float value) {
  67.494 +        ensure(OP_FLOAT_LENGTH);
  67.495 +        writeOp(OP_FLOAT);
  67.496 +        writeFloat(value);
  67.497 +    }
  67.498 +    void cvt_i2f() {
  67.499 +        singleByteOp(OP_CVT_I2F);
  67.500 +    }
  67.501 +    void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
  67.502 +        assert(op == OP_NEWFIXED ||
  67.503 +               op == OP_NEWEMPTY ||
  67.504 +               op == OP_NEWSIZED);
  67.505 +
  67.506 +        recordOops();
  67.507 +        ensure(OpcodeInfo[op].length);
  67.508 +        writeOp(op);
  67.509 +        writeUint8(tenure);
  67.510 +        writeObject(map);
  67.511 +
  67.512 +        if (op == OP_NEWSIZED)
  67.513 +            drop(map->type()->levels());
  67.514 +
  67.515 +        markOop(1);
  67.516 +    }
  67.517 +    void newstruct(Handle<Map> map, Heap::Tenure tenure) {
  67.518 +        recordOops();
  67.519 +        ensure(OP_NEWSTRUCT_LENGTH);
  67.520 +        writeOp(OP_NEWSTRUCT);
  67.521 +        writeUint8(tenure);
  67.522 +        writeObject(map);
  67.523 +        markOop(1);
  67.524 +    }
  67.525 +    void savelifo(unsigned slot) {
  67.526 +        ensure(OP_SAVELIFO_LENGTH);
  67.527 +        writeOp(OP_SAVELIFO);
  67.528 +        writeUint32(slot);
  67.529 +    }
  67.530 +    void unwindlifo(unsigned slot) {
  67.531 +        ensure(OP_UNWINDLIFO_LENGTH);
  67.532 +        writeOp(OP_UNWINDLIFO);
  67.533 +        writeUint32(slot);
  67.534 +    }
  67.535 +#if 0
  67.536 +    void newref(Variable *var) {
  67.537 +        recordOops();
  67.538 +        if (var->location() == Variable::STACK) {
  67.539 +            ensure(OP_VARREF_LIFO_LENGTH);
  67.540 +            writeOp(OP_VARREF_LIFO);
  67.541 +        } else {
  67.542 +            assert(var->location() == Variable::PARAMETER);
  67.543 +            ensure(OP_ARGREF_LIFO_LENGTH);
  67.544 +            writeOp(OP_ARGREF_LIFO);
  67.545 +        }
  67.546 +        writeUint32(var->slot());
  67.547 +        markOop(1);
  67.548 +    }
  67.549 +#endif
  67.550 +
  67.551 +    void slotref_lifo() {
  67.552 +        recordOops();
  67.553 +        singleByteOp(OP_SLOTREF_LIFO);
  67.554 +        markOop(1);
  67.555 +    }
  67.556 +    void getref(Type *type) {
  67.557 +        if (type->pod() == PrimitiveType_Int32) {
  67.558 +            singleByteOp(OP_GETREF_I);
  67.559 +        } else {
  67.560 +            assert(type->pod() == PrimitiveType_Float);
  67.561 +            singleByteOp(OP_GETREF_F);
  67.562 +        }
  67.563 +    }
  67.564 +    void setref(Type *type) {
  67.565 +        if (type->pod() == PrimitiveType_Int32) {
  67.566 +            singleByteOp(OP_SETREF_I);
  67.567 +        } else {
  67.568 +            assert(type->pod() == PrimitiveType_Float);
  67.569 +            singleByteOp(OP_SETREF_F);
  67.570 +        }
  67.571 +    }
  67.572 +    void object(Handle<Object> obj) {
  67.573 +        ensure(OP_OBJECT_LENGTH);
  67.574 +        writeOp(OP_OBJECT);
  67.575 +        writeObject(obj);
  67.576 +        markOop(1);
  67.577 +    }
  67.578 +    void copyarray() {
  67.579 +        singleByteOp(OP_COPYARRAY);
  67.580 +        markOop(1);
  67.581 +    }
  67.582 +    void copystruct() {
  67.583 +        singleByteOp(OP_COPYSTRUCT);
  67.584 +        markOop(1);
  67.585 +    }
  67.586 +    void sizeof_() {
  67.587 +        singleByteOp(OP_SIZEOF);
  67.588 +    }
  67.589 +
  67.590 +    void dup() {
  67.591 +        bool oop = getOop(1);
  67.592 +        singleByteOp(OP_DUP);
  67.593 +        markOop(1, oop);
  67.594 +    }
  67.595 +    void dup2() {
  67.596 +        bool oop2 = getOop(2);
  67.597 +        bool oop1 = getOop(1);
  67.598 +
  67.599 +        singleByteOp(OP_DUP2);
  67.600 +
  67.601 +        markOop(2, oop2);
  67.602 +        markOop(1, oop1);
  67.603 +    }
  67.604 +    void swap() {
  67.605 +        bool oop2 = getOop(2);
  67.606 +        bool oop1 = getOop(1);
  67.607 +
  67.608 +        singleByteOp(OP_SWAP);
  67.609 +
  67.610 +        markOop(2, oop1);
  67.611 +        markOop(1, oop2);
  67.612 +    }
  67.613 +    void roll3() {
  67.614 +        bool oop3 = getOop(3);
  67.615 +        bool oop2 = getOop(2);
  67.616 +        bool oop1 = getOop(1);
  67.617 +
  67.618 +        singleByteOp(OP_ROLL3);
  67.619 +
  67.620 +        markOop(3, oop2);
  67.621 +        markOop(2, oop1);
  67.622 +        markOop(1, oop3);
  67.623 +    }
  67.624 +    void pick2() {
  67.625 +        bool oop2 = getOop(2);
  67.626 +        bool oop1 = getOop(1);
  67.627 +
  67.628 +        singleByteOp(OP_PICK2);
  67.629 +
  67.630 +        markOop(3, oop2);
  67.631 +        markOop(2, oop1);
  67.632 +        markOop(1, oop2);
  67.633 +    }
  67.634 +    void pick3() {
  67.635 +        bool oop3 = getOop(3);
  67.636 +        bool oop2 = getOop(2);
  67.637 +        bool oop1 = getOop(1);
  67.638 +
  67.639 +        singleByteOp(OP_PICK3);
  67.640 +
  67.641 +        markOop(4, oop3);
  67.642 +        markOop(3, oop2);
  67.643 +        markOop(2, oop1);
  67.644 +        markOop(1, oop3);
  67.645 +    }
  67.646 +
  67.647 +    void returnvoid() {
  67.648 +        singleByteOp(OP_RETURNVOID);
  67.649 +    }
  67.650 +    void bitnot() {
  67.651 +        singleByteOp(OP_BITNOT);
  67.652 +    }
  67.653 +    void not_() {
  67.654 +        singleByteOp(OP_NOT);
  67.655 +    }
  67.656 +    void not_f() {
  67.657 +        singleByteOp(OP_NOT_F);
  67.658 +    }
  67.659 +    void neg() {
  67.660 +        singleByteOp(OP_NEG);
  67.661 +    }
  67.662 +    void neg_f() {
  67.663 +        singleByteOp(OP_NEG_F);
  67.664 +    }
  67.665 +    void bits_i2f() {
  67.666 +        singleByteOp(OP_BITS_I2F);
  67.667 +    }
  67.668 +    void bits_f2i() {
  67.669 +        singleByteOp(OP_BITS_F2I);
  67.670 +    }
  67.671 +    void true_() {
  67.672 +        singleByteOp(OP_TRUE);
  67.673 +    }
  67.674 +    void false_() {
  67.675 +        singleByteOp(OP_FALSE);
  67.676 +    }
  67.677 +    
  67.678 +    unsigned addString(Handle<String> name) {
  67.679 +        unsigned index;
  67.680 +        if (!strings_.add(name, &index)) {
  67.681 +            oom_ |= true;
  67.682 +            return 0;
  67.683 +        }
  67.684 +        return index;
  67.685 +    }
  67.686 +
  67.687 +    void getglobal(Symbol *sym);
  67.688 +    void setglobal(Symbol *sym);
  67.689 +
  67.690 +    void public_() {
  67.691 +        recordOops();
  67.692 +        singleByteOp(OP_PUBLIC);
  67.693 +    }
  67.694 +
  67.695 +    void tableswitch(int low, int high, Label *def, Label **labels) {
  67.696 +        unsigned tablesize = TableSwitchEntries(low, high);
  67.697 +        assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
  67.698 +
  67.699 +        ensure(OP_TABLESWITCH_LENGTH);
  67.700 +        writeOp(OP_TABLESWITCH);
  67.701 +        writeInt32(low);
  67.702 +        writeInt32(high);
  67.703 +        jump(def);
  67.704 +
  67.705 +        // When labels are patched, we assume each position is a jump. Rather
  67.706 +        // than hack position offsets to make labels work without actual
  67.707 +        // incoming jumps, we emit a jump inline.
  67.708 +        for (unsigned i = 0; i < tablesize; i++)
  67.709 +            jump(labels[i]);
  67.710 +    }
  67.711 +
  67.712 +    bool allocate(VariableSymbol *sym);
  67.713 +
  67.714 +    Code *finish();
  67.715 +
  67.716 +    // Helpers.
  67.717 +#if 0
  67.718 +    void get(Variable *var) {
  67.719 +        if (var->location() == Variable::STACK) {
  67.720 +            getlocal(var);
  67.721 +        } else {
  67.722 +            assert(var->location() == Variable::PARAMETER);
  67.723 +            getarg(var);
  67.724 +        }
  67.725 +    }
  67.726 +    void set(Variable *var) {
  67.727 +        assert(!var->type()->isReference());
  67.728 +        if (var->location() == Variable::STACK) {
  67.729 +            setlocal(var);
  67.730 +        } else {
  67.731 +            assert(var->location() == Variable::PARAMETER);
  67.732 +            setarg(var);
  67.733 +        }
  67.734 +    }
  67.735 +#endif
  67.736 +};
  67.737 +
  67.738 +}
  67.739 +
  67.740 +#endif // _include_bytecode_emitter_h_
    68.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    68.2 +++ b/src/compiler/CompileContext.cpp	Sat Nov 17 18:41:01 2012 -0800
    68.3 @@ -0,0 +1,268 @@
    68.4 +/*
    68.5 + * Copyright (C) 2012 David Anderson
    68.6 + *
    68.7 + * This file is part of JITCraft.
    68.8 + *
    68.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   68.10 + * the terms of the GNU General Public License as published by the Free
   68.11 + * Software Foundation, either version 3 of the License, or (at your option)
   68.12 + * any later version.
   68.13 + * 
   68.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   68.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   68.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   68.17 + *
   68.18 + * You should have received a copy of the GNU General Public License along with
   68.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   68.20 + */
   68.21 +#include <stdio.h>
   68.22 +#include "../Zone.h"
   68.23 +#include "../Interpreter.h"
   68.24 +#include "Scanner.h"
   68.25 +#include "CompileContext.h"
   68.26 +#include "Parser.h"
   68.27 +#include "NameBinding.h"
   68.28 +#include "SemanticAnalysis.h"
   68.29 +#include "../Spaces-inl.h"
   68.30 +#include "../Heap-inl.h"
   68.31 +
   68.32 +using namespace ke;
   68.33 +
   68.34 +CompileContext::CompileContext(Zone *zone, const char *file)
   68.35 +  : zone_(zone),
   68.36 +    failures_(0),
   68.37 +    file_(file)
   68.38 +{
   68.39 +}
   68.40 +
   68.41 +CompileContext::~CompileContext()
   68.42 +{
   68.43 +    if (failures_)
   68.44 +        zone_->endCompilationErrors();
   68.45 +}
   68.46 +
   68.47 +bool
   68.48 +CompileContext::addTranslationUnit(TranslationUnit *unit)
   68.49 +{
   68.50 +    if (!units_.append(unit))
   68.51 +        return false;
   68.52 +
   68.53 +    if (!unparsed_.append(unit))
   68.54 +        return false;
   68.55 +
   68.56 +    return true;
   68.57 +}
   68.58 +
   68.59 +char *
   68.60 +CompileContext::loadSource(const char *file, size_t *lengthp)
   68.61 +{
   68.62 +    char *bytes = NULL;
   68.63 +    size_t length;
   68.64 +
   68.65 +    FILE *fp = fopen(file, "rb");
   68.66 +    if (!fp) {
   68.67 +        reportError(SourcePosition(), Message_CantOpenFile);
   68.68 +        return NULL;
   68.69 +    }
   68.70 +
   68.71 +    if (fseek(fp, 0, SEEK_END)) {
   68.72 +        reportError(SourcePosition(), Message_ErrorSeekingFile);
   68.73 +        fclose(fp);
   68.74 +        return NULL;
   68.75 +    }
   68.76 +    long size = ftell(fp);
   68.77 +    if (size < 0) {
   68.78 +        reportError(SourcePosition(), Message_ErrorSeekingFile);
   68.79 +        fclose(fp);
   68.80 +        return NULL;
   68.81 +    }
   68.82 +    rewind(fp);
   68.83 +    length = size_t(size);
   68.84 +    bytes = new char[length + 1];
   68.85 +    if (fread(bytes, 1, length, fp) != length) {
   68.86 +        reportError(SourcePosition(), Message_ErrorReadingFile);
   68.87 +        fclose(fp);
   68.88 +        delete [] bytes;
   68.89 +        return NULL;
   68.90 +    }
   68.91 +    fclose(fp);
   68.92 +
   68.93 +    *lengthp = length;
   68.94 +    return bytes;
   68.95 +}
   68.96 +
   68.97 +bool
   68.98 +CompileContext::parse(TranslationUnit *unit)
   68.99 +{
  68.100 +    assert(!unit->tree_);
  68.101 +
  68.102 +    size_t length;
  68.103 +    char *source = loadSource(unit->path_.c_str(), &length);
  68.104 +    if (!source)
  68.105 +        return false;
  68.106 +
  68.107 +    Parser parser(ZONE(), *this, source, length);
  68.108 +    if ((unit->tree_ = parser.parse()) == NULL)
  68.109 +        return false;
  68.110 +
  68.111 +    return true;
  68.112 +}
  68.113 +
  68.114 +bool
  68.115 +CompileContext::evaluateImports(TranslationUnit *unit)
  68.116 +{
  68.117 +    if (units_.length() > 1)
  68.118 +        return true;
  68.119 +
  68.120 +#if 0
  68.121 +    // For now we hardcode this...
  68.122 +    TranslationUnit *u2 = new (ZONE()->pool()) TranslationUnit();
  68.123 +    u2->path_ = "C:\\Users\\dvander\\jitcraft\\jitcraft-2\\src\\Debug\\wizard.sp";
  68.124 +
  68.125 +    ImportStatement *stmt = unit->tree()->imports()->at(0)->toImportStatement();
  68.126 +    stmt->setImportSource(u2);
  68.127 +
  68.128 +    if (!u2->dependents_.append(unit))
  68.129 +        return false;
  68.130 +
  68.131 +    if (!addTranslationUnit(u2))
  68.132 +        return false;
  68.133 +#endif
  68.134 +
  68.135 +    return true;
  68.136 +}
  68.137 +
  68.138 +bool
  68.139 +CompileContext::propagateFailure()
  68.140 +{
  68.141 +    Vector<TranslationUnit *> worklist;
  68.142 +    for (size_t i = 0; i < units_.length(); i++) {
  68.143 +        if (units_[i]->failed() && !worklist.append(units_[i]))
  68.144 +            return false;
  68.145 +    }
  68.146 +
  68.147 +    while (!worklist.empty()) {
  68.148 +        TranslationUnit *unit = worklist.popCopy();
  68.149 +        for (size_t i = 0; i < unit->dependents().length(); i++) {
  68.150 +            TranslationUnit *other = unit->dependents().at(i);
  68.151 +            if (other->failed())
  68.152 +                continue;
  68.153 +
  68.154 +            other->failed_ = true;
  68.155 +            if (!worklist.append(other))
  68.156 +                return false;
  68.157 +        }
  68.158 +    }
  68.159 +
  68.160 +    return true;
  68.161 +}
  68.162 +
  68.163 +bool
  68.164 +CompileContext::compile()
  68.165 +{
  68.166 +    // Phase 1. Parse all modules we're importing. This process may load new
  68.167 +    // modules off disk, and add them to the parse queue.
  68.168 +    while (!unparsed_.empty()) {
  68.169 +        TranslationUnit *unit = unparsed_.popCopy();
  68.170 +
  68.171 +        if (!parse(unit))
  68.172 +            unit->failed_ = true;
  68.173 +
  68.174 +        if (!evaluateImports(unit))
  68.175 +            unit->failed_ = true;
  68.176 +    }
  68.177 +
  68.178 +    // Phase 2. Create scopes and symbol tables for every lexical region with
  68.179 +    // a declaration. This phase excludes declarations created via imports.
  68.180 +    for (size_t i = 0; i < units_.length(); i++) {
  68.181 +        TranslationUnit *unit = units_[i];
  68.182 +        if (unit->failed())
  68.183 +            continue;
  68.184 +
  68.185 +        if (!PopulateNamesAndTypes(zone_, *this, unit))
  68.186 +            unit->failed_ = true;
  68.187 +    }
  68.188 +
  68.189 +    // Phase 3. Complete imports and bind all names.
  68.190 +    for (size_t i = 0; i < units_.length(); i++) {
  68.191 +        TranslationUnit *unit = units_[i];
  68.192 +        if (unit->failed())
  68.193 +            continue;
  68.194 +
  68.195 +        if (!BindNamesAndTypes(zone_, *this, unit))
  68.196 +            unit->failed_ = true;
  68.197 +    }
  68.198 +
  68.199 +    // Phase 4. Assign types to every public name in the module.
  68.200 +    for (size_t i = 0; i < units_.length(); i++) {
  68.201 +        TranslationUnit *unit = units_[i];
  68.202 +        if (unit->failed())
  68.203 +            continue;
  68.204 +
  68.205 +    }
  68.206 +
  68.207 +    // Intermediate phase. Decide which modules we should not perform
  68.208 +    // semantic analysis on.
  68.209 +    if (!propagateFailure())
  68.210 +        return false;
  68.211 +
  68.212 +    // Phase 4. Perform full semantic analysis on each module.
  68.213 +    for (size_t i = 0; i < units_.length(); i++) {
  68.214 +        TranslationUnit *unit = units_[i];
  68.215 +        if (unit->failed())
  68.216 +            continue;
  68.217 +
  68.218 +  
  68.219 +    }
  68.220 +
  68.221 +    // Intermediate phase. Propagate failure from semantic analysis.
  68.222 +    if (!propagateFailure())
  68.223 +        return false;
  68.224 +
  68.225 +    // Phase 5. Now we can finally perform bytecode compilation.
  68.226 +    for (size_t i = 0; i < units_.length(); i++) {
  68.227 +        TranslationUnit *unit = units_[i];
  68.228 +        if (unit->failed())
  68.229 +            continue;
  68.230 +
  68.231 +        SemanticAnalysis sema(zone_, *this, unit);
  68.232 +        sema.analyze();
  68.233 +    }
  68.234 +
  68.235 +    // Phase 6. Run modules.
  68.236 +    for (size_t i = 0; i < units_.length(); i++) {
  68.237 +        TranslationUnit *unit = units_[i];
  68.238 +        if (unit->failed())
  68.239 +            continue;
  68.240 +
  68.241 +        InvokeArgs args;
  68.242 +        if (!zone_->stack().pushModuleFrame(unit->module_, args))
  68.243 +            assert(false);
  68.244 +
  68.245 +        ke::LocalSlot slot;
  68.246 +        if (!Interpret(zone_, NULL, &slot))
  68.247 +            assert(false);
  68.248 +    }
  68.249 +
  68.250 +    return true;
  68.251 +}
  68.252 +
  68.253 +void
  68.254 +CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap)
  68.255 +{
  68.256 +    if (!failures_)
  68.257 +        zone_->beginCompilationErrors(file_);
  68.258 +
  68.259 +    zone_->reportCompilationError(msg, pos.line, pos.col, ap);
  68.260 +
  68.261 +    failures_++;
  68.262 +}
  68.263 +
  68.264 +void
  68.265 +CompileContext::reportError(const SourcePosition &pos, Message msg, ...)
  68.266 +{
  68.267 +    va_list ap;
  68.268 +    va_start(ap, msg);
  68.269 +    reportErrorVa(pos, msg, ap);
  68.270 +    va_end(ap);
  68.271 +}
    69.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    69.2 +++ b/src/compiler/CompileContext.h	Sat Nov 17 18:41:01 2012 -0800
    69.3 @@ -0,0 +1,113 @@
    69.4 +/*
    69.5 + * Copyright (C) 2012 David Anderson
    69.6 + *
    69.7 + * This file is part of JITCraft.
    69.8 + *
    69.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   69.10 + * the terms of the GNU General Public License as published by the Free
   69.11 + * Software Foundation, either version 3 of the License, or (at your option)
   69.12 + * any later version.
   69.13 + * 
   69.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   69.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   69.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   69.17 + *
   69.18 + * You should have received a copy of the GNU General Public License along with
   69.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   69.20 + */
   69.21 +#ifndef _include_jitcraft_compile_context_h_
   69.22 +#define _include_jitcraft_compile_context_h_
   69.23 +
   69.24 +#include <stdarg.h>
   69.25 +#include <string>
   69.26 +#include "../Messages.h"
   69.27 +#include "../PoolAllocator.h"
   69.28 +#include "../Handles.h"
   69.29 +#include "../Modules.h"
   69.30 +
   69.31 +namespace ke {
   69.32 +
   69.33 +class Zone;
   69.34 +class ParseTree;
   69.35 +class String;
   69.36 +class ImportScope;
   69.37 +class GlobalScope;
   69.38 +struct SourcePosition;
   69.39 +struct TranslationUnit;
   69.40 +class ImportStatement;
   69.41 +
   69.42 +struct TranslationUnit : public PoolObject
   69.43 +{
   69.44 +    TranslationUnit()
   69.45 +      : tree_(NULL),
   69.46 +        failed_(false),
   69.47 +        importScope_(NULL),
   69.48 +        globalScope_(NULL)
   69.49 +    {
   69.50 +    }
   69.51 +
   69.52 +    ParseTree *tree_;
   69.53 +    std::string path_;
   69.54 +    bool failed_;
   69.55 +    PoolList<TranslationUnit *> dependents_;
   69.56 +    ImportScope *importScope_;
   69.57 +    GlobalScope *globalScope_;
   69.58 +    ScopedRoot<Module> module_;
   69.59 +
   69.60 +    ParseTree *tree() const {
   69.61 +        return tree_;
   69.62 +    }
   69.63 +    PoolList<TranslationUnit *> &dependents() {
   69.64 +        return dependents_;
   69.65 +    }
   69.66 +    bool failed() const {
   69.67 +        return failed_;
   69.68 +    }
   69.69 +    void setImportScope(ImportScope *scope) {
   69.70 +        assert(!importScope_);
   69.71 +        importScope_ = scope;
   69.72 +    }
   69.73 +    void setGlobalScope(GlobalScope *scope) {
   69.74 +        assert(!globalScope_);
   69.75 +        globalScope_ = scope;
   69.76 +    }
   69.77 +    ImportScope *importScope() const {
   69.78 +        return importScope_;
   69.79 +    }
   69.80 +    GlobalScope *globalScope() const {
   69.81 +        return globalScope_;
   69.82 +    }
   69.83 +};
   69.84 +
   69.85 +class CompileContext
   69.86 +{
   69.87 +    Zone *zone_;
   69.88 +    unsigned failures_;
   69.89 +    const char *file_;
   69.90 +    Vector<TranslationUnit *> units_;
   69.91 +    Vector<TranslationUnit *> unparsed_;
   69.92 +
   69.93 +  private:
   69.94 +    char *loadSource(const char *file, size_t *length);
   69.95 +    bool parse(TranslationUnit *unit);
   69.96 +    bool evaluateImports(TranslationUnit *unit);
   69.97 +    bool propagateFailure();
   69.98 +
   69.99 +  public:
  69.100 +    CompileContext(Zone *zone, const char *file);
  69.101 +    ~CompileContext();
  69.102 +
  69.103 +    bool addTranslationUnit(TranslationUnit *unit);
  69.104 +    bool compile();
  69.105 +
  69.106 +    void reportErrorVa(const SourcePosition &pos, Message msg, va_list ap);
  69.107 +    void reportError(const SourcePosition &pos, Message msg, ...);
  69.108 +
  69.109 +    unsigned failures() const {
  69.110 +        return failures_;
  69.111 +    }
  69.112 +};
  69.113 +
  69.114 +}
  69.115 +
  69.116 +#endif // _include_jitcraft_compile_context_h_
    70.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    70.2 +++ b/src/compiler/HIR.cpp	Sat Nov 17 18:41:01 2012 -0800
    70.3 @@ -0,0 +1,246 @@
    70.4 +/* vim: set ts=4 sw=4 tw=99 et:
    70.5 + *
    70.6 + * Copyright (C) 2012 David Anderson
    70.7 + *
    70.8 + * This file is part of JITCraft.
    70.9 + *
   70.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   70.11 + * the terms of the GNU General Public License as published by the Free
   70.12 + * Software Foundation, either version 3 of the License, or (at your option)
   70.13 + * any later version.
   70.14 + * 
   70.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   70.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   70.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   70.18 + *
   70.19 + * You should have received a copy of the GNU General Public License along with
   70.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   70.21 + */
   70.22 +#include "HIR.h"
   70.23 +#include "BytecodeEmitter.h"
   70.24 +
   70.25 +using namespace ke;
   70.26 +
   70.27 +class HIRTranslator : public HIRVisitor
   70.28 +{
   70.29 +  public:
   70.30 +    HIRTranslator(Zone *zone, BytecodeEmitter &emitter)
   70.31 +      : zone_(zone),
   70.32 +        emitter_(emitter)
   70.33 +    {
   70.34 +    }
   70.35 +
   70.36 +    void translate(HIR *hir) {
   70.37 +        hir->accept(this);
   70.38 +    }
   70.39 +
   70.40 +    void visitFloat(HFloat *hir);
   70.41 +    void visitInteger(HInteger *hir);
   70.42 +    void visitCall(HCall *call);
   70.43 +    void visitStore(HStore *store);
   70.44 +    void visitBinary(HBinary *binary);
   70.45 +    void visitLocal(HLocal *local);
   70.46 +    void visitGlobal(HGlobal *global);
   70.47 +    void visitConvert(HConvert *convert);
   70.48 +
   70.49 +  private:
   70.50 +    Zone *zone_;
   70.51 +    BytecodeEmitter &emitter_;
   70.52 +};
   70.53 +
   70.54 +#define __ emitter_.
   70.55 +
   70.56 +void
   70.57 +HIRTranslator::visitFloat(HFloat *hir)
   70.58 +{
   70.59 +    __ float_(hir->value());
   70.60 +}
   70.61 +
   70.62 +void
   70.63 +HIRTranslator::visitInteger(HInteger *hir)
   70.64 +{
   70.65 +    __ int_(hir->value());
   70.66 +}
   70.67 +
   70.68 +void
   70.69 +HIRTranslator::visitCall(HCall *call)
   70.70 +{
   70.71 +    Local<FunctionType> fun(zone_, FunctionType::cast(call->callee()->type()));
   70.72 +    
   70.73 +    assert(call->args()->length() == fun->parameters()->length());
   70.74 +
   70.75 +    unsigned argc = call->args()->length();
   70.76 +
   70.77 +    for (size_t i = call->args()->length() - 1; i < call->args()->length(); i--) {
   70.78 +        HIR *hir = call->args()->at(i);
   70.79 +        hir->accept(this);
   70.80 +    }
   70.81 +
   70.82 +    call->callee()->accept(this);
   70.83 +    __ call(fun, argc);
   70.84 +}
   70.85 +
   70.86 +void
   70.87 +HGlobal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   70.88 +{
   70.89 +}
   70.90 +
   70.91 +void
   70.92 +HGlobal::store(BytecodeEmitter &emitter_)
   70.93 +{
   70.94 +    __ setglobal(sym_);
   70.95 +}
   70.96 +
   70.97 +void
   70.98 +HGlobal::load(BytecodeEmitter &emitter_)
   70.99 +{
  70.100 +    __ getglobal(sym_);
  70.101 +}
  70.102 +
  70.103 +void
  70.104 +HLocal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
  70.105 +{
  70.106 +    if (sym_->type()->isReference())
  70.107 +        __ getlocal(sym_);
  70.108 +}
  70.109 +
  70.110 +void
  70.111 +HLocal::store(BytecodeEmitter &emitter_)
  70.112 +{
  70.113 +    if (sym_->type()->isReference())
  70.114 +        __ setref(sym_->type()->contained());
  70.115 +    else
  70.116 +        __ setlocal(sym_);
  70.117 +}
  70.118 +
  70.119 +void
  70.120 +HLocal::load(BytecodeEmitter &emitter_)
  70.121 +{
  70.122 +    if (sym_->type()->isReference())
  70.123 +        __ getref(sym_->type());
  70.124 +    else
  70.125 +        __ getlocal(sym_);
  70.126 +}
  70.127 +
  70.128 +void
  70.129 +HIndex::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
  70.130 +{
  70.131 +    left_->accept(visitor);
  70.132 +    right_->accept(visitor);
  70.133 +}
  70.134 +
  70.135 +void
  70.136 +HIndex::store(BytecodeEmitter &emitter_)
  70.137 +{
  70.138 +    __ setelem(type());
  70.139 +}
  70.140 +
  70.141 +void
  70.142 +HIndex::load(BytecodeEmitter &emitter_)
  70.143 +{
  70.144 +    __ getelem(type());
  70.145 +}
  70.146 +
  70.147 +void
  70.148 +HIRTranslator::visitLocal(HLocal *local)
  70.149 +{
  70.150 +    local->bind(this, emitter_);
  70.151 +    local->load(emitter_);
  70.152 +}
  70.153 +
  70.154 +void
  70.155 +HIRTranslator::visitGlobal(HGlobal *global)
  70.156 +{
  70.157 +    __ getglobal(global->sym());
  70.158 +}
  70.159 +
  70.160 +void
  70.161 +HIRTranslator::visitStore(HStore *store)
  70.162 +{
  70.163 +    store->lval()->bind(this, emitter_);
  70.164 +    store->rval()->accept(this);
  70.165 +    store->lval()->store(emitter_);
  70.166 +}
  70.167 +
  70.168 +static inline Opcode
  70.169 +TokenToOpcode(TokenKind kind)
  70.170 +{
  70.171 +    switch (kind) {
  70.172 +      case TOK_PLUS:
  70.173 +        return OP_ADD;
  70.174 +      case TOK_MINUS:
  70.175 +        return OP_SUB;
  70.176 +      case TOK_STAR:
  70.177 +        return OP_MUL;
  70.178 +      case TOK_SLASH:
  70.179 +        return OP_DIV;
  70.180 +      case TOK_PERCENT:
  70.181 +        return OP_MOD;
  70.182 +      case TOK_SHR:
  70.183 +        return OP_SHR;
  70.184 +      case TOK_USHR:
  70.185 +        return OP_USHR;
  70.186 +      case TOK_SHL:
  70.187 +        return OP_SHL;
  70.188 +      case TOK_BITAND:
  70.189 +        return OP_BITAND;
  70.190 +      case TOK_BITOR:
  70.191 +        return OP_BITOR;
  70.192 +      case TOK_GT:
  70.193 +          return OP_GT;
  70.194 +      case TOK_GE:
  70.195 +          return OP_GE;
  70.196 +      case TOK_LT:
  70.197 +          return OP_LT;
  70.198 +      case TOK_LE:
  70.199 +          return OP_LE;
  70.200 +      case TOK_EQUALS:
  70.201 +          return OP_EQ;
  70.202 +      case TOK_NOTEQUALS:
  70.203 +          return OP_NE;
  70.204 +      default:
  70.205 +        assert(kind == TOK_BITXOR);
  70.206 +        return OP_BITXOR;
  70.207 +    }
  70.208 +}
  70.209 +
  70.210 +void
  70.211 +HIRTranslator::visitBinary(HBinary *binary)
  70.212 +{
  70.213 +    binary->left()->accept(this);
  70.214 +    binary->right()->accept(this);
  70.215 +
  70.216 +    // We define three sets of math operators:
  70.217 +    //
  70.218 +    //  (1) ADD, SUB, MUL, DIV, MOD, which take two equal types and produce
  70.219 +    //      the same type.
  70.220 +    //  (2) LT, LE, GE, GT, EQ, NE, which take two equal types and produce
  70.221 +    //      a boolean.
  70.222 +    //  (3) SHL, SR, USHR, BITAND, BITOR, BITXOR, BITNOT, which take two
  70.223 +    //      equal integer types and return that integer type.
  70.224 +    //
  70.225 +    Opcode op = TokenToOpcode(binary->token());
  70.226 +
  70.227 +    if (op >= OP_ADD && op <= OP_NE) {
  70.228 +        if (binary->type()->isFloat())
  70.229 +            op = Opcode(int(op) + int(OP_ADD_F - OP_ADD));
  70.230 +    } else {
  70.231 +        assert(binary->type()->isInt32());
  70.232 +    }
  70.233 +
  70.234 +    __ binary(op);
  70.235 +}
  70.236 +
  70.237 +void
  70.238 +HIRTranslator::visitConvert(HConvert *convert)
  70.239 +{
  70.240 +    convert->in()->accept(this);
  70.241 +    __ unary(convert->opcode());
  70.242 +}
  70.243 +
  70.244 +void
  70.245 +ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir)
  70.246 +{
  70.247 +    HIRTranslator translator(zone, emitter);
  70.248 +    translator.translate(hir);
  70.249 +}
    71.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    71.2 +++ b/src/compiler/HIR.h	Sat Nov 17 18:41:01 2012 -0800
    71.3 @@ -0,0 +1,331 @@
    71.4 +/*
    71.5 + * Copyright (C) 2012 David Anderson
    71.6 + *
    71.7 + * This file is part of SourcePawn.
    71.8 + *
    71.9 + * SourcePawn is free software: you can redistribute it and/or modify it under
   71.10 + * the terms of the GNU General Public License as published by the Free
   71.11 + * Software Foundation, either version 3 of the License, or (at your option)
   71.12 + * any later version.
   71.13 + * 
   71.14 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   71.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   71.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   71.17 + *
   71.18 + * You should have received a copy of the GNU General Public License along with
   71.19 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   71.20 + */
   71.21 +#ifndef _include_sp2_hir_h_
   71.22 +#define _include_sp2_hir_h_
   71.23 +
   71.24 +#include "../Types.h"
   71.25 +#include "../PoolAllocator.h"
   71.26 +#include "../Opcodes.h"
   71.27 +#include "Symbols.h"
   71.28 +
   71.29 +namespace ke {
   71.30 +
   71.31 +#define HIR_OPS(_)                      \
   71.32 +    _(Call)                             \
   71.33 +    _(Integer)                          \
   71.34 +    _(Float)                            \
   71.35 +    _(Store)                            \
   71.36 +    /* Special LValue types */          \
   71.37 +    _(Index)                            \
   71.38 +    _(Local)                            \
   71.39 +    _(Global)                           \
   71.40 +    /* End LValues */                   \
   71.41 +    _(Binary)                           \
   71.42 +    _(Convert)
   71.43 +
   71.44 +// Forward declarations.
   71.45 +#define _(name)    class H##name;
   71.46 +HIR_OPS(_)
   71.47 +#undef _
   71.48 +
   71.49 +class HIRVisitor;
   71.50 +
   71.51 +class HIR : public PoolObject
   71.52 +{
   71.53 +  public:
   71.54 +    enum HOp {
   71.55 +#define _(name) k##name,
   71.56 +        HIR_OPS(_)
   71.57 +#undef _
   71.58 +        kTotalOps
   71.59 +    };
   71.60 +
   71.61 +  public:
   71.62 +    HIR(Type *type)
   71.63 +      : type_(type)
   71.64 +    {
   71.65 +    }
   71.66 +
   71.67 +    Handle<Type> type() {
   71.68 +        return type_;
   71.69 +    }
   71.70 +
   71.71 +    virtual bool isLValue() const {
   71.72 +        return false;
   71.73 +    }
   71.74 +
   71.75 +    virtual HOp op() const = 0;
   71.76 +    virtual void accept(HIRVisitor *visitor) = 0;
   71.77 +
   71.78 +  private:
   71.79 +    ScopedRoot<Type> type_;
   71.80 +};
   71.81 +
   71.82 +class BytecodeEmitter;
   71.83 +
   71.84 +class HIRVisitor
   71.85 +{
   71.86 +  public:
   71.87 +#define _(name)                                 \
   71.88 +    virtual void visit##name(H##name *hir) {    \
   71.89 +        assert(false);                          \
   71.90 +    }
   71.91 +    HIR_OPS(_)
   71.92 +#undef _
   71.93 +};
   71.94 +
   71.95 +typedef PoolList<HIR *> HIRList;
   71.96 +
   71.97 +#define DEFINE_HIR(name)                        \
   71.98 +    virtual HOp op() const {                    \
   71.99 +        return k##name;                         \
  71.100 +    }                                           \
  71.101 +    virtual void accept(HIRVisitor *visitor) {  \
  71.102 +        visitor->visit##name(this);             \
  71.103 +    }
  71.104 +
  71.105 +class HInteger : public HIR
  71.106 +{
  71.107 +  public:
  71.108 +    HInteger(Type *type, int value)
  71.109 +      : HIR(type),
  71.110 +        value_(value)
  71.111 +    {
  71.112 +    }
  71.113 +
  71.114 +    DEFINE_HIR(Integer);
  71.115 +    int value() const {
  71.116 +        return value_;
  71.117 +    }
  71.118 +
  71.119 +  private:
  71.120 +    int value_;
  71.121 +};
  71.122 +
  71.123 +class HConvert : public HIR
  71.124 +{
  71.125 +  public:
  71.126 +    HConvert(Type *type, Opcode op, HIR *in)
  71.127 +      : HIR(type),
  71.128 +        op_(op),
  71.129 +        in_(in)
  71.130 +    {
  71.131 +    }
  71.132 +
  71.133 +    DEFINE_HIR(Convert);
  71.134 +    Opcode opcode() const {
  71.135 +        return op_;
  71.136 +    }
  71.137 +    HIR *in() const {
  71.138 +        return in_;
  71.139 +    }
  71.140 +
  71.141 +  private:
  71.142 +    Opcode op_;
  71.143 +    HIR *in_;
  71.144 +};
  71.145 +
  71.146 +class HLValue : public HIR
  71.147 +{
  71.148 +  public:
  71.149 +    HLValue(Type *type)
  71.150 +      : HIR(type)
  71.151 +    {
  71.152 +    }
  71.153 +
  71.154 +    // Pushes a reference to the LValue on the stack.
  71.155 +    virtual void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_) = 0;
  71.156 +
  71.157 +    // Given a stack layout of the form:
  71.158 +    //  [-1]    value
  71.159 +    //  [-2..n] ref
  71.160 +    //
  71.161 +    // Emits a store to the reference.
  71.162 +    virtual void store(BytecodeEmitter &emitter_) = 0;
  71.163 +    virtual void load(BytecodeEmitter &emitter_) = 0;
  71.164 +
  71.165 +    bool isLValue() const {
  71.166 +        return true;
  71.167 +    }
  71.168 +};
  71.169 +
  71.170 +class HLocal : public HLValue
  71.171 +{
  71.172 +  public:
  71.173 +    HLocal(VariableSymbol *sym)
  71.174 +      : HLValue(sym->type()),
  71.175 +        sym_(sym)
  71.176 +    {
  71.177 +    }
  71.178 +
  71.179 +    DEFINE_HIR(Local);
  71.180 +
  71.181 +    // Pushes a reference to the LValue on the stack.
  71.182 +    void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
  71.183 +    void store(BytecodeEmitter &emitter_);
  71.184 +    void load(BytecodeEmitter &emitter_);
  71.185 +
  71.186 +  private:
  71.187 +    VariableSymbol *sym_;
  71.188 +};
  71.189 +
  71.190 +class HIndex : public HLValue
  71.191 +{
  71.192 +  public:
  71.193 +    HIndex(Type *type, HIR *left, HIR *right)
  71.194 +      : HLValue(type),
  71.195 +        left_(left),
  71.196 +        right_(right)
  71.197 +    {
  71.198 +    }
  71.199 +
  71.200 +    DEFINE_HIR(Index);
  71.201 +
  71.202 +    void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
  71.203 +    void store(BytecodeEmitter &emitter_);
  71.204 +    void load(BytecodeEmitter &emitter_);
  71.205 +
  71.206 +  private:
  71.207 +    HIR *left_;
  71.208 +    HIR *right_;
  71.209 +};
  71.210 +
  71.211 +class HGlobal : public HLValue
  71.212 +{
  71.213 +  public:
  71.214 +    HGlobal(Symbol *sym)
  71.215 +      : HLValue(sym->type()),
  71.216 +        sym_(sym)
  71.217 +    {
  71.218 +    }
  71.219 +
  71.220 +    DEFINE_HIR(Global);
  71.221 +
  71.222 +    void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
  71.223 +    void store(BytecodeEmitter &emitter_);
  71.224 +    void load(BytecodeEmitter &emitter_);
  71.225 +
  71.226 +    Symbol *sym() const {
  71.227 +        return sym_;
  71.228 +    }
  71.229 +
  71.230 +  private:
  71.231 +    Symbol *sym_;
  71.232 +};
  71.233 +
  71.234 +class HBinary : public HIR
  71.235 +{
  71.236 +  public:
  71.237 +    HBinary(Type *type, TokenKind token, HIR *left, HIR *right)
  71.238 +      : HIR(type),
  71.239 +        token_(token),
  71.240 +        left_(left),
  71.241 +        right_(right)
  71.242 +    {
  71.243 +    }
  71.244 +
  71.245 +    DEFINE_HIR(Binary);
  71.246 +    TokenKind token() const {
  71.247 +        return token_;
  71.248 +    }
  71.249 +    HIR *left() const {
  71.250 +        return left_;
  71.251 +    }
  71.252 +    HIR *right() const {
  71.253 +        return right_;
  71.254 +    }
  71.255 +
  71.256 +  private:
  71.257 +    TokenKind token_;
  71.258 +    HIR *left_;
  71.259 +    HIR *right_;
  71.260 +};
  71.261 +
  71.262 +class HFloat : public HIR
  71.263 +{
  71.264 +  public:
  71.265 +    HFloat(Type *type, float value)
  71.266 +      : HIR(type),
  71.267 +        value_(value)
  71.268 +    {
  71.269 +    }
  71.270 +
  71.271 +    DEFINE_HIR(Float);
  71.272 +    float value() const {
  71.273 +        return value_;
  71.274 +    }
  71.275 +
  71.276 +  private:
  71.277 +    float value_;
  71.278 +};
  71.279 +
  71.280 +class HStore : public HIR
  71.281 +{
  71.282 +  public:
  71.283 +    HStore(HLValue *lval, HIR *rval)
  71.284 +      : HIR(lval->type()),
  71.285 +        lval_(lval),
  71.286 +        rval_(rval)
  71.287 +    {
  71.288 +    }
  71.289 +
  71.290 +    DEFINE_HIR(Store);
  71.291 +
  71.292 +    HLValue *lval() const {
  71.293 +        return lval_;
  71.294 +    }
  71.295 +    HIR *rval() const {
  71.296 +        return rval_;
  71.297 +    }
  71.298 +
  71.299 +  private:
  71.300 +    HLValue *lval_;
  71.301 +    HIR *rval_;
  71.302 +};
  71.303 +
  71.304 +class HCall : public HIR
  71.305 +{
  71.306 +  public:
  71.307 +    HCall(Type *type, HIR *callee, HIRList *args)
  71.308 +      : HIR(type),
  71.309 +        callee_(callee),
  71.310 +        args_(args)
  71.311 +    {
  71.312 +    }
  71.313 +
  71.314 +    DEFINE_HIR(Call);
  71.315 +
  71.316 +    HIR *callee() const {
  71.317 +        return callee_;
  71.318 +    }
  71.319 +    HIRList *args() const {
  71.320 +        return args_;
  71.321 +    }
  71.322 +
  71.323 +  private:
  71.324 +    HIR *callee_;
  71.325 +    HIRList *args_;
  71.326 +};
  71.327 +
  71.328 +#undef DEFINE_HIR
  71.329 +
  71.330 +void EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir);
  71.331 +
  71.332 +}
  71.333 +
  71.334 +#endif // _include_sp2_hir_h_
    72.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    72.2 +++ b/src/compiler/NameBinding.cpp	Sat Nov 17 18:41:01 2012 -0800
    72.3 @@ -0,0 +1,710 @@
    72.4 +/* vim: set ts=4 sw=4 tw=99 et:
    72.5 + *
    72.6 + * Copyright (C) 2012 David Anderson
    72.7 + *
    72.8 + * This file is part of SourcePawn.
    72.9 + *
   72.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   72.11 + * the terms of the GNU General Public License as published by the Free
   72.12 + * Software Foundation, either version 3 of the License, or (at your option)
   72.13 + * any later version.
   72.14 + * 
   72.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   72.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   72.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   72.18 + *
   72.19 + * You should have received a copy of the GNU General Public License along with
   72.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   72.21 + */
   72.22 +#include "../Strings.h"
   72.23 +#include "../Zone.h"
   72.24 +#include "../TypeManager.h"
   72.25 +#include "NameBinding.h"
   72.26 +#include "Scopes.h"
   72.27 +#include "../Spaces-inl.h"
   72.28 +#include "../Heap-inl.h"
   72.29 +
   72.30 +using namespace ke;
   72.31 +
   72.32 +// Create symbol tables and symbols for every scope and declaration. For type
   72.33 +// declarations and methods, we also pre-allocate a Type object, so that
   72.34 +// circular dependencies between types will work.
   72.35 +class NamePopulator : public AstVisitor
   72.36 +{
   72.37 +  private:
   72.38 +    // This class is analagous to a Scope, however, it allows us to create
   72.39 +    // scopes lazily. If a scope is requested, and the current environment
   72.40 +    // has no scope, then a scope is created. If no scope is ever requested,
   72.41 +    // a scope does not need to be created.
   72.42 +    class SymbolEnv
   72.43 +    {
   72.44 +      public:
   72.45 +        SymbolEnv(SymbolEnv **prevp, Scope *scope = NULL)
   72.46 +          : envp_(prevp),
   72.47 +            prev_(*prevp),
   72.48 +            scope_(scope)
   72.49 +        {
   72.50 +            *envp_ = this;
   72.51 +        }
   72.52 +        ~SymbolEnv() {
   72.53 +            *envp_ = prev_;
   72.54 +        }
   72.55 +
   72.56 +        Scope *scope() {
   72.57 +            return scope_;
   72.58 +        }
   72.59 +        void setScope(Scope *scope) {
   72.60 +            assert(!scope_);
   72.61 +            scope_ = scope;
   72.62 +        }
   72.63 +        SymbolEnv *prev() const {
   72.64 +            return prev_;
   72.65 +        }
   72.66 +
   72.67 +      private:
   72.68 +        SymbolEnv **envp_;
   72.69 +        SymbolEnv *prev_;
   72.70 +        Scope *scope_;
   72.71 +    };
   72.72 +
   72.73 +    enum ReturnStatus {
   72.74 +        NoReturn,
   72.75 +        VoidReturn,
   72.76 +        ValueReturn
   72.77 +    };
   72.78 +
   72.79 +    class FunctionScope
   72.80 +    {
   72.81 +      public:
   72.82 +        FunctionScope(FunctionScope **prevp)
   72.83 +          : prevp_(prevp),
   72.84 +            prev_(*prevp),
   72.85 +            status_(NoReturn)
   72.86 +        {
   72.87 +            *prevp_ = this;
   72.88 +        }
   72.89 +        ~FunctionScope() {
   72.90 +            *prevp_ = prev_;
   72.91 +        }
   72.92 +        ReturnStatus returns() const {
   72.93 +            return status_;
   72.94 +        }
   72.95 +        void returns(ReturnStatus status) {
   72.96 +            if (status > status_)
   72.97 +                status_ = status;
   72.98 +        }
   72.99 +      private:
  72.100 +        FunctionScope **prevp_;
  72.101 +        FunctionScope *prev_;
  72.102 +        ReturnStatus status_;
  72.103 +    };
  72.104 +
  72.105 +  public:
  72.106 +    NamePopulator(Zone *zone, CompileContext &cc, TranslationUnit *unit)
  72.107 +      : zone_(zone),
  72.108 +        pool_(zone->pool()),
  72.109 +        cc_(cc),
  72.110 +        unit_(unit),
  72.111 +        env_(NULL),
  72.112 +        fun_(NULL)
  72.113 +    {
  72.114 +    }
  72.115 +
  72.116 +    bool analyze() {
  72.117 +        ImportScope *importScope = ImportScope::New(pool_);
  72.118 +        if (!importScope)
  72.119 +            return false;
  72.120 +
  72.121 +        // At the import level, we declare system types.
  72.122 +        if (!declareSystemTypes(importScope))
  72.123 +            return false;
  72.124 +
  72.125 +        GlobalScope *globalScope = GlobalScope::New(pool_, importScope);
  72.126 +        if (!globalScope)
  72.127 +            return false;
  72.128 +
  72.129 +        unit_->setImportScope(importScope);
  72.130 +        unit_->setGlobalScope(globalScope);
  72.131 +
  72.132 +        SymbolEnv env(&env_, globalScope);
  72.133 +
  72.134 +        for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
  72.135 +            Statement *stmt = unit_->tree()->statements()->at(i);
  72.136 +            stmt->accept(this);
  72.137 +        }
  72.138 +
  72.139 +        return true;
  72.140 +    }
  72.141 +
  72.142 +    bool declareSystemType(ImportScope *scope, const char *name, Handle<Type> type) {
  72.143 +        Local<String> tag(zone_, zone_->makeSymbol(name));
  72.144 +        if (!tag)
  72.145 +            return false;
  72.146 +
  72.147 +        TypeSymbol *sym = new (pool_) TypeSymbol(scope, tag, type);
  72.148 +        return scope->addSymbol(sym);
  72.149 +    }
  72.150 +
  72.151 +    bool declareSystemType(ImportScope *scope, const char *name, PrimitiveType prim) {
  72.152 +        Local<Type> primitive(zone_, zone_->types()->getPrimitive(prim));
  72.153 +        assert(primitive);
  72.154 +        return declareSystemType(scope, name, primitive);
  72.155 +    }
  72.156 +
  72.157 +    bool declareSystemTypes(ImportScope *scope) {
  72.158 +        if (!declareSystemType(scope, "float", PrimitiveType_Float))
  72.159 +            return false;
  72.160 +        if (!declareSystemType(scope, "_", PrimitiveType_Int32))
  72.161 +            return false;
  72.162 +        if (!declareSystemType(scope, "int", PrimitiveType_Int32))
  72.163 +            return false;
  72.164 +        if (!declareSystemType(scope, "bool", PrimitiveType_Bool))
  72.165 +            return false;
  72.166 +        if (!declareSystemType(scope, "char", PrimitiveType_Char))
  72.167 +            return false;
  72.168 +
  72.169 +        Local<Type> voidType(zone_, zone_->types()->getVoid());
  72.170 +        if (!declareSystemType(scope, "void", voidType))
  72.171 +            return false;
  72.172 +
  72.173 +        return true;
  72.174 +    }
  72.175 +
  72.176 +    void visitVariableDeclaration(VariableDeclaration *node) {
  72.177 +        Scope *scope = env_->scope();
  72.178 +        if (!scope || scope->kind() != Scope::GLOBAL) {
  72.179 +            if ((scope = getOrCreateBlockScope()) == NULL)
  72.180 +                return;
  72.181 +        }
  72.182 +
  72.183 +        if (scope->kind() == Scope::GLOBAL) {
  72.184 +            // The symbol must be added now, since it could be an export.
  72.185 +            VariableSymbol *sym = new (pool_) VariableSymbol(scope, node->name(), node->pos());
  72.186 +            node->setSymbol(sym);
  72.187 +
  72.188 +            if (!registerName(scope, sym))
  72.189 +                return;
  72.190 +        } else {
  72.191 +            // We ensure the scope will exist at the name binding phase, but
  72.192 +            // we don't actually register the variable symbol yet. Otherwise,
  72.193 +            // when binding the initializer, we could encounter:
  72.194 +            //    new x = x;
  72.195 +            //
  72.196 +            // And we don't necessarily want this to bind.
  72.197 +        }
  72.198 +
  72.199 +        node->initialization()->accept(this);
  72.200 +    }
  72.201 +    void visitEnumStatement(EnumStatement *node) {
  72.202 +        assert(false);
  72.203 +    }
  72.204 +    void visitFunctionStatement(FunctionStatement *node) {
  72.205 +        // We create function types ahead of time, not for any particular
  72.206 +        // reason. It makes things consistent with FunctionTypeStatement,
  72.207 +        // which actually does produce a type.
  72.208 +        Local<FunctionType> type(zone_, FunctionType::New(zone_, node->token()));
  72.209 +        if (!type)
  72.210 +            return;
  72.211 +
  72.212 +        assert(env_->scope());
  72.213 +
  72.214 +        // Function statements are always named, so add the name to the outer scope.
  72.215 +        FunctionSymbol *sym = new (pool_) FunctionSymbol(env_->scope(), node->name(), node->pos(), type);
  72.216 +        if (!registerName(env_->scope(), sym))
  72.217 +            return;
  72.218 +
  72.219 +        if (node->token() == TOK_PUBLIC ||
  72.220 +            node->token() == TOK_FORWARD ||
  72.221 +            node->token() == TOK_NATIVE)
  72.222 +        {
  72.223 +            // We're in the global scope, for sure.
  72.224 +            assert(env_->scope()->kind() == Scope::GLOBAL);
  72.225 +            GlobalScope *globals = (GlobalScope *)env_->scope();
  72.226 +            if (!globals->addPublic(sym))
  72.227 +                return;
  72.228 +        }
  72.229 +
  72.230 +        node->setSymbol(sym);
  72.231 +
  72.232 +        // Scope for the function's arguments.
  72.233 +        SymbolEnv argEnv(&env_);
  72.234 +        if (!registerArguments(node->signature()))
  72.235 +            return;
  72.236 +
  72.237 +        // Scope for function body.
  72.238 +        SymbolEnv localEnv(&env_);
  72.239 +        FunctionScope fun(&fun_);
  72.240 +        if (node->body())
  72.241 +            node->body()->accept(this);
  72.242 +
  72.243 +        // Function statements have quirky semantics around their return
  72.244 +        // type. For reasonable compatibility with SP1, we use the following
  72.245 +        // heuristics for when no explicit type is declared.
  72.246 +        if (!node->signature().returnType()) {
  72.247 +            Local<Type> type(zone_);
  72.248 +            if (node->token() == TOK_FORWARD || node->token() == TOK_NATIVE) {
  72.249 +                // If the function type is a native or forward, we always
  72.250 +                // assume it returns an int32.
  72.251 +                type = zone_->types()->getPrimitive(PrimitiveType_Int32);
  72.252 +            } else if (fun.returns() != ValueReturn) {
  72.253 +                // This function never returns a value, so mark it as
  72.254 +                // returning void.
  72.255 +                type = zone_->types()->getVoid();
  72.256 +            }
  72.257 +            // No need to NULL check here, we'll catch OOM later.
  72.258 +            node->sym()->type()->setReturnType(type);
  72.259 +        }
  72.260 +
  72.261 +        node->setScopes(argEnv.scope(), localEnv.scope());
  72.262 +    }
  72.263 +    void visitStructureStatement(StructureStatement *node) {
  72.264 +        assert(false);
  72.265 +    }
  72.266 +    void visiFunctionTypeStatementt(FunctionTypeStatement *node) {
  72.267 +        assert(false);
  72.268 +    }
  72.269 +
  72.270 +    void visitNameProxy(NameProxy *name) {
  72.271 +    }
  72.272 +    void visitAssignment(Assignment *node) {
  72.273 +        node->lvalue()->accept(this);
  72.274 +        node->expression()->accept(this);
  72.275 +    }
  72.276 +    void visitBinaryExpression(BinaryExpression *node) {
  72.277 +        node->left()->accept(this);
  72.278 +        node->right()->accept(this);
  72.279 +    }
  72.280 +    void visitReturnStatement(ReturnStatement *node) {
  72.281 +        if (node->expression())
  72.282 +            fun_->returns(ValueReturn);
  72.283 +        else
  72.284 +            fun_->returns(VoidReturn);
  72.285 +    }
  72.286 +    void visitForStatement(ForStatement *node) {
  72.287 +        SymbolEnv env(&env_);
  72.288 +
  72.289 +        if (node->initialization())
  72.290 +            node->initialization()->accept(this);
  72.291 +        if (node->condition())
  72.292 +            node->condition()->accept(this);
  72.293 +        if (node->update())
  72.294 +            node->update()->accept(this);
  72.295 +        node->body()->accept(this);
  72.296 +
  72.297 +        node->setScope(env.scope());
  72.298 +    }
  72.299 +    void visitBlockStatement(BlockStatement *node) {
  72.300 +        SymbolEnv env(&env_);
  72.301 +
  72.302 +        for (size_t i = 0; i < node->statements()->length(); i++)
  72.303 +            node->statements()->at(i)->accept(this);
  72.304 +
  72.305 +        node->setScope(env.scope());
  72.306 +    }
  72.307 +    void visitIntegerLiteral(IntegerLiteral *node) {
  72.308 +    }
  72.309 +    void visitExpressionStatement(ExpressionStatement *node) {
  72.310 +        node->expression()->accept(this);
  72.311 +    }
  72.312 +    void visitCallExpression(CallExpression *node) {
  72.313 +        node->callee()->accept(this);
  72.314 +        for (size_t i = 0; i < node->arguments()->length(); i++)
  72.315 +            node->arguments()->at(i)->accept(this);
  72.316 +    }
  72.317 +    void visitIfStatement(IfStatement *node) {
  72.318 +        node->ifTrue()->accept(this);
  72.319 +        if (node->ifFalse())
  72.320 +            node->ifFalse()->accept(this);
  72.321 +    }
  72.322 +    void visitIndexExpression(IndexExpression *node) {
  72.323 +        assert(false);
  72.324 +    }
  72.325 +    void visitFloatLiteral(FloatLiteral *node) {
  72.326 +    }
  72.327 +    void visitWhileStatement(WhileStatement *node) {
  72.328 +        node->condition()->accept(this);
  72.329 +        node->body()->accept(this);
  72.330 +    }
  72.331 +    void visitBreakStatement(BreakStatement *node) {
  72.332 +    }
  72.333 +    void visitContinueStatement(ContinueStatement *node) {
  72.334 +    }
  72.335 +    void visitStringLiteral(StringLiteral *node) {
  72.336 +    }
  72.337 +    void visitIncDecExpression(IncDecExpression *node) {
  72.338 +        assert(false);
  72.339 +    }
  72.340 +    void visitUnaryExpression(UnaryExpression *node) {
  72.341 +        assert(false);
  72.342 +    }
  72.343 +    void visitTernaryExpression(TernaryExpression *node) {
  72.344 +        assert(false);
  72.345 +    }
  72.346 +    void visitBooleanLiteral(BooleanLiteral *node) {
  72.347 +    }
  72.348 +    void visitFieldExpression(FieldExpression *node) {
  72.349 +    }
  72.350 +    void visitSwitchStatement(SwitchStatement *node) {
  72.351 +        if (node->defaultCase())
  72.352 +            node->defaultCase()->accept(this);
  72.353 +
  72.354 +        for (size_t i = 0; i < node->cases()->length(); i++)
  72.355 +            node->cases()->at(i)->statement()->accept(this);
  72.356 +    }
  72.357 +    void visitArrayLiteral(ArrayLiteral *node) {
  72.358 +    }
  72.359 +    void visitImportStatement(ImportStatement *node) {
  72.360 +    }
  72.361 +
  72.362 +  private:
  72.363 +    Scope *getOrCreateBlockScope() {
  72.364 +        if (env_->scope()) {
  72.365 +            assert(env_->scope()->kind() == Scope::BLOCK);
  72.366 +            return env_->scope();
  72.367 +        }
  72.368 +        
  72.369 +        LocalScope *scope = LocalScope::New(pool_);
  72.370 +        if (!scope)
  72.371 +            return NULL;
  72.372 +
  72.373 +        env_->setScope(scope);
  72.374 +        return scope;
  72.375 +    }
  72.376 +
  72.377 +    bool registerName(Scope *scope, Symbol *sym) {
  72.378 +        if (!scope)
  72.379 +            return false;
  72.380 +
  72.381 +        if (Symbol *other = scope->localLookup(sym->name())) {
  72.382 +            // Report, but allow errors to continue.
  72.383 +            cc_.reportError(sym->pos(), Message_RedeclaredName,
  72.384 +                            sym->name()->chars(),
  72.385 +                            other->pos().line,
  72.386 +                            other->pos().col);
  72.387 +            return true;
  72.388 +        }
  72.389 +
  72.390 +        return scope->addSymbol(sym);
  72.391 +    }
  72.392 +
  72.393 +    bool registerArguments(const FunctionSignature &sig) {
  72.394 +        if (!sig.parameters()->length())
  72.395 +            return true;
  72.396 +
  72.397 +        ArgumentScope *argScope = ArgumentScope::New(pool_);
  72.398 +        if (!argScope)
  72.399 +            return false;
  72.400 +        env_->setScope(argScope);
  72.401 +
  72.402 +        for (size_t i = 0; i < sig.parameters()->length(); i++) {
  72.403 +            Parameter *param = sig.parameters()->at(i);
  72.404 +            VariableSymbol *sym = new (pool_) VariableSymbol(argScope, param->name(), param->pos());
  72.405 +            if (!registerName(env_->scope(), sym))
  72.406 +                return false;
  72.407 +            param->setSymbol(sym);
  72.408 +        }
  72.409 +
  72.410 +        return true;
  72.411 +    }
  72.412 +
  72.413 +  private:
  72.414 +    Zone *zone_;
  72.415 +    PoolAllocator &pool_;
  72.416 +    CompileContext &cc_;
  72.417 +    TranslationUnit *unit_;
  72.418 +    SymbolEnv *env_;
  72.419 +    FunctionScope *fun_;
  72.420 +};
  72.421 +
  72.422 +bool
  72.423 +ke::PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
  72.424 +{
  72.425 +    NamePopulator populator(zone, cc, unit);
  72.426 +    return populator.analyze();
  72.427 +}
  72.428 +
  72.429 +class NameBinder : public AstVisitor
  72.430 +{
  72.431 +  public:
  72.432 +    class AutoLinkScope
  72.433 +    {
  72.434 +      public:
  72.435 +        AutoLinkScope(AutoLinkScope **prevp, Scope *scope)
  72.436 +          : prevp_(prevp),
  72.437 +            prev_(*prevp),
  72.438 +            scope_(scope)
  72.439 +        {
  72.440 +            if (scope_) {
  72.441 +                *prevp_ = this;
  72.442 +                if (prev_)
  72.443 +                    scope_->setParent(prev_->scope());
  72.444 +            }
  72.445 +        }
  72.446 +        ~AutoLinkScope() {
  72.447 +            if (scope_) {
  72.448 +                assert(*prevp_ == this);
  72.449 +                *prevp_ = prev_;
  72.450 +            }
  72.451 +        }
  72.452 +        Scope *scope() const {
  72.453 +            return scope_;
  72.454 +        }
  72.455 +
  72.456 +      private:
  72.457 +        AutoLinkScope **prevp_;
  72.458 +        AutoLinkScope *prev_;
  72.459 +        Scope *scope_;
  72.460 +    };
  72.461 +
  72.462 +  public:
  72.463 +    NameBinder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
  72.464 +      : zone_(zone),
  72.465 +        pool_(zone->pool()),
  72.466 +        cc_(cc),
  72.467 +        unit_(unit),
  72.468 +        link_(NULL)
  72.469 +    {
  72.470 +    }
  72.471 +
  72.472 +    bool bind() {
  72.473 +        // Start with the import scope, and collect all imported names.
  72.474 +        AutoLinkScope importScope(&link_, unit_->importScope());
  72.475 +
  72.476 +        for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
  72.477 +            unit_->tree()->imports()->at(i)->accept(this);
  72.478 +
  72.479 +        // Next, enter the global scope and walk all statements.
  72.480 +        AutoLinkScope globalScope(&link_, unit_->globalScope());
  72.481 +        for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
  72.482 +            Statement *stmt = unit_->tree()->statements()->at(i);
  72.483 +            stmt->accept(this);
  72.484 +        }
  72.485 +
  72.486 +        return true;
  72.487 +    }
  72.488 +
  72.489 +    void visitVariableDeclaration(VariableDeclaration *node) {
  72.490 +        // Bind the initializer before registering the declaration, so that we
  72.491 +        // can error on bogus initializers (new x = x).
  72.492 +        node->initialization()->accept(this);
  72.493 +
  72.494 +        Local<Type> type(zone_, bindType(node->type()));
  72.495 +        if (!type)
  72.496 +            return;
  72.497 +
  72.498 +        // If the node already has a symbol (meaning it was a global), then
  72.499 +        // we don't have to do anything more.
  72.500 +        if (node->sym()) {
  72.501 +            assert(node->sym()->scope()->kind() == Scope::GLOBAL);
  72.502 +            return;
  72.503 +        }
  72.504 +
  72.505 +        VariableSymbol *sym = new (pool_) VariableSymbol(link_->scope(), node->name(), node->pos(), type);
  72.506 +        node->setSymbol(sym);
  72.507 +       
  72.508 +        if (Symbol *other = link_->scope()->localLookup(sym->name())) {
  72.509 +            // Report, but allow errors to continue.
  72.510 +            cc_.reportError(sym->pos(), Message_RedeclaredName,
  72.511 +                            sym->name()->chars(),
  72.512 +                            other->pos().line,
  72.513 +                            other->pos().col);
  72.514 +            return;
  72.515 +        }
  72.516 +        
  72.517 +        if (link_->scope()->addSymbol(sym))
  72.518 +            return;
  72.519 +    }
  72.520 +    void visitEnumStatement(EnumStatement *node) {
  72.521 +        assert(false);
  72.522 +    }
  72.523 +    void visitFunctionStatement(FunctionStatement *node) {
  72.524 +        AutoLinkScope argScope(&link_, node->argScope());
  72.525 +        AutoLinkScope varScope(&link_, node->varScope());
  72.526 +
  72.527 +        Local<FunctionType> type(zone_, node->sym()->type());
  72.528 +        if (!fillFunctionType(type, node->signature()))
  72.529 +            return;
  72.530 +
  72.531 +        if (node->body())
  72.532 +            node->body()->accept(this);
  72.533 +    }
  72.534 +    void visitStructureStatement(StructureStatement *node) {
  72.535 +        assert(false);
  72.536 +    }
  72.537 +    void visitFunctionTypeStatement(FunctionTypeStatement *node) {
  72.538 +        assert(false);
  72.539 +    }
  72.540 +
  72.541 +    void visitNameProxy(NameProxy *proxy) {
  72.542 +        Scope *scope = link_->scope();
  72.543 +        Symbol *sym = scope->lookup(proxy->name());
  72.544 +        if (!sym)
  72.545 +            cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
  72.546 +        proxy->bind(sym);
  72.547 +    }
  72.548 +    void visitAssignment(Assignment *node) {
  72.549 +        node->lvalue()->accept(this);
  72.550 +        node->expression()->accept(this);
  72.551 +    }
  72.552 +    void visitBinaryExpression(BinaryExpression *node) {
  72.553 +        node->left()->accept(this);
  72.554 +        node->right()->accept(this);
  72.555 +    }
  72.556 +    void visitReturnStatement(ReturnStatement *node) {
  72.557 +        node->expression()->accept(this);
  72.558 +    }
  72.559 +    void visitForStatement(ForStatement *node) {
  72.560 +        AutoLinkScope scope(&link_, node->scope());
  72.561 +
  72.562 +        if (node->initialization())
  72.563 +            node->initialization()->accept(this);
  72.564 +        if (node->condition())
  72.565 +            node->condition()->accept(this);
  72.566 +        if (node->update())
  72.567 +            node->update()->accept(this);
  72.568 +        node->body()->accept(this);
  72.569 +    }
  72.570 +    void visitBlockStatement(BlockStatement *node) {
  72.571 +        AutoLinkScope scope(&link_, node->scope());
  72.572 +        for (size_t i = 0; i < node->statements()->length(); i++)
  72.573 +            node->statements()->at(i)->accept(this);
  72.574 +    }
  72.575 +    void visitIntegerLiteral(IntegerLiteral *node) {
  72.576 +    }
  72.577 +    void visitExpressionStatement(ExpressionStatement *node) {
  72.578 +        node->expression()->accept(this);
  72.579 +    }
  72.580 +    void visitCallExpression(CallExpression *node) {
  72.581 +        node->callee()->accept(this);
  72.582 +        for (size_t i = 0; i < node->arguments()->length(); i++)
  72.583 +            node->arguments()->at(i)->accept(this);
  72.584 +    }
  72.585 +    void visitIfStatement(IfStatement *node) {
  72.586 +        node->condition()->accept(this);
  72.587 +        node->ifTrue()->accept(this);
  72.588 +        node->ifFalse()->accept(this);
  72.589 +    }
  72.590 +    void visitIndexExpression(IndexExpression *node) {
  72.591 +        node->left()->accept(this);
  72.592 +        node->right()->accept(this);
  72.593 +    }
  72.594 +    void visitFloatLiteral(FloatLiteral *node) {
  72.595 +    }
  72.596 +    void visitWhileStatement(WhileStatement *node) {
  72.597 +        node->condition()->accept(this);
  72.598 +        node->body()->accept(this);
  72.599 +    }
  72.600 +    void visitBreakStatement(BreakStatement *node) {
  72.601 +    }
  72.602 +    void visitContinueStatement(ContinueStatement *node) {
  72.603 +    }
  72.604 +    void visitStringLiteral(StringLiteral *node) {
  72.605 +    }
  72.606 +    void visitIncDecExpression(IncDecExpression *node) {
  72.607 +        node->expression()->accept(this);
  72.608 +    }
  72.609 +    void visitUnaryExpression(UnaryExpression *node) {
  72.610 +        if (node->tag())
  72.611 +            node->tag()->accept(this);
  72.612 +        node->expression()->accept(this);
  72.613 +    }
  72.614 +    void visitTernaryExpression(TernaryExpression *node) {
  72.615 +        node->condition()->accept(this);
  72.616 +        node->left()->accept(this);
  72.617 +        node->right()->accept(this);
  72.618 +    }
  72.619 +    void visitBooleanLiteral(BooleanLiteral *node) {
  72.620 +    }
  72.621 +    void visitFieldExpression(FieldExpression *node) {
  72.622 +        node->left()->accept(this);
  72.623 +    }
  72.624 +    void visitSwitchStatement(SwitchStatement *node) {
  72.625 +        node->expression()->accept(this);
  72.626 +        node->defaultCase()->accept(this);
  72.627 +        for (size_t i = 0; i < node->cases()->length(); i++) {
  72.628 +            // We don't test case expressions because they are literals.
  72.629 +            Case *c = node->cases()->at(i);
  72.630 +            c->statement()->accept(this);
  72.631 +        }
  72.632 +    }
  72.633 +    void visitArrayLiteral(ArrayLiteral *node) {
  72.634 +        for (size_t i = 0; i < node->expressions()->length(); i++)
  72.635 +            node->expressions()->at(i)->accept(this);
  72.636 +    }
  72.637 +    void visitImportStatement(ImportStatement *node) {
  72.638 +        if (node->suffix() == TOK_STAR) {
  72.639 +            // Import every name.
  72.640 +            assert(false);
  72.641 +        } else {
  72.642 +            GlobalScope *other = node->source()->globalScope();
  72.643 +            Symbol *sym = other->findPublic(node->name());
  72.644 +            if (!sym) {
  72.645 +                cc_.reportError(node->pos(), Message_CannotResolveImport, node->name()->chars());
  72.646 +                return;
  72.647 +            }
  72.648 +            link_->scope()->addSymbol(sym);
  72.649 +        }
  72.650 +    }
  72.651 +
  72.652 +  private:
  72.653 +    bool fillFunctionType(Handle<FunctionType> fun, const FunctionSignature &sig) {
  72.654 +        Local<Type> type(zone_);
  72.655 +        if (!fun->returnType()) {
  72.656 +            if ((type = bindType(sig.returnType())) == NULL)
  72.657 +                return false;
  72.658 +            fun->setReturnType(type);
  72.659 +        }
  72.660 +
  72.661 +        Local<FixedArray> params(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
  72.662 +        if (!params)
  72.663 +            return false;
  72.664 +
  72.665 +        for (size_t i = 0; i < sig.parameters()->length(); i++) {
  72.666 +            Parameter *param = sig.parameters()->at(i);
  72.667 +            if ((type = bindType(param->type())) == NULL)
  72.668 +                return false;
  72.669 +            params->set(zone_, i, type);
  72.670 +        }
  72.671 +
  72.672 +        fun->setParameterTypes(params);
  72.673 +
  72.674 +        return true;
  72.675 +    }
  72.676 +
  72.677 +    Type *bindType(Expression *expr) {
  72.678 +        if (!expr) {
  72.679 +            // If no type was declared, we return int32.
  72.680 +            return zone_->types()->getPrimitive(PrimitiveType_Int32);
  72.681 +        }
  72.682 +        
  72.683 +        expr->accept(this);
  72.684 +
  72.685 +        NameProxy *proxy = expr->asNameProxy();
  72.686 +        assert(proxy);
  72.687 +
  72.688 +        Symbol *sym = proxy->sym();
  72.689 +        if (!sym)
  72.690 +            return NULL;
  72.691 +
  72.692 +        if (!sym->isType()) {
  72.693 +            cc_.reportError(expr->pos(), Message_IdentifierIsNotAType, sym->name()->chars());
  72.694 +            return NULL;
  72.695 +        }
  72.696 +
  72.697 +        return sym->type();
  72.698 +    }
  72.699 +
  72.700 +  private:
  72.701 +    Zone *zone_;
  72.702 +    PoolAllocator &pool_;
  72.703 +    CompileContext &cc_;
  72.704 +    TranslationUnit *unit_;
  72.705 +    AutoLinkScope *link_;
  72.706 +};
  72.707 +
  72.708 +bool
  72.709 +ke::BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
  72.710 +{
  72.711 +    NameBinder binder(zone, cc, unit);
  72.712 +    return binder.bind();
  72.713 +}
    73.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    73.2 +++ b/src/compiler/NameBinding.h	Sat Nov 17 18:41:01 2012 -0800
    73.3 @@ -0,0 +1,40 @@
    73.4 +/* vim: set ts=4 sw=4 tw=99 et:
    73.5 + *
    73.6 + * Copyright (C) 2012 David Anderson
    73.7 + *
    73.8 + * This file is part of SourcePawn.
    73.9 + *
   73.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   73.11 + * the terms of the GNU General Public License as published by the Free
   73.12 + * Software Foundation, either version 3 of the License, or (at your option)
   73.13 + * any later version.
   73.14 + * 
   73.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   73.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   73.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   73.18 + *
   73.19 + * You should have received a copy of the GNU General Public License along with
   73.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   73.21 + */
   73.22 +#ifndef _include_name_binding_h_
   73.23 +#define _include_name_binding_h_
   73.24 +
   73.25 +#include "../PoolAllocator.h"
   73.26 +#include "../Types.h"
   73.27 +#include "Scanner.h"
   73.28 +
   73.29 +namespace ke {
   73.30 +
   73.31 +class Zone;
   73.32 +class CompileContext;
   73.33 +struct TranslationUnit;
   73.34 +
   73.35 +// Creates symbols and types for names that are global or can be derived from a global.
   73.36 +bool PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
   73.37 +
   73.38 +// Bind all outstanding names and finalize all unfinished types.
   73.39 +bool BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
   73.40 +
   73.41 +}
   73.42 +
   73.43 +#endif // _include_name_binding_h_
    74.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    74.2 +++ b/src/compiler/Parser.cpp	Sat Nov 17 18:41:01 2012 -0800
    74.3 @@ -0,0 +1,1737 @@
    74.4 +/* vim: set ts=4 sw=4 tw=99 et:
    74.5 + *
    74.6 + * Copyright (C) 2012 David Anderson
    74.7 + *
    74.8 + * This file is part of SourcePawn.
    74.9 + *
   74.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   74.11 + * the terms of the GNU General Public License as published by the Free
   74.12 + * Software Foundation, either version 3 of the License, or (at your option)
   74.13 + * any later version.
   74.14 + * 
   74.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   74.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   74.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   74.18 + *
   74.19 + * You should have received a copy of the GNU General Public License along with
   74.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   74.21 + */
   74.22 +#include <string.h>
   74.23 +#include "../Zone.h"
   74.24 +#include "../FixedArray.h"
   74.25 +#include "../Heap.h"
   74.26 +#include "../Strings.h"
   74.27 +#include "../TypeManager.h"
   74.28 +#include "Parser.h"
   74.29 +#include "../Heap-inl.h"
   74.30 +
   74.31 +using namespace ke;
   74.32 +
   74.33 +Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length)
   74.34 +  : zone_(zone),
   74.35 +    cc_(cc),
   74.36 +    pool_(zone_->pool()),
   74.37 +    scanner_(cc, stream, length),
   74.38 +    unbound_(NULL)
   74.39 +{
   74.40 +    unbound_ = new (pool_) PoolList<NameProxy *>();
   74.41 +    imports_ = new (pool_) PoolList<ImportStatement *>();
   74.42 +}
   74.43 +
   74.44 +bool
   74.45 +Parser::peek(TokenKind kind)
   74.46 +{
   74.47 +    return scanner_.peek() == kind;
   74.48 +}
   74.49 +
   74.50 +bool
   74.51 +Parser::match(TokenKind kind)
   74.52 +{
   74.53 +    if (!peek(kind))
   74.54 +        return false;
   74.55 +    scanner_.scan();
   74.56 +    return true;
   74.57 +}
   74.58 +
   74.59 +bool
   74.60 +Parser::matchSemicolon()
   74.61 +{
   74.62 +    return expect(TOK_SEMICOLON);
   74.63 +}
   74.64 +
   74.65 +bool
   74.66 +Parser::expect(TokenKind kind)
   74.67 +{
   74.68 +    TokenKind got = scanner_.scan();
   74.69 +    if (got == kind)
   74.70 +        return true;
   74.71 +    cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]);
   74.72 +    return false;
   74.73 +}
   74.74 +
   74.75 +bool
   74.76 +Parser::matchName(String **name, TokenKind kind)
   74.77 +{
   74.78 +    assert(kind == TOK_NAME || kind == TOK_LABEL);
   74.79 +    *name = NULL;
   74.80 +    if (!match(kind))
   74.81 +        return false;
   74.82 +    *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
   74.83 +    return true;
   74.84 +}
   74.85 +
   74.86 +String *
   74.87 +Parser::expectName()
   74.88 +{
   74.89 +    if (!expect(TOK_NAME))
   74.90 +        return NULL;
   74.91 +    return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
   74.92 +}
   74.93 +
   74.94 +Expression *
   74.95 +Parser::primitive()
   74.96 +{
   74.97 +    TokenKind kind = scanner_.peek();
   74.98 +    switch (kind) {
   74.99 +      case TOK_FLOAT_LITERAL:
  74.100 +      {
  74.101 +        scanner_.scan();
  74.102 +        double value = Scanner::ParseDouble(scanner_.literal());
  74.103 +        return new (pool_) FloatLiteral(scanner_.begin(), value);
  74.104 +      }
  74.105 +
  74.106 +      case TOK_HEX_LITERAL:
  74.107 +      {
  74.108 +        scanner_.scan();
  74.109 +        int value = strtol(scanner_.literal(), NULL, 16);
  74.110 +        return new (pool_) IntegerLiteral(scanner_.begin(), value);
  74.111 +      }
  74.112 +
  74.113 +      case TOK_INTEGER_LITERAL:
  74.114 +      {
  74.115 +        scanner_.scan();
  74.116 +        int value = atoi(scanner_.literal());
  74.117 +        return new (pool_) IntegerLiteral(scanner_.begin(), value);
  74.118 +      }
  74.119 +
  74.120 +      case TOK_TRUE:
  74.121 +      case TOK_FALSE:
  74.122 +        scanner_.scan();
  74.123 +        return new (pool_) BooleanLiteral(scanner_.begin(), kind);
  74.124 +
  74.125 +      case TOK_STRING_LITERAL:
  74.126 +      {
  74.127 +        scanner_.scan();
  74.128 +        Local<ByteArray> array(zone_, ByteArray::New(zone_, scanner_.literal_length() + 1));
  74.129 +        if (!array)
  74.130 +            return NULL;
  74.131 +        memcpy(array->raw(), scanner_.literal(), scanner_.literal_length() + 1);
  74.132 +        return new (pool_) StringLiteral(scanner_.begin(), array);
  74.133 +      }
  74.134 +
  74.135 +      default:
  74.136 +      {
  74.137 +        if (kind != TOK_ERROR)
  74.138 +            cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]);
  74.139 +        return NULL;
  74.140 +      }
  74.141 +    }
  74.142 +}
  74.143 +
  74.144 +Expression *
  74.145 +Parser::arrayLiteral(TokenKind kind)
  74.146 +{
  74.147 +    assert(kind == TOK_LBRACE || kind == TOK_LBRACKET);
  74.148 +
  74.149 +    TokenKind close = (kind == TOK_LBRACE)
  74.150 +                      ? TOK_RBRACE
  74.151 +                      : TOK_RBRACKET;
  74.152 +
  74.153 +    SourcePosition pos = scanner_.begin();
  74.154 +
  74.155 +    ExpressionList *list = new (pool_) ExpressionList();
  74.156 +    do {
  74.157 +        if (match(close))
  74.158 +            break;
  74.159 +
  74.160 +        Expression *expr = NULL;
  74.161 +        if (kind == TOK_LBRACE) {
  74.162 +            if (peek(TOK_LBRACE))
  74.163 +                expr = arrayLiteral(TOK_LBRACE);
  74.164 +            else
  74.165 +                expr = primitive();
  74.166 +        } else {
  74.167 +            expr = expression();
  74.168 +        }
  74.169 +        if (!expr)
  74.170 +            return NULL;
  74.171 +
  74.172 +        if (!list->append(expr))
  74.173 +            return NULL;
  74.174 +
  74.175 +        if (!match(TOK_COMMA)) {
  74.176 +            if (!expect(close))
  74.177 +                return NULL;
  74.178 +            break;
  74.179 +        }
  74.180 +    } while (true);
  74.181 +
  74.182 +    return new (pool_) ArrayLiteral(pos, kind, list);
  74.183 +}
  74.184 +
  74.185 +Expression *
  74.186 +Parser::prefix()
  74.187 +{
  74.188 +    switch (scanner_.peek()) {
  74.189 +      case TOK_LPAREN:
  74.190 +      {
  74.191 +        scanner_.scan();
  74.192 +        Expression *expr = expression();
  74.193 +        if (!expr)
  74.194 +            return NULL;
  74.195 +        if (!expect(TOK_RPAREN))
  74.196 +            return NULL;
  74.197 +        return expr;
  74.198 +      }
  74.199 +
  74.200 +      case TOK_NAME:
  74.201 +      {
  74.202 +        Local<String> name(zone_, expectName());
  74.203 +        if (!name)
  74.204 +            return NULL;
  74.205 +        return new (pool_) NameProxy(scanner_.begin(), name);
  74.206 +      }
  74.207 +
  74.208 +      default:
  74.209 +        return primitive();
  74.210 +    }
  74.211 +}
  74.212 +
  74.213 +// Parses only old-style declarations.
  74.214 +bool
  74.215 +Parser::typeAndName(Expression **type, String **namep)
  74.216 +{
  74.217 +    if (match(TOK_LABEL)) {
  74.218 +        // Old-style declaration:
  74.219 +        //   new X:type
  74.220 +        Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
  74.221 +        if (!name)
  74.222 +            return false;
  74.223 +
  74.224 +        *type = new (pool_) NameProxy(scanner_.begin(), name);
  74.225 +        *namep = expectName();
  74.226 +        return !!*namep;
  74.227 +    }
  74.228 +    
  74.229 +    *type = NULL;
  74.230 +    *namep = expectName();
  74.231 +
  74.232 +    return !!*namep;
  74.233 +}
  74.234 +
  74.235 +// Parses both old and new style declarations.
  74.236 +bool
  74.237 +Parser::fullTypeAndName(Expression **type, String **namep, DeclKind kind)
  74.238 +{
  74.239 +    // Declaration:
  74.240 +    //   NewDecl ::= Type Ident
  74.241 +    //   OldDecl ::= Label? (Ident | "...")
  74.242 +    //   Type    ::= Ident
  74.243 +    //   Label   ::= Ident ":"
  74.244 +    //
  74.245 +    if (match(TOK_LABEL)) {
  74.246 +        // We something of the form:
  74.247 +        //     Label Ident
  74.248 +        // or: Label "..."
  74.249 +        Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
  74.250 +        if (!name)
  74.251 +            return false;
  74.252 +
  74.253 +        *type = new (pool_) NameProxy(scanner_.begin(), name);
  74.254 +        if (kind == DeclArg && match(TOK_ELLIPSES)) {
  74.255 +            *namep = NULL;
  74.256 +        } else {
  74.257 +            if ((*namep = expectName()) == NULL)
  74.258 +                return false;
  74.259 +        }
  74.260 +        return true;
  74.261 +    }
  74.262 +
  74.263 +    Local<String> name(zone_, expectName());
  74.264 +    if (!name)
  74.265 +        return false;
  74.266 +
  74.267 +    if (peek(TOK_NAME) || (kind == DeclArg && peek(TOK_ELLIPSES))) {
  74.268 +        // We got something of the form:
  74.269 +        //    Ident Ident
  74.270 +        *type = new (pool_) NameProxy(scanner_.begin(), name);
  74.271 +        if (peek(TOK_NAME)) {
  74.272 +            if ((*namep = expectName()) == NULL)
  74.273 +                return false;
  74.274 +        } else {
  74.275 +            *namep = NULL;
  74.276 +        }
  74.277 +        return true;
  74.278 +    }
  74.279 +
  74.280 +    // We got something of the form:
  74.281 +    //    Ident
  74.282 +    *type = NULL;
  74.283 +    *namep = name;
  74.284 +    return true;
  74.285 +}
  74.286 +
  74.287 +Expression *
  74.288 +Parser::call(Expression *callee)
  74.289 +{
  74.290 +    ExpressionList *arguments = new (pool_) ExpressionList();
  74.291 +
  74.292 +    SourcePosition pos = scanner_.begin();
  74.293 +    expect(TOK_LPAREN);
  74.294 +    
  74.295 +    if (!match(TOK_RPAREN)) {
  74.296 +        while (true) {
  74.297 +            Expression *expr = expression();
  74.298 +            if (!expr)
  74.299 +                return NULL;
  74.300 +
  74.301 +            if (!arguments->append(expr))
  74.302 +                return NULL;
  74.303 +
  74.304 +            if (!match(TOK_COMMA))
  74.305 +                break;
  74.306 +        }
  74.307 +
  74.308 +        if (!expect(TOK_RPAREN))
  74.309 +            return NULL;
  74.310 +    }
  74.311 +
  74.312 +    return new (pool_) CallExpression(pos, callee, arguments);
  74.313 +}
  74.314 +
  74.315 +Expression *
  74.316 +Parser::index(Expression *left)
  74.317 +{
  74.318 +    expect(TOK_LBRACKET);
  74.319 +    
  74.320 +    SourcePosition pos = scanner_.begin();
  74.321 +    Expression *expr = expression();
  74.322 +    if (!expr)
  74.323 +        return NULL;
  74.324 +
  74.325 +    if (!expect(TOK_RBRACKET))
  74.326 +        return NULL;
  74.327 +
  74.328 +    return new (pool_) IndexExpression(pos, left, expr);
  74.329 +}
  74.330 +
  74.331 +Expression *
  74.332 +Parser::field(Expression *left)
  74.333 +{
  74.334 +    expect(TOK_DOT);
  74.335 +
  74.336 +    SourcePosition pos = scanner_.begin();
  74.337 +    Local<String> name(zone_, expectName());
  74.338 +    if (!name)
  74.339 +        return NULL;
  74.340 +
  74.341 +    return new (pool_) FieldExpression(pos, left, name);
  74.342 +}
  74.343 +
  74.344 +Expression *
  74.345 +Parser::primary()
  74.346 +{
  74.347 +    Expression *expr = prefix();
  74.348 +    if (!expr)
  74.349 +        return NULL;
  74.350 +
  74.351 +    for (;;) {
  74.352 +        switch (scanner_.peek()) {
  74.353 +          case TOK_LPAREN:
  74.354 +            if ((expr = call(expr)) == NULL)
  74.355 +                return NULL;
  74.356 +            break;
  74.357 +
  74.358 +          case TOK_LBRACKET:
  74.359 +            if ((expr = index(expr)) == NULL)
  74.360 +                return NULL;
  74.361 +            break;
  74.362 +
  74.363 +          case TOK_DOT:
  74.364 +            if ((expr = field(expr)) == NULL)
  74.365 +                return NULL;
  74.366 +            break;
  74.367 +
  74.368 +          default:
  74.369 +            return expr;
  74.370 +        }
  74.371 +    }
  74.372 +}
  74.373 +
  74.374 +Expression *
  74.375 +Parser::unary()
  74.376 +{
  74.377 +    TokenKind token = scanner_.peek();
  74.378 +
  74.379 +    SourcePosition pos = scanner_.begin();
  74.380 +    switch (token) {
  74.381 +      case TOK_INCREMENT:
  74.382 +      case TOK_DECREMENT:
  74.383 +      {
  74.384 +        scanner_.scan();
  74.385 +        Expression *expr = unary();
  74.386 +        if (!expr)
  74.387 +            return NULL;
  74.388 +        return new (pool_) IncDecExpression(pos, token, expr, false);
  74.389 +      }
  74.390 +
  74.391 +      case TOK_MINUS:
  74.392 +      case TOK_NOT:
  74.393 +      case TOK_TILDE:
  74.394 +      {
  74.395 +        scanner_.scan();
  74.396 +        Expression *expr = unary();
  74.397 +        if (!expr)
  74.398 +            return NULL;
  74.399 +        return new (pool_) UnaryExpression(pos, token, expr);
  74.400 +      }
  74.401 +
  74.402 +      case TOK_SIZEOF:
  74.403 +      {
  74.404 +        scanner_.scan();
  74.405 +        if (!expect(TOK_LPAREN))
  74.406 +            return NULL;
  74.407 +        Expression *expr = unary();
  74.408 +        if (!expr)
  74.409 +            return NULL;
  74.410 +        if (!expect(TOK_RPAREN))
  74.411 +            return NULL;
  74.412 +        return new (pool_) UnaryExpression(pos, token, expr);
  74.413 +      }
  74.414 +
  74.415 +      case TOK_LABEL:
  74.416 +      {
  74.417 +        scanner_.scan();
  74.418 +        Local<String> tag(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
  74.419 +        if (!tag)
  74.420 +            return NULL;
  74.421 +
  74.422 +        NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), tag);
  74.423 +
  74.424 +        Expression *expr = unary();
  74.425 +        if (!expr)
  74.426 +            return NULL;
  74.427 +
  74.428 +        return new (pool_) UnaryExpression(pos, TOK_LABEL, expr, proxy);
  74.429 +      }
  74.430 +
  74.431 +      default:
  74.432 +        break;
  74.433 +    }
  74.434 +
  74.435 +    Expression *expr = primary();
  74.436 +
  74.437 +    token = scanner_.peek();
  74.438 +    if (token == TOK_INCREMENT || token == TOK_DECREMENT) {
  74.439 +        scanner_.scan();
  74.440 +        return new (pool_) IncDecExpression(pos, token, expr, true);
  74.441 +    }
  74.442 +
  74.443 +    return expr;
  74.444 +}
  74.445 +
  74.446 +Expression *
  74.447 +Parser::multiplication()
  74.448 +{
  74.449 +    Expression *left = unary();
  74.450 +    do {
  74.451 +        if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT))
  74.452 +            break;
  74.453 +        SourcePosition pos = scanner_.begin();
  74.454 +        TokenKind kind = scanner_.last();
  74.455 +        Expression *right = unary();
  74.456 +        if (!right)
  74.457 +            return NULL;
  74.458 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
  74.459 +    } while (left);
  74.460 +    return left;
  74.461 +}
  74.462 +
  74.463 +Expression *
  74.464 +Parser::addition()
  74.465 +{
  74.466 +    Expression *left = multiplication();
  74.467 +    while (left) {
  74.468 +        if (!match(TOK_PLUS) && !match(TOK_MINUS))
  74.469 +            break;
  74.470 +        SourcePosition pos = scanner_.begin();
  74.471 +        TokenKind kind = scanner_.last();
  74.472 +        Expression *right = multiplication();
  74.473 +        if (!right)
  74.474 +            return NULL;
  74.475 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
  74.476 +    }
  74.477 +    return left;
  74.478 +}
  74.479 +
  74.480 +Expression *
  74.481 +Parser::shift()
  74.482 +{
  74.483 +    Expression *left = addition();
  74.484 +    while (left) {
  74.485 +        if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR))
  74.486 +            break;
  74.487 +        SourcePosition pos = scanner_.begin();
  74.488 +        TokenKind kind = scanner_.last();
  74.489 +        Expression *right = addition();
  74.490 +        if (!right)
  74.491 +            return NULL;
  74.492 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
  74.493 +    }
  74.494 +    return left;
  74.495 +}
  74.496 +
  74.497 +Expression *
  74.498 +Parser::bitand_()
  74.499 +{
  74.500 +    Expression *left = shift();
  74.501 +    while (left) {
  74.502 +        if (!match(TOK_BITAND))
  74.503 +            break;
  74.504 +        SourcePosition pos = scanner_.begin();
  74.505 +        Expression *right = shift();
  74.506 +        if (!right)
  74.507 +            return NULL;
  74.508 +        left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right);
  74.509 +    }
  74.510 +    return left;
  74.511 +}
  74.512 +
  74.513 +Expression *
  74.514 +Parser::bitxor()
  74.515 +{
  74.516 +    Expression *left = bitand_();
  74.517 +    while (left) {
  74.518 +        if (!match(TOK_BITXOR))
  74.519 +            break;
  74.520 +        SourcePosition pos = scanner_.begin();
  74.521 +        Expression *right = shift();
  74.522 +        if (!right)
  74.523 +            return NULL;
  74.524 +        left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right);
  74.525 +    }
  74.526 +    return left;
  74.527 +}
  74.528 +
  74.529 +Expression *
  74.530 +Parser::bitor_()
  74.531 +{
  74.532 +    Expression *left = bitxor();
  74.533 +    while (left) {
  74.534 +        if (!match(TOK_BITOR))
  74.535 +            break;
  74.536 +        SourcePosition pos = scanner_.begin();
  74.537 +        Expression *right = bitxor();
  74.538 +        if (!right)
  74.539 +            return NULL;
  74.540 +        left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right);
  74.541 +    }
  74.542 +    return left;
  74.543 +}
  74.544 +
  74.545 +Expression *
  74.546 +Parser::relational()
  74.547 +{
  74.548 +    Expression *left = bitor_();
  74.549 +    while (left) {
  74.550 +        TokenKind kind = scanner_.peek();
  74.551 +        if (kind < TOK_LT || kind > TOK_GE)
  74.552 +            break;
  74.553 +        scanner_.scan();
  74.554 +        SourcePosition pos = scanner_.begin();
  74.555 +        Expression *right = shift();
  74.556 +        if (!right)
  74.557 +            return NULL;
  74.558 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
  74.559 +    }
  74.560 +    return left;
  74.561 +}
  74.562 +
  74.563 +Expression *
  74.564 +Parser::equals()
  74.565 +{
  74.566 +    Expression *left = relational();
  74.567 +    while (left) {
  74.568 +        if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS))
  74.569 +            break;
  74.570 +        TokenKind kind = scanner_.last();
  74.571 +        SourcePosition pos = scanner_.begin();
  74.572 +        Expression *right = relational();
  74.573 +        if (!right)
  74.574 +            return NULL;
  74.575 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
  74.576 +    }
  74.577 +    return left;
  74.578 +}
  74.579 +
  74.580 +Expression *
  74.581 +Parser::and_()
  74.582 +{
  74.583 +    Expression *left = equals();
  74.584 +    while (left) {
  74.585 +        if (!match(TOK_AND))
  74.586 +            break;
  74.587 +        SourcePosition pos = scanner_.begin();
  74.588 +        Expression *right = equals();
  74.589 +        if (!right)
  74.590 +            return NULL;
  74.591 +        left = new (pool_) BinaryExpression(pos, TOK_AND, left, right);
  74.592 +    }
  74.593 +    return left;
  74.594 +}
  74.595 +
  74.596 +Expression *
  74.597 +Parser::or_()
  74.598 +{
  74.599 +    Expression *left = and_();
  74.600 +    while (left) {
  74.601 +        if (!match(TOK_OR))
  74.602 +            break;
  74.603 +        SourcePosition pos = scanner_.begin();
  74.604 +        Expression *right = and_();
  74.605 +        if (!right)
  74.606 +            return NULL;
  74.607 +        left = new (pool_) BinaryExpression(pos, TOK_OR, left, right);
  74.608 +    }
  74.609 +    return left;
  74.610 +}
  74.611 +
  74.612 +Expression *
  74.613 +Parser::ternary()
  74.614 +{
  74.615 +    Expression *cond = or_();
  74.616 +    if (!cond)
  74.617 +        return NULL;
  74.618 +    
  74.619 +    if (!match(TOK_QMARK))
  74.620 +        return cond;
  74.621 +
  74.622 +    Expression *left;
  74.623 +    SourcePosition pos = scanner_.begin();
  74.624 +    AutoAllowTags<false> disableTags(scanner_);
  74.625 +    {
  74.626 +        if ((left = expression()) == NULL)
  74.627 +            return NULL;
  74.628 +    }
  74.629 +
  74.630 +    if (!expect(TOK_COLON))
  74.631 +        return NULL;
  74.632 +
  74.633 +    Expression *right = expression();
  74.634 +    if (!right)
  74.635 +        return NULL;
  74.636 +
  74.637 +    return new (pool_) TernaryExpression(pos, cond, left, right);
  74.638 +}
  74.639 +
  74.640 +Expression *
  74.641 +Parser::assignment()
  74.642 +{
  74.643 +    Expression *left = ternary();
  74.644 +    while (left) {
  74.645 +        TokenKind token = scanner_.peek();
  74.646 +        if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL))
  74.647 +            break;
  74.648 +        scanner_.scan();
  74.649 +        SourcePosition pos = scanner_.begin();
  74.650 +        Expression *expr = ternary();
  74.651 +        if (!expr)
  74.652 +            return NULL;
  74.653 +
  74.654 +        left = new (pool_) Assignment(pos, token, left, expr);
  74.655 +    }
  74.656 +    return left;
  74.657 +}
  74.658 +
  74.659 +Expression *
  74.660 +Parser::expression()
  74.661 +{
  74.662 +    return assignment();
  74.663 +}
  74.664 +
  74.665 +Statement *
  74.666 +Parser::while_()
  74.667 +{
  74.668 +    SourcePosition pos = scanner_.begin();
  74.669 +    scanner_.scan();
  74.670 +
  74.671 +    if (!expect(TOK_LPAREN))
  74.672 +        return NULL;
  74.673 +
  74.674 +    Expression *condition = expression();
  74.675 +    if (!condition)
  74.676 +        return NULL;
  74.677 +
  74.678 +    if (!expect(TOK_RPAREN))
  74.679 +        return NULL;
  74.680 +
  74.681 +    Statement *body;
  74.682 +    if (scanner_.peek() == TOK_LBRACE)
  74.683 +        body = block();
  74.684 +    else
  74.685 +        body = localStatement();
  74.686 +    if (!body)
  74.687 +        return NULL;
  74.688 +
  74.689 +    return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body);
  74.690 +}
  74.691 +
  74.692 +Statement *
  74.693 +Parser::do_()
  74.694 +{
  74.695 +    SourcePosition pos = scanner_.begin();
  74.696 +    scanner_.scan();
  74.697 +
  74.698 +    Statement *body;
  74.699 +    if (scanner_.peek() == TOK_LBRACE)
  74.700 +        body = block();
  74.701 +    else
  74.702 +        body = localStatement();
  74.703 +    if (!body)
  74.704 +        return NULL;
  74.705 +
  74.706 +    if (!expect(TOK_WHILE))
  74.707 +        return NULL;
  74.708 +
  74.709 +    if (!expect(TOK_LPAREN))
  74.710 +        return NULL;
  74.711 +    Expression *condition = expression();
  74.712 +    if (!condition)
  74.713 +        return NULL;
  74.714 +    if (!expect(TOK_RPAREN))
  74.715 +        return NULL;
  74.716 +
  74.717 +    return new (pool_) WhileStatement(pos, TOK_DO, condition, body);
  74.718 +}
  74.719 +
  74.720 +Statement *
  74.721 +Parser::switch_()
  74.722 +{
  74.723 +    expect(TOK_SWITCH);
  74.724 +
  74.725 +    SourcePosition pos = scanner_.begin();
  74.726 +
  74.727 +    if (!expect(TOK_LPAREN))
  74.728 +        return NULL;
  74.729 +    Expression *expr = expression();
  74.730 +    if (!expr)
  74.731 +        return NULL;
  74.732 +    if (!expect(TOK_RPAREN))
  74.733 +        return NULL;
  74.734 +
  74.735 +    if (!expect(TOK_LBRACE))
  74.736 +        return NULL;
  74.737 +
  74.738 +    SourcePosition defaultPos;
  74.739 +    PoolList<Case *> *cases = new (pool_) PoolList<Case *>();
  74.740 +
  74.741 +    Statement *defaultCase = NULL;
  74.742 +
  74.743 +    while (!peek(TOK_RBRACE)) {
  74.744 +        Expression *expr = NULL;
  74.745 +        ExpressionList *others = NULL;
  74.746 +        if (match(TOK_DEFAULT)) {
  74.747 +            if (defaultCase) {
  74.748 +                cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch);
  74.749 +                return NULL;
  74.750 +            }
  74.751 +
  74.752 +            defaultPos = scanner_.begin();
  74.753 +        } else {
  74.754 +            if (defaultCase) {
  74.755 +                cc_.reportError(defaultPos, Message_DefaultMustBeLastCase);
  74.756 +                return NULL;
  74.757 +            }
  74.758 +
  74.759 +            if (!expect(TOK_CASE))
  74.760 +                return NULL;
  74.761 +
  74.762 +            // A limitation in the grammar is that |case <NAME>:| will be
  74.763 +            // detected as a label.
  74.764 +            AutoAllowTags<false> disableTags(scanner_);
  74.765 +
  74.766 +            if ((expr = expression()) == NULL)
  74.767 +                return NULL;
  74.768 +
  74.769 +            if (peek(TOK_COMMA)) {
  74.770 +                others = new (pool_) ExpressionList();
  74.771 +                while (match(TOK_COMMA)) {
  74.772 +                    Expression *other = expression();
  74.773 +                    if (!other)
  74.774 +                        return NULL;
  74.775 +                    if (!others->append(other))
  74.776 +                        return NULL;
  74.777 +                }
  74.778 +            }
  74.779 +        }
  74.780 +
  74.781 +        if (!expect(TOK_COLON))
  74.782 +            return NULL;
  74.783 +
  74.784 +        Statement *statement = localStatement();
  74.785 +        if (!statement)
  74.786 +            return NULL;
  74.787 +
  74.788 +        if (!peek(TOK_CASE) &&
  74.789 +            !peek(TOK_DEFAULT) &&
  74.790 +            !peek(TOK_RBRACE))
  74.791 +        {
  74.792 +            cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase);
  74.793 +            return NULL;
  74.794 +        }
  74.795 +
  74.796 +        if (expr) {
  74.797 +            Case *caze = new (pool_) Case(expr, others, statement);
  74.798 +            if (!cases->append(caze))
  74.799 +                return NULL;
  74.800 +        } else {
  74.801 +            defaultCase = statement;
  74.802 +        }
  74.803 +    }
  74.804 +
  74.805 +    if (!expect(TOK_RBRACE))
  74.806 +        return NULL;
  74.807 +
  74.808 +    return new (pool_) SwitchStatement(pos, expr, cases, defaultCase);
  74.809 +}
  74.810 +
  74.811 +Statement *
  74.812 +Parser::forStatement()
  74.813 +{
  74.814 +    SourcePosition pos = scanner_.begin();
  74.815 +    scanner_.scan();
  74.816 +    if (!expect(TOK_LPAREN))
  74.817 +        return NULL;
  74.818 +
  74.819 +    Statement *decl = NULL;
  74.820 +    if (!match(TOK_SEMICOLON)) {
  74.821 +        if (match(TOK_NEW)) {
  74.822 +            if ((decl = vars(Qual_None)) == NULL)
  74.823 +                return NULL;
  74.824 +        } else {
  74.825 +            if ((decl = expressionStatement()) == NULL)
  74.826 +                return NULL;
  74.827 +        }
  74.828 +        if (!expect(TOK_SEMICOLON))
  74.829 +            return NULL;
  74.830 +    }
  74.831 +
  74.832 +    Expression *condition = NULL;
  74.833 +    if (!match(TOK_SEMICOLON)) {
  74.834 +        if ((condition = expression()) == NULL)
  74.835 +            return NULL;
  74.836 +        if (!expect(TOK_SEMICOLON))
  74.837 +            return NULL;
  74.838 +    }
  74.839 +
  74.840 +    Statement *update = NULL;
  74.841 +    if (!match(TOK_RPAREN)) {
  74.842 +        if ((update = expressionStatement()) == NULL)
  74.843 +            return NULL;
  74.844 +        if (!expect(TOK_RPAREN))
  74.845 +            return NULL;
  74.846 +    }
  74.847 +
  74.848 +    Statement *body;
  74.849 +    if (scanner_.peek() == TOK_LBRACE)
  74.850 +        body = block();
  74.851 +    else
  74.852 +        body = localStatement();
  74.853 +    if (!body)
  74.854 +        return NULL;
  74.855 +
  74.856 +    return new (pool_) ForStatement(pos, decl, condition, update, body);
  74.857 +}
  74.858 +
  74.859 +ExpressionList *
  74.860 +Parser::dimensions()
  74.861 +{
  74.862 +    ExpressionList *postDimensions = new (pool_) ExpressionList();
  74.863 +    while (match(TOK_LBRACKET)) {
  74.864 +        Expression *dim = NULL;
  74.865 +        if (!match(TOK_RBRACKET)) {
  74.866 +            if ((dim = expression()) == NULL)
  74.867 +                return NULL;
  74.868 +            if (!expect(TOK_RBRACKET))
  74.869 +                return NULL;
  74.870 +        }
  74.871 +
  74.872 +        if (!postDimensions->append(dim))
  74.873 +            return NULL;
  74.874 +    }
  74.875 +    return postDimensions;
  74.876 +}
  74.877 +
  74.878 +VariableDeclaration *
  74.879 +Parser::var(TypeQualifiers qual)
  74.880 +{
  74.881 +    Expression *type;
  74.882 +    Local<String> name(zone_);
  74.883 +    
  74.884 +    if (!typeAndName(&type, name.ref()))
  74.885 +        return NULL;
  74.886 +
  74.887 +    SourcePosition pos = scanner_.begin();
  74.888 +    
  74.889 +    Expression *expr = NULL;
  74.890 +    if (match(TOK_ASSIGN)) {
  74.891 +        switch (scanner_.peek()) {
  74.892 +          // Note: we don't support [] literals yet.
  74.893 +          case TOK_LBRACE:
  74.894 +            if ((expr = arrayLiteral(scanner_.scan())) == NULL)
  74.895 +                return NULL;
  74.896 +            break;
  74.897 +
  74.898 +          default:
  74.899 +            if ((expr = expression()) == NULL)
  74.900 +                return NULL;
  74.901 +            break;
  74.902 +        }
  74.903 +    }
  74.904 +
  74.905 +    return new (pool_) VariableDeclaration(pos, qual, name, type, expr);
  74.906 +}
  74.907 +
  74.908 +Statement *
  74.909 +Parser::vars(TypeQualifiers qual)
  74.910 +{
  74.911 +    VariableDeclaration *decl = var(qual);
  74.912 +    if (!decl)
  74.913 +        return NULL;
  74.914 +
  74.915 +    if (!peek(TOK_COMMA))
  74.916 +        return decl;
  74.917 +
  74.918 +    StatementList *statements = new (pool_) StatementList();
  74.919 +    if (!statements->append(decl))
  74.920 +        return NULL;
  74.921 +
  74.922 +    while (match(TOK_COMMA)) {
  74.923 +        Statement *decl = var(qual);
  74.924 +        if (!decl)
  74.925 +            return NULL;
  74.926 +        if (!statements->append(decl))
  74.927 +            return NULL;
  74.928 +    }
  74.929 +
  74.930 +    // Create a fake-o block with no scope to create a statement list.
  74.931 +    return new (pool_) BlockStatement(decl->pos(), statements);
  74.932 +}
  74.933 +
  74.934 +Statement *
  74.935 +Parser::returnStatement()
  74.936 +{
  74.937 +    SourcePosition pos = scanner_.begin();
  74.938 +    if (!expect(TOK_RETURN))
  74.939 +        return NULL;
  74.940 +
  74.941 +    Expression *expr = NULL;
  74.942 +    if (scanner_.peek() != TOK_SEMICOLON) {
  74.943 +        if ((expr = expression()) == NULL)
  74.944 +            return NULL;
  74.945 +
  74.946 +        // We only care about non-void returns when determining whether a
  74.947 +        // tagless function is non-void.
  74.948 +        encounteredReturn_ = true;
  74.949 +    }
  74.950 +
  74.951 +    return new (pool_) ReturnStatement(pos, expr);
  74.952 +}
  74.953 +
  74.954 +Statement *
  74.955 +Parser::expressionStatement()
  74.956 +{
  74.957 +    Expression *left = assignment();
  74.958 +    if (!left)
  74.959 +        return NULL;
  74.960 +
  74.961 +    return new (pool_) ExpressionStatement(left);
  74.962 +}
  74.963 +
  74.964 +Statement *
  74.965 +Parser::block()
  74.966 +{
  74.967 +    if (!expect(TOK_LBRACE))
  74.968 +        return NULL;
  74.969 +
  74.970 +    SourcePosition pos = scanner_.begin();
  74.971 +
  74.972 +    StatementList *statements = new (pool_) StatementList();
  74.973 +    while (!match(TOK_RBRACE)) {
  74.974 +        Statement *statement = localStatement();
  74.975 +        if (statement == NULL)
  74.976 +            return NULL;
  74.977 +        if (!statements->append(statement))
  74.978 +            return NULL;
  74.979 +    }
  74.980 +
  74.981 +    BlockStatement *block = new (pool_) BlockStatement(pos, statements);
  74.982 +    return block;
  74.983 +}
  74.984 +
  74.985 +Statement *
  74.986 +Parser::if_()
  74.987 +{
  74.988 +    expect(TOK_IF);
  74.989 +    
  74.990 +    SourcePosition pos = scanner_.begin();
  74.991 +    if (!expect(TOK_LPAREN))
  74.992 +        return NULL;
  74.993 +
  74.994 +    Expression *cond = expression();
  74.995 +    if (!cond)
  74.996 +        return NULL;
  74.997 +
  74.998 +    if (!expect(TOK_RPAREN))
  74.999 +        return NULL;
 74.1000 +
 74.1001 +    Statement *ifTrue = localStatement();
 74.1002 +    if (!ifTrue)
 74.1003 +        return NULL;
 74.1004 +
 74.1005 +    IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue);
 74.1006 +
 74.1007 +    IfStatement *last = outer;
 74.1008 +    while (match(TOK_ELSE)) {
 74.1009 +        if (!match(TOK_IF)) {
 74.1010 +            Statement *ifFalse = localStatement();
 74.1011 +            if (!ifFalse)
 74.1012 +                return NULL;
 74.1013 +
 74.1014 +            last->setIfFalse(ifFalse);
 74.1015 +            break;
 74.1016 +        }
 74.1017 +
 74.1018 +        SourcePosition pos = scanner_.begin();
 74.1019 +        if (!expect(TOK_LPAREN))
 74.1020 +            return NULL;
 74.1021 +
 74.1022 +        Expression *otherCond = expression();
 74.1023 +        if (!otherCond)
 74.1024 +            return NULL;
 74.1025 +
 74.1026 +        if (!expect(TOK_RPAREN))
 74.1027 +            return NULL;
 74.1028 +
 74.1029 +        Statement *otherIfTrue = localStatement();
 74.1030 +        if (!otherIfTrue)
 74.1031 +            return NULL;
 74.1032 +
 74.1033 +        IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue);
 74.1034 +        last->setIfFalse(inner);
 74.1035 +        last = inner;
 74.1036 +    }
 74.1037 +
 74.1038 +    return outer;
 74.1039 +}
 74.1040 +
 74.1041 +Statement *
 74.1042 +Parser::localStatement()
 74.1043 +{
 74.1044 +    Statement *statement = NULL;
 74.1045 +
 74.1046 +    // Statements which must be followed by a semicolon will break out of the
 74.1047 +    // switch. If they may end in BlockStatements, they'll immediately return.
 74.1048 +
 74.1049 +    TokenKind kind = scanner_.peek();
 74.1050 +    switch (kind) {
 74.1051 +      case TOK_CONST:
 74.1052 +      case TOK_NEW:
 74.1053 +      {
 74.1054 +        TypeQualifiers quals = (kind == TOK_CONST)
 74.1055 +                              ? Qual_Const
 74.1056 +                              : Qual_None;
 74.1057 +        scanner_.scan();
 74.1058 +        if ((statement = vars(quals)) == NULL)
 74.1059 +          return NULL;
 74.1060 +        break;
 74.1061 +      }
 74.1062 +
 74.1063 +      case TOK_FOR:
 74.1064 +        return forStatement();
 74.1065 +
 74.1066 +      case TOK_WHILE:
 74.1067 +        return while_();
 74.1068 +
 74.1069 +      case TOK_BREAK:
 74.1070 +        scanner_.scan();
 74.1071 +        statement = new (pool_) BreakStatement(scanner_.begin());
 74.1072 +        break;
 74.1073 +
 74.1074 +      case TOK_CONTINUE:
 74.1075 +        scanner_.scan();
 74.1076 +        statement = new (pool_) ContinueStatement(scanner_.begin());
 74.1077 +        break;
 74.1078 +
 74.1079 +      case TOK_DO:
 74.1080 +        if ((statement = do_()) == NULL)
 74.1081 +            return NULL;
 74.1082 +        break;
 74.1083 +
 74.1084 +      case TOK_RETURN:
 74.1085 +        if ((statement = returnStatement()) == NULL)
 74.1086 +          return NULL;
 74.1087 +        break;
 74.1088 +
 74.1089 +      case TOK_ENUM:
 74.1090 +        if ((statement = enum_()) == NULL)
 74.1091 +          return NULL;
 74.1092 +        break;
 74.1093 +
 74.1094 +      case TOK_STRUCT:
 74.1095 +        if ((statement = struct_()) == NULL)
 74.1096 +          return NULL;
 74.1097 +        break;
 74.1098 +
 74.1099 +      case TOK_SWITCH:
 74.1100 +        return switch_();
 74.1101 +
 74.1102 +      case TOK_IF:
 74.1103 +        return if_();
 74.1104 +
 74.1105 +      case TOK_LBRACE:
 74.1106 +        return block();
 74.1107 +
 74.1108 +      default:
 74.1109 +        break;
 74.1110 +    }
 74.1111 +
 74.1112 +    if (!statement) {
 74.1113 +        if ((statement = expressionStatement()) == NULL)
 74.1114 +            return NULL;
 74.1115 +    }
 74.1116 +
 74.1117 +    if (!expect(TOK_SEMICOLON))
 74.1118 +        return NULL;
 74.1119 +
 74.1120 +    return statement;
 74.1121 +}
 74.1122 +
 74.1123 +Statement *
 74.1124 +Parser::struct_()
 74.1125 +{
 74.1126 +    expect(TOK_STRUCT);
 74.1127 +
 74.1128 +    Local<String> name(zone_, expectName());
 74.1129 +    if (!name)
 74.1130 +        return NULL;
 74.1131 +
 74.1132 +    SourcePosition pos = scanner_.begin();
 74.1133 +
 74.1134 +    if (!expect(TOK_LBRACE))
 74.1135 +        return NULL;
 74.1136 +
 74.1137 +    FieldList *fields = new (pool_) FieldList();
 74.1138 +
 74.1139 +    while (!peek(TOK_RBRACE)) {
 74.1140 +        Expression *type;
 74.1141 +        Local<String> fieldName(zone_);
 74.1142 +
 74.1143 +        if (!fullTypeAndName(&type, fieldName.ref(), DeclField))
 74.1144 +            return NULL;
 74.1145 +
 74.1146 +        SourcePosition pos = scanner_.begin();
 74.1147 +
 74.1148 +        if (!matchSemicolon())
 74.1149 +            return NULL;
 74.1150 +
 74.1151 +        StructureStatement::Field *field =
 74.1152 +            new (pool_) StructureStatement::Field(pos, type, fieldName);
 74.1153 +        if (!field || !fields->append(field))
 74.1154 +            return NULL;
 74.1155 +    }
 74.1156 +
 74.1157 +    if (!expect(TOK_RBRACE))
 74.1158 +        return NULL;
 74.1159 +
 74.1160 +    if (fields->empty()) {
 74.1161 +        cc_.reportError(pos, Message_StructCantBeEmpty);
 74.1162 +        return NULL;
 74.1163 +    }
 74.1164 +
 74.1165 +    return new (pool_) StructureStatement(pos, name, fields);
 74.1166 +}
 74.1167 +
 74.1168 +Statement *
 74.1169 +Parser::enum_()
 74.1170 +{
 74.1171 +    expect(TOK_ENUM);
 74.1172 +
 74.1173 +    SourcePosition pos = scanner_.begin();
 74.1174 +
 74.1175 +    Local<String> name(zone_);
 74.1176 +    if (matchName(name.ref()) && !name)
 74.1177 +        return NULL;
 74.1178 +
 74.1179 +    EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList();
 74.1180 +
 74.1181 +    if (!expect(TOK_LBRACE))
 74.1182 +        return NULL;
 74.1183 +
 74.1184 +    do {
 74.1185 +        if (scanner_.peek() == TOK_RBRACE)
 74.1186 +            break;
 74.1187 +
 74.1188 +        Local<String> name(zone_, expectName());
 74.1189 +        if (!name)
 74.1190 +            return NULL;
 74.1191 +
 74.1192 +        Expression *expr = NULL;
 74.1193 +        if (match(TOK_ASSIGN)) {
 74.1194 +            if ((expr = expression()) == NULL)
 74.1195 +                return NULL;
 74.1196 +        }
 74.1197 +
 74.1198 +        if (!entries->append(EnumStatement::Entry(name, expr)))
 74.1199 +            return NULL;
 74.1200 +    } while (match(TOK_COMMA));
 74.1201 +    if (!expect(TOK_RBRACE))
 74.1202 +        return NULL;
 74.1203 +
 74.1204 +    return new (pool_) EnumStatement(pos, name, entries);
 74.1205 +}
 74.1206 +
 74.1207 +template <class T>
 74.1208 +static inline ScopedRoot<T> *
 74.1209 +NewScopedRoot(PoolAllocator &pool, Handle<T> obj)
 74.1210 +{
 74.1211 +    ScopedRoot<T> *root = pool.alloc<ScopedRoot<T> >();
 74.1212 +    new (root) ScopedRoot<T>(obj);
 74.1213 +    return root;
 74.1214 +}
 74.1215 +
 74.1216 +ImportStatement *
 74.1217 +Parser::import()
 74.1218 +{
 74.1219 +    NameList *names = new (pool_) NameList();
 74.1220 +
 74.1221 +    SourcePosition pos = scanner_.begin();
 74.1222 +
 74.1223 +    Local<String> name(zone_, expectName());
 74.1224 +    if (!name || !names->append(NewScopedRoot<String>(pool_, name)))
 74.1225 +        return NULL;
 74.1226 +
 74.1227 +    TokenKind suffix = TOK_NONE;
 74.1228 +    while (match(TOK_DOT)) {
 74.1229 +        if (match(TOK_STAR)) {
 74.1230 +            suffix = TOK_STAR;
 74.1231 +            break;
 74.1232 +        }
 74.1233 +
 74.1234 +        if ((name = expectName()) == NULL)
 74.1235 +            return NULL;
 74.1236 +
 74.1237 +        if (!names->append(NewScopedRoot<String>(pool_, name)))
 74.1238 +            return NULL;
 74.1239 +    }
 74.1240 +
 74.1241 +    return new (pool_) ImportStatement(pos, names, suffix);
 74.1242 +}
 74.1243 +
 74.1244 +Statement *
 74.1245 +Parser::function(TokenKind token)
 74.1246 +{
 74.1247 +    Expression *returnType;
 74.1248 +    Local<String> name(zone_);
 74.1249 +
 74.1250 +    if (!fullTypeAndName(&returnType, name.ref(), DeclFun))
 74.1251 +        return NULL;
 74.1252 +
 74.1253 +    SourcePosition pos = scanner_.begin();
 74.1254 +    ParameterList *parameters = new (pool_) ParameterList();
 74.1255 +
 74.1256 +    if (!expect(TOK_LPAREN))
 74.1257 +        return NULL;
 74.1258 +
 74.1259 +    bool variadic = false;
 74.1260 +
 74.1261 +    if (!match(TOK_RPAREN)) {
 74.1262 +        while (true) {
 74.1263 +            bool isConst = match(TOK_CONST);
 74.1264 +            bool ref = match(TOK_AMPERSAND);
 74.1265 +
 74.1266 +            SourcePosition begin = scanner_.begin();
 74.1267 +            Expression *type;
 74.1268 +            Local<String> name(zone_);
 74.1269 +            if (!fullTypeAndName(&type, name.ref(), DeclArg))
 74.1270 +                return NULL;
 74.1271 +
 74.1272 +            if (!name) {
 74.1273 +                if (isConst || ref) {
 74.1274 +                    cc_.reportError(begin, Message_InvalidVarArgs);
 74.1275 +                    return NULL;
 74.1276 +                }
 74.1277 +
 74.1278 +                if (token != TOK_NATIVE) {
 74.1279 +                    cc_.reportError(begin, Message_VarArgsOutsideNative);
 74.1280 +                    return NULL;
 74.1281 +                }
 74.1282 +
 74.1283 +                variadic = true;
 74.1284 +                break;
 74.1285 +            }
 74.1286 +
 74.1287 +            Expression *expr = NULL;
 74.1288 +            if (match(TOK_ASSIGN)) {
 74.1289 +                if ((expr = expression()) == NULL)
 74.1290 +                    return NULL;
 74.1291 +            }
 74.1292 +
 74.1293 +            Parameter *parameter = new (pool_) Parameter(name, type, ref, isConst, expr, begin);
 74.1294 +            if (!parameters->append(parameter))
 74.1295 +                return NULL;
 74.1296 +
 74.1297 +            if (!match(TOK_COMMA))
 74.1298 +                break;
 74.1299 +        }
 74.1300 +        if (!expect(TOK_RPAREN))
 74.1301 +            return NULL;
 74.1302 +    }
 74.1303 +
 74.1304 +    encounteredReturn_ = false;
 74.1305 +
 74.1306 +    Statement *body = NULL;
 74.1307 +    if (token != TOK_FORWARD && token != TOK_NATIVE && token != TOK_TYPEDEF) {
 74.1308 +        body = block();
 74.1309 +        if (!body)
 74.1310 +            return NULL;
 74.1311 +    }
 74.1312 +
 74.1313 +    FunctionSignature signature(returnType, parameters, variadic);
 74.1314 +    if (token == TOK_TYPEDEF)
 74.1315 +        return new (pool_) FunctionTypeStatement(pos, name, signature);
 74.1316 +
 74.1317 +    return new (pool_) FunctionStatement(pos, name, token, body, signature, encounteredReturn_);
 74.1318 +}
 74.1319 +
 74.1320 +static inline bool
 74.1321 +DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, Handle<Type> type)
 74.1322 +{
 74.1323 +    Local<String> tag(zone, zone->makeSymbol(name));
 74.1324 +    if (!tag)
 74.1325 +        return false;
 74.1326 +
 74.1327 +    assert(false);
 74.1328 +    return false; //return !!scope->declareType(tag, type);
 74.1329 +}
 74.1330 +
 74.1331 +static inline bool
 74.1332 +DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, PrimitiveType type)
 74.1333 +{
 74.1334 +    Local<Type> primitive(zone, zone->types()->getPrimitive(type));
 74.1335 +    assert(primitive);
 74.1336 +    return DeclareIntrinsicType(zone, scope, name, primitive);
 74.1337 +}
 74.1338 +
 74.1339 +bool
 74.1340 +Parser::setupIntrinsics()
 74.1341 +{
 74.1342 +#if 0
 74.1343 +    if (!DeclareIntrinsicType(zone_, scope_, "Float", PrimitiveType_Float))
 74.1344 +        return false;
 74.1345 +    if (!DeclareIntrinsicType(zone_, scope_, "_", PrimitiveType_Int32))
 74.1346 +        return false;
 74.1347 +    if (!DeclareIntrinsicType(zone_, scope_, "bool", PrimitiveType_Bool))
 74.1348 +        return false;
 74.1349 +    if (!DeclareIntrinsicType(zone_, scope_, "String", PrimitiveType_Char))
 74.1350 +        return false;
 74.1351 +
 74.1352 +    Local<Type> unchecked(zone_, zone_->types()->getUnchecked());
 74.1353 +    if (!DeclareIntrinsicType(zone_, scope_, "unchecked", unchecked))
 74.1354 +        return false;
 74.1355 +
 74.1356 +    Local<Type> voidType(zone_, zone_->types()->getVoid());
 74.1357 +    if (!DeclareIntrinsicType(zone_, scope_, "void", voidType))
 74.1358 +        return false;
 74.1359 +
 74.1360 +    Local<Type> intType(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
 74.1361 +    if (!DeclareIntrinsicType(zone_, scope_, "int", intType))
 74.1362 +        return false;
 74.1363 +#endif
 74.1364 +    return true;
 74.1365 +}
 74.1366 +
 74.1367 +ParseTree *
 74.1368 +Parser::parse()
 74.1369 +{
 74.1370 +    StatementList *statements = new (pool_) StatementList();
 74.1371 +
 74.1372 +    if (!setupIntrinsics())
 74.1373 +        return NULL;
 74.1374 +
 74.1375 +    for (;;) {
 74.1376 +        Statement *statement = NULL;
 74.1377 +
 74.1378 +        TokenKind kind = scanner_.peek();
 74.1379 +        switch (kind) {
 74.1380 +          case TOK_ERROR:
 74.1381 +            return NULL;
 74.1382 +
 74.1383 +          case TOK_EOF:
 74.1384 +            break;
 74.1385 +
 74.1386 +          case TOK_NAME:
 74.1387 +            if ((statement = function(TOK_NAME)) == NULL)
 74.1388 +                return NULL;
 74.1389 +            break;
 74.1390 +
 74.1391 +          case TOK_IMPORT:
 74.1392 +          {
 74.1393 +            scanner_.scan();
 74.1394 +            if (statements->length())
 74.1395 +                cc_.reportError(scanner_.begin(), Message_ImportsMustBeFirst);
 74.1396 +            ImportStatement *stmt = import();
 74.1397 +            if (!stmt)
 74.1398 +                return NULL;
 74.1399 +            if (!imports_->append(stmt))
 74.1400 +                return NULL;
 74.1401 +            if (!matchSemicolon())
 74.1402 +                return NULL;
 74.1403 +            continue;
 74.1404 +          }
 74.1405 +
 74.1406 +          case TOK_FORWARD:
 74.1407 +          case TOK_PUBLIC:
 74.1408 +          case TOK_NATIVE:
 74.1409 +          case TOK_STOCK:
 74.1410 +          case TOK_LABEL:
 74.1411 +          case TOK_TYPEDEF:
 74.1412 +          {
 74.1413 +            if (kind != TOK_LABEL)
 74.1414 +                scanner_.scan();
 74.1415 +            if (kind == TOK_PUBLIC && peek(TOK_CONST)) {
 74.1416 +                TypeQualifiers quals = TypeQualifiers(Qual_Public | Qual_Const);
 74.1417 +                if ((statement = var(quals)) == NULL)
 74.1418 +                    return NULL;
 74.1419 +                if (!matchSemicolon())
 74.1420 +                    return NULL;
 74.1421 +            } else {
 74.1422 +                if ((statement = function(kind)) == NULL)
 74.1423 +                    return NULL;
 74.1424 +                if ((kind == TOK_FORWARD || kind == TOK_NATIVE || kind == TOK_TYPEDEF) && !matchSemicolon())
 74.1425 +                    return NULL;
 74.1426 +            }
 74.1427 +            break;
 74.1428 +          }
 74.1429 +
 74.1430 +          case TOK_CONST:
 74.1431 +          case TOK_NEW:
 74.1432 +          {
 74.1433 +            TypeQualifiers quals = (kind == TOK_NEW) ? Qual_Const : Qual_None;
 74.1434 +            // Note: at global scope, we don't accept comma-delimited
 74.1435 +            // declarations yet, to see if we can get away with forcing
 74.1436 +            // a nicer top-level style.
 74.1437 +            scanner_.scan();
 74.1438 +            if ((statement = var(quals)) == NULL)
 74.1439 +                return NULL;
 74.1440 +            if (!matchSemicolon())
 74.1441 +                return NULL;
 74.1442 +            break;
 74.1443 +          }
 74.1444 +
 74.1445 +          case TOK_ENUM:
 74.1446 +            if ((statement = enum_()) == NULL)
 74.1447 +                return NULL;
 74.1448 +            if (!matchSemicolon())
 74.1449 +                return NULL;
 74.1450 +            break;
 74.1451 +
 74.1452 +          case TOK_STRUCT:
 74.1453 +            if ((statement = struct_()) == NULL)
 74.1454 +                return NULL;
 74.1455 +            if (!matchSemicolon())
 74.1456 +                return NULL;
 74.1457 +            break;
 74.1458 +
 74.1459 +          default:
 74.1460 +            cc_.reportError(scanner_.begin(), Message_ExpectedGlobal);
 74.1461 +            return NULL;
 74.1462 +        }
 74.1463 +
 74.1464 +        if (!statement)
 74.1465 +            break;
 74.1466 +
 74.1467 +        if (!statements->append(statement))
 74.1468 +            return NULL;
 74.1469 +    }
 74.1470 +
 74.1471 +    return new (pool_) ParseTree(statements, unbound_, imports_);
 74.1472 +}
 74.1473 +
 74.1474 +class AstPrinter : public AstVisitor
 74.1475 +{
 74.1476 +    FILE *fp_;
 74.1477 +    size_t level_;
 74.1478 +
 74.1479 +  private:
 74.1480 +    void prefix() {
 74.1481 +        for (size_t i = 0; i < level_; i++)
 74.1482 +            fprintf(fp_, "  ");
 74.1483 +    }
 74.1484 +    void indent() {
 74.1485 +        level_++;
 74.1486 +    }
 74.1487 +    void unindent() {
 74.1488 +        level_--;
 74.1489 +    }
 74.1490 +
 74.1491 +  public:
 74.1492 +    AstPrinter(FILE *fp)
 74.1493 +      : fp_(fp),
 74.1494 +        level_(0)
 74.1495 +    {
 74.1496 +    }
 74.1497 +
 74.1498 +    void dump(const FunctionSignature &sig) {
 74.1499 +        prefix();
 74.1500 +        fprintf(fp_, "()\n");
 74.1501 +    }
 74.1502 +    void visitNameProxy(NameProxy *name) {
 74.1503 +        prefix();
 74.1504 +        fprintf(fp_, "[ NameProxy (%s)\n", name->name()->chars());
 74.1505 +    }
 74.1506 +    void visitCallExpression(CallExpression *node) {
 74.1507 +        prefix();
 74.1508 +        fprintf(fp_, "[ CallExpression\n");
 74.1509 +        indent();
 74.1510 +        node->callee()->accept(this);
 74.1511 +        for (size_t i = 0; i < node->arguments()->length(); i++)
 74.1512 +            node->arguments()->at(i)->accept(this);
 74.1513 +        unindent();
 74.1514 +    }
 74.1515 +    void visitFunctionTypeStatement(FunctionTypeStatement *node) {
 74.1516 +        prefix();
 74.1517 +        fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->name()->chars());
 74.1518 +        indent();
 74.1519 +        dump(node->signature());
 74.1520 +        unindent();
 74.1521 +    }
 74.1522 +    void visitFunctionStatement(FunctionStatement *node) {
 74.1523 +        prefix();
 74.1524 +        fprintf(fp_, "[ FunctionStatement (%s)\n", node->name()->chars());
 74.1525 +        indent();
 74.1526 +        dump(node->signature());
 74.1527 +        if (node->body())
 74.1528 +            node->body()->accept(this);
 74.1529 +        unindent();
 74.1530 +    }
 74.1531 +    void visitExpressionStatement(ExpressionStatement *node) {
 74.1532 +        prefix();
 74.1533 +        fprintf(fp_, "[ ExpressionStatement\n");
 74.1534 +        indent();
 74.1535 +        node->expression()->accept(this);
 74.1536 +        unindent();
 74.1537 +    }
 74.1538 +    void visitAssignment(Assignment *node) {
 74.1539 +        prefix();
 74.1540 +        fprintf(fp_, "[ Assignment\n");
 74.1541 +        indent();
 74.1542 +        node->lvalue()->accept(this);
 74.1543 +        node->expression()->accept(this);
 74.1544 +        unindent();
 74.1545 +    }
 74.1546 +    void visitTernaryExpression(TernaryExpression *node) {
 74.1547 +        prefix();
 74.1548 +        fprintf(fp_, "[ TernaryExpression\n");
 74.1549 +        indent();
 74.1550 +        node->condition()->accept(this);
 74.1551 +        node->left()->accept(this);
 74.1552 +        node->right()->accept(this);
 74.1553 +        unindent();
 74.1554 +    }
 74.1555 +    void visitBinaryExpression(BinaryExpression *node) {
 74.1556 +        prefix();
 74.1557 +        fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]);
 74.1558 +        indent();
 74.1559 +        node->left()->accept(this);
 74.1560 +        node->right()->accept(this);
 74.1561 +        unindent();
 74.1562 +    }
 74.1563 +    void visitUnaryExpression(UnaryExpression *node) {
 74.1564 +        prefix();
 74.1565 +        fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]);
 74.1566 +        indent();
 74.1567 +        node->expression()->accept(this);
 74.1568 +        unindent();
 74.1569 +    }
 74.1570 +    void visitReturnStatement(ReturnStatement *node) {
 74.1571 +        prefix();
 74.1572 +        fprintf(fp_, "[ ReturnStatement\n");
 74.1573 +        indent();
 74.1574 +        if (node->expression())
 74.1575 +            node->expression()->accept(this);
 74.1576 +        unindent();
 74.1577 +    }
 74.1578 +    void visitForStatement(ForStatement *node) {
 74.1579 +        prefix();
 74.1580 +        fprintf(fp_, "[ ForStatement\n");
 74.1581 +        indent();
 74.1582 +        if (node->initialization())
 74.1583 +            node->initialization()->accept(this);
 74.1584 +        if (node->condition())
 74.1585 +            node->condition()->accept(this);
 74.1586 +        if (node->update())
 74.1587 +            node->update()->accept(this);
 74.1588 +        node->body()->accept(this);
 74.1589 +        unindent();
 74.1590 +    }
 74.1591 +    void visitBlockStatement(BlockStatement *node) {
 74.1592 +        prefix();
 74.1593 +        fprintf(fp_, "[ BlockStatement\n");
 74.1594 +        indent();
 74.1595 +        for (size_t i = 0; i < node->statements()->length(); i++)
 74.1596 +            node->statements()->at(i)->accept(this);
 74.1597 +        unindent();
 74.1598 +    }
 74.1599 +    void visitVariableDeclaration(VariableDeclaration *node) {
 74.1600 +        prefix();
 74.1601 +        fprintf(fp_, "[ VariableDeclaration (%s)\n", node->name()->chars());
 74.1602 +        indent();
 74.1603 +        if (node->initialization())
 74.1604 +            node->initialization()->accept(this);
 74.1605 +        unindent();
 74.1606 +    }
 74.1607 +    void visitIntegerLiteral(IntegerLiteral *node) {
 74.1608 +        prefix();
 74.1609 +        fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value());
 74.1610 +    }
 74.1611 +    void visitBooleanLiteral(BooleanLiteral *node) {
 74.1612 +        prefix();
 74.1613 +        fprintf(fp_, "[ BooleanLiteral (%s)\n",
 74.1614 +                (node->token() == TOK_TRUE) ? "true" : "false");
 74.1615 +    }
 74.1616 +    void visitFloatLiteral(FloatLiteral *node) {
 74.1617 +        prefix();
 74.1618 +        fprintf(fp_, "[ FloatLiteral (%f)\n", node->value());
 74.1619 +    }
 74.1620 +    void visitIfStatement(IfStatement *node) {
 74.1621 +        prefix();
 74.1622 +        fprintf(fp_, "[ IfStatement\n");
 74.1623 +        indent();
 74.1624 +        node->ifTrue()->accept(this);
 74.1625 +        if (node->ifFalse())
 74.1626 +            node->ifFalse()->accept(this);
 74.1627 +        unindent();
 74.1628 +    }
 74.1629 +    void visitIndexExpression(IndexExpression *node) {
 74.1630 +        prefix();
 74.1631 +        fprintf(fp_, "[ IndexExpression\n");
 74.1632 +        indent();
 74.1633 +        node->left()->accept(this);
 74.1634 +        node->right()->accept(this);
 74.1635 +        unindent();
 74.1636 +    }
 74.1637 +    void visitEnumStatement(EnumStatement *node) {
 74.1638 +        prefix();
 74.1639 +        fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : "<anonymous>");
 74.1640 +        indent();
 74.1641 +        for (size_t i = 0; i < node->entries()->length(); i++) {
 74.1642 +            prefix();
 74.1643 +            fprintf(fp_, "%s =\n", node->entries()->at(i).name->chars());
 74.1644 +            if (node->entries()->at(i).expr) {
 74.1645 +                indent();
 74.1646 +                node->entries()->at(i).expr->accept(this);
 74.1647 +                unindent();
 74.1648 +            }
 74.1649 +        }
 74.1650 +        unindent();
 74.1651 +    }
 74.1652 +    void visitWhileStatement(WhileStatement *node) {
 74.1653 +        prefix();
 74.1654 +        fprintf(fp_, "[ WhileStatement (%s)\n",
 74.1655 +                (node->token() == TOK_DO) ? "do" : "while");
 74.1656 +        indent();
 74.1657 +        if (node->token() == TOK_DO) {
 74.1658 +            node->condition()->accept(this);
 74.1659 +            node->body()->accept(this);
 74.1660 +        } else {
 74.1661 +            node->condition()->accept(this);
 74.1662 +            node->body()->accept(this);
 74.1663 +        }
 74.1664 +        unindent();
 74.1665 +    }
 74.1666 +    void visitBreakStatement(BreakStatement *node) {
 74.1667 +        prefix();
 74.1668 +        fprintf(fp_, "[ BreakStatement\n");
 74.1669 +    }
 74.1670 +    void visitContinueStatement(ContinueStatement *node) {
 74.1671 +        prefix();
 74.1672 +        fprintf(fp_, "[ ContinueStatement\n");
 74.1673 +    }
 74.1674 +    void visitStringLiteral(StringLiteral *node) {
 74.1675 +        prefix();
 74.1676 +        fprintf(fp_, "[ StringLiteral\n");
 74.1677 +    }
 74.1678 +    void visitIncDecExpression(IncDecExpression *node) {
 74.1679 +        prefix();
 74.1680 +        fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix());
 74.1681 +        indent();
 74.1682 +        node->expression()->accept(this);
 74.1683 +        unindent();
 74.1684 +    }
 74.1685 +    void visitStructureStatement(StructureStatement *node) {
 74.1686 +        prefix();
 74.1687 +        fprintf(fp_, "[ StructureStatement %s\n", node->name()->chars());
 74.1688 +    }
 74.1689 +    void visitFieldExpression(FieldExpression *node) {
 74.1690 +        prefix();
 74.1691 +        fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars());
 74.1692 +        indent();
 74.1693 +        node->left()->accept(this);
 74.1694 +        unindent();
 74.1695 +    }
 74.1696 +    void visitSwitchStatement(SwitchStatement *node) {
 74.1697 +        prefix();
 74.1698 +        fprintf(fp_, "[ SwitchStatement\n");
 74.1699 +        indent();
 74.1700 +        node->expression()->accept(this);
 74.1701 +        for (size_t i = 0; i < node->cases()->length(); i++) {
 74.1702 +            Case *c = node->cases()->at(i);
 74.1703 +            c->expression()->accept(this);
 74.1704 +            if (c->others()) {
 74.1705 +                for (size_t j = 0; j < c->others()->length(); j++)
 74.1706 +                    c->others()->at(j)->accept(this);
 74.1707 +            }
 74.1708 +            indent();
 74.1709 +            c->statement()->accept(this);
 74.1710 +            unindent();
 74.1711 +        }
 74.1712 +        if (node->defaultCase())
 74.1713 +            node->defaultCase()->accept(this);
 74.1714 +        unindent();
 74.1715 +    }
 74.1716 +    void visitArrayLiteral(ArrayLiteral *node) {
 74.1717 +        prefix();
 74.1718 +        fprintf(fp_, "[ ArrayLiteral\n");
 74.1719 +        indent();
 74.1720 +        for (size_t i = 0; i < node->expressions()->length(); i++) {
 74.1721 +            Expression *expr = node->expressions()->at(i);
 74.1722 +            indent();
 74.1723 +            expr->accept(this);
 74.1724 +            unindent();
 74.1725 +        }
 74.1726 +    }
 74.1727 +    void visitImportStatement(ImportStatement *node) {
 74.1728 +        prefix();
 74.1729 +        fprintf(fp_, "[ ImportStatement\n");
 74.1730 +    }
 74.1731 +};
 74.1732 +
 74.1733 +void
 74.1734 +ParseTree::dump(FILE *fp)
 74.1735 +{
 74.1736 +    AstPrinter printer(fp);
 74.1737 +
 74.1738 +    for (size_t i = 0; i < statements_->length(); i++)
 74.1739 +        statements_->at(i)->accept(&printer);
 74.1740 +}
    75.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    75.2 +++ b/src/compiler/Parser.h	Sat Nov 17 18:41:01 2012 -0800
    75.3 @@ -0,0 +1,108 @@
    75.4 +/* vim: set ts=4 sw=4 tw=99 et:
    75.5 + *
    75.6 + * Copyright (C) 2012 David Anderson
    75.7 + *
    75.8 + * This file is part of SourcePawn.
    75.9 + *
   75.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   75.11 + * the terms of the GNU General Public License as published by the Free
   75.12 + * Software Foundation, either version 3 of the License, or (at your option)
   75.13 + * any later version.
   75.14 + * 
   75.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   75.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   75.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   75.18 + *
   75.19 + * You should have received a copy of the GNU General Public License along with
   75.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   75.21 + */
   75.22 +#ifndef _include_jitcraft_parser_h_
   75.23 +#define _include_jitcraft_parser_h_
   75.24 +
   75.25 +#include <stdio.h>
   75.26 +#include "../Strings.h"
   75.27 +#include "AST.h"
   75.28 +#include "Scanner.h"
   75.29 +#include "Scopes.h"
   75.30 +
   75.31 +namespace ke {
   75.32 +
   75.33 +class Parser
   75.34 +{
   75.35 +    Zone *zone_;
   75.36 +    CompileContext &cc_;
   75.37 +    PoolAllocator &pool_;
   75.38 +    Scanner scanner_;
   75.39 +    PoolList<NameProxy *> *unbound_;
   75.40 +    PoolList<ImportStatement *> *imports_;
   75.41 +    bool encounteredReturn_;
   75.42 +
   75.43 +  private:
   75.44 +    bool peek(TokenKind kind);
   75.45 +    bool match(TokenKind kind);
   75.46 +    bool expect(TokenKind kind);
   75.47 +    bool matchSemicolon();
   75.48 +
   75.49 +    enum DeclKind {
   75.50 +        DeclArg,
   75.51 +        DeclFun,
   75.52 +        DeclField
   75.53 +    };
   75.54 +
   75.55 +    VariableDeclaration *var(TypeQualifiers qual);
   75.56 +    Statement *vars(TypeQualifiers qual);
   75.57 +    bool matchName(String **name, TokenKind kind = TOK_NAME);
   75.58 +    bool typeAndName(Expression **type, String **namep);
   75.59 +    bool fullTypeAndName(Expression **type, String **namep, DeclKind kind);
   75.60 +
   75.61 +    ExpressionList *dimensions();
   75.62 +    String *expectName();
   75.63 +
   75.64 +    Expression *primitive();
   75.65 +    Expression *arrayLiteral(TokenKind kind);
   75.66 +    Expression *call(Expression *callee);
   75.67 +    Expression *field(Expression *left);
   75.68 +    Expression *index(Expression *left);
   75.69 +    Expression *prefix();
   75.70 +    Expression *primary();
   75.71 +    Expression *unary();
   75.72 +    Expression *multiplication();
   75.73 +    Expression *addition();
   75.74 +    Expression *shift();
   75.75 +    Expression *bitand_();
   75.76 +    Expression *bitxor();
   75.77 +    Expression *bitor_();
   75.78 +    Expression *relational();
   75.79 +    Expression *equals();
   75.80 +    Expression *and_();
   75.81 +    Expression *or_();
   75.82 +    Expression *ternary();
   75.83 +    Expression *assignment();
   75.84 +    Expression *expression();
   75.85 +
   75.86 +    Statement *switch_();
   75.87 +    Statement *struct_();
   75.88 +    Statement *enum_();
   75.89 +    Statement *if_();
   75.90 +    Statement *block();
   75.91 +    Statement *function(TokenKind tok);
   75.92 +    Statement *expressionStatement();
   75.93 +    Statement *while_();
   75.94 +    Statement *do_();
   75.95 +    Statement *forStatement();
   75.96 +    Statement *localStatement();
   75.97 +    Statement *globalStatement();
   75.98 +    Statement *returnStatement();
   75.99 +    ImportStatement *import();
  75.100 +
  75.101 +    bool setupIntrinsics();
  75.102 +
  75.103 +  public:
  75.104 +    Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length);
  75.105 +
  75.106 +    ParseTree *parse();
  75.107 +};
  75.108 +
  75.109 +}
  75.110 +
  75.111 +#endif // _include_jitcraft_parser_h_
    76.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    76.2 +++ b/src/compiler/Scanner.cpp	Sat Nov 17 18:41:01 2012 -0800
    76.3 @@ -0,0 +1,681 @@
    76.4 +/* vim: set ts=4 sw=4 tw=99 et:
    76.5 + *
    76.6 + * Copyright (C) 2012 David Anderson
    76.7 + *
    76.8 + * This file is part of JITCraft.
    76.9 + *
   76.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   76.11 + * the terms of the GNU General Public License as published by the Free
   76.12 + * Software Foundation, either version 3 of the License, or (at your option)
   76.13 + * any later version.
   76.14 + * 
   76.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   76.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   76.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   76.18 + *
   76.19 + * You should have received a copy of the GNU General Public License along with
   76.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   76.21 + */
   76.22 +#include <assert.h>
   76.23 +#include <ctype.h>
   76.24 +#include <math.h>
   76.25 +#include <limits.h>
   76.26 +#include <string.h>
   76.27 +#include "../Utility.h"
   76.28 +#include "Scanner.h"
   76.29 +
   76.30 +using namespace ke;
   76.31 +
   76.32 +const char *ke::TokenNames[] =
   76.33 +{
   76.34 +#define _(name, str) str,
   76.35 +    TOKENMAP(_)
   76.36 +#undef _
   76.37 +    NULL
   76.38 +};
   76.39 +
   76.40 +Scanner::Scanner(CompileContext &cc, const char *stream, size_t length)
   76.41 +  : cc_(cc),
   76.42 +    stream_(stream),
   76.43 +    length_(length),
   76.44 +    pushed_(false),
   76.45 +    allowTags_(true),
   76.46 +    saved_('\0'),
   76.47 +    pos_(stream_)
   76.48 +{
   76.49 +    cur_.line = 1;
   76.50 +    cur_.col = 1;
   76.51 +    last_ = cur_;
   76.52 +}
   76.53 +
   76.54 +char
   76.55 +Scanner::getChar()
   76.56 +{
   76.57 +    if (saved_ != '\0') {
   76.58 +        char temp = saved_;
   76.59 +        saved_ = '\0';
   76.60 +        return temp;
   76.61 +    }
   76.62 +    if (pos_ >= stream_ + length_)
   76.63 +        return '\0';
   76.64 +    last_.col = cur_.col++;
   76.65 +    return *pos_++;
   76.66 +}
   76.67 +
   76.68 +void
   76.69 +Scanner::putChar(char c)
   76.70 +{
   76.71 +    assert(saved_ == '\0');
   76.72 +    saved_ = c;
   76.73 +    cur_.col = last_.col;
   76.74 +}
   76.75 +
   76.76 +void
   76.77 +Scanner::calcNewLine(char c)
   76.78 +{
   76.79 +    cur_.line++;
   76.80 +    cur_.col = 1;
   76.81 +    last_ = cur_;
   76.82 +
   76.83 +    char o;
   76.84 +    if (c == '\r' && ((o = getChar()) != '\n'))
   76.85 +        putChar(o);
   76.86 +}
   76.87 +
   76.88 +void
   76.89 +Scanner::eatSingleLine()
   76.90 +{
   76.91 +    char c;
   76.92 +    while ((c = getChar()) != '\0') {
   76.93 +        if (c == '\n' || c == '\r') {
   76.94 +            calcNewLine(c);
   76.95 +            break;
   76.96 +        }
   76.97 +    }
   76.98 +}
   76.99 +
  76.100 +bool
  76.101 +Scanner::eatComment()
  76.102 +{
  76.103 +    char c;
  76.104 +
  76.105 +    while ((c = getChar()) != '\0') {
  76.106 +        while (c == '*') {
  76.107 +            c = getChar();
  76.108 +            if (c == '\0')
  76.109 +                return false;
  76.110 +            if (c == '/')
  76.111 +                return true;
  76.112 +        }
  76.113 +        if (c == '\r' || c == '\n')
  76.114 +            calcNewLine(c);
  76.115 +    }
  76.116 +
  76.117 +    return false;
  76.118 +}
  76.119 +
  76.120 +static inline bool
  76.121 +IsDigit(char c)
  76.122 +{
  76.123 +    return c >= '0' && c <= '9';
  76.124 +}
  76.125 +
  76.126 +// Based off the logic in sc2.c's ftoi()...
  76.127 +double
  76.128 +Scanner::ParseDouble(const char *string)
  76.129 +{
  76.130 +    const char *ptr = string;
  76.131 +
  76.132 +    double number = 0.0;
  76.133 +    while (IsDigit(*ptr)) {
  76.134 +        number = (number * 10) + (*ptr - '0');
  76.135 +        ptr++;
  76.136 +    }
  76.137 +
  76.138 +    assert(*ptr == '.');
  76.139 +    ptr++;
  76.140 +
  76.141 +    double fraction = 0.0;
  76.142 +    double multiplier = 1.0;
  76.143 +    while (IsDigit(*ptr)) {
  76.144 +        fraction = (fraction * 10) + (*ptr - '0');
  76.145 +        multiplier = multiplier / 10.0;
  76.146 +        ptr++;
  76.147 +    }
  76.148 +
  76.149 +    number += fraction * multiplier;
  76.150 +
  76.151 +    if (*ptr++ == 'e') {
  76.152 +        int sign = 1;
  76.153 +        if (*ptr == '-') {
  76.154 +            sign = -1;
  76.155 +            ptr++;
  76.156 +        }
  76.157 +
  76.158 +        int exponent = 0;
  76.159 +        while (IsDigit(*ptr)) {
  76.160 +            exponent = (exponent * 10) + (*ptr - '0');
  76.161 +            ptr++;
  76.162 +        }
  76.163 +
  76.164 +        multiplier = pow(10.0, exponent * sign);
  76.165 +        number *= multiplier;
  76.166 +    }
  76.167 +
  76.168 +    return number;
  76.169 +}
  76.170 +
  76.171 +static inline bool
  76.172 +IsHexDigit(char c)
  76.173 +{
  76.174 +    return IsDigit(c) ||
  76.175 +           (c >= 'a' && c <= 'f') ||
  76.176 +           (c >= 'A' && c <= 'F');
  76.177 +}
  76.178 +
  76.179 +// Based on the logic for litchar() in sc2.c.
  76.180 +int
  76.181 +Scanner::readEscapeCode()
  76.182 +{
  76.183 +    char c = getChar();
  76.184 +    if (c == '\\')
  76.185 +        return c;
  76.186 +
  76.187 +    switch (c) {
  76.188 +      case 'a':
  76.189 +        return '\a';
  76.190 +      case 'b':
  76.191 +        return '\b';
  76.192 +      case 'e':
  76.193 +        return 27;          // Apparently \e is non-standard.
  76.194 +      case 'f':
  76.195 +        return '\f';
  76.196 +      case 'n':
  76.197 +        return '\n';
  76.198 +      case 'r':
  76.199 +        return '\r';
  76.200 +      case 't':
  76.201 +        return '\t';
  76.202 +      case '\v':
  76.203 +        return '\v';
  76.204 +
  76.205 +      case 'x':
  76.206 +      {
  76.207 +          unsigned digits = 0;
  76.208 +          char r = 0;
  76.209 +  
  76.210 +          c = getChar();
  76.211 +          while (IsHexDigit(c) && digits < 2) {
  76.212 +              if (IsDigit(c))
  76.213 +                  c = (c << 4) + (c - '0');
  76.214 +              else
  76.215 +                  c = (c << 4) + (tolower(c) - 'a' + 10);
  76.216 +              digits++;
  76.217 +              c = getChar();
  76.218 +           }
  76.219 +                
  76.220 +          // Swallow a trailing ';'
  76.221 +          if (c != ';')
  76.222 +              putChar(c);
  76.223 +  
  76.224 +          return r;
  76.225 +      }
  76.226 +
  76.227 +      case '\'':
  76.228 +      case '\"':
  76.229 +      case '%':
  76.230 +        return c;
  76.231 +
  76.232 +      default:
  76.233 +      {
  76.234 +        if (IsDigit(c)) {
  76.235 +            // \ddd
  76.236 +            char r = 0;
  76.237 +            while (IsDigit(c)) {
  76.238 +                r = r * 10 + (c - '0');
  76.239 +                c = getChar();
  76.240 +            }
  76.241 +
  76.242 +            // Swallow a trailing ;
  76.243 +            if (c != ';')
  76.244 +                putChar(c);
  76.245 +
  76.246 +            return r;
  76.247 +        }
  76.248 +        cc_.reportError(begin(), Message_UnknownEscapeCode, c);
  76.249 +        return INT_MAX;
  76.250 +      }
  76.251 +    }
  76.252 +}
  76.253 +
  76.254 +TokenKind
  76.255 +Scanner::stringLiteral()
  76.256 +{
  76.257 +    literal_.clear();
  76.258 +
  76.259 +    for (;;) {
  76.260 +        char c = getChar();
  76.261 +        if (c == '\"')
  76.262 +            break;
  76.263 +        if (c == '\r' || c == '\n' || c == '\0') {
  76.264 +            cc_.reportError(begin(), Message_UnterminatedString);
  76.265 +            return TOK_ERROR;
  76.266 +        }
  76.267 +        if (c == '\\') {
  76.268 +            int code = readEscapeCode();
  76.269 +            if (code == INT_MAX)
  76.270 +                return TOK_ERROR;
  76.271 +            c = char(code);
  76.272 +        }
  76.273 +        if (!literal_.append(c))
  76.274 +            return TOK_ERROR;
  76.275 +    }
  76.276 +
  76.277 +    if (!literal_.append('\0'))
  76.278 +        return TOK_ERROR;
  76.279 +
  76.280 +    return TOK_STRING_LITERAL;
  76.281 +}
  76.282 +
  76.283 +TokenKind
  76.284 +Scanner::hexLiteral()
  76.285 +{
  76.286 +    literal_.clear();
  76.287 +
  76.288 +    char c;
  76.289 +    for (;;) {
  76.290 +        c = getChar();
  76.291 +        if (!IsHexDigit(c))
  76.292 +            break;
  76.293 +        if (!literal_.append(c))
  76.294 +            return TOK_ERROR;
  76.295 +    }
  76.296 +
  76.297 +    putChar(c);
  76.298 +
  76.299 +    if (!literal_.append('\0'))
  76.300 +        return TOK_ERROR;
  76.301 +    return TOK_HEX_LITERAL;
  76.302 +}
  76.303 +
  76.304 +TokenKind
  76.305 +Scanner::numberLiteral(char first)
  76.306 +{
  76.307 +    literal_.clear();
  76.308 +    if (!literal_.append(first))
  76.309 +        return TOK_ERROR;
  76.310 +
  76.311 +    char c;
  76.312 +    for (;;) {
  76.313 +        c = getChar();
  76.314 +        if (!IsDigit(c))
  76.315 +            break;
  76.316 +        if (!literal_.append(c))
  76.317 +            return TOK_ERROR;
  76.318 +    }
  76.319 +
  76.320 +    // Detect a hexadecimal string.
  76.321 +    if (literal_.length() == 1 &&
  76.322 +        literal_[0] == '0' &&
  76.323 +        (c == 'x' || c == 'X'))
  76.324 +    {
  76.325 +        return hexLiteral();
  76.326 +    }
  76.327 +
  76.328 +    if (c != '.') {
  76.329 +        putChar(c);
  76.330 +        if (!literal_.append('\0'))
  76.331 +            return TOK_ERROR;
  76.332 +        return TOK_INTEGER_LITERAL;
  76.333 +    }
  76.334 +    if (!literal_.append(c))
  76.335 +        return TOK_ERROR;
  76.336 +
  76.337 +    c = getChar();
  76.338 +    if (!IsDigit(c)) {
  76.339 +        cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
  76.340 +        return TOK_ERROR;
  76.341 +    }
  76.342 +    if (!literal_.append(c))
  76.343 +        return TOK_ERROR;
  76.344 +
  76.345 +    for (;;) {
  76.346 +        c = getChar();
  76.347 +        if (!IsDigit(c))
  76.348 +            break;
  76.349 +        if (!literal_.append(c))
  76.350 +            return TOK_ERROR;
  76.351 +    }
  76.352 +
  76.353 +    if (c != 'e') {
  76.354 +        putChar(c);
  76.355 +    } else {
  76.356 +        if (!literal_.append(c))
  76.357 +            return TOK_ERROR;
  76.358 +        c = getChar();
  76.359 +        if (c == '-') {
  76.360 +            if (!literal_.append(c))
  76.361 +                return TOK_ERROR;
  76.362 +            c = getChar();
  76.363 +        }
  76.364 +        if (!IsDigit(c)) {
  76.365 +            cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
  76.366 +            return TOK_ERROR;
  76.367 +        }
  76.368 +        if (!literal_.append(c))
  76.369 +            return TOK_ERROR;
  76.370 +        for (;;) {
  76.371 +            c = getChar();
  76.372 +            if (!IsDigit(c)) {
  76.373 +                putChar(c);
  76.374 +                break;
  76.375 +            }
  76.376 +            if (!literal_.append(c))
  76.377 +                return TOK_ERROR;
  76.378 +        }
  76.379 +    }
  76.380 +
  76.381 +    if (!literal_.append('\0'))
  76.382 +        return TOK_ERROR;
  76.383 +
  76.384 +    return TOK_FLOAT_LITERAL;
  76.385 +}
  76.386 +
  76.387 +static inline TokenKind
  76.388 +FindIdentifier(const char *str)
  76.389 +{
  76.390 +    if (!strcmp(str,  "new"))
  76.391 +        return TOK_NEW;
  76.392 +    if (!strcmp(str,  "for"))
  76.393 +        return TOK_FOR;
  76.394 +    if (!strcmp(str,  "return"))
  76.395 +        return TOK_RETURN;
  76.396 +    if (!strcmp(str,  "if"))
  76.397 +        return TOK_IF;
  76.398 +    if (!strcmp(str,  "else"))
  76.399 +        return TOK_ELSE;
  76.400 +    if (!strcmp(str,  "enum"))
  76.401 +        return TOK_ENUM;
  76.402 +    if (!strcmp(str,  "while"))
  76.403 +        return TOK_WHILE;
  76.404 +    if (!strcmp(str,  "do"))
  76.405 +        return TOK_DO;
  76.406 +    if (!strcmp(str,  "break"))
  76.407 +        return TOK_BREAK;
  76.408 +    if (!strcmp(str,  "continue"))
  76.409 +        return TOK_CONTINUE;
  76.410 +    if (!strcmp(str,  "forward"))
  76.411 +        return TOK_FORWARD;
  76.412 +    if (!strcmp(str,  "public"))
  76.413 +        return TOK_PUBLIC;
  76.414 +    if (!strcmp(str,  "const"))
  76.415 +        return TOK_CONST;
  76.416 +    if (!strcmp(str,  "native"))
  76.417 +        return TOK_NATIVE;
  76.418 +    if (!strcmp(str,  "stock"))
  76.419 +        return TOK_STOCK;
  76.420 +    if (!strcmp(str,  "true"))
  76.421 +        return TOK_TRUE;
  76.422 +    if (!strcmp(str,  "false"))
  76.423 +        return TOK_FALSE;
  76.424 +    if (!strcmp(str,  "struct"))
  76.425 +        return TOK_STRUCT;
  76.426 +    if (!strcmp(str,  "switch"))
  76.427 +        return TOK_SWITCH;
  76.428 +    if (!strcmp(str,  "case"))
  76.429 +        return TOK_CASE;
  76.430 +    if (!strcmp(str,  "default"))
  76.431 +        return TOK_DEFAULT;
  76.432 +    if (!strcmp(str,  "typedef"))
  76.433 +        return TOK_TYPEDEF;
  76.434 +    if (!strcmp(str,  "void"))
  76.435 +        return TOK_VOID;
  76.436 +    if (!strcmp(str,  "int"))
  76.437 +        return TOK_INT;
  76.438 +    if (!strcmp(str,  "sizeof"))
  76.439 +        return TOK_SIZEOF;
  76.440 +    if (!strcmp(str,  "import"))
  76.441 +        return TOK_IMPORT;
  76.442 +    return TOK_NONE;
  76.443 +}
  76.444 +
  76.445 +TokenKind
  76.446 +Scanner::identifier(char first)
  76.447 +{
  76.448 +    literal_.clear();
  76.449 +    if (!literal_.append(first))
  76.450 +        return TOK_ERROR;
  76.451 +
  76.452 +    char c;
  76.453 +    for (;;) {
  76.454 +        c = getChar();
  76.455 +        if (!isascii(c) || (!isalnum(c) && c != '_'))
  76.456 +            break;
  76.457 +        if (!literal_.append(c))
  76.458 +            return TOK_ERROR;
  76.459 +    }
  76.460 +    
  76.461 +    if (!literal_.append('\0'))
  76.462 +        return TOK_ERROR;
  76.463 +
  76.464 +    // Most keywords do not act as labels.
  76.465 +    TokenKind kind = FindIdentifier(literal());
  76.466 +    if (kind != TOK_NONE) {
  76.467 +        putChar(c);
  76.468 +        return kind;
  76.469 +    }
  76.470 +
  76.471 +    if (c == ':' && allowTags_)
  76.472 +        return TOK_LABEL;
  76.473 +
  76.474 +    putChar(c);
  76.475 +
  76.476 +    // _ is a special case which acts as a tag and a keyword.
  76.477 +    if (!strcmp(literal(), "_"))
  76.478 +        return TOK_UNDERSCORE;
  76.479 +
  76.480 +    return TOK_NAME;
  76.481 +}
  76.482 +
  76.483 +TokenKind
  76.484 +Scanner::next()
  76.485 +{
  76.486 +    assert(!pushed_);
  76.487 +
  76.488 +    for (;;) {
  76.489 +        begin_ = cur_;
  76.490 +
  76.491 +        char c = getChar();
  76.492 +        switch (c) {
  76.493 +          case '/':
  76.494 +          {
  76.495 +            c = getChar();
  76.496 +            if (c == '/') {
  76.497 +                eatSingleLine();
  76.498 +                break;
  76.499 +            }
  76.500 +            if (c == '*') {
  76.501 +                if (!eatComment()) {
  76.502 +                    cc_.reportError(begin(), Message_UnterminatedComment);
  76.503 +                    return TOK_ERROR;
  76.504 +                }
  76.505 +                break;
  76.506 +            }
  76.507 +            putChar(c);
  76.508 +            return TOK_SLASH;
  76.509 +          }
  76.510 +
  76.511 +          case '\n':
  76.512 +          case '\r':
  76.513 +            calcNewLine(c);
  76.514 +            break;
  76.515 +
  76.516 +          case ';': return TOK_SEMICOLON;
  76.517 +          case '{': return TOK_LBRACE;
  76.518 +          case '}': return TOK_RBRACE;
  76.519 +          case '(': return TOK_LPAREN;
  76.520 +          case ')': return TOK_RPAREN;
  76.521 +          case '[': return TOK_LBRACKET;
  76.522 +          case ']': return TOK_RBRACKET;
  76.523 +          case '~': return TOK_TILDE;
  76.524 +          case '?': return TOK_QMARK;
  76.525 +          case ':': return TOK_COLON;
  76.526 +
  76.527 +          case '.':
  76.528 +            c = getChar();
  76.529 +            if (c == '.') {
  76.530 +                c = getChar();
  76.531 +                if (c == '.')
  76.532 +                    return TOK_ELLIPSES;
  76.533 +                cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
  76.534 +                return TOK_ERROR;
  76.535 +            }
  76.536 +            putChar(c);
  76.537 +            return TOK_DOT;
  76.538 +
  76.539 +          case '*':
  76.540 +            c = getChar();
  76.541 +            if (c == '=')
  76.542 +                return TOK_ASSIGN_MUL;
  76.543 +            putChar(c);
  76.544 +            return TOK_STAR;
  76.545 +
  76.546 +          case '+':
  76.547 +            c = getChar();
  76.548 +            if (c == '=')
  76.549 +                return TOK_ASSIGN_ADD;
  76.550 +            if (c == '+')
  76.551 +                return TOK_INCREMENT;
  76.552 +            putChar(c);
  76.553 +            return TOK_PLUS;
  76.554 +
  76.555 +          case '&':
  76.556 +            c = getChar();
  76.557 +            if (c == '=')
  76.558 +                return TOK_ASSIGN_BITAND;
  76.559 +            if (c == '&')
  76.560 +                return TOK_AND;
  76.561 +            putChar(c);
  76.562 +            return TOK_BITAND;
  76.563 +
  76.564 +          case '|':
  76.565 +            c = getChar();
  76.566 +            if (c == '=')
  76.567 +                return TOK_ASSIGN_BITOR;
  76.568 +            if (c == '|')
  76.569 +                return TOK_OR;
  76.570 +            putChar(c);
  76.571 +            return TOK_BITOR;
  76.572 +
  76.573 +          case '^':
  76.574 +            c = getChar();
  76.575 +            if (c == '=')
  76.576 +                return TOK_ASSIGN_BITXOR;
  76.577 +            putChar(c);
  76.578 +            return TOK_BITXOR;
  76.579 +
  76.580 +          case '%':
  76.581 +            c = getChar();
  76.582 +            if (c == '=')
  76.583 +                return TOK_ASSIGN_MOD;
  76.584 +            putChar(c);
  76.585 +            return TOK_PERCENT;
  76.586 +
  76.587 +          case '-':
  76.588 +            c = getChar();
  76.589 +            if (c == '=')
  76.590 +                return TOK_ASSIGN_SUB;
  76.591 +            if (c == '-')
  76.592 +                return TOK_DECREMENT;
  76.593 +            putChar(c);
  76.594 +            return TOK_MINUS;
  76.595 +
  76.596 +          case ',': return TOK_COMMA;
  76.597 +          case '\0': return TOK_EOF;
  76.598 +
  76.599 +          case '!':
  76.600 +            c = getChar();
  76.601 +            if (c == '=')
  76.602 +                return TOK_NOTEQUALS;
  76.603 +            putChar(c);
  76.604 +            return TOK_NOT;
  76.605 +
  76.606 +          case '=':
  76.607 +            c = getChar();
  76.608 +            if (c == '=')
  76.609 +                return TOK_EQUALS;
  76.610 +            putChar(c);
  76.611 +            return TOK_ASSIGN;
  76.612 +
  76.613 +
  76.614 +          case '<':
  76.615 +            c = getChar();
  76.616 +            if (c == '=')
  76.617 +                return TOK_LE;
  76.618 +            if (c == '<') {
  76.619 +                c = getChar();
  76.620 +                if (c == '=')
  76.621 +                    return TOK_ASSIGN_SHL;
  76.622 +                putChar(c);
  76.623 +                return TOK_SHL;
  76.624 +            }
  76.625 +            putChar(c);
  76.626 +            return TOK_LT;
  76.627 +
  76.628 +          case '>':
  76.629 +            c = getChar();
  76.630 +            if (c == '=')
  76.631 +                return TOK_GE;
  76.632 +            if (c == '>') {
  76.633 +                c = getChar();
  76.634 +                if (c == '>') {
  76.635 +                    c = getChar();
  76.636 +                    if (c == '=')
  76.637 +                        return TOK_ASSIGN_USHR;
  76.638 +                    putChar(c);
  76.639 +                    return TOK_USHR;
  76.640 +                }
  76.641 +                return TOK_SHR;
  76.642 +            }
  76.643 +            putChar(c);
  76.644 +            return TOK_GT;
  76.645 +
  76.646 +          case ' ':
  76.647 +          case '\t':
  76.648 +          case '\f':
  76.649 +            break;
  76.650 +
  76.651 +          case '"':
  76.652 +            return stringLiteral();
  76.653 +
  76.654 +          default:
  76.655 +            if (c >= '0' && c <= '9')
  76.656 +                return numberLiteral(c);
  76.657 +            if (c == '_' || (isascii(c) && isalpha(c)))
  76.658 +                return identifier(c);
  76.659 +            cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
  76.660 +            return TOK_ERROR;
  76.661 +        }
  76.662 +    }
  76.663 +}
  76.664 +
  76.665 +TokenKind
  76.666 +Scanner::scan()
  76.667 +{
  76.668 +    if (pushed_) {
  76.669 +        pushed_ = false;
  76.670 +        return lastToken_;
  76.671 +    }
  76.672 +    lastToken_ = next();
  76.673 +    return lastToken_;
  76.674 +}
  76.675 +
  76.676 +TokenKind
  76.677 +Scanner::peek()
  76.678 +{
  76.679 +    if (pushed_)
  76.680 +        return lastToken_;
  76.681 +    scan();
  76.682 +    pushed_ = true;
  76.683 +    return lastToken_;
  76.684 +}
    77.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    77.2 +++ b/src/compiler/Scanner.h	Sat Nov 17 18:41:01 2012 -0800
    77.3 @@ -0,0 +1,115 @@
    77.4 +/* vim: set ts=4 sw=4 tw=99 et:
    77.5 + *
    77.6 + * Copyright (C) 2012 David Anderson
    77.7 + *
    77.8 + * This file is part of SourcePawn.
    77.9 + *
   77.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   77.11 + * the terms of the GNU General Public License as published by the Free
   77.12 + * Software Foundation, either version 3 of the License, or (at your option)
   77.13 + * any later version.
   77.14 + * 
   77.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   77.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   77.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   77.18 + *
   77.19 + * You should have received a copy of the GNU General Public License along with
   77.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   77.21 + */
   77.22 +#ifndef _include_jitcraft_scanner_h_
   77.23 +#define _include_jitcraft_scanner_h_
   77.24 +
   77.25 +#include <string>
   77.26 +#include "Token.h"
   77.27 +#include "CompileContext.h"
   77.28 +#include "../Opcodes.h"
   77.29 +#include "../Vector.h"
   77.30 +
   77.31 +namespace ke {
   77.32 +
   77.33 +class Scanner
   77.34 +{
   77.35 +    template <bool Enabled>
   77.36 +    friend class AutoAllowTags;
   77.37 +
   77.38 +    CompileContext &cc_;
   77.39 +    const char *stream_;
   77.40 +    size_t length_;
   77.41 +    bool pushed_;
   77.42 +    bool allowTags_;
   77.43 +    char saved_;
   77.44 +    const char *pos_;
   77.45 +    Vector<char> literal_;
   77.46 +    TokenKind lastToken_;
   77.47 +    SourcePosition last_;
   77.48 +    SourcePosition cur_;
   77.49 +    SourcePosition begin_;
   77.50 +
   77.51 +  private:
   77.52 +    char getChar();
   77.53 +    void putChar(char c);
   77.54 +    void eatSingleLine();
   77.55 +    bool eatComment();
   77.56 +    void calcNewLine(char c);
   77.57 +    int readEscapeCode();
   77.58 +    TokenKind stringLiteral();
   77.59 +    TokenKind hexLiteral();
   77.60 +    TokenKind numberLiteral(char first);
   77.61 +    TokenKind identifier(char first);
   77.62 +
   77.63 +    TokenKind next();
   77.64 +
   77.65 +  public:
   77.66 +    Scanner(CompileContext &cc, const char *stream, size_t length);
   77.67 +
   77.68 +    static double ParseDouble(const char *string);
   77.69 +
   77.70 +    TokenKind scan();
   77.71 +    TokenKind peek();
   77.72 +    TokenKind last() const {
   77.73 +        return lastToken_;
   77.74 +    }
   77.75 +
   77.76 +    bool tagsEnabled() const {
   77.77 +        return allowTags_;
   77.78 +    }
   77.79 +    void setTagsEnabled(bool enabled) {
   77.80 +        allowTags_ = enabled;
   77.81 +    }
   77.82 +
   77.83 +    // Beginning source position of the last instruction.
   77.84 +    SourcePosition begin() const {
   77.85 +        return begin_;
   77.86 +    }
   77.87 +
   77.88 +    // Note: the literal may have embedded NUL characters.
   77.89 +    const char *literal() const {
   77.90 +        return literal_.buffer();
   77.91 +    }
   77.92 +    size_t literal_length() const {
   77.93 +        return literal_.length() - 1;
   77.94 +    }
   77.95 +};
   77.96 +
   77.97 +template <bool Enabled>
   77.98 +class AutoAllowTags
   77.99 +{
  77.100 +    Scanner &scanner_;
  77.101 +    bool prev_;
  77.102 +
  77.103 +  public:
  77.104 +    AutoAllowTags(Scanner &scanner)
  77.105 +      : scanner_(scanner),
  77.106 +        prev_(scanner_.tagsEnabled())
  77.107 +    {
  77.108 +        scanner_.setTagsEnabled(Enabled);
  77.109 +    }
  77.110 +    ~AutoAllowTags()
  77.111 +    {
  77.112 +        scanner_.setTagsEnabled(prev_);
  77.113 +    }
  77.114 +};
  77.115 +
  77.116 +} // namespace ke
  77.117 +
  77.118 +#endif // _include_jitcraft_scanner_h_
    78.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    78.2 +++ b/src/compiler/Scopes.cpp	Sat Nov 17 18:41:01 2012 -0800
    78.3 @@ -0,0 +1,225 @@
    78.4 +/* vim: set ts=4 sw=4 tw=99 et:
    78.5 + *
    78.6 + * Copyright (C) 2012 David Anderson
    78.7 + *
    78.8 + * This file is part of JITCraft.
    78.9 + *
   78.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   78.11 + * the terms of the GNU General Public License as published by the Free
   78.12 + * Software Foundation, either version 3 of the License, or (at your option)
   78.13 + * any later version.
   78.14 + * 
   78.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   78.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   78.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   78.18 + *
   78.19 + * You should have received a copy of the GNU General Public License along with
   78.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   78.21 + */
   78.22 +#include "../Zone.h"
   78.23 +#include "../Types.h"
   78.24 +#include "../TypeManager.h"
   78.25 +#include "../Strings.h"
   78.26 +#include "../Environments.h"
   78.27 +#include "../Structures.h"
   78.28 +#include "CompileContext.h"
   78.29 +#include "Scopes.h"
   78.30 +#include "../Spaces-inl.h"
   78.31 +#include "../Heap-inl.h"
   78.32 +
   78.33 +using namespace ke;
   78.34 +
   78.35 +Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
   78.36 +  : pool_(pool),
   78.37 +    kind_(kind),
   78.38 +    enclosing_(enclosing)
   78.39 +{
   78.40 +}
   78.41 +
   78.42 +bool
   78.43 +Scope::initialize()
   78.44 +{
   78.45 +    if (enclosing_ && !enclosing_->children_.append(this))
   78.46 +        return false;
   78.47 +    return true;
   78.48 +}
   78.49 +
   78.50 +void
   78.51 +Scope::unlink()
   78.52 +{
   78.53 +    assert(empty());
   78.54 +
   78.55 +    assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
   78.56 +    enclosing_->children_.pop();
   78.57 +
   78.58 +    // OOM here is swallowed and checked after compilation.
   78.59 +    // :TODO: make the above true.
   78.60 +    for (size_t i = 0; i < children_.length(); i++)
   78.61 +        enclosing_->children_.append(children_[i]);
   78.62 +}
   78.63 +
   78.64 +Scope *
   78.65 +Scope::unlinkIfEmpty()
   78.66 +{
   78.67 +    if (empty()) {
   78.68 +        unlink();
   78.69 +        return NULL;
   78.70 +    }
   78.71 +    return this;
   78.72 +}
   78.73 +
   78.74 +Symbol *
   78.75 +Scope::localLookup(Handle<String> name)
   78.76 +{
   78.77 +    for (size_t i = 0; i < names_.length(); i++) {
   78.78 +        if (names_[i]->name() == name)
   78.79 +            return names_[i];
   78.80 +    }
   78.81 +    return NULL;
   78.82 +}
   78.83 +
   78.84 +Symbol  *
   78.85 +Scope::lookup(Handle<String> name)
   78.86 +{
   78.87 +    for (Scope *scope = this; scope; scope = scope->enclosing()) {
   78.88 +        if (Symbol *bound = scope->localLookup(name))
   78.89 +            return bound;
   78.90 +    }
   78.91 +    return NULL;
   78.92 +}
   78.93 +
   78.94 +#if 0
   78.95 +void
   78.96 +Scope::setUsesLifoHeap()
   78.97 +{
   78.98 +    // Only one lifo slot is needed per scope.
   78.99 +#if 0
  78.100 +    if (lifoSlot_)
  78.101 +        return;
  78.102 +#endif
  78.103 +
  78.104 +    // If the parent of this scope is the function scope, then this is the
  78.105 +    // function's block scope, and the lifo slot is part of the Frame instead.
  78.106 +    // Note we can get a function scope here if we're making a temporary in a
  78.107 +    // function with no local variables.
  78.108 +    if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
  78.109 +        return;
  78.110 +
  78.111 +    Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
  78.112 +    if (!type)
  78.113 +        return;
  78.114 +
  78.115 +    Local<String> name(ZONE());
  78.116 +#if 0
  78.117 +    lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
  78.118 +    lifoSlot_->setType(type);
  78.119 +#endif
  78.120 +}
  78.121 +#endif
  78.122 +
  78.123 +bool
  78.124 +Scope::addSymbol(Symbol *sym)
  78.125 +{
  78.126 +    return names_.append(sym);
  78.127 +}
  78.128 +
  78.129 +LocalScope::LocalScope(PoolAllocator &pool)
  78.130 +  : Scope(pool, Scope::BLOCK, NULL)
  78.131 +{
  78.132 +}
  78.133 +
  78.134 +LocalScope *
  78.135 +LocalScope::New(PoolAllocator &pool)
  78.136 +{
  78.137 +    LocalScope *scope = new (pool) LocalScope(pool);
  78.138 +    if (!scope->initialize())
  78.139 +        return NULL;
  78.140 +
  78.141 +    return scope;
  78.142 +}
  78.143 +
  78.144 +ArgumentScope::ArgumentScope(PoolAllocator &pool)
  78.145 +  : Scope(pool, Scope::FUNCTION, NULL)
  78.146 +{
  78.147 +}
  78.148 +
  78.149 +ArgumentScope *
  78.150 +ArgumentScope::New(PoolAllocator &pool)
  78.151 +{
  78.152 +    ArgumentScope *scope = new (pool) ArgumentScope(pool);
  78.153 +    if (!scope->initialize())
  78.154 +        return NULL;
  78.155 +
  78.156 +    return scope;
  78.157 +}
  78.158 +
  78.159 +GlobalScope::GlobalScope(PoolAllocator &pool, ImportScope *parent)
  78.160 +  : Scope(pool, Scope::GLOBAL, parent)
  78.161 +{
  78.162 +}
  78.163 +
  78.164 +GlobalScope *
  78.165 +GlobalScope::New(PoolAllocator &pool, ImportScope *parent)
  78.166 +{
  78.167 +    GlobalScope *scope = new (pool) GlobalScope(pool, parent);
  78.168 +    if (!scope->initialize())
  78.169 +        return NULL;
  78.170 +
  78.171 +    return scope;
  78.172 +}
  78.173 +
  78.174 +bool
  78.175 +GlobalScope::addPublic(Symbol *sym)
  78.176 +{
  78.177 +    return publics_.append(sym);
  78.178 +}
  78.179 +
  78.180 +Symbol *
  78.181 +GlobalScope::findPublic(Handle<String> name)
  78.182 +{
  78.183 +    for (size_t i = 0; i < publics_.length(); i++) {
  78.184 +        if (publics_[i]->name() == name)
  78.185 +            return publics_[i];
  78.186 +    }
  78.187 +    return NULL;
  78.188 +}
  78.189 +
  78.190 +Struct *
  78.191 +GlobalScope::build(Zone *zone)
  78.192 +{
  78.193 +    Local<FixedArray> descriptors(zone, FixedArray::New(zone, names_.length(), Heap::Tenure_Old));
  78.194 +
  78.195 +    for (size_t i = 0; i < names_.length(); i++) {
  78.196 +        Handle<String> name = names_[i]->name();
  78.197 +        Handle<Type> type = names_[i]->type();
  78.198 +        assert(type);
  78.199 +
  78.200 +        Local<Descriptor> desc(zone, Descriptor::New(zone, name, type));
  78.201 +        if (!desc)
  78.202 +            return NULL;
  78.203 +        
  78.204 +        descriptors->set(zone, i, desc);
  78.205 +    }
  78.206 +
  78.207 +    Local<StructType> type(zone, StructType::New(zone, Handle<String>::Null(), descriptors));
  78.208 +    if (!type)
  78.209 +        return NULL;
  78.210 +
  78.211 +    Local<StructMap> map(zone, type->newMap());
  78.212 +    return Struct::New(zone, map, Heap::Tenure_Old);
  78.213 +}
  78.214 +
  78.215 +ImportScope::ImportScope(PoolAllocator &pool)
  78.216 +  : Scope(pool, Scope::IMPORT, NULL)
  78.217 +{
  78.218 +}
  78.219 +
  78.220 +ImportScope *
  78.221 +ImportScope::New(PoolAllocator &pool)
  78.222 +{
  78.223 +    ImportScope *scope = new (pool) ImportScope(pool);
  78.224 +    if (!scope->initialize())
  78.225 +        return NULL;
  78.226 +
  78.227 +    return scope;
  78.228 +}
    79.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    79.2 +++ b/src/compiler/Scopes.h	Sat Nov 17 18:41:01 2012 -0800
    79.3 @@ -0,0 +1,126 @@
    79.4 +/*
    79.5 + * Copyright (C) 2012 David Anderson
    79.6 + *
    79.7 + * This file is part of JITCraft.
    79.8 + *
    79.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   79.10 + * the terms of the GNU General Public License as published by the Free
   79.11 + * Software Foundation, either version 3 of the License, or (at your option)
   79.12 + * any later version.
   79.13 + * 
   79.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   79.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   79.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   79.17 + *
   79.18 + * You should have received a copy of the GNU General Public License along with
   79.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   79.20 + */
   79.21 +#ifndef _include_jitcraft_scopes_h_
   79.22 +#define _include_jitcraft_scopes_h_
   79.23 +
   79.24 +#include "../PoolAllocator.h"
   79.25 +#include "../Structures.h"
   79.26 +#include "AST.h"
   79.27 +#include "NameBinding.h"
   79.28 +
   79.29 +namespace ke {
   79.30 +
   79.31 +class CompileContext;
   79.32 +class EnvironmentMap;
   79.33 +class Struct;
   79.34 +
   79.35 +class Scope : public PoolObject
   79.36 +{
   79.37 +  protected:
   79.38 +    PoolAllocator &pool_;
   79.39 +    PoolList<Symbol *> names_;
   79.40 +    PoolList<Scope *> children_;
   79.41 +    
   79.42 +    bool empty() const {
   79.43 +        return names_.length() == 0;
   79.44 +    }
   79.45 +    void unlink();
   79.46 +
   79.47 +  public:
   79.48 +    enum Kind {
   79.49 +        IMPORT,
   79.50 +        GLOBAL,
   79.51 +        FUNCTION,
   79.52 +        BLOCK
   79.53 +    };
   79.54 +
   79.55 +  public:
   79.56 +    Scope(PoolAllocator &pool, Kind kind, Scope *enclosing);
   79.57 +    bool initialize();
   79.58 +
   79.59 +    Kind kind() const {
   79.60 +        return kind_;
   79.61 +    }
   79.62 +    Scope *enclosing() const {
   79.63 +        return enclosing_;
   79.64 +    }
   79.65 +
   79.66 +    bool addSymbol(Symbol *symbol);
   79.67 +
   79.68 +    Scope *unlinkIfEmpty();
   79.69 +    Symbol *localLookup(Handle<String> name);
   79.70 +    Symbol *lookup(Handle<String> name);
   79.71 +
   79.72 +    EnvironmentMap *createEnvironmentMap(Zone *zone);
   79.73 +
   79.74 +    void setParent(Scope *parent) {
   79.75 +        assert(!enclosing_ || enclosing_ == parent);
   79.76 +        enclosing_ = parent;
   79.77 +    }
   79.78 +
   79.79 +  private:
   79.80 +    Kind kind_;
   79.81 +    Scope *enclosing_;
   79.82 +};
   79.83 +
   79.84 +class ArgumentScope : public Scope
   79.85 +{
   79.86 +  public:
   79.87 +    static ArgumentScope *New(PoolAllocator &pool);
   79.88 +
   79.89 +  private:
   79.90 +    ArgumentScope(PoolAllocator &pool);
   79.91 +};
   79.92 +
   79.93 +class LocalScope : public Scope
   79.94 +{
   79.95 +  public:
   79.96 +    static LocalScope *New(PoolAllocator &pool);
   79.97 +
   79.98 +  private:
   79.99 +    LocalScope(PoolAllocator &pool);
  79.100 +};
  79.101 +
  79.102 +class GlobalScope : public Scope
  79.103 +{
  79.104 +  public:
  79.105 +    static GlobalScope *New(PoolAllocator &pool, ImportScope *parent);
  79.106 +
  79.107 +    bool addPublic(Symbol *symbol);
  79.108 +    Symbol *findPublic(Handle<String> name);
  79.109 +    Struct *build(Zone *zone);
  79.110 +
  79.111 +  private:
  79.112 +    GlobalScope(PoolAllocator &pool, ImportScope *parent);
  79.113 +
  79.114 +  private:
  79.115 +    PoolList<Symbol *> publics_;
  79.116 +};
  79.117 +
  79.118 +class ImportScope : public Scope
  79.119 +{
  79.120 +  public:
  79.121 +    static ImportScope *New(PoolAllocator &pool);
  79.122 +
  79.123 +  private:
  79.124 +    ImportScope(PoolAllocator &pool);
  79.125 +};
  79.126 +
  79.127 +}
  79.128 +
  79.129 +#endif // _include_jitcraft_scopes_h_
    80.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.2 +++ b/src/compiler/SemanticAnalysis.cpp	Sat Nov 17 18:41:01 2012 -0800
    80.3 @@ -0,0 +1,624 @@
    80.4 +/* vim: set ts=4 sw=4 tw=99 et:
    80.5 + *
    80.6 + * Copyright (C) 2012 David Anderson
    80.7 + *
    80.8 + * This file is part of SourcePawn.
    80.9 + *
   80.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   80.11 + * the terms of the GNU General Public License as published by the Free
   80.12 + * Software Foundation, either version 3 of the License, or (at your option)
   80.13 + * any later version.
   80.14 + * 
   80.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   80.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   80.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   80.18 + *
   80.19 + * You should have received a copy of the GNU General Public License along with
   80.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   80.21 + */
   80.22 +#include <assert.h>
   80.23 +#include "../Zone.h"
   80.24 +#include "../Strings.h"
   80.25 +#include "../NativeTable.h"
   80.26 +#include "../TypeManager.h"
   80.27 +#include "../Modules.h"
   80.28 +#include "../Code.h"
   80.29 +#include "SemanticAnalysis.h"
   80.30 +
   80.31 +using namespace ke;
   80.32 +
   80.33 +#define __ emitter_.
   80.34 +
   80.35 +typedef BytecodeEmitter::Label Label;
   80.36 +
   80.37 +class AutoEnterScope
   80.38 +{
   80.39 +  public:
   80.40 +    AutoEnterScope(Scope **prevp, Scope *scope)
   80.41 +      : prevp_(prevp),
   80.42 +        prev_(*prevp),
   80.43 +        scope_(scope)
   80.44 +    {
   80.45 +        if (!scope_)
   80.46 +            return;
   80.47 +        prev_ = *prevp_;
   80.48 +        *prevp_ = scope;
   80.49 +        assert(prev_ == scope->enclosing());
   80.50 +    }
   80.51 +    ~AutoEnterScope()
   80.52 +    {
   80.53 +        if (scope_)
   80.54 +            *prevp_ = prev_;
   80.55 +    }
   80.56 +  private:
   80.57 +    Scope **prevp_;
   80.58 +    Scope *prev_;
   80.59 +    Scope *scope_;
   80.60 +};
   80.61 +
   80.62 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit)
   80.63 +  : zone_(zone),
   80.64 +    pool_(zone->pool()),
   80.65 +    cc_(cc),
   80.66 +    unit_(unit),
   80.67 +    hir_(NULL),
   80.68 +    emitter_(pool_),
   80.69 +    module_(NULL),
   80.70 +    loop_(NULL)
   80.71 +{
   80.72 +}
   80.73 +
   80.74 +SemanticAnalysis::SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun)
   80.75 +  : zone_(parent->zone_),
   80.76 +    pool_(parent->pool_),
   80.77 +    cc_(parent->cc_),
   80.78 +    unit_(parent->unit_),
   80.79 +    hir_(NULL),
   80.80 +    scope_(parent->scope_),
   80.81 +    emitter_(pool_),
   80.82 +    module_(parent->module_),
   80.83 +    fun_(fun),
   80.84 +    loop_(NULL)
   80.85 +{
   80.86 +
   80.87 +}
   80.88 +
   80.89 +void
   80.90 +SemanticAnalysis::analyze()
   80.91 +{
   80.92 +    scope_ = unit_->globalScope();
   80.93 +
   80.94 +    module_ = Module::New(zone_);
   80.95 +
   80.96 +    for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
   80.97 +        Statement *stmt = unit_->tree()->statements()->at(i);
   80.98 +        stmt->accept(this);
   80.99 +    }
  80.100 +
  80.101 +    Local<Struct> globals(zone_, unit_->globalScope()->build(zone_));
  80.102 +    if (!globals)
  80.103 +        return;
  80.104 +    module_->setGlobals(globals);
  80.105 +
  80.106 +    Local<Code> code(zone_, __ finish());
  80.107 +    if (!code)
  80.108 +        return;
  80.109 +    code->setModule(module_);
  80.110 +    module_->setCode(code);
  80.111 +
  80.112 +#ifndef NDEBUG
  80.113 +//    Disassemble(code, stdout);
  80.114 +#endif
  80.115 +
  80.116 +    unit_->module_ = module_;
  80.117 +}
  80.118 +
  80.119 +void
  80.120 +SemanticAnalysis::visitFunctionStatement(FunctionStatement *stmt)
  80.121 +{
  80.122 +    FunctionSymbol *sym = stmt->sym();
  80.123 +    Local<FunctionType> type(zone_, sym->type());
  80.124 +
  80.125 +    assert(scope_->kind() == Scope::GLOBAL);
  80.126 +
  80.127 +    if (stmt->token() == TOK_NATIVE) {
  80.128 +        // Define the native now.
  80.129 +        size_t index;
  80.130 +        if (!zone_->nativeTable()->add(stmt->name(), &index))
  80.131 +            return;
  80.132 +
  80.133 +        Local<Native> native(zone_, Native::New(zone_, type, index));
  80.134 +        if (!native)
  80.135 +            return;
  80.136 +
  80.137 +        __ object(native);
  80.138 +        __ setglobal(sym);
  80.139 +        __ pop();
  80.140 +    }
  80.141 +
  80.142 +    // If the function is a forward or native, we don't have to do anything.
  80.143 +    if (stmt->token() == TOK_NATIVE || stmt->token() == TOK_FORWARD)
  80.144 +        return;
  80.145 +
  80.146 +    SemanticAnalysis child(this, type);
  80.147 +    Local<Function> funobj(zone_, child.compile(stmt));
  80.148 +    if (!funobj)
  80.149 +        return;
  80.150 +
  80.151 +    __ object(funobj);
  80.152 +    __ setglobal(sym);
  80.153 +    __ public_();
  80.154 +}
  80.155 +
  80.156 +Function *
  80.157 +SemanticAnalysis::compile(FunctionStatement *stmt)
  80.158 +{
  80.159 +    __ setFirstLine(stmt->pos().line);
  80.160 +
  80.161 +    AutoEnterScope argScope(&scope_, stmt->argScope());
  80.162 +    AutoEnterScope varScope(&scope_, stmt->varScope());
  80.163 +
  80.164 +    stmt->body()->accept(this);
  80.165 +
  80.166 +    Local<Code> code(zone_, __ finish());
  80.167 +    if (!code)
  80.168 +        return NULL;
  80.169 +    code->setModule(module_);
  80.170 +
  80.171 +    Local<Function> fun(zone_, Function::New(zone_, code, fun_, stmt->name(), stmt->pos()));
  80.172 +    if (!fun)
  80.173 +        return NULL;
  80.174 +
  80.175 +#ifndef NDEBUG
  80.176 +//    Disassemble(code, stdout);
  80.177 +#endif
  80.178 +
  80.179 +    return fun;
  80.180 +}
  80.181 +
  80.182 +void 
  80.183 +SemanticAnalysis::visitBlockStatement(BlockStatement *node)
  80.184 +{
  80.185 +    AutoEnterScope scope(&scope_, node->scope());
  80.186 +
  80.187 +    for (size_t i = 0; i < node->statements()->length(); i++) {
  80.188 +        Statement *stmt = node->statements()->at(i);
  80.189 +        stmt->accept(this);
  80.190 +        assert(__ stackDepth() == 0);
  80.191 +    }
  80.192 +}
  80.193 +
  80.194 +void
  80.195 +SemanticAnalysis::visitExpressionStatement(ExpressionStatement *node)
  80.196 +{
  80.197 +    // While building HIR, we enter new pool and root scopes, since HIR
  80.198 +    // creation is purely temporary.
  80.199 +    PoolScope poolScope(zone_->pool());
  80.200 +    RootScope rootScope(zone_);
  80.201 +
  80.202 +    HIR *hir = eval(node->expression());
  80.203 +    if (!hir)
  80.204 +        return;
  80.205 +
  80.206 +    discharge(hir);
  80.207 +    __ pop();
  80.208 +}
  80.209 +
  80.210 +void
  80.211 +SemanticAnalysis::visitForStatement(ForStatement *node)
  80.212 +{
  80.213 +    AutoEnterScope scope(&scope_, node->scope());
  80.214 +    PoolScope poolScope(zone_->pool());
  80.215 +    RootScope rootScope(zone_);
  80.216 +
  80.217 +    Label join, update;
  80.218 +    LoopScope loop(scope_, &join, &update, &loop_);
  80.219 +
  80.220 +    if (node->initialization())
  80.221 +        node->initialization()->accept(this);
  80.222 +
  80.223 +    Label header, test;
  80.224 +    if (node->condition())
  80.225 +        __ jump(&test);
  80.226 +
  80.227 +    __ bind(&header);
  80.228 +    node->body()->accept(this);
  80.229 +
  80.230 +    __ bind(&update);
  80.231 +    if (node->update())
  80.232 +        node->update()->accept(this);
  80.233 +
  80.234 +    if (node->condition()) {
  80.235 +        __ bind(&test);
  80.236 +        visitForTest(node->condition(), &header, &join, &join);
  80.237 +    } else {
  80.238 +        __ jump(&header);
  80.239 +    }
  80.240 +
  80.241 +    __ bind(&join);
  80.242 +
  80.243 +    assert(__ stackDepth() == 0);
  80.244 +}
  80.245 +
  80.246 +void
  80.247 +SemanticAnalysis::visitVariableDeclaration(VariableDeclaration *node)
  80.248 +{
  80.249 +    PoolScope poolScope(zone_->pool());
  80.250 +    RootScope rootScope(zone_);
  80.251 +
  80.252 +    HIR *hir;
  80.253 +    if (node->initialization()) {
  80.254 +        if ((hir = eval(node->initialization())) == NULL)
  80.255 +            return;
  80.256 +        if ((hir = coerce(hir, node->sym()->type(), Coerce_Assign)) == NULL)
  80.257 +            return;
  80.258 +    } else {
  80.259 +        assert(false);
  80.260 +    }
  80.261 +
  80.262 +    discharge(hir);
  80.263 +
  80.264 +    if (!__ allocate(node->sym()))
  80.265 +        return;
  80.266 +
  80.267 +    set(node->sym());
  80.268 +    __ pop();
  80.269 +}
  80.270 +
  80.271 +void
  80.272 +SemanticAnalysis::visitReturnStatement(ReturnStatement *node)
  80.273 +{
  80.274 +    if (!node->expression()) {
  80.275 +        if (!fun_->returnType()->isVoid()) {
  80.276 +            cc_.reportError(node->pos(), Message_UsedVoidReturn);
  80.277 +            return;
  80.278 +        }
  80.279 +
  80.280 +        __ returnvoid();
  80.281 +        return;
  80.282 +    }
  80.283 +
  80.284 +    PoolScope poolScope(zone_->pool());
  80.285 +    RootScope rootScope(zone_);
  80.286 +
  80.287 +    HIR *hir = eval(node->expression());
  80.288 +    if (!hir)
  80.289 +        return;
  80.290 +
  80.291 +    Local<Type> returnType(zone_, fun_->returnType());
  80.292 +    if ((hir = coerce(hir, returnType, Coerce_Return)) == NULL)
  80.293 +        return;
  80.294 +
  80.295 +    discharge(hir);
  80.296 +    __ return_();
  80.297 +}
  80.298 +
  80.299 +void
  80.300 +SemanticAnalysis::visitBinaryExpression(BinaryExpression *node)
  80.301 +{
  80.302 +    HIR *left = eval(node->left());
  80.303 +    HIR *right = eval(node->right());
  80.304 +    if (!left || !right)
  80.305 +        return;
  80.306 +
  80.307 +    hir_ = binary(node->token(), left, right);
  80.308 +}
  80.309 +
  80.310 +bool
  80.311 +SemanticAnalysis::checkArgumentCount(Handle<FunctionType> type, unsigned actual)
  80.312 +{
  80.313 +    if (type->parameters()->length() == actual)
  80.314 +        return true;
  80.315 +
  80.316 +    if (actual > type->parameters()->length()) {
  80.317 +        if (!type->isNative() || !type->isNativeVariadic())
  80.318 +            return false;
  80.319 +        return true;
  80.320 +    }
  80.321 +
  80.322 +    if (!type->defaults())
  80.323 +        return false;
  80.324 +
  80.325 +    // Missing arguments. See if there's a default argument for each missing
  80.326 +    // actual.
  80.327 +    for (unsigned i = actual; i < type->parameters()->length(); i++) {
  80.328 +        if (!type->defaults()->at(i))
  80.329 +            return false;
  80.330 +    }
  80.331 +
  80.332 +    return true;
  80.333 +}
  80.334 +
  80.335 +void
  80.336 +SemanticAnalysis::visitNameProxy(NameProxy *proxy)
  80.337 +{
  80.338 +    Symbol *sym = proxy->sym();
  80.339 +    Handle<Type> type = sym->type();
  80.340 +
  80.341 +    VariableSymbol *var = sym->asVariable();
  80.342 +
  80.343 +    Scope *in = sym->scope();
  80.344 +    switch (in->kind()) {
  80.345 +      case Scope::GLOBAL:
  80.346 +        hir_ = new (pool_) HGlobal(sym);
  80.347 +        return;
  80.348 +
  80.349 +      default:
  80.350 +        assert(in->kind() == Scope::BLOCK);
  80.351 +        assert(var->storage() == VariableSymbol::Local);
  80.352 +        hir_ = new (pool_) HLocal(var);
  80.353 +        return;
  80.354 +    }
  80.355 +}
  80.356 +
  80.357 +void
  80.358 +SemanticAnalysis::visitIntegerLiteral(IntegerLiteral *lit)
  80.359 +{
  80.360 +    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
  80.361 +    hir_ = new (pool_) HInteger(type, lit->value());
  80.362 +}
  80.363 +
  80.364 +void
  80.365 +SemanticAnalysis::visitFloatLiteral(FloatLiteral *node)
  80.366 +{
  80.367 +    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
  80.368 +    hir_ = new (pool_) HFloat(type, (float)node->value());
  80.369 +}
  80.370 +
  80.371 +void
  80.372 +SemanticAnalysis::visitCallExpression(CallExpression *node)
  80.373 +{
  80.374 +    HIR *callee = eval(node->callee());
  80.375 +    if (!callee)
  80.376 +        return;
  80.377 +
  80.378 +    if (!callee->type()->isFunction()) {
  80.379 +        cc_.reportError(node->pos(), Message_CalleeNotFunction);
  80.380 +        return;
  80.381 +    }
  80.382 +
  80.383 +    Local<FunctionType> fun(zone_, FunctionType::cast(callee->type()));
  80.384 +    
  80.385 +    if (!checkArgumentCount(fun, node->arguments()->length())) {
  80.386 +        cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
  80.387 +        return;
  80.388 +    }
  80.389 +
  80.390 +    if (fun->isForward()) {
  80.391 +        cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
  80.392 +        return;
  80.393 +    }
  80.394 +
  80.395 +    HIRList *args = new (pool_) HIRList;
  80.396 +    for (unsigned i = 0; i < node->arguments()->length(); i++) {
  80.397 +        Expression *expression = node->arguments()->at(i);
  80.398 +        HIR *arg = eval(expression);
  80.399 +        if (!arg)
  80.400 +            return;
  80.401 +
  80.402 +        Handle<Type> given = arg->type();
  80.403 +        
  80.404 +        bool mustComputeReference;
  80.405 +        if (i >= fun->parameters()->length()) {
  80.406 +            // Special handling for natives. Arguments past the formal must
  80.407 +            // always have references computed. However, arrays are already
  80.408 +            // references for natives.
  80.409 +            assert(fun->isNative() && fun->isNativeVariadic());
  80.410 +            mustComputeReference = !given->isReference() &&
  80.411 +                                   !given->isArray();
  80.412 +        } else {
  80.413 +            Local<Type> actual(zone_, fun->parameterAt(i));
  80.414 +
  80.415 +            if (expression->isIndexExpression()) {
  80.416 +                // Temporarily disabled.
  80.417 +                assert(!actual->isArray());
  80.418 +                if (actual->isReference()) {
  80.419 +                    cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
  80.420 +                    return;
  80.421 +                }
  80.422 +            }
  80.423 +
  80.424 +            // When we start overloading, coercion will have to happen later.
  80.425 +            arg = coerce(arg, actual, Coerce_Arg);
  80.426 +            if (!arg)
  80.427 +                return;
  80.428 +
  80.429 +            mustComputeReference = actual->isReference() && !given->isReference();
  80.430 +        }
  80.431 +
  80.432 +        // :TODO: handle mustComputeReference
  80.433 +        assert(!mustComputeReference);
  80.434 +
  80.435 +        if (!args->append(arg))
  80.436 +            return;
  80.437 +    }
  80.438 +
  80.439 +    hir_ = new (pool_) HCall(fun->returnType(), callee, args);
  80.440 +}
  80.441 +
  80.442 +void
  80.443 +SemanticAnalysis::visitAssignment(Assignment *node)
  80.444 +{
  80.445 +    HLValue *lval = lvalue(node->lvalue());
  80.446 +    if (!lval)
  80.447 +        return;
  80.448 +
  80.449 +    HIR *hir = eval(node->expression());
  80.450 +    if ((hir = coerce(hir, lval->type(), Coerce_Assign)) == NULL)
  80.451 +        return;
  80.452 +
  80.453 +    hir_ = new (pool_) HStore(lval, hir);
  80.454 +}
  80.455 +
  80.456 +Type *
  80.457 +SemanticAnalysis::coercionType(TokenKind token, HIR *left, HIR *right)
  80.458 +{
  80.459 +    Handle<Type> l = left->type();
  80.460 +    Handle<Type> r = right->type();
  80.461 +
  80.462 +    if (token >= TOK_PLUS && token <= TOK_SLASH) {
  80.463 +        // We allow: [float|int32] + [float|int32]
  80.464 +        if (l->isFloat() && r->isInt32())
  80.465 +            return l;
  80.466 +        if (l->isInt32() && r->isFloat())
  80.467 +            return r;
  80.468 +        if (l->isInt32() && r->isInt32())
  80.469 +            return l;
  80.470 +    }
  80.471 +
  80.472 +    assert(l == r);
  80.473 +
  80.474 +    return left->type();
  80.475 +}
  80.476 +
  80.477 +HIR *
  80.478 +SemanticAnalysis::coerce(HIR *hir, Handle<Type> to, CoercionKind kind)
  80.479 +{
  80.480 +    Handle<Type> from = hir->type();
  80.481 +
  80.482 +    if (from->isInt32() && to->isFloat())
  80.483 +        return new (pool_) HConvert(to, OP_CVT_I2F, hir);
  80.484 +    
  80.485 +    assert(from == to);
  80.486 +    
  80.487 +    return hir;
  80.488 +}
  80.489 +
  80.490 +void
  80.491 +SemanticAnalysis::set(VariableSymbol *sym)
  80.492 +{
  80.493 +    if (sym->scope()->kind() == Scope::GLOBAL) {
  80.494 +        __ setglobal(sym);
  80.495 +    } else {
  80.496 +        assert(sym->storage() == VariableSymbol::Local);
  80.497 +        __ setlocal(sym);
  80.498 +    }
  80.499 +}
  80.500 +
  80.501 +HIR *
  80.502 +SemanticAnalysis::binary(TokenKind token, HIR *left, HIR *right)
  80.503 +{
  80.504 +    Local<Type> coercion(zone_, coercionType(token, left, right));
  80.505 +    if (!coercion)
  80.506 +        return NULL;
  80.507 +    if ((left = coerce(left, coercion, Coerce_Arg)) == NULL)
  80.508 +        return NULL;
  80.509 +    if ((right = coerce(right, coercion, Coerce_Arg)) == NULL)
  80.510 +        return NULL;
  80.511 +    
  80.512 +    switch (token) {
  80.513 +     case TOK_PLUS:
  80.514 +      case TOK_MINUS:
  80.515 +      case TOK_STAR:
  80.516 +      case TOK_SLASH:
  80.517 +      case TOK_PERCENT:
  80.518 +      case TOK_AMPERSAND:
  80.519 +      case TOK_BITOR:
  80.520 +      case TOK_BITXOR:
  80.521 +      case TOK_SHR:
  80.522 +      case TOK_USHR:
  80.523 +      case TOK_SHL:
  80.524 +        return new (pool_) HBinary(left->type(), token, left, right);
  80.525 +
  80.526 +      case TOK_EQUALS:
  80.527 +      case TOK_NOTEQUALS:
  80.528 +      case TOK_LT:
  80.529 +      case TOK_LE:
  80.530 +      case TOK_GT:
  80.531 +      case TOK_GE:
  80.532 +      case TOK_AND:
  80.533 +      case TOK_OR:
  80.534 +      {
  80.535 +        Local<Type> result(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
  80.536 +        return new (pool_) HBinary(result, token, left, right);
  80.537 +      }
  80.538 +
  80.539 +      default:
  80.540 +        assert(false);
  80.541 +        return NULL;
  80.542 +    }
  80.543 +}
  80.544 +
  80.545 +static inline TokenKind
  80.546 +ToCompare(Expression *expr)
  80.547 +{
  80.548 +    if (expr->isBinaryExpression()) {
  80.549 +        BinaryExpression *b = expr->toBinaryExpression();
  80.550 +        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
  80.551 +            return b->token();
  80.552 +    } else if (expr->isUnaryExpression()) {
  80.553 +        UnaryExpression *u = expr->toUnaryExpression();
  80.554 +        if (u->token() == TOK_NOT)
  80.555 +            return TOK_NOT;
  80.556 +    }
  80.557 +    return TOK_EOF;
  80.558 +}
  80.559 +
  80.560 +void
  80.561 +SemanticAnalysis::visitForTest(Expression *expr,
  80.562 +                               Label *trueBranch,
  80.563 +                               Label *falseBranch,
  80.564 +                               Label *fallthrough)
  80.565 +{
  80.566 +    TokenKind token = ToCompare(expr);
  80.567 +    if (token == TOK_EOF || token == TOK_NOT) {
  80.568 +        assert(false);
  80.569 +        //visitForUnaryTest(expr, trueBranch, falseBranch, fallthrough);
  80.570 +        return;
  80.571 +    }
  80.572 +
  80.573 +    BinaryExpression *bin = expr->toBinaryExpression();
  80.574 +    if (token == TOK_AND || token == TOK_OR) {
  80.575 +        assert(false);
  80.576 +        //visitForLogicTest(expr, trueBranch, falseBranch, fallthrough);
  80.577 +        return;
  80.578 +    }
  80.579 +
  80.580 +    HIR *left = eval(bin->left());
  80.581 +    HIR *right = eval(bin->right());
  80.582 +    if (!left || !right)
  80.583 +        return;
  80.584 +
  80.585 +    HIR *hir = binary(bin->token(), left, right);
  80.586 +    if (!hir)
  80.587 +        return;
  80.588 +
  80.589 +    discharge(hir);
  80.590 +    if (fallthrough == trueBranch)
  80.591 +        __ j(OP_JF, falseBranch);
  80.592 +    else
  80.593 +        __ j(OP_JT, trueBranch);
  80.594 +}
  80.595 +
  80.596 +HLValue *
  80.597 +SemanticAnalysis::lvalue(Expression *expr)
  80.598 +{
  80.599 +    HIR *hir = eval(expr);
  80.600 +    if (!hir)
  80.601 +        return NULL;
  80.602 +    
  80.603 +    if (!hir->isLValue()) {
  80.604 +        cc_.reportError(expr->pos(), Message_ExpectedLValue);
  80.605 +        return NULL;
  80.606 +    }
  80.607 +
  80.608 +    return static_cast<HLValue *>(hir);
  80.609 +}
  80.610 +
  80.611 +HIR *
  80.612 +SemanticAnalysis::eval(Expression *expr)
  80.613 +{
  80.614 +    assert(!hir_);
  80.615 +    expr->accept(this);
  80.616 +
  80.617 +    HIR *hir = hir_;
  80.618 +    hir_ = NULL;
  80.619 +
  80.620 +    return hir;
  80.621 +}
  80.622 +
  80.623 +void
  80.624 +SemanticAnalysis::discharge(HIR *hir)
  80.625 +{
  80.626 +    EmitHIR(zone_, emitter_, hir);
  80.627 +}
    81.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    81.2 +++ b/src/compiler/SemanticAnalysis.h	Sat Nov 17 18:41:01 2012 -0800
    81.3 @@ -0,0 +1,159 @@
    81.4 +/*
    81.5 + * Copyright (C) 2012 David Anderson
    81.6 + *
    81.7 + * This file is part of SourcePawn.
    81.8 + *
    81.9 + * SourcePawn is free software: you can redistribute it and/or modify it under
   81.10 + * the terms of the GNU General Public License as published by the Free
   81.11 + * Software Foundation, either version 3 of the License, or (at your option)
   81.12 + * any later version.
   81.13 + * 
   81.14 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   81.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   81.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   81.17 + *
   81.18 + * You should have received a copy of the GNU General Public License along with
   81.19 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   81.20 + */
   81.21 +#ifndef _include_sp2_sema_h_
   81.22 +#define _include_sp2_sema_h_
   81.23 +
   81.24 +#include "AST.h"
   81.25 +#include "HIR.h"
   81.26 +#include "Scopes.h"
   81.27 +#include "BytecodeEmitter.h"
   81.28 +
   81.29 +namespace ke {
   81.30 +
   81.31 +// Semantic analysis occurs after all names and types have been bound. It
   81.32 +// performs the important task of validating the semantics and type safety
   81.33 +// of a parse tree.
   81.34 +// 
   81.35 +// The semantic analysis phase also produces bytecode. This occurs on a
   81.36 +// statement-by-statement basis. The result of analyzing an expression is a
   81.37 +// tree of operations which is then flattened.
   81.38 +class SemanticAnalysis : public AstVisitor
   81.39 +{
   81.40 +  public:
   81.41 +    SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit);
   81.42 +
   81.43 +    void analyze();
   81.44 +
   81.45 +  private:
   81.46 +    SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun);
   81.47 +    Function *compile(FunctionStatement *stmt);
   81.48 +
   81.49 +  public:
   81.50 +    void visitFunctionStatement(FunctionStatement *node);
   81.51 +    void visitBlockStatement(BlockStatement *node);
   81.52 +    void visitExpressionStatement(ExpressionStatement *node);
   81.53 +    void visitReturnStatement(ReturnStatement *node);
   81.54 +
   81.55 +    void visitCallExpression(CallExpression *node);
   81.56 +    void visitNameProxy(NameProxy *name);
   81.57 +    void visitIntegerLiteral(IntegerLiteral *node);
   81.58 +    void visitFloatLiteral(FloatLiteral *node);
   81.59 +    void visitVariableDeclaration(VariableDeclaration *node);
   81.60 +    void visitForStatement(ForStatement *node);
   81.61 +    void visitAssignment(Assignment *node);
   81.62 +    void visitBinaryExpression(BinaryExpression *node);
   81.63 +#if 0
   81.64 +    void visitFunctionTypeStatement(FunctionTypeStatement *node);
   81.65 +    void visitImportStatement(ImportStatement *node);
   81.66 +    void visitExpressionStatement(ExpressionStatement *node);
   81.67 +    void visitEnumStatement(EnumStatement *node);
   81.68 +    void visitWhileStatement(WhileStatement *node);
   81.69 +    void visitBreakStatement(BreakStatement *node);
   81.70 +    void visitContinueStatement(ContinueStatement *node);
   81.71 +    void visitStructureStatement(StructureStatement *node);
   81.72 +    void visitSwitchStatement(SwitchStatement *node);
   81.73 +
   81.74 +    void visitBinaryExpression(BinaryExpression *node);
   81.75 +    void visitCallExpression(CallExpression *node);
   81.76 +    void visitIfStatement(IfStatement *node);
   81.77 +    void visitIndexExpression(IndexExpression *node);
   81.78 +    void visitStringLiteral(StringLiteral *node);
   81.79 +    void visitIncDecExpression(IncDecExpression *node);
   81.80 +    void visitUnaryExpression(UnaryExpression *node);
   81.81 +    void visitTernaryExpression(TernaryExpression *node);
   81.82 +    void visitBooleanLiteral(BooleanLiteral *node);
   81.83 +    void visitFieldExpression(FieldExpression *node);
   81.84 +    void visitArrayLiteral(ArrayLiteral *node);
   81.85 +#endif
   81.86 +
   81.87 +  private:
   81.88 +    bool checkArgumentCount(Handle<FunctionType> type, unsigned actual);
   81.89 +
   81.90 +  private:
   81.91 +    enum CoercionKind {
   81.92 +        Coerce_Arg,
   81.93 +        Coerce_Return,
   81.94 +        Coerce_Assign
   81.95 +    };
   81.96 +
   81.97 +    void visitForTest(Expression *expr,
   81.98 +                      BytecodeEmitter::Label *trueBranch,
   81.99 +                      BytecodeEmitter::Label *falseBranch,
  81.100 +                      BytecodeEmitter::Label *fallthrough);
  81.101 +    void set(VariableSymbol *sym);
  81.102 +    HIR *eval(Expression *expr);
  81.103 +    HIR *binary(TokenKind token, HIR *left, HIR *right);
  81.104 +    HIR *coerce(HIR *from, Handle<Type> to, CoercionKind kind);
  81.105 +    Type *coercionType(TokenKind token, HIR *left, HIR *right);
  81.106 +    HLValue *lvalue(Expression *expr);
  81.107 +    void discharge(HIR *hir);
  81.108 +
  81.109 +  private:
  81.110 +    // Used to target break/catch statements.
  81.111 +    class LoopScope
  81.112 +    {
  81.113 +        Scope *scope_;
  81.114 +        BytecodeEmitter::Label *bk_;
  81.115 +        BytecodeEmitter::Label *ct_;
  81.116 +        LoopScope **prevp_;
  81.117 +        LoopScope *prev_;
  81.118 +
  81.119 +      public:
  81.120 +        LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
  81.121 +                  LoopScope **prevp)
  81.122 +          : scope_(scope),
  81.123 +            bk_(bk),
  81.124 +            ct_(ct),
  81.125 +            prevp_(prevp),
  81.126 +            prev_(*prevp)
  81.127 +        {
  81.128 +            *prevp_ = this;
  81.129 +        }
  81.130 +
  81.131 +        ~LoopScope()
  81.132 +        {
  81.133 +            *prevp_ = prev_;
  81.134 +        }
  81.135 +
  81.136 +        BytecodeEmitter::Label *break_() {
  81.137 +            return bk_;
  81.138 +        }
  81.139 +        BytecodeEmitter::Label *continue_() {
  81.140 +            return ct_;
  81.141 +        }
  81.142 +        Scope *scope() {
  81.143 +            return scope_;
  81.144 +        }
  81.145 +    };
  81.146 +    
  81.147 +  private:
  81.148 +    Zone *zone_;
  81.149 +    PoolAllocator &pool_;
  81.150 +    CompileContext &cc_;
  81.151 +    TranslationUnit *unit_;
  81.152 +    HIR *hir_;
  81.153 +    Scope *scope_;
  81.154 +    BytecodeEmitter emitter_;
  81.155 +    ScopedRoot<Module> module_;
  81.156 +    ScopedRoot<FunctionType> fun_;
  81.157 +    LoopScope *loop_;
  81.158 +};
  81.159 +
  81.160 +} // namespace ke
  81.161 +
  81.162 +#endif // _include_sp2_sema_h_
    82.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    82.2 +++ b/src/compiler/Symbols.cpp	Sat Nov 17 18:41:01 2012 -0800
    82.3 @@ -0,0 +1,20 @@
    82.4 +/* vim: set ts=4 sw=4 tw=99 et:
    82.5 + *
    82.6 + * Copyright (C) 2012 David Anderson
    82.7 + *
    82.8 + * This file is part of JITCraft.
    82.9 + *
   82.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   82.11 + * the terms of the GNU General Public License as published by the Free
   82.12 + * Software Foundation, either version 3 of the License, or (at your option)
   82.13 + * any later version.
   82.14 + * 
   82.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   82.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   82.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   82.18 + *
   82.19 + * You should have received a copy of the GNU General Public License along with
   82.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   82.21 + */
   82.22 +#include "Symbols.h"
   82.23 +
    83.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    83.2 +++ b/src/compiler/Symbols.h	Sat Nov 17 18:41:01 2012 -0800
    83.3 @@ -0,0 +1,188 @@
    83.4 +/* vim: set ts=4 sw=4 tw=99 et:
    83.5 + *
    83.6 + * Copyright (C) 2012 David Anderson
    83.7 + *
    83.8 + * This file is part of SourcePawn.
    83.9 + *
   83.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   83.11 + * the terms of the GNU General Public License as published by the Free
   83.12 + * Software Foundation, either version 3 of the License, or (at your option)
   83.13 + * any later version.
   83.14 + * 
   83.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   83.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   83.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   83.18 + *
   83.19 + * You should have received a copy of the GNU General Public License along with
   83.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   83.21 + */
   83.22 +#ifndef _include_sp2_symbol_h_
   83.23 +#define _include_sp2_symbol_h_
   83.24 +
   83.25 +#include "../PoolAllocator.h"
   83.26 +#include "../Handles.h"
   83.27 +#include "../Opcodes.h"
   83.28 +#include "../Types.h"
   83.29 +
   83.30 +namespace ke {
   83.31 +
   83.32 +class String;
   83.33 +
   83.34 +#define SYMBOL_KINDS(_) \
   83.35 +    /* Any kind of variable or argument produces a VariableSymbol. */ \
   83.36 +    _(Variable)         \
   83.37 +    /* A function declaration produces a FunctionSymbol. */ \
   83.38 +    _(Function)         \
   83.39 +    /* A named constant produces a ConstantSymbol. */ \
   83.40 +    _(Constant)         \
   83.41 +    /* A named type (class struct, typedef, etc) produces a TypeSymbol. */ \
   83.42 +    _(Type)             \
   83.43 +    /* // A module import produces a ModuleSymbol. */   \
   83.44 +    _(Module)
   83.45 +
   83.46 +#define _(name)     class name##Symbol;
   83.47 +SYMBOL_KINDS(_)
   83.48 +#undef _
   83.49 +
   83.50 +class Scope;
   83.51 +
   83.52 +// A symbol represents the declaration of a named entity.
   83.53 +class Symbol : public PoolObject
   83.54 +{
   83.55 +  public:
   83.56 +    enum Kind {
   83.57 +#       define _(name) k##name,
   83.58 +        SYMBOL_KINDS(_)
   83.59 +#       undef _
   83.60 +        kTotalSymbolKinds
   83.61 +    };
   83.62 +
   83.63 +  public:
   83.64 +    Symbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
   83.65 +      : scope_(scope),
   83.66 +        name_(name),
   83.67 +        pos_(pos)
   83.68 +    {
   83.69 +    }
   83.70 +
   83.71 +    virtual Kind kind() const = 0;
   83.72 +
   83.73 +    Handle<String> name() const {
   83.74 +        return name_;
   83.75 +    }
   83.76 +    const SourcePosition &pos() const {
   83.77 +        return pos_;
   83.78 +    }
   83.79 +    Handle<Type> type() const {
   83.80 +        return type_;
   83.81 +    }
   83.82 +    Scope *scope() const {
   83.83 +        return scope_;
   83.84 +    }
   83.85 +
   83.86 +  public:
   83.87 +#define _(name)                                             \
   83.88 +    bool is##name() const {                                 \
   83.89 +        return (kind() == k##name);                         \
   83.90 +    }                                                       \
   83.91 +    name##Symbol *as##name() {                              \
   83.92 +        if (is##name())                                     \
   83.93 +            return to##name();                              \
   83.94 +        return NULL;                                        \
   83.95 +    }                                                       \
   83.96 +    name##Symbol *to##name() {                              \
   83.97 +        assert(is##name());                                 \
   83.98 +        return reinterpret_cast<name##Symbol *>(this);      \
   83.99 +    }
  83.100 +    SYMBOL_KINDS(_)
  83.101 +#undef _
  83.102 +
  83.103 +  private:
  83.104 +    Scope *scope_;
  83.105 +    ScopedRoot<String> name_;
  83.106 +    SourcePosition pos_;
  83.107 +
  83.108 +  protected:
  83.109 +    ScopedRoot<Type> type_;
  83.110 +};
  83.111 +
  83.112 +class VariableSymbol : public Symbol
  83.113 +{
  83.114 +  public:
  83.115 +    enum Storage {
  83.116 +        Unknown,
  83.117 +        Local,
  83.118 +        Heap
  83.119 +    };
  83.120 +
  83.121 +  public:
  83.122 +    VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
  83.123 +      : Symbol(scope, name, pos),
  83.124 +        storage_(Unknown)
  83.125 +    {
  83.126 +    }
  83.127 +
  83.128 +    VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type)
  83.129 +      : Symbol(scope, name, pos),
  83.130 +        storage_(Unknown)
  83.131 +    {
  83.132 +        type_ = type;
  83.133 +    }
  83.134 +
  83.135 +    Kind kind() const {
  83.136 +        return kVariable;
  83.137 +    }
  83.138 +    void setType(Type *type) {
  83.139 +        type_ = type;
  83.140 +    }
  83.141 +    void allocate(Storage storage, unsigned slot) {
  83.142 +        storage_ = storage;
  83.143 +        slot_ = slot;
  83.144 +    }
  83.145 +    Storage storage() const {
  83.146 +        return storage_;
  83.147 +    }
  83.148 +    unsigned slot() const {
  83.149 +        assert(storage() != Unknown);
  83.150 +        return slot_;
  83.151 +    }
  83.152 +
  83.153 +  private:
  83.154 +    Storage storage_;
  83.155 +    unsigned slot_;
  83.156 +};
  83.157 +
  83.158 +class TypeSymbol : public Symbol
  83.159 +{
  83.160 +  public:
  83.161 +    TypeSymbol(Scope *scope, Handle<String> name, Handle<Type> type)
  83.162 +      : Symbol(scope, name, SourcePosition())
  83.163 +    {
  83.164 +        type_ = type;
  83.165 +    }
  83.166 +
  83.167 +    Kind kind() const {
  83.168 +        return kType;
  83.169 +    }
  83.170 +};
  83.171 +
  83.172 +class FunctionSymbol : public Symbol
  83.173 +{
  83.174 +  public:
  83.175 +    FunctionSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<FunctionType> type)
  83.176 +      : Symbol(scope, name, pos)
  83.177 +    {
  83.178 +        type_ = type;
  83.179 +    }
  83.180 +
  83.181 +    Kind kind() const {
  83.182 +        return kFunction;
  83.183 +    }
  83.184 +    FunctionType *type() const {
  83.185 +        return FunctionType::cast(type_);
  83.186 +    }
  83.187 +};
  83.188 +
  83.189 +}
  83.190 +
  83.191 +#endif // _include_sp2_symbol_h_
    84.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    84.2 +++ b/src/compiler/Token.h	Sat Nov 17 18:41:01 2012 -0800
    84.3 @@ -0,0 +1,127 @@
    84.4 +/* vim: set ts=4 sw=4 tw=99 et:
    84.5 + * 
    84.6 + * Copyright (C) 2012 David Anderson
    84.7 + *
    84.8 + * This file is part of SourcePawn.
    84.9 + *
   84.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   84.11 + * the terms of the GNU General Public License as published by the Free
   84.12 + * Software Foundation, either version 3 of the License, or (at your option)
   84.13 + * any later version.
   84.14 + * 
   84.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   84.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   84.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   84.18 + *
   84.19 + * You should have received a copy of the GNU General Public License along with
   84.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   84.21 + */
   84.22 +#ifndef _include_jitcraft_token_h_
   84.23 +#define _include_jitcraft_token_h_
   84.24 +
   84.25 +namespace ke {
   84.26 +
   84.27 +// List of tokens the scanner can recognize.
   84.28 +//
   84.29 +// Some restrictions:
   84.30 +//   * (ASSIGN_ADD - TOK_PLUS) must be the delta between an operator and its
   84.31 +//     op-and-assign equivalent.
   84.32 +#define TOKENMAP(_)                                     \
   84.33 +    _(NONE,               "<none>")                     \
   84.34 +    _(ERROR,              "<error>")                    \
   84.35 +    _(NEW,                "'new'")                      \
   84.36 +    _(FOR,                "'for'")                      \
   84.37 +    _(RETURN,             "'return'")                   \
   84.38 +    _(NAME,               "<name>")                     \
   84.39 +    _(INTEGER_LITERAL,    "<integer>")                  \
   84.40 +    _(HEX_LITERAL,        "<hex>")                      \
   84.41 +    _(FLOAT_LITERAL,      "<float>")                    \
   84.42 +    _(STRING_LITERAL,     "<string>")                   \
   84.43 +    _(IF,                 "<if>")                       \
   84.44 +    _(ELSE,               "<else>")                     \
   84.45 +    _(ENUM,               "<enum>")                     \
   84.46 +    _(LABEL,              "<label>")                    \
   84.47 +    _(WHILE,              "<while>")                    \
   84.48 +    _(DO,                 "<do>")                       \
   84.49 +    _(BREAK,              "<break>")                    \
   84.50 +    _(CONTINUE,           "<continue>")                 \
   84.51 +    _(FORWARD,            "<forward>")                  \
   84.52 +    _(PUBLIC,             "<public>")                   \
   84.53 +    _(CONST,              "<const>")                    \
   84.54 +    _(NATIVE,             "<native>")                   \
   84.55 +    _(STOCK,              "<stock>")                    \
   84.56 +    _(TRUE,               "<true>")                     \
   84.57 +    _(FALSE,              "<false>")                    \
   84.58 +    _(STRUCT,             "<struct>")                   \
   84.59 +    _(SWITCH,             "<switch>")                   \
   84.60 +    _(CASE,               "<case>")                     \
   84.61 +    _(DEFAULT,            "<default>")                  \
   84.62 +    _(TYPEDEF,            "<typedef>")                  \
   84.63 +    _(VOID,               "<void>")                     \
   84.64 +    _(INT,                "<int>")                      \
   84.65 +    _(SIZEOF,             "<sizeof>")                   \
   84.66 +    _(IMPORT,             "<import>")                   \
   84.67 +    _(ELLIPSES,           "...")                        \
   84.68 +    _(PLUS,               "+")                          \
   84.69 +    _(MINUS,              "-")                          \
   84.70 +    _(STAR,               "*")                          \
   84.71 +    _(SLASH,              "/")                          \
   84.72 +    _(PERCENT,            "%")                          \
   84.73 +    _(AMPERSAND,          "&")                          \
   84.74 +    _(BITOR,              "|")                          \
   84.75 +    _(BITXOR,             "^")                          \
   84.76 +    _(SHR,                ">>")                         \
   84.77 +    _(USHR,               ">>>")                        \
   84.78 +    _(SHL,                "<<")                         \
   84.79 +    _(ASSIGN,             "=")                          \
   84.80 +    _(SEMICOLON,          ";")                          \
   84.81 +    _(LBRACE,             "{")                          \
   84.82 +    _(RBRACE,             "}")                          \
   84.83 +    _(LPAREN,             "(")                          \
   84.84 +    _(RPAREN,             ")")                          \
   84.85 +    _(LBRACKET,           "[")                          \
   84.86 +    _(RBRACKET,           "]")                          \
   84.87 +    _(ASSIGN_ADD,         "+=")                         \
   84.88 +    _(ASSIGN_SUB,         "-=")                         \
   84.89 +    _(ASSIGN_MUL,         "*=")                         \
   84.90 +    _(ASSIGN_DIV,         "/=")                         \
   84.91 +    _(ASSIGN_MOD,         "%=")                         \
   84.92 +    _(ASSIGN_BITAND,      "&=")                         \
   84.93 +    _(ASSIGN_BITOR,       "|=")                         \
   84.94 +    _(ASSIGN_BITXOR,      "^=")                         \
   84.95 +    _(ASSIGN_SHR,         ">>=")                        \
   84.96 +    _(ASSIGN_USHR,        ">>>=")                       \
   84.97 +    _(ASSIGN_SHL,         "<<=")                        \
   84.98 +    _(INCREMENT,          "++")                         \
   84.99 +    _(DECREMENT,          "--")                         \
  84.100 +    _(EQUALS,             "==")                         \
  84.101 +    _(NOTEQUALS,          "!=")                         \
  84.102 +    _(LT,                 "<")                          \
  84.103 +    _(LE,                 "<=")                         \
  84.104 +    _(GT,                 ">")                          \
  84.105 +    _(GE,                 ">=")                         \
  84.106 +    _(AND,                "&&")                         \
  84.107 +    _(OR,                 "||")                         \
  84.108 +    _(COMMA,              ",")                          \
  84.109 +    _(NOT,                "!")                          \
  84.110 +    _(TILDE,              "~")                          \
  84.111 +    _(QMARK,              "?")                          \
  84.112 +    _(COLON,              ":")                          \
  84.113 +    _(UNDERSCORE,         "_")                          \
  84.114 +    _(DOT,                ".")                          \
  84.115 +    _(EOF,                "<end-of-file>")
  84.116 +
  84.117 +enum TokenKind
  84.118 +{
  84.119 +#   define _(name, str) TOK_##name,
  84.120 +    TOKENMAP(_)
  84.121 +#   undef _
  84.122 +    TOK_BITAND = TOK_AMPERSAND,
  84.123 +    TOKENS_TOTAL
  84.124 +};
  84.125 +
  84.126 +extern const char *TokenNames[];
  84.127 +
  84.128 +} // namespace ke
  84.129 +
  84.130 +#endif //_include_jitcraft_token_h_
    85.1 --- a/src/jitcraft.vcxproj	Mon Sep 17 00:10:01 2012 -0700
    85.2 +++ b/src/jitcraft.vcxproj	Sat Nov 17 18:41:01 2012 -0800
    85.3 @@ -97,9 +97,15 @@
    85.4      <ClCompile Include="API.cpp" />
    85.5      <ClCompile Include="Array.cpp" />
    85.6      <ClCompile Include="Box.cpp" />
    85.7 -    <ClCompile Include="BytecodeCompiler.cpp" />
    85.8 -    <ClCompile Include="BytecodeEmitter.cpp" />
    85.9 -    <ClCompile Include="CompileContext.cpp" />
   85.10 +    <ClCompile Include="compiler\BytecodeEmitter.cpp" />
   85.11 +    <ClCompile Include="compiler\CompileContext.cpp" />
   85.12 +    <ClCompile Include="compiler\HIR.cpp" />
   85.13 +    <ClCompile Include="compiler\NameBinding.cpp" />
   85.14 +    <ClCompile Include="compiler\Parser.cpp" />
   85.15 +    <ClCompile Include="compiler\Scanner.cpp" />
   85.16 +    <ClCompile Include="compiler\Scopes.cpp" />
   85.17 +    <ClCompile Include="compiler\SemanticAnalysis.cpp" />
   85.18 +    <ClCompile Include="compiler\Symbols.cpp" />
   85.19      <ClCompile Include="Environments.cpp" />
   85.20      <ClCompile Include="Exception.cpp" />
   85.21      <ClCompile Include="FixedArray.cpp" />
   85.22 @@ -109,16 +115,12 @@
   85.23      <ClCompile Include="Interpreter.cpp" />
   85.24      <ClCompile Include="main.cpp" />
   85.25      <ClCompile Include="Modules.cpp" />
   85.26 -    <ClCompile Include="NameBinding.cpp" />
   85.27 +    <ClCompile Include="NativeTable.cpp" />
   85.28      <ClCompile Include="Opcodes.cpp" />
   85.29 -    <ClCompile Include="Parser.cpp" />
   85.30      <ClCompile Include="Platform-Windows.cpp" />
   85.31      <ClCompile Include="PoolAllocator.cpp" />
   85.32      <ClCompile Include="Reference.cpp" />
   85.33      <ClCompile Include="RootScopes.cpp" />
   85.34 -    <ClCompile Include="Scanner.cpp" />
   85.35 -    <ClCompile Include="Scopes.cpp" />
   85.36 -    <ClCompile Include="SemanticAnalysis.cpp" />
   85.37      <ClCompile Include="Spaces.cpp" />
   85.38      <ClCompile Include="Stack.cpp" />
   85.39      <ClCompile Include="StringPool.cpp" />
   85.40 @@ -133,13 +135,20 @@
   85.41      <ClInclude Include="..\include\keima_util.h" />
   85.42      <ClInclude Include="AllocatorPolicies.h" />
   85.43      <ClInclude Include="Array.h" />
   85.44 -    <ClInclude Include="AST.h" />
   85.45      <ClInclude Include="Barriers.h" />
   85.46      <ClInclude Include="Box.h" />
   85.47 -    <ClInclude Include="BytecodeEmitter.h" />
   85.48 -    <ClInclude Include="BytecodeCompiler.h" />
   85.49      <ClInclude Include="CompactBuffer.h" />
   85.50 -    <ClInclude Include="CompileContext.h" />
   85.51 +    <ClInclude Include="compiler\AST.h" />
   85.52 +    <ClInclude Include="compiler\BytecodeEmitter.h" />
   85.53 +    <ClInclude Include="compiler\CompileContext.h" />
   85.54 +    <ClInclude Include="compiler\HIR.h" />
   85.55 +    <ClInclude Include="compiler\NameBinding.h" />
   85.56 +    <ClInclude Include="compiler\Parser.h" />
   85.57 +    <ClInclude Include="compiler\Scanner.h" />
   85.58 +    <ClInclude Include="compiler\Scopes.h" />
   85.59 +    <ClInclude Include="compiler\SemanticAnalysis.h" />
   85.60 +    <ClInclude Include="compiler\Symbols.h" />
   85.61 +    <ClInclude Include="compiler\Token.h" />
   85.62      <ClInclude Include="Environments.h" />
   85.63      <ClInclude Include="FixedArray.h" />
   85.64      <ClInclude Include="Functions.h" />
   85.65 @@ -151,21 +160,18 @@
   85.66      <ClInclude Include="Interpreter.h" />
   85.67      <ClInclude Include="Messages.h" />
   85.68      <ClInclude Include="Modules.h" />
   85.69 -    <ClInclude Include="NameBinding.h" />
   85.70      <ClInclude Include="Heap.h" />
   85.71 +    <ClInclude Include="NativeTable.h" />
   85.72      <ClInclude Include="Objects.h" />
   85.73      <ClInclude Include="ObjectVisitor.h" />
   85.74      <ClInclude Include="Opcodes.h" />
   85.75 -    <ClInclude Include="Parser.h" />
   85.76      <ClInclude Include="Platform.h" />
   85.77      <ClInclude Include="PoolAllocator.h" />
   85.78      <ClInclude Include="Handles.h" />
   85.79 +    <ClInclude Include="QualType.h" />
   85.80      <ClInclude Include="Reference.h" />
   85.81      <ClInclude Include="RootScopes.h" />
   85.82 -    <ClInclude Include="Scanner.h" />
   85.83 -    <ClInclude Include="Scopes.h" />
   85.84      <ClInclude Include="Code.h" />
   85.85 -    <ClInclude Include="SemanticAnalysis.h" />
   85.86      <ClInclude Include="Spaces-inl.h" />
   85.87      <ClInclude Include="Spaces.h" />
   85.88      <ClInclude Include="Stack.h" />
   85.89 @@ -177,7 +183,6 @@
   85.90      <ClInclude Include="Vector.h" />
   85.91      <ClInclude Include="VirtualObjectVisitor.h" />
   85.92      <ClInclude Include="Zone.h" />
   85.93 -    <ClInclude Include="Token.h" />
   85.94      <ClInclude Include="Utility.h" />
   85.95    </ItemGroup>
   85.96    <ItemGroup>
   85.97 @@ -187,4 +192,4 @@
   85.98    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   85.99    <ImportGroup Label="ExtensionTargets">
  85.100    </ImportGroup>
  85.101 -</Project>
  85.102 +</Project>
  85.103 \ No newline at end of file
    86.1 --- a/src/main.cpp	Mon Sep 17 00:10:01 2012 -0700
    86.2 +++ b/src/main.cpp	Sat Nov 17 18:41:01 2012 -0800
    86.3 @@ -54,6 +54,31 @@
    86.4      }
    86.5  } s_Reporter;
    86.6  
    86.7 +class MainCollector : public Ke::IPublicFunctionListener
    86.8 +{
    86.9 +  public:
   86.10 +    MainCollector()
   86.11 +    {
   86.12 +    }
   86.13 +    void registerPublic(Handle<Function> fun) {
   86.14 +        Local<String> str = fun->name();
   86.15 +        if (str && strcmp(str->chars(), "main") == 0)
   86.16 +            fun_ = fun;
   86.17 +    }
   86.18 +
   86.19 +    void unregisterPublic(Handle<Function> fun) {
   86.20 +        if (fun_ == fun)
   86.21 +            fun_ = Handle<Function>();
   86.22 +    }
   86.23 +
   86.24 +    Handle<Function> fun() const {
   86.25 +        return fun_;
   86.26 +    }
   86.27 +
   86.28 +  private:
   86.29 +    Root<Function> fun_;
   86.30 +};
   86.31 +
   86.32  intptr_t PrintFloat(void *blah, intptr_t *params)
   86.33  {
   86.34      fprintf(stdout, "%f", *reinterpret_cast<float *>(&params[1]));
   86.35 @@ -86,36 +111,22 @@
   86.36  
   86.37      Keima::InstallMessageReporter(&s_Reporter);
   86.38      {
   86.39 +        MainCollector entry;
   86.40 +        Keima::SetPublicFunctionListener(&entry);
   86.41 +
   86.42          HandleScope scope;
   86.43 -        Local<Module> module = Compile(argv[1]);
   86.44 -        if (!module)
   86.45 -            return 1;
   86.46 +        Compile(argv[1]);
   86.47  
   86.48          Keima::CollectGarbage();
   86.49  
   86.50 -        // Look for a public named "main".
   86.51 -        Local<Function> fun;
   86.52 -        for (unsigned i = 0; i < module->numPublics(); i++) {
   86.53 -            if (strcmp(module->getPublic(i)->name()->chars(), "main") == 0) {
   86.54 -                fun = module->getPublic(i);
   86.55 -                break;
   86.56 -            }
   86.57 -        }
   86.58 +        Keima::BindNative("PrintFloat", PrintFloat);
   86.59 +        Keima::BindNative("PrintNum", PrintNum);
   86.60 +        Keima::BindNative("PrintString", PrintString);
   86.61  
   86.62 -        for (unsigned i = 0; i < module->numNatives(); i++) {
   86.63 -            Local<Native> native = module->getNative(i);
   86.64 -
   86.65 -            if (strcmp(native->name()->chars(), "PrintFloat") == 0)
   86.66 -                native->bind(reinterpret_cast<void *>(PrintFloat));
   86.67 -            else if (strcmp(native->name()->chars(), "PrintNum") == 0)
   86.68 -                native->bind(reinterpret_cast<void *>(PrintNum));
   86.69 -            else if (strcmp(native->name()->chars(), "PrintString") == 0)
   86.70 -                native->bind(reinterpret_cast<void *>(PrintString));
   86.71 -        }
   86.72 -
   86.73 +        Handle<Function> fun = entry.fun();
   86.74  
   86.75          if (!fun) {
   86.76 -            fprintf(stdout, "Plugin compiles!\nNot running; no public 'main'.\n");
   86.77 +            fprintf(stdout, "Not running; no public 'main'.\n");
   86.78          } else {
   86.79              if (!Keima::Invoke(fun, NULL, 0, true, &rval))
   86.80                  rval = 1;
    87.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    87.2 +++ b/tests/basic/floats.out	Sat Nov 17 18:41:01 2012 -0800
    87.3 @@ -0,0 +1,1 @@
    87.4 +5012.000000
    88.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    88.2 +++ b/tests/basic/floats.sp	Sat Nov 17 18:41:01 2012 -0800
    88.3 @@ -0,0 +1,9 @@
    88.4 +native PrintFloat(float:num);
    88.5 +
    88.6 +main()
    88.7 +{
    88.8 +   new float:f = 12.0;
    88.9 +   for (new i = 0; i < 100; i = i + 1)
   88.10 +      f = f + 0.5 + i;
   88.11 +   PrintFloat(f);
   88.12 +}
    89.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    89.2 +++ b/tests/display.py	Sat Nov 17 18:41:01 2012 -0800
    89.3 @@ -0,0 +1,23 @@
    89.4 +# vim: set ts=2 sw=2 tw=99 ft=python et:
    89.5 +
    89.6 +class Interactive:
    89.7 +  def __init__(self):
    89.8 +    self.failures = []
    89.9 +    self.timeouts = []
   89.10 +
   89.11 +  def begin(self, tests):
   89.12 +    return
   89.13 +
   89.14 +  def result(self, test, r):
   89.15 +    if r.ok:
   89.16 +      print('PASS: ' + test.name)
   89.17 +    else:
   89.18 +      if r.timeout:
   89.19 +        print('TIMEOUT: ' + test.name)
   89.20 +      else:
   89.21 +        print('FAIL: ' + test.name)
   89.22 +      print(' -- Error code: ' + str(r.code))
   89.23 +      print(' -- message: \n' + r.message)
   89.24 +      print(' -- stdout: \n' + r.out)
   89.25 +      print(' -- stderr: \n' + r.err)
   89.26 +
    90.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    90.2 +++ b/tests/harness.py	Sat Nov 17 18:41:01 2012 -0800
    90.3 @@ -0,0 +1,118 @@
    90.4 +# vim: set ts=2 sw=4 tw=99 ft=python et:
    90.5 +import os
    90.6 +import re
    90.7 +import sys
    90.8 +import time
    90.9 +import os.path
   90.10 +from test import Test
   90.11 +from subprocess import *
   90.12 +from threading import Thread
   90.13 +from display import Interactive
   90.14 +
   90.15 +def FindTests(tests, root, folder):
   90.16 +  folders = []
   90.17 +  for name in os.listdir(os.path.join(root, folder)):
   90.18 +    path = os.path.join(root, folder, name)
   90.19 +    if os.path.isdir(path):
   90.20 +      folders.append(name)
   90.21 +      continue
   90.22 +
   90.23 +    path = os.path.join(root, folder)
   90.24 +    out = re.match("^([^\.]+)\.out$", name)
   90.25 +    err = re.match("^([^\.]+)\.err$", name)
   90.26 +    if out:
   90.27 +        name = out.group(1)
   90.28 +        tests.append(Test(path, name, 'out'))
   90.29 +    elif err:
   90.30 +        name = err.group(1)
   90.31 +        tests.append(Test(path, name, 'err'))
   90.32 +
   90.33 +  for name in folders:
   90.34 +    path = os.path.join(folder, name)
   90.35 +    FindTests(tests, root, path)
   90.36 +
   90.37 +def IsTestRoot(path, name):
   90.38 +  return os.path.isdir(path)
   90.39 +
   90.40 +def RunTest_(argv, options, L):
   90.41 +  if sys.platform != 'win32':
   90.42 +    options['close_fds'] = True
   90.43 +
   90.44 +  p = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE, **options)
   90.45 +
   90.46 +  L[0] = p
   90.47 +  out, err = p.communicate()
   90.48 +  L[1] = (out, err, p.returncode)
   90.49 +
   90.50 +def RunTest(test, options, shell):
   90.51 +  argv = [shell, test.cmd()]
   90.52 +
   90.53 +  L = [None, None]
   90.54 +  timeout = False
   90.55 +  th = Thread(target = RunTest_, args = (argv, options, L))
   90.56 +  th.start()
   90.57 +  th.join(60.0)
   90.58 +  while th.isAlive():
   90.59 +    if L[0] is not None:
   90.60 +      try:
   90.61 +        L[0].kill()
   90.62 +        time.sleep(.1)
   90.63 +        timeout = True
   90.64 +      except OSError:
   90.65 +        # Expecting a "No such process" error
   90.66 +        pass
   90.67 +
   90.68 +  th.join()
   90.69 +  (out, err, code) = L[1]
   90.70 +
   90.71 +  return test.check(out, err, code, timeout)
   90.72 +
   90.73 +def RunTests(display, tests, shell):
   90.74 +  display.begin(tests)
   90.75 +  ok = True
   90.76 +  try:
   90.77 +    for test in tests:
   90.78 +      options = { }
   90.79 +      result = RunTest(test, options, shell)
   90.80 +
   90.81 +      ok = ok and result.ok
   90.82 +      
   90.83 +      display.result(test, result)
   90.84 +  except KeyboardInterrupt:
   90.85 +    display.cancel()
   90.86 +    ok = False
   90.87 +
   90.88 +  return ok
   90.89 +
   90.90 +  
   90.91 +def main(argv):
   90.92 +  root = os.path.dirname(os.path.abspath(__file__))
   90.93 +
   90.94 +  from optparse import OptionParser
   90.95 +  op = OptionParser(usage='%prog [options] <shell>')
   90.96 +  (options, args) = op.parse_args(argv)
   90.97 +
   90.98 +  if len(args) != 1:
   90.99 +    op.error('missing <shell> argument')
  90.100 +
  90.101 +  shell = os.path.normpath(args[0])
  90.102 +
  90.103 +  tests = []
  90.104 +  for name in os.listdir(root):
  90.105 +    path = os.path.join(root, name)
  90.106 +    if IsTestRoot(path, name):
  90.107 +      FindTests(tests, root, name)
  90.108 +
  90.109 +  if len(tests) == 0:
  90.110 +    op.error('no test cases found')
  90.111 +
  90.112 +  display = Interactive()
  90.113 +  ok = RunTests(display, tests, shell)
  90.114 +  if ok:
  90.115 +    sys.exit(0)
  90.116 +  else:
  90.117 +    sys.exit(1)
  90.118 +
  90.119 +if __name__ == '__main__':
  90.120 +  main(sys.argv[1:])
  90.121 +
    91.1 --- a/tests/prototype/floats.sp	Mon Sep 17 00:10:01 2012 -0700
    91.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    91.3 @@ -1,7 +0,0 @@
    91.4 -main()
    91.5 -{
    91.6 -   new Float:f = 12.0;
    91.7 -   for (new i = 0; i < 100; i = i + 1)
    91.8 -      f = f + 0.5 + i;
    91.9 -   return f;
   91.10 -}
    92.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    92.2 +++ b/tests/test.py	Sat Nov 17 18:41:01 2012 -0800
    92.3 @@ -0,0 +1,60 @@
    92.4 +# vim: set ts=2 sw=4 tw=99 ft=python et:
    92.5 +import os
    92.6 +import os.path
    92.7 +
    92.8 +class Result:
    92.9 +  def __init__(self, ok, out, err, code, timeout, message):
   92.10 +    self.ok = ok
   92.11 +    self.out = out
   92.12 +    self.err = err
   92.13 +    self.code = code
   92.14 +    self.timeout = timeout
   92.15 +    self.message = message
   92.16 +
   92.17 +class Test:
   92.18 +  def __init__(self, path, name, type):
   92.19 +    self.path = path
   92.20 +    self.name = name
   92.21 +    self.type = type
   92.22 +
   92.23 +  def cmd(self):
   92.24 +    return os.path.join(self.path, self.name + '.sp')
   92.25 +
   92.26 +  def compare(self, text):
   92.27 +    ok = True
   92.28 +    message = None
   92.29 +    with open(os.path.join(self.path, self.name + '.' + self.type)) as f:
   92.30 +      lines = text.split('\n')
   92.31 +      i = 0
   92.32 +      for line in f:
   92.33 +        line = line.rstrip('\r\n')
   92.34 +        if line != lines[i]:
   92.35 +          message = 'Got "' + lines[i] + '", expected "' + line + '"'
   92.36 +          ok = False
   92.37 +          break
   92.38 +        i += 1
   92.39 +    return (ok, message)
   92.40 +
   92.41 +  def check(self, out, err, code, timeout):
   92.42 +    if not out:
   92.43 +      out = ''
   92.44 +    if not err:
   92.45 +      err = ''
   92.46 +    if self.type == 'err':
   92.47 +      if code == 0:
   92.48 +        message = 'Expected failure, got success'
   92.49 +        ok = False
   92.50 +      else:
   92.51 +        (ok, message) = self.compare(err)
   92.52 +    elif self.type == 'out':
   92.53 +      if code != 0:
   92.54 +        message = 'Expected success, got failure (code: ' + str(code) + ')'
   92.55 +        ok = False
   92.56 +      else:
   92.57 +        (ok, message) = self.compare(out)
   92.58 +
   92.59 +    if timeout:
   92.60 +      ok = false
   92.61 +      message = 'timeout'
   92.62 +
   92.63 +    return Result(ok, out, err, code, timeout, message)