src/SemanticAnalysis.h
author David Anderson <dvander@alliedmods.net>
Sun Aug 05 21:24:41 2012 -0700 (2012-08-05)
changeset 168 4d0fff61d65e
parent 148 c0740249963c
child 172 48cffae8c9e0
permissions -rw-r--r--
Added runtime support for default arguments.
     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 Box;
    28 
    29 class SemanticAnalysis : public AstVisitor
    30 {
    31     Zone *zone_;
    32     CompileContext &cc_;
    33     ParseTree *tree_;
    34     Scope *scope_;
    35     NamedFunction *function_;
    36 
    37     enum ReturnStatus
    38     {
    39         Returns_Never,
    40         Returns_Sometimes,
    41         Returns_Always
    42     };
    43 
    44     // Tuple that describes whether a path terminates control flow, and
    45     // if it is guaranteed to end in a return.
    46     class ControlStatus
    47     {
    48         bool terminates_;
    49         ReturnStatus returns_;
    50 
    51       public:
    52         ControlStatus(bool terminates, ReturnStatus returns)
    53           : terminates_(terminates),
    54             returns_(returns)
    55         {
    56         }
    57 
    58         bool terminates() const {
    59             return terminates_;
    60         }
    61         ReturnStatus returns() const {
    62             return returns_;
    63         }
    64     };
    65 
    66     // Used to keep track of terminating control flow and return statements
    67     // inside control structures.
    68     class ControlScope
    69     {
    70         ReturnStatus returns_;
    71         ControlScope **prevp_;
    72         ControlScope *prev_;
    73         bool terminates_;
    74 
    75       public:
    76         ControlScope(ControlScope **prev)
    77           : returns_(Returns_Never),
    78             prevp_(prev),
    79             prev_(*prev),
    80             terminates_(false)
    81         {
    82             *prevp_ = this;
    83         }
    84 
    85         ControlStatus status() const {
    86             return ControlStatus(terminates_, returns_);
    87         }
    88 
    89         // We allow multiple terminators, but only the first one takes effect.
    90         // For example, |break; continue;| is legal but the continue is
    91         // unreachable.
    92         void returns(ReturnStatus status) {
    93             if (terminates_)
    94                 return;
    95             if (status > returns_)
    96                 returns_ = status;
    97         }
    98         void terminate(ReturnStatus status) {
    99             if (terminates_)
   100                 return;
   101             terminates_ = true;
   102             returns_ = status;
   103         }
   104         void merge(const ControlStatus &left, const ControlStatus &right);
   105 
   106         ~ControlScope()
   107         {
   108             *prevp_ = prev_;
   109         }
   110     };
   111 
   112     class LoopScope
   113     {
   114         LoopScope **prevp_;
   115         LoopScope *prev_;
   116         unsigned breaks_;
   117         unsigned continues_;
   118 
   119       public:
   120         LoopScope(LoopScope **prev)
   121           : prevp_(prev),
   122             prev_(*prev),
   123             breaks_(0),
   124             continues_(0)
   125         {
   126             *prevp_ = this;
   127         }
   128 
   129         ~LoopScope()
   130         {
   131             *prevp_ = prev_;
   132         }
   133 
   134         void addBreak() {
   135             breaks_++;
   136         }
   137         void addContinue() {
   138             continues_++;
   139         }
   140         unsigned breaks() const {
   141             return breaks_;
   142         }
   143         unsigned continues() const {
   144             return continues_;
   145         }
   146     };
   147 
   148     ControlScope *control_;
   149     LoopScope *loop_;
   150 
   151   private:
   152     bool canTest(AstNode *node, Handle<Type> type);
   153     void typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given);
   154     void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
   155     void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
   156     Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
   157 
   158     Type *bindType(const SourcePosition &pos, BoundName *name);
   159 
   160     // These check if one type is compatible with another type, for various
   161     // purposes, like:
   162     //      return (expr) matches function return type
   163     //      call(a, b)    matches expected arg type
   164     //      a = b         matches declared type
   165     //
   166     bool typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
   167     bool typeCheckAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
   168     bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
   169 
   170     Type *visitForLoad(Expression *expression);
   171     bool preanalyze(FunctionStatement *node);
   172     Type *visitForLValue(Expression *expression);
   173     Type *visitAndApplyType(Expression *expression);
   174     ControlStatus visitForControl(Statement *statement);
   175 
   176     Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
   177     bool checkArgumentCount(Handle<Type> type, unsigned actual);
   178 
   179     void markCallResultUsed(CallExpression *call);
   180 
   181     bool determineLiveFunctions();
   182 
   183   public:
   184     SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
   185     bool analyze();
   186 
   187   public:
   188     void visit(NameProxy *name);
   189     void visit(Assignment *node);
   190     void visit(BinaryExpression *node);
   191     void visit(ReturnStatement *node);
   192     void visit(ForStatement *node);
   193     void visit(BlockStatement *node);
   194     void visit(VariableDeclaration *node);
   195     void visit(IntegerLiteral *node);
   196     void visit(ExpressionStatement *node);
   197     void visit(FunctionStatement *node);
   198     void visit(CallExpression *node);
   199     void visit(IfStatement *node);
   200     void visit(IndexExpression *node);
   201     void visit(EnumStatement *node);
   202     void visit(FloatLiteral *node);
   203     void visit(WhileStatement *node);
   204     void visit(BreakStatement *node);
   205     void visit(ContinueStatement *node);
   206     void visit(StringLiteral *node);
   207     void visit(IncDecExpression *node);
   208     void visit(UnaryExpression *node);
   209     void visit(TernaryExpression *node);
   210     void visit(BooleanLiteral *node);
   211     void visit(StructureStatement *node);
   212     void visit(FieldExpression *node);
   213 };
   214 
   215 const char *GetTypeName(Type *type);
   216 
   217 } // namespace ke
   218 
   219 #endif // _include_semantic_analysis_h_