src/compiler/SemanticAnalysis.cpp
author David Anderson <dvander@alliedmods.net>
Sat Nov 17 18:41:01 2012 -0800 (2012-11-17)
changeset 195 c1ba166f3fc4
parent 194 src/SemanticAnalysis.cpp@b029d63565a2
child 196 9904633b1dfc
permissions -rw-r--r--
Massive SemA/BC refactoring to support better type systems. Read on for more.

The previous compiler had a simple pipeline, best outlined as:
(1) Parsing and name binding -> AST
(2) Storage allocation -> AST
(3) Semantic Analysis (SemA) -> AST
(4) Bytecode Compilation (BC) -> Code

This pipeline, unfortunately, had two problems. First, name binding cannot be performed in one pass if we wish to have multi-file support in the form of modules. Name binding must be two-pass.

Second, because SemA was only capable of annotating AST nodes with a single type, most coercion work had to be duplicated in the BC phase, as coercion was not explicit in the SemA output. This made introducing new type rules extremely difficult, and all but precluded concepts like operator overloading (or overloading at all).

This patch rewrites most of Keima's backend. Of interest are the following changes:
(1) CompileContext has been refactored around future multi-file support.
(2) Parsing no longer performs any name binding.
(3) The grammar for type-and-name has been changed from:
(Label | Identifier)? Identifier
to:
Type? Identifier
where:
Type ::= OldType | NewType
OldType ::= Label
NewType ::= Identifier (. NewType)*


Although we do not implement the full production for Type yet, this
distinction is important. A type identifier is now affixed to the AST
as an Expression (right now, always a NameProxy), so it can fully
participate in name binding.

(4) Immediately after parsing, the AST goes through a NamePopulation phase.
This phase creates Scope objects for every scope which declares a name,
and if those names are declaring types or functions, a Symbol is created
and entered into the scope. Symbols entirely replace the old BoundName
classes.

(5) After NamePopulation comes NameBinding. This phase performs three steps:
(a) Links Scope objects together, to form a tree.
(b) Binds any free name to an existing name in the scope chain.
(c) Creates and registers any Symbols for names which have not yet been
added to the scope (for example, local variables).

In accordance, all "allocation" and "binding" concepts have been removed
from Scopes, which are now lightweight container classes.

(6) SemA now generates bytecode for each statement in the AST. Expression
compilation is performed via a separate mechanism called HIR (High-level
Intermediate Representation). To analyze an expression, SemA will walk
the AST, and produce a HIR object for each node. HIR is typed, and SemA
may insert coercion nodes, or even expand an AST node into multiple HIR
nodes. The result of evaluating an expression in SemA is therefore the
the root of a HIR tree, which SemA then sends to the HIRTranslator, which
performs bytecode generation.

As before, SemA still performs full semantic analysis. However, not it
also produces each function's bytecode.

This split allows us to decompose potentially complex semantics into
a more fine-grained, AST-like structure, which can have very simple
code-generation logic. For example, (1.0 + 5) might look like:

HAdd(HFloat(1.0), HConvert(HInteger(5), <Float>))

As part of this decomposition, many opcodes have been removed. Rather than
using typed jumps, we now expand jumps into longer tests. For example:
jge.f <label>
becomes:
ge.f
cvt.f2b
jt <label>

This simplifies the pipeline, and JITs should be able to melt the added
work away.

HIR is not used at a statement level, and HIR does not have any concept
of control-flow.

(7) The old BytecodeCompiler has been removed, as its work is now split
between SemA and HIRTranslator.


In addition, some minor refactorings have taken place:

(1) Opcodes.tbl no longer hardcodes numbers (aaah).
(2) Type has been split into smaller, typed structs.
(3) BytecodeEmitter no longer relies on Pools or RootScopes.
(4) SemA is now responsible for variable/storage allocation.
(5) Native table are now global, rather than per-module. As such, native
declarations now result in a Native object (which still requires a
CALLNATIVE opcode), which is an index into the global table. Natives
must be bound globally. This is in preparation for module support.
(6) Publics are no longer tracked, but rather registered via a global
callback upon module load. This callback can be set by embedders. This
is in preparation for multi-file support.
(7) The BytecodeEmitter now performs Symbol allocations itself, and it
also generates Code objects itself, which removes a good deal of
complexity.

Finally, a test harness has been added. This harness is a python script which finds *.test files, recursively, in the tests folder. For each file it runs the corresponding .sp. The contents of the .test file must match stdout+stderr.
dvander@30
     1
/* vim: set ts=4 sw=4 tw=99 et:
dvander@30
     2
 *
dvander@0
     3
 * Copyright (C) 2012 David Anderson
dvander@0
     4
 *
dvander@195
     5
 * This file is part of SourcePawn.
dvander@0
     6
 *
dvander@195
     7
 * SourcePawn is free software: you can redistribute it and/or modify it under
dvander@0
     8
 * the terms of the GNU General Public License as published by the Free
dvander@0
     9
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@0
    10
 * any later version.
dvander@0
    11
 * 
dvander@195
    12
 * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@0
    13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@0
    14
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@0
    15
 *
dvander@0
    16
 * You should have received a copy of the GNU General Public License along with
dvander@195
    17
 * SourcePawn. If not, see http://www.gnu.org/licenses/.
dvander@0
    18
 */
dvander@195
    19
#include <assert.h>
dvander@195
    20
#include "../Zone.h"
dvander@195
    21
#include "../Strings.h"
dvander@195
    22
#include "../NativeTable.h"
dvander@195
    23
#include "../TypeManager.h"
dvander@195
    24
#include "../Modules.h"
dvander@195
    25
#include "../Code.h"
dvander@0
    26
#include "SemanticAnalysis.h"
dvander@0
    27
dvander@59
    28
using namespace ke;
dvander@0
    29
dvander@195
    30
#define __ emitter_.
dvander@2
    31
dvander@195
    32
typedef BytecodeEmitter::Label Label;
dvander@2
    33
dvander@195
    34
class AutoEnterScope
dvander@2
    35
{
dvander@195
    36
  public:
dvander@195
    37
    AutoEnterScope(Scope **prevp, Scope *scope)
dvander@195
    38
      : prevp_(prevp),
dvander@195
    39
        prev_(*prevp),
dvander@195
    40
        scope_(scope)
dvander@195
    41
    {
dvander@195
    42
        if (!scope_)
dvander@195
    43
            return;
dvander@195
    44
        prev_ = *prevp_;
dvander@195
    45
        *prevp_ = scope;
dvander@195
    46
        assert(prev_ == scope->enclosing());
dvander@195
    47
    }
dvander@195
    48
    ~AutoEnterScope()
dvander@195
    49
    {
dvander@195
    50
        if (scope_)
dvander@195
    51
            *prevp_ = prev_;
dvander@195
    52
    }
dvander@195
    53
  private:
dvander@195
    54
    Scope **prevp_;
dvander@195
    55
    Scope *prev_;
dvander@195
    56
    Scope *scope_;
dvander@195
    57
};
dvander@144
    58
dvander@195
    59
SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit)
dvander@30
    60
  : zone_(zone),
dvander@195
    61
    pool_(zone->pool()),
dvander@30
    62
    cc_(cc),
dvander@195
    63
    unit_(unit),
dvander@195
    64
    hir_(NULL),
dvander@195
    65
    emitter_(pool_),
dvander@195
    66
    module_(NULL),
dvander@71
    67
    loop_(NULL)
dvander@0
    68
{
dvander@0
    69
}
dvander@0
    70
dvander@195
    71
SemanticAnalysis::SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun)
dvander@195
    72
  : zone_(parent->zone_),
dvander@195
    73
    pool_(parent->pool_),
dvander@195
    74
    cc_(parent->cc_),
dvander@195
    75
    unit_(parent->unit_),
dvander@195
    76
    hir_(NULL),
dvander@195
    77
    scope_(parent->scope_),
dvander@195
    78
    emitter_(pool_),
dvander@195
    79
    module_(parent->module_),
dvander@195
    80
    fun_(fun),
dvander@195
    81
    loop_(NULL)
dvander@0
    82
{
dvander@137
    83
dvander@4
    84
}
dvander@4
    85
dvander@25
    86
void
dvander@195
    87
SemanticAnalysis::analyze()
dvander@21
    88
{
dvander@195
    89
    scope_ = unit_->globalScope();
dvander@195
    90
dvander@195
    91
    module_ = Module::New(zone_);
dvander@195
    92
dvander@195
    93
    for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
dvander@195
    94
        Statement *stmt = unit_->tree()->statements()->at(i);
dvander@195
    95
        stmt->accept(this);
dvander@195
    96
    }
dvander@21
    97
dvander@195
    98
    Local<Struct> globals(zone_, unit_->globalScope()->build(zone_));
dvander@195
    99
    if (!globals)
dvander@195
   100
        return;
dvander@195
   101
    module_->setGlobals(globals);
dvander@195
   102
dvander@195
   103
    Local<Code> code(zone_, __ finish());
dvander@195
   104
    if (!code)
dvander@195
   105
        return;
dvander@195
   106
    code->setModule(module_);
dvander@195
   107
    module_->setCode(code);
dvander@195
   108
dvander@195
   109
#ifndef NDEBUG
dvander@195
   110
//    Disassemble(code, stdout);
dvander@195
   111
#endif
dvander@195
   112
dvander@195
   113
    unit_->module_ = module_;
dvander@21
   114
}
dvander@21
   115
dvander@25
   116
void
dvander@195
   117
SemanticAnalysis::visitFunctionStatement(FunctionStatement *stmt)
dvander@25
   118
{
dvander@195
   119
    FunctionSymbol *sym = stmt->sym();
dvander@195
   120
    Local<FunctionType> type(zone_, sym->type());
dvander@22
   121
dvander@195
   122
    assert(scope_->kind() == Scope::GLOBAL);
dvander@79
   123
dvander@195
   124
    if (stmt->token() == TOK_NATIVE) {
dvander@195
   125
        // Define the native now.
dvander@195
   126
        size_t index;
dvander@195
   127
        if (!zone_->nativeTable()->add(stmt->name(), &index))
dvander@195
   128
            return;
dvander@22
   129
dvander@195
   130
        Local<Native> native(zone_, Native::New(zone_, type, index));
dvander@195
   131
        if (!native)
dvander@195
   132
            return;
dvander@25
   133
dvander@195
   134
        __ object(native);
dvander@195
   135
        __ setglobal(sym);
dvander@195
   136
        __ pop();
dvander@23
   137
    }
dvander@23
   138
dvander@195
   139
    // If the function is a forward or native, we don't have to do anything.
dvander@195
   140
    if (stmt->token() == TOK_NATIVE || stmt->token() == TOK_FORWARD)
dvander@23
   141
        return;
dvander@4
   142
dvander@195
   143
    SemanticAnalysis child(this, type);
dvander@195
   144
    Local<Function> funobj(zone_, child.compile(stmt));
dvander@195
   145
    if (!funobj)
dvander@25
   146
        return;
dvander@25
   147
dvander@195
   148
    __ object(funobj);
dvander@195
   149
    __ setglobal(sym);
dvander@195
   150
    __ public_();
dvander@0
   151
}
dvander@0
   152
dvander@195
   153
Function *
dvander@195
   154
SemanticAnalysis::compile(FunctionStatement *stmt)
dvander@83
   155
{
dvander@195
   156
    __ setFirstLine(stmt->pos().line);
dvander@83
   157
dvander@195
   158
    AutoEnterScope argScope(&scope_, stmt->argScope());
dvander@195
   159
    AutoEnterScope varScope(&scope_, stmt->varScope());
dvander@4
   160
dvander@195
   161
    stmt->body()->accept(this);
dvander@71
   162
dvander@195
   163
    Local<Code> code(zone_, __ finish());
dvander@195
   164
    if (!code)
dvander@195
   165
        return NULL;
dvander@195
   166
    code->setModule(module_);
dvander@25
   167
dvander@195
   168
    Local<Function> fun(zone_, Function::New(zone_, code, fun_, stmt->name(), stmt->pos()));
dvander@195
   169
    if (!fun)
dvander@195
   170
        return NULL;
dvander@25
   171
dvander@195
   172
#ifndef NDEBUG
dvander@195
   173
//    Disassemble(code, stdout);
dvander@195
   174
#endif
dvander@71
   175
dvander@195
   176
    return fun;
dvander@0
   177
}
dvander@0
   178
dvander@9
   179
void 
dvander@195
   180
SemanticAnalysis::visitBlockStatement(BlockStatement *node)
dvander@9
   181
{
dvander@195
   182
    AutoEnterScope scope(&scope_, node->scope());
dvander@71
   183
dvander@195
   184
    for (size_t i = 0; i < node->statements()->length(); i++) {
dvander@195
   185
        Statement *stmt = node->statements()->at(i);
dvander@195
   186
        stmt->accept(this);
dvander@195
   187
        assert(__ stackDepth() == 0);
dvander@71
   188
    }
dvander@9
   189
}
dvander@9
   190
dvander@0
   191
void
dvander@195
   192
SemanticAnalysis::visitExpressionStatement(ExpressionStatement *node)
dvander@145
   193
{
dvander@195
   194
    // While building HIR, we enter new pool and root scopes, since HIR
dvander@195
   195
    // creation is purely temporary.
dvander@195
   196
    PoolScope poolScope(zone_->pool());
dvander@195
   197
    RootScope rootScope(zone_);
dvander@190
   198
dvander@195
   199
    HIR *hir = eval(node->expression());
dvander@195
   200
    if (!hir)
dvander@195
   201
        return;
dvander@187
   202
dvander@195
   203
    discharge(hir);
dvander@195
   204
    __ pop();
dvander@187
   205
}
dvander@187
   206
dvander@195
   207
void
dvander@195
   208
SemanticAnalysis::visitForStatement(ForStatement *node)
dvander@187
   209
{
dvander@195
   210
    AutoEnterScope scope(&scope_, node->scope());
dvander@195
   211
    PoolScope poolScope(zone_->pool());
dvander@195
   212
    RootScope rootScope(zone_);
dvander@195
   213
dvander@195
   214
    Label join, update;
dvander@195
   215
    LoopScope loop(scope_, &join, &update, &loop_);
dvander@195
   216
dvander@195
   217
    if (node->initialization())
dvander@195
   218
        node->initialization()->accept(this);
dvander@187
   219
dvander@195
   220
    Label header, test;
dvander@195
   221
    if (node->condition())
dvander@195
   222
        __ jump(&test);
dvander@195
   223
dvander@195
   224
    __ bind(&header);
dvander@195
   225
    node->body()->accept(this);
dvander@195
   226
dvander@195
   227
    __ bind(&update);
dvander@195
   228
    if (node->update())
dvander@195
   229
        node->update()->accept(this);
dvander@195
   230
dvander@195
   231
    if (node->condition()) {
dvander@195
   232
        __ bind(&test);
dvander@195
   233
        visitForTest(node->condition(), &header, &join, &join);
dvander@187
   234
    } else {
dvander@195
   235
        __ jump(&header);
dvander@187
   236
    }
dvander@187
   237
dvander@195
   238
    __ bind(&join);
dvander@187
   239
dvander@195
   240
    assert(__ stackDepth() == 0);
dvander@187
   241
}
dvander@187
   242
dvander@0
   243
void
dvander@195
   244
SemanticAnalysis::visitVariableDeclaration(VariableDeclaration *node)
dvander@0
   245
{
dvander@195
   246
    PoolScope poolScope(zone_->pool());
dvander@195
   247
    RootScope rootScope(zone_);
dvander@195
   248
dvander@195
   249
    HIR *hir;
dvander@195
   250
    if (node->initialization()) {
dvander@195
   251
        if ((hir = eval(node->initialization())) == NULL)
dvander@195
   252
            return;
dvander@195
   253
        if ((hir = coerce(hir, node->sym()->type(), Coerce_Assign)) == NULL)
dvander@195
   254
            return;
dvander@195
   255
    } else {
dvander@195
   256
        assert(false);
dvander@195
   257
    }
dvander@195
   258
dvander@195
   259
    discharge(hir);
dvander@195
   260
dvander@195
   261
    if (!__ allocate(node->sym()))
dvander@0
   262
        return;
dvander@0
   263
dvander@195
   264
    set(node->sym());
dvander@195
   265
    __ pop();
dvander@195
   266
}
dvander@195
   267
dvander@195
   268
void
dvander@195
   269
SemanticAnalysis::visitReturnStatement(ReturnStatement *node)
dvander@195
   270
{
dvander@195
   271
    if (!node->expression()) {
dvander@195
   272
        if (!fun_->returnType()->isVoid()) {
dvander@195
   273
            cc_.reportError(node->pos(), Message_UsedVoidReturn);
dvander@0
   274
            return;
dvander@0
   275
        }
dvander@0
   276
dvander@195
   277
        __ returnvoid();
dvander@195
   278
        return;
dvander@0
   279
    }
dvander@0
   280
dvander@195
   281
    PoolScope poolScope(zone_->pool());
dvander@195
   282
    RootScope rootScope(zone_);
dvander@195
   283
dvander@195
   284
    HIR *hir = eval(node->expression());
dvander@195
   285
    if (!hir)
dvander@195
   286
        return;
dvander@147
   287
dvander@195
   288
    Local<Type> returnType(zone_, fun_->returnType());
dvander@195
   289
    if ((hir = coerce(hir, returnType, Coerce_Return)) == NULL)
dvander@195
   290
        return;
dvander@195
   291
dvander@195
   292
    discharge(hir);
dvander@195
   293
    __ return_();
dvander@0
   294
}
dvander@0
   295
dvander@0
   296
void
dvander@195
   297
SemanticAnalysis::visitBinaryExpression(BinaryExpression *node)
dvander@143
   298
{
dvander@195
   299
    HIR *left = eval(node->left());
dvander@195
   300
    HIR *right = eval(node->right());
dvander@195
   301
    if (!left || !right)
dvander@195
   302
        return;
dvander@168
   303
dvander@195
   304
    hir_ = binary(node->token(), left, right);
dvander@168
   305
}
dvander@168
   306
dvander@14
   307
bool
dvander@195
   308
SemanticAnalysis::checkArgumentCount(Handle<FunctionType> type, unsigned actual)
dvander@168
   309
{
dvander@168
   310
    if (type->parameters()->length() == actual)
dvander@168
   311
        return true;
dvander@168
   312
dvander@168
   313
    if (actual > type->parameters()->length()) {
dvander@168
   314
        if (!type->isNative() || !type->isNativeVariadic())
dvander@168
   315
            return false;
dvander@168
   316
        return true;
dvander@168
   317
    }
dvander@168
   318
dvander@168
   319
    if (!type->defaults())
dvander@168
   320
        return false;
dvander@168
   321
dvander@168
   322
    // Missing arguments. See if there's a default argument for each missing
dvander@168
   323
    // actual.
dvander@168
   324
    for (unsigned i = actual; i < type->parameters()->length(); i++) {
dvander@168
   325
        if (!type->defaults()->at(i))
dvander@168
   326
            return false;
dvander@168
   327
    }
dvander@168
   328
dvander@168
   329
    return true;
dvander@14
   330
}
dvander@14
   331
dvander@0
   332
void
dvander@195
   333
SemanticAnalysis::visitNameProxy(NameProxy *proxy)
dvander@0
   334
{
dvander@195
   335
    Symbol *sym = proxy->sym();
dvander@195
   336
    Handle<Type> type = sym->type();
dvander@195
   337
dvander@195
   338
    VariableSymbol *var = sym->asVariable();
dvander@195
   339
dvander@195
   340
    Scope *in = sym->scope();
dvander@195
   341
    switch (in->kind()) {
dvander@195
   342
      case Scope::GLOBAL:
dvander@195
   343
        hir_ = new (pool_) HGlobal(sym);
dvander@14
   344
        return;
dvander@14
   345
dvander@195
   346
      default:
dvander@195
   347
        assert(in->kind() == Scope::BLOCK);
dvander@195
   348
        assert(var->storage() == VariableSymbol::Local);
dvander@195
   349
        hir_ = new (pool_) HLocal(var);
dvander@195
   350
        return;
dvander@195
   351
    }
dvander@195
   352
}
dvander@195
   353
dvander@195
   354
void
dvander@195
   355
SemanticAnalysis::visitIntegerLiteral(IntegerLiteral *lit)
dvander@195
   356
{
dvander@195
   357
    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
dvander@195
   358
    hir_ = new (pool_) HInteger(type, lit->value());
dvander@195
   359
}
dvander@195
   360
dvander@195
   361
void
dvander@195
   362
SemanticAnalysis::visitFloatLiteral(FloatLiteral *node)
dvander@195
   363
{
dvander@195
   364
    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
dvander@195
   365
    hir_ = new (pool_) HFloat(type, (float)node->value());
dvander@195
   366
}
dvander@195
   367
dvander@195
   368
void
dvander@195
   369
SemanticAnalysis::visitCallExpression(CallExpression *node)
dvander@195
   370
{
dvander@195
   371
    HIR *callee = eval(node->callee());
dvander@195
   372
    if (!callee)
dvander@195
   373
        return;
dvander@195
   374
dvander@195
   375
    if (!callee->type()->isFunction()) {
dvander@25
   376
        cc_.reportError(node->pos(), Message_CalleeNotFunction);
dvander@25
   377
        return;
dvander@25
   378
    }
dvander@168
   379
dvander@195
   380
    Local<FunctionType> fun(zone_, FunctionType::cast(callee->type()));
dvander@195
   381
    
dvander@195
   382
    if (!checkArgumentCount(fun, node->arguments()->length())) {
dvander@168
   383
        cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
dvander@168
   384
        return;
dvander@25
   385
    }
dvander@14
   386
dvander@195
   387
    if (fun->isForward()) {
dvander@195
   388
        cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
dvander@195
   389
        return;
dvander@195
   390
    }
dvander@63
   391
dvander@195
   392
    HIRList *args = new (pool_) HIRList;
dvander@55
   393
    for (unsigned i = 0; i < node->arguments()->length(); i++) {
dvander@14
   394
        Expression *expression = node->arguments()->at(i);
dvander@195
   395
        HIR *arg = eval(expression);
dvander@195
   396
        if (!arg)
dvander@14
   397
            return;
dvander@14
   398
dvander@195
   399
        Handle<Type> given = arg->type();
dvander@71
   400
        
dvander@68
   401
        bool mustComputeReference;
dvander@195
   402
        if (i >= fun->parameters()->length()) {
dvander@68
   403
            // Special handling for natives. Arguments past the formal must
dvander@68
   404
            // always have references computed. However, arrays are already
dvander@195
   405
            // references for natives.
dvander@195
   406
            assert(fun->isNative() && fun->isNativeVariadic());
dvander@195
   407
            mustComputeReference = !given->isReference() &&
dvander@195
   408
                                   !given->isArray();
dvander@68
   409
        } else {
dvander@195
   410
            Local<Type> actual(zone_, fun->parameterAt(i));
dvander@166
   411
dvander@188
   412
            if (expression->isIndexExpression()) {
dvander@195
   413
                // Temporarily disabled.
dvander@195
   414
                assert(!actual->isArray());
dvander@188
   415
                if (actual->isReference()) {
dvander@188
   416
                    cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
dvander@188
   417
                    return;
dvander@188
   418
                }
dvander@166
   419
            }
dvander@166
   420
dvander@195
   421
            // When we start overloading, coercion will have to happen later.
dvander@195
   422
            arg = coerce(arg, actual, Coerce_Arg);
dvander@195
   423
            if (!arg)
dvander@68
   424
                return;
dvander@195
   425
dvander@68
   426
            mustComputeReference = actual->isReference() && !given->isReference();
dvander@68
   427
        }
dvander@14
   428
dvander@195
   429
        // :TODO: handle mustComputeReference
dvander@195
   430
        assert(!mustComputeReference);
dvander@195
   431
dvander@195
   432
        if (!args->append(arg))
dvander@195
   433
            return;
dvander@14
   434
    }
dvander@66
   435
dvander@195
   436
    hir_ = new (pool_) HCall(fun->returnType(), callee, args);
dvander@172
   437
}
dvander@172
   438
dvander@172
   439
void
dvander@195
   440
SemanticAnalysis::visitAssignment(Assignment *node)
dvander@71
   441
{
dvander@195
   442
    HLValue *lval = lvalue(node->lvalue());
dvander@195
   443
    if (!lval)
dvander@71
   444
        return;
dvander@71
   445
dvander@195
   446
    HIR *hir = eval(node->expression());
dvander@195
   447
    if ((hir = coerce(hir, lval->type(), Coerce_Assign)) == NULL)
dvander@195
   448
        return;
dvander@71
   449
dvander@195
   450
    hir_ = new (pool_) HStore(lval, hir);
dvander@71
   451
}
dvander@71
   452
dvander@195
   453
Type *
dvander@195
   454
SemanticAnalysis::coercionType(TokenKind token, HIR *left, HIR *right)
dvander@0
   455
{
dvander@195
   456
    Handle<Type> l = left->type();
dvander@195
   457
    Handle<Type> r = right->type();
dvander@195
   458
dvander@195
   459
    if (token >= TOK_PLUS && token <= TOK_SLASH) {
dvander@195
   460
        // We allow: [float|int32] + [float|int32]
dvander@195
   461
        if (l->isFloat() && r->isInt32())
dvander@195
   462
            return l;
dvander@195
   463
        if (l->isInt32() && r->isFloat())
dvander@195
   464
            return r;
dvander@195
   465
        if (l->isInt32() && r->isInt32())
dvander@195
   466
            return l;
dvander@195
   467
    }
dvander@25
   468
dvander@195
   469
    assert(l == r);
dvander@195
   470
dvander@195
   471
    return left->type();
dvander@195
   472
}
dvander@25
   473
dvander@195
   474
HIR *
dvander@195
   475
SemanticAnalysis::coerce(HIR *hir, Handle<Type> to, CoercionKind kind)
dvander@195
   476
{
dvander@195
   477
    Handle<Type> from = hir->type();
dvander@71
   478
dvander@195
   479
    if (from->isInt32() && to->isFloat())
dvander@195
   480
        return new (pool_) HConvert(to, OP_CVT_I2F, hir);
dvander@195
   481
    
dvander@195
   482
    assert(from == to);
dvander@195
   483
    
dvander@195
   484
    return hir;
dvander@0
   485
}
dvander@0
   486
dvander@0
   487
void
dvander@195
   488
SemanticAnalysis::set(VariableSymbol *sym)
dvander@0
   489
{
dvander@195
   490
    if (sym->scope()->kind() == Scope::GLOBAL) {
dvander@195
   491
        __ setglobal(sym);
dvander@195
   492
    } else {
dvander@195
   493
        assert(sym->storage() == VariableSymbol::Local);
dvander@195
   494
        __ setlocal(sym);
dvander@0
   495
    }
dvander@0
   496
}
dvander@2
   497
dvander@195
   498
HIR *
dvander@195
   499
SemanticAnalysis::binary(TokenKind token, HIR *left, HIR *right)
dvander@148
   500
{
dvander@195
   501
    Local<Type> coercion(zone_, coercionType(token, left, right));
dvander@195
   502
    if (!coercion)
dvander@195
   503
        return NULL;
dvander@195
   504
    if ((left = coerce(left, coercion, Coerce_Arg)) == NULL)
dvander@195
   505
        return NULL;
dvander@195
   506
    if ((right = coerce(right, coercion, Coerce_Arg)) == NULL)
dvander@195
   507
        return NULL;
dvander@195
   508
    
dvander@195
   509
    switch (token) {
dvander@195
   510
     case TOK_PLUS:
dvander@195
   511
      case TOK_MINUS:
dvander@195
   512
      case TOK_STAR:
dvander@195
   513
      case TOK_SLASH:
dvander@195
   514
      case TOK_PERCENT:
dvander@195
   515
      case TOK_AMPERSAND:
dvander@195
   516
      case TOK_BITOR:
dvander@195
   517
      case TOK_BITXOR:
dvander@195
   518
      case TOK_SHR:
dvander@195
   519
      case TOK_USHR:
dvander@195
   520
      case TOK_SHL:
dvander@195
   521
        return new (pool_) HBinary(left->type(), token, left, right);
dvander@148
   522
dvander@195
   523
      case TOK_EQUALS:
dvander@195
   524
      case TOK_NOTEQUALS:
dvander@195
   525
      case TOK_LT:
dvander@195
   526
      case TOK_LE:
dvander@195
   527
      case TOK_GT:
dvander@195
   528
      case TOK_GE:
dvander@195
   529
      case TOK_AND:
dvander@195
   530
      case TOK_OR:
dvander@195
   531
      {
dvander@195
   532
        Local<Type> result(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
dvander@195
   533
        return new (pool_) HBinary(result, token, left, right);
dvander@195
   534
      }
dvander@148
   535
dvander@195
   536
      default:
dvander@195
   537
        assert(false);
dvander@195
   538
        return NULL;
dvander@148
   539
    }
dvander@195
   540
}
dvander@148
   541
dvander@195
   542
static inline TokenKind
dvander@195
   543
ToCompare(Expression *expr)
dvander@195
   544
{
dvander@195
   545
    if (expr->isBinaryExpression()) {
dvander@195
   546
        BinaryExpression *b = expr->toBinaryExpression();
dvander@195
   547
        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
dvander@195
   548
            return b->token();
dvander@195
   549
    } else if (expr->isUnaryExpression()) {
dvander@195
   550
        UnaryExpression *u = expr->toUnaryExpression();
dvander@195
   551
        if (u->token() == TOK_NOT)
dvander@195
   552
            return TOK_NOT;
dvander@195
   553
    }
dvander@195
   554
    return TOK_EOF;
dvander@148
   555
}
dvander@148
   556
dvander@148
   557
void
dvander@195
   558
SemanticAnalysis::visitForTest(Expression *expr,
dvander@195
   559
                               Label *trueBranch,
dvander@195
   560
                               Label *falseBranch,
dvander@195
   561
                               Label *fallthrough)
dvander@2
   562
{
dvander@195
   563
    TokenKind token = ToCompare(expr);
dvander@195
   564
    if (token == TOK_EOF || token == TOK_NOT) {
dvander@195
   565
        assert(false);
dvander@195
   566
        //visitForUnaryTest(expr, trueBranch, falseBranch, fallthrough);
dvander@172
   567
        return;
dvander@172
   568
    }
dvander@172
   569
dvander@195
   570
    BinaryExpression *bin = expr->toBinaryExpression();
dvander@195
   571
    if (token == TOK_AND || token == TOK_OR) {
dvander@195
   572
        assert(false);
dvander@195
   573
        //visitForLogicTest(expr, trueBranch, falseBranch, fallthrough);
dvander@195
   574
        return;
dvander@172
   575
    }
dvander@172
   576
dvander@195
   577
    HIR *left = eval(bin->left());
dvander@195
   578
    HIR *right = eval(bin->right());
dvander@195
   579
    if (!left || !right)
dvander@195
   580
        return;
dvander@195
   581
dvander@195
   582
    HIR *hir = binary(bin->token(), left, right);
dvander@195
   583
    if (!hir)
dvander@195
   584
        return;
dvander@172
   585
dvander@195
   586
    discharge(hir);
dvander@195
   587
    if (fallthrough == trueBranch)
dvander@195
   588
        __ j(OP_JF, falseBranch);
dvander@195
   589
    else
dvander@195
   590
        __ j(OP_JT, trueBranch);
dvander@195
   591
}
dvander@195
   592
dvander@195
   593
HLValue *
dvander@195
   594
SemanticAnalysis::lvalue(Expression *expr)
dvander@195
   595
{
dvander@195
   596
    HIR *hir = eval(expr);
dvander@195
   597
    if (!hir)
dvander@195
   598
        return NULL;
dvander@195
   599
    
dvander@195
   600
    if (!hir->isLValue()) {
dvander@195
   601
        cc_.reportError(expr->pos(), Message_ExpectedLValue);
dvander@195
   602
        return NULL;
dvander@172
   603
    }
dvander@172
   604
dvander@195
   605
    return static_cast<HLValue *>(hir);
dvander@195
   606
}
dvander@172
   607
dvander@195
   608
HIR *
dvander@195
   609
SemanticAnalysis::eval(Expression *expr)
dvander@195
   610
{
dvander@195
   611
    assert(!hir_);
dvander@195
   612
    expr->accept(this);
dvander@172
   613
dvander@195
   614
    HIR *hir = hir_;
dvander@195
   615
    hir_ = NULL;
dvander@195
   616
dvander@195
   617
    return hir;
dvander@172
   618
}
dvander@172
   619
dvander@4
   620
void
dvander@195
   621
SemanticAnalysis::discharge(HIR *hir)
dvander@146
   622
{
dvander@195
   623
    EmitHIR(zone_, emitter_, hir);
dvander@146
   624
}