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); }
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); }
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(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, 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(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()); }
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(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(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; }
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; }