src/Scopes.cpp
author David Anderson <dvander@alliedmods.net>
Sun Sep 16 21:59:26 2012 -0700 (2012-09-16)
changeset 190 dd04fce774cd
parent 145 e9d804821c48
permissions -rw-r--r--
Enable dynamic array declarations.
     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 #include "CompileContext.h"
    25 #include "Environments.h"
    26 #include "Spaces-inl.h"
    27 #include "Heap-inl.h"
    28 
    29 using namespace ke;
    30 
    31 Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
    32   : pool_(pool),
    33     locals_(0),
    34     maxContainedLocals_(0),
    35     numFunctions_(0),
    36     numNatives_(0),
    37     lifoSlot_(NULL),
    38     kind_(kind),
    39     enclosing_(enclosing)
    40 {
    41 }
    42 
    43 bool
    44 Scope::initialize()
    45 {
    46     if (enclosing_ && !enclosing_->children_.append(this))
    47         return false;
    48     return true;
    49 }
    50 
    51 void
    52 Scope::unlink()
    53 {
    54     assert(empty());
    55 
    56     assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
    57     enclosing_->children_.pop();
    58 
    59     // OOM here is swallowed and checked after compilation.
    60     // :TODO: make the above true.
    61     for (size_t i = 0; i < children_.length(); i++)
    62         enclosing_->children_.append(children_[i]);
    63 }
    64 
    65 Scope *
    66 Scope::unlinkIfEmpty()
    67 {
    68     if (empty()) {
    69         unlink();
    70         return NULL;
    71     }
    72     return this;
    73 }
    74 
    75 BoundName *
    76 Scope::localLookup(Handle<String> name)
    77 {
    78     for (size_t i = 0; i < names_.length(); i++) {
    79         if (names_[i]->name() == name)
    80             return names_[i];
    81     }
    82     return NULL;
    83 }
    84 
    85 BoundName *
    86 Scope::lookup(Handle<String> name)
    87 {
    88     for (Scope *scope = this; scope; scope = scope->enclosing()) {
    89         if (BoundName *bound = scope->localLookup(name))
    90             return bound;
    91     }
    92     return NULL;
    93 }
    94 
    95 Variable *
    96 Scope::declareVariable(Handle<String> name, const SourcePosition &pos)
    97 {
    98     assert(!localLookup(name));
    99     
   100     Variable *var = new (pool_) Variable(this, name, pos);
   101     if (!names_.append(var))
   102         return NULL;
   103     return var;
   104 }
   105 
   106 Variable *
   107 Scope::declareArgument(Handle<String> name, const SourcePosition &pos)
   108 {
   109     assert(kind() == FUNCTION);
   110     Variable *var = declareVariable(name, pos);
   111     if (!names_.append(var))
   112         return NULL;
   113     if (!parameters_.append(var))
   114         return NULL;
   115     return var;
   116 }
   117 
   118 NamedFunction *
   119 Scope::declareFunction(Handle<String> name, const SourcePosition &pos, TokenKind token)
   120 {
   121     assert(!localLookup(name));
   122     assert(kind() == GLOBAL);
   123 
   124     NamedFunction *fun = new (pool_) NamedFunction(this, name, pos, token);
   125     if (!names_.append(fun))
   126         return NULL;
   127     return fun;
   128 }
   129 
   130 NamedConstant *
   131 Scope::declareConstant(Handle<String> name, const SourcePosition &pos)
   132 {
   133     NamedConstant *constant = new (pool_) NamedConstant(this, name, pos);
   134     if (!names_.append(constant))
   135         return NULL;
   136     return constant;
   137 }
   138 
   139 NamedType *
   140 Scope::declareType(Handle<String> name, const SourcePosition &pos)
   141 {
   142     NamedType *decl = new (pool_) NamedType(this, name, pos);
   143     if (!names_.append(decl))
   144         return NULL;
   145     return decl;
   146 }
   147 
   148 NamedType *
   149 Scope::declareType(Handle<String> name, Handle<Type> type)
   150 {
   151     NamedType *decl = new (pool_) NamedType(this, name, type);
   152     if (!names_.append(decl))
   153         return NULL;
   154     return decl;
   155 }
   156 
   157 void
   158 Scope::allocateGlobals()
   159 {
   160     assert(kind() == GLOBAL);
   161 
   162     for (size_t i = 0; i < children_.length(); i++) {
   163         assert(children_[i]->kind() == FUNCTION);
   164         children_[i]->allocate();
   165     }
   166 
   167     Local<Type> type(ZONE());
   168     for (size_t i = 0; i < names_.length(); i++) {
   169         BoundName *name = names_[i];
   170 
   171         if (name->kind() == BoundName::FUNCTION) {
   172             NamedFunction *fun = name->toNamedFunction();
   173             if (!fun->used())
   174                 continue;
   175 
   176             if (fun->isNative())
   177                 fun->allocate(numNatives_++);
   178             else
   179                 fun->allocate(numFunctions_++);
   180         } else if (name->kind() == BoundName::VARIABLE) {
   181             allocate(name->toVariable());
   182         }
   183     }
   184 }
   185 
   186 void
   187 Scope::allocate(Variable *var)
   188 {
   189     if (!var->unallocated())
   190         return;
   191 
   192     if (kind() == GLOBAL) {
   193         var->allocate(Variable::ENVIRONMENT, envVars_.length());
   194         envVars_.append(var);
   195     } else {
   196         var->allocate(Variable::STACK, maxContainedLocals_ + locals_);
   197         locals_++;
   198     }
   199 }
   200 
   201 void
   202 Scope::allocate()
   203 {
   204     maxContainedLocals_ = 0;
   205     for (size_t i = 0; i < children_.length(); i++) {
   206         Scope *scope = children_[i];
   207         scope->allocate();
   208         if (scope->maxContainedLocals() > maxContainedLocals_)
   209             maxContainedLocals_ = scope->maxContainedLocals();
   210     }
   211 
   212     for (size_t i = 0; i < parameters_.length(); i++)
   213         parameters_[i]->allocate(Variable::PARAMETER, i);
   214 
   215     if (lifoSlot_)
   216         allocate(lifoSlot_);
   217     for (size_t i = 0; i < names_.length(); i++) {
   218         if (names_[i]->kind() != BoundName::VARIABLE)
   219             continue;
   220 
   221         allocate(names_[i]->toVariable());
   222     }
   223 
   224     maxContainedLocals_ += locals_;
   225 }
   226 
   227 bool
   228 Scope::Bind(CompileContext &cc, ParseTree *tree)
   229 {
   230     Local<String> name(ZONE());
   231     for (size_t i = 0; i < tree->unbound()->length(); i++) {
   232         NameProxy *proxy = tree->unbound()->at(i);
   233         name = proxy->name();
   234         BoundName *binding = tree->scope()->lookup(name);
   235 
   236         if (!binding) {
   237             cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
   238             return false;
   239         }
   240 
   241         // We only allow global functions to be late-bound.
   242         if (binding->kind() != BoundName::FUNCTION ||
   243             binding->scope()->kind() != Scope::GLOBAL)
   244         {
   245             cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
   246             return false;
   247         }
   248 
   249         proxy->bind(binding);
   250 
   251         // Find the function the proxy is defined in.
   252     }
   253     return true;
   254 }
   255 
   256 void
   257 Scope::Allocate(ParseTree *tree)
   258 {
   259     tree->scope()->allocateGlobals();
   260 }
   261 
   262 void
   263 Scope::setUsesLifoHeap()
   264 {
   265     // Only one lifo slot is needed per scope.
   266     if (lifoSlot_)
   267         return;
   268 
   269     // If the parent of this scope is the function scope, then this is the
   270     // function's block scope, and the lifo slot is part of the Frame instead.
   271     // Note we can get a function scope here if we're making a temporary in a
   272     // function with no local variables.
   273     if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
   274         return;
   275 
   276     Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
   277     if (!type)
   278         return;
   279 
   280     Local<String> name(ZONE());
   281     lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
   282     lifoSlot_->setType(type);
   283 }
   284 
   285 EnvironmentMap *
   286 Scope::createEnvironmentMap(Zone *zone)
   287 {
   288     return EnvironmentMap::New(zone, envVars_.length(), envVars_.buffer());
   289 }