src/SemanticAnalysis.h
author David Anderson <dvander@alliedmods.net>
Sat Aug 04 20:12:20 2012 -0700 (2012-08-04)
changeset 148 c0740249963c
parent 146 dc7d3b7a918c
child 168 4d0fff61d65e
permissions -rw-r--r--
All but interpreter support for getting and setting struct fields.
     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     NamedFunction *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 typeMismatch(AstNode *node, Handle<Type> actual, Handle<Type> given);
   152     void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
   153     void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
   154     Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
   155 
   156     Type *bindType(const SourcePosition &pos, BoundName *name);
   157 
   158     // These check if one type is compatible with another type, for various
   159     // purposes, like:
   160     //      return (expr) matches function return type
   161     //      call(a, b)    matches expected arg type
   162     //      a = b         matches declared type
   163     //
   164     bool typeCheckArrayAssignment(AstNode *node, Handle<Type> given, Handle<Type> actual, bool forAssign);
   165     bool typeCheckAssignment(AstNode *node, Handle<Type> given, Handle<Type> actual, bool forAssign);
   166     bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
   167 
   168     Type *visitForLoad(Expression *expression);
   169     bool preanalyze(FunctionStatement *node);
   170     Type *visitForLValue(Expression *expression);
   171     Type *visitAndApplyType(Expression *expression);
   172     ControlStatus visitForControl(Statement *statement);
   173 
   174     void markCallResultUsed(CallExpression *call);
   175 
   176     bool determineLiveFunctions();
   177 
   178   public:
   179     SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
   180     bool analyze();
   181 
   182   public:
   183     void visit(NameProxy *name);
   184     void visit(Assignment *node);
   185     void visit(BinaryExpression *node);
   186     void visit(ReturnStatement *node);
   187     void visit(ForStatement *node);
   188     void visit(BlockStatement *node);
   189     void visit(VariableDeclaration *node);
   190     void visit(IntegerLiteral *node);
   191     void visit(ExpressionStatement *node);
   192     void visit(FunctionStatement *node);
   193     void visit(CallExpression *node);
   194     void visit(IfStatement *node);
   195     void visit(IndexExpression *node);
   196     void visit(EnumStatement *node);
   197     void visit(FloatLiteral *node);
   198     void visit(WhileStatement *node);
   199     void visit(BreakStatement *node);
   200     void visit(ContinueStatement *node);
   201     void visit(StringLiteral *node);
   202     void visit(IncDecExpression *node);
   203     void visit(UnaryExpression *node);
   204     void visit(TernaryExpression *node);
   205     void visit(BooleanLiteral *node);
   206     void visit(StructureStatement *node);
   207     void visit(FieldExpression *node);
   208 };
   209 
   210 const char *GetTypeName(Type *type);
   211 
   212 } // namespace ke
   213 
   214 #endif // _include_semantic_analysis_h_