jitcraft/Scopes.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jul 07 21:01:39 2012 -0700 (2012-07-07)
changeset 57 8f1e74d35718
parent 54 8e22792a3921
child 58 4d6265f95ff1
permissions -rw-r--r--
Convert AST std::vector to PoolList.
     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 jc;
    26 
    27 Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
    28   : pool_(pool),
    29     locals_(0),
    30     maxContainedLocals_(0),
    31     numFunctions_(0),
    32     lifoSlot_(NULL),
    33     kind_(kind),
    34     enclosing_(enclosing)
    35 {
    36 }
    37 
    38 bool
    39 Scope::initialize()
    40 {
    41     if (enclosing_)
    42         enclosing_->children_.push_back(this);
    43     return true;
    44 }
    45 
    46 void
    47 Scope::unlink()
    48 {
    49     assert(empty());
    50 
    51     assert(enclosing_->children_[enclosing_->children_.size() - 1] == this);
    52     enclosing_->children_.pop_back();
    53 
    54     for (size_t i = 0; i < children_.size(); i++)
    55         enclosing_->children_.push_back(children_[i]);
    56 }
    57 
    58 Scope *
    59 Scope::unlinkIfEmpty()
    60 {
    61     if (empty()) {
    62         unlink();
    63         return NULL;
    64     }
    65     return this;
    66 }
    67 
    68 BoundName *
    69 Scope::localLookup(Handle<String> name)
    70 {
    71     for (size_t i = 0; i < names_.size(); i++) {
    72         if (names_[i]->name() == name)
    73             return names_[i];
    74     }
    75     return NULL;
    76 }
    77 
    78 BoundName *
    79 Scope::lookup(Handle<String> name)
    80 {
    81     for (Scope *scope = this; scope; scope = scope->enclosing()) {
    82         if (BoundName *bound = scope->localLookup(name))
    83             return bound;
    84     }
    85     return NULL;
    86 }
    87 
    88 Variable *
    89 Scope::declareVariable(Handle<String> name, const SourcePosition &pos)
    90 {
    91     assert(!localLookup(name));
    92     
    93     Variable *var = new (pool_) Variable(this, name, pos);
    94     names_.push_back(var);
    95     return var;
    96 }
    97 
    98 Variable *
    99 Scope::declareArgument(Handle<String> name, const SourcePosition &pos)
   100 {
   101     assert(kind() == FUNCTION);
   102     Variable *var = declareVariable(name, pos);
   103     names_.push_back(var);
   104     parameters_.push_back(var);
   105     return var;
   106 }
   107 
   108 NamedFunction *
   109 Scope::declareFunction(Handle<String> name, const SourcePosition &pos)
   110 {
   111     assert(!localLookup(name));
   112     assert(kind() == GLOBAL);
   113 
   114     NamedFunction *fun = new (pool_) NamedFunction(this, name, pos);
   115     names_.push_back(fun);
   116     return fun;
   117 }
   118 
   119 NamedEnum *
   120 Scope::declareEnum(Handle<String> name, const SourcePosition &pos)
   121 {
   122     NamedEnum *e = new (pool_) NamedEnum(this, name, pos);
   123     names_.push_back(e);
   124     return e;
   125 }
   126 
   127 NamedConstant *
   128 Scope::declareConstant(Handle<String> name, const SourcePosition &pos)
   129 {
   130     NamedConstant *constant = new (pool_) NamedConstant(this, name, pos);
   131     names_.push_back(constant);
   132     return constant;
   133 }
   134 
   135 void
   136 Scope::allocateGlobals()
   137 {
   138     assert(kind() == GLOBAL);
   139 
   140     for (size_t i = 0; i < children_.size(); i++) {
   141         assert(children_[i]->kind() == FUNCTION);
   142         children_[i]->allocate();
   143     }
   144 
   145     for (size_t i = 0; i < names_.size(); i++) {
   146         BoundName *name = names_[i];
   147         
   148         if (name->kind() == BoundName::FUNCTION) {
   149             NamedFunction *fun = name->toNamedFunction();
   150             fun->allocate(numFunctions_++);
   151         }
   152     }
   153 }
   154 
   155 void
   156 Scope::allocate(Variable *var)
   157 {
   158     if (!var->unallocated())
   159         return;
   160 
   161     var->allocate(Variable::STACK, maxContainedLocals_ + locals_);
   162     locals_++;
   163 }
   164 
   165 void
   166 Scope::allocate()
   167 {
   168     maxContainedLocals_ = 0;
   169     for (size_t i = 0; i < children_.size(); i++) {
   170         Scope *scope = children_[i];
   171         scope->allocate();
   172         if (scope->maxContainedLocals() > maxContainedLocals_)
   173             maxContainedLocals_ = scope->maxContainedLocals();
   174     }
   175 
   176     for (size_t i = 0; i < parameters_.size(); i++)
   177         parameters_[i]->allocate(Variable::PARAMETER, i);
   178 
   179     if (lifoSlot_)
   180         allocate(lifoSlot_);
   181     for (size_t i = 0; i < names_.size(); i++) {
   182         if (names_[i]->kind() != BoundName::VARIABLE)
   183             continue;
   184 
   185         allocate(names_[i]->toVariable());
   186     }
   187 
   188     maxContainedLocals_ += locals_;
   189 }
   190 
   191 bool
   192 Scope::Bind(ParseTree *tree)
   193 {
   194     Local<String> name(ZONE());
   195     for (size_t i = 0; i < tree->unbound()->length(); i++) {
   196         NameProxy *proxy = tree->unbound()->at(i);
   197         name = proxy->name();
   198         BoundName *binding = tree->scope()->lookup(name);
   199         if (!binding) {
   200             assert(false);
   201             return false;
   202         }
   203 
   204         proxy->bind(binding);
   205     }
   206     return true;
   207 }
   208 
   209 void
   210 Scope::Allocate(ParseTree *tree)
   211 {
   212     tree->scope()->allocateGlobals();
   213 }
   214 
   215 void
   216 Scope::setUsesLifoHeap()
   217 {
   218     // Only one lifo slot is needed per scope.
   219     if (lifoSlot_)
   220         return;
   221 
   222     // If the parent of this scope is the function scope, then this is the
   223     // function's block scope, and the lifo slot is part of the Frame instead.
   224     // Note we can get a function scope here if we're making a temporary in a
   225     // function with no local variables.
   226     if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
   227         return;
   228 
   229     Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
   230     if (!type)
   231         return;
   232 
   233     Local<String> name(ZONE());
   234     lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
   235     lifoSlot_->setType(type);
   236 }