/* raw-value-style-enum → enum-name generic-parameter-clause opt : type-identifier{raw-value-style-enum-members opt} raw-value-style-enum-members → raw-value-style-enum-member raw-value-style-enum-members opt raw-value-style-enum-member → declaration | raw-value-style-enum-case-clause raw-value-style-enum-case-clause → attributes opt case raw-value-style-enum-case-list raw-value-style-enum-case-list → raw-value-style-enum-case | raw-value-style-enum-case,raw-value-style-enum-case-list raw-value-style-enum-case → enum-case-name raw-value-assignment opt raw-value-assignment → =literal */ DeclarationPtr Parser::parseRawValueEnum(const std::vector<AttributePtr>& attrs, const std::wstring& name, const TypeIdentifierPtr& baseType) { Token token; expect(L"{", token); EnumDefPtr ret = nodeFactory->createEnum(token.state); ret->setAttributes(attrs); TypeIdentifierPtr typeId = nodeFactory->createTypeIdentifier(token.state); typeId->setName(name); ret->setIdentifier(typeId); ret->addParent(baseType); while(!predicate(L"}")) { if(match(Keyword::Case)) { do { expect_identifier(token); ExpressionPtr val = NULL; if(match(L"=")) { val = parseLiteral(); } ret->addConstant(token.token, val); }while(match(L",")); } else { DeclarationPtr decl = parseDeclaration(); ret->addDeclaration(decl); } } expect(L"}"); return ret; }
/* “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; }
/* union-style-enum → enum-name generic-parameter-clause opt{union-style-enum-members opt} union-style-enum-members → union-style-enum-member union-style-enum-members opt union-style-enum-member → declaration | union-style-enum-case-clause union-style-enum-case-clause → attributes opt case union-style-enum-case-list union-style-enum-case-list → union-style-enum-case | union-style-enum-case,union-style-enum-case-list union-style-enum-case → enum-case-name tuple-type opt */ DeclarationPtr Parser::parseUnionEnum(const std::vector<AttributePtr>& attrs, const std::wstring& name) { Token token; expect(L"{", token); EnumDefPtr ret = nodeFactory->createEnum(token.state); ret->setAttributes(attrs); TypeIdentifierPtr typeId = nodeFactory->createTypeIdentifier(token.state); typeId->setName(name); ret->setIdentifier(typeId); while(!predicate(L"}")) { if(match(Keyword::Case)) { do { expect_identifier(token); TupleTypePtr associatedType = NULL; if(predicate(L"(")) { associatedType = parseTupleType(); } ret->addAssociatedType(token.token, associatedType); }while(match(L",")); } else { DeclarationPtr decl = parseDeclaration(); ret->addDeclaration(decl); } } expect(L"}"); return ret; }
/* GRAMMAR OF A TYPE IDENTIFIER type-identifier → type-name generic-argument-clause opt | type-name generic-argument-clause opt . type-identifier type-name → identifier */ TypeIdentifierPtr Parser::parseTypeIdentifier() { Token token; expect_next(token); if(token.type != TokenType::Identifier || (token.identifier.keyword != Keyword::_ && token.identifier.keyword != Keyword::SelfType)) { ResultItems items = {token.token}; error(token, Errors::E_EXPECT_IDENTIFIER_1, items); return nullptr; } TypeIdentifierPtr ret = nodeFactory->createTypeIdentifier(token.state); ret->setName(token.token); ENTER_CONTEXT(TokenizerContextType); if(match(L"<")) { do { TypeNodePtr arg = parseType(); ret->addGenericArgument(arg); }while(match(L",")); expect(L">"); } if(match(L".")) { //read next TypeIdentifierPtr next = parseTypeIdentifier(); ret->setNestedType(next); } return ret; }
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); }
TypePtr DeclarationAnalyzer::getOrDefineType(const std::shared_ptr<TypeDeclaration>& node) { SymbolScope* currentScope = symbolRegistry->getCurrentScope(); TypeIdentifierPtr id = node->getIdentifier(); TypePtr type = currentScope->getForwardDeclaration(id->getName()); if(type) return type; type = defineType(node); return type; }
TEST(TestDeclaration, TypeAlias) { PARSE_STATEMENT(L"typealias NewType = Int"); ASSERT_EQ(0, compilerResults.numResults()); TypeAliasPtr typealias; TypeIdentifierPtr Int; ASSERT_NOT_NULL(typealias = std::dynamic_pointer_cast<TypeAlias>(root)); ASSERT_EQ(L"NewType", typealias->getName()); ASSERT_NOT_NULL(Int = std::dynamic_pointer_cast<TypeIdentifier>(typealias->getType())); ASSERT_EQ(L"Int", Int->getName()); }
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_Protocol) { PARSE_STATEMENT(L"protocol MyProtocol { typealias NewType = Int }"); 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_NOT_NULL(Int = std::dynamic_pointer_cast<TypeIdentifier>(typealias->getType())); ASSERT_EQ(L"Int", Int->getName()); }
TEST(TestFunc, testFunc) { PARSE_STATEMENT(L"func stepForward(input: Int) -> Int {" L"return input + 1" L"}"); FunctionDefPtr func; ParametersNodePtr params; ParameterNodePtr param; TypeIdentifierPtr type; CodeBlockPtr cb; ReturnStatementPtr ret; BinaryOperatorPtr add; IdentifierPtr id; IntegerLiteralPtr i; ASSERT_NOT_NULL(func = std::dynamic_pointer_cast<FunctionDef>(root)); ASSERT_EQ(L"stepForward", func->getName()); ASSERT_EQ(1, func->numParameters()); ASSERT_NOT_NULL(params = func->getParameters(0)); ASSERT_EQ(1, params->numParameters()); ASSERT_NOT_NULL(param = params->getParameter(0)); ASSERT_EQ(ParameterNode::None, param->getAccessibility()); ASSERT_FALSE(param->isShorthandExternalName()); ASSERT_FALSE(param->isInout()); ASSERT_NULL(param->getDefaultValue()); ASSERT_EQ(L"", param->getExternalName()); ASSERT_EQ(L"input", param->getLocalName()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(param->getDeclaredType())); ASSERT_EQ(L"Int", type->getName()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(func->getReturnType())); ASSERT_EQ(L"Int", type->getName()); ASSERT_NOT_NULL(cb = func->getBody()); ASSERT_EQ(1, cb->numStatements()); ASSERT_NOT_NULL(ret = std::dynamic_pointer_cast<ReturnStatement>(cb->getStatement(0))); ASSERT_NOT_NULL(add = std::dynamic_pointer_cast<BinaryOperator>(ret->getExpression())); ASSERT_EQ(L"+", add->getOperator()); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(add->getLHS())); ASSERT_NOT_NULL(i = std::dynamic_pointer_cast<IntegerLiteral>(add->getRHS())); ASSERT_EQ(L"input", id->getIdentifier()); ASSERT_EQ(L"1", i->valueAsString); }
TEST(TestFunc, testFunc_ReturnFunc) { PARSE_STATEMENT(L"func chooseStepFunction(backwards: Bool) -> (Int) -> Int {" L"return backwards ? stepBackward : stepForward" L"}"); FunctionDefPtr func; ParametersNodePtr params; ParameterNodePtr param; TypeIdentifierPtr type; FunctionTypePtr rettype; TupleTypePtr tupleType; ASSERT_NOT_NULL(func = std::dynamic_pointer_cast<FunctionDef>(root)); ASSERT_EQ(L"chooseStepFunction", func->getName()); ASSERT_EQ(1, func->numParameters()); ASSERT_NOT_NULL(params = func->getParameters(0)); ASSERT_EQ(1, params->numParameters()); ASSERT_FALSE(params->isVariadicParameters()); ASSERT_NOT_NULL(param = params->getParameter(0)); ASSERT_EQ(ParameterNode::None, param->getAccessibility()); ASSERT_FALSE(param->isShorthandExternalName()); ASSERT_FALSE(param->isInout()); ASSERT_NULL(param->getDefaultValue()); ASSERT_EQ(L"", param->getExternalName()); ASSERT_EQ(L"backwards", param->getLocalName()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(param->getDeclaredType())); ASSERT_EQ(L"Bool", type->getName()); ASSERT_NOT_NULL(rettype = std::dynamic_pointer_cast<FunctionType>(func->getReturnType())); ASSERT_NOT_NULL(tupleType = std::dynamic_pointer_cast<TupleType>(rettype->getArgumentsType())); ASSERT_FALSE(tupleType->getVariadicParameters()); ASSERT_EQ(1, tupleType->numElements()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(tupleType->getElementType(0))); ASSERT_EQ(L"Int", type->getName()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(rettype->getReturnType())); ASSERT_EQ(L"Int", type->getName()); }
TEST(TestDeclaration, testVar_Typed) { PARSE_STATEMENT(L"var welcomeMessage: String"); ValueBindingsPtr vars; ValueBindingPtr var; IdentifierPtr id; TypeIdentifierPtr t; ASSERT_NOT_NULL(vars = std::dynamic_pointer_cast<ValueBindings>(root)); ASSERT_TRUE(!vars->isReadOnly()); ASSERT_EQ(1, vars->numBindings()); ASSERT_NOT_NULL(var = std::dynamic_pointer_cast<ValueBinding>(vars->get(0))); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(var->getName())); ASSERT_EQ(L"welcomeMessage", id->getIdentifier()); ASSERT_NOT_NULL(t = std::dynamic_pointer_cast<TypeIdentifier>(var->getDeclaredType())); ASSERT_EQ(L"String", t->getName()); }
TEST(TestFunc, testFunc_MultipleParameters) { PARSE_STATEMENT(L"func halfOpenRangeLength(start: Int, end: Int) -> Int {" L"return end - start" L"}"); FunctionDefPtr func; ParametersNodePtr params; ParameterNodePtr param; TypeIdentifierPtr type; ASSERT_NOT_NULL(func = std::dynamic_pointer_cast<FunctionDef>(root)); ASSERT_EQ(L"halfOpenRangeLength", func->getName()); ASSERT_EQ(1, func->numParameters()); ASSERT_NOT_NULL(params = func->getParameters(0)); ASSERT_EQ(2, params->numParameters()); ASSERT_FALSE(params->isVariadicParameters()); ASSERT_NOT_NULL(param = params->getParameter(0)); ASSERT_EQ(ParameterNode::None, param->getAccessibility()); ASSERT_FALSE(param->isShorthandExternalName()); ASSERT_FALSE(param->isInout()); ASSERT_NULL(param->getDefaultValue()); ASSERT_EQ(L"", param->getExternalName()); ASSERT_EQ(L"start", param->getLocalName()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(param->getDeclaredType())); ASSERT_EQ(L"Int", type->getName()); ASSERT_NOT_NULL(param = params->getParameter(1)); ASSERT_EQ(ParameterNode::None, param->getAccessibility()); ASSERT_FALSE(param->isShorthandExternalName()); ASSERT_FALSE(param->isInout()); ASSERT_NULL(param->getDefaultValue()); ASSERT_EQ(L"", param->getExternalName()); ASSERT_EQ(L"end", param->getLocalName()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(param->getDeclaredType())); ASSERT_EQ(L"Int", type->getName()); }
/* “GRAMMAR OF A STRUCTURE DECLARATION struct-declaration → attributes opt struct struct-name generic-parameter-clause opt type-inheritance-clause opt struct-body struct-name → identifier struct-body → {declarations opt}” */ DeclarationPtr Parser::parseStruct(const std::vector<AttributePtr>& attrs) { Token token; expect(Keyword::Struct); StructDefPtr ret = nodeFactory->createStruct(token.state); ret->setAttributes(attrs); expect_identifier(token); TypeIdentifierPtr typeId = nodeFactory->createTypeIdentifier(token.state); typeId->setName(token.token); ret->setIdentifier(typeId); if(predicate(L"<")) { GenericParametersDefPtr params = parseGenericParametersDef(); ret->setGenericParametersDef(params); } if(match(L":")) { do { TypeIdentifierPtr protocol = parseTypeIdentifier(); ret->addParent(protocol); }while(match(L",")); } Flags f(this); flags += UNDER_STRUCT; expect(L"{"); while(!predicate(L"}")) { DeclarationPtr decl = parseDeclaration(); ret->addDeclaration(decl); } expect(L"}"); return ret; }
TEST(TestDeclaration, testLet_Multiple) { PARSE_STATEMENT(L"let a=[k1 : 1, k2 : 2], b : Int = 2"); ValueBindingsPtr c; ValueBindingPtr b; IdentifierPtr id; TypeIdentifierPtr Int; DictionaryLiteralPtr dict; ASSERT_NOT_NULL(c = std::dynamic_pointer_cast<ValueBindings>(root)); ASSERT_TRUE(c->isReadOnly()); ASSERT_EQ(2, c->numBindings()); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(c->get(0)->getName())); ASSERT_EQ(L"a", id->getIdentifier()); ASSERT_NOT_NULL(dict = std::dynamic_pointer_cast<DictionaryLiteral>(c->get(0)->getInitializer())); ASSERT_EQ(2, dict->numElements()); ASSERT_NOT_NULL(b = c->get(1)); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(b->getName())); ASSERT_EQ(L"b", id->getIdentifier()); ASSERT_NOT_NULL(Int = std::dynamic_pointer_cast<TypeIdentifier>(b->getDeclaredType())); ASSERT_EQ(L"Int", Int->getName()); }
TypePtr DeclarationAnalyzer::defineType(const std::shared_ptr<TypeDeclaration>& node) { TypeIdentifierPtr id = node->getIdentifier(); //Analyze the type's category Type::Category category; switch(node->getNodeType()) { case NodeType::Enum: category = Type::Enum; break; case NodeType::Class: category = Type::Class; break; case NodeType::Struct: category = Type::Struct; break; case NodeType::Protocol: category = Type::Protocol; break; default: assert(0 && "Impossible to execute here."); } //it's inside the type's scope, so need to access parent scope; //prepare for generic types GenericParametersDefPtr genericParams = node->getGenericParametersDef(); //check if it's defined as a nested type if(ctx->currentType) { if(genericParams) { error(node, Errors::E_GENERIC_TYPE_A_NESTED_IN_TYPE_B_IS_NOT_ALLOWED_2, id->getName(), ctx->currentType->getName()); return nullptr; } if(ctx->currentType->isGenericType()) { error(node, Errors::E_TYPE_A_NESTED_IN_GENERIC_TYPE_B_IS_NOT_ALLOWED_2, id->getName(), ctx->currentType->getName()); return nullptr; } } //register this type SymbolScope* currentScope = symbolRegistry->getCurrentScope(); TypeBuilderPtr type = static_pointer_cast<TypeBuilder>(currentScope->getForwardDeclaration(id->getName())); S_ASSERT(type == nullptr); type = static_pointer_cast<TypeBuilder>(Type::newType(id->getName(), category)); currentScope->addForwardDeclaration(type); TypeDeclarationPtr tnode = dynamic_pointer_cast<TypeDeclaration>(node); type->setReference(tnode); if(tnode) tnode->setType(type); assert(type != nullptr); assert(type->getCategory() == category); //prepare for generic if(!type->getGenericDefinition() && node->getGenericParametersDef()) { GenericParametersDefPtr genericParams = node->getGenericParametersDef(); GenericDefinitionPtr generic = prepareGenericTypes(genericParams); generic->registerTo(type->getScope()); type->setGenericDefinition(generic); } if(node->hasModifier(DeclarationModifiers::Final)) type->setFlags(SymbolFlagFinal, true); static_pointer_cast<TypeBuilder>(type)->setModuleName(ctx->currentModule->getName()); ctx->allTypes.push_back(type); //check inheritance clause { TypePtr parent = nullptr; bool first = true; ScopeGuard scope(symbolRegistry, type->getScope()); SCOPED_SET(ctx->currentType, type); for(const TypeIdentifierPtr& parentType : node->getParents()) { parentType->accept(this); if(first) declareImmediately(parentType->getName()); TypePtr ptr = resolveType(parentType, true); Type::Category pcategory = ptr->getCategory(); if(pcategory == Type::Specialized) pcategory = ptr->getInnerType()->getCategory(); if(pcategory == Type::Class && category == Type::Class) { if(!first) { //only the first type can be class type error(parentType, Errors::E_SUPERCLASS_MUST_APPEAR_FIRST_IN_INHERITANCE_CLAUSE_1, toString(parentType)); return nullptr; } parent = ptr; if(parent->hasFlags(SymbolFlagFinal)) { error(parentType, Errors::E_INHERITANCE_FROM_A_FINAL_CLASS_A_1, parentType->getName()); return nullptr; } } else if(category == Type::Enum && pcategory != Type::Protocol) { if(parent)//already has a raw type { error(parentType, Errors::E_MULTIPLE_ENUM_RAW_TYPES_A_AND_B_2, parent->toString(), ptr->toString()); return nullptr; } if(!first) { error(parentType, Errors::E_RAW_TYPE_A_MUST_APPEAR_FIRST_IN_THE_ENUM_INHERITANCE_CLAUSE_1, ptr->toString()); return nullptr; } //check if the raw type is literal convertible if(!isLiteralTypeForEnum(symbolRegistry->getGlobalScope(), ptr)) { error(parentType, Errors::E_RAW_TYPE_A_IS_NOT_CONVERTIBLE_FROM_ANY_LITERAL_1, ptr->toString()); return nullptr; } if(!ptr->canAssignTo(symbolRegistry->getGlobalScope()->Equatable())) { error(parentType, Errors::E_RAWREPRESENTABLE_INIT_CANNOT_BE_SYNTHESIZED_BECAUSE_RAW_TYPE_A_IS_NOT_EQUATABLE_1, ptr->toString()); return nullptr; } parent = ptr; } else if(pcategory == Type::Protocol) { type->addProtocol(ptr); } else { if(category == Type::Class) error(parentType, Errors::E_INHERITANCE_FROM_NONE_PROTOCOL_NON_CLASS_TYPE_1, toString(parentType)); else error(parentType, Errors::E_INHERITANCE_FROM_NONE_PROTOCOL_TYPE_1, toString(parentType)); return nullptr; } first = false; } type->setParentType(parent); if(parent && parent->getAccessLevel() == AccessLevelPublic && (node->getModifiers() & DeclarationModifiers::AccessModifiers) == 0) type->setAccessLevel(AccessLevelPublic);//when access level is undefined, try to inherit base's access level else type->setAccessLevel(parseAccessLevel(node->getModifiers())); } declarationFinished(type->getName(), type, node); return type; }
GenericParametersDefPtr Parser::parseGenericParametersDef() { Token token; ENTER_CONTEXT(TokenizerContextType); expect(L"<", token); GenericParametersDefPtr ret = nodeFactory->createGenericParametersDef(token.state); // generic-parameter-list → generic-parameter | generic-parameter,generic-parameter-list do { // generic-parameter → type-name // generic-parameter → type-name:type-identifier // generic-parameter → type-name:protocol-composition-type expect_identifier(token); std::wstring typeName = token.token; TypeIdentifierPtr typeId = nodeFactory->createTypeIdentifier(token.state); typeId->setName(typeName); ret->addGenericType(typeId); if(match(L":")) { TypeNodePtr expected; if(predicate(L"protocol")) expected = parseProtocolComposition(); else expected = parseTypeIdentifier(); GenericConstraintDefPtr c = nodeFactory->createGenericConstraintDef(token.state); typeId = nodeFactory->createTypeIdentifier(token.state); typeId->setName(typeName); c->setIdentifier(typeId); c->setConstraintType(GenericConstraintDef::AssignableTo); c->setExpectedType(expected); ret->addConstraint(c); } } while (match(L",")); // requirement-clause → where requirement-list if(match(Keyword::Where)) { // requirement-list → requirement | requirement,requirement-list do { TypeIdentifierPtr type = parseTypeIdentifier(); // requirement → conformance-requirement | same-type-requirement if(match(L":")) { // conformance-requirement → type-identifier:type-identifier // conformance-requirement → type-identifier:protocol-composition-type TypeNodePtr expected; if (predicate(L"protocol")) expected = this->parseProtocolComposition(); else expected = parseTypeIdentifier(); GenericConstraintDefPtr c = nodeFactory->createGenericConstraintDef(*type->getSourceInfo()); c->setConstraintType(GenericConstraintDef::AssignableTo); c->setIdentifier(type); c->setExpectedType(expected); ret->addConstraint(c); } else if(match(L"==")) { // same-type-requirement → type-identifier==type-identifier GenericConstraintDefPtr c = nodeFactory->createGenericConstraintDef(*type->getSourceInfo()); ret->addConstraint(c); c->setIdentifier(type); TypeIdentifierPtr expectedType = parseTypeIdentifier(); c->setConstraintType(GenericConstraintDef::EqualsTo); c->setExpectedType(expectedType); } } while (match(L",")); } expect(L">"); return ret; }
void NodeSerializer::visitTypeIdentifier(const TypeIdentifierPtr& node) { append(node->getName()); }
TypePtr DeclarationAnalyzer::defineType(const std::shared_ptr<TypeDeclaration>& node) { TypeIdentifierPtr id = node->getIdentifier(); SymbolScope* scope = NULL; TypePtr type; //Analyze the type's category Type::Category category; switch(node->getNodeType()) { case NodeType::Enum: category = Type::Enum; break; case NodeType::Class: category = Type::Class; break; case NodeType::Struct: category = Type::Struct; break; case NodeType::Protocol: category = Type::Protocol; break; default: assert(0 && "Impossible to execute here."); } //it's inside the type's scope, so need to access parent scope; SymbolScope* typeScope = symbolRegistry->getCurrentScope(); SymbolScope* currentScope = typeScope->getParentScope(); //check if this type is already defined symbolRegistry->lookupType(id->getName(), &scope, &type); if(type && scope == currentScope) { //invalid redeclaration of type T error(node, Errors::E_INVALID_REDECLARATION_1, id->getName()); return nullptr; } //prepare for generic types GenericDefinitionPtr generic; GenericParametersDefPtr genericParams = node->getGenericParametersDef(); //check if it's defined as a nested type if(ctx->currentType) { if(genericParams) { error(node, Errors::E_GENERIC_TYPE_A_NESTED_IN_TYPE_B_IS_NOT_ALLOWED_2, id->getName(), ctx->currentType->getName()); return nullptr; } if(ctx->currentType->isGenericType()) { error(node, Errors::E_TYPE_A_NESTED_IN_GENERIC_TYPE_B_IS_NOT_ALLOWED_2, id->getName(), ctx->currentType->getName()); return nullptr; } } if(genericParams) { generic = prepareGenericTypes(genericParams); generic->registerTo(typeScope); } //check inheritance clause TypePtr parent = nullptr; std::vector<TypePtr> protocols; bool first = true; for(const TypeIdentifierPtr& parentType : node->getParents()) { parentType->accept(semanticAnalyzer); TypePtr ptr = this->lookupType(parentType); if(ptr->getCategory() == Type::Class && category == Type::Class) { if(!first) { //only the first type can be class type error(parentType, Errors::E_SUPERCLASS_MUST_APPEAR_FIRST_IN_INHERITANCE_CLAUSE_1, toString(parentType)); return nullptr; } parent = ptr; if(parent->hasFlags(SymbolFlagFinal)) { error(parentType, Errors::E_INHERITANCE_FROM_A_FINAL_CLASS_A_1, parentType->getName()); return nullptr; } } else if(category == Type::Enum && ptr->getCategory() != Type::Protocol) { if(parent)//already has a raw type { error(parentType, Errors::E_MULTIPLE_ENUM_RAW_TYPES_A_AND_B_2, parent->toString(), ptr->toString()); return nullptr; } if(!first) { error(parentType, Errors::E_RAW_TYPE_A_MUST_APPEAR_FIRST_IN_THE_ENUM_INHERITANCE_CLAUSE_1, ptr->toString()); return nullptr; } //check if the raw type is literal convertible if(!isLiteralTypeForEnum(symbolRegistry->getGlobalScope(), ptr)) { error(parentType, Errors::E_RAW_TYPE_A_IS_NOT_CONVERTIBLE_FROM_ANY_LITERAL_1, ptr->toString()); return nullptr; } if(!ptr->canAssignTo(symbolRegistry->getGlobalScope()->Equatable())) { error(parentType, Errors::E_RAWREPRESENTABLE_INIT_CANNOT_BE_SYNTHESIZED_BECAUSE_RAW_TYPE_A_IS_NOT_EQUATABLE_1, ptr->toString()); return nullptr; } parent = ptr; } else if(ptr->getCategory() == Type::Protocol) { protocols.push_back(ptr); } else { if(category == Type::Class) error(parentType, Errors::E_INHERITANCE_FROM_NONE_PROTOCOL_NON_CLASS_TYPE_1, toString(parentType)); else error(parentType, Errors::E_INHERITANCE_FROM_NONE_PROTOCOL_TYPE_1, toString(parentType)); return nullptr; } first = false; } //register this type type = Type::newType(node->getIdentifier()->getName(), category, node, parent, protocols, generic); node->setType(type); if(parent && parent->getAccessLevel() == AccessLevelPublic && (node->getModifiers() & DeclarationModifiers::AccessModifiers) == 0) type->setAccessLevel(AccessLevelPublic);//when access level is undefined, try to inherit base's access level else type->setAccessLevel(parseAccessLevel(node->getModifiers())); currentScope->addSymbol(type); if(node->hasModifier(DeclarationModifiers::Final)) type->setFlags(SymbolFlagFinal, true); declarationFinished(type->getName(), type, node); return type; }