src/SemanticAnalysis.h
author David Anderson <dvander@alliedmods.net>
Sat Jul 28 21:43:37 2012 -0700 (2012-07-28)
changeset 117 2041ab5ec56c
parent 86 32ad0523b309
child 137 be919b22085b
permissions -rw-r--r--
trigger build.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #ifndef _include_semantic_analysis_h_
    20 #define _include_semantic_analysis_h_
    21 
    22 #include <assert.h>
    23 #include "AST.h"
    24 
    25 namespace ke {
    26 
    27 class SemanticAnalysis : public AstVisitor
    28 {
    29     Zone *zone_;
    30     CompileContext &cc_;
    31     ParseTree *tree_;
    32     Scope *scope_;
    33     ScopedRoot<Type> function_;
    34 
    35     enum ReturnStatus
    36     {
    37         Returns_Never,
    38         Returns_Sometimes,
    39         Returns_Always
    40     };
    41 
    42     // Tuple that describes whether a path terminates control flow, and
    43     // if it is guaranteed to end in a return.
    44     class ControlStatus
    45     {
    46         bool terminates_;
    47         ReturnStatus returns_;
    48 
    49       public:
    50         ControlStatus(bool terminates, ReturnStatus returns)
    51           : terminates_(terminates),
    52             returns_(returns)
    53         {
    54         }
    55 
    56         bool terminates() const {
    57             return terminates_;
    58         }
    59         ReturnStatus returns() const {
    60             return returns_;
    61         }
    62     };
    63 
    64     // Used to keep track of terminating control flow and return statements
    65     // inside control structures.
    66     class ControlScope
    67     {
    68         ReturnStatus returns_;
    69         ControlScope **prevp_;
    70         ControlScope *prev_;
    71         bool terminates_;
    72 
    73       public:
    74         ControlScope(ControlScope **prev)
    75           : returns_(Returns_Never),
    76             prevp_(prev),
    77             prev_(*prev),
    78             terminates_(false)
    79         {
    80             *prevp_ = this;
    81         }
    82 
    83         ControlStatus status() const {
    84             return ControlStatus(terminates_, returns_);
    85         }
    86 
    87         // We allow multiple terminators, but only the first one takes effect.
    88         // For example, |break; continue;| is legal but the continue is
    89         // unreachable.
    90         void returns(ReturnStatus status) {
    91             if (terminates_)
    92                 return;
    93             if (status > returns_)
    94                 returns_ = status;
    95         }
    96         void terminate(ReturnStatus status) {
    97             if (terminates_)
    98                 return;
    99             terminates_ = true;
   100             returns_ = status;
   101         }
   102         void merge(const ControlStatus &left, const ControlStatus &right);
   103 
   104         ~ControlScope()
   105         {
   106             *prevp_ = prev_;
   107         }
   108     };
   109 
   110     class LoopScope
   111     {
   112         LoopScope **prevp_;
   113         LoopScope *prev_;
   114         unsigned breaks_;
   115         unsigned continues_;
   116 
   117       public:
   118         LoopScope(LoopScope **prev)
   119           : prevp_(prev),
   120             prev_(*prev),
   121             breaks_(0),
   122             continues_(0)
   123         {
   124             *prevp_ = this;
   125         }
   126 
   127         ~LoopScope()
   128         {
   129             *prevp_ = prev_;
   130         }
   131 
   132         void addBreak() {
   133             breaks_++;
   134         }
   135         void addContinue() {
   136             continues_++;
   137         }
   138         unsigned breaks() const {
   139             return breaks_;
   140         }
   141         unsigned continues() const {
   142             return continues_;
   143         }
   144     };
   145 
   146     ControlScope *control_;
   147     LoopScope *loop_;
   148 
   149   private:
   150     bool canTest(AstNode *node, Handle<Type> type);
   151     void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
   152     void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
   153     Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
   154 
   155     // These check if one type is compatible with another type, for various
   156     // purposes, like:
   157     //      return (expr) matches function return type
   158     //      call(a, b)    matches expected arg type
   159     //      a = b         matches declared type
   160     //
   161     bool typeCheckArrayAssignment(AstNode *node, Handle<Type> given, Handle<Type> actual, bool forAssign);
   162     bool typeCheckAssignment(AstNode *node, Handle<Type> given, Handle<Type> actual, bool forAssign);
   163     bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
   164 
   165     Type *visitForLoad(Expression *expression);
   166     bool preanalyze(FunctionStatement *node);
   167     Type *visitForLValue(Expression *expression);
   168     Type *visitAndApplyType(Expression *expression);
   169     ControlStatus visitForControl(Statement *statement);
   170 
   171     void markCallResultUsed(CallExpression *call);
   172 
   173   public:
   174     SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
   175     bool analyze();
   176 
   177   public:
   178     void visit(NameProxy *name);
   179     void visit(Assignment *node);
   180     void visit(BinaryExpression *node);
   181     void visit(ReturnStatement *node);
   182     void visit(ForStatement *node);
   183     void visit(BlockStatement *node);
   184     void visit(VariableDeclaration *node);
   185     void visit(IntegerLiteral *node);
   186     void visit(ExpressionStatement *node);
   187     void visit(FunctionStatement *node);
   188     void visit(CallExpression *node);
   189     void visit(IfStatement *node);
   190     void visit(IndexExpression *node);
   191     void visit(EnumStatement *node);
   192     void visit(FloatLiteral *node);
   193     void visit(WhileStatement *node);
   194     void visit(BreakStatement *node);
   195     void visit(ContinueStatement *node);
   196     void visit(StringLiteral *node);
   197     void visit(IncDecExpression *node);
   198     void visit(UnaryExpression *node);
   199     void visit(TernaryExpression *node);
   200 };
   201 
   202 } // namespace ke
   203 
   204 #endif // _include_semantic_analysis_h_