dvander@30: /* vim: set ts=4 sw=4 tw=99 et: dvander@30: * 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: */ danderson@92: #include 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@85: #include "NameBinding.h" dvander@168: #include "Strings.h" dvander@168: #include "Box.h" dvander@169: #include "Array.h" dvander@28: #include "Heap-inl.h" dvander@0: dvander@59: using namespace ke; 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@28: dvander@28: default: dvander@47: return false; dvander@2: } dvander@2: } dvander@2: dvander@144: static inline bool dvander@144: EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out) dvander@144: { dvander@144: switch (kind) { dvander@144: case TOK_MINUS: dvander@144: *out = BoxedPrimitive::Int(-inner.toInt()); dvander@144: return true; dvander@144: dvander@144: default: dvander@144: return false; dvander@144: } dvander@144: } dvander@144: 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@144: case AstNode::kUnaryExpression: dvander@144: { dvander@144: BoxedPrimitive inner; dvander@144: UnaryExpression *u = expression->toUnaryExpression(); dvander@144: if (!EvaluateForConstant(u->expression(), &inner)) dvander@144: return false; dvander@144: return EvaluateUnaryOperation(u->token(), inner, out); dvander@144: } dvander@144: 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@168: case AstNode::kBooleanLiteral: dvander@172: *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0); dvander@168: return true; dvander@168: 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@30: SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree) dvander@30: : zone_(zone), dvander@30: cc_(cc), dvander@25: tree_(tree), dvander@71: scope_(NULL), dvander@71: loop_(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@85: scope_ = tree_->scope(); dvander@85: 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@145: } else if (statement->isEnumStatement()) { dvander@145: EnumStatement *enumstmt = statement->toEnumStatement(); dvander@145: dvander@145: // We pre-fill global enum types, since they may occur in function dvander@145: // signatures. This should probably be somewhere else... dvander@172: enumstmt->accept(this); dvander@146: } else if (statement->isStructureStatement()) { dvander@147: StructureStatement *node = statement->toStructureStatement(); dvander@147: node->accept(this); dvander@147: if (!node->decl()->type()) dvander@147: return false; dvander@174: } else if (statement->isFunctionTypeStatement()) { dvander@174: FunctionTypeStatement *node = statement->toFunctionTypeStatement(); dvander@174: node->accept(this); dvander@174: if (!node->decl()->type()) dvander@174: 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@172: dvander@172: // We can't double-process these. Maybe put this check somewhere else. dvander@172: if (statement->isEnumStatement()) dvander@172: continue; dvander@172: dvander@0: statement->accept(this); dvander@0: } dvander@0: dvander@137: if (!determineLiveFunctions()) dvander@137: return false; dvander@137: dvander@25: return !cc_.failures(); dvander@0: } dvander@0: dvander@137: bool dvander@137: SemanticAnalysis::determineLiveFunctions() dvander@137: { dvander@137: Vector worklist; dvander@137: dvander@137: // Add the root set. dvander@137: for (size_t i = 0; i < tree_->statements()->length(); i++) { dvander@137: Statement *statement = tree_->statements()->at(i); dvander@137: if (!statement->isFunctionStatement()) dvander@137: continue; dvander@137: dvander@137: FunctionStatement *stmt = statement->toFunctionStatement(); dvander@137: NamedFunction *fun = stmt->fun(); dvander@137: if (!fun->used()) dvander@137: continue; dvander@137: dvander@137: for (size_t i = 0; i < fun->usedGlobals()->length(); i++) { dvander@137: NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction(); dvander@137: dvander@137: // Names in these lists are always unused, however, we mark them dvander@137: // as used while inserting into the work queue, to avoid double- dvander@137: // insertion. dvander@137: if (name->used()) dvander@137: continue; dvander@137: dvander@137: if (!worklist.append(name)) dvander@137: return false; dvander@137: dvander@137: name->setUsed(); dvander@137: } dvander@137: } dvander@137: dvander@137: while (!worklist.empty()) { dvander@137: NamedFunction *fun = worklist.popCopy(); dvander@137: dvander@137: for (size_t i = 0; i < fun->usedGlobals()->length(); i++) { dvander@137: NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction(); dvander@137: if (name->used()) dvander@137: continue; dvander@137: if (!worklist.append(name)) dvander@137: return false; dvander@137: name->setUsed(); dvander@137: } dvander@137: } dvander@137: dvander@137: return true; dvander@137: } dvander@137: dvander@145: Type * dvander@145: SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name) dvander@145: { dvander@145: if (!name) dvander@145: return zone_->types()->getPrimitive(PrimitiveType_Int32); dvander@145: dvander@145: if (name->kind() == BoundName::UNBOUND) { dvander@145: cc_.reportError(pos, Message_TypeNotFound, name->name()->chars()); dvander@145: return NULL; dvander@145: } dvander@145: dvander@145: if (name->kind() != BoundName::TYPE) { dvander@145: cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars()); dvander@145: return NULL; dvander@145: } dvander@145: dvander@145: if (!name->type()) dvander@145: return NULL; dvander@145: dvander@145: return name->type(); dvander@145: } dvander@137: 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@40: Local type(zone_, visitAndApplyType(expression)); dvander@25: if (!type) dvander@21: return NULL; dvander@21: dvander@21: if (type->isReference()) { dvander@21: expression->setType(type->contained()); dvander@71: } else if (expression->isCallExpression()) { dvander@71: if (type->isVoid()) { dvander@71: CallExpression *call = expression->toCallExpression(); dvander@71: cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue); dvander@71: return NULL; dvander@71: } dvander@14: } dvander@25: dvander@7: return expression->type(); dvander@7: } dvander@7: dvander@54: // :TODO: this leaks an interior pointer. dvander@145: const char * dvander@145: ke::GetTypeName(Type *type) dvander@4: { dvander@25: if (type->isArray()) dvander@25: return "array"; dvander@25: if (type->isFunction()) dvander@25: return "function"; dvander@129: if (type->isVoid()) dvander@129: return "void"; dvander@147: if (type->isEnum() || type->isStruct()) dvander@145: return type->name()->chars(); dvander@25: if (type->isReference()) dvander@25: type = type->contained(); dvander@145: switch (type->primitive()) { dvander@145: case PrimitiveType_Bool: dvander@145: return "bool"; dvander@145: case PrimitiveType_Char: dvander@145: return "String"; dvander@145: case PrimitiveType_Int32: dvander@145: return "int"; dvander@145: case PrimitiveType_Float: dvander@148: return "Float"; dvander@145: default: dvander@145: return ""; dvander@145: } dvander@4: } dvander@4: dvander@25: void dvander@40: SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle 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@40: SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle left, Handle 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@40: SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle left, Handle 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@145: if (other->isFloat() || other->isInt32()) dvander@28: return floatType; dvander@22: } dvander@22: } dvander@22: dvander@79: if (token == TOK_OR || token == TOK_AND) { dvander@79: if (!canTest(node, left) || !canTest(node, right)) dvander@79: return NULL; dvander@145: return zone_->types()->getPrimitive(PrimitiveType_Bool); dvander@79: } dvander@79: dvander@79: if (token >= TOK_EQUALS && token <= TOK_GE) { dvander@145: if ((left->isFloat() || left->isInt32()) && dvander@145: (right->isFloat() || right->isInt32())) dvander@74: { dvander@145: return zone_->types()->getPrimitive(PrimitiveType_Bool); dvander@74: } dvander@74: binaryTypeError(node, token, left, right); dvander@74: return NULL; dvander@74: } dvander@74: dvander@145: if (!left->isInt32() || !right->isInt32()) { 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@40: SemanticAnalysis::canTest(AstNode *node, Handle type) dvander@25: { dvander@145: if (!type->isPrimitive() && !type->isEnum()) { 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@154: // if (type->isConst()) { dvander@154: // cc_.reportError(expression->pos(), Message_ReferenceIsConstant); dvander@154: // return NULL; dvander@154: // } dvander@67: dvander@150: return type; dvander@23: } dvander@23: dvander@148: if (expression->isFieldExpression()) { dvander@148: Type *type = visitAndApplyType(expression); dvander@148: if (!type) dvander@148: return NULL; dvander@148: dvander@148: // if (expression->toFieldExpression()->left()->type()->isConst()) { dvander@148: // cc_.reportError(expression->pos(), Message_ReferenceIsConstant); dvander@148: // return NULL; dvander@148: // } dvander@148: dvander@148: return type; dvander@148: } dvander@148: 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@67: if (var->type()->isReference()) { dvander@67: if (var->type()->isConst()) { dvander@67: cc_.reportError(expression->pos(), Message_ReferenceIsConstant); dvander@67: return NULL; dvander@67: } dvander@23: return var->type()->contained(); dvander@67: } dvander@23: return var->type(); dvander@23: } dvander@23: dvander@71: SemanticAnalysis::ControlStatus dvander@71: SemanticAnalysis::visitForControl(Statement *statement) dvander@71: { dvander@71: ControlScope scope(&control_); dvander@71: statement->accept(this); dvander@71: return scope.status(); dvander@71: } dvander@71: dvander@0: void dvander@25: SemanticAnalysis::visit(NameProxy *name) dvander@25: { dvander@137: BoundName *binding = name->binding(); dvander@137: dvander@137: if (binding->scope()->kind() == Scope::GLOBAL) { dvander@137: if (!function_ || function_->isPublic()) { dvander@137: // Whatever we're referencing must be kept alive no matter what. dvander@137: // As such, we simply mark it used, and don't do anything special. dvander@137: binding->setUsed(); dvander@137: } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) { dvander@137: // Otherwise, we're inside a normal stock or function. Since we dvander@137: // don't really know if we've been used yet, we shouldn't dvander@137: // prematurely references as alive. Instead, we keep a list of dvander@137: // which names have been used, so we can mark them later if needed. dvander@137: // dvander@137: // Note that we skip this step if the binding is already in the dvander@137: // root set. dvander@137: if (!function_->addUsedGlobal(binding)) dvander@137: return; dvander@137: } dvander@137: } dvander@137: dvander@137: name->setType(binding->type()); dvander@25: } dvander@25: dvander@25: void dvander@0: SemanticAnalysis::visit(Assignment *node) dvander@0: { dvander@40: Local exprType(zone_, visitForLoad(node->expression())); dvander@25: if (!exprType) dvander@25: return ; dvander@0: dvander@40: Local type(zone_, 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@168: if (!typeCheckAssignment(node->pos(), 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@40: Local type(zone_, visitForLValue(node->expression())); dvander@23: if (!type) dvander@23: return; dvander@23: dvander@23: assert(!type->isReference()); dvander@25: dvander@145: if (!type->isInt32() && !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@78: SemanticAnalysis::visit(UnaryExpression *node) dvander@78: { dvander@78: Local type(zone_, visitForLoad(node->expression())); dvander@78: if (!type) dvander@78: return; dvander@78: dvander@78: switch (node->token()) dvander@78: { dvander@79: case TOK_NOT: dvander@79: if (!canTest(node->expression(), type)) dvander@79: return; dvander@79: type = zone_->types()->getPrimitive(PrimitiveType_Int32); dvander@79: if (!type) dvander@79: return; dvander@79: node->setType(type); dvander@79: break; dvander@79: dvander@80: case TOK_MINUS: dvander@145: if (!type->isFloat() && !type->isInt32()) { dvander@80: unaryTypeError(node, node->token(), type); dvander@80: return; dvander@80: } dvander@80: node->setType(type); dvander@80: break; dvander@80: dvander@142: case TOK_LABEL: dvander@142: { dvander@145: Local to(zone_, bindType(node->pos(), node->type())); dvander@142: if (!to) dvander@142: return; dvander@142: dvander@145: if ((!type->isFloat() && !type->isInt32OrEnum()) || dvander@145: (!to->isFloat() && !to->isInt32OrEnum())) dvander@142: { dvander@142: unaryTypeError(node, node->token(), type); dvander@142: return; dvander@142: } dvander@142: dvander@142: node->setType(to); dvander@142: break; dvander@142: } dvander@142: dvander@78: default: dvander@78: assert(node->token() == TOK_TILDE); dvander@145: if (!type->isInt32()) { dvander@78: unaryTypeError(node, node->token(), type); dvander@78: return; dvander@78: } dvander@78: node->setType(type); dvander@78: break; dvander@78: } dvander@78: } dvander@78: dvander@78: void dvander@83: SemanticAnalysis::visit(TernaryExpression *node) dvander@83: { dvander@83: Local type(zone_, visitForLoad(node->condition())); dvander@83: if (!type) dvander@83: return; dvander@83: dvander@83: if (!canTest(node->condition(), type)) dvander@83: return; dvander@83: dvander@83: Local left(zone_, visitForLoad(node->left())); dvander@83: Local right(zone_, visitForLoad(node->right())); dvander@83: if (!left || !right) dvander@83: return; dvander@83: dvander@83: if (left != right) { dvander@83: binaryTypeError(node, TOK_QMARK, left, right); dvander@83: return; dvander@83: } dvander@83: } dvander@83: dvander@83: void dvander@0: SemanticAnalysis::visit(BinaryExpression *node) dvander@0: { dvander@40: Local left(zone_, visitForLoad(node->left())); dvander@40: Local right(zone_, visitForLoad(node->right())); dvander@25: if (!left || !right) dvander@25: return; dvander@4: dvander@40: Local result(zone_, 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@71: // Set this early, so if we error we don't get more errors. dvander@71: control_->returns(Returns_Always); dvander@71: dvander@72: if (!node->expression()) { dvander@137: if (!function_->type()->returnType()->isVoid()) dvander@72: cc_.reportError(node->pos(), Message_NotAllPathsReturnValue); dvander@72: return; dvander@72: } dvander@72: dvander@40: Local type(zone_, visitForLoad(node->expression())); dvander@25: if (!type) dvander@25: return; dvander@0: dvander@137: Local returnType(zone_, function_->type()->returnType()); dvander@168: if (!typeCheckAssignment(node->pos(), type, returnType, true)) dvander@25: return; dvander@0: } dvander@0: dvander@0: void dvander@0: SemanticAnalysis::visit(ForStatement *node) dvander@0: { dvander@71: LoopScope loop(&loop_); dvander@71: 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@40: Local type(zone_, visitForLoad(node->condition())); dvander@25: if (!type || !canTest(node->condition(), type)) { dvander@25: return; dvander@25: } dvander@25: } dvander@25: dvander@0: if (node->update()) dvander@0: node->update()->accept(this); dvander@25: dvander@71: ControlStatus status = visitForControl(node->body()); dvander@71: dvander@71: // If there is a condition, we treat this like a while loop. Otherwise, dvander@71: // join point is only reachable if the loop contains a break. The dvander@71: // termination status doesn't tell us anything yet. dvander@71: if (node->condition() || loop.breaks()) dvander@71: control_->merge(status, ControlStatus(false, Returns_Never)); dvander@71: else dvander@71: control_->terminate(status.returns()); dvander@25: dvander@12: if (node->scope()) dvander@12: scope_ = scope_->enclosing(); dvander@0: } dvander@0: dvander@9: void dvander@9: SemanticAnalysis::visit(WhileStatement *node) dvander@9: { dvander@71: LoopScope loop(&loop_); dvander@25: dvander@40: Local type(zone_, visitForLoad(node->condition())); dvander@25: if (!type || !canTest(node->condition(), type)) { dvander@25: return; dvander@25: } dvander@25: dvander@71: ControlStatus status = visitForControl(node->body()); dvander@71: dvander@71: // Detect loops that will always have a fork in the control-flow graph. dvander@71: // This will be a |while| loop, or a |do-while| loop whose body does dvander@71: // not terminate. dvander@71: // dvander@71: // For now, we treat these as an |if| regardless of the direction the dvander@71: // branch can take. That means the control-flow is always conditional. dvander@71: if (node->token() == TOK_WHILE || dvander@71: !status.terminates() || dvander@71: loop.breaks()) dvander@71: { dvander@71: control_->merge(status, ControlStatus(false, Returns_Never)); dvander@71: } else { dvander@71: // At this point, we've got a do-while loop with a |return| or dvander@71: // |continue|, meaning that the rest of the block is unreachable. dvander@71: control_->terminate(status.returns()); dvander@71: } 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@145: static inline bool dvander@145: IsScalarString(Type *type) dvander@145: { dvander@145: if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) dvander@145: return true; dvander@145: if (type->isReference()) dvander@145: return IsScalarString(type->contained()); dvander@145: return false; dvander@145: } dvander@145: dvander@187: static const int INFER_ARRAY_SIZE = 0; dvander@187: static const int EVAL_ARRAY_SIZE = -1; dvander@187: static const int DYNAMIC_ARRAY_SIZE = -2; dvander@187: dvander@187: bool dvander@187: SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]) dvander@187: { dvander@187: for (size_t i = 0; i < exprs->length(); i++) { dvander@187: Expression *expr = exprs->at(i); dvander@187: if (!expr) { dvander@187: dims[i] = INFER_ARRAY_SIZE; dvander@187: continue; dvander@187: } dvander@187: dvander@187: BoxedPrimitive box; dvander@187: if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) { dvander@187: int size = box.toInt(); dvander@187: if (size <= 0) { dvander@187: cc_.reportError(expr->pos(), Message_BadArraySize); dvander@187: return false; dvander@187: } dvander@187: dvander@187: dims[i] = size; dvander@187: continue; dvander@187: } dvander@187: dvander@187: Local exprType(zone_, visitForLoad(expr)); dvander@187: if (!exprType) dvander@187: return false; dvander@187: dvander@187: if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) { dvander@187: cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger); dvander@187: return false; dvander@187: } dvander@187: dvander@187: dims[i] = EVAL_ARRAY_SIZE; dvander@187: } dvander@187: dvander@187: return true; dvander@187: } dvander@187: dvander@187: bool dvander@187: SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle contained, dvander@187: int dims[MAX_ARRAY_DEPTH], dvander@187: unsigned dimcount, unsigned level) dvander@187: { dvander@187: if (dims[level] == EVAL_ARRAY_SIZE) { dvander@187: cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray); dvander@187: return false; dvander@187: } dvander@187: dvander@187: if (dims[level] == INFER_ARRAY_SIZE) { dvander@187: // Strings always become dynamic arrays. dvander@187: if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char)) dvander@187: dims[level] = literal->expressions()->length(); dvander@187: } else if (dims[level] == DYNAMIC_ARRAY_SIZE) { dvander@187: cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray); dvander@187: return false; dvander@187: } else { dvander@187: if (literal->expressions()->length() != unsigned(dims[level])) { dvander@187: cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1); dvander@187: return false; dvander@187: } dvander@187: } dvander@187: dvander@187: if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) { dvander@187: for (size_t i = 0; i < literal->expressions()->length(); i++) { dvander@187: Expression *expr = literal->expressions()->at(i); dvander@187: if (!expr->isStringLiteral()) { dvander@187: cc_.reportError(expr->pos(), Message_ExpectedStringLiteral); dvander@187: return false; dvander@187: } dvander@187: dvander@187: StringLiteral *lit = expr->toStringLiteral(); dvander@187: if (dims[level + 1] > 0 && dvander@187: unsigned(dims[level]) < lit->string()->length()) dvander@187: { dvander@187: cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2); dvander@187: return false; dvander@187: } dvander@187: if (!visitAndApplyType(lit)) dvander@187: return false; dvander@187: } dvander@187: } else if (level == dimcount - 1) { dvander@187: Local type(zone_); dvander@187: for (size_t i = 0; i < literal->expressions()->length(); i++) { dvander@187: Expression *expr = literal->expressions()->at(i); dvander@187: if (expr->isArrayLiteral()) { dvander@187: cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch); dvander@187: return false; dvander@187: } dvander@187: dvander@187: if ((type = visitAndApplyType(expr)) == NULL) dvander@187: return false; dvander@187: dvander@187: if (!typeCheckAssignment(expr->pos(), type, contained, true)) dvander@187: return false; dvander@187: } dvander@187: } else { dvander@187: for (size_t i = 0; i < literal->expressions()->length(); i++) { dvander@187: Expression *expr = literal->expressions()->at(i); dvander@187: if (!expr->isArrayLiteral()) { dvander@187: cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch); dvander@187: return false; dvander@187: } dvander@187: dvander@187: assert(expr->toArrayLiteral()->isFixed()); dvander@187: dvander@187: if (!inferFixedArrayLiteral(expr->toArrayLiteral(), dvander@187: contained, dvander@187: dims, dvander@187: dimcount, dvander@187: level + 1)) dvander@187: { dvander@187: return false; dvander@187: } dvander@187: } dvander@187: } dvander@187: dvander@187: return true; dvander@187: } dvander@187: dvander@0: void dvander@0: SemanticAnalysis::visit(VariableDeclaration *node) dvander@0: { dvander@145: Local type(zone_, bindType(node->pos(), node->type())); dvander@0: if (!type) dvander@0: return; dvander@0: dvander@187: if (node->postDimensions() || type->isArray()) { dvander@187: // The type could be an array type, so sum the type and postDimensions dvander@187: // together. dvander@187: unsigned dimcount = node->postDimensions()->length(); dvander@187: if (type->isArray()) dvander@187: dimcount += type->levels(); dvander@187: if (dimcount > MAX_ARRAY_DEPTH) { dvander@25: cc_.reportError(node->pos(), Message_MaximumArrayDepth); dvander@0: return; dvander@0: } dvander@0: dvander@187: // Take an initial guess at the array dimension sizes. dvander@187: int dims[MAX_ARRAY_DEPTH]; dvander@187: if (!evaluateDimensions(node->postDimensions(), dims)) dvander@25: return; dvander@187: dvander@187: // Now add in the type's array dimensions. dvander@187: Local contained(zone_, type); dvander@187: for (size_t i = node->postDimensions()->length(); i < dimcount; i++) { dvander@187: if (type->isFixedLength()) dvander@187: dims[i] = type->fixedLength(); dvander@187: else dvander@187: dims[i] = DYNAMIC_ARRAY_SIZE; dvander@187: contained = contained->contained(); dvander@21: } dvander@21: dvander@187: Expression *initializer = node->initialization(); dvander@187: if (initializer && dvander@187: initializer->isArrayLiteral() && dvander@187: initializer->toArrayLiteral()->isFixed()) dvander@187: { dvander@187: // Fixed array initializers are special; we use them to infer any dvander@187: // missing information in the original array. We do not evaluate dvander@187: // the array initializer as an expression. dvander@187: if (!inferFixedArrayLiteral(initializer->toArrayLiteral(), dvander@187: contained, dvander@187: dims, dvander@187: dimcount, dvander@187: 0)) dvander@187: { dvander@187: return; dvander@187: } dvander@187: initializer = NULL; dvander@187: } dvander@25: dvander@187: // We now have enough information to build the actual array type. dvander@187: // Start from the original dimcount, not the one computed for dvander@187: // initializers. dvander@187: for (size_t i = node->postDimensions()->length() - 1; dvander@187: i < node->postDimensions()->length(); dvander@187: i--) dvander@187: { dvander@187: int size = dims[i] > 0 dvander@187: ? dims[i] dvander@187: : Type::DYNAMIC_ARRAY_SIZE; dvander@0: dvander@185: type = zone_->types()->newArray(type, size, false); dvander@25: if (!type) dvander@25: return; dvander@187: } dvander@21: dvander@187: // Finally, if we had a non-fixed initializer, make sure it type dvander@187: // checks. dvander@187: if (initializer) { dvander@187: Local right(zone_, visitForLoad(initializer)); dvander@187: if (!right) dvander@187: return; dvander@187: dvander@187: if (!typeCheckAssignment(node->pos(), right, type, true)) dvander@187: return; dvander@0: } dvander@8: } else { dvander@10: if (node->initialization()) { dvander@40: Local right(zone_, visitForLoad(node->initialization())); dvander@25: if (!right) dvander@25: return; dvander@187: if (!typeCheckAssignment(node->pos(), right, type, true)) dvander@25: return; dvander@10: } dvander@147: dvander@147: if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) { dvander@25: cc_.reportError(node->pos(), Message_CannotDeclareStringCell); dvander@21: return; dvander@21: } dvander@0: } dvander@0: dvander@147: // If this variable is stack allocated, we could use the LIFO heap dvander@147: // to allocate it. If that's the case, make sure to reserve a slot dvander@147: // so we can unwind the LIFO heap at the end of this scope. dvander@147: if (!node->variable()->needsHeapAllocation()) { dvander@147: if (type->isArray() || type->isStruct()) dvander@147: scope_->setUsesLifoHeap(); dvander@147: } dvander@147: dvander@0: node->variable()->setType(type); dvander@0: } dvander@0: dvander@0: void dvander@4: SemanticAnalysis::visit(IntegerLiteral *node) dvander@0: { dvander@30: node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32)); dvander@0: } dvander@0: dvander@0: void dvander@143: SemanticAnalysis::visit(BooleanLiteral *node) dvander@143: { dvander@143: node->setType(zone_->types()->getPrimitive(PrimitiveType_Bool)); dvander@143: } dvander@143: dvander@143: void dvander@0: SemanticAnalysis::visit(ExpressionStatement *node) dvander@0: { dvander@71: visitAndApplyType(node->expression()); dvander@0: } dvander@0: dvander@168: Box * dvander@168: SemanticAnalysis::evaluateDefaultParameter(Handle type, Parameter *parameter) dvander@168: { dvander@172: Local given(zone_, visitForLoad(parameter->initializer())); dvander@172: dvander@168: BoxedPrimitive prim; dvander@168: if (EvaluateForConstant(parameter->initializer(), &prim)) { dvander@168: if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false)) dvander@168: return NULL; dvander@168: dvander@168: if (prim.type() == PrimitiveType_Int32) dvander@172: return Box::New(zone_, given, prim.toInt()); dvander@172: return Box::New(zone_, given, prim.toFloat()); dvander@169: } else if (parameter->initializer()->isStringLiteral()) { dvander@169: StringLiteral *literal = parameter->initializer()->toStringLiteral(); dvander@169: dvander@169: if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false)) dvander@169: return NULL; dvander@169: dvander@169: Local map(zone_, ArrayMap::Attach(zone_, given)); dvander@169: if (!map) dvander@169: return NULL; dvander@169: dvander@169: Local array(zone_, dvander@169: Array::NewString(zone_, dvander@169: map, dvander@169: literal->string()->raw(), dvander@169: literal->string()->length(), dvander@169: Heap::Tenure_Old)); dvander@169: if (!array) dvander@169: return NULL; dvander@169: dvander@169: return Box::NewObj(zone_, given, array, Heap::Tenure_Old); dvander@168: } dvander@168: dvander@168: cc_.reportError(parameter->initializer()->pos(), Message_MustBeConstant); dvander@168: return NULL; dvander@168: } dvander@168: dvander@14: bool dvander@174: SemanticAnalysis::buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig, dvander@174: FixedArray **argsp, FixedArray **defaultsp) dvander@14: { dvander@174: Local args(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old)); dvander@14: if (!args) dvander@14: return false; dvander@14: dvander@168: Local defaults(zone_); dvander@168: dvander@14: // Apply types to arguments. dvander@174: for (size_t i = 0; i < sig.parameters()->length(); i++) { dvander@174: Parameter *parameter = sig.parameters()->at(i); dvander@14: dvander@145: Local type(zone_, bindType(parameter->variable()->pos(), parameter->type())); dvander@14: if (!type) dvander@14: return false; dvander@14: dvander@14: if (parameter->reference()) { dvander@66: if (parameter->dimensions()) { dvander@66: cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference); dvander@168: return false; dvander@66: } dvander@66: dvander@164: if (type->isStruct()) { dvander@164: cc_.reportError(parameter->variable()->pos(), Message_StructCantBeReference); dvander@168: return false; dvander@164: } dvander@164: dvander@67: type = zone_->types()->getReference(type, parameter->isConst()); dvander@14: if (!type) dvander@14: return false; dvander@66: } else if (parameter->dimensions()) { dvander@187: // :TODO: factor in type dimcount dvander@187: if (parameter->dimensions()->length() > MAX_ARRAY_DEPTH) { dvander@68: cc_.reportError(parameter->variable()->pos(), Message_MaximumArrayDepth); dvander@68: return false; dvander@68: } dvander@68: dvander@174: if (kind == TOK_NATIVE && parameter->dimensions()->length() > 1) { dvander@68: cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative); dvander@66: return false; dvander@66: } dvander@66: dvander@66: for (size_t i = parameter->dimensions()->length() - 1; dvander@66: i < parameter->dimensions()->length(); dvander@184: i--) dvander@66: { dvander@184: int size = Type::DYNAMIC_ARRAY_SIZE; dvander@66: if (Expression *expr = parameter->dimensions()->at(i)) { dvander@66: BoxedPrimitive box; dvander@168: if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) { dvander@66: cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant); dvander@66: return false; dvander@66: } dvander@66: size = box.toInt(); dvander@66: } dvander@66: dvander@185: type = zone_->types()->newArray(type, size, parameter->isConst()); dvander@66: if (!type) dvander@66: return false; dvander@66: } dvander@14: } dvander@14: dvander@145: if (IsScalarString(type)) { dvander@68: cc_.reportError(node->pos(), Message_CannotDeclareStringCell); dvander@68: return false; dvander@68: } dvander@68: dvander@30: args->set(zone_, i, type); dvander@14: parameter->variable()->setType(type); dvander@169: dvander@169: if (parameter->initializer()) { dvander@169: if (!defaults) { dvander@174: defaults = FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old); dvander@169: if (!defaults) dvander@169: return false; dvander@169: } dvander@169: dvander@169: Local box(zone_, evaluateDefaultParameter(type, parameter)); dvander@169: if (!box) dvander@169: return false; dvander@169: dvander@169: defaults->set(zone_, i, box); dvander@169: } dvander@14: } dvander@14: dvander@174: *argsp = args; dvander@174: *defaultsp = defaults; dvander@174: dvander@174: return true; dvander@174: } dvander@174: dvander@174: void dvander@174: SemanticAnalysis::visit(FunctionTypeStatement *node) dvander@174: { dvander@174: if (node->decl()->type()) dvander@174: return; dvander@174: dvander@174: Local args(zone_); dvander@174: Local defaults(zone_); dvander@174: dvander@174: const FunctionSignature &sig= node->signature(); dvander@174: if (!buildFunctionArgs(node, dvander@174: TOK_STOCK, dvander@174: sig, dvander@174: args.address(), dvander@174: defaults.address())) dvander@174: { dvander@174: return; dvander@174: } dvander@174: dvander@71: Local returnType(zone_); dvander@174: if (sig.returnType()) dvander@174: returnType = bindType(node->pos(), sig.returnType()); dvander@174: else dvander@174: returnType = zone_->types()->getPrimitive(PrimitiveType_Int32); dvander@174: dvander@174: if (!returnType) dvander@174: return; dvander@174: dvander@174: Local funtype(zone_, zone_->types()->newFunction(returnType, args, defaults)); dvander@174: if (!funtype) dvander@174: return; dvander@174: dvander@174: node->decl()->setType(funtype); dvander@174: } dvander@174: dvander@174: bool dvander@174: SemanticAnalysis::preanalyze(FunctionStatement *node) dvander@174: { dvander@174: Local args(zone_); dvander@174: Local defaults(zone_); dvander@174: dvander@174: const FunctionSignature &sig = node->signature(); dvander@174: if (!buildFunctionArgs(node, dvander@174: node->fun()->token(), dvander@174: sig, dvander@174: args.address(), dvander@174: defaults.address())) dvander@174: { dvander@174: return false; dvander@174: } dvander@174: dvander@174: Local returnType(zone_); dvander@174: if (sig.returnType() || dvander@145: node->hasExplicitReturn() || dvander@145: node->fun()->isNative()) dvander@145: { dvander@174: returnType = bindType(node->pos(), sig.returnType()); dvander@132: } else { dvander@71: returnType = zone_->types()->getVoid(); dvander@132: } dvander@14: if (!returnType) dvander@14: return false; dvander@14: dvander@68: Local funtype(zone_); dvander@68: if (node->fun()->isNative()) dvander@168: funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic()); dvander@68: else dvander@168: funtype = zone_->types()->newFunction(returnType, args, defaults); dvander@14: if (!funtype) dvander@14: return false; dvander@63: dvander@63: // If the function already has a type, it was forward declared before, and dvander@63: // now this is our chance to type check the second declaration. dvander@63: if (node->fun()->type()) { dvander@63: Local forward(zone_, node->fun()->type()); dvander@63: if (!Type::Compare(funtype, forward)) { dvander@63: cc_.reportError(node->pos(), Message_ForwardDeclareMismatches); dvander@63: return false; dvander@63: } dvander@63: node->fun()->setForwardType(forward); dvander@63: } dvander@14: dvander@14: node->fun()->setType(funtype); dvander@63: dvander@14: return true; dvander@14: } dvander@14: dvander@0: void dvander@0: SemanticAnalysis::visit(FunctionStatement *node) dvander@0: { dvander@137: function_ = node->fun(); dvander@12: scope_ = node->scope(); dvander@71: dvander@71: ControlScope control(&control_); dvander@71: if (node->body()) { dvander@63: node->body()->accept(this); dvander@71: dvander@71: ControlStatus status = control.status(); dvander@71: if (status.returns() == Returns_Sometimes) { dvander@71: cc_.reportError(node->pos(), Message_NotAllPathsReturnValue); dvander@71: } else if (status.returns() == Returns_Never) { dvander@137: if (!function_->type()->returnType()->isVoid()) dvander@71: cc_.reportError(node->pos(), Message_MissingReturnValue); dvander@71: } dvander@71: } dvander@71: dvander@12: scope_ = NULL; dvander@25: function_ = NULL; dvander@0: } dvander@0: dvander@145: void dvander@168: SemanticAnalysis::typeMismatch(const SourcePosition &pos, Handle actual, Handle given) dvander@145: { dvander@168: cc_.reportError(pos, Message_TypeMismatch, dvander@145: GetTypeName(actual), dvander@145: GetTypeName(given)); dvander@145: } dvander@145: dvander@25: bool dvander@168: SemanticAnalysis::typeCheckArrayAssignment(const SourcePosition &pos, Handle argGiven, dvander@168: Handle argActual, bool forAssign) dvander@14: { dvander@40: Local actual(zone_, argActual); dvander@40: Local given(zone_, argGiven); dvander@40: dvander@25: if (!given->isArray()) { dvander@168: cc_.reportError(pos, Message_ExpectedArray); dvander@25: return false; dvander@25: } dvander@25: if (given->levels() != actual->levels()) { dvander@168: cc_.reportError(pos, Message_ArrayDimensionsMismatch); dvander@25: return false; dvander@25: } dvander@25: dvander@183: unsigned level = 1; dvander@25: while (given->isArray()) { dvander@184: if (actual->isFixedLength()) { dvander@25: if (forAssign) { dvander@184: if (!given->isFixedLength()) { dvander@184: cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level); dvander@25: return false; dvander@25: } dvander@25: dvander@25: if (actual->isCharArray()) { dvander@25: // String assignment can have a truncated |given|. dvander@184: if (given->fixedLength() > actual->fixedLength()) { dvander@168: cc_.reportError(pos, Message_ArrayAssignmentTooBig); dvander@25: return false; dvander@25: } dvander@25: } else { dvander@184: if (given->fixedLength() != actual->fixedLength()) { dvander@168: cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level); dvander@25: return false; dvander@25: } dvander@25: } dvander@184: } dvander@184: } else if (given->isFixedLength()) { dvander@184: // We do not allow assignments in the form: dvander@187: // [][] = [][Y] dvander@184: // dvander@184: // Otherwise, the following code could break the size guarantees dvander@184: // of the right-hand side: dvander@184: // dvander@184: // new x[][5]; dvander@184: // new y[][]; dvander@184: // new z[3]; dvander@184: // dvander@184: // y = x; dvander@184: // y[0] = z; dvander@184: // dvander@184: // Now |x[0]| contains a 4-length array. dvander@184: if (level > 1) { dvander@184: cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level); dvander@184: return false; dvander@25: } dvander@25: } dvander@25: given = given->contained(); dvander@25: actual = actual->contained(); dvander@183: level++; dvander@14: } dvander@14: dvander@168: return typeCheckAssignment(pos, given, actual, forAssign); dvander@25: } dvander@25: dvander@25: bool dvander@168: SemanticAnalysis::typeCheckAssignment(const SourcePosition &pos, Handle argGiven, dvander@168: Handle argActual, bool forAssign) dvander@25: { dvander@40: Local actual(zone_, argActual); dvander@40: Local given(zone_, argGiven); dvander@40: dvander@25: if (actual->isArray()) dvander@168: return typeCheckArrayAssignment(pos, given, actual, forAssign); dvander@25: dvander@25: if (given->isArray()) { dvander@168: cc_.reportError(pos, Message_CannotAssignArrayToScalar); dvander@25: return false; dvander@25: } dvander@25: dvander@47: // The given type may not have been dereferenced. dvander@47: if (given->isReference()) dvander@47: given = given->contained(); dvander@47: if (actual->isReference()) dvander@47: actual = actual->contained(); dvander@47: dvander@168: // We coerce unchecked to a few things. dvander@168: if (actual->isUnchecked() || given->isUnchecked()) { dvander@168: Type *check = actual->isUnchecked() ? given : actual; dvander@168: if (check->isUnchecked() || dvander@168: check->isEnum() || dvander@168: check->isInt32() || dvander@168: check->isBool() || dvander@168: check->isFloat()) dvander@168: { dvander@168: return true; dvander@168: } dvander@168: typeMismatch(pos, actual, given); dvander@168: return false; dvander@168: } dvander@168: dvander@174: if (given->isFunction() && actual->isFunction()) { dvander@174: if (!Type::Compare(given, actual)) { dvander@174: typeMismatch(pos, actual, given); dvander@174: return false; dvander@174: } dvander@174: return true; dvander@174: } dvander@174: dvander@145: if (actual->isEnum()) { dvander@145: if (!given->isEnum() || actual != given) { dvander@168: typeMismatch(pos, actual, given); dvander@145: return false; dvander@145: } dvander@145: return true; dvander@145: } dvander@145: dvander@149: if (actual->isStruct()) { dvander@149: if (!given->isStruct() || actual != given) { dvander@168: typeMismatch(pos, actual, given); dvander@149: return false; dvander@149: } dvander@149: return true; dvander@149: } dvander@149: dvander@149: if (given->isEnum() || given->isFunction() || given->isStruct()) { dvander@168: typeMismatch(pos, actual, given); dvander@25: return false; dvander@25: } dvander@145: dvander@168: // This coercion is trivial. dvander@168: if (given->isBool() && actual->isInt32()) dvander@168: return true; dvander@168: dvander@25: if (given->primitive() != actual->primitive()) { dvander@168: typeMismatch(pos, actual, given); dvander@25: return false; dvander@25: } dvander@25: dvander@25: return true; dvander@25: } dvander@25: dvander@25: bool dvander@40: SemanticAnalysis::typeCheckParameter(AstNode *node, Handle given, Handle actual) dvander@25: { dvander@168: return typeCheckAssignment(node->pos(), given, actual, false); dvander@168: } dvander@168: dvander@168: bool dvander@168: SemanticAnalysis::checkArgumentCount(Handle type, unsigned actual) dvander@168: { dvander@168: if (type->parameters()->length() == actual) dvander@168: return true; dvander@168: dvander@168: if (actual > type->parameters()->length()) { dvander@168: if (!type->isNative() || !type->isNativeVariadic()) dvander@168: return false; dvander@168: return true; dvander@168: } dvander@168: dvander@168: if (!type->defaults()) dvander@168: return false; dvander@168: dvander@168: // Missing arguments. See if there's a default argument for each missing dvander@168: // actual. dvander@168: for (unsigned i = actual; i < type->parameters()->length(); i++) { dvander@168: if (!type->defaults()->at(i)) dvander@168: return false; dvander@168: } dvander@168: dvander@168: return true; dvander@14: } dvander@14: dvander@0: void dvander@0: SemanticAnalysis::visit(CallExpression *node) dvander@0: { dvander@40: Local type(zone_, 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@168: dvander@168: if (!checkArgumentCount(type, node->arguments()->length())) { dvander@168: cc_.reportError(node->pos(), Message_ArgumentCountMismatch); dvander@168: return; dvander@25: } dvander@14: dvander@174: // NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction(); dvander@174: // if (fun->isForward()) { dvander@174: // cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars()); dvander@174: // return; dvander@174: // } dvander@63: dvander@55: for (unsigned i = 0; i < node->arguments()->length(); 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@40: Local given(zone_, visitAndApplyType(expression)); dvander@14: if (!given) dvander@14: return; dvander@14: dvander@71: // Since we skip a load, check for a call expression that returns void. dvander@71: if (given->isVoid()) { dvander@71: assert(expression->isCallExpression()); dvander@71: CallExpression *call = expression->toCallExpression(); dvander@71: cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue); dvander@71: return; dvander@71: } dvander@71: dvander@68: bool mustComputeReference; dvander@68: if (i >= type->parameters()->length()) { dvander@68: // Special handling for natives. Arguments past the formal must dvander@68: // always have references computed. However, arrays are already dvander@68: // references for natives. dvander@68: assert(type->isNative() && type->isNativeVariadic()); dvander@68: mustComputeReference = !given->isReference() && !given->isArray(); dvander@68: } else { dvander@68: Local actual(zone_, type->parameterAt(i)); dvander@166: dvander@188: if (expression->isIndexExpression()) { dvander@188: // Disabled until we can make it work. dvander@188: #if 0 dvander@188: if (actual->isArray()) { dvander@188: // We special case the ability to pass x[y] into x[], which dvander@188: // creates an array slice. We only do this if we know the dvander@188: // assignment would otherwise not type-check. dvander@188: IndexExpression *index = expression->toIndexExpression(); dvander@188: if (index->left()->type()->levels() == actual->levels()) dvander@188: given = index->left()->type(); dvander@188: } else dvander@188: #endif dvander@188: if (actual->isReference()) { dvander@188: cc_.reportError(expression->pos(), Message_CannotComputeIndexRef); dvander@188: return; dvander@188: } dvander@166: } dvander@166: dvander@68: if (!typeCheckParameter(expression, given, actual)) dvander@68: return; dvander@68: mustComputeReference = actual->isReference() && !given->isReference(); dvander@68: } 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@68: if (mustComputeReference) dvander@14: scope_->setUsesLifoHeap(); dvander@14: } dvander@66: dvander@174: node->setType(type->returnType()); dvander@0: } dvander@0: dvander@0: void dvander@172: SemanticAnalysis::ControlScope::inherit(const ControlStatus &other) dvander@172: { dvander@172: if (other.returns() < status().returns()) dvander@172: return; dvander@172: dvander@172: if (other.terminates()) dvander@172: terminate(other.returns()); dvander@172: else dvander@172: returns(other.returns()); dvander@172: } dvander@172: dvander@172: void dvander@71: SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right) dvander@71: { dvander@71: // If both sides terminate in a return, we consider this a return as well. dvander@71: if (left.returns() == Returns_Always && right.returns() == Returns_Always) { dvander@71: terminate(Returns_Always); dvander@71: return; dvander@71: } dvander@71: dvander@71: ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never) dvander@71: ? Returns_Never dvander@71: : Returns_Sometimes; dvander@71: dvander@71: if (left.terminates() && right.terminates()) dvander@71: terminate(status); dvander@71: else dvander@71: returns(status); dvander@71: } dvander@71: dvander@71: void dvander@0: SemanticAnalysis::visit(IfStatement *node) dvander@0: { dvander@40: Local type(zone_, visitForLoad(node->condition())); dvander@25: if (!type) dvander@25: return; dvander@25: dvander@25: if (!canTest(node, type)) dvander@25: return; dvander@25: dvander@71: ControlStatus trueBranch = visitForControl(node->ifTrue()); dvander@71: ControlStatus falseBranch = ControlStatus(false, Returns_Never); dvander@71: dvander@10: if (node->ifFalse()) dvander@71: falseBranch = visitForControl(node->ifFalse()); dvander@71: dvander@71: control_->merge(trueBranch, falseBranch); dvander@0: } dvander@0: dvander@0: void dvander@0: SemanticAnalysis::visit(IndexExpression *node) dvander@0: { dvander@71: Local left(zone_, visitForLoad(node->left())); dvander@40: Local right(zone_, visitForLoad(node->right())); dvander@0: dvander@25: if (!left || !right) dvander@25: return; dvander@25: dvander@145: if (!right->isInt32() && !right->isEnum()) { 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@160: dvander@160: // Note: char arrays are automatically up-casted to return an int32. dvander@160: if (left->isCharArray()) dvander@160: node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32)); dvander@160: else dvander@160: node->setType(left->contained()); dvander@0: } dvander@2: dvander@2: void dvander@148: SemanticAnalysis::visit(FieldExpression *node) dvander@148: { dvander@148: Local left(zone_, visitForLoad(node->left())); dvander@148: if (!left) dvander@148: return; dvander@148: dvander@148: if (!left->isStruct()) { dvander@148: cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(), dvander@148: GetTypeName(left)); dvander@148: return; dvander@148: } dvander@148: dvander@148: Local field(zone_, node->field()); dvander@148: dvander@148: unsigned offset; dvander@148: Local desc(zone_, left->lookupField(field, &offset)); dvander@148: if (!desc) { dvander@148: cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(), dvander@148: GetTypeName(left)); dvander@148: return; dvander@148: } dvander@148: dvander@148: node->setFieldIndex(offset); dvander@148: node->setType(desc->type()); dvander@148: } dvander@148: dvander@148: void dvander@2: SemanticAnalysis::visit(EnumStatement *node) dvander@2: { dvander@172: Local name(zone_, node->name()); dvander@172: Local type(zone_); dvander@172: if (name) dvander@172: type = zone_->types()->newEnum(name); dvander@172: else dvander@172: type = zone_->types()->getPrimitive(PrimitiveType_Int32); dvander@3: dvander@172: if (!type) dvander@172: return; dvander@172: dvander@172: if (node->decl()) dvander@172: node->decl()->setType(type); dvander@2: dvander@2: int value = 0; dvander@57: for (size_t i = 0; i < node->entries()->length(); 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@168: if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) { 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@172: static int dvander@172: SortCaseIntValues(const void *p1, const void *p2) dvander@172: { dvander@172: CaseValue *v1 = (CaseValue *)p1; dvander@172: CaseValue *v2 = (CaseValue *)p2; dvander@172: dvander@172: return v1->box.toInt() - v2->box.toInt(); dvander@172: } dvander@172: dvander@172: void dvander@172: SemanticAnalysis::visit(SwitchStatement *node) dvander@172: { dvander@172: Local caseType(zone_, visitForLoad(node->expression())); dvander@172: if (!caseType) dvander@172: return; dvander@172: dvander@172: if (!caseType->isEnum() && !caseType->isInt32()) { dvander@172: cc_.reportError(node->pos(), Message_CaseMustBeInteger); dvander@172: return; dvander@172: } dvander@172: dvander@172: PoolList *values = new (zone_->pool()) PoolList(); dvander@172: ControlStatus status = ControlStatus(false, Returns_Never); dvander@172: dvander@172: Local check(zone_); dvander@172: for (size_t i = 0; i < node->cases()->length(); i++) { dvander@172: Case *c = node->cases()->at(i); dvander@172: dvander@172: check = visitForLoad(c->expression()); dvander@172: if (!check) dvander@172: return; dvander@172: dvander@172: if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false)) dvander@172: return; dvander@172: dvander@172: CaseValue v(i); dvander@172: if (!EvaluateForConstant(c->expression(), &v.box)) { dvander@172: cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant); dvander@172: return; dvander@172: } dvander@172: if (!values->append(v)) dvander@172: return; dvander@172: dvander@172: if (c->others()) { dvander@172: for (size_t j = 0; j < c->others()->length(); j++) { dvander@172: Expression *expr = c->others()->at(j); dvander@172: check = visitForLoad(expr); dvander@172: if (!check) dvander@172: return; dvander@172: dvander@172: if (!typeCheckAssignment(expr->pos(), check, caseType, false)) dvander@172: return; dvander@172: dvander@172: CaseValue v(i); dvander@172: if (!EvaluateForConstant(expr, &v.box)) { dvander@172: cc_.reportError(expr->pos(), Message_CaseMustBeConstant); dvander@172: return; dvander@172: } dvander@172: if (!values->append(v)) dvander@172: return; dvander@172: } dvander@172: } dvander@172: dvander@172: ControlStatus latest = visitForControl(c->statement()); dvander@172: dvander@172: if (i != 0) dvander@172: control_->merge(status, latest); dvander@172: dvander@172: status = latest; dvander@172: } dvander@172: dvander@172: if (node->defaultCase()) { dvander@172: ControlStatus latest = visitForControl(node->defaultCase()); dvander@172: dvander@172: if (node->cases()->length()) { dvander@172: // If we had any other cases, we must merge. dvander@172: control_->merge(status, latest); dvander@172: } else { dvander@172: // Otherwise, control-flow always flows through here. dvander@172: control_->inherit(latest); dvander@172: } dvander@172: } else if (node->cases()->length()) { dvander@172: control_->merge(status, ControlStatus(false, Returns_Never)); dvander@172: } dvander@172: dvander@172: if (values->length() > 1) { dvander@172: qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues); dvander@172: dvander@172: for (size_t i = 1; i < values->length(); i++) { dvander@172: CaseValue &prev = values->at(i - 1); dvander@172: CaseValue &cur = values->at(i); dvander@172: if (prev.box.toInt() == cur.box.toInt()) { dvander@172: cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue); dvander@172: return; dvander@172: } dvander@172: } dvander@172: } dvander@172: dvander@172: node->setCaseValueList(values); dvander@172: } dvander@172: dvander@4: void dvander@146: SemanticAnalysis::visit(StructureStatement *node) dvander@146: { dvander@146: // If this node already has a type, it was pre-analyzed, so skip it. dvander@146: if (node->decl()->type()) dvander@146: return; dvander@146: dvander@146: FieldList *fields = node->fields(); dvander@146: Local desctable(zone_, FixedArray::New(zone_, fields->length(), Heap::Tenure_Old)); dvander@146: if (!desctable) dvander@146: return; dvander@146: dvander@153: Vector composedList; dvander@146: StructureBufferBuilder builder; dvander@146: dvander@146: Local type(zone_); dvander@146: Local name(zone_); dvander@146: Local desc(zone_); dvander@146: for (size_t i = 0; i < fields->length(); i++) { dvander@146: StructureStatement::Field *field = fields->at(i); dvander@146: dvander@146: type = bindType(field->pos(), field->type()); dvander@146: if (!type) dvander@146: return; dvander@146: dvander@159: if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) { dvander@159: cc_.reportError(field->pos(), Message_CannotDeclareStringCell); dvander@159: return; dvander@159: } dvander@159: dvander@146: unsigned offset; dvander@146: if (!builder.add(type, &offset)) dvander@146: return; dvander@146: dvander@146: name = field->name(); dvander@146: desc = Descriptor::New(zone_, name, type, offset); dvander@146: if (!desc) dvander@146: return; dvander@146: dvander@146: desctable->set(zone_, i, desc); dvander@153: dvander@153: if (type->isStruct() || type->isArray()) { dvander@153: if (!composedList.append(i)) dvander@153: return; dvander@153: } dvander@146: } dvander@146: dvander@153: Local composed(zone_); dvander@153: if (composedList.length()) { dvander@153: composed = FixedArray::New(zone_, composedList.length(), Heap::Tenure_Old); dvander@153: if (!composed) dvander@153: return; dvander@153: dvander@153: for (unsigned i = 0; i < composedList.length(); i++) dvander@153: composed->set(zone_, i, desctable->at(i)); dvander@153: } dvander@153: dvander@153: Local map(zone_, StructMap::New(zone_, builder, composed)); dvander@147: if (!map) dvander@147: return; dvander@147: dvander@146: name = node->decl()->name(); dvander@147: type = zone_->types()->newStruct(name, desctable, map); dvander@146: if (!type) dvander@146: return; dvander@146: dvander@147: map->setType(type); dvander@146: node->decl()->setType(type); dvander@146: } dvander@146: dvander@146: void dvander@21: SemanticAnalysis::visit(StringLiteral *node) dvander@21: { dvander@40: Local type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char)); dvander@21: if (!type) dvander@21: return; dvander@21: dvander@30: 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@40: Local type(zone_, 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@71: if (!loop_) { dvander@25: cc_.reportError(node->pos(), Message_BreakOutsideLoop); dvander@71: return; dvander@71: } dvander@71: dvander@71: // Note: ignore breaks that occur in unreachable control-flow. dvander@71: if (!control_->status().terminates()) dvander@71: loop_->addBreak(); dvander@71: dvander@71: control_->terminate(Returns_Never); dvander@10: } dvander@10: dvander@10: void dvander@10: SemanticAnalysis::visit(ContinueStatement *node) dvander@10: { dvander@71: if (!loop_) { dvander@25: cc_.reportError(node->pos(), Message_ContinueOutsideLoop); dvander@71: return; dvander@71: } dvander@71: dvander@71: // Note: ignore continues that occur in unreachable control-flow. dvander@71: if (!control_->status().terminates()) dvander@71: loop_->addContinue(); dvander@71: dvander@71: control_->terminate(Returns_Never); dvander@10: } dvander@187: dvander@187: void dvander@187: SemanticAnalysis::visit(ArrayLiteral *node) dvander@187: { dvander@187: // We should never visit this. dvander@187: cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral); dvander@187: } dvander@187: