void SemanticAnalyzer::checkTupleDefinition(const TuplePtr& tuple, const ExpressionPtr& initializer) { //this is a tuple definition, the corresponding declared type must be a tuple type TypeNodePtr declaredType = tuple->getDeclaredType(); TypePtr type = lookupType(declaredType); if(!type) { error(tuple, Errors::E_USE_OF_UNDECLARED_TYPE_1, toString(declaredType)); return; } if(!(type->getCategory() == Type::Tuple)) { //tuple definition must have a tuple type definition error(tuple, Errors::E_TUPLE_PATTERN_MUST_MATCH_TUPLE_TYPE_1, toString(declaredType)); return; } if(tuple->numElements() != type->numElementTypes()) { //tuple pattern has the wrong length for tuple type '%' error(tuple, Errors::E_TUPLE_PATTERN_MUST_MATCH_TUPLE_TYPE_1, toString(declaredType)); return; } //check if initializer has the same type with the declared type if(initializer) { TypePtr valueType = evaluateType(initializer); if(valueType && !Type::equals(valueType, type)) { //tuple pattern has the wrong length for tuple type '%' //tuple types '%0' and '%1' have a different number of elements (%2 vs. %3) wstring expectedType = type->toString(); wstring got = toString(valueType->numElementTypes()); wstring expected = toString(type->numElementTypes()); error(initializer, Errors::E_TUPLE_TYPES_HAVE_A_DIFFERENT_NUMBER_OF_ELEMENT_4, toString(declaredType), expectedType, got, expected); return; } } for(const PatternPtr& p : *tuple) { NodeType nodeType = p->getNodeType(); if(nodeType != NodeType::Identifier) { } } }
TEST(TestDeclaration, testLet_Tuple) { PARSE_STATEMENT(L"let (a, b) : Int = (1, 2)"); ValueBindingsPtr c; TuplePtr tuple; TypeIdentifierPtr type; ParenthesizedExpressionPtr p; ASSERT_NOT_NULL(c = std::dynamic_pointer_cast<ValueBindings>(root)); ASSERT_TRUE(c->isReadOnly()); ASSERT_NOT_NULL(tuple = std::dynamic_pointer_cast<Tuple>(c->get(0)->getName())); ASSERT_EQ(2, tuple->numElements()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(c->get(0)->getDeclaredType())); ASSERT_NOT_NULL(p = std::dynamic_pointer_cast<ParenthesizedExpression>(c->get(0)->getInitializer())); ASSERT_EQ(2, p->numExpressions()); }
/* tuple-pattern → (tuple-pattern-element-list opt) tuple-pattern-element-list → tuple-pattern-element | tuple-pattern-element,tuple-pattern-element-list tuple-pattern-element → pattern */ PatternPtr Parser::parseTuple() { Token token; expect(L"(", token); TuplePtr ret = nodeFactory->createTuple(token.state); if(!predicate(L")")) { do { PatternPtr pattern = parsePattern(); ret->add(pattern); }while(match(L",")); } expect(L")"); return ret; }
/* GRAMMAR OF A PATTERN pattern → wildcard-pattern type-annotation opt pattern → identifier-pattern type-annotation opt pattern → value-binding-pattern pattern → tuple-pattern type-annotation opt pattern → enum-case-pattern pattern → type-casting-pattern pattern → expression-pattern */ PatternPtr Parser::parsePattern() { Token token; expect_next(token); if(token.type == TokenType::Identifier) { switch(token.identifier.keyword) { // pattern → wildcard-pattern type-annotationopt // pattern → identifier-pattern type-annotationopt case Keyword::_: { IdentifierPtr id = nodeFactory->createIdentifier(token.state); id->setIdentifier(token.token); if((flags & UNDER_CASE) == 0)//type annotation is not parsed when it's inside a let/var { if(match(L":")) { TypedPatternPtr ret = nodeFactory->createTypedPattern(*id->getSourceInfo()); TypeNodePtr type = parseTypeAnnotation(); ret->setDeclaredType(type); ret->setPattern(id); return ret; } } return id; } // pattern → value-binding-pattern case Keyword::Var: case Keyword::Let: { ValueBindingPatternPtr ret = nodeFactory->createValueBindingPattern(token.state); PatternPtr binding = parsePattern(); if(TypedPatternPtr p = std::dynamic_pointer_cast<TypedPattern>(binding)) { ret->setBinding(p->getPattern()); ret->setDeclaredType(p->getDeclaredType()); } else { ret->setBinding(binding); } ret->setReadOnly(token.identifier.keyword == Keyword::Let); return ret; } default: break; } } restore(token); if(token.type == TokenType::OpenParen) { //pattern → tuple-pattern type-annotation opt TuplePtr ret = std::static_pointer_cast<Tuple>(parseTuple()); if(flags & (UNDER_LET | UNDER_VAR)) { //type-annotation only exists under let/var statement if(match(L":")) { TypeNodePtr type = parseTypeAnnotation(); TypedPatternPtr pattern = nodeFactory->createTypedPattern(*ret->getSourceInfo()); pattern->setDeclaredType(type); pattern->setPattern(ret); return pattern; } } return ret; } if(this->flags & UNDER_SWITCH_CASE) { //the following patterns are only exists in switch/case statement // pattern → enum-case-pattern if(token.type == TokenType::Attribute || token == L".") { return parseEnumPattern(); } // pattern → type-casting-pattern if(token.getKeyword() == Keyword::Is) { return parseTypeCastingPattern(); } } // pattern → expression-pattern PatternPtr ret = parseExpression(); if(this->flags & UNDER_SWITCH_CASE) { if(predicate(L"as")) { restore(token); ret = NULL; return parseTypeCastingPattern(); } } return ret; }
void SemanticAnalyzer::validateTupleTypeDeclaration(const PatternPtr& name, const TypePtr& declType, const TypePtr& initType) { switch(name->getNodeType()) { case NodeType::Identifier: { if(initType && declType && !initType->canAssignTo(declType)) { error(name, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, initType->toString(), declType->toString()); } break; } case NodeType::TypedPattern: { TypedPatternPtr pat = static_pointer_cast<TypedPattern>(name); assert(pat->getDeclaredType()); TypePtr nameType = lookupType(pat->getDeclaredType()); assert(nameType != nullptr); if(declType && !Type::equals(nameType, declType)) { error(name, Errors::E_TYPE_ANNOTATION_DOES_NOT_MATCH_CONTEXTUAL_TYPE_A_1, declType->toString()); abort(); return; } break; } case NodeType::Tuple: { TuplePtr tuple = static_pointer_cast<Tuple>(name); if(declType) { if((declType->getCategory() != Type::Tuple) || (tuple->numElements() != declType->numElementTypes())) { error(name, Errors::E_TYPE_ANNOTATION_DOES_NOT_MATCH_CONTEXTUAL_TYPE_A_1, declType->toString()); abort(); return; } } int elements = tuple->numElements(); for(int i = 0; i < elements; i++) { PatternPtr element = tuple->getElement(i); TypePtr elementDecl = declType ? declType->getElementType(i) : nullptr; TypePtr elementInit = initType ? initType->getElementType(i) : nullptr; validateTupleTypeDeclaration(element, elementDecl, elementInit); } break; } case NodeType::ValueBindingPattern: break; case NodeType::EnumCasePattern: { break; } case NodeType::TypeCase: case NodeType::TypeCheck: default: error(name, Errors::E_EXPECT_TUPLE_OR_IDENTIFIER); break; } }