jitcraft/Scopes.cpp
author David Anderson <dvander@alliedmods.net>
Tue Jul 10 02:11:13 2012 -0700 (2012-07-10)
changeset 68 b40b0e18a918
parent 63 dd57743d220e
child 84 eaa43f765cbd
permissions -rw-r--r--
Added support for ISourcePawnEngine natives.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include "Scopes.h"
    20 #include "Zone.h"
    21 #include "Types.h"
    22 #include "TypeManager.h"
    23 #include "Strings.h"
    24 
    25 using namespace ke;
    26 
    27 Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
    28   : pool_(pool),
    29     locals_(0),
    30     maxContainedLocals_(0),
    31     numFunctions_(0),
    32     numNatives_(0),
    33     lifoSlot_(NULL),
    34     kind_(kind),
    35     enclosing_(enclosing)
    36 {
    37 }
    38 
    39 bool
    40 Scope::initialize()
    41 {
    42     if (enclosing_ && !enclosing_->children_.append(this))
    43         return false;
    44     return true;
    45 }
    46 
    47 void
    48 Scope::unlink()
    49 {
    50     assert(empty());
    51 
    52     assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
    53     enclosing_->children_.pop();
    54 
    55     // OOM here is swallowed and checked after compilation.
    56     // :TODO: make the above true.
    57     for (size_t i = 0; i < children_.length(); i++)
    58         enclosing_->children_.append(children_[i]);
    59 }
    60 
    61 Scope *
    62 Scope::unlinkIfEmpty()
    63 {
    64     if (empty()) {
    65         unlink();
    66         return NULL;
    67     }
    68     return this;
    69 }
    70 
    71 BoundName *
    72 Scope::localLookup(Handle<String> name)
    73 {
    74     for (size_t i = 0; i < names_.length(); i++) {
    75         if (names_[i]->name() == name)
    76             return names_[i];
    77     }
    78     return NULL;
    79 }
    80 
    81 BoundName *
    82 Scope::lookup(Handle<String> name)
    83 {
    84     for (Scope *scope = this; scope; scope = scope->enclosing()) {
    85         if (BoundName *bound = scope->localLookup(name))
    86             return bound;
    87     }
    88     return NULL;
    89 }
    90 
    91 Variable *
    92 Scope::declareVariable(Handle<String> name, const SourcePosition &pos)
    93 {
    94     assert(!localLookup(name));
    95     
    96     Variable *var = new (pool_) Variable(this, name, pos);
    97     if (!names_.append(var))
    98         return NULL;
    99     return var;
   100 }
   101 
   102 Variable *
   103 Scope::declareArgument(Handle<String> name, const SourcePosition &pos)
   104 {
   105     assert(kind() == FUNCTION);
   106     Variable *var = declareVariable(name, pos);
   107     if (!names_.append(var))
   108         return NULL;
   109     if (!parameters_.append(var))
   110         return NULL;
   111     return var;
   112 }
   113 
   114 NamedFunction *
   115 Scope::declareFunction(Handle<String> name, const SourcePosition &pos, TokenKind token)
   116 {
   117     assert(!localLookup(name));
   118     assert(kind() == GLOBAL);
   119 
   120     NamedFunction *fun = new (pool_) NamedFunction(this, name, pos, token);
   121     if (!names_.append(fun))
   122         return NULL;
   123     return fun;
   124 }
   125 
   126 NamedEnum *
   127 Scope::declareEnum(Handle<String> name, const SourcePosition &pos)
   128 {
   129     NamedEnum *e = new (pool_) NamedEnum(this, name, pos);
   130     if (!names_.append(e))
   131         return NULL;
   132     return e;
   133 }
   134 
   135 NamedConstant *
   136 Scope::declareConstant(Handle<String> name, const SourcePosition &pos)
   137 {
   138     NamedConstant *constant = new (pool_) NamedConstant(this, name, pos);
   139     if (!names_.append(constant))
   140         return NULL;
   141     return constant;
   142 }
   143 
   144 void
   145 Scope::allocateGlobals()
   146 {
   147     assert(kind() == GLOBAL);
   148 
   149     for (size_t i = 0; i < children_.length(); i++) {
   150         assert(children_[i]->kind() == FUNCTION);
   151         children_[i]->allocate();
   152     }
   153 
   154     for (size_t i = 0; i < names_.length(); i++) {
   155         BoundName *name = names_[i];
   156         
   157         if (name->kind() == BoundName::FUNCTION) {
   158             NamedFunction *fun = name->toNamedFunction();
   159             if (fun->isNative())
   160                 fun->allocate(numNatives_++);
   161             else
   162                 fun->allocate(numFunctions_++);
   163         }
   164     }
   165 }
   166 
   167 void
   168 Scope::allocate(Variable *var)
   169 {
   170     if (!var->unallocated())
   171         return;
   172 
   173     var->allocate(Variable::STACK, maxContainedLocals_ + locals_);
   174     locals_++;
   175 }
   176 
   177 void
   178 Scope::allocate()
   179 {
   180     maxContainedLocals_ = 0;
   181     for (size_t i = 0; i < children_.length(); i++) {
   182         Scope *scope = children_[i];
   183         scope->allocate();
   184         if (scope->maxContainedLocals() > maxContainedLocals_)
   185             maxContainedLocals_ = scope->maxContainedLocals();
   186     }
   187 
   188     for (size_t i = 0; i < parameters_.length(); i++)
   189         parameters_[i]->allocate(Variable::PARAMETER, i);
   190 
   191     if (lifoSlot_)
   192         allocate(lifoSlot_);
   193     for (size_t i = 0; i < names_.length(); i++) {
   194         if (names_[i]->kind() != BoundName::VARIABLE)
   195             continue;
   196 
   197         allocate(names_[i]->toVariable());
   198     }
   199 
   200     maxContainedLocals_ += locals_;
   201 }
   202 
   203 bool
   204 Scope::Bind(ParseTree *tree)
   205 {
   206     Local<String> name(ZONE());
   207     for (size_t i = 0; i < tree->unbound()->length(); i++) {
   208         NameProxy *proxy = tree->unbound()->at(i);
   209         name = proxy->name();
   210         BoundName *binding = tree->scope()->lookup(name);
   211         if (!binding) {
   212             assert(false);
   213             return false;
   214         }
   215 
   216         proxy->bind(binding);
   217     }
   218     return true;
   219 }
   220 
   221 void
   222 Scope::Allocate(ParseTree *tree)
   223 {
   224     tree->scope()->allocateGlobals();
   225 }
   226 
   227 void
   228 Scope::setUsesLifoHeap()
   229 {
   230     // Only one lifo slot is needed per scope.
   231     if (lifoSlot_)
   232         return;
   233 
   234     // If the parent of this scope is the function scope, then this is the
   235     // function's block scope, and the lifo slot is part of the Frame instead.
   236     // Note we can get a function scope here if we're making a temporary in a
   237     // function with no local variables.
   238     if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
   239         return;
   240 
   241     Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
   242     if (!type)
   243         return;
   244 
   245     Local<String> name(ZONE());
   246     lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
   247     lifoSlot_->setType(type);
   248 }