void FunctionAnalyzer::visitComputedProperty(const ComputedPropertyPtr& node) { CodeBlockPtr didSet = node->getDidSet(); CodeBlockPtr willSet = node->getWillSet(); CodeBlockPtr getter = node->getGetter(); CodeBlockPtr setter = node->getSetter(); TypePtr type = declarationAnalyzer->resolveType(node->getDeclaredType(), true); assert(type != nullptr); shared_ptr<ComposedComputedProperty> property = static_pointer_cast<ComposedComputedProperty>(node); //prepare type for getter/setter /* std::vector<Parameter> params; TypePtr getterType = Type::newFunction(params, type, nullptr); params.push_back(Parameter(type)); TypePtr setterType = Type::newFunction(params, symbolRegistry->getGlobalScope()->Void(), false); */ SCOPED_SET(ctx->flags, (ctx->flags & (~SemanticContext::FLAG_PROCESS_DECLARATION)) | SemanticContext::FLAG_PROCESS_IMPLEMENTATION); if(!property->hasModifier(DeclarationModifiers::_Generated)) { if(property->functions.getter) property->functions.getter->accept(semanticAnalyzer); if(property->functions.setter) property->functions.setter->accept(semanticAnalyzer); if(property->functions.willSet) property->functions.willSet->accept(semanticAnalyzer); if(property->functions.didSet) property->functions.didSet->accept(semanticAnalyzer); } }
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()); }
void NodeVisitor::visitComputedProperty(const ComputedPropertyPtr& node) { ACCEPT(node->getInitializer()); ACCEPT(node->getGetter()); ACCEPT(node->getSetter()); ACCEPT(node->getWillSet()); ACCEPT(node->getDidSet()); }
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, 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()); }
/* didSet-clause → attributes opt didSet setter-name opt code-block */ void Parser::parseDidSetClause(const ComputedPropertyPtr& property, bool opt) { Token token; if(!peek(token)) return; if(opt && token.type == TokenType::CloseBrace) return; Attributes attrs; parseAttributes(attrs); expect(Keyword::DidSet); if(match(L"(")) { expect_identifier(token); property->setDidSetSetter(token.token); expect(L")"); } CodeBlockPtr cb = parseCodeBlock(); property->setDidSet(cb); }
/* GRAMMAR OF A VARIABLE DECLARATION variable-declaration → variable-declaration-head pattern-initializer-list variable-declaration → variable-declaration-head variable-name type-annotation code-block variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-block variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-keyword-block variable-declaration → variable-declaration-head variable-name type-annotation initializer opt willSet-didSet-block variable-declaration-head → attributes opt declaration-specifiers opt var variable-name → identifier */ DeclarationPtr Parser::parseVar(const std::vector<AttributePtr>& attrs, int specifiers) { Token token; expect(Keyword::Var, token); Flags flags(this, UNDER_VAR); //try read it as pattern-initializer-list ValueBindingsPtr ret = nodeFactory->createValueBindings(token.state); ret->setReadOnly(false); ret->setAttributes(attrs); ret->setSpecifiers(specifiers); ValueBindingPtr var = parseVariableDeclaration(); var->setSpecifiers(specifiers); ret->add(var); if(predicate(L",")) { while(match(L",")) { var = parseVariableDeclaration(); var->setSpecifiers(specifiers); ret->add(var); } return ret; } if(!match(L"{")) return ret; peek(token); IdentifierPtr name = std::dynamic_pointer_cast<Identifier>(var->getName()); tassert(token, name != nullptr, Errors::E_GETTER_SETTER_CAN_ONLY_BE_DEFINED_FOR_A_SINGLE_VARIABLE, L""); ComputedPropertyPtr prop = nodeFactory->createComputedProperty(*var->getSourceInfo()); prop->setAttributes(attrs); prop->setSpecifiers(specifiers); prop->setTypeAttributes(var->getTypeAttributes()); prop->setName(name->getIdentifier()); prop->setDeclaredType(var->getDeclaredType()); prop->setInitializer(var->getInitializer()); var = nullptr; ret = nullptr; if(token.type != TokenType::CloseBrace) { Flags flags(this, SUPPRESS_TRAILING_CLOSURE); switch(token.getKeyword()) { case Keyword::Get: case Keyword::Set: if(this->flags & UNDER_PROTOCOL) { // variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-keyword-block //no code block for getter/setter for protocol std::pair<CodeBlockPtr, CodeBlockPtr> r = parseGetterSetterKeywordBlock(); prop->setGetter(r.first); prop->setSetter(r.second); } else { // variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-block std::pair<CodeBlockPtr, std::pair<std::wstring, CodeBlockPtr> > r = parseGetterSetterBlock(); prop->setGetter(r.first); prop->setSetterName(r.second.first); prop->setSetter(r.second.second); } break; case Keyword::WillSet: case Keyword::DidSet: // variable-declaration → variable-declaration-head variable-name type-annotation initializer opt willSet-didSet-block parseWillSetDidSetBlock(prop); break; default: // variable-declaration → variable-declaration-head variable-name type-annotation code-block CodeBlockPtr getter = nodeFactory->createCodeBlock(token.state); prop->setGetter(getter); do { StatementPtr st = parseStatement(); getter->addStatement(st); }while(!predicate(L"}")); break; } } expect(L"}"); return prop; }