src/compiler/NameBinding.cpp
author Asher Baker <asherkin@gmail.com>
Mon Jun 10 15:52:44 2013 +0100 (2013-06-10)
changeset 265 3a903b89a514
parent 263 ba85a47ee414
permissions -rw-r--r--
Fixed type checking for multidimensional arrays.
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 SourcePawn.
asherkin@263
     6
 *
asherkin@263
     7
 * SourcePawn 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
 * SourcePawn 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
 * SourcePawn. If not, see http://www.gnu.org/licenses/.
asherkin@263
    18
 */
asherkin@263
    19
#include "../Strings.h"
asherkin@263
    20
#include "../Zone.h"
asherkin@263
    21
#include "../TypeManager.h"
asherkin@263
    22
#include "NameBinding.h"
asherkin@263
    23
#include "Scopes.h"
asherkin@263
    24
#include "ConstantEvaluator.h"
asherkin@263
    25
#include "../Spaces-inl.h"
asherkin@263
    26
#include "../Heap-inl.h"
asherkin@263
    27
asherkin@263
    28
using namespace ke;
asherkin@263
    29
asherkin@263
    30
// Create symbol tables and symbols for every scope and declaration. For type
asherkin@263
    31
// declarations and methods, we also pre-allocate a Type object, so that
asherkin@263
    32
// circular dependencies between types will work.
asherkin@263
    33
class NamePopulator : public AstVisitor
asherkin@263
    34
{
asherkin@263
    35
  private:
asherkin@263
    36
    // This class is analagous to a Scope, however, it allows us to create
asherkin@263
    37
    // scopes lazily. If a scope is requested, and the current environment
asherkin@263
    38
    // has no scope, then a scope is created. If no scope is ever requested,
asherkin@263
    39
    // a scope does not need to be created.
asherkin@263
    40
    class SymbolEnv
asherkin@263
    41
    {
asherkin@263
    42
      public:
asherkin@263
    43
        SymbolEnv(SymbolEnv **prevp, Scope *scope = NULL)
asherkin@263
    44
          : envp_(prevp),
asherkin@263
    45
            prev_(*prevp),
asherkin@263
    46
            scope_(scope)
asherkin@263
    47
        {
asherkin@263
    48
            *envp_ = this;
asherkin@263
    49
        }
asherkin@263
    50
        ~SymbolEnv() {
asherkin@263
    51
            *envp_ = prev_;
asherkin@263
    52
        }
asherkin@263
    53
asherkin@263
    54
        Scope *scope() {
asherkin@263
    55
            return scope_;
asherkin@263
    56
        }
asherkin@263
    57
        void setScope(Scope *scope) {
asherkin@263
    58
            assert(!scope_);
asherkin@263
    59
            scope_ = scope;
asherkin@263
    60
        }
asherkin@263
    61
        SymbolEnv *prev() const {
asherkin@263
    62
            return prev_;
asherkin@263
    63
        }
asherkin@263
    64
asherkin@263
    65
      private:
asherkin@263
    66
        SymbolEnv **envp_;
asherkin@263
    67
        SymbolEnv *prev_;
asherkin@263
    68
        Scope *scope_;
asherkin@263
    69
    };
asherkin@263
    70
asherkin@263
    71
    enum ReturnStatus {
asherkin@263
    72
        NoReturn,
asherkin@263
    73
        VoidReturn,
asherkin@263
    74
        ValueReturn
asherkin@263
    75
    };
asherkin@263
    76
asherkin@263
    77
    class FunctionScope
asherkin@263
    78
    {
asherkin@263
    79
      public:
asherkin@263
    80
        FunctionScope(FunctionScope **prevp)
asherkin@263
    81
          : prevp_(prevp),
asherkin@263
    82
            prev_(*prevp),
asherkin@263
    83
            status_(NoReturn)
asherkin@263
    84
        {
asherkin@263
    85
            *prevp_ = this;
asherkin@263
    86
        }
asherkin@263
    87
        ~FunctionScope() {
asherkin@263
    88
            *prevp_ = prev_;
asherkin@263
    89
        }
asherkin@263
    90
        ReturnStatus returns() const {
asherkin@263
    91
            return status_;
asherkin@263
    92
        }
asherkin@263
    93
        void returns(ReturnStatus status) {
asherkin@263
    94
            if (status > status_)
asherkin@263
    95
                status_ = status;
asherkin@263
    96
        }
asherkin@263
    97
      private:
asherkin@263
    98
        FunctionScope **prevp_;
asherkin@263
    99
        FunctionScope *prev_;
asherkin@263
   100
        ReturnStatus status_;
asherkin@263
   101
    };
asherkin@263
   102
asherkin@263
   103
  public:
asherkin@263
   104
    NamePopulator(Zone *zone, CompileContext &cc, TranslationUnit *unit)
asherkin@263
   105
      : zone_(zone),
asherkin@263
   106
        pool_(zone->pool()),
asherkin@263
   107
        cc_(cc),
asherkin@263
   108
        unit_(unit),
asherkin@263
   109
        env_(NULL),
asherkin@263
   110
        fun_(NULL)
asherkin@263
   111
    {
asherkin@263
   112
    }
asherkin@263
   113
asherkin@263
   114
    void analyze() {
asherkin@263
   115
        ImportScope *importScope = ImportScope::New(pool_);
asherkin@263
   116
        if (!importScope)
asherkin@263
   117
            return;
asherkin@263
   118
asherkin@263
   119
        // At the import level, we declare system types.
asherkin@263
   120
        if (!declareSystemTypes(importScope))
asherkin@263
   121
            return;
asherkin@263
   122
asherkin@263
   123
        GlobalScope *globalScope = GlobalScope::New(pool_, importScope);
asherkin@263
   124
        if (!globalScope)
asherkin@263
   125
            return;
asherkin@263
   126
asherkin@263
   127
        unit_->setImportScope(importScope);
asherkin@263
   128
        unit_->setGlobalScope(globalScope);
asherkin@263
   129
asherkin@263
   130
        SymbolEnv env(&env_, globalScope);
asherkin@263
   131
asherkin@263
   132
        for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
asherkin@263
   133
            Statement *stmt = unit_->tree()->statements()->at(i);
asherkin@263
   134
            stmt->accept(this);
asherkin@263
   135
        }
asherkin@263
   136
asherkin@263
   137
        return;
asherkin@263
   138
    }
asherkin@263
   139
asherkin@263
   140
    bool declareSystemType(ImportScope *scope, const char *name, Handle<Type> effective) {
asherkin@263
   141
        Local<String> tag(zone_, zone_->makeSymbol(name));
asherkin@263
   142
        if (!tag)
asherkin@263
   143
            return false;
asherkin@263
   144
asherkin@263
   145
        Local<Type> type(zone_, zone_->types()->getType());
asherkin@263
   146
asherkin@263
   147
        TypeSymbol *sym = new (pool_) TypeSymbol(scope, tag, type, effective);
asherkin@263
   148
        return scope->addSymbol(sym);
asherkin@263
   149
    }
asherkin@263
   150
asherkin@263
   151
    bool declareSystemType(ImportScope *scope, const char *name, PrimitiveType prim) {
asherkin@263
   152
        Local<Type> primitive(zone_, zone_->types()->getPrimitive(prim));
asherkin@263
   153
        assert(primitive);
asherkin@263
   154
        return declareSystemType(scope, name, primitive);
asherkin@263
   155
    }
asherkin@263
   156
asherkin@263
   157
    bool declareSystemTypes(ImportScope *scope) {
asherkin@263
   158
        if (!declareSystemType(scope, "float", PrimitiveType_Float))
asherkin@263
   159
            return false;
asherkin@263
   160
        if (!declareSystemType(scope, "_", PrimitiveType_Int32))
asherkin@263
   161
            return false;
asherkin@263
   162
        if (!declareSystemType(scope, "int", PrimitiveType_Int32))
asherkin@263
   163
            return false;
asherkin@263
   164
        if (!declareSystemType(scope, "bool", PrimitiveType_Bool))
asherkin@263
   165
            return false;
asherkin@263
   166
        if (!declareSystemType(scope, "char", PrimitiveType_Char))
asherkin@263
   167
            return false;
asherkin@263
   168
asherkin@263
   169
        Local<Type> voidType(zone_, zone_->types()->getVoid());
asherkin@263
   170
        if (!declareSystemType(scope, "void", voidType))
asherkin@263
   171
            return false;
asherkin@263
   172
asherkin@263
   173
        return true;
asherkin@263
   174
    }
asherkin@263
   175
asherkin@263
   176
    void visitVariableDeclaration(VariableDeclaration *node) {
asherkin@263
   177
        Scope *scope = env_->scope();
asherkin@263
   178
        if (!scope || scope->kind() != Scope::GLOBAL) {
asherkin@263
   179
            if ((scope = getOrCreateBlockScope()) == NULL)
asherkin@263
   180
                return;
asherkin@263
   181
        }
asherkin@263
   182
asherkin@263
   183
        if (scope->kind() == Scope::GLOBAL) {
asherkin@263
   184
            // The symbol must be added now, since it could be an export.
asherkin@263
   185
            VariableSymbol *sym = new (pool_) VariableSymbol(scope, node->name(), node->pos());
asherkin@263
   186
            node->setSymbol(sym);
asherkin@263
   187
asherkin@263
   188
            if (!registerName(scope, sym))
asherkin@263
   189
                return;
asherkin@263
   190
        } else {
asherkin@263
   191
            // We ensure the scope will exist at the name binding phase, but
asherkin@263
   192
            // we don't actually register the variable symbol yet. Otherwise,
asherkin@263
   193
            // when binding the initializer, we could encounter:
asherkin@263
   194
            //    new x = x;
asherkin@263
   195
            //
asherkin@263
   196
            // And we don't necessarily want this to bind.
asherkin@263
   197
        }
asherkin@263
   198
asherkin@263
   199
        if (node->initialization())
asherkin@263
   200
            node->initialization()->accept(this);
asherkin@263
   201
    }
asherkin@263
   202
asherkin@263
   203
    void visitEnumStatement(EnumStatement *node) {
asherkin@263
   204
        Local<String> name(zone_, node->name());
asherkin@263
   205
        Local<Type> type(zone_);
asherkin@263
   206
        if (name)
asherkin@263
   207
            type = zone_->types()->newEnum(name);
asherkin@263
   208
        else
asherkin@263
   209
            type = zone_->types()->getPrimitive(PrimitiveType_Int32);
asherkin@263
   210
asherkin@263
   211
        if (!type)
asherkin@263
   212
            return;
asherkin@263
   213
asherkin@263
   214
        Scope *scope = getGlobalOrCreateBlockScope();
asherkin@263
   215
        if (!scope)
asherkin@263
   216
            return;
asherkin@263
   217
asherkin@263
   218
        if (name) {
asherkin@263
   219
            Local<Type> symType(zone_, zone_->types()->getType());
asherkin@263
   220
            TypeSymbol *sym = new (pool_) TypeSymbol(scope, name, symType, type);
asherkin@263
   221
            if (!registerName(scope, sym))
asherkin@263
   222
                return;
asherkin@263
   223
asherkin@263
   224
            if (scope->kind() == Scope::GLOBAL) {
asherkin@263
   225
                if (!unit_->globalScope()->exported()->append(sym))
asherkin@263
   226
                    return;
asherkin@263
   227
            }
asherkin@263
   228
        }
asherkin@263
   229
asherkin@263
   230
        // We want each field of the expression to qualify as a constant expression.
asherkin@263
   231
        if ((type = zone_->types()->qualify(type, TypeQual_ConstExpr)) == NULL)
asherkin@263
   232
            return;
asherkin@263
   233
        
asherkin@263
   234
        int value = 0;
asherkin@263
   235
        for (size_t i = 0; i < node->entries()->length(); i++) {
asherkin@263
   236
            EnumStatement::Entry &entry = node->entries()->at(i);
asherkin@263
   237
            BoxedPrimitive box = BoxedPrimitive::Int(value);
asherkin@263
   238
            if (entry.expr) {
asherkin@263
   239
                if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
asherkin@263
   240
                    cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
asherkin@263
   241
                    return;
asherkin@263
   242
                }
asherkin@263
   243
asherkin@263
   244
                assert(box.type() == PrimitiveType_Int32);
asherkin@263
   245
                value = box.toInt();
asherkin@263
   246
            }
asherkin@263
   247
         
asherkin@263
   248
            ConstantSymbol *sym = new (pool_) ConstantSymbol(scope, entry.name, entry.pos, type, box);
asherkin@263
   249
            if (!registerName(scope, sym))
asherkin@263
   250
                return;
asherkin@263
   251
            if (scope->kind() == Scope::GLOBAL) {
asherkin@263
   252
                if (!unit_->globalScope()->exported()->append(sym))
asherkin@263
   253
                    return;
asherkin@263
   254
            }
asherkin@263
   255
asherkin@263
   256
            entry.sym = sym;
asherkin@263
   257
            value++;
asherkin@263
   258
        }
asherkin@263
   259
    }
asherkin@263
   260
asherkin@263
   261
    void visitFunctionStatement(FunctionStatement *node) {
asherkin@263
   262
        // We create function types ahead of time, not for any particular
asherkin@263
   263
        // reason. It makes things consistent with FunctionTypeStatement,
asherkin@263
   264
        // which actually does produce a type.
asherkin@263
   265
        Local<FunctionType> type(zone_, FunctionType::New(zone_, node->name(), node->token()));
asherkin@263
   266
        if (!type)
asherkin@263
   267
            return;
asherkin@263
   268
asherkin@263
   269
        assert(env_->scope());
asherkin@263
   270
asherkin@263
   271
        // Function statements are always named, so add the name to the outer scope.
asherkin@263
   272
        FunctionSymbol *sym = new (pool_) FunctionSymbol(env_->scope(), node->name(), node->pos(), type);
asherkin@263
   273
        if (!registerName(env_->scope(), sym))
asherkin@263
   274
            return;
asherkin@263
   275
asherkin@263
   276
        if (node->token() == TOK_PUBLIC ||
asherkin@263
   277
            node->token() == TOK_FORWARD ||
asherkin@263
   278
            node->token() == TOK_NATIVE)
asherkin@263
   279
        {
asherkin@263
   280
            // We're in the global scope, for sure.
asherkin@263
   281
            assert(env_->scope()->kind() == Scope::GLOBAL);
asherkin@263
   282
asherkin@263
   283
            if (!unit_->globalScope()->exported()->append(sym))
asherkin@263
   284
                return;
asherkin@263
   285
        }
asherkin@263
   286
asherkin@263
   287
        node->setSymbol(sym);
asherkin@263
   288
asherkin@263
   289
        // Scope for the function's arguments.
asherkin@263
   290
        SymbolEnv argEnv(&env_);
asherkin@263
   291
        if (!registerArguments(node->signature()))
asherkin@263
   292
            return;
asherkin@263
   293
asherkin@263
   294
        // Scope for function body.
asherkin@263
   295
        SymbolEnv localEnv(&env_);
asherkin@263
   296
        FunctionScope fun(&fun_);
asherkin@263
   297
        if (node->body())
asherkin@263
   298
            node->body()->accept(this);
asherkin@263
   299
asherkin@263
   300
        // Function statements have quirky semantics around their return
asherkin@263
   301
        // type. For reasonable compatibility with SP1, we use the following
asherkin@263
   302
        // heuristics for when no explicit type is declared.
asherkin@263
   303
        if (!node->signature().returnType()) {
asherkin@263
   304
            Local<Type> type(zone_);
asherkin@263
   305
            if (node->token() == TOK_FORWARD || node->token() == TOK_NATIVE) {
asherkin@263
   306
                // If the function type is a native or forward, we always
asherkin@263
   307
                // assume it returns an int32.
asherkin@263
   308
                type = zone_->types()->getPrimitive(PrimitiveType_Int32);
asherkin@263
   309
            } else if (fun.returns() != ValueReturn) {
asherkin@263
   310
                // This function never returns a value, so mark it as
asherkin@263
   311
                // returning void.
asherkin@263
   312
                type = zone_->types()->getVoid();
asherkin@263
   313
            }
asherkin@263
   314
            // No need to NULL check here, we'll catch OOM later.
asherkin@263
   315
            node->sym()->type()->setReturnType(type);
asherkin@263
   316
        }
asherkin@263
   317
asherkin@263
   318
        node->setScopes(argEnv.scope(), localEnv.scope());
asherkin@263
   319
    }
asherkin@263
   320
asherkin@263
   321
    void visitStructureStatement(StructureStatement *node) {
asherkin@263
   322
        assert(false);
asherkin@263
   323
    }
asherkin@263
   324
asherkin@263
   325
    void visiFunctionTypeStatementt(FunctionTypeStatement *node) {
asherkin@263
   326
        assert(false);
asherkin@263
   327
    }
asherkin@263
   328
asherkin@263
   329
    void visitNameProxy(NameProxy *name) {
asherkin@263
   330
    }
asherkin@263
   331
    void visitAssignment(Assignment *node) {
asherkin@263
   332
        node->lvalue()->accept(this);
asherkin@263
   333
        node->expression()->accept(this);
asherkin@263
   334
    }
asherkin@263
   335
    void visitBinaryExpression(BinaryExpression *node) {
asherkin@263
   336
        node->left()->accept(this);
asherkin@263
   337
        node->right()->accept(this);
asherkin@263
   338
    }
asherkin@263
   339
    void visitReturnStatement(ReturnStatement *node) {
asherkin@263
   340
        if (node->expression())
asherkin@263
   341
            fun_->returns(ValueReturn);
asherkin@263
   342
        else
asherkin@263
   343
            fun_->returns(VoidReturn);
asherkin@263
   344
    }
asherkin@263
   345
    void visitForStatement(ForStatement *node) {
asherkin@263
   346
        SymbolEnv env(&env_);
asherkin@263
   347
asherkin@263
   348
        if (node->initialization())
asherkin@263
   349
            node->initialization()->accept(this);
asherkin@263
   350
        if (node->condition())
asherkin@263
   351
            node->condition()->accept(this);
asherkin@263
   352
        if (node->update())
asherkin@263
   353
            node->update()->accept(this);
asherkin@263
   354
        node->body()->accept(this);
asherkin@263
   355
asherkin@263
   356
        node->setScope(env.scope());
asherkin@263
   357
    }
asherkin@263
   358
    void visitBlockStatement(BlockStatement *node) {
asherkin@263
   359
        if (node->type() == TOK_NEW) {
asherkin@263
   360
            // Don't create a symbol environment for this block, since it
asherkin@263
   361
            // was created solely to house multiple variable decls.
asherkin@263
   362
            for (size_t i = 0; i < node->statements()->length(); i++)
asherkin@263
   363
                node->statements()->at(i)->accept(this);
asherkin@263
   364
        } else {
asherkin@263
   365
            assert(node->type() == TOK_LBRACE);
asherkin@263
   366
asherkin@263
   367
            SymbolEnv env(&env_);
asherkin@263
   368
asherkin@263
   369
            for (size_t i = 0; i < node->statements()->length(); i++)
asherkin@263
   370
                node->statements()->at(i)->accept(this);
asherkin@263
   371
        
asherkin@263
   372
            if (node->type() == TOK_NEW) {
asherkin@263
   373
                assert(!env.scope());
asherkin@263
   374
                return;
asherkin@263
   375
            }
asherkin@263
   376
asherkin@263
   377
            node->setScope(env.scope());
asherkin@263
   378
        }
asherkin@263
   379
    }
asherkin@263
   380
    void visitIntegerLiteral(IntegerLiteral *node) {
asherkin@263
   381
    }
asherkin@263
   382
    void visitExpressionStatement(ExpressionStatement *node) {
asherkin@263
   383
        node->expression()->accept(this);
asherkin@263
   384
    }
asherkin@263
   385
    void visitCallExpression(CallExpression *node) {
asherkin@263
   386
        node->callee()->accept(this);
asherkin@263
   387
        for (size_t i = 0; i < node->arguments()->length(); i++)
asherkin@263
   388
            node->arguments()->at(i)->accept(this);
asherkin@263
   389
    }
asherkin@263
   390
    void visitIfStatement(IfStatement *node) {
asherkin@263
   391
        node->ifTrue()->accept(this);
asherkin@263
   392
        if (node->ifFalse())
asherkin@263
   393
            node->ifFalse()->accept(this);
asherkin@263
   394
    }
asherkin@263
   395
    void visitIndexExpression(IndexExpression *node) {
asherkin@263
   396
        node->left()->accept(this);
asherkin@263
   397
        node->right()->accept(this);
asherkin@263
   398
    }
asherkin@263
   399
    void visitFloatLiteral(FloatLiteral *node) {
asherkin@263
   400
    }
asherkin@263
   401
    void visitWhileStatement(WhileStatement *node) {
asherkin@263
   402
        node->condition()->accept(this);
asherkin@263
   403
        node->body()->accept(this);
asherkin@263
   404
    }
asherkin@263
   405
    void visitBreakStatement(BreakStatement *node) {
asherkin@263
   406
    }
asherkin@263
   407
    void visitContinueStatement(ContinueStatement *node) {
asherkin@263
   408
    }
asherkin@263
   409
    void visitStringLiteral(StringLiteral *node) {
asherkin@263
   410
    }
asherkin@263
   411
    void visitIncDecExpression(IncDecExpression *node) {
asherkin@263
   412
        node->expression()->accept(this);
asherkin@263
   413
    }
asherkin@263
   414
    void visitUnaryExpression(UnaryExpression *node) {
asherkin@263
   415
        node->expression()->accept(this);
asherkin@263
   416
    }
asherkin@263
   417
    void visitTernaryExpression(TernaryExpression *node) {
asherkin@263
   418
        assert(false);
asherkin@263
   419
    }
asherkin@263
   420
    void visitBooleanLiteral(BooleanLiteral *node) {
asherkin@263
   421
    }
asherkin@263
   422
    void visitFieldExpression(FieldExpression *node) {
asherkin@263
   423
    }
asherkin@263
   424
    void visitSwitchStatement(SwitchStatement *node) {
asherkin@263
   425
        if (node->defaultCase())
asherkin@263
   426
            node->defaultCase()->accept(this);
asherkin@263
   427
asherkin@263
   428
        for (size_t i = 0; i < node->cases()->length(); i++)
asherkin@263
   429
            node->cases()->at(i)->statement()->accept(this);
asherkin@263
   430
    }
asherkin@263
   431
    void visitArrayLiteral(ArrayLiteral *node) {
asherkin@263
   432
    }
asherkin@263
   433
    void visitImportStatement(ImportStatement *node) {
asherkin@263
   434
    }
asherkin@263
   435
asherkin@263
   436
  private:
asherkin@263
   437
    Scope *getGlobalOrCreateBlockScope() {
asherkin@263
   438
        if (env_->scope()) {
asherkin@263
   439
            assert(env_->scope()->kind() == Scope::BLOCK ||
asherkin@263
   440
                   env_->scope()->kind() == Scope::GLOBAL);
asherkin@263
   441
            return env_->scope();
asherkin@263
   442
        }
asherkin@263
   443
        return getOrCreateBlockScope();
asherkin@263
   444
    }
asherkin@263
   445
    Scope *getOrCreateBlockScope() {
asherkin@263
   446
        if (env_->scope()) {
asherkin@263
   447
            assert(env_->scope()->kind() == Scope::BLOCK);
asherkin@263
   448
            return env_->scope();
asherkin@263
   449
        }
asherkin@263
   450
        
asherkin@263
   451
        LocalScope *scope = LocalScope::New(pool_);
asherkin@263
   452
        if (!scope)
asherkin@263
   453
            return NULL;
asherkin@263
   454
asherkin@263
   455
        env_->setScope(scope);
asherkin@263
   456
        return scope;
asherkin@263
   457
    }
asherkin@263
   458
asherkin@263
   459
    bool registerName(Scope *scope, Symbol *sym) {
asherkin@263
   460
        if (!scope)
asherkin@263
   461
            return false;
asherkin@263
   462
asherkin@263
   463
        if (Symbol *other = scope->localLookup(sym->name())) {
asherkin@263
   464
            // Report, but allow errors to continue.
asherkin@263
   465
            cc_.reportError(sym->pos(), Message_RedeclaredName,
asherkin@263
   466
                            sym->name()->chars(),
asherkin@263
   467
                            other->pos().line,
asherkin@263
   468
                            other->pos().col);
asherkin@263
   469
            return true;
asherkin@263
   470
        }
asherkin@263
   471
asherkin@263
   472
        return scope->addSymbol(sym);
asherkin@263
   473
    }
asherkin@263
   474
asherkin@263
   475
    bool registerArguments(const FunctionSignature &sig) {
asherkin@263
   476
        if (!sig.parameters()->length())
asherkin@263
   477
            return true;
asherkin@263
   478
asherkin@263
   479
        ArgumentScope *argScope = ArgumentScope::New(pool_);
asherkin@263
   480
        if (!argScope)
asherkin@263
   481
            return false;
asherkin@263
   482
        env_->setScope(argScope);
asherkin@263
   483
asherkin@263
   484
        for (size_t i = 0; i < sig.parameters()->length(); i++) {
asherkin@263
   485
            Parameter *param = sig.parameters()->at(i);
asherkin@263
   486
            VariableSymbol *sym = new (pool_) VariableSymbol(argScope, param->name(), param->pos());
asherkin@263
   487
            if (!registerName(env_->scope(), sym))
asherkin@263
   488
                return false;
asherkin@263
   489
            param->setSymbol(sym);
asherkin@263
   490
        }
asherkin@263
   491
asherkin@263
   492
        return true;
asherkin@263
   493
    }
asherkin@263
   494
asherkin@263
   495
  private:
asherkin@263
   496
    Zone *zone_;
asherkin@263
   497
    PoolAllocator &pool_;
asherkin@263
   498
    CompileContext &cc_;
asherkin@263
   499
    TranslationUnit *unit_;
asherkin@263
   500
    SymbolEnv *env_;
asherkin@263
   501
    FunctionScope *fun_;
asherkin@263
   502
};
asherkin@263
   503
asherkin@263
   504
void
asherkin@263
   505
ke::PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
asherkin@263
   506
{
asherkin@263
   507
    AutoEnterCompileContext enter(cc, unit);
asherkin@263
   508
    NamePopulator populator(zone, cc, unit);
asherkin@263
   509
    populator.analyze();
asherkin@263
   510
}
asherkin@263
   511
asherkin@263
   512
static const int INFER_ARRAY_SIZE = 0;
asherkin@263
   513
static const int EVAL_ARRAY_SIZE = -1;
asherkin@263
   514
static const int DYNAMIC_ARRAY_SIZE = -2;
asherkin@263
   515
asherkin@263
   516
class NameBinderBase : public AstVisitor
asherkin@263
   517
{
asherkin@263
   518
  public:
asherkin@263
   519
    NameBinderBase(Zone *zone, CompileContext &cc, TranslationUnit *unit)
asherkin@263
   520
      : zone_(zone),
asherkin@263
   521
        pool_(zone->pool()),
asherkin@263
   522
        cc_(cc),
asherkin@263
   523
        unit_(unit)
asherkin@263
   524
    {
asherkin@263
   525
    }
asherkin@263
   526
asherkin@263
   527
  protected:
asherkin@263
   528
    Type *buildVariableType(VariableDeclaration *node) {
asherkin@263
   529
        Local<Type> type(zone_, bindType(node->type(), node->quals()));
asherkin@263
   530
        if (!type)
asherkin@263
   531
            return NULL;
asherkin@263
   532
asherkin@263
   533
        // We don't allow array typedefs yet.
asherkin@263
   534
        assert(!type->isArray());
asherkin@263
   535
asherkin@263
   536
        if (node->dims()) {
asherkin@263
   537
            int dims[MAX_ARRAY_DEPTH];
asherkin@263
   538
            int levels = evaluateDimensions(node->pos(), type, node->dims(), dims);
asherkin@263
   539
            if (levels < 0)
asherkin@263
   540
                return NULL;
asherkin@263
   541
asherkin@263
   542
            // Do some extra inference based on the initializer, if present.
asherkin@263
   543
            Expression *init = node->initialization();
asherkin@263
   544
            if (init) {
asherkin@263
   545
                if (init->isArrayLiteral() && init->toArrayLiteral()->isFixed()) {
asherkin@263
   546
                    Local<Type> contained(zone_, type->isArray()
asherkin@263
   547
                                                 ? ArrayType::cast(type)->contained()
asherkin@263
   548
                                                 : type);
asherkin@263
   549
                    if (!inferFixedArrayDimensions(init->toArrayLiteral(), contained, dims, levels))
asherkin@263
   550
                        return NULL;
asherkin@263
   551
                } else if (init->isStringLiteral()) {
asherkin@263
   552
                    dims[levels - 1] = init->toStringLiteral()->string()->length() + 1;
asherkin@263
   553
                }
asherkin@263
   554
            }
asherkin@263
   555
asherkin@263
   556
            // If we got extra dimensions, we need to build a new type.
asherkin@263
   557
            if (node->dims()) {
asherkin@263
   558
                if ((type = buildArrayType(type, node->quals(), dims, node->dims()->length())) == NULL)
asherkin@263
   559
                    return NULL;
asherkin@263
   560
            }
asherkin@263
   561
        }
asherkin@263
   562
asherkin@263
   563
        return type;
asherkin@263
   564
    }
asherkin@263
   565
asherkin@263
   566
    int evaluateDimensions(const SourcePosition &pos, Handle<Type> typeArg, ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]) {
asherkin@263
   567
        unsigned level = 0;
asherkin@263
   568
        Local<Type> type(zone_, typeArg);
asherkin@263
   569
        while (type->isArray()) {
asherkin@263
   570
            ArrayType *atype = ArrayType::cast(type);
asherkin@263
   571
            dims[level] = atype->isFixedLength()
asherkin@263
   572
                          ? atype->fixedLength()
asherkin@263
   573
                          : DYNAMIC_ARRAY_SIZE;
asherkin@263
   574
            type = atype->contained();
asherkin@263
   575
            level++;
asherkin@263
   576
        }
asherkin@263
   577
asherkin@263
   578
        if (!exprs)
asherkin@263
   579
            return level;
asherkin@263
   580
asherkin@263
   581
        if (level + exprs->length() > MAX_ARRAY_DEPTH) {
asherkin@263
   582
            cc_.reportError(pos, Message_MaximumArrayDepth);
asherkin@263
   583
            return -1;
asherkin@263
   584
        }
asherkin@263
   585
asherkin@263
   586
        bool hadEmptySize = false;
asherkin@263
   587
        for (size_t i = 0; i < exprs->length(); i++) {
asherkin@263
   588
            Expression *expr = exprs->at(i);
asherkin@263
   589
            if (!expr) {
asherkin@263
   590
                dims[i] = INFER_ARRAY_SIZE;
asherkin@263
   591
                hadEmptySize = true;
asherkin@263
   592
                continue;
asherkin@263
   593
            }
asherkin@263
   594
asherkin@263
   595
            BoxedPrimitive box;
asherkin@263
   596
            if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
asherkin@263
   597
                int size = box.toInt();
asherkin@263
   598
                if (size <= 0) {
asherkin@263
   599
                    cc_.reportError(expr->pos(), Message_BadArraySize);
asherkin@263
   600
                    return false;
asherkin@263
   601
                }
asherkin@263
   602
asherkin@263
   603
                dims[i] = size;
asherkin@263
   604
                continue;
asherkin@263
   605
            }
asherkin@263
   606
asherkin@263
   607
            if (hadEmptySize) {
asherkin@263
   608
                cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
asherkin@263
   609
                return false;
asherkin@263
   610
            }
asherkin@263
   611
asherkin@263
   612
            dims[i] = EVAL_ARRAY_SIZE;
asherkin@263
   613
        }
asherkin@263
   614
asherkin@263
   615
        return level + exprs->length();
asherkin@263
   616
    }
asherkin@263
   617
asherkin@263
   618
    // This function computes missing dimension sizes based on a literal
asherkin@263
   619
    // initializer. We don't really handle any size rules here; we just
asherkin@263
   620
    // do a really dumb inference.
asherkin@263
   621
    bool inferFixedArrayDimensions(ArrayLiteral *lit, Handle<Type> contained, int dims[MAX_ARRAY_DEPTH], int levels) {
asherkin@263
   622
        for (int i = 0; i < levels; i++) {
asherkin@263
   623
            if (dims[i] == EVAL_ARRAY_SIZE || dims[i] == DYNAMIC_ARRAY_SIZE) {
asherkin@263
   624
                // The following are invalid:
asherkin@263
   625
                //   new x[<expr>] = {...}
asherkin@263
   626
                //   new Type:x = {...}  // where Type is a non-fixed array type
asherkin@263
   627
                cc_.reportError(lit->pos(), Message_CannotInitializeEvalArray);
asherkin@263
   628
                return false;
asherkin@263
   629
            }
asherkin@263
   630
asherkin@263
   631
            if (dims[i] == INFER_ARRAY_SIZE) {
asherkin@263
   632
                // Character arrays are always dynamic when inferred from string literals.
asherkin@263
   633
                if (i == levels - 1 && contained->isChar())
asherkin@263
   634
                    dims[i] = DYNAMIC_ARRAY_SIZE;
asherkin@263
   635
                else
asherkin@263
   636
                    dims[i] = lit->expressions()->length();
asherkin@263
   637
            }
asherkin@263
   638
asherkin@263
   639
            if (i != levels - 1) {
asherkin@263
   640
                // Fixed array literals are guaranteed to have at least one expression.
asherkin@263
   641
                Expression *next = lit->expressions()->at(0);
asherkin@263
   642
                if (!next->isArrayLiteral()) {
asherkin@263
   643
                    // Whelp... this array is just malformed. Not the best error message
asherkin@263
   644
                    // but whatever.
asherkin@263
   645
                    cc_.reportError(next->pos(), Message_ArraySizeCannotBeDetermined);
asherkin@263
   646
                    return false;
asherkin@263
   647
                }
asherkin@263
   648
                lit = next->toArrayLiteral();
asherkin@263
   649
            }
asherkin@263
   650
        }
asherkin@263
   651
asherkin@263
   652
        return true;
asherkin@263
   653
    }
asherkin@263
   654
asherkin@263
   655
    ArrayType *buildArrayType(Handle<Type> contained, TypeQualifiers quals, int dims[MAX_ARRAY_DEPTH], size_t postlevels) {
asherkin@263
   656
        Local<Type> type(zone_, contained);
asherkin@263
   657
asherkin@265
   658
        for (size_t i = postlevels; i > 0; --i) {
asherkin@265
   659
            int size = dims[i - 1] > 0
asherkin@265
   660
                       ? dims[i - 1]
asherkin@263
   661
                       : ArrayType::DYNAMIC_ARRAY_SIZE;
asherkin@263
   662
            
asherkin@265
   663
            if ((type = zone_->types()->newArray(type, size)) == NULL)
asherkin@263
   664
                return NULL;
asherkin@263
   665
            if ((type = zone_->types()->qualify(type, quals)) == NULL)
asherkin@263
   666
                return NULL;
asherkin@263
   667
        }
asherkin@263
   668
        return ArrayType::cast(type);
asherkin@263
   669
    }
asherkin@263
   670
asherkin@263
   671
    bool fillFunctionType(Handle<FunctionType> fun, const FunctionSignature &sig) {
asherkin@263
   672
        Local<Type> type(zone_);
asherkin@263
   673
        if (!fun->returnType()) {
asherkin@263
   674
            if ((type = bindType(sig.returnType(), TypeQual_None)) == NULL)
asherkin@263
   675
                return false;
asherkin@263
   676
            fun->setReturnType(type);
asherkin@263
   677
        }
asherkin@263
   678
asherkin@263
   679
        if (sig.variadic())
asherkin@263
   680
            fun->setVariadic();
asherkin@263
   681
asherkin@263
   682
        Local<FixedArray> params(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
asherkin@263
   683
        if (!params)
asherkin@263
   684
            return false;
asherkin@263
   685
asherkin@263
   686
        for (size_t i = 0; i < sig.parameters()->length(); i++) {
asherkin@263
   687
            Parameter *param = sig.parameters()->at(i);
asherkin@263
   688
            if ((type = bindType(param->type(), param->quals())) == NULL)
asherkin@263
   689
                return false;
asherkin@263
   690
asherkin@263
   691
            assert(!type->isArray());
asherkin@263
   692
asherkin@263
   693
            if (param->dims()) {
asherkin@263
   694
                int dims[MAX_ARRAY_DEPTH];
asherkin@263
   695
                int levels = evaluateDimensions(param->pos(), type, param->dims(), dims);
asherkin@263
   696
                if (levels < 0)
asherkin@263
   697
                    return false;
asherkin@263
   698
asherkin@263
   699
                // If we got extra dimensions, we need to build a new type.
asherkin@263
   700
                // Unlike variables, we do not infer anything about array
asherkin@263
   701
                // sizes from its default initializer.
asherkin@263
   702
                if (param->dims()) {
asherkin@263
   703
                    if ((type = buildArrayType(type, param->quals(), dims, param->dims()->length())) == NULL)
asherkin@263
   704
                        return false;
asherkin@263
   705
                }
asherkin@263
   706
asherkin@263
   707
                if (ArrayType::cast(type)->innermost()->isVoid()) {
asherkin@263
   708
                    cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid);
asherkin@263
   709
                    return false;
asherkin@263
   710
                }
asherkin@263
   711
            }
asherkin@263
   712
asherkin@263
   713
            if (param->reference()) {
asherkin@263
   714
                if (!type->isPod()) {
asherkin@263
   715
                    cc_.reportError(param->pos(), Message_ArrayCantBeReference);
asherkin@263
   716
                    return false;
asherkin@263
   717
                }
asherkin@263
   718
                if (param->quals() & TypeQual_Const) {
asherkin@263
   719
                    cc_.reportError(param->pos(), Message_CannotConstReference);
asherkin@263
   720
                    return false;
asherkin@263
   721
                }
asherkin@263
   722
                if ((type = zone_->types()->getReference(type, false)) == NULL)
asherkin@263
   723
                    return false;
asherkin@263
   724
            }
asherkin@263
   725
            if (param->quals() & TypeQual_Const) {
asherkin@263
   726
                if (!type->isArray() && !type->isStruct()) {
asherkin@263
   727
                    cc_.reportError(param->pos(), Message_InvalidConstOnFormal);
asherkin@263
   728
                    return false;
asherkin@263
   729
                }
asherkin@263
   730
            }
asherkin@263
   731
asherkin@263
   732
            if (type->isVoid()) {
asherkin@263
   733
                cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid);
asherkin@263
   734
                return false;
asherkin@263
   735
            }
asherkin@263
   736
asherkin@263
   737
            params->set(zone_, i, type);
asherkin@263
   738
            param->sym()->setType(type);
asherkin@263
   739
        }
asherkin@263
   740
asherkin@263
   741
        fun->setParameterTypes(params);
asherkin@263
   742
asherkin@263
   743
        return true;
asherkin@263
   744
    }
asherkin@263
   745
asherkin@263
   746
    Type *bindType(Expression *expr, TypeQualifiers quals) {
asherkin@263
   747
        Local<Type> type(zone_);
asherkin@263
   748
asherkin@263
   749
        if (!expr) {
asherkin@263
   750
            // If no type was declared, we return int32.
asherkin@263
   751
            type = zone_->types()->getPrimitive(PrimitiveType_Int32);
asherkin@263
   752
        } else {
asherkin@263
   753
            expr->accept(this);
asherkin@263
   754
asherkin@263
   755
            NameProxy *proxy = expr->asNameProxy();
asherkin@263
   756
            assert(proxy);
asherkin@263
   757
asherkin@263
   758
            Symbol *sym = proxy->sym();
asherkin@263
   759
            if (!sym)
asherkin@263
   760
                return NULL;
asherkin@263
   761
asherkin@263
   762
            if (!sym->isType()) {
asherkin@263
   763
                cc_.reportError(expr->pos(), Message_IdentifierIsNotAType, sym->name()->chars());
asherkin@263
   764
                return NULL;
asherkin@263
   765
            }
asherkin@263
   766
asherkin@263
   767
            type = sym->toType()->effective();
asherkin@263
   768
        }
asherkin@263
   769
asherkin@263
   770
        return zone_->types()->qualify(type, quals);
asherkin@263
   771
    }
asherkin@263
   772
asherkin@263
   773
  protected:
asherkin@263
   774
    Zone *zone_;
asherkin@263
   775
    PoolAllocator &pool_;
asherkin@263
   776
    CompileContext &cc_;
asherkin@263
   777
    TranslationUnit *unit_;
asherkin@263
   778
};
asherkin@263
   779
asherkin@263
   780
class GlobalBuilder : public NameBinderBase
asherkin@263
   781
{
asherkin@263
   782
    typedef ScopedRoot<Descriptor> ScopedDescriptor;
asherkin@263
   783
    struct PrimitiveFill {
asherkin@263
   784
        ScopedDescriptor *desc;
asherkin@263
   785
        BoxedPrimitive prim;
asherkin@263
   786
asherkin@263
   787
        PrimitiveFill(ScopedDescriptor *desc, BoxedPrimitive prim)
asherkin@263
   788
          : desc(desc),
asherkin@263
   789
            prim(prim)
asherkin@263
   790
        {
asherkin@263
   791
        }
asherkin@263
   792
    };
asherkin@263
   793
asherkin@263
   794
  public:
asherkin@263
   795
    GlobalBuilder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
asherkin@263
   796
      : NameBinderBase(zone, cc, unit),
asherkin@263
   797
        globalScope_(unit->globalScope())
asherkin@263
   798
    {
asherkin@263
   799
    }
asherkin@263
   800
asherkin@263
   801
    Struct *build() {
asherkin@263
   802
        for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
asherkin@263
   803
            unit_->tree()->imports()->at(i)->accept(this);
asherkin@263
   804
asherkin@263
   805
        // Next, enter the global scope and walk all statements.
asherkin@263
   806
        for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
asherkin@263
   807
            Statement *stmt = unit_->tree()->statements()->at(i);
asherkin@263
   808
            stmt->accept(this);
asherkin@263
   809
        }
asherkin@263
   810
asherkin@263
   811
        Local<Struct> globals(zone_, createGlobals());
asherkin@263
   812
        if (!globals)
asherkin@263
   813
            return NULL;
asherkin@263
   814
asherkin@263
   815
        populate(globals);
asherkin@263
   816
asherkin@263
   817
        return globals;
asherkin@263
   818
    }
asherkin@263
   819
asherkin@263
   820
  private:
asherkin@263
   821
    Struct *createGlobals() {
asherkin@263
   822
        Local<FixedArray> descs(zone_, FixedArray::New(zone_, descriptors_.length(), Heap::Tenure_Old));
asherkin@263
   823
        if (!descs)
asherkin@263
   824
            return NULL;
asherkin@263
   825
asherkin@263
   826
        for (unsigned i = 0; i < descriptors_.length(); i++)
asherkin@263
   827
            descs->set(zone_, i, *descriptors_[i]);
asherkin@263
   828
asherkin@263
   829
        Local<String> name(zone_, unit_->module()->name());
asherkin@263
   830
        Local<StructType> type(zone_, StructType::New(zone_, name, descs));
asherkin@263
   831
        if (!type)
asherkin@263
   832
            return NULL;
asherkin@263
   833
asherkin@263
   834
        Local<StructMap> map(zone_, type->newMap());
asherkin@263
   835
        return Struct::New(zone_, map, Heap::Tenure_Old);
asherkin@263
   836
    }
asherkin@263
   837
asherkin@263
   838
    void populate(Handle<Struct> globals) {
asherkin@263
   839
        // This is a huge hack, but it's probably better than a full extra
asherkin@263
   840
        // pass. The problem is that until we have all the descriptors, we
asherkin@263
   841
        // can't start setting constexprs in the struct, and we need to set
asherkin@263
   842
        // them now so they're available during full semantic analysis. To
asherkin@263
   843
        // work around this, we build up the list of values we need to set
asherkin@263
   844
        // as we build up descriptors, and then populate the global struct
asherkin@263
   845
        // with this set.
asherkin@263
   846
        //
asherkin@263
   847
        // Note, this code is also kind of dead until we support linking. We
asherkin@263
   848
        // handle constexprs explicitly in importFrom(), by sniffing out the
asherkin@263
   849
        // symbol type. That code will go away later.
asherkin@263
   850
        for (size_t i = 0; i < primitiveFills_.length(); i++) {
asherkin@263
   851
            const PrimitiveFill &fill = primitiveFills_[i];
asherkin@263
   852
            assert(fill.prim.type() == PrimitiveType_Int32);
asherkin@263
   853
            globals->set(*fill.desc, fill.prim.toInt());
asherkin@263
   854
        }
asherkin@263
   855
    }
asherkin@263
   856
asherkin@263
   857
  public:
asherkin@263
   858
    void visitEnumStatement(EnumStatement *stmt) {
asherkin@263
   859
        if (stmt->visibility() != TOK_PUBLIC || !stmt->name())
asherkin@263
   860
            return;
asherkin@263
   861
asherkin@263
   862
        Local<Type> type(zone_, zone_->types()->getType());
asherkin@263
   863
        Descriptor *desc = Descriptor::New(zone_, stmt->name(), type, Descriptor::Public);
asherkin@263
   864
        if (!desc)
asherkin@263
   865
            return;
asherkin@263
   866
        if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
asherkin@263
   867
            return;
asherkin@263
   868
asherkin@263
   869
        for (size_t i = 0; i < stmt->entries()->length(); i++) {
asherkin@263
   870
            EnumStatement::Entry &e = stmt->entries()->at(i);
asherkin@263
   871
            ScopedDescriptor *desc = new (pool_) ScopedDescriptor(Descriptor::New(zone_, e.name, e.sym->type(), Descriptor::Public));
asherkin@263
   872
            if (!desc || !descriptors_.append(desc))
asherkin@263
   873
                return;
asherkin@263
   874
asherkin@263
   875
            // Save the value so we can export it immediately.
asherkin@263
   876
            if (!primitiveFills_.append(PrimitiveFill(desc, e.sym->value())))
asherkin@263
   877
                return;
asherkin@263
   878
        }
asherkin@263
   879
    }
asherkin@263
   880
asherkin@263
   881
    void visitNameProxy(NameProxy *proxy) {
asherkin@263
   882
        Scope *scope = unit_->globalScope();
asherkin@263
   883
        Symbol *sym = scope->lookup(proxy->name());
asherkin@263
   884
        if (!sym)
asherkin@263
   885
            cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
asherkin@263
   886
        proxy->bind(sym);
asherkin@263
   887
    }
asherkin@263
   888
asherkin@263
   889
    void visitFunctionStatement(FunctionStatement *node) {
asherkin@263
   890
        Local<FunctionType> type(zone_, node->sym()->type());
asherkin@263
   891
        if (!fillFunctionType(type, node->signature()))
asherkin@263
   892
            return;
asherkin@263
   893
asherkin@263
   894
        unsigned offset;
asherkin@263
   895
        if (!builder_.add(type, &offset))
asherkin@263
   896
            return;
asherkin@263
   897
asherkin@263
   898
        Descriptor::Visibility visibility = (node->token() == TOK_NATIVE || node->token() == TOK_FORWARD)
asherkin@263
   899
                                            ? Descriptor::Public
asherkin@263
   900
                                            : Descriptor::Private;
asherkin@263
   901
asherkin@263
   902
        Descriptor *desc = Descriptor::New(zone_, node->name(), type, visibility);
asherkin@263
   903
        if (!desc)
asherkin@263
   904
            return;
asherkin@263
   905
        if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
asherkin@263
   906
            return;
asherkin@263
   907
    }
asherkin@263
   908
asherkin@263
   909
    void visitVariableDeclaration(VariableDeclaration *node) {
asherkin@263
   910
        Local<Type> type(zone_, buildVariableType(node));
asherkin@263
   911
        if (!type)
asherkin@263
   912
            return;
asherkin@263
   913
asherkin@263
   914
        // If we're in global scope, and we received a |const| qualifier, then
asherkin@263
   915
        // we extend this to array references as well. This is to sort of mimic
asherkin@263
   916
        // SP1 functionality, but also means that you cannot have changeable
asherkin@263
   917
        // const pointers in global scope.
asherkin@263
   918
        if ((node->quals() & TypeQual_Const) && type->isArray()) {
asherkin@263
   919
            if ((type = zone_->types()->qualify(type, TypeQual_Const)) == NULL)
asherkin@263
   920
                return;
asherkin@263
   921
        }
asherkin@263
   922
asherkin@263
   923
        node->sym()->setType(type);
asherkin@263
   924
asherkin@263
   925
        unsigned offset;
asherkin@263
   926
        if (!builder_.add(type, &offset))
asherkin@263
   927
            return;
asherkin@263
   928
asherkin@263
   929
        Descriptor *desc = Descriptor::New(zone_, node->name(), type, Descriptor::Private);
asherkin@263
   930
        if (!desc)
asherkin@263
   931
            return;
asherkin@263
   932
        if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
asherkin@263
   933
            return;
asherkin@263
   934
    }
asherkin@263
   935
asherkin@263
   936
    void visitImportStatement(ImportStatement *node) {
asherkin@263
   937
        if (!node->names()) {
asherkin@263
   938
            PathComponent *path = node->path();
asherkin@263
   939
            while (path->next)
asherkin@263
   940
                path = path->next;
asherkin@263
   941
asherkin@263
   942
            // Imports automatically go into the importScope. For now, we
asherkin@263
   943
            // error if there are any duplicate symbols entered into the
asherkin@263
   944
            // importScope.
asherkin@263
   945
            if (unit_->importScope()->localLookup(path->name)) {
asherkin@263
   946
                cc_.reportError(node->pos(), Message_DuplicateImport, path->name->chars());
asherkin@263
   947
                return;
asherkin@263
   948
            }
asherkin@263
   949
asherkin@263
   950
            Local<Type> type(zone_, zone_->types()->getImportable());
asherkin@263
   951
            ImportSymbol *sym = new (pool_) ImportSymbol(unit_->importScope(), path->name, node->pos(), type, node->importIndex());
asherkin@263
   952
            if (!unit_->importScope()->addSymbol(sym))
asherkin@263
   953
                return;
asherkin@263
   954
        } else if (node->importAllNames()) {
asherkin@263
   955
            Local<Importable> importable(zone_, unit_->module()->getImportAt(node->importIndex()));
asherkin@263
   956
            if (importable->isPackage()) {
asherkin@263
   957
                assert(false);
asherkin@263
   958
            } else {
asherkin@263
   959
                Local<Module> module(zone_, Module::cast(importable));
asherkin@263
   960
                if (!module->globals())
asherkin@263
   961
                    importAllFromTranslationUnit(node, module->translationUnit());
asherkin@263
   962
                else
asherkin@263
   963
                    assert(false);
asherkin@263
   964
            }
asherkin@263
   965
        } else {
asherkin@263
   966
            Local<Importable> importable(zone_, unit_->module()->getImportAt(node->importIndex()));
asherkin@263
   967
            if (importable->isPackage()) {
asherkin@263
   968
                assert(false);
asherkin@263
   969
            } else {
asherkin@263
   970
                Local<Module> module(zone_, Module::cast(importable));
asherkin@263
   971
asherkin@263
   972
                // Always grab from the translation unit if we can, for now.
asherkin@263
   973
                if (module->translationUnit())
asherkin@263
   974
                    importFromTranslationUnit(node, module->translationUnit());
asherkin@263
   975
                else
asherkin@263
   976
                    assert(false);
asherkin@263
   977
            }
asherkin@263
   978
        }
asherkin@263
   979
    }
asherkin@263
   980
asherkin@263
   981
  private:
asherkin@263
   982
    bool importFrom(ImportStatement *node, Symbol *import) {
asherkin@263
   983
        assert(import->type());
asherkin@263
   984
asherkin@263
   985
        // Check for duplicate import names.
asherkin@263
   986
        if (unit_->importScope()->localLookup(import->name())) {
asherkin@263
   987
            cc_.reportError(node->pos(), Message_DuplicateImport, import->name()->chars());
asherkin@263
   988
            return false;
asherkin@263
   989
        }
asherkin@263
   990
asherkin@263
   991
        Symbol *sym;
asherkin@263
   992
        if (import->isType()) {
asherkin@263
   993
            // Fuck it, make a TypeSymbol instead of an ImplicitSymbol. This
asherkin@263
   994
            // makes bindType() much simpler. We may run into problems
asherkin@263
   995
            // implementing linking, but it seems unlikely, as long as we are
asherkin@263
   996
            // exporting Types in module structs.
asherkin@263
   997
            Local<Type> type(zone_, zone_->types()->getType());
asherkin@263
   998
            sym = new (pool_) TypeSymbol(unit_->importScope(),
asherkin@263
   999
                                         import->name(),
asherkin@263
  1000
                                         type,
asherkin@263
  1001
                                         import->toType()->effective());
asherkin@263
  1002
        } else if (import->isConstant()) {
asherkin@263
  1003
            // Same deal. No reason to lookup in the module globals if we
asherkin@263
  1004
            // already have a symbol.
asherkin@263
  1005
            sym = new (pool_) ConstantSymbol(unit_->importScope(),
asherkin@263
  1006
                                             import->name(),
asherkin@263
  1007
                                             node->pos(),
asherkin@263
  1008
                                             import->type(),
asherkin@263
  1009
                                             import->toConstant()->value());
asherkin@263
  1010
        } else {
asherkin@263
  1011
            sym = new (pool_) ImplicitSymbol(unit_->importScope(),
asherkin@263
  1012
                                             import->name(),
asherkin@263
  1013
                                             node->pos(),
asherkin@263
  1014
                                             import->type(),
asherkin@263
  1015
                                             node->importIndex());
asherkin@263
  1016
        }
asherkin@263
  1017
asherkin@263
  1018
        if (!unit_->importScope()->addSymbol(sym))
asherkin@263
  1019
            return false;
asherkin@263
  1020
asherkin@263
  1021
        return true;
asherkin@263
  1022
    }
asherkin@263
  1023
asherkin@263
  1024
    void importFromTranslationUnit(ImportStatement *node, TranslationUnit *other) {
asherkin@263
  1025
        assert(!other->failed());
asherkin@263
  1026
asherkin@263
  1027
        for (size_t i = 0; i < node->names()->length(); i++) {
asherkin@263
  1028
            Handle<String> name = *node->names()->at(i);
asherkin@263
  1029
asherkin@263
  1030
            // See if the name exists in the other translation unit.
asherkin@263
  1031
            Symbol *import = other->globalScope()->findExported(name);
asherkin@263
  1032
            if (!import) {
asherkin@263
  1033
                FixedArray *path = unit_->module()->importPathAt(node->importIndex());
asherkin@263
  1034
                cc_.reportError(node->pos(), Message_NotFoundInImportable,
asherkin@263
  1035
                                name->chars(),
asherkin@263
  1036
                                String::cast(path->at(path->length() - 1))->chars());
asherkin@263
  1037
                return;
asherkin@263
  1038
            }
asherkin@263
  1039
asherkin@263
  1040
            if (!importFrom(node, import))
asherkin@263
  1041
                return;
asherkin@263
  1042
        }
asherkin@263
  1043
    }
asherkin@263
  1044
asherkin@263
  1045
    void importAllFromTranslationUnit(ImportStatement *node, TranslationUnit *other) {
asherkin@263
  1046
        assert(!other->failed());
asherkin@263
  1047
asherkin@263
  1048
        for (size_t i = 0; i < other->globalScope()->exported()->length(); i++) {
asherkin@263
  1049
            Symbol *import = other->globalScope()->exported()->at(i);
asherkin@263
  1050
            if (!importFrom(node, import))
asherkin@263
  1051
                return;
asherkin@263
  1052
        }
asherkin@263
  1053
    }
asherkin@263
  1054
asherkin@263
  1055
  private:
asherkin@263
  1056
    StructureBufferBuilder builder_;
asherkin@263
  1057
    Vector<ScopedRoot<Descriptor> *> descriptors_;
asherkin@263
  1058
    GlobalScope *globalScope_;
asherkin@263
  1059
    Vector<PrimitiveFill> primitiveFills_;
asherkin@263
  1060
};
asherkin@263
  1061
    
asherkin@263
  1062
class NameBinder : public NameBinderBase
asherkin@263
  1063
{
asherkin@263
  1064
  public:
asherkin@263
  1065
    class AutoLinkScope
asherkin@263
  1066
    {
asherkin@263
  1067
      public:
asherkin@263
  1068
        AutoLinkScope(AutoLinkScope **prevp, Scope *scope)
asherkin@263
  1069
          : prevp_(prevp),
asherkin@263
  1070
            prev_(*prevp),
asherkin@263
  1071
            scope_(scope)
asherkin@263
  1072
        {
asherkin@263
  1073
            if (scope_) {
asherkin@263
  1074
                *prevp_ = this;
asherkin@263
  1075
                if (prev_)
asherkin@263
  1076
                    scope_->setParent(prev_->scope());
asherkin@263
  1077
            }
asherkin@263
  1078
        }
asherkin@263
  1079
        ~AutoLinkScope() {
asherkin@263
  1080
            if (scope_) {
asherkin@263
  1081
                assert(*prevp_ == this);
asherkin@263
  1082
                *prevp_ = prev_;
asherkin@263
  1083
            }
asherkin@263
  1084
        }
asherkin@263
  1085
        Scope *scope() const {
asherkin@263
  1086
            return scope_;
asherkin@263
  1087
        }
asherkin@263
  1088
asherkin@263
  1089
      private:
asherkin@263
  1090
        AutoLinkScope **prevp_;
asherkin@263
  1091
        AutoLinkScope *prev_;
asherkin@263
  1092
        Scope *scope_;
asherkin@263
  1093
    };
asherkin@263
  1094
asherkin@263
  1095
  public:
asherkin@263
  1096
    NameBinder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
asherkin@263
  1097
      : NameBinderBase(zone, cc, unit),
asherkin@263
  1098
        link_(NULL)
asherkin@263
  1099
    {
asherkin@263
  1100
    }
asherkin@263
  1101
asherkin@263
  1102
    void bind() {
asherkin@263
  1103
        // Start with the import scope, and collect all imported names.
asherkin@263
  1104
        AutoLinkScope importScope(&link_, unit_->importScope());
asherkin@263
  1105
asherkin@263
  1106
        for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
asherkin@263
  1107
            unit_->tree()->imports()->at(i)->accept(this);
asherkin@263
  1108
asherkin@263
  1109
        // Next, enter the global scope and walk all statements.
asherkin@263
  1110
        AutoLinkScope globalScope(&link_, unit_->globalScope());
asherkin@263
  1111
        for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
asherkin@263
  1112
            Statement *stmt = unit_->tree()->statements()->at(i);
asherkin@263
  1113
            stmt->accept(this);
asherkin@263
  1114
        }
asherkin@263
  1115
    }
asherkin@263
  1116
asherkin@263
  1117
    void visitVariableDeclaration(VariableDeclaration *node) {
asherkin@263
  1118
        // Bind the initializer before registering the declaration, so that we
asherkin@263
  1119
        // can error on bogus initializers (new x = x).
asherkin@263
  1120
        if (node->initialization())
asherkin@263
  1121
            node->initialization()->accept(this);
asherkin@263
  1122
asherkin@263
  1123
        // If the node already has a symbol (meaning it was a global), then
asherkin@263
  1124
        // we don't have to do anything more.
asherkin@263
  1125
        if (node->sym())
asherkin@263
  1126
            return;
asherkin@263
  1127
asherkin@263
  1128
        Local<Type> type(zone_, buildVariableType(node));
asherkin@263
  1129
        if (!type)
asherkin@263
  1130
            return;
asherkin@263
  1131
asherkin@263
  1132
        VariableSymbol *sym = new (pool_) VariableSymbol(link_->scope(), node->name(), node->pos(), type);
asherkin@263
  1133
        node->setSymbol(sym);
asherkin@263
  1134
       
asherkin@263
  1135
        if (Symbol *other = link_->scope()->localLookup(sym->name())) {
asherkin@263
  1136
            // Report, but allow errors to continue.
asherkin@263
  1137
            cc_.reportError(sym->pos(), Message_RedeclaredName,
asherkin@263
  1138
                            sym->name()->chars(),
asherkin@263
  1139
                            other->pos().line,
asherkin@263
  1140
                            other->pos().col);
asherkin@263
  1141
            return;
asherkin@263
  1142
        }
asherkin@263
  1143
        
asherkin@263
  1144
        link_->scope()->addSymbol(sym);
asherkin@263
  1145
    }
asherkin@263
  1146
    void visitEnumStatement(EnumStatement *node) {
asherkin@263
  1147
    }
asherkin@263
  1148
    void visitFunctionStatement(FunctionStatement *node) {
asherkin@263
  1149
        AutoLinkScope argScope(&link_, node->argScope());
asherkin@263
  1150
        AutoLinkScope varScope(&link_, node->varScope());
asherkin@263
  1151
asherkin@263
  1152
        // If the function is in the global scope, we've already computed its
asherkin@263
  1153
        // type.
asherkin@263
  1154
        if (node->sym()->scope()->kind() != Scope::GLOBAL) {
asherkin@263
  1155
            Local<FunctionType> type(zone_, node->sym()->type());
asherkin@263
  1156
            if (!fillFunctionType(type, node->signature()))
asherkin@263
  1157
                return;
asherkin@263
  1158
        }
asherkin@263
  1159
asherkin@263
  1160
        if (node->body())
asherkin@263
  1161
            node->body()->accept(this);
asherkin@263
  1162
    }
asherkin@263
  1163
    void visitStructureStatement(StructureStatement *node) {
asherkin@263
  1164
        assert(false);
asherkin@263
  1165
    }
asherkin@263
  1166
    void visitFunctionTypeStatement(FunctionTypeStatement *node) {
asherkin@263
  1167
        assert(false);
asherkin@263
  1168
    }
asherkin@263
  1169
asherkin@263
  1170
    void visitNameProxy(NameProxy *proxy) {
asherkin@263
  1171
        // We could have already bound globals.
asherkin@263
  1172
        if (proxy->sym())
asherkin@263
  1173
            return;
asherkin@263
  1174
asherkin@263
  1175
        Scope *scope = link_->scope();
asherkin@263
  1176
        Symbol *sym = scope->lookup(proxy->name());
asherkin@263
  1177
        if (!sym)
asherkin@263
  1178
            cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
asherkin@263
  1179
        proxy->bind(sym);
asherkin@263
  1180
    }
asherkin@263
  1181
    void visitAssignment(Assignment *node) {
asherkin@263
  1182
        node->lvalue()->accept(this);
asherkin@263
  1183
        node->expression()->accept(this);
asherkin@263
  1184
    }
asherkin@263
  1185
    void visitBinaryExpression(BinaryExpression *node) {
asherkin@263
  1186
        node->left()->accept(this);
asherkin@263
  1187
        node->right()->accept(this);
asherkin@263
  1188
    }
asherkin@263
  1189
    void visitReturnStatement(ReturnStatement *node) {
asherkin@263
  1190
        node->expression()->accept(this);
asherkin@263
  1191
    }
asherkin@263
  1192
    void visitForStatement(ForStatement *node) {
asherkin@263
  1193
        AutoLinkScope scope(&link_, node->scope());
asherkin@263
  1194
asherkin@263
  1195
        if (node->initialization())
asherkin@263
  1196
            node->initialization()->accept(this);
asherkin@263
  1197
        if (node->condition())
asherkin@263
  1198
            node->condition()->accept(this);
asherkin@263
  1199
        if (node->update())
asherkin@263
  1200
            node->update()->accept(this);
asherkin@263
  1201
        node->body()->accept(this);
asherkin@263
  1202
    }
asherkin@263
  1203
    void visitBlockStatement(BlockStatement *node) {
asherkin@263
  1204
        AutoLinkScope scope(&link_, node->scope());
asherkin@263
  1205
        for (size_t i = 0; i < node->statements()->length(); i++)
asherkin@263
  1206
            node->statements()->at(i)->accept(this);
asherkin@263
  1207
    }
asherkin@263
  1208
    void visitIntegerLiteral(IntegerLiteral *node) {
asherkin@263
  1209
    }
asherkin@263
  1210
    void visitExpressionStatement(ExpressionStatement *node) {
asherkin@263
  1211
        node->expression()->accept(this);
asherkin@263
  1212
    }
asherkin@263
  1213
    void visitCallExpression(CallExpression *node) {
asherkin@263
  1214
        node->callee()->accept(this);
asherkin@263
  1215
        for (size_t i = 0; i < node->arguments()->length(); i++)
asherkin@263
  1216
            node->arguments()->at(i)->accept(this);
asherkin@263
  1217
    }
asherkin@263
  1218
    void visitIfStatement(IfStatement *node) {
asherkin@263
  1219
        node->condition()->accept(this);
asherkin@263
  1220
        node->ifTrue()->accept(this);
asherkin@263
  1221
        if (node->ifFalse())
asherkin@263
  1222
            node->ifFalse()->accept(this);
asherkin@263
  1223
    }
asherkin@263
  1224
    void visitIndexExpression(IndexExpression *node) {
asherkin@263
  1225
        node->left()->accept(this);
asherkin@263
  1226
        node->right()->accept(this);
asherkin@263
  1227
    }
asherkin@263
  1228
    void visitFloatLiteral(FloatLiteral *node) {
asherkin@263
  1229
    }
asherkin@263
  1230
    void visitWhileStatement(WhileStatement *node) {
asherkin@263
  1231
        node->condition()->accept(this);
asherkin@263
  1232
        node->body()->accept(this);
asherkin@263
  1233
    }
asherkin@263
  1234
    void visitBreakStatement(BreakStatement *node) {
asherkin@263
  1235
    }
asherkin@263
  1236
    void visitContinueStatement(ContinueStatement *node) {
asherkin@263
  1237
    }
asherkin@263
  1238
    void visitStringLiteral(StringLiteral *node) {
asherkin@263
  1239
    }
asherkin@263
  1240
    void visitIncDecExpression(IncDecExpression *node) {
asherkin@263
  1241
        node->expression()->accept(this);
asherkin@263
  1242
    }
asherkin@263
  1243
    void visitUnaryExpression(UnaryExpression *node) {
asherkin@263
  1244
        if (node->tag())
asherkin@263
  1245
            node->tag()->accept(this);
asherkin@263
  1246
        node->expression()->accept(this);
asherkin@263
  1247
    }
asherkin@263
  1248
    void visitTernaryExpression(TernaryExpression *node) {
asherkin@263
  1249
        node->condition()->accept(this);
asherkin@263
  1250
        node->left()->accept(this);
asherkin@263
  1251
        node->right()->accept(this);
asherkin@263
  1252
    }
asherkin@263
  1253
    void visitBooleanLiteral(BooleanLiteral *node) {
asherkin@263
  1254
    }
asherkin@263
  1255
    void visitFieldExpression(FieldExpression *node) {
asherkin@263
  1256
        node->left()->accept(this);
asherkin@263
  1257
    }
asherkin@263
  1258
    void visitSwitchStatement(SwitchStatement *node) {
asherkin@263
  1259
        node->expression()->accept(this);
asherkin@263
  1260
        node->defaultCase()->accept(this);
asherkin@263
  1261
        for (size_t i = 0; i < node->cases()->length(); i++) {
asherkin@263
  1262
            // We don't test case expressions because they are literals.
asherkin@263
  1263
            Case *c = node->cases()->at(i);
asherkin@263
  1264
            c->statement()->accept(this);
asherkin@263
  1265
        }
asherkin@263
  1266
    }
asherkin@263
  1267
    void visitArrayLiteral(ArrayLiteral *node) {
asherkin@263
  1268
        for (size_t i = 0; i < node->expressions()->length(); i++)
asherkin@263
  1269
            node->expressions()->at(i)->accept(this);
asherkin@263
  1270
    }
asherkin@263
  1271
    void visitImportStatement(ImportStatement *node) {
asherkin@263
  1272
    }
asherkin@263
  1273
asherkin@263
  1274
  private:
asherkin@263
  1275
    AutoLinkScope *link_;
asherkin@263
  1276
};
asherkin@263
  1277
asherkin@263
  1278
void
asherkin@263
  1279
ke::BindGlobals(Zone *zone, CompileContext &cc, TranslationUnit *unit)
asherkin@263
  1280
{
asherkin@263
  1281
    AutoEnterCompileContext enter(cc, unit);
asherkin@263
  1282
asherkin@263
  1283
    GlobalBuilder builder(zone, cc, unit);
asherkin@263
  1284
    Local<Struct> globals(zone, builder.build());
asherkin@263
  1285
    if (!globals || unit->failed())
asherkin@263
  1286
        return;
asherkin@263
  1287
asherkin@263
  1288
    unit->module()->setGlobals(globals);
asherkin@263
  1289
}
asherkin@263
  1290
asherkin@263
  1291
void
asherkin@263
  1292
ke::BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
asherkin@263
  1293
{
asherkin@263
  1294
    AutoEnterCompileContext enter(cc, unit);
asherkin@263
  1295
    NameBinder binder(zone, cc, unit);
asherkin@263
  1296
    binder.bind();
asherkin@263
  1297
}