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