jitcraft/SemanticAnalysis.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jul 01 18:21:15 2012 -0700 (2012-07-01)
changeset 23 8a31742781c1
parent 22 765ab1b672a3
child 25 23e8b3d8e4e6
permissions -rw-r--r--
Implement ++ and -- operators.
     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 Type *
   215 SemanticAnalysis::visitForLValue(Expression *expression)
   216 {
   217     if (expression->isIndexExpression()) {
   218         expression->accept(this);
   219         if (!expression->type())
   220             return NULL;
   221         return expression->type()->contained();
   222     }
   223 
   224     if (!expression->isNameProxy()) {
   225         assert(false);
   226         return NULL;
   227     }
   228 
   229     NameProxy *proxy = expression->toNameProxy();
   230     if (!proxy->binding()->kind() == BoundName::VARIABLE) {
   231         fprintf(stderr, "error\n");
   232         return NULL;
   233     }
   234 
   235     Variable *var = proxy->binding()->toVariable();
   236     if (!var->type())
   237         return NULL;
   238 
   239     if  (var->type()->isReference())
   240         return var->type()->contained();
   241     return var->type();
   242 }
   243 
   244 void
   245 SemanticAnalysis::visit(Assignment *node)
   246 {
   247     visitForLoad(node->expression());
   248 
   249     // :TODO: use Local
   250     Type *type = visitForLValue(node->lvalue());
   251     if (!type)
   252         return;
   253     node->setType(type);
   254 
   255     if (node->token() != TOK_ASSIGN)
   256         assert(TypeCheckBinary(node->token(), node->type(), node->expression()->type()));
   257 
   258     assert(TypeCheckAssignment(node->type(), node->expression()->type()));
   259 }
   260 
   261 void
   262 SemanticAnalysis::visit(IncDecExpression *node)
   263 {
   264     // :TODO: use Local
   265     Type *type = visitForLValue(node->expression());
   266     if (!type)
   267         return;
   268 
   269     assert(!type->isReference());
   270     if (type->isArray()) {
   271         // can't a[]++
   272         assert(false);
   273         return;
   274     }
   275 
   276     assert((type->isInt32() && !type->tag()) || type->isFloat());
   277     node->setType(type);
   278 }
   279 
   280 void
   281 SemanticAnalysis::visit(BinaryExpression *node)
   282 {
   283     // :TODO: use Local
   284     Type *left = visitForLoad(node->left());
   285     Type *right = visitForLoad(node->right());
   286 
   287     Type *result = TypeCheckBinary(node->token(), left, right);
   288     node->setType(result);
   289 }
   290 
   291 void
   292 SemanticAnalysis::visit(ReturnStatement *node)
   293 {
   294     visitForLoad(node->expression());
   295 
   296     // :TODO: type check
   297 }
   298 
   299 void
   300 SemanticAnalysis::visit(ForStatement *node)
   301 {
   302     loopDepth_++;
   303     if (node->scope())
   304         scope_ = node->scope();
   305     if (node->initialization())
   306         node->initialization()->accept(this);
   307     if (node->condition())
   308         visitForLoad(node->condition());
   309     if (node->update())
   310         node->update()->accept(this);
   311     node->body()->accept(this);
   312     if (node->scope())
   313         scope_ = scope_->enclosing();
   314     loopDepth_--;
   315 }
   316 
   317 void 
   318 SemanticAnalysis::visit(WhileStatement *node)
   319 {
   320     loopDepth_++;
   321     node->condition()->accept(this);
   322     node->body()->accept(this);
   323     loopDepth_--;
   324 }
   325 
   326 void
   327 SemanticAnalysis::visit(BlockStatement *node)
   328 {
   329     if (node->scope())
   330         scope_ = node->scope();
   331     for (size_t i = 0; i < node->statements()->length(); i++) {
   332         Statement *statement = node->statements()->at(i);
   333         statement->accept(this);
   334     }
   335     if (node->scope())
   336         scope_ = scope_->enclosing();
   337 }
   338 
   339 void
   340 SemanticAnalysis::visit(VariableDeclaration *node)
   341 {
   342     // :TODO: use locals
   343     Type *type = ZONE()->types()->getPrimitiveForTag(node->tag());
   344     if (!type)
   345         return;
   346 
   347     if (node->postDimensions()) {
   348         Type *init = NULL;
   349         if (node->initialization()) {
   350             node->initialization()->accept(this);
   351             if ((init = node->initialization()->type()) == NULL)
   352                 return;
   353         }
   354 
   355         if (node->postDimensions()->size() > Type::MAX_UNSAFE_ARRAY_DEPTH) {
   356             error();
   357             return;
   358         }
   359 
   360         // If we have an initializer, make sure it's the same type.
   361         if (init) {
   362             assert(init->levels() == node->postDimensions()->size());
   363         }
   364 
   365         Type *check = init;
   366         for (size_t i = node->postDimensions()->size() - 1; i < node->postDimensions()->size(); i--) {
   367             Expression *expr = node->postDimensions()->at(i);
   368             visitForLoad(expr);
   369 
   370             if (!IsPrimitiveType(expr->type(), PrimitiveType_Int32)) {
   371                 typeError(expr, "integer");
   372                 return;
   373             }
   374 
   375             int size = -1;
   376             if (expr->isIntegerLiteral()) {
   377                 size = expr->toIntegerLiteral()->value();
   378                 if (size <= 0) {
   379                     error();
   380                     return;
   381                 }
   382                 if (size >= INT_MAX / sizeof(int)) {
   383                     error();
   384                     return;
   385                 }
   386             } else {
   387                 assert(false);
   388             }
   389 
   390             type = ZONE()->types()->unsafeArray(type, size);
   391 
   392             if (check) {
   393                 assert(check->elements() != -1);
   394                 assert(size != -1);
   395                     
   396                 // If we're assigning a string, we're allowed to pad with
   397                 // zeroes.
   398                 if (check->isCharArray()) {
   399                     assert(type->isCharArray());
   400                     assert(type->elements() >= check->elements());
   401                 } else {
   402                     assert(false);
   403                 }
   404             }
   405 
   406             if (check)
   407                 check = check->contained();
   408         }
   409 
   410         // Right now, any array is allowed on the LIFO heap. In case the
   411         // runtime actually decides to use the LIFO heap, we must reserve
   412         // a slot so we can unwind the heap when the current scope leaves.
   413         scope_->setUsesLifoHeap();
   414     } else {
   415         if (node->initialization()) {
   416             Type *right = visitForLoad(node->initialization());
   417             assert(TypeCheck(type, right));
   418         }
   419         if (type->primitive() == PrimitiveType_Char) {
   420             assert(false);
   421             return;
   422         }
   423     }
   424 
   425     node->variable()->setType(type);
   426 }
   427 
   428 void
   429 SemanticAnalysis::visit(IntegerLiteral *node)
   430 {
   431     node->setType(ZONE()->types()->getPrimitive(PrimitiveType_Int32));
   432 }
   433 
   434 void
   435 SemanticAnalysis::visit(ExpressionStatement *node)
   436 {
   437     node->expression()->accept(this);
   438 }
   439 
   440 bool
   441 SemanticAnalysis::preanalyze(FunctionStatement *node)
   442 {
   443     // :TODO: use Local
   444 
   445     FixedArray *args = FixedArray::New(ZONE(), node->parameters()->size(), Heap::Tenure_Old);
   446     if (!args)
   447         return false;
   448 
   449     // Apply types to arguments.
   450     for (size_t i = 0; i < node->parameters()->size(); i++) {
   451         Parameter *parameter = node->parameters()->at(i);
   452         
   453         Type *type = ZONE()->types()->getPrimitiveForTag(parameter->tag());
   454         if (!type)
   455             return false;
   456 
   457         if (parameter->reference()) {
   458             type = ZONE()->types()->getReference(type);
   459             if (!type)
   460                 return false;
   461         }
   462 
   463         args->set(ZONE(), i, type);
   464         parameter->variable()->setType(type);
   465     }
   466 
   467     Type *returnType = ZONE()->types()->getPrimitive(PrimitiveType_Int32);
   468     if (!returnType)
   469         return false;
   470 
   471     Type *funtype = ZONE()->types()->newFunction(returnType, args);
   472     if (!funtype)
   473         return false;
   474 
   475     node->fun()->setType(funtype);
   476     return true;
   477 }
   478 
   479 void
   480 SemanticAnalysis::visit(FunctionStatement *node)
   481 {
   482     scope_ = node->scope();
   483 
   484     // :TODO: call this ahead of time.
   485     if (!preanalyze(node))
   486         return;
   487 
   488     node->body()->accept(this);
   489     scope_ = NULL;
   490 }
   491 
   492 // :TODO: use handles
   493 static inline bool
   494 TypeCheckParameter(Type *given, Type *actual)
   495 {
   496     if (actual->isReference()) {
   497         if (given->isReference())
   498             given = given->contained();
   499         return TypeCheck(given, actual->contained());
   500     }
   501 
   502     return TypeCheck(given, actual);
   503 }
   504 
   505 void
   506 SemanticAnalysis::visit(CallExpression *node)
   507 {
   508     visitForLoad(node->callee());
   509 
   510     // :TODO: use locals
   511     Type *type = node->callee()->type();
   512     if (!type)
   513         return;
   514 
   515     assert(type->isFunction());
   516     assert(node->arguments()->size() == type->parameters()->length());
   517 
   518     for (unsigned i = 0; i < node->arguments()->size(); i++) {
   519         // Note: we don't compute references unless the callee needs a
   520         // reference type.
   521         Expression *expression = node->arguments()->at(i);
   522         expression->accept(this);
   523 
   524         Type *given = expression->type();
   525         if (!given)
   526             return;
   527 
   528         // If it's an IndexExpression, we special case the ability to compute
   529         // a reference. Maybe we should compute actual Ref types for
   530         // IndexExpression?
   531         if (expression->isIndexExpression())
   532             given = given->contained();
   533 
   534         Type *actual = Type::cast(type->parameters()->at(i));
   535         assert(TypeCheckParameter(given, actual));
   536 
   537         // If the actual is a reference, and the given is not, we'll need to
   538         // compute a reference, which may be allocated on the stack.
   539         if (actual->isReference() && !given->isReference())
   540             scope_->setUsesLifoHeap();
   541     }
   542 }
   543 
   544 void
   545 SemanticAnalysis::visit(IfStatement *node)
   546 {
   547     visitForLoad(node->condition());
   548     node->ifTrue()->accept(this);
   549     if (node->ifFalse())
   550         node->ifFalse()->accept(this);
   551 }
   552 
   553 void
   554 SemanticAnalysis::visit(IndexExpression *node)
   555 {
   556     // :TODO: use locals
   557     Type *left = visitForRef(node->left());
   558     Type *right = visitForLoad(node->right());
   559 
   560     if (!right || !right->isInt32()) {
   561         typeError(node->right(), "integer");
   562         return;
   563     }
   564     if (!left || !left->isArray() || !left->contained()->isPrimitive()) {
   565         typeError(node->left(), "array");
   566         return;
   567     }
   568     node->setType(left);
   569 }
   570 
   571 void
   572 SemanticAnalysis::visit(EnumStatement *node)
   573 {
   574     // :TODO: test "enum Float { ..."
   575     Name *tag = node->name();
   576 
   577     Type *type = ZONE()->types()->getPrimitiveForTag(tag);
   578     if (!type)
   579         return;
   580 
   581     int value = 0;
   582     for (size_t i = 0; i < node->entries()->size(); i++) {
   583         EnumStatement::Entry &entry = node->entries()->at(i);
   584 
   585         BoxedPrimitive box = BoxedPrimitive::Int(value);
   586         if (entry.expr) {
   587             entry.expr->accept(this);
   588             if (!EvaluateForConstant(entry.expr, &box))
   589                 fprintf(stderr, "expected constant integer expression\n");
   590 
   591             assert(box.type() == PrimitiveType_Int32);
   592             value = box.toInt();
   593         }
   594 
   595         entry.name->set(type, box);
   596         value++;
   597     }
   598 }
   599 
   600 void
   601 SemanticAnalysis::visit(StringLiteral *node)
   602 {
   603     Type *type = ZONE()->types()->getPrimitive(PrimitiveType_Char);
   604     if (!type)
   605         return;
   606 
   607     type = Type::NewArray(ZONE(), type, node->string()->length() + 1, true);
   608     if (!type)
   609         return;
   610 
   611     node->setType(type);
   612 }
   613 
   614 void
   615 SemanticAnalysis::visit(FloatLiteral *node)
   616 {
   617     Type *type = ZONE()->types()->getPrimitive(PrimitiveType_Float);
   618     if (!type)
   619         return;
   620 
   621     node->setType(type);
   622 }
   623 
   624 void
   625 SemanticAnalysis::visit(BreakStatement *node)
   626 {
   627     assert(loopDepth_ > 0);
   628 }
   629 
   630 void
   631 SemanticAnalysis::visit(ContinueStatement *node)
   632 {
   633     assert(loopDepth_ > 0);
   634 }