src/Scopes.cpp
author David Anderson <dvander@alliedmods.net>
Mon Jul 30 00:03:46 2012 -0700 (2012-07-30)
changeset 137 be919b22085b
parent 92 e3974e7360e9
child 145 e9d804821c48
permissions -rw-r--r--
Allow unused functions to be semantically checked, but do not bytecode compile them.
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@137
   161
dvander@28
   162
        if (name->kind() == BoundName::FUNCTION) {
dvander@2
   163
            NamedFunction *fun = name->toNamedFunction();
dvander@137
   164
            if (!fun->used())
dvander@137
   165
                continue;
dvander@137
   166
dvander@68
   167
            if (fun->isNative())
dvander@68
   168
                fun->allocate(numNatives_++);
dvander@68
   169
            else
dvander@68
   170
                fun->allocate(numFunctions_++);
dvander@85
   171
        } else if (name->kind() == BoundName::VARIABLE) {
dvander@85
   172
            allocate(name->toVariable());
dvander@2
   173
        }
dvander@0
   174
    }
dvander@0
   175
}
dvander@0
   176
dvander@0
   177
void
dvander@12
   178
Scope::allocate(Variable *var)
dvander@12
   179
{
dvander@12
   180
    if (!var->unallocated())
dvander@12
   181
        return;
dvander@12
   182
dvander@85
   183
    if (kind() == GLOBAL) {
dvander@85
   184
        var->allocate(Variable::ENVIRONMENT, envVars_.length());
dvander@85
   185
        envVars_.append(var);
dvander@85
   186
    } else {
dvander@85
   187
        var->allocate(Variable::STACK, maxContainedLocals_ + locals_);
dvander@85
   188
        locals_++;
dvander@85
   189
    }
dvander@12
   190
}
dvander@12
   191
dvander@12
   192
void
dvander@0
   193
Scope::allocate()
dvander@0
   194
{
dvander@0
   195
    maxContainedLocals_ = 0;
dvander@58
   196
    for (size_t i = 0; i < children_.length(); i++) {
dvander@0
   197
        Scope *scope = children_[i];
dvander@0
   198
        scope->allocate();
dvander@0
   199
        if (scope->maxContainedLocals() > maxContainedLocals_)
dvander@0
   200
            maxContainedLocals_ = scope->maxContainedLocals();
dvander@0
   201
    }
dvander@0
   202
dvander@58
   203
    for (size_t i = 0; i < parameters_.length(); i++)
dvander@0
   204
        parameters_[i]->allocate(Variable::PARAMETER, i);
dvander@0
   205
dvander@12
   206
    if (lifoSlot_)
dvander@12
   207
        allocate(lifoSlot_);
dvander@58
   208
    for (size_t i = 0; i < names_.length(); i++) {
dvander@2
   209
        if (names_[i]->kind() != BoundName::VARIABLE)
dvander@2
   210
            continue;
dvander@0
   211
dvander@12
   212
        allocate(names_[i]->toVariable());
dvander@0
   213
    }
dvander@0
   214
dvander@0
   215
    maxContainedLocals_ += locals_;
dvander@0
   216
}
dvander@0
   217
dvander@0
   218
bool
dvander@84
   219
Scope::Bind(CompileContext &cc, ParseTree *tree)
dvander@0
   220
{
dvander@54
   221
    Local<String> name(ZONE());
dvander@57
   222
    for (size_t i = 0; i < tree->unbound()->length(); i++) {
dvander@0
   223
        NameProxy *proxy = tree->unbound()->at(i);
dvander@54
   224
        name = proxy->name();
dvander@54
   225
        BoundName *binding = tree->scope()->lookup(name);
dvander@84
   226
dvander@54
   227
        if (!binding) {
dvander@84
   228
            cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
dvander@84
   229
            return false;
dvander@84
   230
        }
dvander@84
   231
dvander@84
   232
        // We only allow global functions to be late-bound.
dvander@84
   233
        if (binding->kind() != BoundName::FUNCTION ||
dvander@84
   234
            binding->scope()->kind() != Scope::GLOBAL)
dvander@84
   235
        {
dvander@84
   236
            cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
dvander@0
   237
            return false;
dvander@2
   238
        }
dvander@0
   239
dvander@54
   240
        proxy->bind(binding);
dvander@137
   241
dvander@137
   242
        // Find the function the proxy is defined in.
dvander@0
   243
    }
dvander@0
   244
    return true;
dvander@0
   245
}
dvander@1
   246
dvander@12
   247
void
dvander@12
   248
Scope::Allocate(ParseTree *tree)
dvander@12
   249
{
dvander@12
   250
    tree->scope()->allocateGlobals();
dvander@12
   251
}
dvander@12
   252
dvander@12
   253
void
dvander@12
   254
Scope::setUsesLifoHeap()
dvander@1
   255
{
dvander@12
   256
    // Only one lifo slot is needed per scope.
dvander@12
   257
    if (lifoSlot_)
dvander@12
   258
        return;
dvander@12
   259
dvander@12
   260
    // If the parent of this scope is the function scope, then this is the
dvander@12
   261
    // function's block scope, and the lifo slot is part of the Frame instead.
dvander@16
   262
    // Note we can get a function scope here if we're making a temporary in a
dvander@16
   263
    // function with no local variables.
dvander@16
   264
    if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
dvander@12
   265
        return;
dvander@12
   266
dvander@37
   267
    Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
dvander@37
   268
    if (!type)
dvander@37
   269
        return;
dvander@37
   270
dvander@54
   271
    Local<String> name(ZONE());
dvander@54
   272
    lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
dvander@37
   273
    lifoSlot_->setType(type);
dvander@1
   274
}
dvander@85
   275
dvander@85
   276
EnvironmentMap *
dvander@85
   277
Scope::createEnvironmentMap(Zone *zone)
dvander@85
   278
{
dvander@85
   279
    return EnvironmentMap::New(zone, envVars_.length(), envVars_.buffer());
dvander@85
   280
}