jitcraft/SemanticAnalysis.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jun 30 22:45:25 2012 -0700 (2012-06-30)
changeset 16 23627f8bc421
parent 14 0784ac5cc347
child 17 8aa89dd41e25
permissions -rw-r--r--
Added support for arbitrary expression references.
dvander@0
     1
/*
dvander@0
     2
 * Copyright (C) 2012 David Anderson
dvander@0
     3
 *
dvander@0
     4
 * This file is part of JITCraft.
dvander@0
     5
 *
dvander@0
     6
 * JITCraft is free software: you can redistribute it and/or modify it under
dvander@0
     7
 * the terms of the GNU General Public License as published by the Free
dvander@0
     8
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@0
     9
 * any later version.
dvander@0
    10
 * 
dvander@0
    11
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@0
    12
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@0
    13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@0
    14
 *
dvander@0
    15
 * You should have received a copy of the GNU General Public License along with
dvander@0
    16
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@0
    17
 */
dvander@0
    18
#include "SemanticAnalysis.h"
dvander@0
    19
#include "Types.h"
dvander@11
    20
#include "Zone.h"
dvander@11
    21
#include "TypeManager.h"
dvander@12
    22
#include "Scopes.h"
dvander@0
    23
dvander@0
    24
using namespace jc;
dvander@0
    25
dvander@2
    26
static inline bool
dvander@2
    27
IsPrimitiveType(Type *type, PrimitiveType primitive)
dvander@2
    28
{
dvander@2
    29
    if (!type)
dvander@2
    30
        return false;
dvander@2
    31
dvander@2
    32
    if (!type->isPrimitive())
dvander@2
    33
        return false;
dvander@2
    34
dvander@2
    35
    return primitive == type->primitive();
dvander@2
    36
}
dvander@2
    37
dvander@2
    38
static inline bool
dvander@2
    39
EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
dvander@2
    40
                        BoxedPrimitive *out)
dvander@2
    41
{
dvander@2
    42
    switch (kind) {
dvander@2
    43
      case TOK_PLUS:
dvander@2
    44
        *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
dvander@2
    45
        return true;
dvander@2
    46
dvander@2
    47
      case TOK_SHL:
dvander@2
    48
        *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
dvander@2
    49
        return true;
dvander@2
    50
    }
dvander@2
    51
dvander@2
    52
    return true;
dvander@2
    53
}
dvander@2
    54
dvander@2
    55
static bool
dvander@2
    56
EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
dvander@2
    57
{
dvander@2
    58
    switch (expression->kind()) {
dvander@2
    59
      case AstNode::kBinaryExpression:
dvander@2
    60
      {
dvander@2
    61
        BoxedPrimitive left;
dvander@2
    62
        BoxedPrimitive right;
dvander@2
    63
        BinaryExpression *b = expression->toBinaryExpression();
dvander@2
    64
        if (!EvaluateForConstant(b->left(), &left) ||
dvander@2
    65
            !EvaluateForConstant(b->right(), &right))
dvander@2
    66
        {
dvander@2
    67
            return false;
dvander@2
    68
        }
dvander@2
    69
        return EvaluateBinaryOperation(b->token(), left, right, out);
dvander@2
    70
      }
dvander@2
    71
dvander@2
    72
      case AstNode::kNameProxy:
dvander@2
    73
      {
dvander@2
    74
        NameProxy *proxy = expression->toNameProxy();
dvander@2
    75
        if (proxy->binding()->kind() != BoundName::CONSTANT)
dvander@2
    76
            return false;
dvander@2
    77
dvander@2
    78
        NamedConstant *c = proxy->binding()->toNamedConstant();
dvander@2
    79
        if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
dvander@2
    80
            return false;
dvander@2
    81
dvander@2
    82
        *out = c->value();
dvander@2
    83
        return true;
dvander@2
    84
      }
dvander@2
    85
dvander@4
    86
      case AstNode::kIntegerLiteral:
dvander@4
    87
        *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
dvander@2
    88
        return true;
dvander@2
    89
dvander@2
    90
      default:
dvander@2
    91
        return false;
dvander@2
    92
    }
dvander@2
    93
}
dvander@2
    94
dvander@0
    95
SemanticAnalysis::SemanticAnalysis(ParseTree *tree)
dvander@10
    96
  : tree_(tree),
dvander@12
    97
    loopDepth_(0),
dvander@12
    98
    scope_(NULL)
dvander@0
    99
{
dvander@0
   100
}
dvander@0
   101
dvander@0
   102
bool
dvander@0
   103
SemanticAnalysis::analyze()
dvander@0
   104
{
dvander@0
   105
    for (size_t i = 0; i < tree_->statements()->length(); i++) {
dvander@0
   106
        Statement *statement = tree_->statements()->at(i);
dvander@0
   107
        statement->accept(this);
dvander@0
   108
    }
dvander@0
   109
dvander@0
   110
    return true;
dvander@0
   111
}
dvander@0
   112
dvander@0
   113
void
dvander@0
   114
SemanticAnalysis::visit(NameProxy *name)
dvander@0
   115
{
dvander@0
   116
    name->setType(name->binding()->type());
dvander@0
   117
}
dvander@0
   118
dvander@7
   119
Type *
dvander@7
   120
SemanticAnalysis::visitForLoad(Expression *expression)
dvander@7
   121
{
dvander@7
   122
    expression->accept(this);
dvander@14
   123
    if (expression->type()) {
dvander@14
   124
        // :TODO: use Local
dvander@14
   125
        Type *type = expression->type();
dvander@14
   126
        if (type->isArray() || type->isReference())
dvander@14
   127
            expression->setType(type->contained());
dvander@14
   128
    }
dvander@7
   129
    return expression->type();
dvander@7
   130
}
dvander@7
   131
dvander@7
   132
Type *
dvander@7
   133
SemanticAnalysis::visitForRef(Expression *expression)
dvander@7
   134
{
dvander@7
   135
    expression->accept(this);
dvander@7
   136
    return expression->type();
dvander@7
   137
}
dvander@7
   138
dvander@4
   139
static inline bool
dvander@4
   140
TypeCheck(Type *left, Type *right)
dvander@4
   141
{
dvander@4
   142
    if (!left || !right)
dvander@4
   143
        return false;
dvander@4
   144
dvander@4
   145
    if (left->isPrimitive()) {
dvander@4
   146
        if (!right->isPrimitive())
dvander@4
   147
            return false;
dvander@4
   148
        return left->primitive() == right->primitive();
dvander@4
   149
    }
dvander@4
   150
dvander@4
   151
    return false;
dvander@4
   152
}
dvander@4
   153
dvander@0
   154
void
dvander@0
   155
SemanticAnalysis::visit(Assignment *node)
dvander@0
   156
{
dvander@7
   157
    visitForLoad(node->expression());
dvander@0
   158
dvander@0
   159
    if (node->lvalue()->isIndexExpression()) {
dvander@7
   160
        node->lvalue()->accept(this);
dvander@4
   161
        node->setType(node->lvalue()->type()->contained());
dvander@0
   162
    } else {
dvander@0
   163
        NameProxy *proxy = node->lvalue()->toNameProxy();
dvander@0
   164
        if (!proxy->binding()->kind() == BoundName::VARIABLE) {
dvander@0
   165
            fprintf(stderr, "error\n");
dvander@0
   166
            return;
dvander@0
   167
        }
dvander@0
   168
dvander@0
   169
        Variable *var = proxy->binding()->toVariable();
dvander@14
   170
        if  (var->type()->isReference())
dvander@14
   171
            node->setType(var->type()->contained());
dvander@14
   172
        else
dvander@14
   173
            node->setType(var->type());
dvander@0
   174
    }
dvander@4
   175
dvander@4
   176
    assert(TypeCheck(node->type(), node->expression()->type()));
dvander@0
   177
}
dvander@0
   178
dvander@4
   179
dvander@0
   180
void
dvander@0
   181
SemanticAnalysis::visit(BinaryExpression *node)
dvander@0
   182
{
dvander@7
   183
    Type *left = visitForLoad(node->left());
dvander@7
   184
    Type *right = visitForLoad(node->right());
dvander@4
   185
dvander@4
   186
    if (node->token() >= TOK_PLUS && node->token() <= TOK_SLASH) {
dvander@4
   187
        // Both sides must be primitive.
dvander@4
   188
        if (!left || !right)
dvander@4
   189
            return;
dvander@4
   190
dvander@4
   191
        // If either side is a float, the other side must be a float or int.
dvander@4
   192
        if (left->isFloat() || right->isFloat()) {
dvander@4
   193
            assert(left->isFloat() || left->isInt());
dvander@4
   194
            assert(right->isFloat() || right->isInt());
dvander@4
   195
            node->setType(left->isFloat() ? left : right);
dvander@4
   196
            return;
dvander@4
   197
        }
dvander@8
   198
    }
dvander@4
   199
dvander@8
   200
    // For now, assert everything else is integer and untagged.
dvander@8
   201
    assert(left->isInt() && right->isInt());
dvander@8
   202
    assert(!left->tag() && !right->tag());
dvander@8
   203
    node->setType(left);
dvander@0
   204
}
dvander@0
   205
dvander@0
   206
void
dvander@0
   207
SemanticAnalysis::visit(ReturnStatement *node)
dvander@0
   208
{
dvander@7
   209
    visitForLoad(node->expression());
dvander@0
   210
dvander@0
   211
    // :TODO: type check
dvander@0
   212
}
dvander@0
   213
dvander@0
   214
void
dvander@0
   215
SemanticAnalysis::visit(ForStatement *node)
dvander@0
   216
{
dvander@10
   217
    loopDepth_++;
dvander@12
   218
    if (node->scope())
dvander@12
   219
        scope_ = node->scope();
dvander@0
   220
    if (node->declaration())
dvander@0
   221
        node->declaration()->accept(this);
dvander@0
   222
    if (node->condition())
dvander@7
   223
        visitForLoad(node->condition());
dvander@0
   224
    if (node->update())
dvander@0
   225
        node->update()->accept(this);
dvander@0
   226
    node->body()->accept(this);
dvander@12
   227
    if (node->scope())
dvander@12
   228
        scope_ = scope_->enclosing();
dvander@10
   229
    loopDepth_--;
dvander@0
   230
}
dvander@0
   231
dvander@9
   232
void 
dvander@9
   233
SemanticAnalysis::visit(WhileStatement *node)
dvander@9
   234
{
dvander@10
   235
    loopDepth_++;
dvander@9
   236
    node->condition()->accept(this);
dvander@9
   237
    node->body()->accept(this);
dvander@10
   238
    loopDepth_--;
dvander@9
   239
}
dvander@9
   240
dvander@0
   241
void
dvander@0
   242
SemanticAnalysis::visit(BlockStatement *node)
dvander@0
   243
{
dvander@12
   244
    if (node->scope())
dvander@12
   245
        scope_ = node->scope();
dvander@0
   246
    for (size_t i = 0; i < node->statements()->length(); i++) {
dvander@0
   247
        Statement *statement = node->statements()->at(i);
dvander@0
   248
        statement->accept(this);
dvander@0
   249
    }
dvander@12
   250
    if (node->scope())
dvander@12
   251
        scope_ = scope_->enclosing();
dvander@0
   252
}
dvander@0
   253
dvander@0
   254
void
dvander@0
   255
SemanticAnalysis::visit(VariableDeclaration *node)
dvander@0
   256
{
dvander@14
   257
    // :TODO: use locals
dvander@11
   258
    Type *type = ZONE()->types()->getPrimitiveForTag(node->tag());
dvander@0
   259
    if (!type)
dvander@0
   260
        return;
dvander@0
   261
dvander@0
   262
    if (node->postDimensions()) {
dvander@0
   263
        if (node->postDimensions()->size() > Type::MAX_UNSAFE_ARRAY_DEPTH) {
dvander@0
   264
            error();
dvander@0
   265
            return;
dvander@0
   266
        }
dvander@0
   267
dvander@0
   268
        for (size_t i = node->postDimensions()->size() - 1; i < node->postDimensions()->size(); i--) {
dvander@0
   269
            Expression *expr = node->postDimensions()->at(i);
dvander@7
   270
            visitForLoad(expr);
dvander@0
   271
dvander@0
   272
            if (!IsPrimitiveType(expr->type(), PrimitiveType_Int32)) {
dvander@0
   273
                typeError(expr, "integer");
dvander@0
   274
                return;
dvander@0
   275
            }
dvander@0
   276
dvander@0
   277
            int size = -1;
dvander@4
   278
            if (expr->isIntegerLiteral()) {
dvander@4
   279
                size = expr->toIntegerLiteral()->value();
dvander@0
   280
                if (size <= 0) {
dvander@0
   281
                    error();
dvander@0
   282
                    return;
dvander@0
   283
                }
dvander@0
   284
                if (size >= INT_MAX / sizeof(int)) {
dvander@0
   285
                    error();
dvander@0
   286
                    return;
dvander@0
   287
                }
dvander@0
   288
            }
dvander@0
   289
dvander@11
   290
            type = ZONE()->types()->unsafeArray(type, size);
dvander@0
   291
        }
dvander@12
   292
dvander@12
   293
        // Right now, any array is allowed on the LIFO heap. In case the
dvander@12
   294
        // runtime actually decides to use the LIFO heap, we must reserve
dvander@12
   295
        // a slot so we can unwind the heap when the current scope leaves.
dvander@12
   296
        scope_->setUsesLifoHeap();
dvander@8
   297
    } else {
dvander@10
   298
        if (node->initialization()) {
dvander@10
   299
            Type *right = visitForLoad(node->initialization());
dvander@10
   300
            assert(TypeCheck(type, right));
dvander@10
   301
        }
dvander@0
   302
    }
dvander@0
   303
dvander@0
   304
    node->variable()->setType(type);
dvander@0
   305
}
dvander@0
   306
dvander@0
   307
void
dvander@4
   308
SemanticAnalysis::visit(IntegerLiteral *node)
dvander@0
   309
{
dvander@11
   310
    node->setType(ZONE()->types()->getPrimitive(PrimitiveType_Int32));
dvander@0
   311
}
dvander@0
   312
dvander@0
   313
void
dvander@0
   314
SemanticAnalysis::visit(ExpressionStatement *node)
dvander@0
   315
{
dvander@0
   316
    node->expression()->accept(this);
dvander@0
   317
}
dvander@0
   318
dvander@14
   319
bool
dvander@14
   320
SemanticAnalysis::preanalyze(FunctionStatement *node)
dvander@14
   321
{
dvander@14
   322
    // :TODO: use Local
dvander@14
   323
dvander@14
   324
    FixedArray *args = FixedArray::New(ZONE(), node->parameters()->size(), Heap::Tenure_Old);
dvander@14
   325
    if (!args)
dvander@14
   326
        return false;
dvander@14
   327
dvander@14
   328
    // Apply types to arguments.
dvander@14
   329
    for (size_t i = 0; i < node->parameters()->size(); i++) {
dvander@14
   330
        Parameter *parameter = node->parameters()->at(i);
dvander@14
   331
        
dvander@14
   332
        Type *type = ZONE()->types()->getPrimitiveForTag(parameter->tag());
dvander@14
   333
        if (!type)
dvander@14
   334
            return false;
dvander@14
   335
dvander@14
   336
        if (parameter->reference()) {
dvander@14
   337
            type = ZONE()->types()->getReference(type);
dvander@14
   338
            if (!type)
dvander@14
   339
                return false;
dvander@14
   340
        }
dvander@14
   341
dvander@14
   342
        args->set(ZONE(), i, type);
dvander@14
   343
        parameter->variable()->setType(type);
dvander@14
   344
    }
dvander@14
   345
dvander@14
   346
    Type *returnType = ZONE()->types()->getPrimitive(PrimitiveType_Int32);
dvander@14
   347
    if (!returnType)
dvander@14
   348
        return false;
dvander@14
   349
dvander@14
   350
    Type *funtype = ZONE()->types()->newFunction(returnType, args);
dvander@14
   351
    if (!funtype)
dvander@14
   352
        return false;
dvander@14
   353
dvander@14
   354
    node->fun()->setType(funtype);
dvander@14
   355
    return true;
dvander@14
   356
}
dvander@14
   357
dvander@0
   358
void
dvander@0
   359
SemanticAnalysis::visit(FunctionStatement *node)
dvander@0
   360
{
dvander@12
   361
    scope_ = node->scope();
dvander@14
   362
dvander@14
   363
    // :TODO: call this ahead of time.
dvander@14
   364
    if (!preanalyze(node))
dvander@14
   365
        return;
dvander@14
   366
dvander@0
   367
    node->body()->accept(this);
dvander@12
   368
    scope_ = NULL;
dvander@0
   369
}
dvander@0
   370
dvander@14
   371
// :TODO: use handles
dvander@14
   372
static inline bool
dvander@14
   373
TypeCheckParameter(Type *given, Type *actual)
dvander@14
   374
{
dvander@14
   375
    if (actual->isReference()) {
dvander@14
   376
        if (given->isReference())
dvander@14
   377
            given = given->contained();
dvander@14
   378
        return TypeCheck(given, actual->contained());
dvander@14
   379
    }
dvander@14
   380
dvander@14
   381
    return TypeCheck(given, actual);
dvander@14
   382
}
dvander@14
   383
dvander@0
   384
void
dvander@0
   385
SemanticAnalysis::visit(CallExpression *node)
dvander@0
   386
{
dvander@14
   387
    visitForLoad(node->callee());
dvander@14
   388
dvander@14
   389
    // :TODO: use locals
dvander@14
   390
    Type *type = node->callee()->type();
dvander@14
   391
    if (!type)
dvander@14
   392
        return;
dvander@14
   393
dvander@14
   394
    assert(type->isFunction());
dvander@14
   395
    assert(node->arguments()->size() == type->parameters()->length());
dvander@14
   396
dvander@14
   397
    for (unsigned i = 0; i < node->arguments()->size(); i++) {
dvander@14
   398
        Expression *expression = node->arguments()->at(i);
dvander@14
   399
        expression->accept(this);
dvander@14
   400
dvander@14
   401
        Type *given = expression->type();
dvander@14
   402
        if (!given)
dvander@14
   403
            return;
dvander@14
   404
dvander@14
   405
        Type *actual = Type::cast(type->parameters()->at(i));
dvander@14
   406
        assert(TypeCheckParameter(given, actual));
dvander@14
   407
dvander@14
   408
        // If the actual is a reference, and the given is not, we'll need to
dvander@14
   409
        // compute a reference, which may be allocated on the stack.
dvander@14
   410
        if (actual->isReference() && !given->isReference())
dvander@14
   411
            scope_->setUsesLifoHeap();
dvander@14
   412
    }
dvander@0
   413
}
dvander@0
   414
dvander@0
   415
void
dvander@0
   416
SemanticAnalysis::visit(IfStatement *node)
dvander@0
   417
{
dvander@10
   418
    visitForLoad(node->condition());
dvander@10
   419
    node->ifTrue()->accept(this);
dvander@10
   420
    if (node->ifFalse())
dvander@10
   421
        node->ifFalse()->accept(this);
dvander@0
   422
}
dvander@0
   423
dvander@0
   424
void
dvander@0
   425
SemanticAnalysis::visit(IndexExpression *node)
dvander@0
   426
{
dvander@14
   427
    // :TODO: use locals
dvander@7
   428
    Type *left = visitForRef(node->left());
dvander@7
   429
    Type *right = visitForLoad(node->right());
dvander@0
   430
dvander@7
   431
    if (!right || !right->isInt()) {
dvander@0
   432
        typeError(node->right(), "integer");
dvander@0
   433
        return;
dvander@0
   434
    }
dvander@7
   435
    if (!left || !left->isArray() || !left->contained()->isPrimitive()) {
dvander@0
   436
        typeError(node->left(), "array");
dvander@0
   437
        return;
dvander@0
   438
    }
dvander@7
   439
    node->setType(left);
dvander@0
   440
}
dvander@2
   441
dvander@2
   442
void
dvander@2
   443
SemanticAnalysis::visit(EnumStatement *node)
dvander@2
   444
{
dvander@4
   445
    // :TODO: test "enum Float { ..."
dvander@4
   446
    Name *tag = node->name();
dvander@3
   447
dvander@11
   448
    Type *type = ZONE()->types()->getPrimitiveForTag(tag);
dvander@2
   449
    if (!type)
dvander@2
   450
        return;
dvander@2
   451
dvander@2
   452
    int value = 0;
dvander@2
   453
    for (size_t i = 0; i < node->entries()->size(); i++) {
dvander@2
   454
        EnumStatement::Entry &entry = node->entries()->at(i);
dvander@2
   455
dvander@2
   456
        BoxedPrimitive box = BoxedPrimitive::Int(value);
dvander@2
   457
        if (entry.expr) {
dvander@2
   458
            entry.expr->accept(this);
dvander@2
   459
            if (!EvaluateForConstant(entry.expr, &box))
dvander@3
   460
                fprintf(stderr, "expected constant integer expression\n");
dvander@2
   461
dvander@2
   462
            assert(box.type() == PrimitiveType_Int32);
dvander@2
   463
            value = box.toInt();
dvander@2
   464
        }
dvander@2
   465
dvander@2
   466
        entry.name->set(type, box);
dvander@2
   467
        value++;
dvander@2
   468
    }
dvander@2
   469
}
dvander@4
   470
dvander@4
   471
void
dvander@4
   472
SemanticAnalysis::visit(FloatLiteral *node)
dvander@4
   473
{
dvander@11
   474
    Type *type = ZONE()->types()->getPrimitive(PrimitiveType_Float);
dvander@4
   475
    if (!type)
dvander@4
   476
        return;
dvander@4
   477
dvander@4
   478
    node->setType(type);
dvander@4
   479
}
dvander@10
   480
dvander@10
   481
void
dvander@10
   482
SemanticAnalysis::visit(BreakStatement *node)
dvander@10
   483
{
dvander@10
   484
    assert(loopDepth_ > 0);
dvander@10
   485
}
dvander@10
   486
dvander@10
   487
void
dvander@10
   488
SemanticAnalysis::visit(ContinueStatement *node)
dvander@10
   489
{
dvander@10
   490
    assert(loopDepth_ > 0);
dvander@10
   491
}