/* “GRAMMAR OF A PROTOCOL DECLARATION protocol-declaration → attributes opt protocol protocol-name type-inheritance-clause opt protocol-body protocol-name → identifier protocol-body → {protocol-member-declarations opt} protocol-member-declaration → protocol-property-declaration protocol-member-declaration → protocol-method-declaration protocol-member-declaration → protocol-initializer-declaration protocol-member-declaration → protocol-subscript-declaration protocol-member-declaration → protocol-associated-type-declaration protocol-member-declarations → protocol-member-declaration protocol-member-declarations opt ” “GRAMMAR OF A PROTOCOL PROPERTY DECLARATION protocol-property-declaration → variable-declaration-head variable-name type-annotation getter-setter-keyword-block ” “GRAMMAR OF A PROTOCOL METHOD DECLARATION protocol-method-declaration → function-head function-name generic-parameter-clause opt function-signature ” “GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION protocol-initializer-declaration → initializer-head generic-parameter-clause opt parameter-clause ” “GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION protocol-subscript-declaration → subscript-head subscript-result getter-setter-keyword-block” “GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION protocol-associated-type-declaration → typealias-head type-inheritance-clause opt typealias-assignment opt ” */ DeclarationPtr Parser::parseProtocol(const std::vector<AttributePtr>& attrs) { Token token; expect(Keyword::Protocol); ProtocolDefPtr ret = nodeFactory->createProtocol(token.state); ret->setAttributes(attrs); expect_identifier(token); TypeIdentifierPtr typeId = nodeFactory->createTypeIdentifier(token.state); typeId->setName(token.token); ret->setIdentifier(typeId); if(match(L":")) { do { TypeIdentifierPtr protocol = parseTypeIdentifier(); ret->addParent(protocol); }while(match(L",")); } expect(L"{"); Flags f(this); f += UNDER_PROTOCOL; while(!predicate(L"}")) { DeclarationPtr decl = parseDeclaration(); ret->addDeclaration(decl); } expect(L"}"); return ret; }
TEST(TestProtocol, testPropertyRequirements) { PARSE_STATEMENT(L"protocol SomeProtocol {\n" L"var mustBeSettable: Int { get set }\n" L"var doesNotNeedToBeSettable: Int { get }\n" L"}"); ProtocolDefPtr p; ASSERT_NOT_NULL(p = std::dynamic_pointer_cast<ProtocolDef>(root)); ASSERT_EQ(2, p->numDeclarations()); ComputedPropertyPtr var; ASSERT_NOT_NULL(var = std::dynamic_pointer_cast<ComputedProperty>(p->getDeclaration(0))); ASSERT_EQ(L"mustBeSettable", var->getName()); ASSERT_EQ(0, var->getModifiers()); ASSERT_NOT_NULL(var->getGetter()); ASSERT_NOT_NULL(var->getSetter()); ASSERT_NOT_NULL(var = std::dynamic_pointer_cast<ComputedProperty>(p->getDeclaration(1))); ASSERT_EQ(L"doesNotNeedToBeSettable", var->getName()); ASSERT_NOT_NULL(var->getGetter()); ASSERT_NULL(var->getSetter()); }
TEST(TestProtocol, testOptional) { PARSE_STATEMENT(L"@objc protocol CounterDataSource {\n" L"optional func incrementForCount(count: Int) -> Int\n" L"optional var fixedIncrement: Int { get }\n" L"}"); ProtocolDefPtr p; ASSERT_NOT_NULL(p = std::dynamic_pointer_cast<ProtocolDef>(root)); ASSERT_EQ(2, p->numDeclarations()); ASSERT_NOT_NULL(p->getAttribute(L"objc")); FunctionDefPtr f; ASSERT_NOT_NULL(f = std::dynamic_pointer_cast<FunctionDef>(p->getDeclaration(0))); ASSERT_EQ(L"incrementForCount", f->getName()); ASSERT_TRUE(f->getModifiers() & DeclarationModifiers::Optional); ComputedPropertyPtr var; ASSERT_NOT_NULL(var = std::dynamic_pointer_cast<ComputedProperty>(p->getDeclaration(1))); ASSERT_TRUE(f->getModifiers() & DeclarationModifiers::Optional); ASSERT_EQ(L"fixedIncrement", var->getName()); ASSERT_NOT_NULL(var->getGetter()); ASSERT_NULL(var->getSetter()); }
TEST(TestProtocol, testEmptyProtocol) { PARSE_STATEMENT(L"protocol SomeProtocol {\n" L"// protocol definition goes here\n" L"}"); ProtocolDefPtr p; TypeIdentifierPtr id; ASSERT_NOT_NULL(p = std::dynamic_pointer_cast<ProtocolDef>(root)); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<TypeIdentifier>(p->getIdentifier())); ASSERT_EQ(L"SomeProtocol", id->getName()); }
TEST(TestDeclaration, TypeAlias_ProtocolNoType) { PARSE_STATEMENT(L"protocol MyProtocol { typealias NewType }"); ASSERT_EQ(0, compilerResults.numResults()); ProtocolDefPtr protocol; TypeAliasPtr typealias; TypeIdentifierPtr Int; ASSERT_NOT_NULL(protocol = std::dynamic_pointer_cast<ProtocolDef>(root)); ASSERT_EQ(1, protocol->numDeclarations()); ASSERT_NOT_NULL(typealias = std::dynamic_pointer_cast<TypeAlias>(protocol->getDeclaration(0))); ASSERT_EQ(L"NewType", typealias->getName()); ASSERT_NULL(typealias->getType()); }
TEST(TestProtocol, testMutatingMethod) { PARSE_STATEMENT(L"protocol Togglable {\n" L"mutating func toggle()\n" L"}"); ProtocolDefPtr p; ASSERT_NOT_NULL(p = std::dynamic_pointer_cast<ProtocolDef>(root)); ASSERT_EQ(1, p->numDeclarations()); FunctionDefPtr f; ASSERT_NOT_NULL(f = std::dynamic_pointer_cast<FunctionDef>(p->getDeclaration(0))); ASSERT_EQ((int)DeclarationModifiers::Mutating, f->getModifiers()); ASSERT_EQ(L"toggle", f->getName()); //ASSERT_NULL(f->getBody()); }
TEST(TestProtocol, testMethodRequirements2) { PARSE_STATEMENT(L"protocol RandomNumberGenerator {\n" L"func random() -> Double\n" L"}"); ProtocolDefPtr p; ASSERT_NOT_NULL(p = std::dynamic_pointer_cast<ProtocolDef>(root)); ASSERT_EQ(1, p->numDeclarations()); FunctionDefPtr f; ASSERT_NOT_NULL(f = std::dynamic_pointer_cast<FunctionDef>(p->getDeclaration(0))); ASSERT_EQ(0, f->getModifiers()); ASSERT_EQ(L"random", f->getName()); //ASSERT_NULL(f->getBody()); }
TEST(TestProtocol, testMethodRequirements) { PARSE_STATEMENT(L"protocol SomeProtocol {\n" L"class func someTypeMethod()\n" L"}"); ProtocolDefPtr p; ASSERT_NOT_NULL(p = std::dynamic_pointer_cast<ProtocolDef>(root)); ASSERT_EQ(1, p->numDeclarations()); FunctionDefPtr f; ASSERT_NOT_NULL(f = std::dynamic_pointer_cast<FunctionDef>(p->getDeclaration(0))); ASSERT_EQ((int)DeclarationModifiers::Class, f->getModifiers()); ASSERT_EQ(L"someTypeMethod", f->getName()); //ASSERT_NULL(f->getBody()); }
TEST(TestProtocol, testPropertyRequirements2) { PARSE_STATEMENT(L"protocol AnotherProtocol {\n" L"class var someTypeProperty: Int { get set }\n" L"}"); ProtocolDefPtr p; ASSERT_NOT_NULL(p = std::dynamic_pointer_cast<ProtocolDef>(root)); ASSERT_EQ(1, p->numDeclarations()); ComputedPropertyPtr var; ASSERT_NOT_NULL(var = std::dynamic_pointer_cast<ComputedProperty>(p->getDeclaration(0))); ASSERT_EQ((int)DeclarationModifiers::Class, var->getModifiers()); ASSERT_EQ(L"someTypeProperty", var->getName()); ASSERT_NOT_NULL(var->getGetter()); ASSERT_NOT_NULL(var->getSetter()); }
TEST(TestProtocol, testPropertyRequirements3) { PARSE_STATEMENT(L"protocol FullyNamed {\n" L"var fullName: String { get }\n" L"}"); ProtocolDefPtr p; ASSERT_NOT_NULL(p = std::dynamic_pointer_cast<ProtocolDef>(root)); ASSERT_EQ(1, p->numDeclarations()); ComputedPropertyPtr var; ASSERT_NOT_NULL(var = std::dynamic_pointer_cast<ComputedProperty>(p->getDeclaration(0))); ASSERT_EQ(0, var->getModifiers()); ASSERT_EQ(L"fullName", var->getName()); ASSERT_NOT_NULL(var->getGetter()); ASSERT_NULL(var->getSetter()); }
void FunctionAnalyzer::visitProtocol(const ProtocolDefPtr& node) { SymbolScope* scope = symbolRegistry->getCurrentScope(); SymbolPtr sym = scope->getForwardDeclaration(node->getIdentifier()->getName()); assert(sym && sym->getKind() == SymbolKindType); TypePtr type = static_pointer_cast<Type>(sym); ScopeGuard guard(symbolRegistry, type->getScope()); SCOPED_SET(ctx->currentType, type); semanticAnalyzer->visitImplementation(node, this, true); }
TEST(TestProtocol, testInheritance) { PARSE_STATEMENT(L"protocol PrettyTextRepresentable: TextRepresentable {\n" L"func asPrettyText() -> String\n" L"}"); ProtocolDefPtr p; ASSERT_NOT_NULL(p = std::dynamic_pointer_cast<ProtocolDef>(root)); ASSERT_EQ(1, p->numDeclarations()); ASSERT_EQ(1, p->numParents()); ASSERT_EQ(L"TextRepresentable", p->getParent(0)->getName()); FunctionDefPtr f; ASSERT_NOT_NULL(f = std::dynamic_pointer_cast<FunctionDef>(p->getDeclaration(0))); ASSERT_EQ(0, f->getModifiers()); ASSERT_EQ(L"asPrettyText", f->getName()); //ASSERT_NULL(f->getBody()); }