src/SemanticAnalysis.h
author David Anderson <dvander@alliedmods.net>
Mon Sep 17 00:10:01 2012 -0700 (2012-09-17)
changeset 194 b029d63565a2
parent 191 9d17f29fe16a
permissions -rw-r--r--
Implement sizeof operator.
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@0
     5
 * This file is part of JITCraft.
dvander@0
     6
 *
dvander@0
     7
 * JITCraft 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@0
    12
 * Foobar 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@0
    17
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@0
    18
 */
dvander@0
    19
#ifndef _include_semantic_analysis_h_
dvander@0
    20
#define _include_semantic_analysis_h_
dvander@0
    21
dvander@0
    22
#include <assert.h>
dvander@0
    23
#include "AST.h"
dvander@187
    24
#include "Types.h"
dvander@0
    25
dvander@59
    26
namespace ke {
dvander@0
    27
dvander@168
    28
class Box;
dvander@168
    29
dvander@0
    30
class SemanticAnalysis : public AstVisitor
dvander@0
    31
{
dvander@30
    32
    Zone *zone_;
dvander@25
    33
    CompileContext &cc_;
dvander@0
    34
    ParseTree *tree_;
dvander@12
    35
    Scope *scope_;
dvander@137
    36
    NamedFunction *function_;
dvander@0
    37
dvander@71
    38
    enum ReturnStatus
dvander@71
    39
    {
dvander@71
    40
        Returns_Never,
dvander@71
    41
        Returns_Sometimes,
dvander@71
    42
        Returns_Always
dvander@71
    43
    };
dvander@71
    44
dvander@71
    45
    // Tuple that describes whether a path terminates control flow, and
dvander@71
    46
    // if it is guaranteed to end in a return.
dvander@71
    47
    class ControlStatus
dvander@71
    48
    {
dvander@71
    49
        bool terminates_;
dvander@71
    50
        ReturnStatus returns_;
dvander@71
    51
dvander@71
    52
      public:
dvander@71
    53
        ControlStatus(bool terminates, ReturnStatus returns)
dvander@71
    54
          : terminates_(terminates),
dvander@71
    55
            returns_(returns)
dvander@71
    56
        {
dvander@71
    57
        }
dvander@71
    58
dvander@71
    59
        bool terminates() const {
dvander@71
    60
            return terminates_;
dvander@71
    61
        }
dvander@71
    62
        ReturnStatus returns() const {
dvander@71
    63
            return returns_;
dvander@71
    64
        }
dvander@71
    65
    };
dvander@71
    66
dvander@71
    67
    // Used to keep track of terminating control flow and return statements
dvander@71
    68
    // inside control structures.
dvander@71
    69
    class ControlScope
dvander@71
    70
    {
dvander@71
    71
        ReturnStatus returns_;
dvander@71
    72
        ControlScope **prevp_;
dvander@71
    73
        ControlScope *prev_;
dvander@71
    74
        bool terminates_;
dvander@71
    75
dvander@71
    76
      public:
dvander@71
    77
        ControlScope(ControlScope **prev)
dvander@71
    78
          : returns_(Returns_Never),
dvander@71
    79
            prevp_(prev),
dvander@71
    80
            prev_(*prev),
dvander@71
    81
            terminates_(false)
dvander@71
    82
        {
dvander@71
    83
            *prevp_ = this;
dvander@71
    84
        }
dvander@71
    85
dvander@71
    86
        ControlStatus status() const {
dvander@71
    87
            return ControlStatus(terminates_, returns_);
dvander@71
    88
        }
dvander@71
    89
dvander@71
    90
        // We allow multiple terminators, but only the first one takes effect.
dvander@71
    91
        // For example, |break; continue;| is legal but the continue is
dvander@71
    92
        // unreachable.
dvander@71
    93
        void returns(ReturnStatus status) {
dvander@71
    94
            if (terminates_)
dvander@71
    95
                return;
dvander@71
    96
            if (status > returns_)
dvander@71
    97
                returns_ = status;
dvander@71
    98
        }
dvander@71
    99
        void terminate(ReturnStatus status) {
dvander@71
   100
            if (terminates_)
dvander@71
   101
                return;
dvander@71
   102
            terminates_ = true;
dvander@71
   103
            returns_ = status;
dvander@71
   104
        }
dvander@71
   105
        void merge(const ControlStatus &left, const ControlStatus &right);
dvander@172
   106
        void inherit(const ControlStatus &other);
dvander@71
   107
dvander@71
   108
        ~ControlScope()
dvander@71
   109
        {
dvander@71
   110
            *prevp_ = prev_;
dvander@71
   111
        }
dvander@71
   112
    };
dvander@71
   113
dvander@71
   114
    class LoopScope
dvander@71
   115
    {
dvander@71
   116
        LoopScope **prevp_;
dvander@71
   117
        LoopScope *prev_;
dvander@71
   118
        unsigned breaks_;
dvander@71
   119
        unsigned continues_;
dvander@71
   120
dvander@71
   121
      public:
dvander@71
   122
        LoopScope(LoopScope **prev)
dvander@71
   123
          : prevp_(prev),
dvander@71
   124
            prev_(*prev),
dvander@71
   125
            breaks_(0),
dvander@71
   126
            continues_(0)
dvander@71
   127
        {
dvander@71
   128
            *prevp_ = this;
dvander@71
   129
        }
dvander@71
   130
dvander@71
   131
        ~LoopScope()
dvander@71
   132
        {
dvander@71
   133
            *prevp_ = prev_;
dvander@71
   134
        }
dvander@71
   135
dvander@71
   136
        void addBreak() {
dvander@71
   137
            breaks_++;
dvander@71
   138
        }
dvander@71
   139
        void addContinue() {
dvander@71
   140
            continues_++;
dvander@71
   141
        }
dvander@71
   142
        unsigned breaks() const {
dvander@71
   143
            return breaks_;
dvander@71
   144
        }
dvander@71
   145
        unsigned continues() const {
dvander@71
   146
            return continues_;
dvander@71
   147
        }
dvander@71
   148
    };
dvander@71
   149
dvander@71
   150
    ControlScope *control_;
dvander@71
   151
    LoopScope *loop_;
dvander@71
   152
dvander@0
   153
  private:
dvander@40
   154
    bool canTest(AstNode *node, Handle<Type> type);
dvander@168
   155
    void typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given);
dvander@40
   156
    void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
dvander@40
   157
    void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
dvander@40
   158
    Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
dvander@25
   159
dvander@145
   160
    Type *bindType(const SourcePosition &pos, BoundName *name);
dvander@145
   161
dvander@25
   162
    // These check if one type is compatible with another type, for various
dvander@25
   163
    // purposes, like:
dvander@25
   164
    //      return (expr) matches function return type
dvander@25
   165
    //      call(a, b)    matches expected arg type
dvander@25
   166
    //      a = b         matches declared type
dvander@25
   167
    //
dvander@168
   168
    bool typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
dvander@168
   169
    bool typeCheckAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
dvander@40
   170
    bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
dvander@25
   171
dvander@7
   172
    Type *visitForLoad(Expression *expression);
dvander@14
   173
    bool preanalyze(FunctionStatement *node);
dvander@23
   174
    Type *visitForLValue(Expression *expression);
dvander@25
   175
    Type *visitAndApplyType(Expression *expression);
dvander@71
   176
    ControlStatus visitForControl(Statement *statement);
dvander@71
   177
dvander@187
   178
    bool evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]);
dvander@187
   179
    bool inferFixedArrayLiteral(ArrayLiteral *literal,
dvander@187
   180
                                Handle<Type> type,
dvander@187
   181
                                int dims[MAX_ARRAY_DEPTH],
dvander@187
   182
                                unsigned dimcount,
dvander@187
   183
                                unsigned level);
dvander@187
   184
dvander@191
   185
    // Builds an array type used for parameters, returns, or field entries.
dvander@191
   186
    Type *buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst);
dvander@191
   187
dvander@168
   188
    Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
dvander@168
   189
    bool checkArgumentCount(Handle<Type> type, unsigned actual);
dvander@174
   190
    bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
dvander@174
   191
                           FixedArray **args, FixedArray **defaults);
dvander@168
   192
dvander@71
   193
    void markCallResultUsed(CallExpression *call);
dvander@0
   194
dvander@137
   195
    bool determineLiveFunctions();
dvander@137
   196
dvander@0
   197
  public:
dvander@30
   198
    SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
dvander@0
   199
    bool analyze();
dvander@0
   200
dvander@0
   201
  public:
dvander@0
   202
    void visit(NameProxy *name);
dvander@0
   203
    void visit(Assignment *node);
dvander@0
   204
    void visit(BinaryExpression *node);
dvander@0
   205
    void visit(ReturnStatement *node);
dvander@0
   206
    void visit(ForStatement *node);
dvander@0
   207
    void visit(BlockStatement *node);
dvander@0
   208
    void visit(VariableDeclaration *node);
dvander@4
   209
    void visit(IntegerLiteral *node);
dvander@0
   210
    void visit(ExpressionStatement *node);
dvander@0
   211
    void visit(FunctionStatement *node);
dvander@0
   212
    void visit(CallExpression *node);
dvander@0
   213
    void visit(IfStatement *node);
dvander@0
   214
    void visit(IndexExpression *node);
dvander@2
   215
    void visit(EnumStatement *node);
dvander@4
   216
    void visit(FloatLiteral *node);
dvander@9
   217
    void visit(WhileStatement *node);
dvander@10
   218
    void visit(BreakStatement *node);
dvander@10
   219
    void visit(ContinueStatement *node);
dvander@21
   220
    void visit(StringLiteral *node);
dvander@23
   221
    void visit(IncDecExpression *node);
dvander@78
   222
    void visit(UnaryExpression *node);
dvander@83
   223
    void visit(TernaryExpression *node);
dvander@143
   224
    void visit(BooleanLiteral *node);
dvander@146
   225
    void visit(StructureStatement *node);
dvander@148
   226
    void visit(FieldExpression *node);
dvander@172
   227
    void visit(SwitchStatement *node);
dvander@174
   228
    void visit(FunctionTypeStatement *node);
dvander@187
   229
    void visit(ArrayLiteral *node);
dvander@0
   230
};
dvander@0
   231
dvander@145
   232
const char *GetTypeName(Type *type);
dvander@145
   233
dvander@59
   234
} // namespace ke
dvander@0
   235
dvander@0
   236
#endif // _include_semantic_analysis_h_