src/OldSema.cpp
author Michael Busby <prodigysim@gmail.com>
Mon Jun 10 01:50:18 2013 +0100 (2013-06-10)
changeset 264 70b8f318c379
parent 263 ba85a47ee414
permissions -rw-r--r--
Parse assignment RTL instead of LTR, fixes multiple assignment (bug 5420).
asherkin@263
     1
/* vim: set ts=4 sw=4 tw=99 et:
asherkin@263
     2
 *
asherkin@263
     3
 * Copyright (C) 2012 David Anderson
asherkin@263
     4
 *
asherkin@263
     5
 * This file is part of JITCraft.
asherkin@263
     6
 *
asherkin@263
     7
 * JITCraft is free software: you can redistribute it and/or modify it under
asherkin@263
     8
 * the terms of the GNU General Public License as published by the Free
asherkin@263
     9
 * Software Foundation, either version 3 of the License, or (at your option)
asherkin@263
    10
 * any later version.
asherkin@263
    11
 * 
asherkin@263
    12
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
asherkin@263
    13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
asherkin@263
    14
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
asherkin@263
    15
 *
asherkin@263
    16
 * You should have received a copy of the GNU General Public License along with
asherkin@263
    17
 * JITCraft. If not, see http://www.gnu.org/licenses/.
asherkin@263
    18
 */
asherkin@263
    19
#include <string.h>
asherkin@263
    20
#include "SemanticAnalysis.h"
asherkin@263
    21
#include "../Types.h"
asherkin@263
    22
#include "../Zone.h"
asherkin@263
    23
#include "../TypeManager.h"
asherkin@263
    24
#include "../Strings.h"
asherkin@263
    25
#include "../Box.h"
asherkin@263
    26
#include "../Array.h"
asherkin@263
    27
#include "../Heap-inl.h"
asherkin@263
    28
#include "Scopes.h"
asherkin@263
    29
#include "NameBinding.h"
asherkin@263
    30
asherkin@263
    31
using namespace ke;
asherkin@263
    32
asherkin@263
    33
SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
asherkin@263
    34
  : zone_(zone),
asherkin@263
    35
    cc_(cc),
asherkin@263
    36
    tree_(tree),
asherkin@263
    37
    scope_(NULL),
asherkin@263
    38
    loop_(NULL)
asherkin@263
    39
{
asherkin@263
    40
}
asherkin@263
    41
asherkin@263
    42
bool
asherkin@263
    43
SemanticAnalysis::analyze()
asherkin@263
    44
{
asherkin@263
    45
    assert(false);
asherkin@263
    46
    return false;
asherkin@263
    47
}
asherkin@263
    48
asherkin@263
    49
asherkin@263
    50
#if 0
asherkin@263
    51
asherkin@263
    52
static inline bool
asherkin@263
    53
IsPrimitiveType(Type *type, PrimitiveType primitive)
asherkin@263
    54
{
asherkin@263
    55
    if (!type)
asherkin@263
    56
        return false;
asherkin@263
    57
asherkin@263
    58
    if (!type->isPrimitive())
asherkin@263
    59
        return false;
asherkin@263
    60
asherkin@263
    61
    return primitive == type->primitive();
asherkin@263
    62
}
asherkin@263
    63
asherkin@263
    64
static inline bool
asherkin@263
    65
EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
asherkin@263
    66
                        BoxedPrimitive *out)
asherkin@263
    67
{
asherkin@263
    68
    switch (kind) {
asherkin@263
    69
      case TOK_PLUS:
asherkin@263
    70
        *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
asherkin@263
    71
        return true;
asherkin@263
    72
asherkin@263
    73
      case TOK_SHL:
asherkin@263
    74
        *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
asherkin@263
    75
        return true;
asherkin@263
    76
asherkin@263
    77
      default:
asherkin@263
    78
        return false;
asherkin@263
    79
    }
asherkin@263
    80
}
asherkin@263
    81
asherkin@263
    82
static inline bool
asherkin@263
    83
EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
asherkin@263
    84
{
asherkin@263
    85
  switch (kind) {
asherkin@263
    86
    case TOK_MINUS:
asherkin@263
    87
      *out = BoxedPrimitive::Int(-inner.toInt());
asherkin@263
    88
      return true;
asherkin@263
    89
asherkin@263
    90
    default:
asherkin@263
    91
      return false;
asherkin@263
    92
  }
asherkin@263
    93
}
asherkin@263
    94
asherkin@263
    95
static bool
asherkin@263
    96
EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
asherkin@263
    97
{
asherkin@263
    98
    switch (expression->kind()) {
asherkin@263
    99
      case AstNode::kBinaryExpression:
asherkin@263
   100
      {
asherkin@263
   101
        BoxedPrimitive left;
asherkin@263
   102
        BoxedPrimitive right;
asherkin@263
   103
        BinaryExpression *b = expression->toBinaryExpression();
asherkin@263
   104
        if (!EvaluateForConstant(b->left(), &left) ||
asherkin@263
   105
            !EvaluateForConstant(b->right(), &right))
asherkin@263
   106
        {
asherkin@263
   107
            return false;
asherkin@263
   108
        }
asherkin@263
   109
        return EvaluateBinaryOperation(b->token(), left, right, out);
asherkin@263
   110
      }
asherkin@263
   111
asherkin@263
   112
      case AstNode::kUnaryExpression:
asherkin@263
   113
      {
asherkin@263
   114
        BoxedPrimitive inner;
asherkin@263
   115
        UnaryExpression *u = expression->toUnaryExpression();
asherkin@263
   116
        if (!EvaluateForConstant(u->expression(), &inner))
asherkin@263
   117
            return false;
asherkin@263
   118
        return EvaluateUnaryOperation(u->token(), inner, out);
asherkin@263
   119
      }
asherkin@263
   120
asherkin@263
   121
      case AstNode::kNameProxy:
asherkin@263
   122
      {
asherkin@263
   123
        NameProxy *proxy = expression->toNameProxy();
asherkin@263
   124
        if (proxy->binding()->kind() != BoundName::CONSTANT)
asherkin@263
   125
            return false;
asherkin@263
   126
asherkin@263
   127
        NamedConstant *c = proxy->binding()->toNamedConstant();
asherkin@263
   128
        if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
asherkin@263
   129
            return false;
asherkin@263
   130
asherkin@263
   131
        *out = c->value();
asherkin@263
   132
        return true;
asherkin@263
   133
      }
asherkin@263
   134
asherkin@263
   135
      case AstNode::kBooleanLiteral:
asherkin@263
   136
        *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
asherkin@263
   137
        return true;
asherkin@263
   138
asherkin@263
   139
      case AstNode::kIntegerLiteral:
asherkin@263
   140
        *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
asherkin@263
   141
        return true;
asherkin@263
   142
asherkin@263
   143
      default:
asherkin@263
   144
        return false;
asherkin@263
   145
    }
asherkin@263
   146
}
asherkin@263
   147
asherkin@263
   148
SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
asherkin@263
   149
  : zone_(zone),
asherkin@263
   150
    cc_(cc),
asherkin@263
   151
    tree_(tree),
asherkin@263
   152
    scope_(NULL),
asherkin@263
   153
    loop_(NULL)
asherkin@263
   154
{
asherkin@263
   155
}
asherkin@263
   156
asherkin@263
   157
bool
asherkin@263
   158
SemanticAnalysis::analyze()
asherkin@263
   159
{
asherkin@263
   160
    if (cc_.failures())
asherkin@263
   161
        return false;
asherkin@263
   162
asherkin@263
   163
    scope_ = tree_->globalScope();
asherkin@263
   164
    assert(scope_->kind() == Scope::GLOBAL);
asherkin@263
   165
asherkin@263
   166
    for (size_t i = 0; i < tree_->statements()->length(); i++) {
asherkin@263
   167
        Statement *statement = tree_->statements()->at(i);
asherkin@263
   168
        if (statement->isFunctionStatement()) {
asherkin@263
   169
            FunctionStatement *funstmt = statement->toFunctionStatement();
asherkin@263
   170
            if (!preanalyze(funstmt))
asherkin@263
   171
                return false;
asherkin@263
   172
        } else if (statement->isEnumStatement()) {
asherkin@263
   173
            EnumStatement *enumstmt = statement->toEnumStatement();
asherkin@263
   174
asherkin@263
   175
            // We pre-fill global enum types, since they may occur in function
asherkin@263
   176
            // signatures. This should probably be somewhere else...
asherkin@263
   177
            enumstmt->accept(this);
asherkin@263
   178
        } else if (statement->isStructureStatement()) {
asherkin@263
   179
            StructureStatement *node = statement->toStructureStatement();
asherkin@263
   180
            node->accept(this);
asherkin@263
   181
            if (!node->decl()->type())
asherkin@263
   182
                return false;
asherkin@263
   183
        } else if (statement->isFunctionTypeStatement()) {
asherkin@263
   184
            FunctionTypeStatement *node = statement->toFunctionTypeStatement();
asherkin@263
   185
            node->accept(this);
asherkin@263
   186
            if (!node->decl()->type())
asherkin@263
   187
                return false;
asherkin@263
   188
        }
asherkin@263
   189
    }
asherkin@263
   190
asherkin@263
   191
    for (size_t i = 0; i < tree_->statements()->length(); i++) {
asherkin@263
   192
        Statement *statement = tree_->statements()->at(i);
asherkin@263
   193
asherkin@263
   194
        // We can't double-process these. Maybe put this check somewhere else.
asherkin@263
   195
        if (statement->isEnumStatement())
asherkin@263
   196
            continue;
asherkin@263
   197
asherkin@263
   198
        statement->accept(this);
asherkin@263
   199
    }
asherkin@263
   200
asherkin@263
   201
    if (!determineLiveFunctions())
asherkin@263
   202
        return false;
asherkin@263
   203
asherkin@263
   204
    return !cc_.failures();
asherkin@263
   205
}
asherkin@263
   206
asherkin@263
   207
bool
asherkin@263
   208
SemanticAnalysis::determineLiveFunctions()
asherkin@263
   209
{
asherkin@263
   210
    Vector<NamedFunction *> worklist;
asherkin@263
   211
asherkin@263
   212
    // Add the root set.
asherkin@263
   213
    for (size_t i = 0; i < tree_->statements()->length(); i++) {
asherkin@263
   214
        Statement *statement = tree_->statements()->at(i);
asherkin@263
   215
        if (!statement->isFunctionStatement())
asherkin@263
   216
            continue;
asherkin@263
   217
asherkin@263
   218
        FunctionStatement *stmt = statement->toFunctionStatement();
asherkin@263
   219
        NamedFunction  *fun = stmt->fun();
asherkin@263
   220
        if (!fun->used())
asherkin@263
   221
            continue;
asherkin@263
   222
asherkin@263
   223
        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
asherkin@263
   224
            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
asherkin@263
   225
asherkin@263
   226
            // Names in these lists are always unused, however, we mark them
asherkin@263
   227
            // as used while inserting into the work queue, to avoid double-
asherkin@263
   228
            // insertion.
asherkin@263
   229
            if (name->used())
asherkin@263
   230
                continue;
asherkin@263
   231
asherkin@263
   232
            if (!worklist.append(name))
asherkin@263
   233
                return false;
asherkin@263
   234
asherkin@263
   235
            name->setUsed();
asherkin@263
   236
        }
asherkin@263
   237
    }
asherkin@263
   238
asherkin@263
   239
    while (!worklist.empty()) {
asherkin@263
   240
        NamedFunction *fun = worklist.popCopy();
asherkin@263
   241
asherkin@263
   242
        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
asherkin@263
   243
            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
asherkin@263
   244
            if (name->used())
asherkin@263
   245
                continue;
asherkin@263
   246
            if (!worklist.append(name))
asherkin@263
   247
                return false;
asherkin@263
   248
            name->setUsed();
asherkin@263
   249
        }
asherkin@263
   250
    }
asherkin@263
   251
asherkin@263
   252
    return true;
asherkin@263
   253
}
asherkin@263
   254
asherkin@263
   255
Type *
asherkin@263
   256
SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name)
asherkin@263
   257
{
asherkin@263
   258
    if (!name)
asherkin@263
   259
        return zone_->types()->getPrimitive(PrimitiveType_Int32);
asherkin@263
   260
asherkin@263
   261
    if (name->kind() == BoundName::UNBOUND) {
asherkin@263
   262
        cc_.reportError(pos, Message_TypeNotFound, name->name()->chars());
asherkin@263
   263
        return NULL;
asherkin@263
   264
    }
asherkin@263
   265
asherkin@263
   266
    if (name->kind() != BoundName::TYPE) {
asherkin@263
   267
        cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars());
asherkin@263
   268
        return NULL;
asherkin@263
   269
    }
asherkin@263
   270
asherkin@263
   271
    if (!name->type())
asherkin@263
   272
        return NULL;
asherkin@263
   273
asherkin@263
   274
    return name->type();
asherkin@263
   275
}
asherkin@263
   276
asherkin@263
   277
Type *
asherkin@263
   278
SemanticAnalysis::visitAndApplyType(Expression *expression)
asherkin@263
   279
{
asherkin@263
   280
    expression->accept(this);
asherkin@263
   281
    return expression->type();
asherkin@263
   282
}
asherkin@263
   283
asherkin@263
   284
Type *
asherkin@263
   285
SemanticAnalysis::visitForLoad(Expression *expression)
asherkin@263
   286
{
asherkin@263
   287
    Local<Type> type(zone_, visitAndApplyType(expression));
asherkin@263
   288
    if (!type)
asherkin@263
   289
        return NULL;
asherkin@263
   290
asherkin@263
   291
    if (type->isReference()) {
asherkin@263
   292
        expression->setType(type->contained());
asherkin@263
   293
    } else if (expression->isCallExpression()) {
asherkin@263
   294
        if (type->isVoid()) {
asherkin@263
   295
            CallExpression *call = expression->toCallExpression();
asherkin@263
   296
            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
asherkin@263
   297
            return NULL;
asherkin@263
   298
        }
asherkin@263
   299
    }
asherkin@263
   300
asherkin@263
   301
    return expression->type();
asherkin@263
   302
}
asherkin@263
   303
asherkin@263
   304
void
asherkin@263
   305
SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type)
asherkin@263
   306
{
asherkin@263
   307
    const char *op = TokenNames[token];
asherkin@263
   308
    const char *name = GetTypeName(type);
asherkin@263
   309
asherkin@263
   310
    cc_.reportError(node->pos(), Message_UnaryTypeError, op, name);
asherkin@263
   311
}
asherkin@263
   312
asherkin@263
   313
void
asherkin@263
   314
SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
asherkin@263
   315
{
asherkin@263
   316
    const char *op = TokenNames[token];
asherkin@263
   317
    const char *leftName = GetTypeName(left);
asherkin@263
   318
    const char *rightName = GetTypeName(right);
asherkin@263
   319
asherkin@263
   320
    cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName);
asherkin@263
   321
}
asherkin@263
   322
asherkin@263
   323
Type *
asherkin@263
   324
SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
asherkin@263
   325
{
asherkin@263
   326
    if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
asherkin@263
   327
        (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
asherkin@263
   328
    {
asherkin@263
   329
        // If either side is a float, the other side must be a float or int.
asherkin@263
   330
        if (left->isFloat() || right->isFloat()) {
asherkin@263
   331
            Type *floatType = left->isFloat() ? left : right;
asherkin@263
   332
            Type *other = left->isFloat() ? right : left;
asherkin@263
   333
            if (other->isFloat() || other->isInt32())
asherkin@263
   334
                return floatType;
asherkin@263
   335
        }
asherkin@263
   336
    }
asherkin@263
   337
asherkin@263
   338
    if (token == TOK_OR || token == TOK_AND) {
asherkin@263
   339
        if (!canTest(node, left) || !canTest(node, right))
asherkin@263
   340
            return NULL;
asherkin@263
   341
        return zone_->types()->getPrimitive(PrimitiveType_Bool);
asherkin@263
   342
    }
asherkin@263
   343
asherkin@263
   344
    if (token >= TOK_EQUALS && token <= TOK_GE) {
asherkin@263
   345
        if ((left->isFloat() || left->isInt32()) &&
asherkin@263
   346
            (right->isFloat() || right->isInt32()))
asherkin@263
   347
        {
asherkin@263
   348
            return zone_->types()->getPrimitive(PrimitiveType_Bool);
asherkin@263
   349
        }
asherkin@263
   350
        binaryTypeError(node, token, left, right);
asherkin@263
   351
        return NULL;
asherkin@263
   352
    }
asherkin@263
   353
asherkin@263
   354
    if (!left->isInt32() || !right->isInt32()) {
asherkin@263
   355
        binaryTypeError(node, token, left, right);
asherkin@263
   356
        return NULL;
asherkin@263
   357
    }
asherkin@263
   358
asherkin@263
   359
    return left;
asherkin@263
   360
}
asherkin@263
   361
asherkin@263
   362
bool
asherkin@263
   363
SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
asherkin@263
   364
{
asherkin@263
   365
    if (!type->isPrimitive() && !type->isEnum()) {
asherkin@263
   366
        cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
asherkin@263
   367
        return false;
asherkin@263
   368
    }
asherkin@263
   369
    return true;
asherkin@263
   370
}
asherkin@263
   371
asherkin@263
   372
Type *
asherkin@263
   373
SemanticAnalysis::visitForLValue(Expression *expression)
asherkin@263
   374
{
asherkin@263
   375
    if (expression->isIndexExpression()) {
asherkin@263
   376
        Type *type = visitAndApplyType(expression);
asherkin@263
   377
        if (!type)
asherkin@263
   378
            return NULL;
asherkin@263
   379
asherkin@263
   380
        // if (type->isConst()) {
asherkin@263
   381
        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
asherkin@263
   382
        //     return NULL;
asherkin@263
   383
        // }
asherkin@263
   384
asherkin@263
   385
        return type;
asherkin@263
   386
    }
asherkin@263
   387
asherkin@263
   388
    if (expression->isFieldExpression()) {
asherkin@263
   389
        Type *type = visitAndApplyType(expression);
asherkin@263
   390
        if (!type)
asherkin@263
   391
            return NULL;
asherkin@263
   392
asherkin@263
   393
        // if (expression->toFieldExpression()->left()->type()->isConst()) {
asherkin@263
   394
        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
asherkin@263
   395
        //     return NULL;
asherkin@263
   396
        // }
asherkin@263
   397
asherkin@263
   398
        return type;
asherkin@263
   399
    }
asherkin@263
   400
asherkin@263
   401
    if (!expression->isNameProxy()) {
asherkin@263
   402
        cc_.reportError(expression->pos(), Message_ExpectedLValue);
asherkin@263
   403
        return NULL;
asherkin@263
   404
    }
asherkin@263
   405
asherkin@263
   406
    NameProxy *proxy = expression->toNameProxy();
asherkin@263
   407
    if (!proxy->binding()->kind() == BoundName::VARIABLE) {
asherkin@263
   408
        cc_.reportError(expression->pos(), Message_ExpectedLValue);
asherkin@263
   409
        return NULL;
asherkin@263
   410
    }
asherkin@263
   411
asherkin@263
   412
    Variable *var = proxy->binding()->toVariable();
asherkin@263
   413
    if (!var->type())
asherkin@263
   414
        return NULL;
asherkin@263
   415
asherkin@263
   416
    if  (var->type()->isReference()) {
asherkin@263
   417
        if (var->type()->isConst()) {
asherkin@263
   418
            cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
asherkin@263
   419
            return NULL;
asherkin@263
   420
        }
asherkin@263
   421
        return var->type()->contained();
asherkin@263
   422
    }
asherkin@263
   423
    return var->type();
asherkin@263
   424
}
asherkin@263
   425
asherkin@263
   426
SemanticAnalysis::ControlStatus
asherkin@263
   427
SemanticAnalysis::visitForControl(Statement *statement)
asherkin@263
   428
{
asherkin@263
   429
    ControlScope scope(&control_);
asherkin@263
   430
    statement->accept(this);
asherkin@263
   431
    return scope.status();
asherkin@263
   432
}
asherkin@263
   433
asherkin@263
   434
void
asherkin@263
   435
SemanticAnalysis::visit(NameProxy *name)
asherkin@263
   436
{
asherkin@263
   437
    BoundName *binding = name->binding();
asherkin@263
   438
asherkin@263
   439
    if (binding->scope()->kind() == Scope::GLOBAL) {
asherkin@263
   440
        if (!function_ || function_->isPublic()) {
asherkin@263
   441
            // Whatever we're referencing must be kept alive no matter what.
asherkin@263
   442
            // As such, we simply mark it used, and don't do anything special.
asherkin@263
   443
            binding->setUsed();
asherkin@263
   444
        } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) {
asherkin@263
   445
            // Otherwise, we're inside a normal stock or function. Since we
asherkin@263
   446
            // don't really know if we've been used yet, we shouldn't
asherkin@263
   447
            // prematurely references as alive. Instead, we keep a list of
asherkin@263
   448
            // which names have been used, so we can mark them later if needed.
asherkin@263
   449
            //
asherkin@263
   450
            // Note that we skip this step if the binding is already in the
asherkin@263
   451
            // root set.
asherkin@263
   452
            if (!function_->addUsedGlobal(binding))
asherkin@263
   453
                return;
asherkin@263
   454
        }
asherkin@263
   455
    }
asherkin@263
   456
asherkin@263
   457
    name->setType(binding->type());
asherkin@263
   458
}
asherkin@263
   459
asherkin@263
   460
void
asherkin@263
   461
SemanticAnalysis::visit(Assignment *node)
asherkin@263
   462
{
asherkin@263
   463
    Local<Type> exprType(zone_, visitForLoad(node->expression()));
asherkin@263
   464
    if (!exprType)
asherkin@263
   465
        return ;
asherkin@263
   466
asherkin@263
   467
    Local<Type> type(zone_, visitForLValue(node->lvalue()));
asherkin@263
   468
    if (!type)
asherkin@263
   469
        return;
asherkin@263
   470
asherkin@263
   471
    if (node->token() != TOK_ASSIGN) {
asherkin@263
   472
        if (!typeCheckBinary(node, node->token(), type, exprType))
asherkin@263
   473
            return;
asherkin@263
   474
    }
asherkin@263
   475
asherkin@263
   476
    if (!typeCheckAssignment(node->pos(), exprType, type, true))
asherkin@263
   477
        return;
asherkin@263
   478
asherkin@263
   479
    node->setType(type);
asherkin@263
   480
}
asherkin@263
   481
asherkin@263
   482
void
asherkin@263
   483
SemanticAnalysis::visit(IncDecExpression *node)
asherkin@263
   484
{
asherkin@263
   485
    Local<Type> type(zone_, visitForLValue(node->expression()));
asherkin@263
   486
    if (!type)
asherkin@263
   487
        return;
asherkin@263
   488
asherkin@263
   489
    assert(!type->isReference());
asherkin@263
   490
asherkin@263
   491
    if (!type->isInt32() && !type->isFloat()) {
asherkin@263
   492
        unaryTypeError(node, node->token(), type);
asherkin@263
   493
        return;
asherkin@263
   494
    }
asherkin@263
   495
asherkin@263
   496
    node->setType(type);
asherkin@263
   497
}
asherkin@263
   498
asherkin@263
   499
void
asherkin@263
   500
SemanticAnalysis::visit(UnaryExpression *node)
asherkin@263
   501
{
asherkin@263
   502
    Local<Type> type(zone_, visitForLoad(node->expression()));
asherkin@263
   503
    if (!type)
asherkin@263
   504
        return;
asherkin@263
   505
asherkin@263
   506
    switch (node->token())
asherkin@263
   507
    {
asherkin@263
   508
      case TOK_NOT:
asherkin@263
   509
        if (!canTest(node->expression(), type))
asherkin@263
   510
            return;
asherkin@263
   511
        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
asherkin@263
   512
        if (!type)
asherkin@263
   513
            return;
asherkin@263
   514
        node->setType(type);
asherkin@263
   515
        break;
asherkin@263
   516
asherkin@263
   517
      case TOK_MINUS:
asherkin@263
   518
        if (!type->isFloat() && !type->isInt32()) {
asherkin@263
   519
            unaryTypeError(node, node->token(), type);
asherkin@263
   520
            return;
asherkin@263
   521
        }
asherkin@263
   522
        node->setType(type);
asherkin@263
   523
        break;
asherkin@263
   524
asherkin@263
   525
      case TOK_LABEL:
asherkin@263
   526
      {
asherkin@263
   527
        Local<Type> to(zone_, bindType(node->pos(), node->type()));
asherkin@263
   528
        if (!to)
asherkin@263
   529
            return;
asherkin@263
   530
asherkin@263
   531
        if ((!type->isFloat() && !type->isInt32OrEnum()) ||
asherkin@263
   532
            (!to->isFloat() && !to->isInt32OrEnum()))
asherkin@263
   533
        {
asherkin@263
   534
            unaryTypeError(node, node->token(), type);
asherkin@263
   535
            return;
asherkin@263
   536
        }
asherkin@263
   537
asherkin@263
   538
        node->setType(to);
asherkin@263
   539
        break;
asherkin@263
   540
      }
asherkin@263
   541
asherkin@263
   542
      case TOK_SIZEOF:
asherkin@263
   543
      {
asherkin@263
   544
        if (!type->isArray()) {
asherkin@263
   545
            cc_.reportError(node->pos(), Message_SizeofNeedsArray);
asherkin@263
   546
            return;
asherkin@263
   547
        }
asherkin@263
   548
        node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
asherkin@263
   549
        break;
asherkin@263
   550
      }
asherkin@263
   551
asherkin@263
   552
      default:
asherkin@263
   553
        assert(node->token() == TOK_TILDE);
asherkin@263
   554
        if (!type->isInt32()) {
asherkin@263
   555
            unaryTypeError(node, node->token(), type);
asherkin@263
   556
            return;
asherkin@263
   557
        }
asherkin@263
   558
        node->setType(type);
asherkin@263
   559
        break;
asherkin@263
   560
    }
asherkin@263
   561
}
asherkin@263
   562
asherkin@263
   563
void
asherkin@263
   564
SemanticAnalysis::visit(TernaryExpression *node)
asherkin@263
   565
{
asherkin@263
   566
    Local<Type> type(zone_, visitForLoad(node->condition()));
asherkin@263
   567
    if (!type)
asherkin@263
   568
        return;
asherkin@263
   569
asherkin@263
   570
    if (!canTest(node->condition(), type))
asherkin@263
   571
        return;
asherkin@263
   572
asherkin@263
   573
    Local<Type> left(zone_, visitForLoad(node->left()));
asherkin@263
   574
    Local<Type> right(zone_, visitForLoad(node->right()));
asherkin@263
   575
    if (!left || !right)
asherkin@263
   576
        return;
asherkin@263
   577
asherkin@263
   578
    if (left != right) {
asherkin@263
   579
        binaryTypeError(node, TOK_QMARK, left, right);
asherkin@263
   580
        return;
asherkin@263
   581
    }
asherkin@263
   582
}
asherkin@263
   583
asherkin@263
   584
void
asherkin@263
   585
SemanticAnalysis::visit(BinaryExpression *node)
asherkin@263
   586
{
asherkin@263
   587
    Local<Type> left(zone_, visitForLoad(node->left()));
asherkin@263
   588
    Local<Type> right(zone_, visitForLoad(node->right()));
asherkin@263
   589
    if (!left || !right)
asherkin@263
   590
        return;
asherkin@263
   591
asherkin@263
   592
    Local<Type> result(zone_, typeCheckBinary(node, node->token(), left, right));
asherkin@263
   593
    if (!result)
asherkin@263
   594
        return;
asherkin@263
   595
asherkin@263
   596
    node->setType(result);
asherkin@263
   597
}
asherkin@263
   598
asherkin@263
   599
void
asherkin@263
   600
SemanticAnalysis::visit(ReturnStatement *node)
asherkin@263
   601
{
asherkin@263
   602
    // Set this early, so if we error we don't get more errors.
asherkin@263
   603
    control_->returns(Returns_Always);
asherkin@263
   604
asherkin@263
   605
    if (!node->expression()) {
asherkin@263
   606
        if (!function_->type()->returnType()->isVoid())
asherkin@263
   607
            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
asherkin@263
   608
        return;
asherkin@263
   609
    }
asherkin@263
   610
asherkin@263
   611
    Local<Type> type(zone_, visitForLoad(node->expression()));
asherkin@263
   612
    if (!type)
asherkin@263
   613
        return;
asherkin@263
   614
asherkin@263
   615
    Local<Type> returnType(zone_, function_->type()->returnType());
asherkin@263
   616
    if (!typeCheckAssignment(node->pos(), type, returnType, true))
asherkin@263
   617
        return;
asherkin@263
   618
}
asherkin@263
   619
asherkin@263
   620
void
asherkin@263
   621
SemanticAnalysis::visit(ForStatement *node)
asherkin@263
   622
{
asherkin@263
   623
    LoopScope loop(&loop_);
asherkin@263
   624
asherkin@263
   625
    if (node->scope())
asherkin@263
   626
        scope_ = node->scope();
asherkin@263
   627
asherkin@263
   628
    if (node->initialization())
asherkin@263
   629
        node->initialization()->accept(this);
asherkin@263
   630
asherkin@263
   631
    if (node->condition()) {
asherkin@263
   632
        Local<Type> type(zone_, visitForLoad(node->condition()));
asherkin@263
   633
        if (!type || !canTest(node->condition(), type)) {
asherkin@263
   634
            return;
asherkin@263
   635
        }
asherkin@263
   636
    }
asherkin@263
   637
asherkin@263
   638
    if (node->update())
asherkin@263
   639
        node->update()->accept(this);
asherkin@263
   640
asherkin@263
   641
    ControlStatus status = visitForControl(node->body());
asherkin@263
   642
asherkin@263
   643
    // If there is a condition, we treat this like a while loop. Otherwise,
asherkin@263
   644
    // join point is only reachable if the loop contains a break. The
asherkin@263
   645
    // termination status doesn't tell us anything yet.
asherkin@263
   646
    if (node->condition() || loop.breaks())
asherkin@263
   647
        control_->merge(status, ControlStatus(false, Returns_Never));
asherkin@263
   648
    else
asherkin@263
   649
        control_->terminate(status.returns());
asherkin@263
   650
asherkin@263
   651
    if (node->scope())
asherkin@263
   652
        scope_ = scope_->enclosing();
asherkin@263
   653
}
asherkin@263
   654
asherkin@263
   655
void 
asherkin@263
   656
SemanticAnalysis::visit(WhileStatement *node)
asherkin@263
   657
{
asherkin@263
   658
    LoopScope loop(&loop_);
asherkin@263
   659
asherkin@263
   660
    Local<Type> type(zone_, visitForLoad(node->condition()));
asherkin@263
   661
    if (!type || !canTest(node->condition(), type)) {
asherkin@263
   662
        return;
asherkin@263
   663
    }
asherkin@263
   664
asherkin@263
   665
    ControlStatus status = visitForControl(node->body());
asherkin@263
   666
asherkin@263
   667
    // Detect loops that will always have a fork in the control-flow graph.
asherkin@263
   668
    // This will be a |while| loop, or a |do-while| loop whose body does
asherkin@263
   669
    // not terminate.
asherkin@263
   670
    //
asherkin@263
   671
    // For now, we treat these as an |if| regardless of the direction the
asherkin@263
   672
    // branch can take. That means the control-flow is always conditional.
asherkin@263
   673
    if (node->token() == TOK_WHILE ||
asherkin@263
   674
        !status.terminates() ||
asherkin@263
   675
        loop.breaks())
asherkin@263
   676
    {
asherkin@263
   677
        control_->merge(status, ControlStatus(false, Returns_Never));
asherkin@263
   678
    } else {
asherkin@263
   679
        // At this point, we've got a do-while loop with a |return| or
asherkin@263
   680
        // |continue|, meaning that the rest of the block is unreachable.
asherkin@263
   681
        control_->terminate(status.returns());
asherkin@263
   682
    }
asherkin@263
   683
}
asherkin@263
   684
asherkin@263
   685
void
asherkin@263
   686
SemanticAnalysis::visit(BlockStatement *node)
asherkin@263
   687
{
asherkin@263
   688
    if (node->scope())
asherkin@263
   689
        scope_ = node->scope();
asherkin@263
   690
    for (size_t i = 0; i < node->statements()->length(); i++) {
asherkin@263
   691
        Statement *statement = node->statements()->at(i);
asherkin@263
   692
        statement->accept(this);
asherkin@263
   693
    }
asherkin@263
   694
    if (node->scope())
asherkin@263
   695
        scope_ = scope_->enclosing();
asherkin@263
   696
}
asherkin@263
   697
asherkin@263
   698
static inline bool
asherkin@263
   699
IsScalarString(Type *type)
asherkin@263
   700
{
asherkin@263
   701
    if (type->isPrimitive() && type->primitive() == PrimitiveType_Char)
asherkin@263
   702
        return true;
asherkin@263
   703
    if (type->isReference())
asherkin@263
   704
        return IsScalarString(type->contained());
asherkin@263
   705
    return false;
asherkin@263
   706
}
asherkin@263
   707
asherkin@263
   708
static const int INFER_ARRAY_SIZE = 0;
asherkin@263
   709
static const int EVAL_ARRAY_SIZE = -1;
asherkin@263
   710
static const int DYNAMIC_ARRAY_SIZE = -2;
asherkin@263
   711
asherkin@263
   712
bool
asherkin@263
   713
SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH])
asherkin@263
   714
{
asherkin@263
   715
    bool hadEmptySize = false;
asherkin@263
   716
asherkin@263
   717
    for (size_t i = 0; i < exprs->length(); i++) {
asherkin@263
   718
        Expression *expr = exprs->at(i);
asherkin@263
   719
        if (!expr) {
asherkin@263
   720
            dims[i] = INFER_ARRAY_SIZE;
asherkin@263
   721
            hadEmptySize = true;
asherkin@263
   722
            continue;
asherkin@263
   723
        }
asherkin@263
   724
asherkin@263
   725
        BoxedPrimitive box;
asherkin@263
   726
        if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
asherkin@263
   727
            int size = box.toInt();
asherkin@263
   728
            if (size <= 0) {
asherkin@263
   729
                cc_.reportError(expr->pos(), Message_BadArraySize);
asherkin@263
   730
                return false;
asherkin@263
   731
            }
asherkin@263
   732
asherkin@263
   733
            dims[i] = size;
asherkin@263
   734
            continue;
asherkin@263
   735
        }
asherkin@263
   736
asherkin@263
   737
        Local<Type> exprType(zone_, visitForLoad(expr));
asherkin@263
   738
        if (!exprType)
asherkin@263
   739
            return false;
asherkin@263
   740
asherkin@263
   741
        if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
asherkin@263
   742
            cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
asherkin@263
   743
            return false;
asherkin@263
   744
        }
asherkin@263
   745
asherkin@263
   746
        if (hadEmptySize) {
asherkin@263
   747
            cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
asherkin@263
   748
            return false;
asherkin@263
   749
        }
asherkin@263
   750
asherkin@263
   751
        dims[i] = EVAL_ARRAY_SIZE;
asherkin@263
   752
    }
asherkin@263
   753
asherkin@263
   754
    return true;
asherkin@263
   755
}
asherkin@263
   756
asherkin@263
   757
bool
asherkin@263
   758
SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle<Type> contained,
asherkin@263
   759
                                         int dims[MAX_ARRAY_DEPTH],
asherkin@263
   760
                                         unsigned dimcount, unsigned level)
asherkin@263
   761
{
asherkin@263
   762
    if (dims[level] == EVAL_ARRAY_SIZE) {
asherkin@263
   763
        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
asherkin@263
   764
        return false;
asherkin@263
   765
    }
asherkin@263
   766
asherkin@263
   767
    if (dims[level] == INFER_ARRAY_SIZE) {
asherkin@263
   768
        // Strings always become dynamic arrays.
asherkin@263
   769
        if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char))
asherkin@263
   770
            dims[level] = literal->expressions()->length();
asherkin@263
   771
    } else if (dims[level] == DYNAMIC_ARRAY_SIZE) {
asherkin@263
   772
        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
asherkin@263
   773
        return false;
asherkin@263
   774
    } else {
asherkin@263
   775
        if (literal->expressions()->length() != unsigned(dims[level])) {
asherkin@263
   776
            cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1);
asherkin@263
   777
            return false;
asherkin@263
   778
        }
asherkin@263
   779
    }
asherkin@263
   780
asherkin@263
   781
    if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) {
asherkin@263
   782
        for (size_t i = 0; i < literal->expressions()->length(); i++) {
asherkin@263
   783
            Expression *expr = literal->expressions()->at(i);
asherkin@263
   784
            if (!expr->isStringLiteral()) {
asherkin@263
   785
                cc_.reportError(expr->pos(), Message_ExpectedStringLiteral);
asherkin@263
   786
                return false;
asherkin@263
   787
            }
asherkin@263
   788
asherkin@263
   789
            StringLiteral *lit = expr->toStringLiteral();
asherkin@263
   790
            if (dims[level + 1] > 0 &&
asherkin@263
   791
                unsigned(dims[level]) < lit->string()->length())
asherkin@263
   792
            {
asherkin@263
   793
                cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2);
asherkin@263
   794
                return false;
asherkin@263
   795
            }
asherkin@263
   796
            if (!visitAndApplyType(lit))
asherkin@263
   797
                return false;
asherkin@263
   798
        }
asherkin@263
   799
    } else if (level == dimcount - 1) {
asherkin@263
   800
        Local<Type> type(zone_);
asherkin@263
   801
        for (size_t i = 0; i < literal->expressions()->length(); i++) {
asherkin@263
   802
            Expression *expr = literal->expressions()->at(i);
asherkin@263
   803
            if (expr->isArrayLiteral()) {
asherkin@263
   804
                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
asherkin@263
   805
                return false;
asherkin@263
   806
            }
asherkin@263
   807
asherkin@263
   808
            if ((type = visitAndApplyType(expr)) == NULL)
asherkin@263
   809
                return false;
asherkin@263
   810
asherkin@263
   811
            if (!typeCheckAssignment(expr->pos(), type, contained, true))
asherkin@263
   812
                return false;
asherkin@263
   813
        }
asherkin@263
   814
    } else {
asherkin@263
   815
        for (size_t i = 0; i < literal->expressions()->length(); i++) {
asherkin@263
   816
            Expression *expr = literal->expressions()->at(i);
asherkin@263
   817
            if (!expr->isArrayLiteral()) {
asherkin@263
   818
                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
asherkin@263
   819
                return false;
asherkin@263
   820
            }
asherkin@263
   821
asherkin@263
   822
            assert(expr->toArrayLiteral()->isFixed());
asherkin@263
   823
asherkin@263
   824
            if (!inferFixedArrayLiteral(expr->toArrayLiteral(),
asherkin@263
   825
                                        contained,
asherkin@263
   826
                                        dims,
asherkin@263
   827
                                        dimcount,
asherkin@263
   828
                                        level + 1))
asherkin@263
   829
            {
asherkin@263
   830
                return false;
asherkin@263
   831
            }
asherkin@263
   832
        }
asherkin@263
   833
    }
asherkin@263
   834
asherkin@263
   835
    return true;
asherkin@263
   836
}
asherkin@263
   837
asherkin@263
   838
void
asherkin@263
   839
SemanticAnalysis::visit(VariableDeclaration *node)
asherkin@263
   840
{
asherkin@263
   841
    Local<Type> type(zone_, bindType(node->pos(), node->type()));
asherkin@263
   842
    if (!type)
asherkin@263
   843
        return;
asherkin@263
   844
asherkin@263
   845
#if 0
asherkin@263
   846
    if (node->postDimensions() || type->isArray()) {
asherkin@263
   847
        // The type could be an array type, so sum the type and postDimensions
asherkin@263
   848
        // together.
asherkin@263
   849
        unsigned dimcount = node->postDimensions()->length();
asherkin@263
   850
        if (type->isArray())
asherkin@263
   851
            dimcount += type->levels();
asherkin@263
   852
        if (dimcount > MAX_ARRAY_DEPTH) {
asherkin@263
   853
            cc_.reportError(node->pos(), Message_MaximumArrayDepth);
asherkin@263
   854
            return;
asherkin@263
   855
        }
asherkin@263
   856
asherkin@263
   857
        // Take an initial guess at the array dimension sizes.
asherkin@263
   858
        int dims[MAX_ARRAY_DEPTH];
asherkin@263
   859
        if (!evaluateDimensions(node->postDimensions(), dims))
asherkin@263
   860
            return;
asherkin@263
   861
asherkin@263
   862
        // Now add in the type's array dimensions.
asherkin@263
   863
        Local<Type> contained(zone_, type);
asherkin@263
   864
        for (size_t i = node->postDimensions()->length(); i < dimcount; i++) {
asherkin@263
   865
            if (type->isFixedLength())
asherkin@263
   866
                dims[i] = type->fixedLength();
asherkin@263
   867
            else
asherkin@263
   868
                dims[i] = DYNAMIC_ARRAY_SIZE;
asherkin@263
   869
            contained = contained->contained();
asherkin@263
   870
        }
asherkin@263
   871
asherkin@263
   872
        Expression *initializer = node->initialization();
asherkin@263
   873
        if (initializer &&
asherkin@263
   874
            initializer->isArrayLiteral() &&
asherkin@263
   875
            initializer->toArrayLiteral()->isFixed())
asherkin@263
   876
        {
asherkin@263
   877
            // Fixed array initializers are special; we use them to infer any
asherkin@263
   878
            // missing information in the original array. We do not evaluate
asherkin@263
   879
            // the array initializer as an expression.
asherkin@263
   880
            if (!inferFixedArrayLiteral(initializer->toArrayLiteral(),
asherkin@263
   881
                                        contained,
asherkin@263
   882
                                        dims,
asherkin@263
   883
                                        dimcount,
asherkin@263
   884
                                        0))
asherkin@263
   885
            {
asherkin@263
   886
                return;
asherkin@263
   887
            }
asherkin@263
   888
            initializer = NULL;
asherkin@263
   889
        }
asherkin@263
   890
asherkin@263
   891
        // We now have enough information to build the actual array type.
asherkin@263
   892
        // Start from the original dimcount, not the one computed for
asherkin@263
   893
        // initializers.
asherkin@263
   894
        for (size_t i = node->postDimensions()->length() - 1;
asherkin@263
   895
             i < node->postDimensions()->length();
asherkin@263
   896
             i--)
asherkin@263
   897
        {
asherkin@263
   898
            int size = dims[i] > 0
asherkin@263
   899
                       ? dims[i]
asherkin@263
   900
                       : Type::DYNAMIC_ARRAY_SIZE;
asherkin@263
   901
asherkin@263
   902
            type = zone_->types()->newArray(type, size, false);
asherkin@263
   903
            if (!type)
asherkin@263
   904
                return;
asherkin@263
   905
        }
asherkin@263
   906
asherkin@263
   907
        // Finally, if we had a non-fixed initializer, make sure it type
asherkin@263
   908
        // checks. 
asherkin@263
   909
        if (initializer) {
asherkin@263
   910
            Local<Type> right(zone_, visitForLoad(initializer));
asherkin@263
   911
            if (!right)
asherkin@263
   912
                return;
asherkin@263
   913
asherkin@263
   914
            if (!typeCheckAssignment(node->pos(), right, type, true))
asherkin@263
   915
                return;
asherkin@263
   916
        }
asherkin@263
   917
    } else {
asherkin@263
   918
        if (node->initialization()) {
asherkin@263
   919
            Local<Type> right(zone_, visitForLoad(node->initialization()));
asherkin@263
   920
            if (!right)
asherkin@263
   921
                return;
asherkin@263
   922
            if (!typeCheckAssignment(node->pos(), right, type, true))
asherkin@263
   923
                return;
asherkin@263
   924
        }
asherkin@263
   925
asherkin@263
   926
        if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) {
asherkin@263
   927
            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
asherkin@263
   928
            return;
asherkin@263
   929
        }
asherkin@263
   930
    }
asherkin@263
   931
#endif
asherkin@263
   932
asherkin@263
   933
#if 0
asherkin@263
   934
    // If this variable is stack allocated, we could use the LIFO heap
asherkin@263
   935
    // to allocate it. If that's the case, make sure to reserve a slot
asherkin@263
   936
    // so we can unwind the LIFO heap at the end of this scope.
asherkin@263
   937
    if (!node->variable()->needsHeapAllocation()) {
asherkin@263
   938
        if (type->isArray() || type->isStruct())
asherkin@263
   939
            scope_->setUsesLifoHeap();
asherkin@263
   940
    }
asherkin@263
   941
asherkin@263
   942
    node->variable()->setType(type);
asherkin@263
   943
#endif
asherkin@263
   944
}
asherkin@263
   945
asherkin@263
   946
void
asherkin@263
   947
SemanticAnalysis::visit(IntegerLiteral *node)
asherkin@263
   948
{
asherkin@263
   949
    node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
asherkin@263
   950
}
asherkin@263
   951
asherkin@263
   952
void
asherkin@263
   953
SemanticAnalysis::visit(BooleanLiteral *node)
asherkin@263
   954
{
asherkin@263
   955
    node->setType(zone_->types()->getPrimitive(PrimitiveType_Bool));
asherkin@263
   956
}
asherkin@263
   957
asherkin@263
   958
void
asherkin@263
   959
SemanticAnalysis::visit(ExpressionStatement *node)
asherkin@263
   960
{
asherkin@263
   961
    visitAndApplyType(node->expression());
asherkin@263
   962
}
asherkin@263
   963
asherkin@263
   964
Box *
asherkin@263
   965
SemanticAnalysis::evaluateDefaultParameter(Handle<Type> type, Parameter *parameter)
asherkin@263
   966
{
asherkin@263
   967
    Local<Type> given(zone_, visitForLoad(parameter->initializer()));
asherkin@263
   968
asherkin@263
   969
    BoxedPrimitive prim;
asherkin@263
   970
    if (EvaluateForConstant(parameter->initializer(), &prim)) {
asherkin@263
   971
        if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
asherkin@263
   972
            return NULL;
asherkin@263
   973
asherkin@263
   974
        if (prim.type() == PrimitiveType_Int32)
asherkin@263
   975
            return Box::New(zone_, given, prim.toInt());
asherkin@263
   976
        return Box::New(zone_, given, prim.toFloat());
asherkin@263
   977
    } else if (parameter->initializer()->isStringLiteral()) {
asherkin@263
   978
        StringLiteral *literal = parameter->initializer()->toStringLiteral();
asherkin@263
   979
asherkin@263
   980
        if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
asherkin@263
   981
            return NULL;
asherkin@263
   982
asherkin@263
   983
        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, given));
asherkin@263
   984
        if (!map)
asherkin@263
   985
            return NULL;
asherkin@263
   986
asherkin@263
   987
        Local<Array> array(zone_,
asherkin@263
   988
            Array::NewString(zone_,
asherkin@263
   989
                             map,
asherkin@263
   990
                             literal->string()->raw(),
asherkin@263
   991
                             literal->string()->length(),
asherkin@263
   992
                             Heap::Tenure_Old));
asherkin@263
   993
        if (!array)
asherkin@263
   994
            return NULL;
asherkin@263
   995
asherkin@263
   996
        return Box::NewObj(zone_, given, array, Heap::Tenure_Old);
asherkin@263
   997
    }
asherkin@263
   998
asherkin@263
   999
    cc_.reportError(parameter->initializer()->pos(), Message_MustBeConstant);
asherkin@263
  1000
    return NULL;
asherkin@263
  1001
}
asherkin@263
  1002
asherkin@263
  1003
bool
asherkin@263
  1004
SemanticAnalysis::buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
asherkin@263
  1005
                                    FixedArray **argsp, FixedArray **defaultsp)
asherkin@263
  1006
{
asherkin@263
  1007
    Local<FixedArray> args(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
asherkin@263
  1008
    if (!args)
asherkin@263
  1009
        return false;
asherkin@263
  1010
asherkin@263
  1011
    Local<FixedArray> defaults(zone_);
asherkin@263
  1012
asherkin@263
  1013
    // Apply types to arguments.
asherkin@263
  1014
    for (size_t i = 0; i < sig.parameters()->length(); i++) {
asherkin@263
  1015
        Parameter *parameter = sig.parameters()->at(i);
asherkin@263
  1016
        
asherkin@263
  1017
#if 0
asherkin@263
  1018
        Local<Type> type(zone_, bindType(parameter->variable()->pos(), parameter->type()));
asherkin@263
  1019
        if (!type)
asherkin@263
  1020
            return false;
asherkin@263
  1021
asherkin@263
  1022
        if (parameter->reference()) {
asherkin@263
  1023
            if (parameter->dimensions()) {
asherkin@263
  1024
                cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference);
asherkin@263
  1025
                return false;
asherkin@263
  1026
            }
asherkin@263
  1027
asherkin@263
  1028
            if (type->isStruct()) {
asherkin@263
  1029
                cc_.reportError(parameter->variable()->pos(), Message_StructCantBeReference);
asherkin@263
  1030
                return false;
asherkin@263
  1031
            }
asherkin@263
  1032
asherkin@263
  1033
            type = zone_->types()->getReference(type, parameter->isConst());
asherkin@263
  1034
            if (!type)
asherkin@263
  1035
                return false;
asherkin@263
  1036
        } else if (parameter->dimensions()) {
asherkin@263
  1037
            type = buildArrayType(type, parameter->dimensions(), parameter->isConst());
asherkin@263
  1038
            if (!type)
asherkin@263
  1039
                return false;
asherkin@263
  1040
asherkin@263
  1041
            if (kind == TOK_NATIVE && type->levels() > 1) {
asherkin@263
  1042
                cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
asherkin@263
  1043
                return false;
asherkin@263
  1044
            }
asherkin@263
  1045
        }
asherkin@263
  1046
asherkin@263
  1047
        if (IsScalarString(type)) {
asherkin@263
  1048
            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
asherkin@263
  1049
            return false;
asherkin@263
  1050
        }
asherkin@263
  1051
asherkin@263
  1052
        args->set(zone_, i, type);
asherkin@263
  1053
        parameter->variable()->setType(type);
asherkin@263
  1054
asherkin@263
  1055
        if (parameter->initializer()) {
asherkin@263
  1056
            if (!defaults) {
asherkin@263
  1057
                defaults = FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old);
asherkin@263
  1058
                if (!defaults)
asherkin@263
  1059
                    return false;
asherkin@263
  1060
            }
asherkin@263
  1061
asherkin@263
  1062
            Local<Box> box(zone_, evaluateDefaultParameter(type, parameter));
asherkin@263
  1063
            if (!box)
asherkin@263
  1064
                return false;
asherkin@263
  1065
asherkin@263
  1066
            defaults->set(zone_, i, box);
asherkin@263
  1067
        }
asherkin@263
  1068
#endif
asherkin@263
  1069
    }
asherkin@263
  1070
asherkin@263
  1071
    *argsp = args;
asherkin@263
  1072
    *defaultsp = defaults;
asherkin@263
  1073
asherkin@263
  1074
    return true;
asherkin@263
  1075
}
asherkin@263
  1076
asherkin@263
  1077
void
asherkin@263
  1078
SemanticAnalysis::visit(FunctionTypeStatement *node)
asherkin@263
  1079
{
asherkin@263
  1080
    if (node->decl()->type())
asherkin@263
  1081
        return;
asherkin@263
  1082
asherkin@263
  1083
    Local<FixedArray> args(zone_);
asherkin@263
  1084
    Local<FixedArray> defaults(zone_);
asherkin@263
  1085
asherkin@263
  1086
    const FunctionSignature &sig= node->signature();
asherkin@263
  1087
    if (!buildFunctionArgs(node,
asherkin@263
  1088
                           TOK_STOCK,
asherkin@263
  1089
                           sig,
asherkin@263
  1090
                           args.address(),
asherkin@263
  1091
                           defaults.address()))
asherkin@263
  1092
    {
asherkin@263
  1093
        return;
asherkin@263
  1094
    }
asherkin@263
  1095
asherkin@263
  1096
#if 0
asherkin@263
  1097
    Local<Type> returnType(zone_);
asherkin@263
  1098
    if (sig.returnType())
asherkin@263
  1099
        returnType = bindType(node->pos(), sig.returnType());
asherkin@263
  1100
    else
asherkin@263
  1101
        returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
asherkin@263
  1102
asherkin@263
  1103
    if (!returnType)
asherkin@263
  1104
        return;
asherkin@263
  1105
asherkin@263
  1106
    Local<Type> funtype(zone_, zone_->types()->newFunction(returnType, args, defaults));
asherkin@263
  1107
    if (!funtype)
asherkin@263
  1108
        return;
asherkin@263
  1109
asherkin@263
  1110
    node->decl()->setType(funtype);
asherkin@263
  1111
#endif
asherkin@263
  1112
}
asherkin@263
  1113
asherkin@263
  1114
Type *
asherkin@263
  1115
SemanticAnalysis::buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst)
asherkin@263
  1116
{
asherkin@263
  1117
    Local<Type> arrayType(zone_, type);
asherkin@263
  1118
asherkin@263
  1119
    unsigned dimcount = dimensions->length();
asherkin@263
  1120
    if (type->isArray())
asherkin@263
  1121
        dimcount += type->levels();
asherkin@263
  1122
asherkin@263
  1123
    if (dimcount > MAX_ARRAY_DEPTH) {
asherkin@263
  1124
        cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(),
asherkin@263
  1125
                        Message_MaximumArrayDepth);
asherkin@263
  1126
        return false;
asherkin@263
  1127
    }
asherkin@263
  1128
asherkin@263
  1129
    // Note: constness is sort of bogus. Fix this sometime.
asherkin@263
  1130
    for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) {
asherkin@263
  1131
        Expression *expr = dimensions->at(i);
asherkin@263
  1132
        if (!expr) {
asherkin@263
  1133
            arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst);
asherkin@263
  1134
            if (!arrayType)
asherkin@263
  1135
                return NULL;
asherkin@263
  1136
asherkin@263
  1137
            continue;
asherkin@263
  1138
        }
asherkin@263
  1139
asherkin@263
  1140
        BoxedPrimitive box;
asherkin@263
  1141
        if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
asherkin@263
  1142
            cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
asherkin@263
  1143
            return NULL;
asherkin@263
  1144
        }
asherkin@263
  1145
asherkin@263
  1146
        if (box.toInt() <= 0) {
asherkin@263
  1147
            cc_.reportError(expr->pos(), Message_BadArraySize);
asherkin@263
  1148
            return NULL;
asherkin@263
  1149
        }
asherkin@263
  1150
asherkin@263
  1151
        arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst);
asherkin@263
  1152
        if (!arrayType)
asherkin@263
  1153
            return NULL;
asherkin@263
  1154
    }
asherkin@263
  1155
asherkin@263
  1156
    return arrayType;
asherkin@263
  1157
}
asherkin@263
  1158
asherkin@263
  1159
bool
asherkin@263
  1160
SemanticAnalysis::preanalyze(FunctionStatement *node)
asherkin@263
  1161
{
asherkin@263
  1162
    Local<FixedArray> args(zone_);
asherkin@263
  1163
    Local<FixedArray> defaults(zone_);
asherkin@263
  1164
asherkin@263
  1165
    const FunctionSignature &sig = node->signature();
asherkin@263
  1166
    if (!buildFunctionArgs(node,
asherkin@263
  1167
                           node->fun()->token(),
asherkin@263
  1168
                           sig,
asherkin@263
  1169
                           args.address(),
asherkin@263
  1170
                           defaults.address()))
asherkin@263
  1171
    {
asherkin@263
  1172
        return false;
asherkin@263
  1173
    }
asherkin@263
  1174
asherkin@263
  1175
#if 0
asherkin@263
  1176
    Local<Type> returnType(zone_);
asherkin@263
  1177
    if (sig.returnType() ||
asherkin@263
  1178
        node->hasExplicitReturn() ||
asherkin@263
  1179
        node->fun()->isNative())
asherkin@263
  1180
    {
asherkin@263
  1181
        returnType = bindType(node->pos(), sig.returnType());
asherkin@263
  1182
    } else {
asherkin@263
  1183
        returnType = zone_->types()->getVoid();
asherkin@263
  1184
    }
asherkin@263
  1185
    if (!returnType)
asherkin@263
  1186
        return false;
asherkin@263
  1187
asherkin@263
  1188
    if (sig.returnDimensions()) {
asherkin@263
  1189
        returnType = buildArrayType(returnType, sig.returnDimensions(), false);
asherkin@263
  1190
        if (!returnType)
asherkin@263
  1191
            return false;
asherkin@263
  1192
    }
asherkin@263
  1193
asherkin@263
  1194
    if (IsScalarString(returnType)) {
asherkin@263
  1195
        cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
asherkin@263
  1196
        return false;
asherkin@263
  1197
    }
asherkin@263
  1198
asherkin@263
  1199
    Local<Type> funtype(zone_);
asherkin@263
  1200
    if (node->fun()->isNative())
asherkin@263
  1201
        funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic());
asherkin@263
  1202
    else
asherkin@263
  1203
        funtype = zone_->types()->newFunction(returnType, args, defaults);
asherkin@263
  1204
    if (!funtype)
asherkin@263
  1205
        return false;
asherkin@263
  1206
    
asherkin@263
  1207
    // If the function already has a type, it was forward declared before, and
asherkin@263
  1208
    // now this is our chance to type check the second declaration.
asherkin@263
  1209
    if (node->fun()->type()) {
asherkin@263
  1210
        Local<Type> forward(zone_, node->fun()->type());
asherkin@263
  1211
        if (!Type::Compare(funtype, forward)) {
asherkin@263
  1212
            cc_.reportError(node->pos(), Message_ForwardDeclareMismatches);
asherkin@263
  1213
            return false;
asherkin@263
  1214
        }
asherkin@263
  1215
        node->fun()->setForwardType(forward);
asherkin@263
  1216
    }
asherkin@263
  1217
asherkin@263
  1218
    node->fun()->setType(funtype);
asherkin@263
  1219
#endif
asherkin@263
  1220
asherkin@263
  1221
    return true;
asherkin@263
  1222
}
asherkin@263
  1223
asherkin@263
  1224
void
asherkin@263
  1225
SemanticAnalysis::visit(FunctionStatement *node)
asherkin@263
  1226
{
asherkin@263
  1227
    function_ = node->fun();
asherkin@263
  1228
    scope_ = node->scope();
asherkin@263
  1229
asherkin@263
  1230
    ControlScope control(&control_);
asherkin@263
  1231
    if (node->body()) {
asherkin@263
  1232
        node->body()->accept(this);
asherkin@263
  1233
asherkin@263
  1234
        ControlStatus status = control.status();
asherkin@263
  1235
        if (status.returns() == Returns_Sometimes) {
asherkin@263
  1236
            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
asherkin@263
  1237
        } else if (status.returns() == Returns_Never) {
asherkin@263
  1238
            if (!function_->type()->returnType()->isVoid())
asherkin@263
  1239
                cc_.reportError(node->pos(), Message_MissingReturnValue);
asherkin@263
  1240
        }
asherkin@263
  1241
    }
asherkin@263
  1242
asherkin@263
  1243
    scope_ = NULL;
asherkin@263
  1244
    function_ = NULL;
asherkin@263
  1245
}
asherkin@263
  1246
asherkin@263
  1247
void
asherkin@263
  1248
SemanticAnalysis::typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given)
asherkin@263
  1249
{
asherkin@263
  1250
    cc_.reportError(pos, Message_TypeMismatch,
asherkin@263
  1251
                    GetTypeName(actual),
asherkin@263
  1252
                    GetTypeName(given));
asherkin@263
  1253
}
asherkin@263
  1254
asherkin@263
  1255
bool
asherkin@263
  1256
SemanticAnalysis::typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> argGiven,
asherkin@263
  1257
                                           Handle<Type> argActual, bool forAssign)
asherkin@263
  1258
{
asherkin@263
  1259
    Local<Type> actual(zone_, argActual);
asherkin@263
  1260
    Local<Type> given(zone_, argGiven);
asherkin@263
  1261
asherkin@263
  1262
    if (!given->isArray()) {
asherkin@263
  1263
        cc_.reportError(pos, Message_ExpectedArray);
asherkin@263
  1264
        return false;
asherkin@263
  1265
    }
asherkin@263
  1266
    if (given->levels() != actual->levels()) {
asherkin@263
  1267
        cc_.reportError(pos, Message_ArrayDimensionsMismatch);
asherkin@263
  1268
        return false;
asherkin@263
  1269
    }
asherkin@263
  1270
asherkin@263
  1271
    unsigned level = 1;
asherkin@263
  1272
    while (given->isArray()) {
asherkin@263
  1273
        if (actual->isFixedLength()) {
asherkin@263
  1274
            if (forAssign) {
asherkin@263
  1275
                if (!given->isFixedLength()) {
asherkin@263
  1276
                    cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
asherkin@263
  1277
                    return false;
asherkin@263
  1278
                }
asherkin@263
  1279
asherkin@263
  1280
                if (actual->isCharArray()) {
asherkin@263
  1281
                    // String assignment can have a truncated |given|.
asherkin@263
  1282
                    if (given->fixedLength() > actual->fixedLength()) {
asherkin@263
  1283
                        cc_.reportError(pos, Message_ArrayAssignmentTooBig);
asherkin@263
  1284
                        return false;
asherkin@263
  1285
                    }
asherkin@263
  1286
                } else {
asherkin@263
  1287
                    if (given->fixedLength() != actual->fixedLength()) {
asherkin@263
  1288
                        cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
asherkin@263
  1289
                        return false;
asherkin@263
  1290
                    }
asherkin@263
  1291
                }
asherkin@263
  1292
            }
asherkin@263
  1293
        } else if (given->isFixedLength()) {
asherkin@263
  1294
            // We do not allow assignments in the form:
asherkin@263
  1295
            //    [][] = [][Y]
asherkin@263
  1296
            //
asherkin@263
  1297
            // Otherwise, the following code could break the size guarantees
asherkin@263
  1298
            // of the right-hand side:
asherkin@263
  1299
            //
asherkin@263
  1300
            //   new x[][5];
asherkin@263
  1301
            //   new y[][];
asherkin@263
  1302
            //   new z[3];
asherkin@263
  1303
            //
asherkin@263
  1304
            //   y = x;
asherkin@263
  1305
            //   y[0] = z;
asherkin@263
  1306
            //   
asherkin@263
  1307
            // Now |x[0]| contains a 4-length array.
asherkin@263
  1308
            if (level > 1) {
asherkin@263
  1309
                cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
asherkin@263
  1310
                return false;
asherkin@263
  1311
            }
asherkin@263
  1312
        }
asherkin@263
  1313
        given = given->contained();
asherkin@263
  1314
        actual = actual->contained();
asherkin@263
  1315
        level++;
asherkin@263
  1316
    }
asherkin@263
  1317
asherkin@263
  1318
    return typeCheckAssignment(pos, given, actual, forAssign);
asherkin@263
  1319
}
asherkin@263
  1320
asherkin@263
  1321
bool
asherkin@263
  1322
SemanticAnalysis::typeCheckAssignment(const SourcePosition &pos, Handle<Type> argGiven,
asherkin@263
  1323
                                      Handle<Type> argActual, bool forAssign)
asherkin@263
  1324
{
asherkin@263
  1325
    Local<Type> actual(zone_, argActual);
asherkin@263
  1326
    Local<Type> given(zone_, argGiven);
asherkin@263
  1327
asherkin@263
  1328
    if (actual->isArray())
asherkin@263
  1329
        return typeCheckArrayAssignment(pos, given, actual, forAssign);
asherkin@263
  1330
asherkin@263
  1331
    if (given->isArray()) {
asherkin@263
  1332
        cc_.reportError(pos, Message_CannotAssignArrayToScalar);
asherkin@263
  1333
        return false;
asherkin@263
  1334
    }
asherkin@263
  1335
asherkin@263
  1336
    // The given type may not have been dereferenced.
asherkin@263
  1337
    if (given->isReference())
asherkin@263
  1338
        given = given->contained();
asherkin@263
  1339
    if (actual->isReference())
asherkin@263
  1340
        actual = actual->contained();
asherkin@263
  1341
asherkin@263
  1342
    // We coerce unchecked to a few things.
asherkin@263
  1343
    if (actual->isUnchecked() || given->isUnchecked()) {
asherkin@263
  1344
        Type *check = actual->isUnchecked() ? given : actual;
asherkin@263
  1345
        if (check->isUnchecked() ||
asherkin@263
  1346
            check->isEnum() ||
asherkin@263
  1347
            check->isInt32() ||
asherkin@263
  1348
            check->isBool() ||
asherkin@263
  1349
            check->isFloat())
asherkin@263
  1350
        {
asherkin@263
  1351
            return true;
asherkin@263
  1352
        }
asherkin@263
  1353
        typeMismatch(pos, actual, given);
asherkin@263
  1354
        return false;
asherkin@263
  1355
    }
asherkin@263
  1356
asherkin@263
  1357
    if (given->isFunction() && actual->isFunction()) {
asherkin@263
  1358
        if (!Type::Compare(given, actual)) {
asherkin@263
  1359
            typeMismatch(pos, actual, given);
asherkin@263
  1360
            return false;
asherkin@263
  1361
        }
asherkin@263
  1362
        return true;
asherkin@263
  1363
    }
asherkin@263
  1364
asherkin@263
  1365
    if (actual->isEnum()) {
asherkin@263
  1366
        if (!given->isEnum() || actual != given) {
asherkin@263
  1367
            typeMismatch(pos, actual, given);
asherkin@263
  1368
            return false;
asherkin@263
  1369
        }
asherkin@263
  1370
        return true;
asherkin@263
  1371
    }
asherkin@263
  1372
asherkin@263
  1373
    if (actual->isStruct()) {
asherkin@263
  1374
        if (!given->isStruct() || actual != given) {
asherkin@263
  1375
            typeMismatch(pos, actual, given);
asherkin@263
  1376
            return false;
asherkin@263
  1377
        }
asherkin@263
  1378
        return true;
asherkin@263
  1379
    }
asherkin@263
  1380
asherkin@263
  1381
    if (given->isEnum() || given->isFunction() || given->isStruct()) {
asherkin@263
  1382
        typeMismatch(pos, actual, given);
asherkin@263
  1383
        return false;
asherkin@263
  1384
    }
asherkin@263
  1385
asherkin@263
  1386
    // This coercion is trivial.
asherkin@263
  1387
    if (given->isBool() && actual->isInt32())
asherkin@263
  1388
        return true;
asherkin@263
  1389
asherkin@263
  1390
    if (given->primitive() != actual->primitive()) {
asherkin@263
  1391
        typeMismatch(pos, actual, given);
asherkin@263
  1392
        return false;
asherkin@263
  1393
    }
asherkin@263
  1394
asherkin@263
  1395
    return true;
asherkin@263
  1396
}
asherkin@263
  1397
asherkin@263
  1398
bool
asherkin@263
  1399
SemanticAnalysis::typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual)
asherkin@263
  1400
{
asherkin@263
  1401
    return typeCheckAssignment(node->pos(), given, actual, false);
asherkin@263
  1402
}
asherkin@263
  1403
asherkin@263
  1404
bool
asherkin@263
  1405
SemanticAnalysis::checkArgumentCount(Handle<Type> type, unsigned actual)
asherkin@263
  1406
{
asherkin@263
  1407
    if (type->parameters()->length() == actual)
asherkin@263
  1408
        return true;
asherkin@263
  1409
asherkin@263
  1410
    if (actual > type->parameters()->length()) {
asherkin@263
  1411
        if (!type->isNative() || !type->isNativeVariadic())
asherkin@263
  1412
            return false;
asherkin@263
  1413
        return true;
asherkin@263
  1414
    }
asherkin@263
  1415
asherkin@263
  1416
    if (!type->defaults())
asherkin@263
  1417
        return false;
asherkin@263
  1418
asherkin@263
  1419
    // Missing arguments. See if there's a default argument for each missing
asherkin@263
  1420
    // actual.
asherkin@263
  1421
    for (unsigned i = actual; i < type->parameters()->length(); i++) {
asherkin@263
  1422
        if (!type->defaults()->at(i))
asherkin@263
  1423
            return false;
asherkin@263
  1424
    }
asherkin@263
  1425
asherkin@263
  1426
    return true;
asherkin@263
  1427
}
asherkin@263
  1428
asherkin@263
  1429
void
asherkin@263
  1430
SemanticAnalysis::visit(CallExpression *node)
asherkin@263
  1431
{
asherkin@263
  1432
    Local<Type> type(zone_, visitForLoad(node->callee()));
asherkin@263
  1433
    if (!type)
asherkin@263
  1434
        return;
asherkin@263
  1435
asherkin@263
  1436
    if (!type->isFunction()) {
asherkin@263
  1437
        cc_.reportError(node->pos(), Message_CalleeNotFunction);
asherkin@263
  1438
        return;
asherkin@263
  1439
    }
asherkin@263
  1440
asherkin@263
  1441
    if (!checkArgumentCount(type, node->arguments()->length())) {
asherkin@263
  1442
        cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
asherkin@263
  1443
        return;
asherkin@263
  1444
    }
asherkin@263
  1445
asherkin@263
  1446
    // NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
asherkin@263
  1447
    // if (fun->isForward()) {
asherkin@263
  1448
    //     cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
asherkin@263
  1449
    //     return;
asherkin@263
  1450
    // }
asherkin@263
  1451
asherkin@263
  1452
    for (unsigned i = 0; i < node->arguments()->length(); i++) {
asherkin@263
  1453
        // Note: we don't compute references unless the callee needs a
asherkin@263
  1454
        // reference type.
asherkin@263
  1455
        Expression *expression = node->arguments()->at(i);
asherkin@263
  1456
        Local<Type> given(zone_, visitAndApplyType(expression));
asherkin@263
  1457
        if (!given)
asherkin@263
  1458
            return;
asherkin@263
  1459
asherkin@263
  1460
        // Since we skip a load, check for a call expression that returns void.
asherkin@263
  1461
        if (given->isVoid()) {
asherkin@263
  1462
            assert(expression->isCallExpression());
asherkin@263
  1463
            CallExpression *call = expression->toCallExpression();
asherkin@263
  1464
            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
asherkin@263
  1465
            return;
asherkin@263
  1466
        }
asherkin@263
  1467
        
asherkin@263
  1468
        bool mustComputeReference;
asherkin@263
  1469
        if (i >= type->parameters()->length()) {
asherkin@263
  1470
            // Special handling for natives. Arguments past the formal must
asherkin@263
  1471
            // always have references computed. However, arrays are already
asherkin@263
  1472
            // references for natives.  
asherkin@263
  1473
            assert(type->isNative() && type->isNativeVariadic());
asherkin@263
  1474
            mustComputeReference = !given->isReference() && !given->isArray();
asherkin@263
  1475
        } else {
asherkin@263
  1476
            Local<Type> actual(zone_, type->parameterAt(i));
asherkin@263
  1477
asherkin@263
  1478
            if (expression->isIndexExpression()) {
asherkin@263
  1479
                // Disabled until we can make it work.
asherkin@263
  1480
#if 0
asherkin@263
  1481
                if (actual->isArray()) {
asherkin@263
  1482
                    // We special case the ability to pass x[y] into x[], which
asherkin@263
  1483
                    // creates an array slice. We only do this if we know the
asherkin@263
  1484
                    // assignment would otherwise not type-check.
asherkin@263
  1485
                    IndexExpression *index = expression->toIndexExpression();
asherkin@263
  1486
                    if (index->left()->type()->levels() == actual->levels())
asherkin@263
  1487
                        given = index->left()->type();
asherkin@263
  1488
                } else
asherkin@263
  1489
#endif
asherkin@263
  1490
                if (actual->isReference()) {
asherkin@263
  1491
                    cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
asherkin@263
  1492
                    return;
asherkin@263
  1493
                }
asherkin@263
  1494
            }
asherkin@263
  1495
asherkin@263
  1496
            if (!typeCheckParameter(expression, given, actual))
asherkin@263
  1497
                return;
asherkin@263
  1498
            mustComputeReference = actual->isReference() && !given->isReference();
asherkin@263
  1499
        }
asherkin@263
  1500
asherkin@263
  1501
        // If the actual is a reference, and the given is not, we'll need to
asherkin@263
  1502
        // compute a reference, which may be allocated on the stack.
asherkin@263
  1503
        if (mustComputeReference)
asherkin@263
  1504
            scope_->setUsesLifoHeap();
asherkin@263
  1505
    }
asherkin@263
  1506
asherkin@263
  1507
    node->setType(type->returnType());
asherkin@263
  1508
}
asherkin@263
  1509
asherkin@263
  1510
void
asherkin@263
  1511
SemanticAnalysis::ControlScope::inherit(const ControlStatus &other)
asherkin@263
  1512
{
asherkin@263
  1513
    if (other.returns() < status().returns())
asherkin@263
  1514
        return;
asherkin@263
  1515
asherkin@263
  1516
    if (other.terminates())
asherkin@263
  1517
        terminate(other.returns());
asherkin@263
  1518
    else
asherkin@263
  1519
        returns(other.returns());
asherkin@263
  1520
}
asherkin@263
  1521
asherkin@263
  1522
void
asherkin@263
  1523
SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
asherkin@263
  1524
{
asherkin@263
  1525
    // If both sides terminate in a return, we consider this a return as well.
asherkin@263
  1526
    if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
asherkin@263
  1527
        terminate(Returns_Always);
asherkin@263
  1528
        return;
asherkin@263
  1529
    }
asherkin@263
  1530
asherkin@263
  1531
    ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
asherkin@263
  1532
                          ? Returns_Never
asherkin@263
  1533
                          : Returns_Sometimes;
asherkin@263
  1534
asherkin@263
  1535
    if (left.terminates() && right.terminates())
asherkin@263
  1536
        terminate(status);
asherkin@263
  1537
    else
asherkin@263
  1538
        returns(status);
asherkin@263
  1539
}
asherkin@263
  1540
asherkin@263
  1541
void
asherkin@263
  1542
SemanticAnalysis::visit(IfStatement *node)
asherkin@263
  1543
{
asherkin@263
  1544
    Local<Type> type(zone_, visitForLoad(node->condition()));
asherkin@263
  1545
    if (!type)
asherkin@263
  1546
        return;
asherkin@263
  1547
asherkin@263
  1548
    if (!canTest(node, type))
asherkin@263
  1549
        return;
asherkin@263
  1550
asherkin@263
  1551
    ControlStatus trueBranch = visitForControl(node->ifTrue());
asherkin@263
  1552
    ControlStatus falseBranch = ControlStatus(false, Returns_Never);
asherkin@263
  1553
asherkin@263
  1554
    if (node->ifFalse())
asherkin@263
  1555
        falseBranch = visitForControl(node->ifFalse());
asherkin@263
  1556
asherkin@263
  1557
    control_->merge(trueBranch, falseBranch);
asherkin@263
  1558
}
asherkin@263
  1559
asherkin@263
  1560
void
asherkin@263
  1561
SemanticAnalysis::visit(IndexExpression *node)
asherkin@263
  1562
{
asherkin@263
  1563
    Local<Type> left(zone_, visitForLoad(node->left()));
asherkin@263
  1564
    Local<Type> right(zone_, visitForLoad(node->right()));
asherkin@263
  1565
asherkin@263
  1566
    if (!left || !right)
asherkin@263
  1567
        return;
asherkin@263
  1568
asherkin@263
  1569
    if (!right->isInt32() && !right->isEnum()) {
asherkin@263
  1570
        cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger);
asherkin@263
  1571
        return;
asherkin@263
  1572
    }
asherkin@263
  1573
    if (!left->isArray()) {
asherkin@263
  1574
        cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
asherkin@263
  1575
        return;
asherkin@263
  1576
    }
asherkin@263
  1577
asherkin@263
  1578
    // Note: char arrays are automatically up-casted to return an int32.
asherkin@263
  1579
    if (left->isCharArray())
asherkin@263
  1580
        node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
asherkin@263
  1581
    else
asherkin@263
  1582
        node->setType(left->contained());
asherkin@263
  1583
}
asherkin@263
  1584
asherkin@263
  1585
void
asherkin@263
  1586
SemanticAnalysis::visit(FieldExpression *node)
asherkin@263
  1587
{
asherkin@263
  1588
    Local<Type> left(zone_, visitForLoad(node->left()));
asherkin@263
  1589
    if (!left)
asherkin@263
  1590
        return;
asherkin@263
  1591
asherkin@263
  1592
    if (!left->isStruct()) {
asherkin@263
  1593
        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
asherkin@263
  1594
                        GetTypeName(left));
asherkin@263
  1595
        return;
asherkin@263
  1596
    }
asherkin@263
  1597
asherkin@263
  1598
    Local<String> field(zone_, node->field());
asherkin@263
  1599
asherkin@263
  1600
    unsigned offset;
asherkin@263
  1601
    Local<Descriptor> desc(zone_, left->lookupField(field, &offset));
asherkin@263
  1602
    if (!desc) {
asherkin@263
  1603
        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
asherkin@263
  1604
                        GetTypeName(left));
asherkin@263
  1605
        return;
asherkin@263
  1606
    }
asherkin@263
  1607
asherkin@263
  1608
    node->setFieldIndex(offset);
asherkin@263
  1609
    node->setType(desc->type());
asherkin@263
  1610
}
asherkin@263
  1611
asherkin@263
  1612
void
asherkin@263
  1613
SemanticAnalysis::visit(EnumStatement *node)
asherkin@263
  1614
{
asherkin@263
  1615
    Local<String> name(zone_, node->name());
asherkin@263
  1616
    Local<Type> type(zone_);
asherkin@263
  1617
    if (name)
asherkin@263
  1618
        type = zone_->types()->newEnum(name);
asherkin@263
  1619
    else
asherkin@263
  1620
        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
asherkin@263
  1621
asherkin@263
  1622
    if (!type)
asherkin@263
  1623
        return;
asherkin@263
  1624
asherkin@263
  1625
    if (node->decl())
asherkin@263
  1626
        node->decl()->setType(type);
asherkin@263
  1627
asherkin@263
  1628
    int value = 0;
asherkin@263
  1629
    for (size_t i = 0; i < node->entries()->length(); i++) {
asherkin@263
  1630
        EnumStatement::Entry &entry = node->entries()->at(i);
asherkin@263
  1631
asherkin@263
  1632
        BoxedPrimitive box = BoxedPrimitive::Int(value);
asherkin@263
  1633
        if (entry.expr) {
asherkin@263
  1634
            entry.expr->accept(this);
asherkin@263
  1635
            if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
asherkin@263
  1636
                cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
asherkin@263
  1637
                return;
asherkin@263
  1638
            }
asherkin@263
  1639
asherkin@263
  1640
            assert(box.type() == PrimitiveType_Int32);
asherkin@263
  1641
            value = box.toInt();
asherkin@263
  1642
        }
asherkin@263
  1643
asherkin@263
  1644
#if 0
asherkin@263
  1645
        entry.name->set(type, box);
asherkin@263
  1646
#endif
asherkin@263
  1647
        value++;
asherkin@263
  1648
    }
asherkin@263
  1649
}
asherkin@263
  1650
asherkin@263
  1651
static int
asherkin@263
  1652
SortCaseIntValues(const void *p1, const void *p2)
asherkin@263
  1653
{
asherkin@263
  1654
    CaseValue *v1 = (CaseValue *)p1;
asherkin@263
  1655
    CaseValue *v2 = (CaseValue *)p2;
asherkin@263
  1656
asherkin@263
  1657
    return v1->box.toInt() - v2->box.toInt();
asherkin@263
  1658
}
asherkin@263
  1659
asherkin@263
  1660
void
asherkin@263
  1661
SemanticAnalysis::visit(SwitchStatement *node)
asherkin@263
  1662
{
asherkin@263
  1663
    Local<Type> caseType(zone_, visitForLoad(node->expression()));
asherkin@263
  1664
    if (!caseType)
asherkin@263
  1665
        return;
asherkin@263
  1666
asherkin@263
  1667
    if (!caseType->isEnum() && !caseType->isInt32()) {
asherkin@263
  1668
        cc_.reportError(node->pos(), Message_CaseMustBeInteger);
asherkin@263
  1669
        return;
asherkin@263
  1670
    }
asherkin@263
  1671
asherkin@263
  1672
    PoolList<CaseValue> *values = new (zone_->pool()) PoolList<CaseValue>();
asherkin@263
  1673
    ControlStatus status = ControlStatus(false, Returns_Never);
asherkin@263
  1674
asherkin@263
  1675
    Local<Type> check(zone_);
asherkin@263
  1676
    for (size_t i = 0; i < node->cases()->length(); i++) {
asherkin@263
  1677
        Case *c = node->cases()->at(i);
asherkin@263
  1678
asherkin@263
  1679
        check = visitForLoad(c->expression());
asherkin@263
  1680
        if (!check)
asherkin@263
  1681
            return;
asherkin@263
  1682
asherkin@263
  1683
        if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false))
asherkin@263
  1684
            return;
asherkin@263
  1685
asherkin@263
  1686
        CaseValue v(i);
asherkin@263
  1687
        if (!EvaluateForConstant(c->expression(), &v.box)) {
asherkin@263
  1688
            cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant);
asherkin@263
  1689
            return;
asherkin@263
  1690
        }
asherkin@263
  1691
        if (!values->append(v))
asherkin@263
  1692
            return;
asherkin@263
  1693
asherkin@263
  1694
        if (c->others()) {
asherkin@263
  1695
            for (size_t j = 0; j < c->others()->length(); j++) {
asherkin@263
  1696
                Expression *expr = c->others()->at(j);
asherkin@263
  1697
                check = visitForLoad(expr);
asherkin@263
  1698
                if (!check)
asherkin@263
  1699
                    return;
asherkin@263
  1700
asherkin@263
  1701
                if (!typeCheckAssignment(expr->pos(), check, caseType, false))
asherkin@263
  1702
                    return;
asherkin@263
  1703
asherkin@263
  1704
                CaseValue v(i);
asherkin@263
  1705
                if (!EvaluateForConstant(expr, &v.box)) {
asherkin@263
  1706
                    cc_.reportError(expr->pos(), Message_CaseMustBeConstant);
asherkin@263
  1707
                    return;
asherkin@263
  1708
                }
asherkin@263
  1709
                if (!values->append(v))
asherkin@263
  1710
                    return;
asherkin@263
  1711
            }
asherkin@263
  1712
        }
asherkin@263
  1713
asherkin@263
  1714
        ControlStatus latest = visitForControl(c->statement());
asherkin@263
  1715
asherkin@263
  1716
        if (i != 0)
asherkin@263
  1717
            control_->merge(status, latest);
asherkin@263
  1718
asherkin@263
  1719
        status = latest;
asherkin@263
  1720
    }
asherkin@263
  1721
asherkin@263
  1722
    if (node->defaultCase()) {
asherkin@263
  1723
        ControlStatus latest = visitForControl(node->defaultCase());
asherkin@263
  1724
asherkin@263
  1725
        if (node->cases()->length()) {
asherkin@263
  1726
            // If we had any other cases, we must merge.
asherkin@263
  1727
            control_->merge(status, latest);
asherkin@263
  1728
        } else {
asherkin@263
  1729
            // Otherwise, control-flow always flows through here.
asherkin@263
  1730
            control_->inherit(latest);
asherkin@263
  1731
        }
asherkin@263
  1732
    } else if (node->cases()->length()) {
asherkin@263
  1733
        control_->merge(status, ControlStatus(false, Returns_Never));
asherkin@263
  1734
    }
asherkin@263
  1735
asherkin@263
  1736
    if (values->length() > 1) {
asherkin@263
  1737
        qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues);
asherkin@263
  1738
asherkin@263
  1739
        for (size_t i = 1; i < values->length(); i++) {
asherkin@263
  1740
            CaseValue &prev = values->at(i - 1);
asherkin@263
  1741
            CaseValue &cur = values->at(i);
asherkin@263
  1742
            if (prev.box.toInt() == cur.box.toInt()) {
asherkin@263
  1743
                cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue);
asherkin@263
  1744
                return;
asherkin@263
  1745
            }
asherkin@263
  1746
        }
asherkin@263
  1747
    }
asherkin@263
  1748
asherkin@263
  1749
    node->setCaseValueList(values);
asherkin@263
  1750
}
asherkin@263
  1751
asherkin@263
  1752
void
asherkin@263
  1753
SemanticAnalysis::visit(StructureStatement *node)
asherkin@263
  1754
{
asherkin@263
  1755
#if 0
asherkin@263
  1756
    // If this node already has a type, it was pre-analyzed, so skip it.
asherkin@263
  1757
    if (node->decl()->type())
asherkin@263
  1758
        return;
asherkin@263
  1759
asherkin@263
  1760
    FieldList *fields = node->fields();
asherkin@263
  1761
    Local<FixedArray> desctable(zone_, FixedArray::New(zone_, fields->length(), Heap::Tenure_Old));
asherkin@263
  1762
    if (!desctable)
asherkin@263
  1763
        return;
asherkin@263
  1764
asherkin@263
  1765
    Vector<unsigned> composedList;
asherkin@263
  1766
    StructureBufferBuilder builder;
asherkin@263
  1767
asherkin@263
  1768
    Local<Type> type(zone_);
asherkin@263
  1769
    Local<String> name(zone_);
asherkin@263
  1770
    Local<Descriptor> desc(zone_);
asherkin@263
  1771
    for (size_t i = 0; i < fields->length(); i++) {
asherkin@263
  1772
        StructureStatement::Field *field = fields->at(i);
asherkin@263
  1773
asherkin@263
  1774
        type = bindType(field->pos(), field->type());
asherkin@263
  1775
        if (!type)
asherkin@263
  1776
            return;
asherkin@263
  1777
asherkin@263
  1778
        if (field->dimensions()) {
asherkin@263
  1779
            type = buildArrayType(type, field->dimensions(), false);
asherkin@263
  1780
            if (!type)
asherkin@263
  1781
                return;
asherkin@263
  1782
asherkin@263
  1783
            if (!ArrayMap::Attach(zone_, type))
asherkin@263
  1784
                return;
asherkin@263
  1785
        }
asherkin@263
  1786
asherkin@263
  1787
        if (IsScalarString(type)) {
asherkin@263
  1788
            cc_.reportError(field->pos(), Message_CannotDeclareStringCell);
asherkin@263
  1789
            return;
asherkin@263
  1790
        }
asherkin@263
  1791
asherkin@263
  1792
        unsigned offset;
asherkin@263
  1793
        if (!builder.add(type, &offset))
asherkin@263
  1794
            return;
asherkin@263
  1795
asherkin@263
  1796
        name = field->name();
asherkin@263
  1797
        desc = Descriptor::New(zone_, name, type, offset);
asherkin@263
  1798
        if (!desc)
asherkin@263
  1799
            return;
asherkin@263
  1800
asherkin@263
  1801
        desctable->set(zone_, i, desc);
asherkin@263
  1802
asherkin@263
  1803
        if (type->isStruct() || type->isArray()) {
asherkin@263
  1804
            if (!composedList.append(i))
asherkin@263
  1805
                return;
asherkin@263
  1806
        }
asherkin@263
  1807
    }
asherkin@263
  1808
asherkin@263
  1809
    Local<FixedArray> composed(zone_);
asherkin@263
  1810
    if (composedList.length()) {
asherkin@263
  1811
        composed = FixedArray::New(zone_, composedList.length(), Heap::Tenure_Old);
asherkin@263
  1812
        if (!composed)
asherkin@263
  1813
            return;
asherkin@263
  1814
asherkin@263
  1815
        for (unsigned i = 0; i < composedList.length(); i++)
asherkin@263
  1816
            composed->set(zone_, i, desctable->at(i));
asherkin@263
  1817
    }
asherkin@263
  1818
asherkin@263
  1819
    Local<StructMap> map(zone_, StructMap::New(zone_, builder, composed));
asherkin@263
  1820
    if (!map)
asherkin@263
  1821
        return;
asherkin@263
  1822
asherkin@263
  1823
    name = node->decl()->name();
asherkin@263
  1824
    type = zone_->types()->newStruct(name, desctable, map);
asherkin@263
  1825
    if (!type)
asherkin@263
  1826
        return;
asherkin@263
  1827
asherkin@263
  1828
    map->setType(type);
asherkin@263
  1829
    node->decl()->setType(type);
asherkin@263
  1830
#endif
asherkin@263
  1831
}
asherkin@263
  1832
asherkin@263
  1833
void
asherkin@263
  1834
SemanticAnalysis::visit(StringLiteral *node)
asherkin@263
  1835
{
asherkin@263
  1836
    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char));
asherkin@263
  1837
    if (!type)
asherkin@263
  1838
        return;
asherkin@263
  1839
asherkin@263
  1840
    type = Type::NewArray(zone_, type, node->string()->length() + 1, true);
asherkin@263
  1841
    if (!type)
asherkin@263
  1842
        return;
asherkin@263
  1843
asherkin@263
  1844
    node->setType(type);
asherkin@263
  1845
}
asherkin@263
  1846
asherkin@263
  1847
void
asherkin@263
  1848
SemanticAnalysis::visit(FloatLiteral *node)
asherkin@263
  1849
{
asherkin@263
  1850
    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
asherkin@263
  1851
    if (!type)
asherkin@263
  1852
        return;
asherkin@263
  1853
asherkin@263
  1854
    node->setType(type);
asherkin@263
  1855
}
asherkin@263
  1856
asherkin@263
  1857
void
asherkin@263
  1858
SemanticAnalysis::visit(BreakStatement *node)
asherkin@263
  1859
{
asherkin@263
  1860
    if (!loop_) {
asherkin@263
  1861
        cc_.reportError(node->pos(), Message_BreakOutsideLoop);
asherkin@263
  1862
        return;
asherkin@263
  1863
    }
asherkin@263
  1864
asherkin@263
  1865
    // Note: ignore breaks that occur in unreachable control-flow.
asherkin@263
  1866
    if (!control_->status().terminates())
asherkin@263
  1867
        loop_->addBreak();
asherkin@263
  1868
asherkin@263
  1869
    control_->terminate(Returns_Never);
asherkin@263
  1870
}
asherkin@263
  1871
asherkin@263
  1872
void
asherkin@263
  1873
SemanticAnalysis::visit(ContinueStatement *node)
asherkin@263
  1874
{
asherkin@263
  1875
    if (!loop_) {
asherkin@263
  1876
        cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
asherkin@263
  1877
        return;
asherkin@263
  1878
    }
asherkin@263
  1879
asherkin@263
  1880
    // Note: ignore continues that occur in unreachable control-flow.
asherkin@263
  1881
    if (!control_->status().terminates())
asherkin@263
  1882
        loop_->addContinue();
asherkin@263
  1883
asherkin@263
  1884
    control_->terminate(Returns_Never);
asherkin@263
  1885
}
asherkin@263
  1886
asherkin@263
  1887
void
asherkin@263
  1888
SemanticAnalysis::visit(ArrayLiteral *node)
asherkin@263
  1889
{
asherkin@263
  1890
    // We should never visit this.
asherkin@263
  1891
    cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral);
asherkin@263
  1892
}
asherkin@263
  1893
asherkin@263
  1894
void
asherkin@263
  1895
SemanticAnalysis::visit(ImportStatement *node)
asherkin@263
  1896
{
asherkin@263
  1897
}
asherkin@263
  1898
dvander@195
  1899
#endif