Added definite return analysis and void-return deduction.
authorDavid Anderson <dvander@alliedmods.net>
Sat Jul 14 18:43:34 2012 -0700 (2012-07-14)
changeset 71f7e573226c2b
parent 70 1aec996cde2d
child 72 40746ab0a30b
Added definite return analysis and void-return deduction.
jitcraft/AST.h
jitcraft/Messages.tbl
jitcraft/Parser.cpp
jitcraft/Parser.h
jitcraft/Scanner.cpp
jitcraft/SemanticAnalysis.cpp
jitcraft/SemanticAnalysis.h
jitcraft/TypeManager.cpp
jitcraft/TypeManager.h
jitcraft/Types.cpp
jitcraft/Types.h
jitcraft/main.cpp
tests/prototype/precall-void-used.sp
tests/prototype/return-analyze-for-1.sp
tests/prototype/return-analyze-for-2.sp
tests/prototype/return-analyze-for-3.sp
tests/prototype/return-analyze-for-4.sp
tests/prototype/return-analyze-for-5.sp
tests/prototype/return-analyze-if-1.sp
tests/prototype/return-analyze-if-2.sp
tests/prototype/return-analyze-if-3.sp
tests/prototype/return-analyze-if-4.sp
tests/prototype/return-analyze-if-5.sp
     1.1 --- a/jitcraft/AST.h	Thu Jul 12 00:38:00 2012 -0700
     1.2 +++ b/jitcraft/AST.h	Sat Jul 14 18:43:34 2012 -0700
     1.3 @@ -629,15 +629,17 @@
     1.4      NamedFunction *fun_;
     1.5      Statement *body_;
     1.6      ParameterList *parameters_;
     1.7 +    bool explicitReturn_;
     1.8  
     1.9    public:
    1.10      FunctionStatement(const SourcePosition &pos, Scope *scope, NamedFunction *fun, Statement *body,
    1.11 -                      ParameterList *parameters)
    1.12 +                      ParameterList *parameters, bool explicitReturn)
    1.13        : Statement(pos),
    1.14          scope_(scope),
    1.15          fun_(fun),
    1.16          body_(body),
    1.17 -        parameters_(parameters)
    1.18 +        parameters_(parameters),
    1.19 +        explicitReturn_(explicitReturn)
    1.20      {
    1.21      }
    1.22  
    1.23 @@ -659,6 +661,9 @@
    1.24      void accept(AstVisitor *visitor) {
    1.25          visitor->visit(this);
    1.26      }
    1.27 +    bool hasExplicitReturn() const {
    1.28 +        return explicitReturn_;
    1.29 +    }
    1.30  };
    1.31  
    1.32  class IfStatement : public Statement
     2.1 --- a/jitcraft/Messages.tbl	Thu Jul 12 00:38:00 2012 -0700
     2.2 +++ b/jitcraft/Messages.tbl	Sat Jul 14 18:43:34 2012 -0700
     2.3 @@ -54,4 +54,8 @@
     2.4  MSG(ArrayIndexOutOfBounds,          TypeError,              "array index %d is out of bounds [0, %d)")
     2.5  MSG(NativeNotBound,                 TypeError,              "attempted to call unbound native \"%s\"")
     2.6  MSG(AllocationOverflow,             SystemError,            "allocation request overflowed")
     2.7 -MSG(TooMuchRecursion,               SystemError,            "stack overflow: too much recursion")
     2.8 \ No newline at end of file
     2.9 +MSG(TooMuchRecursion,               SystemError,            "stack overflow: too much recursion")
    2.10 +MSG(MissingReturnValue,             SyntaxError,            "tagged function must return a value")
    2.11 +MSG(NotAllPathsReturnValue,         SyntaxError,            "not all paths through function return a value")
    2.12 +MSG(UsedVoidReturn,                 SyntaxError,            "return value expected, but function does not return a value")
    2.13 +MSG(FunctionDoesNotReturnValue,     SyntaxError,            "cannot use the result of a function with no return value")
    2.14 \ No newline at end of file
     3.1 --- a/jitcraft/Parser.cpp	Thu Jul 12 00:38:00 2012 -0700
     3.2 +++ b/jitcraft/Parser.cpp	Sat Jul 14 18:43:34 2012 -0700
     3.3 @@ -625,6 +625,8 @@
     3.4      if (!expr)
     3.5          return NULL;
     3.6  
     3.7 +    encounteredReturn_ = true;
     3.8 +
     3.9      return new (pool_) ReturnStatement(pos, expr);
    3.10  }
    3.11  
    3.12 @@ -698,9 +700,6 @@
    3.13              break;
    3.14          }
    3.15  
    3.16 -        if (!expect(TOK_IF))
    3.17 -            return NULL;
    3.18 -
    3.19          SourcePosition pos = scanner_.begin();
    3.20          if (!expect(TOK_LPAREN))
    3.21              return NULL;
    3.22 @@ -958,6 +957,8 @@
    3.23              return NULL;
    3.24      }
    3.25  
    3.26 +    encounteredReturn_ = false;
    3.27 +
    3.28      Statement *body = NULL;
    3.29      if (token != TOK_FORWARD && token != TOK_NATIVE) {
    3.30          body = block();
    3.31 @@ -966,7 +967,7 @@
    3.32      }
    3.33  
    3.34      scope_ = scope_->enclosing();
    3.35 -    return new (pool_) FunctionStatement(pos, scope, fun, body, parameters);
    3.36 +    return new (pool_) FunctionStatement(pos, scope, fun, body, parameters, encounteredReturn_);
    3.37  }
    3.38  
    3.39  ParseTree *
     4.1 --- a/jitcraft/Parser.h	Thu Jul 12 00:38:00 2012 -0700
     4.2 +++ b/jitcraft/Parser.h	Sat Jul 14 18:43:34 2012 -0700
     4.3 @@ -34,6 +34,7 @@
     4.4      Scanner scanner_;
     4.5      Scope *scope_;
     4.6      PoolList<NameProxy *> *unbound_;
     4.7 +    bool encounteredReturn_;
     4.8  
     4.9    private:
    4.10      void redeclarationError(BoundName *name);
     5.1 --- a/jitcraft/Scanner.cpp	Thu Jul 12 00:38:00 2012 -0700
     5.2 +++ b/jitcraft/Scanner.cpp	Sat Jul 14 18:43:34 2012 -0700
     5.3 @@ -40,7 +40,7 @@
     5.4      pos_(stream_)
     5.5  {
     5.6      cur_.line = 1;
     5.7 -    cur_.col = 0;
     5.8 +    cur_.col = 1;
     5.9      last_ = cur_;
    5.10  }
    5.11  
    5.12 @@ -70,7 +70,7 @@
    5.13  Scanner::calcNewLine(char c)
    5.14  {
    5.15      cur_.line++;
    5.16 -    cur_.col = 0;
    5.17 +    cur_.col = 1;
    5.18      last_ = cur_;
    5.19  
    5.20      char o;
     6.1 --- a/jitcraft/SemanticAnalysis.cpp	Thu Jul 12 00:38:00 2012 -0700
     6.2 +++ b/jitcraft/SemanticAnalysis.cpp	Sat Jul 14 18:43:34 2012 -0700
     6.3 @@ -100,8 +100,8 @@
     6.4    : zone_(zone),
     6.5      cc_(cc),
     6.6      tree_(tree),
     6.7 -    loopDepth_(0),
     6.8 -    scope_(NULL)
     6.9 +    scope_(NULL),
    6.10 +    loop_(NULL)
    6.11  {
    6.12  }
    6.13  
    6.14 @@ -147,18 +147,17 @@
    6.15      } else if (expression->isIndexExpression()) {
    6.16          if (type->isArray())
    6.17              expression->setType(type->contained());
    6.18 +    } else if (expression->isCallExpression()) {
    6.19 +        if (type->isVoid()) {
    6.20 +            CallExpression *call = expression->toCallExpression();
    6.21 +            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
    6.22 +            return NULL;
    6.23 +        }
    6.24      }
    6.25  
    6.26      return expression->type();
    6.27  }
    6.28  
    6.29 -Type *
    6.30 -SemanticAnalysis::visitForRef(Expression *expression)
    6.31 -{
    6.32 -    expression->accept(this);
    6.33 -    return expression->type();
    6.34 -}
    6.35 -
    6.36  // :TODO: this leaks an interior pointer.
    6.37  static inline const char *
    6.38  GetTypeName(Type *type)
    6.39 @@ -269,6 +268,14 @@
    6.40      return var->type();
    6.41  }
    6.42  
    6.43 +SemanticAnalysis::ControlStatus
    6.44 +SemanticAnalysis::visitForControl(Statement *statement)
    6.45 +{
    6.46 +    ControlScope scope(&control_);
    6.47 +    statement->accept(this);
    6.48 +    return scope.status();
    6.49 +}
    6.50 +
    6.51  void
    6.52  SemanticAnalysis::visit(NameProxy *name)
    6.53  {
    6.54 @@ -332,6 +339,9 @@
    6.55  void
    6.56  SemanticAnalysis::visit(ReturnStatement *node)
    6.57  {
    6.58 +    // Set this early, so if we error we don't get more errors.
    6.59 +    control_->returns(Returns_Always);
    6.60 +
    6.61      Local<Type> type(zone_, visitForLoad(node->expression()));
    6.62      if (!type)
    6.63          return;
    6.64 @@ -344,7 +354,8 @@
    6.65  void
    6.66  SemanticAnalysis::visit(ForStatement *node)
    6.67  {
    6.68 -    loopDepth_++;
    6.69 +    LoopScope loop(&loop_);
    6.70 +
    6.71      if (node->scope())
    6.72          scope_ = node->scope();
    6.73  
    6.74 @@ -354,7 +365,6 @@
    6.75      if (node->condition()) {
    6.76          Local<Type> type(zone_, visitForLoad(node->condition()));
    6.77          if (!type || !canTest(node->condition(), type)) {
    6.78 -            loopDepth_--;
    6.79              return;
    6.80          }
    6.81      }
    6.82 @@ -362,26 +372,48 @@
    6.83      if (node->update())
    6.84          node->update()->accept(this);
    6.85  
    6.86 -    node->body()->accept(this);
    6.87 +    ControlStatus status = visitForControl(node->body());
    6.88 +
    6.89 +    // If there is a condition, we treat this like a while loop. Otherwise,
    6.90 +    // join point is only reachable if the loop contains a break. The
    6.91 +    // termination status doesn't tell us anything yet.
    6.92 +    if (node->condition() || loop.breaks())
    6.93 +        control_->merge(status, ControlStatus(false, Returns_Never));
    6.94 +    else
    6.95 +        control_->terminate(status.returns());
    6.96  
    6.97      if (node->scope())
    6.98          scope_ = scope_->enclosing();
    6.99 -    loopDepth_--;
   6.100  }
   6.101  
   6.102  void 
   6.103  SemanticAnalysis::visit(WhileStatement *node)
   6.104  {
   6.105 -    loopDepth_++;
   6.106 +    LoopScope loop(&loop_);
   6.107  
   6.108      Local<Type> type(zone_, visitForLoad(node->condition()));
   6.109      if (!type || !canTest(node->condition(), type)) {
   6.110 -        loopDepth_--;
   6.111          return;
   6.112      }
   6.113  
   6.114 -    node->body()->accept(this);
   6.115 -    loopDepth_--;
   6.116 +    ControlStatus status = visitForControl(node->body());
   6.117 +
   6.118 +    // Detect loops that will always have a fork in the control-flow graph.
   6.119 +    // This will be a |while| loop, or a |do-while| loop whose body does
   6.120 +    // not terminate.
   6.121 +    //
   6.122 +    // For now, we treat these as an |if| regardless of the direction the
   6.123 +    // branch can take. That means the control-flow is always conditional.
   6.124 +    if (node->token() == TOK_WHILE ||
   6.125 +        !status.terminates() ||
   6.126 +        loop.breaks())
   6.127 +    {
   6.128 +        control_->merge(status, ControlStatus(false, Returns_Never));
   6.129 +    } else {
   6.130 +        // At this point, we've got a do-while loop with a |return| or
   6.131 +        // |continue|, meaning that the rest of the block is unreachable.
   6.132 +        control_->terminate(status.returns());
   6.133 +    }
   6.134  }
   6.135  
   6.136  void
   6.137 @@ -408,7 +440,7 @@
   6.138      if (node->postDimensions()) {
   6.139          Local<Type> init(zone_);
   6.140          if (node->initialization()) {
   6.141 -            if ((init = visitAndApplyType(node->initialization())) == NULL)
   6.142 +            if ((init = visitForLoad(node->initialization())) == NULL)
   6.143                  return;
   6.144          }
   6.145  
   6.146 @@ -527,7 +559,7 @@
   6.147  void
   6.148  SemanticAnalysis::visit(ExpressionStatement *node)
   6.149  {
   6.150 -    node->expression()->accept(this);
   6.151 +    visitAndApplyType(node->expression());
   6.152  }
   6.153  
   6.154  bool
   6.155 @@ -597,7 +629,11 @@
   6.156          parameter->variable()->setType(type);
   6.157      }
   6.158  
   6.159 -    Local<Type> returnType(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
   6.160 +    Local<Type> returnType(zone_);
   6.161 +    if (node->hasExplicitReturn())
   6.162 +        returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
   6.163 +    else
   6.164 +        returnType = zone_->types()->getVoid();
   6.165      if (!returnType)
   6.166          return false;
   6.167  
   6.168 @@ -630,8 +666,20 @@
   6.169  {
   6.170      function_ = node->fun()->type();
   6.171      scope_ = node->scope();
   6.172 -    if (node->body())
   6.173 +
   6.174 +    ControlScope control(&control_);
   6.175 +    if (node->body()) {
   6.176          node->body()->accept(this);
   6.177 +
   6.178 +        ControlStatus status = control.status();
   6.179 +        if (status.returns() == Returns_Sometimes) {
   6.180 +            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
   6.181 +        } else if (status.returns() == Returns_Never) {
   6.182 +            if (!function_->returnType()->isVoid())
   6.183 +                cc_.reportError(node->pos(), Message_MissingReturnValue);
   6.184 +        }
   6.185 +    }
   6.186 +
   6.187      scope_ = NULL;
   6.188      function_ = NULL;
   6.189  }
   6.190 @@ -772,6 +820,14 @@
   6.191          if (!given)
   6.192              return;
   6.193  
   6.194 +        // Since we skip a load, check for a call expression that returns void.
   6.195 +        if (given->isVoid()) {
   6.196 +            assert(expression->isCallExpression());
   6.197 +            CallExpression *call = expression->toCallExpression();
   6.198 +            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
   6.199 +            return;
   6.200 +        }
   6.201 +        
   6.202          // If it's an IndexExpression, we special case the ability to compute
   6.203          // a reference.
   6.204          if (expression->isIndexExpression())
   6.205 @@ -801,6 +857,25 @@
   6.206  }
   6.207  
   6.208  void
   6.209 +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
   6.210 +{
   6.211 +    // If both sides terminate in a return, we consider this a return as well.
   6.212 +    if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
   6.213 +        terminate(Returns_Always);
   6.214 +        return;
   6.215 +    }
   6.216 +
   6.217 +    ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
   6.218 +                          ? Returns_Never
   6.219 +                          : Returns_Sometimes;
   6.220 +
   6.221 +    if (left.terminates() && right.terminates())
   6.222 +        terminate(status);
   6.223 +    else
   6.224 +        returns(status);
   6.225 +}
   6.226 +
   6.227 +void
   6.228  SemanticAnalysis::visit(IfStatement *node)
   6.229  {
   6.230      Local<Type> type(zone_, visitForLoad(node->condition()));
   6.231 @@ -810,15 +885,19 @@
   6.232      if (!canTest(node, type))
   6.233          return;
   6.234  
   6.235 -    node->ifTrue()->accept(this);
   6.236 +    ControlStatus trueBranch = visitForControl(node->ifTrue());
   6.237 +    ControlStatus falseBranch = ControlStatus(false, Returns_Never);
   6.238 +
   6.239      if (node->ifFalse())
   6.240 -        node->ifFalse()->accept(this);
   6.241 +        falseBranch = visitForControl(node->ifFalse());
   6.242 +
   6.243 +    control_->merge(trueBranch, falseBranch);
   6.244  }
   6.245  
   6.246  void
   6.247  SemanticAnalysis::visit(IndexExpression *node)
   6.248  {
   6.249 -    Local<Type> left(zone_, visitForRef(node->left()));
   6.250 +    Local<Type> left(zone_, visitForLoad(node->left()));
   6.251      Local<Type> right(zone_, visitForLoad(node->right()));
   6.252  
   6.253      if (!left || !right)
   6.254 @@ -901,13 +980,29 @@
   6.255  void
   6.256  SemanticAnalysis::visit(BreakStatement *node)
   6.257  {
   6.258 -    if (loopDepth_ == 0)
   6.259 +    if (!loop_) {
   6.260          cc_.reportError(node->pos(), Message_BreakOutsideLoop);
   6.261 +        return;
   6.262 +    }
   6.263 +
   6.264 +    // Note: ignore breaks that occur in unreachable control-flow.
   6.265 +    if (!control_->status().terminates())
   6.266 +        loop_->addBreak();
   6.267 +
   6.268 +    control_->terminate(Returns_Never);
   6.269  }
   6.270  
   6.271  void
   6.272  SemanticAnalysis::visit(ContinueStatement *node)
   6.273  {
   6.274 -    if (loopDepth_ == 0)
   6.275 +    if (!loop_) {
   6.276          cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
   6.277 +        return;
   6.278 +    }
   6.279 +
   6.280 +    // Note: ignore continues that occur in unreachable control-flow.
   6.281 +    if (!control_->status().terminates())
   6.282 +        loop_->addContinue();
   6.283 +
   6.284 +    control_->terminate(Returns_Never);
   6.285  }
     7.1 --- a/jitcraft/SemanticAnalysis.h	Thu Jul 12 00:38:00 2012 -0700
     7.2 +++ b/jitcraft/SemanticAnalysis.h	Sat Jul 14 18:43:34 2012 -0700
     7.3 @@ -29,10 +29,123 @@
     7.4      Zone *zone_;
     7.5      CompileContext &cc_;
     7.6      ParseTree *tree_;
     7.7 -    unsigned loopDepth_;
     7.8      Scope *scope_;
     7.9      ScopedRoot<Type> function_;
    7.10  
    7.11 +    enum ReturnStatus
    7.12 +    {
    7.13 +        Returns_Never,
    7.14 +        Returns_Sometimes,
    7.15 +        Returns_Always
    7.16 +    };
    7.17 +
    7.18 +    // Tuple that describes whether a path terminates control flow, and
    7.19 +    // if it is guaranteed to end in a return.
    7.20 +    class ControlStatus
    7.21 +    {
    7.22 +        bool terminates_;
    7.23 +        ReturnStatus returns_;
    7.24 +
    7.25 +      public:
    7.26 +        ControlStatus(bool terminates, ReturnStatus returns)
    7.27 +          : terminates_(terminates),
    7.28 +            returns_(returns)
    7.29 +        {
    7.30 +        }
    7.31 +
    7.32 +        bool terminates() const {
    7.33 +            return terminates_;
    7.34 +        }
    7.35 +        ReturnStatus returns() const {
    7.36 +            return returns_;
    7.37 +        }
    7.38 +    };
    7.39 +
    7.40 +    // Used to keep track of terminating control flow and return statements
    7.41 +    // inside control structures.
    7.42 +    class ControlScope
    7.43 +    {
    7.44 +        ReturnStatus returns_;
    7.45 +        ControlScope **prevp_;
    7.46 +        ControlScope *prev_;
    7.47 +        bool terminates_;
    7.48 +
    7.49 +      public:
    7.50 +        ControlScope(ControlScope **prev)
    7.51 +          : returns_(Returns_Never),
    7.52 +            prevp_(prev),
    7.53 +            prev_(*prev),
    7.54 +            terminates_(false)
    7.55 +        {
    7.56 +            *prevp_ = this;
    7.57 +        }
    7.58 +
    7.59 +        ControlStatus status() const {
    7.60 +            return ControlStatus(terminates_, returns_);
    7.61 +        }
    7.62 +
    7.63 +        // We allow multiple terminators, but only the first one takes effect.
    7.64 +        // For example, |break; continue;| is legal but the continue is
    7.65 +        // unreachable.
    7.66 +        void returns(ReturnStatus status) {
    7.67 +            if (terminates_)
    7.68 +                return;
    7.69 +            if (status > returns_)
    7.70 +                returns_ = status;
    7.71 +        }
    7.72 +        void terminate(ReturnStatus status) {
    7.73 +            if (terminates_)
    7.74 +                return;
    7.75 +            terminates_ = true;
    7.76 +            returns_ = status;
    7.77 +        }
    7.78 +        void merge(const ControlStatus &left, const ControlStatus &right);
    7.79 +
    7.80 +        ~ControlScope()
    7.81 +        {
    7.82 +            *prevp_ = prev_;
    7.83 +        }
    7.84 +    };
    7.85 +
    7.86 +    class LoopScope
    7.87 +    {
    7.88 +        LoopScope **prevp_;
    7.89 +        LoopScope *prev_;
    7.90 +        unsigned breaks_;
    7.91 +        unsigned continues_;
    7.92 +
    7.93 +      public:
    7.94 +        LoopScope(LoopScope **prev)
    7.95 +          : prevp_(prev),
    7.96 +            prev_(*prev),
    7.97 +            breaks_(0),
    7.98 +            continues_(0)
    7.99 +        {
   7.100 +            *prevp_ = this;
   7.101 +        }
   7.102 +
   7.103 +        ~LoopScope()
   7.104 +        {
   7.105 +            *prevp_ = prev_;
   7.106 +        }
   7.107 +
   7.108 +        void addBreak() {
   7.109 +            breaks_++;
   7.110 +        }
   7.111 +        void addContinue() {
   7.112 +            continues_++;
   7.113 +        }
   7.114 +        unsigned breaks() const {
   7.115 +            return breaks_;
   7.116 +        }
   7.117 +        unsigned continues() const {
   7.118 +            return continues_;
   7.119 +        }
   7.120 +    };
   7.121 +
   7.122 +    ControlScope *control_;
   7.123 +    LoopScope *loop_;
   7.124 +
   7.125    private:
   7.126      bool canTest(AstNode *node, Handle<Type> type);
   7.127      void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
   7.128 @@ -47,14 +160,15 @@
   7.129      //
   7.130      bool typeCheckArrayAssignment(AstNode *node, Handle<Type> given, Handle<Type> actual, bool forAssign);
   7.131      bool typeCheckAssignment(AstNode *node, Handle<Type> given, Handle<Type> actual, bool forAssign);
   7.132 -
   7.133      bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
   7.134  
   7.135      Type *visitForLoad(Expression *expression);
   7.136 -    Type *visitForRef(Expression *expression);
   7.137      bool preanalyze(FunctionStatement *node);
   7.138      Type *visitForLValue(Expression *expression);
   7.139      Type *visitAndApplyType(Expression *expression);
   7.140 +    ControlStatus visitForControl(Statement *statement);
   7.141 +
   7.142 +    void markCallResultUsed(CallExpression *call);
   7.143  
   7.144    public:
   7.145      SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
     8.1 --- a/jitcraft/TypeManager.cpp	Thu Jul 12 00:38:00 2012 -0700
     8.2 +++ b/jitcraft/TypeManager.cpp	Sat Jul 14 18:43:34 2012 -0700
     8.3 @@ -32,6 +32,10 @@
     8.4  bool
     8.5  TypeManager::initialize()
     8.6  {
     8.7 +    voidType_ = Type::NewVoid(zone_);
     8.8 +    if (!voidType_)
     8.9 +        return false;
    8.10 +
    8.11      Local<String> floatTag(zone_, zone_->makeSymbol("Float"));
    8.12      if (!floatTag)
    8.13          return false;
    8.14 @@ -112,4 +116,3 @@
    8.15          visitor->visit(referenceTypes_[i].address());
    8.16      }
    8.17  }
    8.18 -
     9.1 --- a/jitcraft/TypeManager.h	Thu Jul 12 00:38:00 2012 -0700
     9.2 +++ b/jitcraft/TypeManager.h	Sat Jul 14 18:43:34 2012 -0700
     9.3 @@ -31,6 +31,7 @@
     9.4      Zone *zone_;
     9.5  
     9.6      // Primitive type cache.
     9.7 +    Unbarriered<Type> voidType_;
     9.8      Unbarriered<Type> primitiveTypes_[PrimitiveTypes_Total];
     9.9      Unbarriered<Type> referenceTypes_[PrimitiveTypes_Total];
    9.10  
    9.11 @@ -44,11 +45,14 @@
    9.12          return primitiveTypes_[type];
    9.13      }
    9.14  
    9.15 +    Type *getVoid() {
    9.16 +        return voidType_;
    9.17 +    }
    9.18      Type *getReference(Handle<Type> type, bool isConst);
    9.19      Type *unsafeArray(Handle<Type> contained, int elements, bool isConst);
    9.20      Type *newFunction(Handle<Type> returnType, Handle<FixedArray> args);
    9.21      Type *newNative(Handle<Type> returnType, Handle<FixedArray> args, bool variadic);
    9.22 -
    9.23 +    
    9.24      void accept(VirtualObjectVisitor *visitor);
    9.25  };
    9.26  
    10.1 --- a/jitcraft/Types.cpp	Thu Jul 12 00:38:00 2012 -0700
    10.2 +++ b/jitcraft/Types.cpp	Sat Jul 14 18:43:34 2012 -0700
    10.3 @@ -23,6 +23,21 @@
    10.4  using namespace ke;
    10.5  
    10.6  Type *
    10.7 +Type::NewVoid(Zone *zone)
    10.8 +{
    10.9 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   10.10 +    if (!type)
   10.11 +        return NULL;
   10.12 +
   10.13 +    type->kind_ = VOID;
   10.14 +    type->tag_ = NULL;
   10.15 +    type->contained_ = NULL;
   10.16 +    type->returnType_ = NULL;
   10.17 +    type->parameters_ = NULL;
   10.18 +    return type;
   10.19 +}
   10.20 +
   10.21 +Type *
   10.22  Type::NewPrimitive(Zone *zone, Handle<String> tag)
   10.23  {
   10.24      Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
    11.1 --- a/jitcraft/Types.h	Thu Jul 12 00:38:00 2012 -0700
    11.2 +++ b/jitcraft/Types.h	Sat Jul 14 18:43:34 2012 -0700
    11.3 @@ -43,7 +43,8 @@
    11.4          ARRAY,
    11.5          REFERENCE,
    11.6          FUNCTION,
    11.7 -        NATIVE
    11.8 +        NATIVE,
    11.9 +        VOID
   11.10      };
   11.11  
   11.12    private:
   11.13 @@ -55,6 +56,7 @@
   11.14      static const int UNKNOWN_SIZE = -1;
   11.15      static const size_t MAX_UNSAFE_ARRAY_DEPTH = 5;
   11.16      
   11.17 +    static Type *NewVoid(Zone *zone);
   11.18      static Type *NewPrimitive(Zone *zone, Handle<String> tag);
   11.19      static Type *NewPrimitive(Zone *zone, PrimitiveType type);
   11.20      static Type *NewArray(Zone *zone, Handle<Type> contained, int elements, bool isConst);
   11.21 @@ -84,6 +86,9 @@
   11.22      bool isNative() {
   11.23          return kind() == NATIVE;
   11.24      }
   11.25 +    bool isVoid() {
   11.26 +        return kind() == VOID;
   11.27 +    }
   11.28      bool isNativeVariadic() {
   11.29          assert(isNative());
   11.30          return variadicNative_;
    12.1 --- a/jitcraft/main.cpp	Thu Jul 12 00:38:00 2012 -0700
    12.2 +++ b/jitcraft/main.cpp	Sat Jul 14 18:43:34 2012 -0700
    12.3 @@ -1,35 +1,35 @@
    12.4 -/*
    12.5 - * Copyright (C) 2012 David Anderson
    12.6 - *
    12.7 - * This file is part of JITCraft.
    12.8 - *
    12.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   12.10 - * the terms of the GNU General Public License as published by the Free
   12.11 - * Software Foundation, either version 3 of the License, or (at your option)
   12.12 - * any later version.
   12.13 - * 
   12.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   12.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   12.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   12.17 - *
   12.18 - * You should have received a copy of the GNU General Public License along with
   12.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   12.20 - */
   12.21 -#include <stdio.h>
   12.22 -#include "Utility.h"
   12.23 -#include "Scanner.h"
   12.24 -#include "Parser.h"
   12.25 -#include "SemanticAnalysis.h"
   12.26 -#include "Zone.h"
   12.27 -#include "BytecodeCompiler.h"
   12.28 -#include "Code.h"
   12.29 -#include "Interpreter.h"
   12.30 -#include "Modules.h"
   12.31 -#include "RootScopes.h"
   12.32 -#include "../include/keima.h"
   12.33 -
   12.34 -using namespace ke;
   12.35 -
   12.36 +/*
   12.37 + * Copyright (C) 2012 David Anderson
   12.38 + *
   12.39 + * This file is part of JITCraft.
   12.40 + *
   12.41 + * JITCraft is free software: you can redistribute it and/or modify it under
   12.42 + * the terms of the GNU General Public License as published by the Free
   12.43 + * Software Foundation, either version 3 of the License, or (at your option)
   12.44 + * any later version.
   12.45 + * 
   12.46 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   12.47 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   12.48 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   12.49 + *
   12.50 + * You should have received a copy of the GNU General Public License along with
   12.51 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   12.52 + */
   12.53 +#include <stdio.h>
   12.54 +#include "Utility.h"
   12.55 +#include "Scanner.h"
   12.56 +#include "Parser.h"
   12.57 +#include "SemanticAnalysis.h"
   12.58 +#include "Zone.h"
   12.59 +#include "BytecodeCompiler.h"
   12.60 +#include "Code.h"
   12.61 +#include "Interpreter.h"
   12.62 +#include "Modules.h"
   12.63 +#include "RootScopes.h"
   12.64 +#include "../include/keima.h"
   12.65 +
   12.66 +using namespace ke;
   12.67 +
   12.68  class MessageReporter : public Ke::IMessageReporter
   12.69  {
   12.70    public:
   12.71 @@ -51,74 +51,82 @@
   12.72              index++;
   12.73          }
   12.74      }
   12.75 -} s_Reporter;
   12.76 -
   12.77 -#if 0
   12.78 -static bool
   12.79 -Compile(const char *stream, size_t length)
   12.80 -{
   12.81 -
   12.82 -    printf("\n ------------ \n\n");
   12.83 -
   12.84 -    Disassemble(module->getFunction(1)->code(), stdout);
   12.85 -    //Disassemble(module->getFunction(1), stdout);
   12.86 -
   12.87 -    printf("\n ------------ \n\n");
   12.88 -
   12.89 -    Function *main = module->getFunction(1);
   12.90 -
   12.91 -    Top top = ZONE()->stack().begin();
   12.92 -    LocalTop localTop(top);
   12.93 -
   12.94 -    Frame *frame = ZONE()->stack().pushFrame(main);
   12.95 -    if (!frame)
   12.96 -        return false;
   12.97 -
   12.98 -    LocalSlot result;
   12.99 -    if (!Interpret(ZONE(), frame, &result))
  12.100 -        return false;
  12.101 -
  12.102 -    printf("Result: %d\n", result.i32);
  12.103 -
  12.104 -    return true;
  12.105 -}
  12.106 -#endif
  12.107 -
  12.108 -intptr_t PrintToServer(void *blah, intptr_t *params)
  12.109 -{
  12.110 -    assert(params[0] == 3);
  12.111 -    const char *fmt = reinterpret_cast<const char *>(params[1]);
  12.112 -    const char *str = reinterpret_cast<const char *>(params[2]);
  12.113 -    int *d = reinterpret_cast<int *>(params[3]);
  12.114 -    printf(fmt, str, *d);
  12.115 -    return 16;
  12.116 -}
  12.117 -
  12.118 -int main(int argc, char **argv)
  12.119 -{
  12.120 -    if (argc < 2) {
  12.121 -        fprintf(stderr, "Usage: <file>\n");
  12.122 -        return 1;
  12.123 -    }
  12.124 -
  12.125 -    if (!Ke::Keima::Initialize())
  12.126 -        return 1;
  12.127 -    Ke::Keima::InstallMessageReporter(&s_Reporter);
  12.128 -    {
  12.129 -        Ke::HandleScope scope;
  12.130 -        Ke::Local<Ke::Module> module = Ke::Compile(argv[1]);
  12.131 -        if (!module)
  12.132 -            return 1;
  12.133 -
  12.134 -        Ke::Local<Ke::Native> native = module->getNative(0);
  12.135 -        native->bind(reinterpret_cast<void *>(PrintToServer));
  12.136 -        module->setNativeIdentity(reinterpret_cast<void *>(5));
  12.137 -
  12.138 -        int result;
  12.139 -        Ke::Local<Ke::Function> fun = module->getPublic(0);
  12.140 -        if (Ke::Keima::Invoke(fun, NULL, 0, &result))
  12.141 -            printf("%d\n", result);
  12.142 -    }
  12.143 -
  12.144 -    Ke::Keima::Shutdown();
  12.145 -}
  12.146 +    virtual void beginCompilationErrors(const char *file) {
  12.147 +        fprintf(stderr, "\nDisplaying compilation errors for \"%s\"\n", file);
  12.148 +    }
  12.149 +    virtual void reportCompilationError(const char *message, unsigned line, unsigned col) {
  12.150 +        fprintf(stderr, "  line %d, col %d: %s\n", line, col, message);
  12.151 +    }
  12.152 +    virtual void endCompilationErrors() {
  12.153 +    }
  12.154 +} s_Reporter;
  12.155 +
  12.156 +#if 0
  12.157 +static bool
  12.158 +Compile(const char *stream, size_t length)
  12.159 +{
  12.160 +
  12.161 +    printf("\n ------------ \n\n");
  12.162 +
  12.163 +    Disassemble(module->getFunction(1)->code(), stdout);
  12.164 +    //Disassemble(module->getFunction(1), stdout);
  12.165 +
  12.166 +    printf("\n ------------ \n\n");
  12.167 +
  12.168 +    Function *main = module->getFunction(1);
  12.169 +
  12.170 +    Top top = ZONE()->stack().begin();
  12.171 +    LocalTop localTop(top);
  12.172 +
  12.173 +    Frame *frame = ZONE()->stack().pushFrame(main);
  12.174 +    if (!frame)
  12.175 +        return false;
  12.176 +
  12.177 +    LocalSlot result;
  12.178 +    if (!Interpret(ZONE(), frame, &result))
  12.179 +        return false;
  12.180 +
  12.181 +    printf("Result: %d\n", result.i32);
  12.182 +
  12.183 +    return true;
  12.184 +}
  12.185 +#endif
  12.186 +
  12.187 +intptr_t PrintToServer(void *blah, intptr_t *params)
  12.188 +{
  12.189 +    assert(params[0] == 3);
  12.190 +    const char *fmt = reinterpret_cast<const char *>(params[1]);
  12.191 +    const char *str = reinterpret_cast<const char *>(params[2]);
  12.192 +    int *d = reinterpret_cast<int *>(params[3]);
  12.193 +    printf(fmt, str, *d);
  12.194 +    return 16;
  12.195 +}
  12.196 +
  12.197 +int main(int argc, char **argv)
  12.198 +{
  12.199 +    if (argc < 2) {
  12.200 +        fprintf(stderr, "Usage: <file>\n");
  12.201 +        return 1;
  12.202 +    }
  12.203 +
  12.204 +    if (!Ke::Keima::Initialize())
  12.205 +        return 1;
  12.206 +    Ke::Keima::InstallMessageReporter(&s_Reporter);
  12.207 +    {
  12.208 +        Ke::HandleScope scope;
  12.209 +        Ke::Local<Ke::Module> module = Ke::Compile(argv[1]);
  12.210 +        if (!module)
  12.211 +            return 1;
  12.212 +
  12.213 +        Ke::Local<Ke::Native> native = module->getNative(0);
  12.214 +        native->bind(reinterpret_cast<void *>(PrintToServer));
  12.215 +        module->setNativeIdentity(reinterpret_cast<void *>(5));
  12.216 +
  12.217 +        int result;
  12.218 +        Ke::Local<Ke::Function> fun = module->getPublic(0);
  12.219 +        if (Ke::Keima::Invoke(fun, NULL, 0, &result))
  12.220 +            printf("%d\n", result);
  12.221 +    }
  12.222 +
  12.223 +    Ke::Keima::Shutdown();
  12.224 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/tests/prototype/precall-void-used.sp	Sat Jul 14 18:43:34 2012 -0700
    13.3 @@ -0,0 +1,11 @@
    13.4 +native PrintToServer(const String:str[], ...);
    13.5 +
    13.6 +f()
    13.7 +{
    13.8 +    return main();
    13.9 +}
   13.10 +
   13.11 +main()
   13.12 +{
   13.13 +}
   13.14 +
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/tests/prototype/return-analyze-for-1.sp	Sat Jul 14 18:43:34 2012 -0700
    14.3 @@ -0,0 +1,14 @@
    14.4 +native PrintToServer(const String:str[], ...);
    14.5 +
    14.6 +main(x)
    14.7 +{
    14.8 +     for (;;) {
    14.9 +     }
   14.10 +}
   14.11 +
   14.12 +public f()
   14.13 +{
   14.14 +    return main(5);
   14.15 +}
   14.16 +
   14.17 +
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/tests/prototype/return-analyze-for-2.sp	Sat Jul 14 18:43:34 2012 -0700
    15.3 @@ -0,0 +1,15 @@
    15.4 +native PrintToServer(const String:str[], ...);
    15.5 +
    15.6 +main(x)
    15.7 +{
    15.8 +     for (;;) {
    15.9 +          return 5;
   15.10 +     }
   15.11 +}
   15.12 +
   15.13 +public f()
   15.14 +{
   15.15 +    return main(5);
   15.16 +}
   15.17 +
   15.18 +
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/tests/prototype/return-analyze-for-3.sp	Sat Jul 14 18:43:34 2012 -0700
    16.3 @@ -0,0 +1,16 @@
    16.4 +native PrintToServer(const String:str[], ...);
    16.5 +
    16.6 +main(x)
    16.7 +{
    16.8 +     for (;;) {
    16.9 +         if (x)
   16.10 +             return 5;
   16.11 +     }
   16.12 +}
   16.13 +
   16.14 +public f()
   16.15 +{
   16.16 +    return main(5);
   16.17 +}
   16.18 +
   16.19 +
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/tests/prototype/return-analyze-for-4.sp	Sat Jul 14 18:43:34 2012 -0700
    17.3 @@ -0,0 +1,15 @@
    17.4 +native PrintToServer(const String:str[], ...);
    17.5 +
    17.6 +main(x)
    17.7 +{
    17.8 +     for (; x;) {
    17.9 +         return 5;
   17.10 +     }
   17.11 +}
   17.12 +
   17.13 +public f()
   17.14 +{
   17.15 +    return main(5);
   17.16 +}
   17.17 +
   17.18 +
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tests/prototype/return-analyze-for-5.sp	Sat Jul 14 18:43:34 2012 -0700
    18.3 @@ -0,0 +1,16 @@
    18.4 +native PrintToServer(const String:str[], ...);
    18.5 +
    18.6 +main(x)
    18.7 +{
    18.8 +     for (; x;) {
    18.9 +         return 5;
   18.10 +     }
   18.11 +     return 4;
   18.12 +}
   18.13 +
   18.14 +public f()
   18.15 +{
   18.16 +    return main(5);
   18.17 +}
   18.18 +
   18.19 +
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/tests/prototype/return-analyze-if-1.sp	Sat Jul 14 18:43:34 2012 -0700
    19.3 @@ -0,0 +1,15 @@
    19.4 +native PrintToServer(const String:str[], ...);
    19.5 +
    19.6 +main(x)
    19.7 +{
    19.8 +    if (x)
    19.9 +        return 5;
   19.10 +    return 2;
   19.11 +}
   19.12 +
   19.13 +f()
   19.14 +{
   19.15 +    return main(5);
   19.16 +}
   19.17 +
   19.18 +
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/tests/prototype/return-analyze-if-2.sp	Sat Jul 14 18:43:34 2012 -0700
    20.3 @@ -0,0 +1,14 @@
    20.4 +native PrintToServer(const String:str[], ...);
    20.5 +
    20.6 +main(x)
    20.7 +{
    20.8 +    if (x)
    20.9 +        return 5;
   20.10 +}
   20.11 +
   20.12 +f()
   20.13 +{
   20.14 +    return main(5);
   20.15 +}
   20.16 +
   20.17 +
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/tests/prototype/return-analyze-if-3.sp	Sat Jul 14 18:43:34 2012 -0700
    21.3 @@ -0,0 +1,16 @@
    21.4 +native PrintToServer(const String:str[], ...);
    21.5 +
    21.6 +main(x)
    21.7 +{
    21.8 +    if (x)
    21.9 +        return 5;
   21.10 +    else
   21.11 +        return 6;
   21.12 +}
   21.13 +
   21.14 +public f()
   21.15 +{
   21.16 +    return main(5);
   21.17 +}
   21.18 +
   21.19 +
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/tests/prototype/return-analyze-if-4.sp	Sat Jul 14 18:43:34 2012 -0700
    22.3 @@ -0,0 +1,16 @@
    22.4 +native PrintToServer(const String:str[], ...);
    22.5 +
    22.6 +main(x)
    22.7 +{
    22.8 +    if (x)
    22.9 +        return 5;
   22.10 +    else if (x)
   22.11 +        return 6;
   22.12 +}
   22.13 +
   22.14 +public f()
   22.15 +{
   22.16 +    return main(5);
   22.17 +}
   22.18 +
   22.19 +
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/tests/prototype/return-analyze-if-5.sp	Sat Jul 14 18:43:34 2012 -0700
    23.3 @@ -0,0 +1,18 @@
    23.4 +native PrintToServer(const String:str[], ...);
    23.5 +
    23.6 +main(x)
    23.7 +{
    23.8 +    if (x)
    23.9 +        return 5;
   23.10 +    else if (x)
   23.11 +        return 6;
   23.12 +    else
   23.13 +        return 6;
   23.14 +}
   23.15 +
   23.16 +public f()
   23.17 +{
   23.18 +    return main(5);
   23.19 +}
   23.20 +
   23.21 +