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