asherkin@263: /* vim: set ts=4 sw=4 tw=99 et: asherkin@263: * asherkin@263: * Copyright (C) 2012 David Anderson asherkin@263: * asherkin@263: * This file is part of JITCraft. asherkin@263: * asherkin@263: * JITCraft is free software: you can redistribute it and/or modify it under asherkin@263: * the terms of the GNU General Public License as published by the Free asherkin@263: * Software Foundation, either version 3 of the License, or (at your option) asherkin@263: * any later version. asherkin@263: * asherkin@263: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY asherkin@263: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS asherkin@263: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. asherkin@263: * asherkin@263: * You should have received a copy of the GNU General Public License along with asherkin@263: * JITCraft. If not, see http://www.gnu.org/licenses/. asherkin@263: */ asherkin@263: #include asherkin@263: #include "SemanticAnalysis.h" asherkin@263: #include "../Types.h" asherkin@263: #include "../Zone.h" asherkin@263: #include "../TypeManager.h" asherkin@263: #include "../Strings.h" asherkin@263: #include "../Box.h" asherkin@263: #include "../Array.h" asherkin@263: #include "../Heap-inl.h" asherkin@263: #include "Scopes.h" asherkin@263: #include "NameBinding.h" asherkin@263: asherkin@263: using namespace ke; asherkin@263: asherkin@263: SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree) asherkin@263: : zone_(zone), asherkin@263: cc_(cc), asherkin@263: tree_(tree), asherkin@263: scope_(NULL), asherkin@263: loop_(NULL) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::analyze() asherkin@263: { asherkin@263: assert(false); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: asherkin@263: #if 0 asherkin@263: asherkin@263: static inline bool asherkin@263: IsPrimitiveType(Type *type, PrimitiveType primitive) asherkin@263: { asherkin@263: if (!type) asherkin@263: return false; asherkin@263: asherkin@263: if (!type->isPrimitive()) asherkin@263: return false; asherkin@263: asherkin@263: return primitive == type->primitive(); asherkin@263: } asherkin@263: asherkin@263: static inline bool asherkin@263: EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right, asherkin@263: BoxedPrimitive *out) asherkin@263: { asherkin@263: switch (kind) { asherkin@263: case TOK_PLUS: asherkin@263: *out = BoxedPrimitive::Int(left.toInt() + right.toInt()); asherkin@263: return true; asherkin@263: asherkin@263: case TOK_SHL: asherkin@263: *out = BoxedPrimitive::Int(left.toInt() << right.toInt()); asherkin@263: return true; asherkin@263: asherkin@263: default: asherkin@263: return false; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: static inline bool asherkin@263: EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out) asherkin@263: { asherkin@263: switch (kind) { asherkin@263: case TOK_MINUS: asherkin@263: *out = BoxedPrimitive::Int(-inner.toInt()); asherkin@263: return true; asherkin@263: asherkin@263: default: asherkin@263: return false; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: static bool asherkin@263: EvaluateForConstant(Expression *expression, BoxedPrimitive *out) asherkin@263: { asherkin@263: switch (expression->kind()) { asherkin@263: case AstNode::kBinaryExpression: asherkin@263: { asherkin@263: BoxedPrimitive left; asherkin@263: BoxedPrimitive right; asherkin@263: BinaryExpression *b = expression->toBinaryExpression(); asherkin@263: if (!EvaluateForConstant(b->left(), &left) || asherkin@263: !EvaluateForConstant(b->right(), &right)) asherkin@263: { asherkin@263: return false; asherkin@263: } asherkin@263: return EvaluateBinaryOperation(b->token(), left, right, out); asherkin@263: } asherkin@263: asherkin@263: case AstNode::kUnaryExpression: asherkin@263: { asherkin@263: BoxedPrimitive inner; asherkin@263: UnaryExpression *u = expression->toUnaryExpression(); asherkin@263: if (!EvaluateForConstant(u->expression(), &inner)) asherkin@263: return false; asherkin@263: return EvaluateUnaryOperation(u->token(), inner, out); asherkin@263: } asherkin@263: asherkin@263: case AstNode::kNameProxy: asherkin@263: { asherkin@263: NameProxy *proxy = expression->toNameProxy(); asherkin@263: if (proxy->binding()->kind() != BoundName::CONSTANT) asherkin@263: return false; asherkin@263: asherkin@263: NamedConstant *c = proxy->binding()->toNamedConstant(); asherkin@263: if (!IsPrimitiveType(c->type(), PrimitiveType_Int32)) asherkin@263: return false; asherkin@263: asherkin@263: *out = c->value(); asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: case AstNode::kBooleanLiteral: asherkin@263: *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0); asherkin@263: return true; asherkin@263: asherkin@263: case AstNode::kIntegerLiteral: asherkin@263: *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value()); asherkin@263: return true; asherkin@263: asherkin@263: default: asherkin@263: return false; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree) asherkin@263: : zone_(zone), asherkin@263: cc_(cc), asherkin@263: tree_(tree), asherkin@263: scope_(NULL), asherkin@263: loop_(NULL) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::analyze() asherkin@263: { asherkin@263: if (cc_.failures()) asherkin@263: return false; asherkin@263: asherkin@263: scope_ = tree_->globalScope(); asherkin@263: assert(scope_->kind() == Scope::GLOBAL); asherkin@263: asherkin@263: for (size_t i = 0; i < tree_->statements()->length(); i++) { asherkin@263: Statement *statement = tree_->statements()->at(i); asherkin@263: if (statement->isFunctionStatement()) { asherkin@263: FunctionStatement *funstmt = statement->toFunctionStatement(); asherkin@263: if (!preanalyze(funstmt)) asherkin@263: return false; asherkin@263: } else if (statement->isEnumStatement()) { asherkin@263: EnumStatement *enumstmt = statement->toEnumStatement(); asherkin@263: asherkin@263: // We pre-fill global enum types, since they may occur in function asherkin@263: // signatures. This should probably be somewhere else... asherkin@263: enumstmt->accept(this); asherkin@263: } else if (statement->isStructureStatement()) { asherkin@263: StructureStatement *node = statement->toStructureStatement(); asherkin@263: node->accept(this); asherkin@263: if (!node->decl()->type()) asherkin@263: return false; asherkin@263: } else if (statement->isFunctionTypeStatement()) { asherkin@263: FunctionTypeStatement *node = statement->toFunctionTypeStatement(); asherkin@263: node->accept(this); asherkin@263: if (!node->decl()->type()) asherkin@263: return false; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: for (size_t i = 0; i < tree_->statements()->length(); i++) { asherkin@263: Statement *statement = tree_->statements()->at(i); asherkin@263: asherkin@263: // We can't double-process these. Maybe put this check somewhere else. asherkin@263: if (statement->isEnumStatement()) asherkin@263: continue; asherkin@263: asherkin@263: statement->accept(this); asherkin@263: } asherkin@263: asherkin@263: if (!determineLiveFunctions()) asherkin@263: return false; asherkin@263: asherkin@263: return !cc_.failures(); asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::determineLiveFunctions() asherkin@263: { asherkin@263: Vector worklist; asherkin@263: asherkin@263: // Add the root set. asherkin@263: for (size_t i = 0; i < tree_->statements()->length(); i++) { asherkin@263: Statement *statement = tree_->statements()->at(i); asherkin@263: if (!statement->isFunctionStatement()) asherkin@263: continue; asherkin@263: asherkin@263: FunctionStatement *stmt = statement->toFunctionStatement(); asherkin@263: NamedFunction *fun = stmt->fun(); asherkin@263: if (!fun->used()) asherkin@263: continue; asherkin@263: asherkin@263: for (size_t i = 0; i < fun->usedGlobals()->length(); i++) { asherkin@263: NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction(); asherkin@263: asherkin@263: // Names in these lists are always unused, however, we mark them asherkin@263: // as used while inserting into the work queue, to avoid double- asherkin@263: // insertion. asherkin@263: if (name->used()) asherkin@263: continue; asherkin@263: asherkin@263: if (!worklist.append(name)) asherkin@263: return false; asherkin@263: asherkin@263: name->setUsed(); asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: while (!worklist.empty()) { asherkin@263: NamedFunction *fun = worklist.popCopy(); asherkin@263: asherkin@263: for (size_t i = 0; i < fun->usedGlobals()->length(); i++) { asherkin@263: NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction(); asherkin@263: if (name->used()) asherkin@263: continue; asherkin@263: if (!worklist.append(name)) asherkin@263: return false; asherkin@263: name->setUsed(); asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name) asherkin@263: { asherkin@263: if (!name) asherkin@263: return zone_->types()->getPrimitive(PrimitiveType_Int32); asherkin@263: asherkin@263: if (name->kind() == BoundName::UNBOUND) { asherkin@263: cc_.reportError(pos, Message_TypeNotFound, name->name()->chars()); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (name->kind() != BoundName::TYPE) { asherkin@263: cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars()); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (!name->type()) asherkin@263: return NULL; asherkin@263: asherkin@263: return name->type(); asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: SemanticAnalysis::visitAndApplyType(Expression *expression) asherkin@263: { asherkin@263: expression->accept(this); asherkin@263: return expression->type(); asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: SemanticAnalysis::visitForLoad(Expression *expression) asherkin@263: { asherkin@263: Local type(zone_, visitAndApplyType(expression)); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: if (type->isReference()) { asherkin@263: expression->setType(type->contained()); asherkin@263: } else if (expression->isCallExpression()) { asherkin@263: if (type->isVoid()) { asherkin@263: CallExpression *call = expression->toCallExpression(); asherkin@263: cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue); asherkin@263: return NULL; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: return expression->type(); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle type) asherkin@263: { asherkin@263: const char *op = TokenNames[token]; asherkin@263: const char *name = GetTypeName(type); asherkin@263: asherkin@263: cc_.reportError(node->pos(), Message_UnaryTypeError, op, name); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle left, Handle right) asherkin@263: { asherkin@263: const char *op = TokenNames[token]; asherkin@263: const char *leftName = GetTypeName(left); asherkin@263: const char *rightName = GetTypeName(right); asherkin@263: asherkin@263: cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName); asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle left, Handle right) asherkin@263: { asherkin@263: if ((token >= TOK_PLUS && token <= TOK_SLASH) || asherkin@263: (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV)) asherkin@263: { asherkin@263: // If either side is a float, the other side must be a float or int. asherkin@263: if (left->isFloat() || right->isFloat()) { asherkin@263: Type *floatType = left->isFloat() ? left : right; asherkin@263: Type *other = left->isFloat() ? right : left; asherkin@263: if (other->isFloat() || other->isInt32()) asherkin@263: return floatType; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: if (token == TOK_OR || token == TOK_AND) { asherkin@263: if (!canTest(node, left) || !canTest(node, right)) asherkin@263: return NULL; asherkin@263: return zone_->types()->getPrimitive(PrimitiveType_Bool); asherkin@263: } asherkin@263: asherkin@263: if (token >= TOK_EQUALS && token <= TOK_GE) { asherkin@263: if ((left->isFloat() || left->isInt32()) && asherkin@263: (right->isFloat() || right->isInt32())) asherkin@263: { asherkin@263: return zone_->types()->getPrimitive(PrimitiveType_Bool); asherkin@263: } asherkin@263: binaryTypeError(node, token, left, right); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (!left->isInt32() || !right->isInt32()) { asherkin@263: binaryTypeError(node, token, left, right); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: return left; asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::canTest(AstNode *node, Handle type) asherkin@263: { asherkin@263: if (!type->isPrimitive() && !type->isEnum()) { asherkin@263: cc_.reportError(node->pos(), Message_ArrayIsNotBoolean); asherkin@263: return false; asherkin@263: } asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: SemanticAnalysis::visitForLValue(Expression *expression) asherkin@263: { asherkin@263: if (expression->isIndexExpression()) { asherkin@263: Type *type = visitAndApplyType(expression); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: // if (type->isConst()) { asherkin@263: // cc_.reportError(expression->pos(), Message_ReferenceIsConstant); asherkin@263: // return NULL; asherkin@263: // } asherkin@263: asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: if (expression->isFieldExpression()) { asherkin@263: Type *type = visitAndApplyType(expression); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: // if (expression->toFieldExpression()->left()->type()->isConst()) { asherkin@263: // cc_.reportError(expression->pos(), Message_ReferenceIsConstant); asherkin@263: // return NULL; asherkin@263: // } asherkin@263: asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: if (!expression->isNameProxy()) { asherkin@263: cc_.reportError(expression->pos(), Message_ExpectedLValue); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: NameProxy *proxy = expression->toNameProxy(); asherkin@263: if (!proxy->binding()->kind() == BoundName::VARIABLE) { asherkin@263: cc_.reportError(expression->pos(), Message_ExpectedLValue); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: Variable *var = proxy->binding()->toVariable(); asherkin@263: if (!var->type()) asherkin@263: return NULL; asherkin@263: asherkin@263: if (var->type()->isReference()) { asherkin@263: if (var->type()->isConst()) { asherkin@263: cc_.reportError(expression->pos(), Message_ReferenceIsConstant); asherkin@263: return NULL; asherkin@263: } asherkin@263: return var->type()->contained(); asherkin@263: } asherkin@263: return var->type(); asherkin@263: } asherkin@263: asherkin@263: SemanticAnalysis::ControlStatus asherkin@263: SemanticAnalysis::visitForControl(Statement *statement) asherkin@263: { asherkin@263: ControlScope scope(&control_); asherkin@263: statement->accept(this); asherkin@263: return scope.status(); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(NameProxy *name) asherkin@263: { asherkin@263: BoundName *binding = name->binding(); asherkin@263: asherkin@263: if (binding->scope()->kind() == Scope::GLOBAL) { asherkin@263: if (!function_ || function_->isPublic()) { asherkin@263: // Whatever we're referencing must be kept alive no matter what. asherkin@263: // As such, we simply mark it used, and don't do anything special. asherkin@263: binding->setUsed(); asherkin@263: } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) { asherkin@263: // Otherwise, we're inside a normal stock or function. Since we asherkin@263: // don't really know if we've been used yet, we shouldn't asherkin@263: // prematurely references as alive. Instead, we keep a list of asherkin@263: // which names have been used, so we can mark them later if needed. asherkin@263: // asherkin@263: // Note that we skip this step if the binding is already in the asherkin@263: // root set. asherkin@263: if (!function_->addUsedGlobal(binding)) asherkin@263: return; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: name->setType(binding->type()); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(Assignment *node) asherkin@263: { asherkin@263: Local exprType(zone_, visitForLoad(node->expression())); asherkin@263: if (!exprType) asherkin@263: return ; asherkin@263: asherkin@263: Local type(zone_, visitForLValue(node->lvalue())); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: if (node->token() != TOK_ASSIGN) { asherkin@263: if (!typeCheckBinary(node, node->token(), type, exprType)) asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: if (!typeCheckAssignment(node->pos(), exprType, type, true)) asherkin@263: return; asherkin@263: asherkin@263: node->setType(type); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(IncDecExpression *node) asherkin@263: { asherkin@263: Local type(zone_, visitForLValue(node->expression())); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: assert(!type->isReference()); asherkin@263: asherkin@263: if (!type->isInt32() && !type->isFloat()) { asherkin@263: unaryTypeError(node, node->token(), type); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: node->setType(type); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(UnaryExpression *node) asherkin@263: { asherkin@263: Local type(zone_, visitForLoad(node->expression())); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: switch (node->token()) asherkin@263: { asherkin@263: case TOK_NOT: asherkin@263: if (!canTest(node->expression(), type)) asherkin@263: return; asherkin@263: type = zone_->types()->getPrimitive(PrimitiveType_Int32); asherkin@263: if (!type) asherkin@263: return; asherkin@263: node->setType(type); asherkin@263: break; asherkin@263: asherkin@263: case TOK_MINUS: asherkin@263: if (!type->isFloat() && !type->isInt32()) { asherkin@263: unaryTypeError(node, node->token(), type); asherkin@263: return; asherkin@263: } asherkin@263: node->setType(type); asherkin@263: break; asherkin@263: asherkin@263: case TOK_LABEL: asherkin@263: { asherkin@263: Local to(zone_, bindType(node->pos(), node->type())); asherkin@263: if (!to) asherkin@263: return; asherkin@263: asherkin@263: if ((!type->isFloat() && !type->isInt32OrEnum()) || asherkin@263: (!to->isFloat() && !to->isInt32OrEnum())) asherkin@263: { asherkin@263: unaryTypeError(node, node->token(), type); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: node->setType(to); asherkin@263: break; asherkin@263: } asherkin@263: asherkin@263: case TOK_SIZEOF: asherkin@263: { asherkin@263: if (!type->isArray()) { asherkin@263: cc_.reportError(node->pos(), Message_SizeofNeedsArray); asherkin@263: return; asherkin@263: } asherkin@263: node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32)); asherkin@263: break; asherkin@263: } asherkin@263: asherkin@263: default: asherkin@263: assert(node->token() == TOK_TILDE); asherkin@263: if (!type->isInt32()) { asherkin@263: unaryTypeError(node, node->token(), type); asherkin@263: return; asherkin@263: } asherkin@263: node->setType(type); asherkin@263: break; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(TernaryExpression *node) asherkin@263: { asherkin@263: Local type(zone_, visitForLoad(node->condition())); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: if (!canTest(node->condition(), type)) asherkin@263: return; asherkin@263: asherkin@263: Local left(zone_, visitForLoad(node->left())); asherkin@263: Local right(zone_, visitForLoad(node->right())); asherkin@263: if (!left || !right) asherkin@263: return; asherkin@263: asherkin@263: if (left != right) { asherkin@263: binaryTypeError(node, TOK_QMARK, left, right); asherkin@263: return; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(BinaryExpression *node) asherkin@263: { asherkin@263: Local left(zone_, visitForLoad(node->left())); asherkin@263: Local right(zone_, visitForLoad(node->right())); asherkin@263: if (!left || !right) asherkin@263: return; asherkin@263: asherkin@263: Local result(zone_, typeCheckBinary(node, node->token(), left, right)); asherkin@263: if (!result) asherkin@263: return; asherkin@263: asherkin@263: node->setType(result); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(ReturnStatement *node) asherkin@263: { asherkin@263: // Set this early, so if we error we don't get more errors. asherkin@263: control_->returns(Returns_Always); asherkin@263: asherkin@263: if (!node->expression()) { asherkin@263: if (!function_->type()->returnType()->isVoid()) asherkin@263: cc_.reportError(node->pos(), Message_NotAllPathsReturnValue); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: Local type(zone_, visitForLoad(node->expression())); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: Local returnType(zone_, function_->type()->returnType()); asherkin@263: if (!typeCheckAssignment(node->pos(), type, returnType, true)) asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(ForStatement *node) asherkin@263: { asherkin@263: LoopScope loop(&loop_); asherkin@263: asherkin@263: if (node->scope()) asherkin@263: scope_ = node->scope(); asherkin@263: asherkin@263: if (node->initialization()) asherkin@263: node->initialization()->accept(this); asherkin@263: asherkin@263: if (node->condition()) { asherkin@263: Local type(zone_, visitForLoad(node->condition())); asherkin@263: if (!type || !canTest(node->condition(), type)) { asherkin@263: return; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: if (node->update()) asherkin@263: node->update()->accept(this); asherkin@263: asherkin@263: ControlStatus status = visitForControl(node->body()); asherkin@263: asherkin@263: // If there is a condition, we treat this like a while loop. Otherwise, asherkin@263: // join point is only reachable if the loop contains a break. The asherkin@263: // termination status doesn't tell us anything yet. asherkin@263: if (node->condition() || loop.breaks()) asherkin@263: control_->merge(status, ControlStatus(false, Returns_Never)); asherkin@263: else asherkin@263: control_->terminate(status.returns()); asherkin@263: asherkin@263: if (node->scope()) asherkin@263: scope_ = scope_->enclosing(); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(WhileStatement *node) asherkin@263: { asherkin@263: LoopScope loop(&loop_); asherkin@263: asherkin@263: Local type(zone_, visitForLoad(node->condition())); asherkin@263: if (!type || !canTest(node->condition(), type)) { asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: ControlStatus status = visitForControl(node->body()); asherkin@263: asherkin@263: // Detect loops that will always have a fork in the control-flow graph. asherkin@263: // This will be a |while| loop, or a |do-while| loop whose body does asherkin@263: // not terminate. asherkin@263: // asherkin@263: // For now, we treat these as an |if| regardless of the direction the asherkin@263: // branch can take. That means the control-flow is always conditional. asherkin@263: if (node->token() == TOK_WHILE || asherkin@263: !status.terminates() || asherkin@263: loop.breaks()) asherkin@263: { asherkin@263: control_->merge(status, ControlStatus(false, Returns_Never)); asherkin@263: } else { asherkin@263: // At this point, we've got a do-while loop with a |return| or asherkin@263: // |continue|, meaning that the rest of the block is unreachable. asherkin@263: control_->terminate(status.returns()); asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(BlockStatement *node) asherkin@263: { asherkin@263: if (node->scope()) asherkin@263: scope_ = node->scope(); asherkin@263: for (size_t i = 0; i < node->statements()->length(); i++) { asherkin@263: Statement *statement = node->statements()->at(i); asherkin@263: statement->accept(this); asherkin@263: } asherkin@263: if (node->scope()) asherkin@263: scope_ = scope_->enclosing(); asherkin@263: } asherkin@263: asherkin@263: static inline bool asherkin@263: IsScalarString(Type *type) asherkin@263: { asherkin@263: if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) asherkin@263: return true; asherkin@263: if (type->isReference()) asherkin@263: return IsScalarString(type->contained()); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: static const int INFER_ARRAY_SIZE = 0; asherkin@263: static const int EVAL_ARRAY_SIZE = -1; asherkin@263: static const int DYNAMIC_ARRAY_SIZE = -2; asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]) asherkin@263: { asherkin@263: bool hadEmptySize = false; asherkin@263: asherkin@263: for (size_t i = 0; i < exprs->length(); i++) { asherkin@263: Expression *expr = exprs->at(i); asherkin@263: if (!expr) { asherkin@263: dims[i] = INFER_ARRAY_SIZE; asherkin@263: hadEmptySize = true; asherkin@263: continue; asherkin@263: } asherkin@263: asherkin@263: BoxedPrimitive box; asherkin@263: if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) { asherkin@263: int size = box.toInt(); asherkin@263: if (size <= 0) { asherkin@263: cc_.reportError(expr->pos(), Message_BadArraySize); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: dims[i] = size; asherkin@263: continue; asherkin@263: } asherkin@263: asherkin@263: Local exprType(zone_, visitForLoad(expr)); asherkin@263: if (!exprType) asherkin@263: return false; asherkin@263: asherkin@263: if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) { asherkin@263: cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: if (hadEmptySize) { asherkin@263: cc_.reportError(expr->pos(), Message_BadDynamicInitializer); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: dims[i] = EVAL_ARRAY_SIZE; asherkin@263: } asherkin@263: asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle contained, asherkin@263: int dims[MAX_ARRAY_DEPTH], asherkin@263: unsigned dimcount, unsigned level) asherkin@263: { asherkin@263: if (dims[level] == EVAL_ARRAY_SIZE) { asherkin@263: cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: if (dims[level] == INFER_ARRAY_SIZE) { asherkin@263: // Strings always become dynamic arrays. asherkin@263: if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char)) asherkin@263: dims[level] = literal->expressions()->length(); asherkin@263: } else if (dims[level] == DYNAMIC_ARRAY_SIZE) { asherkin@263: cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray); asherkin@263: return false; asherkin@263: } else { asherkin@263: if (literal->expressions()->length() != unsigned(dims[level])) { asherkin@263: cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1); asherkin@263: return false; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) { asherkin@263: for (size_t i = 0; i < literal->expressions()->length(); i++) { asherkin@263: Expression *expr = literal->expressions()->at(i); asherkin@263: if (!expr->isStringLiteral()) { asherkin@263: cc_.reportError(expr->pos(), Message_ExpectedStringLiteral); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: StringLiteral *lit = expr->toStringLiteral(); asherkin@263: if (dims[level + 1] > 0 && asherkin@263: unsigned(dims[level]) < lit->string()->length()) asherkin@263: { asherkin@263: cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2); asherkin@263: return false; asherkin@263: } asherkin@263: if (!visitAndApplyType(lit)) asherkin@263: return false; asherkin@263: } asherkin@263: } else if (level == dimcount - 1) { asherkin@263: Local type(zone_); asherkin@263: for (size_t i = 0; i < literal->expressions()->length(); i++) { asherkin@263: Expression *expr = literal->expressions()->at(i); asherkin@263: if (expr->isArrayLiteral()) { asherkin@263: cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: if ((type = visitAndApplyType(expr)) == NULL) asherkin@263: return false; asherkin@263: asherkin@263: if (!typeCheckAssignment(expr->pos(), type, contained, true)) asherkin@263: return false; asherkin@263: } asherkin@263: } else { asherkin@263: for (size_t i = 0; i < literal->expressions()->length(); i++) { asherkin@263: Expression *expr = literal->expressions()->at(i); asherkin@263: if (!expr->isArrayLiteral()) { asherkin@263: cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: assert(expr->toArrayLiteral()->isFixed()); asherkin@263: asherkin@263: if (!inferFixedArrayLiteral(expr->toArrayLiteral(), asherkin@263: contained, asherkin@263: dims, asherkin@263: dimcount, asherkin@263: level + 1)) asherkin@263: { asherkin@263: return false; asherkin@263: } asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(VariableDeclaration *node) asherkin@263: { asherkin@263: Local type(zone_, bindType(node->pos(), node->type())); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: #if 0 asherkin@263: if (node->postDimensions() || type->isArray()) { asherkin@263: // The type could be an array type, so sum the type and postDimensions asherkin@263: // together. asherkin@263: unsigned dimcount = node->postDimensions()->length(); asherkin@263: if (type->isArray()) asherkin@263: dimcount += type->levels(); asherkin@263: if (dimcount > MAX_ARRAY_DEPTH) { asherkin@263: cc_.reportError(node->pos(), Message_MaximumArrayDepth); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: // Take an initial guess at the array dimension sizes. asherkin@263: int dims[MAX_ARRAY_DEPTH]; asherkin@263: if (!evaluateDimensions(node->postDimensions(), dims)) asherkin@263: return; asherkin@263: asherkin@263: // Now add in the type's array dimensions. asherkin@263: Local contained(zone_, type); asherkin@263: for (size_t i = node->postDimensions()->length(); i < dimcount; i++) { asherkin@263: if (type->isFixedLength()) asherkin@263: dims[i] = type->fixedLength(); asherkin@263: else asherkin@263: dims[i] = DYNAMIC_ARRAY_SIZE; asherkin@263: contained = contained->contained(); asherkin@263: } asherkin@263: asherkin@263: Expression *initializer = node->initialization(); asherkin@263: if (initializer && asherkin@263: initializer->isArrayLiteral() && asherkin@263: initializer->toArrayLiteral()->isFixed()) asherkin@263: { asherkin@263: // Fixed array initializers are special; we use them to infer any asherkin@263: // missing information in the original array. We do not evaluate asherkin@263: // the array initializer as an expression. asherkin@263: if (!inferFixedArrayLiteral(initializer->toArrayLiteral(), asherkin@263: contained, asherkin@263: dims, asherkin@263: dimcount, asherkin@263: 0)) asherkin@263: { asherkin@263: return; asherkin@263: } asherkin@263: initializer = NULL; asherkin@263: } asherkin@263: asherkin@263: // We now have enough information to build the actual array type. asherkin@263: // Start from the original dimcount, not the one computed for asherkin@263: // initializers. asherkin@263: for (size_t i = node->postDimensions()->length() - 1; asherkin@263: i < node->postDimensions()->length(); asherkin@263: i--) asherkin@263: { asherkin@263: int size = dims[i] > 0 asherkin@263: ? dims[i] asherkin@263: : Type::DYNAMIC_ARRAY_SIZE; asherkin@263: asherkin@263: type = zone_->types()->newArray(type, size, false); asherkin@263: if (!type) asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: // Finally, if we had a non-fixed initializer, make sure it type asherkin@263: // checks. asherkin@263: if (initializer) { asherkin@263: Local right(zone_, visitForLoad(initializer)); asherkin@263: if (!right) asherkin@263: return; asherkin@263: asherkin@263: if (!typeCheckAssignment(node->pos(), right, type, true)) asherkin@263: return; asherkin@263: } asherkin@263: } else { asherkin@263: if (node->initialization()) { asherkin@263: Local right(zone_, visitForLoad(node->initialization())); asherkin@263: if (!right) asherkin@263: return; asherkin@263: if (!typeCheckAssignment(node->pos(), right, type, true)) asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) { asherkin@263: cc_.reportError(node->pos(), Message_CannotDeclareStringCell); asherkin@263: return; asherkin@263: } asherkin@263: } asherkin@263: #endif asherkin@263: asherkin@263: #if 0 asherkin@263: // If this variable is stack allocated, we could use the LIFO heap asherkin@263: // to allocate it. If that's the case, make sure to reserve a slot asherkin@263: // so we can unwind the LIFO heap at the end of this scope. asherkin@263: if (!node->variable()->needsHeapAllocation()) { asherkin@263: if (type->isArray() || type->isStruct()) asherkin@263: scope_->setUsesLifoHeap(); asherkin@263: } asherkin@263: asherkin@263: node->variable()->setType(type); asherkin@263: #endif asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(IntegerLiteral *node) asherkin@263: { asherkin@263: node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32)); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(BooleanLiteral *node) asherkin@263: { asherkin@263: node->setType(zone_->types()->getPrimitive(PrimitiveType_Bool)); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(ExpressionStatement *node) asherkin@263: { asherkin@263: visitAndApplyType(node->expression()); asherkin@263: } asherkin@263: asherkin@263: Box * asherkin@263: SemanticAnalysis::evaluateDefaultParameter(Handle type, Parameter *parameter) asherkin@263: { asherkin@263: Local given(zone_, visitForLoad(parameter->initializer())); asherkin@263: asherkin@263: BoxedPrimitive prim; asherkin@263: if (EvaluateForConstant(parameter->initializer(), &prim)) { asherkin@263: if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false)) asherkin@263: return NULL; asherkin@263: asherkin@263: if (prim.type() == PrimitiveType_Int32) asherkin@263: return Box::New(zone_, given, prim.toInt()); asherkin@263: return Box::New(zone_, given, prim.toFloat()); asherkin@263: } else if (parameter->initializer()->isStringLiteral()) { asherkin@263: StringLiteral *literal = parameter->initializer()->toStringLiteral(); asherkin@263: asherkin@263: if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false)) asherkin@263: return NULL; asherkin@263: asherkin@263: Local map(zone_, ArrayMap::Attach(zone_, given)); asherkin@263: if (!map) asherkin@263: return NULL; asherkin@263: asherkin@263: Local array(zone_, asherkin@263: Array::NewString(zone_, asherkin@263: map, asherkin@263: literal->string()->raw(), asherkin@263: literal->string()->length(), asherkin@263: Heap::Tenure_Old)); asherkin@263: if (!array) asherkin@263: return NULL; asherkin@263: asherkin@263: return Box::NewObj(zone_, given, array, Heap::Tenure_Old); asherkin@263: } asherkin@263: asherkin@263: cc_.reportError(parameter->initializer()->pos(), Message_MustBeConstant); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig, asherkin@263: FixedArray **argsp, FixedArray **defaultsp) asherkin@263: { asherkin@263: Local args(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old)); asherkin@263: if (!args) asherkin@263: return false; asherkin@263: asherkin@263: Local defaults(zone_); asherkin@263: asherkin@263: // Apply types to arguments. asherkin@263: for (size_t i = 0; i < sig.parameters()->length(); i++) { asherkin@263: Parameter *parameter = sig.parameters()->at(i); asherkin@263: asherkin@263: #if 0 asherkin@263: Local type(zone_, bindType(parameter->variable()->pos(), parameter->type())); asherkin@263: if (!type) asherkin@263: return false; asherkin@263: asherkin@263: if (parameter->reference()) { asherkin@263: if (parameter->dimensions()) { asherkin@263: cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: if (type->isStruct()) { asherkin@263: cc_.reportError(parameter->variable()->pos(), Message_StructCantBeReference); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: type = zone_->types()->getReference(type, parameter->isConst()); asherkin@263: if (!type) asherkin@263: return false; asherkin@263: } else if (parameter->dimensions()) { asherkin@263: type = buildArrayType(type, parameter->dimensions(), parameter->isConst()); asherkin@263: if (!type) asherkin@263: return false; asherkin@263: asherkin@263: if (kind == TOK_NATIVE && type->levels() > 1) { asherkin@263: cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative); asherkin@263: return false; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: if (IsScalarString(type)) { asherkin@263: cc_.reportError(node->pos(), Message_CannotDeclareStringCell); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: args->set(zone_, i, type); asherkin@263: parameter->variable()->setType(type); asherkin@263: asherkin@263: if (parameter->initializer()) { asherkin@263: if (!defaults) { asherkin@263: defaults = FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old); asherkin@263: if (!defaults) asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: Local box(zone_, evaluateDefaultParameter(type, parameter)); asherkin@263: if (!box) asherkin@263: return false; asherkin@263: asherkin@263: defaults->set(zone_, i, box); asherkin@263: } asherkin@263: #endif asherkin@263: } asherkin@263: asherkin@263: *argsp = args; asherkin@263: *defaultsp = defaults; asherkin@263: asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(FunctionTypeStatement *node) asherkin@263: { asherkin@263: if (node->decl()->type()) asherkin@263: return; asherkin@263: asherkin@263: Local args(zone_); asherkin@263: Local defaults(zone_); asherkin@263: asherkin@263: const FunctionSignature &sig= node->signature(); asherkin@263: if (!buildFunctionArgs(node, asherkin@263: TOK_STOCK, asherkin@263: sig, asherkin@263: args.address(), asherkin@263: defaults.address())) asherkin@263: { asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: #if 0 asherkin@263: Local returnType(zone_); asherkin@263: if (sig.returnType()) asherkin@263: returnType = bindType(node->pos(), sig.returnType()); asherkin@263: else asherkin@263: returnType = zone_->types()->getPrimitive(PrimitiveType_Int32); asherkin@263: asherkin@263: if (!returnType) asherkin@263: return; asherkin@263: asherkin@263: Local funtype(zone_, zone_->types()->newFunction(returnType, args, defaults)); asherkin@263: if (!funtype) asherkin@263: return; asherkin@263: asherkin@263: node->decl()->setType(funtype); asherkin@263: #endif asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: SemanticAnalysis::buildArrayType(Handle type, ExpressionList *dimensions, bool isConst) asherkin@263: { asherkin@263: Local arrayType(zone_, type); asherkin@263: asherkin@263: unsigned dimcount = dimensions->length(); asherkin@263: if (type->isArray()) asherkin@263: dimcount += type->levels(); asherkin@263: asherkin@263: if (dimcount > MAX_ARRAY_DEPTH) { asherkin@263: cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(), asherkin@263: Message_MaximumArrayDepth); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: // Note: constness is sort of bogus. Fix this sometime. asherkin@263: for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) { asherkin@263: Expression *expr = dimensions->at(i); asherkin@263: if (!expr) { asherkin@263: arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst); asherkin@263: if (!arrayType) asherkin@263: return NULL; asherkin@263: asherkin@263: continue; asherkin@263: } asherkin@263: asherkin@263: BoxedPrimitive box; asherkin@263: if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) { asherkin@263: cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: if (box.toInt() <= 0) { asherkin@263: cc_.reportError(expr->pos(), Message_BadArraySize); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst); asherkin@263: if (!arrayType) asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: return arrayType; asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::preanalyze(FunctionStatement *node) asherkin@263: { asherkin@263: Local args(zone_); asherkin@263: Local defaults(zone_); asherkin@263: asherkin@263: const FunctionSignature &sig = node->signature(); asherkin@263: if (!buildFunctionArgs(node, asherkin@263: node->fun()->token(), asherkin@263: sig, asherkin@263: args.address(), asherkin@263: defaults.address())) asherkin@263: { asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: #if 0 asherkin@263: Local returnType(zone_); asherkin@263: if (sig.returnType() || asherkin@263: node->hasExplicitReturn() || asherkin@263: node->fun()->isNative()) asherkin@263: { asherkin@263: returnType = bindType(node->pos(), sig.returnType()); asherkin@263: } else { asherkin@263: returnType = zone_->types()->getVoid(); asherkin@263: } asherkin@263: if (!returnType) asherkin@263: return false; asherkin@263: asherkin@263: if (sig.returnDimensions()) { asherkin@263: returnType = buildArrayType(returnType, sig.returnDimensions(), false); asherkin@263: if (!returnType) asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: if (IsScalarString(returnType)) { asherkin@263: cc_.reportError(node->pos(), Message_CannotDeclareStringCell); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: Local funtype(zone_); asherkin@263: if (node->fun()->isNative()) asherkin@263: funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic()); asherkin@263: else asherkin@263: funtype = zone_->types()->newFunction(returnType, args, defaults); asherkin@263: if (!funtype) asherkin@263: return false; asherkin@263: asherkin@263: // If the function already has a type, it was forward declared before, and asherkin@263: // now this is our chance to type check the second declaration. asherkin@263: if (node->fun()->type()) { asherkin@263: Local forward(zone_, node->fun()->type()); asherkin@263: if (!Type::Compare(funtype, forward)) { asherkin@263: cc_.reportError(node->pos(), Message_ForwardDeclareMismatches); asherkin@263: return false; asherkin@263: } asherkin@263: node->fun()->setForwardType(forward); asherkin@263: } asherkin@263: asherkin@263: node->fun()->setType(funtype); asherkin@263: #endif asherkin@263: asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(FunctionStatement *node) asherkin@263: { asherkin@263: function_ = node->fun(); asherkin@263: scope_ = node->scope(); asherkin@263: asherkin@263: ControlScope control(&control_); asherkin@263: if (node->body()) { asherkin@263: node->body()->accept(this); asherkin@263: asherkin@263: ControlStatus status = control.status(); asherkin@263: if (status.returns() == Returns_Sometimes) { asherkin@263: cc_.reportError(node->pos(), Message_NotAllPathsReturnValue); asherkin@263: } else if (status.returns() == Returns_Never) { asherkin@263: if (!function_->type()->returnType()->isVoid()) asherkin@263: cc_.reportError(node->pos(), Message_MissingReturnValue); asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: scope_ = NULL; asherkin@263: function_ = NULL; asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::typeMismatch(const SourcePosition &pos, Handle actual, Handle given) asherkin@263: { asherkin@263: cc_.reportError(pos, Message_TypeMismatch, asherkin@263: GetTypeName(actual), asherkin@263: GetTypeName(given)); asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::typeCheckArrayAssignment(const SourcePosition &pos, Handle argGiven, asherkin@263: Handle argActual, bool forAssign) asherkin@263: { asherkin@263: Local actual(zone_, argActual); asherkin@263: Local given(zone_, argGiven); asherkin@263: asherkin@263: if (!given->isArray()) { asherkin@263: cc_.reportError(pos, Message_ExpectedArray); asherkin@263: return false; asherkin@263: } asherkin@263: if (given->levels() != actual->levels()) { asherkin@263: cc_.reportError(pos, Message_ArrayDimensionsMismatch); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: unsigned level = 1; asherkin@263: while (given->isArray()) { asherkin@263: if (actual->isFixedLength()) { asherkin@263: if (forAssign) { asherkin@263: if (!given->isFixedLength()) { asherkin@263: cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: if (actual->isCharArray()) { asherkin@263: // String assignment can have a truncated |given|. asherkin@263: if (given->fixedLength() > actual->fixedLength()) { asherkin@263: cc_.reportError(pos, Message_ArrayAssignmentTooBig); asherkin@263: return false; asherkin@263: } asherkin@263: } else { asherkin@263: if (given->fixedLength() != actual->fixedLength()) { asherkin@263: cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level); asherkin@263: return false; asherkin@263: } asherkin@263: } asherkin@263: } asherkin@263: } else if (given->isFixedLength()) { asherkin@263: // We do not allow assignments in the form: asherkin@263: // [][] = [][Y] asherkin@263: // asherkin@263: // Otherwise, the following code could break the size guarantees asherkin@263: // of the right-hand side: asherkin@263: // asherkin@263: // new x[][5]; asherkin@263: // new y[][]; asherkin@263: // new z[3]; asherkin@263: // asherkin@263: // y = x; asherkin@263: // y[0] = z; asherkin@263: // asherkin@263: // Now |x[0]| contains a 4-length array. asherkin@263: if (level > 1) { asherkin@263: cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level); asherkin@263: return false; asherkin@263: } asherkin@263: } asherkin@263: given = given->contained(); asherkin@263: actual = actual->contained(); asherkin@263: level++; asherkin@263: } asherkin@263: asherkin@263: return typeCheckAssignment(pos, given, actual, forAssign); asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::typeCheckAssignment(const SourcePosition &pos, Handle argGiven, asherkin@263: Handle argActual, bool forAssign) asherkin@263: { asherkin@263: Local actual(zone_, argActual); asherkin@263: Local given(zone_, argGiven); asherkin@263: asherkin@263: if (actual->isArray()) asherkin@263: return typeCheckArrayAssignment(pos, given, actual, forAssign); asherkin@263: asherkin@263: if (given->isArray()) { asherkin@263: cc_.reportError(pos, Message_CannotAssignArrayToScalar); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: // The given type may not have been dereferenced. asherkin@263: if (given->isReference()) asherkin@263: given = given->contained(); asherkin@263: if (actual->isReference()) asherkin@263: actual = actual->contained(); asherkin@263: asherkin@263: // We coerce unchecked to a few things. asherkin@263: if (actual->isUnchecked() || given->isUnchecked()) { asherkin@263: Type *check = actual->isUnchecked() ? given : actual; asherkin@263: if (check->isUnchecked() || asherkin@263: check->isEnum() || asherkin@263: check->isInt32() || asherkin@263: check->isBool() || asherkin@263: check->isFloat()) asherkin@263: { asherkin@263: return true; asherkin@263: } asherkin@263: typeMismatch(pos, actual, given); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: if (given->isFunction() && actual->isFunction()) { asherkin@263: if (!Type::Compare(given, actual)) { asherkin@263: typeMismatch(pos, actual, given); asherkin@263: return false; asherkin@263: } asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: if (actual->isEnum()) { asherkin@263: if (!given->isEnum() || actual != given) { asherkin@263: typeMismatch(pos, actual, given); asherkin@263: return false; asherkin@263: } asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: if (actual->isStruct()) { asherkin@263: if (!given->isStruct() || actual != given) { asherkin@263: typeMismatch(pos, actual, given); asherkin@263: return false; asherkin@263: } asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: if (given->isEnum() || given->isFunction() || given->isStruct()) { asherkin@263: typeMismatch(pos, actual, given); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: // This coercion is trivial. asherkin@263: if (given->isBool() && actual->isInt32()) asherkin@263: return true; asherkin@263: asherkin@263: if (given->primitive() != actual->primitive()) { asherkin@263: typeMismatch(pos, actual, given); asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::typeCheckParameter(AstNode *node, Handle given, Handle actual) asherkin@263: { asherkin@263: return typeCheckAssignment(node->pos(), given, actual, false); asherkin@263: } asherkin@263: asherkin@263: bool asherkin@263: SemanticAnalysis::checkArgumentCount(Handle type, unsigned actual) asherkin@263: { asherkin@263: if (type->parameters()->length() == actual) asherkin@263: return true; asherkin@263: asherkin@263: if (actual > type->parameters()->length()) { asherkin@263: if (!type->isNative() || !type->isNativeVariadic()) asherkin@263: return false; asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: if (!type->defaults()) asherkin@263: return false; asherkin@263: asherkin@263: // Missing arguments. See if there's a default argument for each missing asherkin@263: // actual. asherkin@263: for (unsigned i = actual; i < type->parameters()->length(); i++) { asherkin@263: if (!type->defaults()->at(i)) asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: return true; asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(CallExpression *node) asherkin@263: { asherkin@263: Local type(zone_, visitForLoad(node->callee())); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: if (!type->isFunction()) { asherkin@263: cc_.reportError(node->pos(), Message_CalleeNotFunction); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: if (!checkArgumentCount(type, node->arguments()->length())) { asherkin@263: cc_.reportError(node->pos(), Message_ArgumentCountMismatch); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: // NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction(); asherkin@263: // if (fun->isForward()) { asherkin@263: // cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars()); asherkin@263: // return; asherkin@263: // } asherkin@263: asherkin@263: for (unsigned i = 0; i < node->arguments()->length(); i++) { asherkin@263: // Note: we don't compute references unless the callee needs a asherkin@263: // reference type. asherkin@263: Expression *expression = node->arguments()->at(i); asherkin@263: Local given(zone_, visitAndApplyType(expression)); asherkin@263: if (!given) asherkin@263: return; asherkin@263: asherkin@263: // Since we skip a load, check for a call expression that returns void. asherkin@263: if (given->isVoid()) { asherkin@263: assert(expression->isCallExpression()); asherkin@263: CallExpression *call = expression->toCallExpression(); asherkin@263: cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: bool mustComputeReference; asherkin@263: if (i >= type->parameters()->length()) { asherkin@263: // Special handling for natives. Arguments past the formal must asherkin@263: // always have references computed. However, arrays are already asherkin@263: // references for natives. asherkin@263: assert(type->isNative() && type->isNativeVariadic()); asherkin@263: mustComputeReference = !given->isReference() && !given->isArray(); asherkin@263: } else { asherkin@263: Local actual(zone_, type->parameterAt(i)); asherkin@263: asherkin@263: if (expression->isIndexExpression()) { asherkin@263: // Disabled until we can make it work. asherkin@263: #if 0 asherkin@263: if (actual->isArray()) { asherkin@263: // We special case the ability to pass x[y] into x[], which asherkin@263: // creates an array slice. We only do this if we know the asherkin@263: // assignment would otherwise not type-check. asherkin@263: IndexExpression *index = expression->toIndexExpression(); asherkin@263: if (index->left()->type()->levels() == actual->levels()) asherkin@263: given = index->left()->type(); asherkin@263: } else asherkin@263: #endif asherkin@263: if (actual->isReference()) { asherkin@263: cc_.reportError(expression->pos(), Message_CannotComputeIndexRef); asherkin@263: return; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: if (!typeCheckParameter(expression, given, actual)) asherkin@263: return; asherkin@263: mustComputeReference = actual->isReference() && !given->isReference(); asherkin@263: } asherkin@263: asherkin@263: // If the actual is a reference, and the given is not, we'll need to asherkin@263: // compute a reference, which may be allocated on the stack. asherkin@263: if (mustComputeReference) asherkin@263: scope_->setUsesLifoHeap(); asherkin@263: } asherkin@263: asherkin@263: node->setType(type->returnType()); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::ControlScope::inherit(const ControlStatus &other) asherkin@263: { asherkin@263: if (other.returns() < status().returns()) asherkin@263: return; asherkin@263: asherkin@263: if (other.terminates()) asherkin@263: terminate(other.returns()); asherkin@263: else asherkin@263: returns(other.returns()); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right) asherkin@263: { asherkin@263: // If both sides terminate in a return, we consider this a return as well. asherkin@263: if (left.returns() == Returns_Always && right.returns() == Returns_Always) { asherkin@263: terminate(Returns_Always); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never) asherkin@263: ? Returns_Never asherkin@263: : Returns_Sometimes; asherkin@263: asherkin@263: if (left.terminates() && right.terminates()) asherkin@263: terminate(status); asherkin@263: else asherkin@263: returns(status); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(IfStatement *node) asherkin@263: { asherkin@263: Local type(zone_, visitForLoad(node->condition())); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: if (!canTest(node, type)) asherkin@263: return; asherkin@263: asherkin@263: ControlStatus trueBranch = visitForControl(node->ifTrue()); asherkin@263: ControlStatus falseBranch = ControlStatus(false, Returns_Never); asherkin@263: asherkin@263: if (node->ifFalse()) asherkin@263: falseBranch = visitForControl(node->ifFalse()); asherkin@263: asherkin@263: control_->merge(trueBranch, falseBranch); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(IndexExpression *node) asherkin@263: { asherkin@263: Local left(zone_, visitForLoad(node->left())); asherkin@263: Local right(zone_, visitForLoad(node->right())); asherkin@263: asherkin@263: if (!left || !right) asherkin@263: return; asherkin@263: asherkin@263: if (!right->isInt32() && !right->isEnum()) { asherkin@263: cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger); asherkin@263: return; asherkin@263: } asherkin@263: if (!left->isArray()) { asherkin@263: cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: // Note: char arrays are automatically up-casted to return an int32. asherkin@263: if (left->isCharArray()) asherkin@263: node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32)); asherkin@263: else asherkin@263: node->setType(left->contained()); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(FieldExpression *node) asherkin@263: { asherkin@263: Local left(zone_, visitForLoad(node->left())); asherkin@263: if (!left) asherkin@263: return; asherkin@263: asherkin@263: if (!left->isStruct()) { asherkin@263: cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(), asherkin@263: GetTypeName(left)); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: Local field(zone_, node->field()); asherkin@263: asherkin@263: unsigned offset; asherkin@263: Local desc(zone_, left->lookupField(field, &offset)); asherkin@263: if (!desc) { asherkin@263: cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(), asherkin@263: GetTypeName(left)); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: node->setFieldIndex(offset); asherkin@263: node->setType(desc->type()); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(EnumStatement *node) asherkin@263: { asherkin@263: Local name(zone_, node->name()); asherkin@263: Local type(zone_); asherkin@263: if (name) asherkin@263: type = zone_->types()->newEnum(name); asherkin@263: else asherkin@263: type = zone_->types()->getPrimitive(PrimitiveType_Int32); asherkin@263: asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: if (node->decl()) asherkin@263: node->decl()->setType(type); asherkin@263: asherkin@263: int value = 0; asherkin@263: for (size_t i = 0; i < node->entries()->length(); i++) { asherkin@263: EnumStatement::Entry &entry = node->entries()->at(i); asherkin@263: asherkin@263: BoxedPrimitive box = BoxedPrimitive::Int(value); asherkin@263: if (entry.expr) { asherkin@263: entry.expr->accept(this); asherkin@263: if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) { asherkin@263: cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: assert(box.type() == PrimitiveType_Int32); asherkin@263: value = box.toInt(); asherkin@263: } asherkin@263: asherkin@263: #if 0 asherkin@263: entry.name->set(type, box); asherkin@263: #endif asherkin@263: value++; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: static int asherkin@263: SortCaseIntValues(const void *p1, const void *p2) asherkin@263: { asherkin@263: CaseValue *v1 = (CaseValue *)p1; asherkin@263: CaseValue *v2 = (CaseValue *)p2; asherkin@263: asherkin@263: return v1->box.toInt() - v2->box.toInt(); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(SwitchStatement *node) asherkin@263: { asherkin@263: Local caseType(zone_, visitForLoad(node->expression())); asherkin@263: if (!caseType) asherkin@263: return; asherkin@263: asherkin@263: if (!caseType->isEnum() && !caseType->isInt32()) { asherkin@263: cc_.reportError(node->pos(), Message_CaseMustBeInteger); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: PoolList *values = new (zone_->pool()) PoolList(); asherkin@263: ControlStatus status = ControlStatus(false, Returns_Never); asherkin@263: asherkin@263: Local check(zone_); asherkin@263: for (size_t i = 0; i < node->cases()->length(); i++) { asherkin@263: Case *c = node->cases()->at(i); asherkin@263: asherkin@263: check = visitForLoad(c->expression()); asherkin@263: if (!check) asherkin@263: return; asherkin@263: asherkin@263: if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false)) asherkin@263: return; asherkin@263: asherkin@263: CaseValue v(i); asherkin@263: if (!EvaluateForConstant(c->expression(), &v.box)) { asherkin@263: cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant); asherkin@263: return; asherkin@263: } asherkin@263: if (!values->append(v)) asherkin@263: return; asherkin@263: asherkin@263: if (c->others()) { asherkin@263: for (size_t j = 0; j < c->others()->length(); j++) { asherkin@263: Expression *expr = c->others()->at(j); asherkin@263: check = visitForLoad(expr); asherkin@263: if (!check) asherkin@263: return; asherkin@263: asherkin@263: if (!typeCheckAssignment(expr->pos(), check, caseType, false)) asherkin@263: return; asherkin@263: asherkin@263: CaseValue v(i); asherkin@263: if (!EvaluateForConstant(expr, &v.box)) { asherkin@263: cc_.reportError(expr->pos(), Message_CaseMustBeConstant); asherkin@263: return; asherkin@263: } asherkin@263: if (!values->append(v)) asherkin@263: return; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: ControlStatus latest = visitForControl(c->statement()); asherkin@263: asherkin@263: if (i != 0) asherkin@263: control_->merge(status, latest); asherkin@263: asherkin@263: status = latest; asherkin@263: } asherkin@263: asherkin@263: if (node->defaultCase()) { asherkin@263: ControlStatus latest = visitForControl(node->defaultCase()); asherkin@263: asherkin@263: if (node->cases()->length()) { asherkin@263: // If we had any other cases, we must merge. asherkin@263: control_->merge(status, latest); asherkin@263: } else { asherkin@263: // Otherwise, control-flow always flows through here. asherkin@263: control_->inherit(latest); asherkin@263: } asherkin@263: } else if (node->cases()->length()) { asherkin@263: control_->merge(status, ControlStatus(false, Returns_Never)); asherkin@263: } asherkin@263: asherkin@263: if (values->length() > 1) { asherkin@263: qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues); asherkin@263: asherkin@263: for (size_t i = 1; i < values->length(); i++) { asherkin@263: CaseValue &prev = values->at(i - 1); asherkin@263: CaseValue &cur = values->at(i); asherkin@263: if (prev.box.toInt() == cur.box.toInt()) { asherkin@263: cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue); asherkin@263: return; asherkin@263: } asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: node->setCaseValueList(values); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(StructureStatement *node) asherkin@263: { asherkin@263: #if 0 asherkin@263: // If this node already has a type, it was pre-analyzed, so skip it. asherkin@263: if (node->decl()->type()) asherkin@263: return; asherkin@263: asherkin@263: FieldList *fields = node->fields(); asherkin@263: Local desctable(zone_, FixedArray::New(zone_, fields->length(), Heap::Tenure_Old)); asherkin@263: if (!desctable) asherkin@263: return; asherkin@263: asherkin@263: Vector composedList; asherkin@263: StructureBufferBuilder builder; asherkin@263: asherkin@263: Local type(zone_); asherkin@263: Local name(zone_); asherkin@263: Local desc(zone_); asherkin@263: for (size_t i = 0; i < fields->length(); i++) { asherkin@263: StructureStatement::Field *field = fields->at(i); asherkin@263: asherkin@263: type = bindType(field->pos(), field->type()); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: if (field->dimensions()) { asherkin@263: type = buildArrayType(type, field->dimensions(), false); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: if (!ArrayMap::Attach(zone_, type)) asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: if (IsScalarString(type)) { asherkin@263: cc_.reportError(field->pos(), Message_CannotDeclareStringCell); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: unsigned offset; asherkin@263: if (!builder.add(type, &offset)) asherkin@263: return; asherkin@263: asherkin@263: name = field->name(); asherkin@263: desc = Descriptor::New(zone_, name, type, offset); asherkin@263: if (!desc) asherkin@263: return; asherkin@263: asherkin@263: desctable->set(zone_, i, desc); asherkin@263: asherkin@263: if (type->isStruct() || type->isArray()) { asherkin@263: if (!composedList.append(i)) asherkin@263: return; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: Local composed(zone_); asherkin@263: if (composedList.length()) { asherkin@263: composed = FixedArray::New(zone_, composedList.length(), Heap::Tenure_Old); asherkin@263: if (!composed) asherkin@263: return; asherkin@263: asherkin@263: for (unsigned i = 0; i < composedList.length(); i++) asherkin@263: composed->set(zone_, i, desctable->at(i)); asherkin@263: } asherkin@263: asherkin@263: Local map(zone_, StructMap::New(zone_, builder, composed)); asherkin@263: if (!map) asherkin@263: return; asherkin@263: asherkin@263: name = node->decl()->name(); asherkin@263: type = zone_->types()->newStruct(name, desctable, map); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: map->setType(type); asherkin@263: node->decl()->setType(type); asherkin@263: #endif asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(StringLiteral *node) asherkin@263: { asherkin@263: Local type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char)); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: type = Type::NewArray(zone_, type, node->string()->length() + 1, true); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: node->setType(type); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(FloatLiteral *node) asherkin@263: { asherkin@263: Local type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float)); asherkin@263: if (!type) asherkin@263: return; asherkin@263: asherkin@263: node->setType(type); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(BreakStatement *node) asherkin@263: { asherkin@263: if (!loop_) { asherkin@263: cc_.reportError(node->pos(), Message_BreakOutsideLoop); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: // Note: ignore breaks that occur in unreachable control-flow. asherkin@263: if (!control_->status().terminates()) asherkin@263: loop_->addBreak(); asherkin@263: asherkin@263: control_->terminate(Returns_Never); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(ContinueStatement *node) asherkin@263: { asherkin@263: if (!loop_) { asherkin@263: cc_.reportError(node->pos(), Message_ContinueOutsideLoop); asherkin@263: return; asherkin@263: } asherkin@263: asherkin@263: // Note: ignore continues that occur in unreachable control-flow. asherkin@263: if (!control_->status().terminates()) asherkin@263: loop_->addContinue(); asherkin@263: asherkin@263: control_->terminate(Returns_Never); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(ArrayLiteral *node) asherkin@263: { asherkin@263: // We should never visit this. asherkin@263: cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral); asherkin@263: } asherkin@263: asherkin@263: void asherkin@263: SemanticAnalysis::visit(ImportStatement *node) asherkin@263: { asherkin@263: } asherkin@263: dvander@195: #endif