TEST(TestDeclaration, testLet) { PARSE_STATEMENT(L"let a : Int[] = [1, 2, 3]"); ValueBindingsPtr c; IdentifierPtr id; ValueBindingPtr a; ArrayLiteralPtr value; ArrayTypePtr type; TypeIdentifierPtr Int; ASSERT_NOT_NULL(c = std::dynamic_pointer_cast<ValueBindings>(root)); ASSERT_TRUE(c->isReadOnly()); ASSERT_EQ(1, c->numBindings()); ASSERT_NOT_NULL(a = c->get(0)); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(a->getName())); ASSERT_EQ(L"a", id->getIdentifier()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<ArrayType>(a->getDeclaredType())); ASSERT_NOT_NULL(Int = std::dynamic_pointer_cast<TypeIdentifier>(type->getInnerType())); ASSERT_EQ(L"Int", Int->getName()); ASSERT_NOT_NULL(value = std::dynamic_pointer_cast<ArrayLiteral>(c->get(0)->getInitializer())); ASSERT_EQ(3, value->numElements()); ASSERT_EQ(L"1", std::dynamic_pointer_cast<IntegerLiteral>(value->getElement(0))->valueAsString); ASSERT_EQ(L"2", std::dynamic_pointer_cast<IntegerLiteral>(value->getElement(1))->valueAsString); ASSERT_EQ(L"3", std::dynamic_pointer_cast<IntegerLiteral>(value->getElement(2))->valueAsString); }
void ArrayIndexNode::computeType (LContext &lcontext, const SymbolInfoPtr &initInfo) { if (!array || !index) return; array->computeType (lcontext, initInfo); index->computeType (lcontext, initInfo); if (!array->type || !index->type) return; ArrayTypePtr arrayType = array->type.cast<ArrayType>(); if (!arrayType) { string name = ""; if( NameNodePtr arrayName = array.cast<NameNode>() ) { name = arrayName->name; MESSAGE_LE (lcontext, ERR_NON_ARR_IND, array->lineNumber, "Applied [] operator to non-array (" << name << " " "is of type " << array->type->asString() << ")."); } else { MESSAGE_LE (lcontext, ERR_NON_ARR_IND, array->lineNumber, "Applied [] operator to non-array of type " << array->type->asString() << "."); } type = lcontext.newIntType(); return; } IntTypePtr intType = lcontext.newIntType (); if (!intType->canPromoteFrom (index->type)) { string name = ""; if( NameNodePtr arrayName = array.cast<NameNode>() ) name = arrayName->name; MESSAGE_LE (lcontext, ERR_ARR_IND_TYPE, array->lineNumber, "Index into array " << name << " is not an iteger " "(index is of type " << index->type->asString() << ")."); type = lcontext.newIntType(); return; } type = arrayType->elementType(); }
TypePtr arrayType(TypePtr elementType, int size) { int h = pointerHash(elementType.ptr()) + size; h &= arrayTypes.size() - 1; vector<ArrayTypePtr>::iterator i, end; for (i = arrayTypes[h].begin(), end = arrayTypes[h].end(); i != end; ++i) { ArrayType *t = i->ptr(); if ((t->elementType == elementType) && (t->size == size)) return t; } ArrayTypePtr t = new ArrayType(elementType, size); arrayTypes[h].push_back(t); return t.ptr(); }
ExprNodePtr SizeNode::evaluate (LContext &lcontext) { obj = obj->evaluate(lcontext); ArrayTypePtr arrayType = obj->type.cast<ArrayType>(); if( !arrayType) { return lcontext.newIntLiteralNode (lineNumber, 1); } else if( arrayType->size() != 0 ) { return lcontext.newIntLiteralNode (lineNumber, arrayType->size()); } return this; }
ExprNodePtr ArrayIndexNode::evaluate (LContext &lcontext) { IntTypePtr intType = lcontext.newIntType (); array = array->evaluate (lcontext); index = index->evaluate (lcontext); if( IntLiteralNodePtr literal = index.cast<IntLiteralNode>()) { if(literal->value < 0) { string name = ""; if( NameNodePtr arrayName = array.cast<NameNode>() ) name = arrayName->name; MESSAGE_LE (lcontext, ERR_ARR_IND_TYPE, array->lineNumber, "Index into array " << name << " is negative " "(" << literal->value << ")."); } ArrayTypePtr arrayType = array->type.cast<ArrayType>(); if(!arrayType) return this; if( literal->value >= arrayType->size() && arrayType->size() != 0) { string name = ""; if( NameNodePtr arrayName = array.cast<NameNode>() ) name = arrayName->name; MESSAGE_LE (lcontext, ERR_ARR_IND_TYPE, array->lineNumber, "Index into array " << name << " is out of range " "(index = " << literal->value << ", " "array size = " << arrayType->size() << ")."); } } if (index->type && !intType->isSameTypeAs (index->type)) index = intType->castValue (lcontext, index); return this; }
FunctionCallPtr Interpreter::newFunctionCall (const std::string &functionName) { Lock lock (_data->mutex); // // Calling a CTL function with variable-size array arguments // from C++ is not supported. // const SymbolInfoPtr info = symtab().lookupSymbol (functionName); if (!info) THROW (ArgExc, "Cannot find CTL function " << functionName << "."); if (!info->isFunction()) THROW (TypeExc, "CTL object " << functionName << " is not a function " "(it is of type " << info->type()->asString() << ")."); const FunctionTypePtr fType = info->type(); const ParamVector ¶meters = fType->parameters(); for (int i = parameters.size() - 1; i >= 0; --i) { const Param ¶m = parameters[i]; ArrayTypePtr aType = param.type.cast<ArrayType>(); if(aType) { SizeVector sizes; aType->sizes (sizes); for (int j = 0; j < sizes.size(); j++) { if (sizes[j] == 0) THROW (ArgExc, "CTL function " << functionName << " " "has a variable-size array " "argument, " << param.name << ", and can " "only be called by another CTL function."); } } } return newFunctionCallInternal (info, functionName); }
/*! * dictionary-type → [type:type] * array-type → [type] */ TypeNodePtr Parser::parseCollectionType() { Token token; expect(L"[", token); TypeNodePtr type = this->parseType(); if(match(L":")) { //it's a dictionary type TypeNodePtr valueType = parseType(); expect(L"]"); DictionaryTypePtr ret = nodeFactory->createDictionaryType(token.state); ret->setKeyType(type); ret->setValueType(valueType); return ret; } else { //it's an array type expect(L"]"); ArrayTypePtr ret = nodeFactory->createArrayType(token.state); ret->setInnerType(type); return ret; } }
void NodeSerializer::visitArrayType(const ArrayTypePtr& node) { append(L"["); node->getInnerType()->accept(this); append(L"]"); }
TypeNodePtr Parser::parseType() { Token token; TypeNodePtr ret = NULL; expect_next(token); restore(token); if(token == TokenType::OpenParen) { ret = parseTupleType(); } else if(token.type == TokenType::Identifier && token.identifier.keyword == Keyword::_) { ret = parseTypeIdentifier(); } else if(token.type == TokenType::Identifier && token.identifier.keyword == Keyword::SelfType) { ret = parseTypeIdentifier(); } else if(token.getKeyword() == Keyword::Protocol) { ret = parseProtocolComposition(); } else if(token == TokenType::OpenBracket) { ret = parseCollectionType(); } else { unexpected(token); } do { if(!next(token)) break; //type chaining if(token == L"->") { //function-type → type->type TupleTypePtr argType = std::dynamic_pointer_cast<TupleType>(ret); if(!argType) { //wrap ret as a tuple type argType = nodeFactory->createTupleType(*ret->getSourceInfo()); argType->add(false, L"", ret); } TypeNodePtr retType = parseType(); FunctionTypePtr func = nodeFactory->createFunctionType(token.state); func->setArgumentsType(argType); func->setReturnType(retType); ret = func; continue; } if(token == TokenType::OpenBracket) { expect(L"]"); ArrayTypePtr array = nodeFactory->createArrayType(token.state); array->setInnerType(ret); ret = array; continue; } if(token == L"?") { //optional-type → type? OptionalTypePtr type = nodeFactory->createOptionalType(token.state); type->setInnerType(ret); ret = type; continue; } if(token == L"!") { //implicitly-unwrapped-optional-type → type! ImplicitlyUnwrappedOptionalPtr type = nodeFactory->createImplicitlyUnwrappedOptional(token.state); type->setInnerType(ret); ret = type; continue; } // metatype-type → type.Type type.Protocol //TODO meta type is not supported restore(token); break; }while(true); return ret; }