jitcraft/SemanticAnalysis.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jul 01 16:36:39 2012 -0700 (2012-07-01)
changeset 22 765ab1b672a3
parent 21 af5d8e985502
child 23 8a31742781c1
permissions -rw-r--r--
Added support for fused math-assign ops (+=, etc).
     1 /*
     2  * Copyright (C) 2012 David Anderson
     3  *
     4  * This file is part of JITCraft.
     5  *
     6  * JITCraft 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  * Foobar 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  * JITCraft. If not, see http://www.gnu.org/licenses/.
    17  */
    18 #include "SemanticAnalysis.h"
    19 #include "Types.h"
    20 #include "Zone.h"
    21 #include "TypeManager.h"
    22 #include "Scopes.h"
    23 
    24 using namespace jc;
    25 
    26 static inline bool
    27 IsPrimitiveType(Type *type, PrimitiveType primitive)
    28 {
    29     if (!type)
    30         return false;
    31 
    32     if (!type->isPrimitive())
    33         return false;
    34 
    35     return primitive == type->primitive();
    36 }
    37 
    38 static inline bool
    39 EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
    40                         BoxedPrimitive *out)
    41 {
    42     switch (kind) {
    43       case TOK_PLUS:
    44         *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
    45         return true;
    46 
    47       case TOK_SHL:
    48         *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
    49         return true;
    50     }
    51 
    52     return true;
    53 }
    54 
    55 static bool
    56 EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
    57 {
    58     switch (expression->kind()) {
    59       case AstNode::kBinaryExpression:
    60       {
    61         BoxedPrimitive left;
    62         BoxedPrimitive right;
    63         BinaryExpression *b = expression->toBinaryExpression();
    64         if (!EvaluateForConstant(b->left(), &left) ||
    65             !EvaluateForConstant(b->right(), &right))
    66         {
    67             return false;
    68         }
    69         return EvaluateBinaryOperation(b->token(), left, right, out);
    70       }
    71 
    72       case AstNode::kNameProxy:
    73       {
    74         NameProxy *proxy = expression->toNameProxy();
    75         if (proxy->binding()->kind() != BoundName::CONSTANT)
    76             return false;
    77 
    78         NamedConstant *c = proxy->binding()->toNamedConstant();
    79         if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
    80             return false;
    81 
    82         *out = c->value();
    83         return true;
    84       }
    85 
    86       case AstNode::kIntegerLiteral:
    87         *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
    88         return true;
    89 
    90       default:
    91         return false;
    92     }
    93 }
    94 
    95 SemanticAnalysis::SemanticAnalysis(ParseTree *tree)
    96   : tree_(tree),
    97     loopDepth_(0),
    98     scope_(NULL)
    99 {
   100 }
   101 
   102 bool
   103 SemanticAnalysis::analyze()
   104 {
   105     for (size_t i = 0; i < tree_->statements()->length(); i++) {
   106         Statement *statement = tree_->statements()->at(i);
   107         statement->accept(this);
   108     }
   109 
   110     return true;
   111 }
   112 
   113 void
   114 SemanticAnalysis::visit(NameProxy *name)
   115 {
   116     name->setType(name->binding()->type());
   117 }
   118 
   119 Type *
   120 SemanticAnalysis::visitForLoad(Expression *expression)
   121 {
   122     expression->accept(this);
   123     if (!expression->type())
   124         return NULL;
   125 
   126     // :TODO: use Local
   127     Type *type = expression->type();
   128     if (type->isReference()) {
   129         expression->setType(type->contained());
   130     } else if (expression->isIndexExpression()) {
   131         if (type->isArray())
   132             expression->setType(type->contained());
   133     }
   134     return expression->type();
   135 }
   136 
   137 Type *
   138 SemanticAnalysis::visitForRef(Expression *expression)
   139 {
   140     expression->accept(this);
   141     return expression->type();
   142 }
   143 
   144 static inline bool
   145 TypeCheck(Type *left, Type *right)
   146 {
   147     if (!left || !right)
   148         return false;
   149 
   150     if (left->isPrimitive()) {
   151         if (!right->isPrimitive())
   152             return false;
   153         return left->primitive() == right->primitive();
   154     }
   155 
   156     return false;
   157 }
   158 
   159 static inline bool
   160 TypeCheckAssignment(Type *left, Type *right)
   161 {
   162     if (!left || !right)
   163         return false;
   164 
   165     if (left->isPrimitive()) {
   166         if (!right->isPrimitive())
   167             return false;
   168         return left->primitive() == right->primitive();
   169     }
   170 
   171     if (left->isArray() != right->isArray())
   172         return false;
   173 
   174     if (left->levels() != 1 || right->levels() != 1)
   175         return false;
   176 
   177     if (left->elements() == -1 || right->elements() == -1)
   178         return false;
   179 
   180     if (!TypeCheckAssignment(left->contained(), right->contained()))
   181         return false;
   182 
   183     if (left->elements() != right->elements()) {
   184         if (left->isCharArray() && (left->elements() >= right->elements()))
   185             return true;
   186         return false;
   187     }
   188 
   189     return false;
   190 }
   191 
   192 static inline Type *
   193 TypeCheckBinary(TokenKind token, Type *left, Type *right)
   194 {
   195     if (!left || !right)
   196         return NULL;
   197 
   198     if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
   199         (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
   200     {
   201         // If either side is a float, the other side must be a float or int.
   202         if (left->isFloat() || right->isFloat()) {
   203             assert(left->isFloat() || left->isInt32());
   204             assert(right->isFloat() || right->isInt32());
   205             return left->isFloat() ? left : right;
   206         }
   207     }
   208 
   209     assert(left->isInt32() && right->isInt32());
   210     assert(!left->tag() && !right->tag());
   211     return left;
   212 }
   213 
   214 void
   215 SemanticAnalysis::visit(Assignment *node)
   216 {
   217     visitForLoad(node->expression());
   218 
   219     if (node->lvalue()->isIndexExpression()) {
   220         node->lvalue()->accept(this);
   221         node->setType(node->lvalue()->type()->contained());
   222     } else {
   223         NameProxy *proxy = node->lvalue()->toNameProxy();
   224         if (!proxy->binding()->kind() == BoundName::VARIABLE) {
   225             fprintf(stderr, "error\n");
   226             return;
   227         }
   228 
   229         Variable *var = proxy->binding()->toVariable();
   230         if (!var->type())
   231             return;
   232 
   233         if  (var->type()->isReference())
   234             node->setType(var->type()->contained());
   235         else
   236             node->setType(var->type());
   237     }
   238 
   239     if (node->token() != TOK_ASSIGN)
   240         assert(TypeCheckBinary(node->token(), node->type(), node->expression()->type()));
   241 
   242     assert(TypeCheckAssignment(node->type(), node->expression()->type()));
   243 }
   244 
   245 void
   246 SemanticAnalysis::visit(BinaryExpression *node)
   247 {
   248     // :TODO: use Local
   249     Type *left = visitForLoad(node->left());
   250     Type *right = visitForLoad(node->right());
   251 
   252     Type *result = TypeCheckBinary(node->token(), left, right);
   253     node->setType(result);
   254 }
   255 
   256 void
   257 SemanticAnalysis::visit(ReturnStatement *node)
   258 {
   259     visitForLoad(node->expression());
   260 
   261     // :TODO: type check
   262 }
   263 
   264 void
   265 SemanticAnalysis::visit(ForStatement *node)
   266 {
   267     loopDepth_++;
   268     if (node->scope())
   269         scope_ = node->scope();
   270     if (node->initialization())
   271         node->initialization()->accept(this);
   272     if (node->condition())
   273         visitForLoad(node->condition());
   274     if (node->update())
   275         node->update()->accept(this);
   276     node->body()->accept(this);
   277     if (node->scope())
   278         scope_ = scope_->enclosing();
   279     loopDepth_--;
   280 }
   281 
   282 void 
   283 SemanticAnalysis::visit(WhileStatement *node)
   284 {
   285     loopDepth_++;
   286     node->condition()->accept(this);
   287     node->body()->accept(this);
   288     loopDepth_--;
   289 }
   290 
   291 void
   292 SemanticAnalysis::visit(BlockStatement *node)
   293 {
   294     if (node->scope())
   295         scope_ = node->scope();
   296     for (size_t i = 0; i < node->statements()->length(); i++) {
   297         Statement *statement = node->statements()->at(i);
   298         statement->accept(this);
   299     }
   300     if (node->scope())
   301         scope_ = scope_->enclosing();
   302 }
   303 
   304 void
   305 SemanticAnalysis::visit(VariableDeclaration *node)
   306 {
   307     // :TODO: use locals
   308     Type *type = ZONE()->types()->getPrimitiveForTag(node->tag());
   309     if (!type)
   310         return;
   311 
   312     if (node->postDimensions()) {
   313         Type *init = NULL;
   314         if (node->initialization()) {
   315             node->initialization()->accept(this);
   316             if ((init = node->initialization()->type()) == NULL)
   317                 return;
   318         }
   319 
   320         if (node->postDimensions()->size() > Type::MAX_UNSAFE_ARRAY_DEPTH) {
   321             error();
   322             return;
   323         }
   324 
   325         // If we have an initializer, make sure it's the same type.
   326         if (init) {
   327             assert(init->levels() == node->postDimensions()->size());
   328         }
   329 
   330         Type *check = init;
   331         for (size_t i = node->postDimensions()->size() - 1; i < node->postDimensions()->size(); i--) {
   332             Expression *expr = node->postDimensions()->at(i);
   333             visitForLoad(expr);
   334 
   335             if (!IsPrimitiveType(expr->type(), PrimitiveType_Int32)) {
   336                 typeError(expr, "integer");
   337                 return;
   338             }
   339 
   340             int size = -1;
   341             if (expr->isIntegerLiteral()) {
   342                 size = expr->toIntegerLiteral()->value();
   343                 if (size <= 0) {
   344                     error();
   345                     return;
   346                 }
   347                 if (size >= INT_MAX / sizeof(int)) {
   348                     error();
   349                     return;
   350                 }
   351             } else {
   352                 assert(false);
   353             }
   354 
   355             type = ZONE()->types()->unsafeArray(type, size);
   356 
   357             if (check) {
   358                 assert(check->elements() != -1);
   359                 assert(size != -1);
   360                     
   361                 // If we're assigning a string, we're allowed to pad with
   362                 // zeroes.
   363                 if (check->isCharArray()) {
   364                     assert(type->isCharArray());
   365                     assert(type->elements() >= check->elements());
   366                 } else {
   367                     assert(false);
   368                 }
   369             }
   370 
   371             if (check)
   372                 check = check->contained();
   373         }
   374 
   375         // Right now, any array is allowed on the LIFO heap. In case the
   376         // runtime actually decides to use the LIFO heap, we must reserve
   377         // a slot so we can unwind the heap when the current scope leaves.
   378         scope_->setUsesLifoHeap();
   379     } else {
   380         if (node->initialization()) {
   381             Type *right = visitForLoad(node->initialization());
   382             assert(TypeCheck(type, right));
   383         }
   384         if (type->primitive() == PrimitiveType_Char) {
   385             assert(false);
   386             return;
   387         }
   388     }
   389 
   390     node->variable()->setType(type);
   391 }
   392 
   393 void
   394 SemanticAnalysis::visit(IntegerLiteral *node)
   395 {
   396     node->setType(ZONE()->types()->getPrimitive(PrimitiveType_Int32));
   397 }
   398 
   399 void
   400 SemanticAnalysis::visit(ExpressionStatement *node)
   401 {
   402     node->expression()->accept(this);
   403 }
   404 
   405 bool
   406 SemanticAnalysis::preanalyze(FunctionStatement *node)
   407 {
   408     // :TODO: use Local
   409 
   410     FixedArray *args = FixedArray::New(ZONE(), node->parameters()->size(), Heap::Tenure_Old);
   411     if (!args)
   412         return false;
   413 
   414     // Apply types to arguments.
   415     for (size_t i = 0; i < node->parameters()->size(); i++) {
   416         Parameter *parameter = node->parameters()->at(i);
   417         
   418         Type *type = ZONE()->types()->getPrimitiveForTag(parameter->tag());
   419         if (!type)
   420             return false;
   421 
   422         if (parameter->reference()) {
   423             type = ZONE()->types()->getReference(type);
   424             if (!type)
   425                 return false;
   426         }
   427 
   428         args->set(ZONE(), i, type);
   429         parameter->variable()->setType(type);
   430     }
   431 
   432     Type *returnType = ZONE()->types()->getPrimitive(PrimitiveType_Int32);
   433     if (!returnType)
   434         return false;
   435 
   436     Type *funtype = ZONE()->types()->newFunction(returnType, args);
   437     if (!funtype)
   438         return false;
   439 
   440     node->fun()->setType(funtype);
   441     return true;
   442 }
   443 
   444 void
   445 SemanticAnalysis::visit(FunctionStatement *node)
   446 {
   447     scope_ = node->scope();
   448 
   449     // :TODO: call this ahead of time.
   450     if (!preanalyze(node))
   451         return;
   452 
   453     node->body()->accept(this);
   454     scope_ = NULL;
   455 }
   456 
   457 // :TODO: use handles
   458 static inline bool
   459 TypeCheckParameter(Type *given, Type *actual)
   460 {
   461     if (actual->isReference()) {
   462         if (given->isReference())
   463             given = given->contained();
   464         return TypeCheck(given, actual->contained());
   465     }
   466 
   467     return TypeCheck(given, actual);
   468 }
   469 
   470 void
   471 SemanticAnalysis::visit(CallExpression *node)
   472 {
   473     visitForLoad(node->callee());
   474 
   475     // :TODO: use locals
   476     Type *type = node->callee()->type();
   477     if (!type)
   478         return;
   479 
   480     assert(type->isFunction());
   481     assert(node->arguments()->size() == type->parameters()->length());
   482 
   483     for (unsigned i = 0; i < node->arguments()->size(); i++) {
   484         // Note: we don't compute references unless the callee needs a
   485         // reference type.
   486         Expression *expression = node->arguments()->at(i);
   487         expression->accept(this);
   488 
   489         Type *given = expression->type();
   490         if (!given)
   491             return;
   492 
   493         // If it's an IndexExpression, we special case the ability to compute
   494         // a reference. Maybe we should compute actual Ref types for
   495         // IndexExpression?
   496         if (expression->isIndexExpression())
   497             given = given->contained();
   498 
   499         Type *actual = Type::cast(type->parameters()->at(i));
   500         assert(TypeCheckParameter(given, actual));
   501 
   502         // If the actual is a reference, and the given is not, we'll need to
   503         // compute a reference, which may be allocated on the stack.
   504         if (actual->isReference() && !given->isReference())
   505             scope_->setUsesLifoHeap();
   506     }
   507 }
   508 
   509 void
   510 SemanticAnalysis::visit(IfStatement *node)
   511 {
   512     visitForLoad(node->condition());
   513     node->ifTrue()->accept(this);
   514     if (node->ifFalse())
   515         node->ifFalse()->accept(this);
   516 }
   517 
   518 void
   519 SemanticAnalysis::visit(IndexExpression *node)
   520 {
   521     // :TODO: use locals
   522     Type *left = visitForRef(node->left());
   523     Type *right = visitForLoad(node->right());
   524 
   525     if (!right || !right->isInt32()) {
   526         typeError(node->right(), "integer");
   527         return;
   528     }
   529     if (!left || !left->isArray() || !left->contained()->isPrimitive()) {
   530         typeError(node->left(), "array");
   531         return;
   532     }
   533     node->setType(left);
   534 }
   535 
   536 void
   537 SemanticAnalysis::visit(EnumStatement *node)
   538 {
   539     // :TODO: test "enum Float { ..."
   540     Name *tag = node->name();
   541 
   542     Type *type = ZONE()->types()->getPrimitiveForTag(tag);
   543     if (!type)
   544         return;
   545 
   546     int value = 0;
   547     for (size_t i = 0; i < node->entries()->size(); i++) {
   548         EnumStatement::Entry &entry = node->entries()->at(i);
   549 
   550         BoxedPrimitive box = BoxedPrimitive::Int(value);
   551         if (entry.expr) {
   552             entry.expr->accept(this);
   553             if (!EvaluateForConstant(entry.expr, &box))
   554                 fprintf(stderr, "expected constant integer expression\n");
   555 
   556             assert(box.type() == PrimitiveType_Int32);
   557             value = box.toInt();
   558         }
   559 
   560         entry.name->set(type, box);
   561         value++;
   562     }
   563 }
   564 
   565 void
   566 SemanticAnalysis::visit(StringLiteral *node)
   567 {
   568     Type *type = ZONE()->types()->getPrimitive(PrimitiveType_Char);
   569     if (!type)
   570         return;
   571 
   572     type = Type::NewArray(ZONE(), type, node->string()->length() + 1, true);
   573     if (!type)
   574         return;
   575 
   576     node->setType(type);
   577 }
   578 
   579 void
   580 SemanticAnalysis::visit(FloatLiteral *node)
   581 {
   582     Type *type = ZONE()->types()->getPrimitive(PrimitiveType_Float);
   583     if (!type)
   584         return;
   585 
   586     node->setType(type);
   587 }
   588 
   589 void
   590 SemanticAnalysis::visit(BreakStatement *node)
   591 {
   592     assert(loopDepth_ > 0);
   593 }
   594 
   595 void
   596 SemanticAnalysis::visit(ContinueStatement *node)
   597 {
   598     assert(loopDepth_ > 0);
   599 }