Added definite return analysis and void-return deduction.
Added definite return analysis and void-return deduction.
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 +