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