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