jitcraft/SemanticAnalysis.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jun 30 22:31:14 2012 -0700 (2012-06-30)
changeset 14 0784ac5cc347
parent 12 75e385f68b7e
child 17 8aa89dd41e25
permissions -rw-r--r--
Added support for non-array references.
     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         // :TODO: use Local
   125         Type *type = expression->type();
   126         if (type->isArray() || type->isReference())
   127             expression->setType(type->contained());
   128     }
   129     return expression->type();
   130 }
   131 
   132 Type *
   133 SemanticAnalysis::visitForRef(Expression *expression)
   134 {
   135     expression->accept(this);
   136     return expression->type();
   137 }
   138 
   139 static inline bool
   140 TypeCheck(Type *left, Type *right)
   141 {
   142     if (!left || !right)
   143         return false;
   144 
   145     if (left->isPrimitive()) {
   146         if (!right->isPrimitive())
   147             return false;
   148         return left->primitive() == right->primitive();
   149     }
   150 
   151     return false;
   152 }
   153 
   154 void
   155 SemanticAnalysis::visit(Assignment *node)
   156 {
   157     visitForLoad(node->expression());
   158 
   159     if (node->lvalue()->isIndexExpression()) {
   160         node->lvalue()->accept(this);
   161         node->setType(node->lvalue()->type()->contained());
   162     } else {
   163         NameProxy *proxy = node->lvalue()->toNameProxy();
   164         if (!proxy->binding()->kind() == BoundName::VARIABLE) {
   165             fprintf(stderr, "error\n");
   166             return;
   167         }
   168 
   169         Variable *var = proxy->binding()->toVariable();
   170         if  (var->type()->isReference())
   171             node->setType(var->type()->contained());
   172         else
   173             node->setType(var->type());
   174     }
   175 
   176     assert(TypeCheck(node->type(), node->expression()->type()));
   177 }
   178 
   179 
   180 void
   181 SemanticAnalysis::visit(BinaryExpression *node)
   182 {
   183     Type *left = visitForLoad(node->left());
   184     Type *right = visitForLoad(node->right());
   185 
   186     if (node->token() >= TOK_PLUS && node->token() <= TOK_SLASH) {
   187         // Both sides must be primitive.
   188         if (!left || !right)
   189             return;
   190 
   191         // If either side is a float, the other side must be a float or int.
   192         if (left->isFloat() || right->isFloat()) {
   193             assert(left->isFloat() || left->isInt());
   194             assert(right->isFloat() || right->isInt());
   195             node->setType(left->isFloat() ? left : right);
   196             return;
   197         }
   198     }
   199 
   200     // For now, assert everything else is integer and untagged.
   201     assert(left->isInt() && right->isInt());
   202     assert(!left->tag() && !right->tag());
   203     node->setType(left);
   204 }
   205 
   206 void
   207 SemanticAnalysis::visit(ReturnStatement *node)
   208 {
   209     visitForLoad(node->expression());
   210 
   211     // :TODO: type check
   212 }
   213 
   214 void
   215 SemanticAnalysis::visit(ForStatement *node)
   216 {
   217     loopDepth_++;
   218     if (node->scope())
   219         scope_ = node->scope();
   220     if (node->declaration())
   221         node->declaration()->accept(this);
   222     if (node->condition())
   223         visitForLoad(node->condition());
   224     if (node->update())
   225         node->update()->accept(this);
   226     node->body()->accept(this);
   227     if (node->scope())
   228         scope_ = scope_->enclosing();
   229     loopDepth_--;
   230 }
   231 
   232 void 
   233 SemanticAnalysis::visit(WhileStatement *node)
   234 {
   235     loopDepth_++;
   236     node->condition()->accept(this);
   237     node->body()->accept(this);
   238     loopDepth_--;
   239 }
   240 
   241 void
   242 SemanticAnalysis::visit(BlockStatement *node)
   243 {
   244     if (node->scope())
   245         scope_ = node->scope();
   246     for (size_t i = 0; i < node->statements()->length(); i++) {
   247         Statement *statement = node->statements()->at(i);
   248         statement->accept(this);
   249     }
   250     if (node->scope())
   251         scope_ = scope_->enclosing();
   252 }
   253 
   254 void
   255 SemanticAnalysis::visit(VariableDeclaration *node)
   256 {
   257     // :TODO: use locals
   258     Type *type = ZONE()->types()->getPrimitiveForTag(node->tag());
   259     if (!type)
   260         return;
   261 
   262     if (node->postDimensions()) {
   263         if (node->postDimensions()->size() > Type::MAX_UNSAFE_ARRAY_DEPTH) {
   264             error();
   265             return;
   266         }
   267 
   268         for (size_t i = node->postDimensions()->size() - 1; i < node->postDimensions()->size(); i--) {
   269             Expression *expr = node->postDimensions()->at(i);
   270             visitForLoad(expr);
   271 
   272             if (!IsPrimitiveType(expr->type(), PrimitiveType_Int32)) {
   273                 typeError(expr, "integer");
   274                 return;
   275             }
   276 
   277             int size = -1;
   278             if (expr->isIntegerLiteral()) {
   279                 size = expr->toIntegerLiteral()->value();
   280                 if (size <= 0) {
   281                     error();
   282                     return;
   283                 }
   284                 if (size >= INT_MAX / sizeof(int)) {
   285                     error();
   286                     return;
   287                 }
   288             }
   289 
   290             type = ZONE()->types()->unsafeArray(type, size);
   291         }
   292 
   293         // Right now, any array is allowed on the LIFO heap. In case the
   294         // runtime actually decides to use the LIFO heap, we must reserve
   295         // a slot so we can unwind the heap when the current scope leaves.
   296         scope_->setUsesLifoHeap();
   297     } else {
   298         if (node->initialization()) {
   299             Type *right = visitForLoad(node->initialization());
   300             assert(TypeCheck(type, right));
   301         }
   302     }
   303 
   304     node->variable()->setType(type);
   305 }
   306 
   307 void
   308 SemanticAnalysis::visit(IntegerLiteral *node)
   309 {
   310     node->setType(ZONE()->types()->getPrimitive(PrimitiveType_Int32));
   311 }
   312 
   313 void
   314 SemanticAnalysis::visit(ExpressionStatement *node)
   315 {
   316     node->expression()->accept(this);
   317 }
   318 
   319 bool
   320 SemanticAnalysis::preanalyze(FunctionStatement *node)
   321 {
   322     // :TODO: use Local
   323 
   324     FixedArray *args = FixedArray::New(ZONE(), node->parameters()->size(), Heap::Tenure_Old);
   325     if (!args)
   326         return false;
   327 
   328     // Apply types to arguments.
   329     for (size_t i = 0; i < node->parameters()->size(); i++) {
   330         Parameter *parameter = node->parameters()->at(i);
   331         
   332         Type *type = ZONE()->types()->getPrimitiveForTag(parameter->tag());
   333         if (!type)
   334             return false;
   335 
   336         if (parameter->reference()) {
   337             type = ZONE()->types()->getReference(type);
   338             if (!type)
   339                 return false;
   340         }
   341 
   342         args->set(ZONE(), i, type);
   343         parameter->variable()->setType(type);
   344     }
   345 
   346     Type *returnType = ZONE()->types()->getPrimitive(PrimitiveType_Int32);
   347     if (!returnType)
   348         return false;
   349 
   350     Type *funtype = ZONE()->types()->newFunction(returnType, args);
   351     if (!funtype)
   352         return false;
   353 
   354     node->fun()->setType(funtype);
   355     return true;
   356 }
   357 
   358 void
   359 SemanticAnalysis::visit(FunctionStatement *node)
   360 {
   361     scope_ = node->scope();
   362 
   363     // :TODO: call this ahead of time.
   364     if (!preanalyze(node))
   365         return;
   366 
   367     node->body()->accept(this);
   368     scope_ = NULL;
   369 }
   370 
   371 // :TODO: use handles
   372 static inline bool
   373 TypeCheckParameter(Type *given, Type *actual)
   374 {
   375     if (actual->isReference()) {
   376         if (given->isReference())
   377             given = given->contained();
   378         return TypeCheck(given, actual->contained());
   379     }
   380 
   381     return TypeCheck(given, actual);
   382 }
   383 
   384 void
   385 SemanticAnalysis::visit(CallExpression *node)
   386 {
   387     visitForLoad(node->callee());
   388 
   389     // :TODO: use locals
   390     Type *type = node->callee()->type();
   391     if (!type)
   392         return;
   393 
   394     assert(type->isFunction());
   395     assert(node->arguments()->size() == type->parameters()->length());
   396 
   397     for (unsigned i = 0; i < node->arguments()->size(); i++) {
   398         Expression *expression = node->arguments()->at(i);
   399         expression->accept(this);
   400 
   401         Type *given = expression->type();
   402         if (!given)
   403             return;
   404 
   405         Type *actual = Type::cast(type->parameters()->at(i));
   406         assert(TypeCheckParameter(given, actual));
   407 
   408         // If the actual is a reference, and the given is not, we'll need to
   409         // compute a reference, which may be allocated on the stack.
   410         if (actual->isReference() && !given->isReference())
   411             scope_->setUsesLifoHeap();
   412     }
   413 }
   414 
   415 void
   416 SemanticAnalysis::visit(IfStatement *node)
   417 {
   418     visitForLoad(node->condition());
   419     node->ifTrue()->accept(this);
   420     if (node->ifFalse())
   421         node->ifFalse()->accept(this);
   422 }
   423 
   424 void
   425 SemanticAnalysis::visit(IndexExpression *node)
   426 {
   427     // :TODO: use locals
   428     Type *left = visitForRef(node->left());
   429     Type *right = visitForLoad(node->right());
   430 
   431     if (!right || !right->isInt()) {
   432         typeError(node->right(), "integer");
   433         return;
   434     }
   435     if (!left || !left->isArray() || !left->contained()->isPrimitive()) {
   436         typeError(node->left(), "array");
   437         return;
   438     }
   439     node->setType(left);
   440 }
   441 
   442 void
   443 SemanticAnalysis::visit(EnumStatement *node)
   444 {
   445     // :TODO: test "enum Float { ..."
   446     Name *tag = node->name();
   447 
   448     Type *type = ZONE()->types()->getPrimitiveForTag(tag);
   449     if (!type)
   450         return;
   451 
   452     int value = 0;
   453     for (size_t i = 0; i < node->entries()->size(); i++) {
   454         EnumStatement::Entry &entry = node->entries()->at(i);
   455 
   456         BoxedPrimitive box = BoxedPrimitive::Int(value);
   457         if (entry.expr) {
   458             entry.expr->accept(this);
   459             if (!EvaluateForConstant(entry.expr, &box))
   460                 fprintf(stderr, "expected constant integer expression\n");
   461 
   462             assert(box.type() == PrimitiveType_Int32);
   463             value = box.toInt();
   464         }
   465 
   466         entry.name->set(type, box);
   467         value++;
   468     }
   469 }
   470 
   471 void
   472 SemanticAnalysis::visit(FloatLiteral *node)
   473 {
   474     Type *type = ZONE()->types()->getPrimitive(PrimitiveType_Float);
   475     if (!type)
   476         return;
   477 
   478     node->setType(type);
   479 }
   480 
   481 void
   482 SemanticAnalysis::visit(BreakStatement *node)
   483 {
   484     assert(loopDepth_ > 0);
   485 }
   486 
   487 void
   488 SemanticAnalysis::visit(ContinueStatement *node)
   489 {
   490     assert(loopDepth_ > 0);
   491 }