jitcraft/SemanticAnalysis.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jun 28 00:54:45 2012 -0700 (2012-06-28)
changeset 9 73781c5a59d7
parent 8 069d207a8f2a
child 10 0c3bcd50e361
permissions -rw-r--r--
Added support for do/while loops.
     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 
    21 using namespace jc;
    22 
    23 static inline bool
    24 IsPrimitiveType(Type *type, PrimitiveType primitive)
    25 {
    26     if (!type)
    27         return false;
    28 
    29     if (!type->isPrimitive())
    30         return false;
    31 
    32     return primitive == type->primitive();
    33 }
    34 
    35 static inline bool
    36 EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
    37                         BoxedPrimitive *out)
    38 {
    39     switch (kind) {
    40       case TOK_PLUS:
    41         *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
    42         return true;
    43 
    44       case TOK_SHL:
    45         *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
    46         return true;
    47     }
    48 
    49     return true;
    50 }
    51 
    52 static bool
    53 EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
    54 {
    55     switch (expression->kind()) {
    56       case AstNode::kBinaryExpression:
    57       {
    58         BoxedPrimitive left;
    59         BoxedPrimitive right;
    60         BinaryExpression *b = expression->toBinaryExpression();
    61         if (!EvaluateForConstant(b->left(), &left) ||
    62             !EvaluateForConstant(b->right(), &right))
    63         {
    64             return false;
    65         }
    66         return EvaluateBinaryOperation(b->token(), left, right, out);
    67       }
    68 
    69       case AstNode::kNameProxy:
    70       {
    71         NameProxy *proxy = expression->toNameProxy();
    72         if (proxy->binding()->kind() != BoundName::CONSTANT)
    73             return false;
    74 
    75         NamedConstant *c = proxy->binding()->toNamedConstant();
    76         if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
    77             return false;
    78 
    79         *out = c->value();
    80         return true;
    81       }
    82 
    83       case AstNode::kIntegerLiteral:
    84         *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
    85         return true;
    86 
    87       default:
    88         return false;
    89     }
    90 }
    91 
    92 SemanticAnalysis::SemanticAnalysis(ParseTree *tree)
    93   : tree_(tree)
    94 {
    95 }
    96 
    97 bool
    98 SemanticAnalysis::analyze()
    99 {
   100     for (size_t i = 0; i < tree_->statements()->length(); i++) {
   101         Statement *statement = tree_->statements()->at(i);
   102         statement->accept(this);
   103     }
   104 
   105     return true;
   106 }
   107 
   108 void
   109 SemanticAnalysis::visit(NameProxy *name)
   110 {
   111     name->setType(name->binding()->type());
   112 }
   113 
   114 Type *
   115 SemanticAnalysis::visitForLoad(Expression *expression)
   116 {
   117     expression->accept(this);
   118     if (expression->type() && expression->type()->isArray())
   119         expression->setType(expression->type()->contained());
   120     return expression->type();
   121 }
   122 
   123 Type *
   124 SemanticAnalysis::visitForRef(Expression *expression)
   125 {
   126     expression->accept(this);
   127     return expression->type();
   128 }
   129 
   130 static inline bool
   131 TypeCheck(Type *left, Type *right)
   132 {
   133     if (!left || !right)
   134         return false;
   135 
   136     if (left->isPrimitive()) {
   137         if (!right->isPrimitive())
   138             return false;
   139         return left->primitive() == right->primitive();
   140     }
   141 
   142     return false;
   143 }
   144 
   145 void
   146 SemanticAnalysis::visit(Assignment *node)
   147 {
   148     visitForLoad(node->expression());
   149 
   150     if (node->lvalue()->isIndexExpression()) {
   151         node->lvalue()->accept(this);
   152         node->setType(node->lvalue()->type()->contained());
   153     } else {
   154         NameProxy *proxy = node->lvalue()->toNameProxy();
   155         if (!proxy->binding()->kind() == BoundName::VARIABLE) {
   156             fprintf(stderr, "error\n");
   157             return;
   158         }
   159 
   160         Variable *var = proxy->binding()->toVariable();
   161         node->setType(var->type());
   162     }
   163 
   164     assert(TypeCheck(node->type(), node->expression()->type()));
   165 }
   166 
   167 
   168 void
   169 SemanticAnalysis::visit(BinaryExpression *node)
   170 {
   171     Type *left = visitForLoad(node->left());
   172     Type *right = visitForLoad(node->right());
   173 
   174     if (node->token() >= TOK_PLUS && node->token() <= TOK_SLASH) {
   175         // Both sides must be primitive.
   176         if (!left || !right)
   177             return;
   178 
   179         // If either side is a float, the other side must be a float or int.
   180         if (left->isFloat() || right->isFloat()) {
   181             assert(left->isFloat() || left->isInt());
   182             assert(right->isFloat() || right->isInt());
   183             node->setType(left->isFloat() ? left : right);
   184             return;
   185         }
   186     }
   187 
   188     // For now, assert everything else is integer and untagged.
   189     assert(left->isInt() && right->isInt());
   190     assert(!left->tag() && !right->tag());
   191     node->setType(left);
   192 }
   193 
   194 void
   195 SemanticAnalysis::visit(ReturnStatement *node)
   196 {
   197     visitForLoad(node->expression());
   198 
   199     // :TODO: type check
   200 }
   201 
   202 void
   203 SemanticAnalysis::visit(ForStatement *node)
   204 {
   205     if (node->declaration())
   206         node->declaration()->accept(this);
   207     if (node->condition())
   208         visitForLoad(node->condition());
   209     if (node->update())
   210         node->update()->accept(this);
   211     node->body()->accept(this);
   212 }
   213 
   214 void 
   215 SemanticAnalysis::visit(WhileStatement *node)
   216 {
   217     node->condition()->accept(this);
   218     node->body()->accept(this);
   219 }
   220 
   221 void
   222 SemanticAnalysis::visit(BlockStatement *node)
   223 {
   224     for (size_t i = 0; i < node->statements()->length(); i++) {
   225         Statement *statement = node->statements()->at(i);
   226         statement->accept(this);
   227     }
   228 }
   229 
   230 void
   231 SemanticAnalysis::visit(VariableDeclaration *node)
   232 {
   233     Type *type = Type::NewPrimitive(node->tag());
   234     if (!type)
   235         return;
   236 
   237     if (node->postDimensions()) {
   238         if (node->postDimensions()->size() > Type::MAX_UNSAFE_ARRAY_DEPTH) {
   239             error();
   240             return;
   241         }
   242 
   243         for (size_t i = node->postDimensions()->size() - 1; i < node->postDimensions()->size(); i--) {
   244             Expression *expr = node->postDimensions()->at(i);
   245             visitForLoad(expr);
   246 
   247             if (!IsPrimitiveType(expr->type(), PrimitiveType_Int32)) {
   248                 typeError(expr, "integer");
   249                 return;
   250             }
   251 
   252             int size = -1;
   253             if (expr->isIntegerLiteral()) {
   254                 size = expr->toIntegerLiteral()->value();
   255                 if (size <= 0) {
   256                     error();
   257                     return;
   258                 }
   259                 if (size >= INT_MAX / sizeof(int)) {
   260                     error();
   261                     return;
   262                 }
   263             }
   264 
   265             type = Type::NewUnsafeArray(type, size);
   266         }
   267     } else {
   268         Type *right = visitForLoad(node->initialization());
   269         assert(TypeCheck(type, right));
   270     }
   271 
   272     node->variable()->setType(type);
   273 }
   274 
   275 void
   276 SemanticAnalysis::visit(IntegerLiteral *node)
   277 {
   278     Type *type = Type::NewPrimitive(NULL);
   279     node->setType(type);
   280 }
   281 
   282 void
   283 SemanticAnalysis::visit(ExpressionStatement *node)
   284 {
   285     node->expression()->accept(this);
   286 }
   287 
   288 void
   289 SemanticAnalysis::visit(FunctionStatement *node)
   290 {
   291     node->body()->accept(this);
   292 }
   293 
   294 void
   295 SemanticAnalysis::visit(CallExpression *node)
   296 {
   297 }
   298 
   299 void
   300 SemanticAnalysis::visit(IfStatement *node)
   301 {
   302 }
   303 
   304 void
   305 SemanticAnalysis::visit(IndexExpression *node)
   306 {
   307     Type *left = visitForRef(node->left());
   308     Type *right = visitForLoad(node->right());
   309 
   310     if (!right || !right->isInt()) {
   311         typeError(node->right(), "integer");
   312         return;
   313     }
   314     if (!left || !left->isArray() || !left->contained()->isPrimitive()) {
   315         typeError(node->left(), "array");
   316         return;
   317     }
   318     node->setType(left);
   319 }
   320 
   321 void
   322 SemanticAnalysis::visit(EnumStatement *node)
   323 {
   324     // :TODO: test "enum Float { ..."
   325     Name *tag = node->name();
   326 
   327     Type *type = Type::NewPrimitive(tag);
   328     if (!type)
   329         return;
   330 
   331     int value = 0;
   332     for (size_t i = 0; i < node->entries()->size(); i++) {
   333         EnumStatement::Entry &entry = node->entries()->at(i);
   334 
   335         BoxedPrimitive box = BoxedPrimitive::Int(value);
   336         if (entry.expr) {
   337             entry.expr->accept(this);
   338             if (!EvaluateForConstant(entry.expr, &box))
   339                 fprintf(stderr, "expected constant integer expression\n");
   340 
   341             assert(box.type() == PrimitiveType_Int32);
   342             value = box.toInt();
   343         }
   344 
   345         entry.name->set(type, box);
   346         value++;
   347     }
   348 }
   349 
   350 void
   351 SemanticAnalysis::visit(FloatLiteral *node)
   352 {
   353     Type *type = Type::NewPrimitive(PrimitiveType_Float);
   354     if (!type)
   355         return;
   356 
   357     node->setType(type);
   358 }