dvander@0: /* dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@0: * This file is part of JITCraft. dvander@0: * dvander@0: * JITCraft is free software: you can redistribute it and/or modify it under dvander@0: * the terms of the GNU General Public License as published by the Free dvander@0: * Software Foundation, either version 3 of the License, or (at your option) dvander@0: * any later version. dvander@0: * dvander@0: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY dvander@0: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@0: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@0: * dvander@0: * You should have received a copy of the GNU General Public License along with dvander@0: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@0: */ dvander@0: #include "SemanticAnalysis.h" dvander@0: #include "Types.h" dvander@11: #include "Zone.h" dvander@11: #include "TypeManager.h" dvander@12: #include "Scopes.h" dvander@0: dvander@0: using namespace jc; dvander@0: dvander@2: static inline bool dvander@2: IsPrimitiveType(Type *type, PrimitiveType primitive) dvander@2: { dvander@2: if (!type) dvander@2: return false; dvander@2: dvander@2: if (!type->isPrimitive()) dvander@2: return false; dvander@2: dvander@2: return primitive == type->primitive(); dvander@2: } dvander@2: dvander@2: static inline bool dvander@2: EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right, dvander@2: BoxedPrimitive *out) dvander@2: { dvander@2: switch (kind) { dvander@2: case TOK_PLUS: dvander@2: *out = BoxedPrimitive::Int(left.toInt() + right.toInt()); dvander@2: return true; dvander@2: dvander@2: case TOK_SHL: dvander@2: *out = BoxedPrimitive::Int(left.toInt() << right.toInt()); dvander@2: return true; dvander@2: } dvander@2: dvander@2: return true; dvander@2: } dvander@2: dvander@2: static bool dvander@2: EvaluateForConstant(Expression *expression, BoxedPrimitive *out) dvander@2: { dvander@2: switch (expression->kind()) { dvander@2: case AstNode::kBinaryExpression: dvander@2: { dvander@2: BoxedPrimitive left; dvander@2: BoxedPrimitive right; dvander@2: BinaryExpression *b = expression->toBinaryExpression(); dvander@2: if (!EvaluateForConstant(b->left(), &left) || dvander@2: !EvaluateForConstant(b->right(), &right)) dvander@2: { dvander@2: return false; dvander@2: } dvander@2: return EvaluateBinaryOperation(b->token(), left, right, out); dvander@2: } dvander@2: dvander@2: case AstNode::kNameProxy: dvander@2: { dvander@2: NameProxy *proxy = expression->toNameProxy(); dvander@2: if (proxy->binding()->kind() != BoundName::CONSTANT) dvander@2: return false; dvander@2: dvander@2: NamedConstant *c = proxy->binding()->toNamedConstant(); dvander@2: if (!IsPrimitiveType(c->type(), PrimitiveType_Int32)) dvander@2: return false; dvander@2: dvander@2: *out = c->value(); dvander@2: return true; dvander@2: } dvander@2: dvander@4: case AstNode::kIntegerLiteral: dvander@4: *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value()); dvander@2: return true; dvander@2: dvander@2: default: dvander@2: return false; dvander@2: } dvander@2: } dvander@2: dvander@25: SemanticAnalysis::SemanticAnalysis(CompileContext &cc, ParseTree *tree) dvander@25: : cc_(cc), dvander@25: tree_(tree), dvander@12: loopDepth_(0), dvander@12: scope_(NULL) dvander@0: { dvander@0: } dvander@0: dvander@0: bool dvander@0: SemanticAnalysis::analyze() dvander@0: { dvander@25: if (cc_.failures()) dvander@25: return false; dvander@25: dvander@25: for (size_t i = 0; i < tree_->statements()->length(); i++) { dvander@25: Statement *statement = tree_->statements()->at(i); dvander@25: if (statement->isFunctionStatement()) { dvander@25: FunctionStatement *funstmt = statement->toFunctionStatement(); dvander@25: if (!preanalyze(funstmt)) dvander@25: return false; dvander@25: } dvander@25: } dvander@25: dvander@0: for (size_t i = 0; i < tree_->statements()->length(); i++) { dvander@0: Statement *statement = tree_->statements()->at(i); dvander@0: statement->accept(this); dvander@0: } dvander@0: dvander@25: return !cc_.failures(); dvander@0: } dvander@0: dvander@25: Type * dvander@25: SemanticAnalysis::visitAndApplyType(Expression *expression) dvander@0: { dvander@25: expression->accept(this); dvander@25: return expression->type(); dvander@0: } dvander@0: dvander@7: Type * dvander@7: SemanticAnalysis::visitForLoad(Expression *expression) dvander@7: { dvander@25: // :TODO: use Local dvander@25: Type *type = visitAndApplyType(expression); dvander@25: if (!type) dvander@21: return NULL; dvander@21: dvander@21: if (type->isReference()) { dvander@21: expression->setType(type->contained()); dvander@21: } else if (expression->isIndexExpression()) { dvander@21: if (type->isArray()) dvander@14: expression->setType(type->contained()); dvander@14: } dvander@25: dvander@7: return expression->type(); dvander@7: } dvander@7: dvander@7: Type * dvander@7: SemanticAnalysis::visitForRef(Expression *expression) dvander@7: { dvander@7: expression->accept(this); dvander@7: return expression->type(); dvander@7: } dvander@7: dvander@25: static inline const char * dvander@25: GetTypeName(Type *type) dvander@4: { dvander@25: if (type->isArray()) dvander@25: return "array"; dvander@25: if (type->isFunction()) dvander@25: return "function"; dvander@25: if (type->isReference()) dvander@25: type = type->contained(); dvander@25: if (type->tag()) dvander@25: return type->tag(); dvander@25: return "int"; dvander@4: } dvander@4: dvander@25: void dvander@25: SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Type *type) dvander@21: { dvander@25: const char *op = TokenNames[token]; dvander@25: const char *name = GetTypeName(type); dvander@21: dvander@25: cc_.reportError(node->pos(), Message_UnaryTypeError, op, name); dvander@21: } dvander@21: dvander@25: void dvander@25: SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Type *left, Type *right) dvander@22: { dvander@25: const char *op = TokenNames[token]; dvander@25: const char *leftName = GetTypeName(left); dvander@25: const char *rightName = GetTypeName(right); dvander@22: dvander@25: cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName); dvander@25: } dvander@25: dvander@25: Type * dvander@25: SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Type *left, Type *right) dvander@25: { dvander@22: if ((token >= TOK_PLUS && token <= TOK_SLASH) || dvander@22: (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV)) dvander@22: { dvander@22: // If either side is a float, the other side must be a float or int. dvander@22: if (left->isFloat() || right->isFloat()) { dvander@25: Type *floatType = left->isFloat() ? left : right; dvander@25: Type *other = left->isFloat() ? right : left; dvander@25: if (other->isFloat() || (other->isInt32() && !other->tag())) dvander@25: return other; dvander@22: } dvander@22: } dvander@22: dvander@25: if ((!left->isInt32() || left->tag()) || dvander@25: (!right->isInt32() || right->tag())) dvander@25: { dvander@25: binaryTypeError(node, token, left, right); dvander@25: return NULL; dvander@25: } dvander@25: dvander@22: return left; dvander@22: } dvander@22: dvander@25: bool dvander@25: SemanticAnalysis::canTest(AstNode *node, Type *type) dvander@25: { dvander@25: if (type->isArray()) { dvander@25: cc_.reportError(node->pos(), Message_ArrayIsNotBoolean); dvander@25: return false; dvander@25: } dvander@25: return true; dvander@25: } dvander@25: dvander@23: Type * dvander@23: SemanticAnalysis::visitForLValue(Expression *expression) dvander@23: { dvander@23: if (expression->isIndexExpression()) { dvander@25: Type *type = visitAndApplyType(expression); dvander@25: if (!type) dvander@23: return NULL; dvander@25: dvander@25: return type->contained(); dvander@23: } dvander@23: dvander@23: if (!expression->isNameProxy()) { dvander@25: cc_.reportError(expression->pos(), Message_ExpectedLValue); dvander@23: return NULL; dvander@23: } dvander@23: dvander@23: NameProxy *proxy = expression->toNameProxy(); dvander@23: if (!proxy->binding()->kind() == BoundName::VARIABLE) { dvander@25: cc_.reportError(expression->pos(), Message_ExpectedLValue); dvander@23: return NULL; dvander@23: } dvander@23: dvander@23: Variable *var = proxy->binding()->toVariable(); dvander@23: if (!var->type()) dvander@23: return NULL; dvander@23: dvander@23: if (var->type()->isReference()) dvander@23: return var->type()->contained(); dvander@23: return var->type(); dvander@23: } dvander@23: dvander@0: void dvander@25: SemanticAnalysis::visit(NameProxy *name) dvander@25: { dvander@25: name->setType(name->binding()->type()); dvander@25: } dvander@25: dvander@25: void dvander@0: SemanticAnalysis::visit(Assignment *node) dvander@0: { dvander@25: Type *exprType = visitForLoad(node->expression()); dvander@25: if (!exprType) dvander@25: return ; dvander@0: dvander@23: // :TODO: use Local dvander@23: Type *type = visitForLValue(node->lvalue()); dvander@23: if (!type) dvander@23: return; dvander@4: dvander@25: if (node->token() != TOK_ASSIGN) { dvander@25: if (!typeCheckBinary(node, node->token(), type, exprType)) dvander@25: return; dvander@25: } dvander@22: dvander@25: if (!typeCheckAssignment(node, exprType, type, true)) dvander@25: return; dvander@25: dvander@25: node->setType(type); dvander@0: } dvander@0: dvander@0: void dvander@23: SemanticAnalysis::visit(IncDecExpression *node) dvander@23: { dvander@23: // :TODO: use Local dvander@23: Type *type = visitForLValue(node->expression()); dvander@23: if (!type) dvander@23: return; dvander@23: dvander@23: assert(!type->isReference()); dvander@25: dvander@25: if ((!type->isInt32() || (type->isInt32() && type->tag())) && !type->isFloat()) { dvander@25: unaryTypeError(node, node->token(), type); dvander@23: return; dvander@23: } dvander@23: dvander@23: node->setType(type); dvander@23: } dvander@23: dvander@23: void dvander@0: SemanticAnalysis::visit(BinaryExpression *node) dvander@0: { dvander@22: // :TODO: use Local dvander@7: Type *left = visitForLoad(node->left()); dvander@7: Type *right = visitForLoad(node->right()); dvander@25: if (!left || !right) dvander@25: return; dvander@4: dvander@25: Type *result = typeCheckBinary(node, node->token(), left, right); dvander@25: if (!result) dvander@25: return; dvander@25: dvander@22: node->setType(result); dvander@0: } dvander@0: dvander@0: void dvander@0: SemanticAnalysis::visit(ReturnStatement *node) dvander@0: { dvander@25: Type *type = visitForLoad(node->expression()); dvander@25: if (!type) dvander@25: return; dvander@0: dvander@25: if (!typeCheckAssignment(node, type, function_->returnType(), true)) dvander@25: return; dvander@0: } dvander@0: dvander@0: void dvander@0: SemanticAnalysis::visit(ForStatement *node) dvander@0: { dvander@10: loopDepth_++; dvander@12: if (node->scope()) dvander@12: scope_ = node->scope(); dvander@25: dvander@22: if (node->initialization()) dvander@22: node->initialization()->accept(this); dvander@25: dvander@25: if (node->condition()) { dvander@25: Type *type = visitForLoad(node->condition()); dvander@25: if (!type || !canTest(node->condition(), type)) { dvander@25: loopDepth_--; dvander@25: return; dvander@25: } dvander@25: } dvander@25: dvander@0: if (node->update()) dvander@0: node->update()->accept(this); dvander@25: dvander@0: node->body()->accept(this); dvander@25: dvander@12: if (node->scope()) dvander@12: scope_ = scope_->enclosing(); dvander@10: loopDepth_--; dvander@0: } dvander@0: dvander@9: void dvander@9: SemanticAnalysis::visit(WhileStatement *node) dvander@9: { dvander@10: loopDepth_++; dvander@25: dvander@25: Type *type = visitForLoad(node->condition()); dvander@25: if (!type || !canTest(node->condition(), type)) { dvander@25: loopDepth_--; dvander@25: return; dvander@25: } dvander@25: dvander@9: node->body()->accept(this); dvander@10: loopDepth_--; dvander@9: } dvander@9: dvander@0: void dvander@0: SemanticAnalysis::visit(BlockStatement *node) dvander@0: { dvander@12: if (node->scope()) dvander@12: scope_ = node->scope(); dvander@0: for (size_t i = 0; i < node->statements()->length(); i++) { dvander@0: Statement *statement = node->statements()->at(i); dvander@0: statement->accept(this); dvander@0: } dvander@12: if (node->scope()) dvander@12: scope_ = scope_->enclosing(); dvander@0: } dvander@0: dvander@0: void dvander@0: SemanticAnalysis::visit(VariableDeclaration *node) dvander@0: { dvander@14: // :TODO: use locals dvander@11: Type *type = ZONE()->types()->getPrimitiveForTag(node->tag()); dvander@0: if (!type) dvander@0: return; dvander@0: dvander@0: if (node->postDimensions()) { dvander@21: Type *init = NULL; dvander@21: if (node->initialization()) { dvander@25: if ((init = visitAndApplyType(node->initialization())) == NULL) dvander@21: return; dvander@21: } dvander@21: dvander@0: if (node->postDimensions()->size() > Type::MAX_UNSAFE_ARRAY_DEPTH) { dvander@25: cc_.reportError(node->pos(), Message_MaximumArrayDepth); dvander@0: return; dvander@0: } dvander@0: dvander@21: // If we have an initializer, make sure it's the same type. dvander@25: if (init && node->postDimensions()->size() != init->levels()) { dvander@25: cc_.reportError(node->pos(), Message_ArrayInitializerDepth); dvander@25: return; dvander@21: } dvander@21: dvander@21: Type *check = init; dvander@0: for (size_t i = node->postDimensions()->size() - 1; i < node->postDimensions()->size(); i--) { dvander@0: Expression *expr = node->postDimensions()->at(i); dvander@25: int size = -1; dvander@0: dvander@25: if (expr) { dvander@25: Type *exprType = visitForLoad(expr); dvander@25: if (!exprType) dvander@25: return; dvander@0: dvander@25: if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) { dvander@25: cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger); dvander@0: return; dvander@0: } dvander@25: dvander@25: BoxedPrimitive box; dvander@25: if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) { dvander@25: size = box.toInt(); dvander@25: if (size <= 0) { dvander@25: cc_.reportError(expr->pos(), Message_BadArraySize); dvander@25: return; dvander@25: } dvander@25: if (size >= INT_MAX / sizeof(int)) { dvander@25: cc_.reportError(expr->pos(), Message_ArraySizeTooBig); dvander@25: return; dvander@25: } dvander@25: dvander@25: if (check) { dvander@25: if (check->elements() == -1) { dvander@25: cc_.reportError(expr->pos(), Message_ArraySizeCannotBeDetermined); dvander@25: return; dvander@25: } dvander@25: dvander@25: if (check->isCharArray()) { dvander@25: if (check->elements() > size) { dvander@25: cc_.reportError(node->pos(), Message_ArrayAssignmentTooBig); dvander@25: return; dvander@25: } dvander@25: } else if (check->elements() != size) { dvander@25: cc_.reportError(node->pos(), Message_ArrayDimensionSizeMismatch, unsigned(i)); dvander@25: return; dvander@25: } dvander@25: } dvander@25: } else { dvander@25: if (init) { dvander@25: cc_.reportError(node->pos(), Message_DynamicArrayHasInitializer); dvander@25: return; dvander@25: } dvander@25: dvander@25: // here until we get dynamic array support. dvander@25: cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger); dvander@0: return; dvander@0: } dvander@21: } else { dvander@25: // Infer the size from the initializer. dvander@25: if (!init) { dvander@25: cc_.reportError(node->pos(), Message_ArraySizeNotSpecified); dvander@25: return; dvander@25: } dvander@25: if (init->elements() == -1) { dvander@25: cc_.reportError(node->pos(), Message_ArraySizeCannotBeDetermined); dvander@25: return; dvander@25: } dvander@25: size = init->elements(); dvander@0: } dvander@0: dvander@11: type = ZONE()->types()->unsafeArray(type, size); dvander@25: if (!type) dvander@25: return; dvander@21: dvander@21: if (check) dvander@21: check = check->contained(); dvander@0: } dvander@12: dvander@12: // Right now, any array is allowed on the LIFO heap. In case the dvander@12: // runtime actually decides to use the LIFO heap, we must reserve dvander@12: // a slot so we can unwind the heap when the current scope leaves. dvander@12: scope_->setUsesLifoHeap(); dvander@8: } else { dvander@10: if (node->initialization()) { dvander@10: Type *right = visitForLoad(node->initialization()); dvander@25: if (!right) dvander@25: return; dvander@25: if (!typeCheckAssignment(node, type, right, true)) dvander@25: return; dvander@10: } dvander@21: if (type->primitive() == PrimitiveType_Char) { dvander@25: cc_.reportError(node->pos(), Message_CannotDeclareStringCell); dvander@21: return; dvander@21: } dvander@0: } dvander@0: dvander@0: node->variable()->setType(type); dvander@0: } dvander@0: dvander@0: void dvander@4: SemanticAnalysis::visit(IntegerLiteral *node) dvander@0: { dvander@11: node->setType(ZONE()->types()->getPrimitive(PrimitiveType_Int32)); dvander@0: } dvander@0: dvander@0: void dvander@0: SemanticAnalysis::visit(ExpressionStatement *node) dvander@0: { dvander@0: node->expression()->accept(this); dvander@0: } dvander@0: dvander@14: bool dvander@14: SemanticAnalysis::preanalyze(FunctionStatement *node) dvander@14: { dvander@14: // :TODO: use Local dvander@14: dvander@14: FixedArray *args = FixedArray::New(ZONE(), node->parameters()->size(), Heap::Tenure_Old); dvander@14: if (!args) dvander@14: return false; dvander@14: dvander@14: // Apply types to arguments. dvander@14: for (size_t i = 0; i < node->parameters()->size(); i++) { dvander@14: Parameter *parameter = node->parameters()->at(i); dvander@14: dvander@14: Type *type = ZONE()->types()->getPrimitiveForTag(parameter->tag()); dvander@14: if (!type) dvander@14: return false; dvander@14: dvander@25: if (type->primitive() == PrimitiveType_Char) { dvander@25: cc_.reportError(node->pos(), Message_CannotDeclareStringCell); dvander@25: return false; dvander@25: } dvander@25: dvander@14: if (parameter->reference()) { dvander@14: type = ZONE()->types()->getReference(type); dvander@14: if (!type) dvander@14: return false; dvander@14: } dvander@14: dvander@14: args->set(ZONE(), i, type); dvander@14: parameter->variable()->setType(type); dvander@14: } dvander@14: dvander@14: Type *returnType = ZONE()->types()->getPrimitive(PrimitiveType_Int32); dvander@14: if (!returnType) dvander@14: return false; dvander@14: dvander@14: Type *funtype = ZONE()->types()->newFunction(returnType, args); dvander@14: if (!funtype) dvander@14: return false; dvander@14: dvander@14: node->fun()->setType(funtype); dvander@14: return true; dvander@14: } dvander@14: dvander@0: void dvander@0: SemanticAnalysis::visit(FunctionStatement *node) dvander@0: { dvander@25: function_ = node->fun()->type(); dvander@12: scope_ = node->scope(); dvander@0: node->body()->accept(this); dvander@12: scope_ = NULL; dvander@25: function_ = NULL; dvander@0: } dvander@0: dvander@25: bool dvander@25: SemanticAnalysis::typeCheckArrayAssignment(AstNode *node, Type *given, Type *actual, bool forAssign) dvander@14: { dvander@25: if (!given->isArray()) { dvander@25: cc_.reportError(node->pos(), Message_ExpectedArray); dvander@25: return false; dvander@25: } dvander@25: if (given->levels() != actual->levels()) { dvander@25: cc_.reportError(node->pos(), Message_ArrayDimensionsMismatch); dvander@25: return false; dvander@25: } dvander@25: dvander@25: unsigned level = 0; dvander@25: while (given->isArray()) { dvander@25: if (actual->elements() != -1) { dvander@25: if (forAssign) { dvander@25: if (given->elements() == -1 || actual->elements() == -1) { dvander@25: cc_.reportError(node->pos(), Message_ArraySizeNotKnown); dvander@25: return false; dvander@25: } dvander@25: dvander@25: if (actual->isCharArray()) { dvander@25: // String assignment can have a truncated |given|. dvander@25: if (given->elements() > actual->elements()) { dvander@25: cc_.reportError(node->pos(), Message_ArrayAssignmentTooBig); dvander@25: return false; dvander@25: } dvander@25: } else { dvander@25: if (given->elements() != actual->elements()) { dvander@25: cc_.reportError(node->pos(), Message_ArrayDimensionSizeMismatch, level); dvander@25: return false; dvander@25: } dvander@25: } dvander@25: } else { dvander@25: if (actual->elements() != -1 && given->elements() != actual->elements()) { dvander@25: cc_.reportError(node->pos(), Message_ArrayDimensionSizeMismatch, level); dvander@25: return false; dvander@25: } dvander@25: } dvander@25: } dvander@25: given = given->contained(); dvander@25: actual = actual->contained(); dvander@14: } dvander@14: dvander@25: if (given->primitive() != actual->primitive()) { dvander@25: const char *givenTag = given->tag() ? given->tag() : "_"; dvander@25: const char *actualTag = given->tag() ? given->tag() : "_"; dvander@25: cc_.reportError(node->pos(), Message_TagMismatch, actualTag, givenTag); dvander@25: return false; dvander@25: } dvander@25: dvander@25: return true; dvander@25: } dvander@25: dvander@25: bool dvander@25: SemanticAnalysis::typeCheckAssignment(AstNode *node, Type *given, Type *actual, bool forAssign) dvander@25: { dvander@25: if (actual->isArray()) dvander@25: return typeCheckArrayAssignment(node, given, actual, forAssign); dvander@25: dvander@25: if (given->isArray()) { dvander@25: cc_.reportError(node->pos(), Message_CannotAssignArrayToScalar); dvander@25: return false; dvander@25: } dvander@25: dvander@25: if (!given->isPrimitive() || !actual->primitive()) { dvander@25: cc_.reportError(node->pos(), Message_UnsupportedType); dvander@25: return false; dvander@25: } dvander@25: dvander@25: // The given type may not have been dereferenced. dvander@25: if (given->isReference()) dvander@25: given = given->contained(); dvander@25: if (actual->isReference()) dvander@25: actual = given->contained(); dvander@25: dvander@25: if (given->primitive() != actual->primitive()) { dvander@25: const char *givenTag = given->tag() ? given->tag() : "_"; dvander@25: const char *actualTag = given->tag() ? given->tag() : "_"; dvander@25: cc_.reportError(node->pos(), Message_TagMismatch, actualTag, givenTag); dvander@25: return false; dvander@25: } dvander@25: dvander@25: return true; dvander@25: } dvander@25: dvander@25: bool dvander@25: SemanticAnalysis::typeCheckParameter(AstNode *node, Type *given, Type *actual) dvander@25: { dvander@25: return typeCheckAssignment(node, given, actual, false); dvander@14: } dvander@14: dvander@0: void dvander@0: SemanticAnalysis::visit(CallExpression *node) dvander@0: { dvander@25: Type *type = visitForLoad(node->callee()); dvander@14: if (!type) dvander@14: return; dvander@14: dvander@25: if (!type->isFunction()) { dvander@25: cc_.reportError(node->pos(), Message_CalleeNotFunction); dvander@25: return; dvander@25: } dvander@25: if (node->arguments()->size() != type->parameters()->length()) { dvander@25: cc_.reportError(node->pos(), Message_ArgumentCountMismatch); dvander@25: return; dvander@25: } dvander@14: dvander@14: for (unsigned i = 0; i < node->arguments()->size(); i++) { dvander@17: // Note: we don't compute references unless the callee needs a dvander@17: // reference type. dvander@14: Expression *expression = node->arguments()->at(i); dvander@25: Type *given = visitAndApplyType(expression); dvander@14: if (!given) dvander@14: return; dvander@14: dvander@17: // If it's an IndexExpression, we special case the ability to compute dvander@25: // a reference. dvander@17: if (expression->isIndexExpression()) dvander@17: given = given->contained(); dvander@17: dvander@25: Type *actual = type->parameterAt(i); dvander@25: if (!typeCheckParameter(expression, given, actual)) dvander@25: return; dvander@14: dvander@14: // If the actual is a reference, and the given is not, we'll need to dvander@14: // compute a reference, which may be allocated on the stack. dvander@14: if (actual->isReference() && !given->isReference()) dvander@14: scope_->setUsesLifoHeap(); dvander@14: } dvander@0: } dvander@0: dvander@0: void dvander@0: SemanticAnalysis::visit(IfStatement *node) dvander@0: { dvander@25: Type *type = visitForLoad(node->condition()); dvander@25: if (!type) dvander@25: return; dvander@25: dvander@25: if (!canTest(node, type)) dvander@25: return; dvander@25: dvander@10: node->ifTrue()->accept(this); dvander@10: if (node->ifFalse()) dvander@10: node->ifFalse()->accept(this); dvander@0: } dvander@0: dvander@0: void dvander@0: SemanticAnalysis::visit(IndexExpression *node) dvander@0: { dvander@14: // :TODO: use locals dvander@7: Type *left = visitForRef(node->left()); dvander@7: Type *right = visitForLoad(node->right()); dvander@0: dvander@25: if (!left || !right) dvander@25: return; dvander@25: dvander@25: if (!right->isInt32()) { dvander@25: cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger); dvander@0: return; dvander@0: } dvander@25: if (!left->isArray()) { dvander@25: cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray); dvander@0: return; dvander@0: } dvander@7: node->setType(left); dvander@0: } dvander@2: dvander@2: void dvander@2: SemanticAnalysis::visit(EnumStatement *node) dvander@2: { dvander@25: // Forbid the blessed types. dvander@4: Name *tag = node->name(); dvander@25: if (!strcmp(tag, "Float") || dvander@25: !strcmp(tag, "String") || dvander@25: !strcmp(tag, "any") || dvander@25: !strcmp(tag, "bool")) dvander@25: { dvander@25: cc_.reportError(node->pos(), Message_InvalidEnumName); dvander@25: return; dvander@25: } dvander@3: dvander@11: Type *type = ZONE()->types()->getPrimitiveForTag(tag); dvander@2: if (!type) dvander@2: return; dvander@2: dvander@2: int value = 0; dvander@2: for (size_t i = 0; i < node->entries()->size(); i++) { dvander@2: EnumStatement::Entry &entry = node->entries()->at(i); dvander@2: dvander@2: BoxedPrimitive box = BoxedPrimitive::Int(value); dvander@2: if (entry.expr) { dvander@2: entry.expr->accept(this); dvander@25: if (!EvaluateForConstant(entry.expr, &box)) { dvander@25: cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant); dvander@25: return; dvander@25: } dvander@2: dvander@2: assert(box.type() == PrimitiveType_Int32); dvander@2: value = box.toInt(); dvander@2: } dvander@2: dvander@2: entry.name->set(type, box); dvander@2: value++; dvander@2: } dvander@2: } dvander@4: dvander@4: void dvander@21: SemanticAnalysis::visit(StringLiteral *node) dvander@21: { dvander@21: Type *type = ZONE()->types()->getPrimitive(PrimitiveType_Char); dvander@21: if (!type) dvander@21: return; dvander@21: dvander@21: type = Type::NewArray(ZONE(), type, node->string()->length() + 1, true); dvander@21: if (!type) dvander@21: return; dvander@21: dvander@21: node->setType(type); dvander@21: } dvander@21: dvander@21: void dvander@4: SemanticAnalysis::visit(FloatLiteral *node) dvander@4: { dvander@11: Type *type = ZONE()->types()->getPrimitive(PrimitiveType_Float); dvander@4: if (!type) dvander@4: return; dvander@4: dvander@4: node->setType(type); dvander@4: } dvander@10: dvander@10: void dvander@10: SemanticAnalysis::visit(BreakStatement *node) dvander@10: { dvander@25: if (loopDepth_ == 0) dvander@25: cc_.reportError(node->pos(), Message_BreakOutsideLoop); dvander@10: } dvander@10: dvander@10: void dvander@10: SemanticAnalysis::visit(ContinueStatement *node) dvander@10: { dvander@25: if (loopDepth_ == 0) dvander@25: cc_.reportError(node->pos(), Message_ContinueOutsideLoop); dvander@10: }