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