src/compiler/SemanticAnalysis.h
author Asher Baker <asherkin@gmail.com>
Mon Jun 10 01:04:43 2013 +0100 (2013-06-10)
changeset 263 ba85a47ee414
parent 256 3c184218462d
permissions -rw-r--r--
Normalise line endings.
asherkin@263
     1
/*
asherkin@263
     2
 * Copyright (C) 2012 David Anderson
asherkin@263
     3
 *
asherkin@263
     4
 * This file is part of SourcePawn.
asherkin@263
     5
 *
asherkin@263
     6
 * SourcePawn is free software: you can redistribute it and/or modify it under
asherkin@263
     7
 * the terms of the GNU General Public License as published by the Free
asherkin@263
     8
 * Software Foundation, either version 3 of the License, or (at your option)
asherkin@263
     9
 * any later version.
asherkin@263
    10
 * 
asherkin@263
    11
 * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
asherkin@263
    12
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
asherkin@263
    13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
asherkin@263
    14
 *
asherkin@263
    15
 * You should have received a copy of the GNU General Public License along with
asherkin@263
    16
 * SourcePawn. If not, see http://www.gnu.org/licenses/.
asherkin@263
    17
 */
asherkin@263
    18
#ifndef _include_sp2_sema_h_
asherkin@263
    19
#define _include_sp2_sema_h_
asherkin@263
    20
asherkin@263
    21
#include "AST.h"
asherkin@263
    22
#include "HIR.h"
asherkin@263
    23
#include "Scopes.h"
asherkin@263
    24
#include "BytecodeEmitter.h"
asherkin@263
    25
asherkin@263
    26
namespace ke {
asherkin@263
    27
asherkin@263
    28
// Semantic analysis occurs after all names and types have been bound. It
asherkin@263
    29
// performs the important task of validating the semantics and type safety
asherkin@263
    30
// of a parse tree.
asherkin@263
    31
// 
asherkin@263
    32
// The semantic analysis phase also produces bytecode. This occurs on a
asherkin@263
    33
// statement-by-statement basis. The result of analyzing an expression is a
asherkin@263
    34
// tree of operations which is then flattened.
asherkin@263
    35
class SemanticAnalysis : public AstVisitor
asherkin@263
    36
{
asherkin@263
    37
  public:
asherkin@263
    38
    SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit);
asherkin@263
    39
asherkin@263
    40
    void analyze();
asherkin@263
    41
asherkin@263
    42
  private:
asherkin@263
    43
    SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun);
asherkin@263
    44
    Function *compile(FunctionStatement *stmt);
asherkin@263
    45
asherkin@263
    46
  public:
asherkin@263
    47
    void visitFunctionStatement(FunctionStatement *node);
asherkin@263
    48
    void visitBlockStatement(BlockStatement *node);
asherkin@263
    49
    void visitExpressionStatement(ExpressionStatement *node);
asherkin@263
    50
    void visitReturnStatement(ReturnStatement *node);
asherkin@263
    51
    void visitEnumStatement(EnumStatement *node);
asherkin@263
    52
asherkin@263
    53
    void visitCallExpression(CallExpression *node);
asherkin@263
    54
    void visitNameProxy(NameProxy *name);
asherkin@263
    55
    void visitIntegerLiteral(IntegerLiteral *node);
asherkin@263
    56
    void visitFloatLiteral(FloatLiteral *node);
asherkin@263
    57
    void visitVariableDeclaration(VariableDeclaration *node);
asherkin@263
    58
    void visitForStatement(ForStatement *node);
asherkin@263
    59
    void visitWhileStatement(WhileStatement *node);
asherkin@263
    60
    void visitAssignment(Assignment *node);
asherkin@263
    61
    void visitBinaryExpression(BinaryExpression *node);
asherkin@263
    62
    void visitBreakStatement(BreakStatement *node);
asherkin@263
    63
    void visitContinueStatement(ContinueStatement *node);
asherkin@263
    64
    void visitIfStatement(IfStatement *node);
asherkin@263
    65
    void visitIndexExpression(IndexExpression *node);
asherkin@263
    66
    void visitIncDecExpression(IncDecExpression *node);
asherkin@263
    67
    void visitStringLiteral(StringLiteral *node);
asherkin@263
    68
    void visitUnaryExpression(UnaryExpression *node);
asherkin@263
    69
    void visitBooleanLiteral(BooleanLiteral *node);
asherkin@263
    70
    void visitFieldExpression(FieldExpression *node);
asherkin@263
    71
#if 0
asherkin@263
    72
    void visitFunctionTypeStatement(FunctionTypeStatement *node);
asherkin@263
    73
    void visitImportStatement(ImportStatement *node);
asherkin@263
    74
    void visitStructureStatement(StructureStatement *node);
asherkin@263
    75
    void visitSwitchStatement(SwitchStatement *node);
asherkin@263
    76
asherkin@263
    77
    void visitTernaryExpression(TernaryExpression *node);
asherkin@263
    78
    void visitArrayLiteral(ArrayLiteral *node);
asherkin@263
    79
#endif
asherkin@263
    80
asherkin@263
    81
  private:
asherkin@263
    82
    bool checkArgumentCount(Handle<FunctionType> type, unsigned actual);
asherkin@263
    83
    void import(HIR *hir, FieldExpression *node);
asherkin@263
    84
asherkin@263
    85
  private:
asherkin@263
    86
    enum CoercionKind {
asherkin@263
    87
        Coerce_Arg,
asherkin@263
    88
        Coerce_Return,
asherkin@263
    89
        Coerce_Decl,
asherkin@263
    90
        Coerce_Assign
asherkin@263
    91
    };
asherkin@263
    92
asherkin@263
    93
    // For a given control flow path, whether it returns.
asherkin@263
    94
    enum ReturnStatus
asherkin@263
    95
    {
asherkin@263
    96
        Returns_Never,
asherkin@263
    97
        Returns_Sometimes,
asherkin@263
    98
        Returns_Always
asherkin@263
    99
    };
asherkin@263
   100
asherkin@263
   101
    // For a given control flow path, whether it terminates,
asherkin@263
   102
    // and if it terminates, whether it returns.
asherkin@263
   103
    class ControlStatus
asherkin@263
   104
    {
asherkin@263
   105
        bool terminates_;
asherkin@263
   106
        ReturnStatus returns_;
asherkin@263
   107
asherkin@263
   108
      public:
asherkin@263
   109
        ControlStatus()
asherkin@263
   110
        {
asherkin@263
   111
        }
asherkin@263
   112
        ControlStatus(bool terminates, ReturnStatus returns)
asherkin@263
   113
          : terminates_(terminates),
asherkin@263
   114
            returns_(returns)
asherkin@263
   115
        {
asherkin@263
   116
        }
asherkin@263
   117
asherkin@263
   118
        bool terminates() const {
asherkin@263
   119
            return terminates_;
asherkin@263
   120
        }
asherkin@263
   121
        ReturnStatus returns() const {
asherkin@263
   122
            return returns_;
asherkin@263
   123
        }
asherkin@263
   124
    };
asherkin@263
   125
asherkin@263
   126
    class ControlScope
asherkin@263
   127
    {
asherkin@263
   128
        ReturnStatus returns_;
asherkin@263
   129
        ControlScope **prevp_;
asherkin@263
   130
        ControlScope *prev_;
asherkin@263
   131
        bool terminates_;
asherkin@263
   132
asherkin@263
   133
      public:
asherkin@263
   134
        ControlScope(ControlScope **prevp)
asherkin@263
   135
          : returns_(Returns_Never),
asherkin@263
   136
            prevp_(prevp),
asherkin@263
   137
            prev_(*prevp),
asherkin@263
   138
            terminates_(false)
asherkin@263
   139
        {
asherkin@263
   140
            *prevp_ = this;
asherkin@263
   141
        }
asherkin@263
   142
        ~ControlScope() {
asherkin@263
   143
            *prevp_ = prev_;
asherkin@263
   144
        }
asherkin@263
   145
        ControlStatus status() {
asherkin@263
   146
            return ControlStatus(terminates_, returns_);
asherkin@263
   147
        }
asherkin@263
   148
asherkin@263
   149
        void returns(ReturnStatus status) {
asherkin@263
   150
            // We allow multiple terminates, but only the first one takes
asherkin@263
   151
            // effect. For example, |break; continue;| is legal, but the
asherkin@263
   152
            // continue is unreachable.
asherkin@263
   153
            if (terminates_)
asherkin@263
   154
                return;
asherkin@263
   155
            if (status > returns_)
asherkin@263
   156
                returns_ = status;
asherkin@263
   157
        }
asherkin@263
   158
        void terminate(ReturnStatus status) {
asherkin@263
   159
            if (terminates_)
asherkin@263
   160
                return;
asherkin@263
   161
            terminates_ = true;
asherkin@263
   162
            returns_ = status;
asherkin@263
   163
        }
asherkin@263
   164
        void merge(const ControlStatus &left, const ControlStatus &right);
asherkin@263
   165
        void inherit(const ControlStatus &other);
asherkin@263
   166
    };
asherkin@263
   167
asherkin@263
   168
asherkin@263
   169
    void requireLifoStack();
asherkin@263
   170
    ControlStatus visitForControl(Statement *statement);
asherkin@263
   171
    ControlStatus visitLoopBody(Statement *stmt);
asherkin@263
   172
    void visitForTest(Expression *expr,
asherkin@263
   173
                      BytecodeEmitter::Label *trueBranch,
asherkin@263
   174
                      BytecodeEmitter::Label *falseBranch,
asherkin@263
   175
                      BytecodeEmitter::Label *fallthrough);
asherkin@263
   176
    void set(VariableSymbol *sym);
asherkin@263
   177
    HIR *eval(Expression *expr);
asherkin@263
   178
    HIR *binary(AstNode *node, TokenKind token, HIR *left, HIR *right);
asherkin@263
   179
    HIR *coerce(HIR *from, Handle<Type> to, CoercionKind kind);
asherkin@263
   180
    Type *coercionType(TokenKind token, HIR *left, HIR *right);
asherkin@263
   181
    HLValue *lvalue(Expression *expr);
asherkin@263
   182
    void discharge(HIR *hir);
asherkin@263
   183
    HIR *typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to);
asherkin@263
   184
asherkin@263
   185
    HIR *typeCheckArray(const SourcePosition &pos,
asherkin@263
   186
                        HIR *from,
asherkin@263
   187
                        Handle<ArrayType> argActual,
asherkin@263
   188
                        CoercionKind kind);
asherkin@263
   189
asherkin@263
   190
  private:
asherkin@263
   191
    // Used to target break/catch statements.
asherkin@263
   192
    class LoopScope
asherkin@263
   193
    {
asherkin@263
   194
        Scope *scope_;
asherkin@263
   195
        BytecodeEmitter::Label *bk_;
asherkin@263
   196
        BytecodeEmitter::Label *ct_;
asherkin@263
   197
        LoopScope **prevp_;
asherkin@263
   198
        LoopScope *prev_;
asherkin@263
   199
        bool usesLifoStack_;
asherkin@263
   200
        bool breaks_;
asherkin@263
   201
asherkin@263
   202
      public:
asherkin@263
   203
        LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
asherkin@263
   204
                  LoopScope **prevp)
asherkin@263
   205
          : scope_(scope),
asherkin@263
   206
            bk_(bk),
asherkin@263
   207
            ct_(ct),
asherkin@263
   208
            prevp_(prevp),
asherkin@263
   209
            prev_(*prevp),
asherkin@263
   210
            usesLifoStack_(false),
asherkin@263
   211
            breaks_(false)
asherkin@263
   212
        {
asherkin@263
   213
            *prevp_ = this;
asherkin@263
   214
        }
asherkin@263
   215
asherkin@263
   216
        ~LoopScope()
asherkin@263
   217
        {
asherkin@263
   218
            *prevp_ = prev_;
asherkin@263
   219
        }
asherkin@263
   220
asherkin@263
   221
        BytecodeEmitter::Label *break_() {
asherkin@263
   222
            return bk_;
asherkin@263
   223
        }
asherkin@263
   224
        BytecodeEmitter::Label *continue_() {
asherkin@263
   225
            return ct_;
asherkin@263
   226
        }
asherkin@263
   227
        Scope *scope() {
asherkin@263
   228
            return scope_;
asherkin@263
   229
        }
asherkin@263
   230
        void setUsesLifoStack() {
asherkin@263
   231
            usesLifoStack_ = true;
asherkin@263
   232
        }
asherkin@263
   233
        bool usesLifoStack() const {
asherkin@263
   234
            return usesLifoStack_;
asherkin@263
   235
        }
asherkin@263
   236
        void setBreaks() {
asherkin@263
   237
            breaks_ = true;
asherkin@263
   238
        }
asherkin@263
   239
        bool breaks() const {
asherkin@263
   240
            return breaks_;
asherkin@263
   241
        }
asherkin@263
   242
    };
asherkin@263
   243
    
asherkin@263
   244
  private:
asherkin@263
   245
    Zone *zone_;
asherkin@263
   246
    PoolAllocator &pool_;
asherkin@263
   247
    CompileContext &cc_;
asherkin@263
   248
    TranslationUnit *unit_;
asherkin@263
   249
    HIR *hir_;
asherkin@263
   250
    Scope *scope_;
asherkin@263
   251
    BytecodeEmitter emitter_;
asherkin@263
   252
    ScopedRoot<FunctionType> fun_;
asherkin@263
   253
    LoopScope *loop_;
asherkin@263
   254
    ControlScope *control_;
asherkin@263
   255
};
asherkin@263
   256
asherkin@263
   257
} // namespace ke
asherkin@263
   258
asherkin@263
   259
#endif // _include_sp2_sema_h_