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