void PackageParser::parseGenericArgumentList(TypeDefinitionWithGenerics *typeDef, TypeContext tc) { while (stream_.nextTokenIs(E_SPIRAL_SHELL)) { stream_.consumeToken(IDENTIFIER); auto variable = stream_.consumeToken(VARIABLE); auto constraintType = parseAndFetchType(tc, NoDynamism, nullptr, true); typeDef->addGenericArgument(variable, constraintType); } }
void Type::parseGenericArguments(Type contextType, EmojicodeChar theNamespace, TypeDynamism dynamism, const Token *errorToken) { if (this->type == TT_CLASS) { this->genericArguments = std::vector<Type>(this->eclass->superGenericArguments); if (this->eclass->ownGenericArgumentCount){ int count = 0; while(nextToken()->value[0] == E_SPIRAL_SHELL){ const Token *token = consumeToken(); Type ta = parseAndFetchType(contextType, theNamespace, dynamism, nullptr); validateGenericArgument(ta, count, contextType, token); genericArguments.push_back(ta); count++; } if(count != this->eclass->ownGenericArgumentCount){ auto str = this->toString(typeNothingness, false); compilerError(errorToken, "Type %s requires %d generic arguments, but %d were given.", str.c_str(), this->eclass->ownGenericArgumentCount, count); } } } }
void PackageParser::parseClassBody(Class *eclass, std::set<EmojicodeChar> *requiredInitializers, bool allowNative) { allowNative = allowNative && package_->requiresBinary(); auto token = stream_.consumeToken(IDENTIFIER); if (token.value[0] != E_GRAPES) { ecCharToCharStack(token.value[0], s); throw CompilerErrorException(token, "Expected 🍇 but found %s instead.", s); } while (stream_.nextTokenIsEverythingBut(E_WATERMELON)) { auto documentation = parseDocumentationToken(); auto deprecated = Attribute<E_WARNING_SIGN>().parse(&stream_); auto final = Attribute<E_LOCK_WITH_INK_PEN>().parse(&stream_); AccessLevel accessLevel = readAccessLevel(&stream_); auto override = Attribute<E_BLACK_NIB>().parse(&stream_); auto staticOnType = Attribute<E_RABBIT>().parse(&stream_); auto required = Attribute<E_KEY>().parse(&stream_); auto canReturnNothingness = Attribute<E_CANDY>().parse(&stream_); auto token = stream_.consumeToken(IDENTIFIER); switch (token.value[0]) { case E_SHORTCAKE: { staticOnType.disallow(); override.disallow(); final.disallow(); required.disallow(); canReturnNothingness.disallow(); deprecated.disallow(); auto &variableName = stream_.consumeToken(VARIABLE); auto type = parseAndFetchType(Type(eclass), GenericTypeVariables); eclass->addInstanceVariable(Argument(variableName, type)); } break; case E_CROCODILE: { staticOnType.disallow(); override.disallow(); final.disallow();
Type Type::parseAndFetchType(Type contextType, EmojicodeChar theNamespace, TypeDynamism dynamism, bool *dynamicType){ if (dynamicType) { *dynamicType = false; } if (dynamism & AllowGenericTypeVariables && contextType.type == TT_CLASS && (nextToken()->type == VARIABLE || (nextToken()->value[0] == E_CANDY && nextToken()->nextToken->type == VARIABLE))) { if (dynamicType) { *dynamicType = true; } bool optional = false; const Token *variableToken = consumeToken(); if (variableToken->value[0] == E_CANDY) { variableToken = consumeToken(); optional = true; } auto it = contextType.eclass->ownGenericArgumentVariables.find(variableToken->value); if (it != contextType.eclass->ownGenericArgumentVariables.end()){ Type type = it->second; type.optional = optional; return type; } else { compilerError(variableToken, "No such generic type variable \"%s\".", variableToken->value.utf8CString()); } } else if (nextToken()->value[0] == E_RAT) { const Token *token = consumeToken(); if(!(dynamism & AllowDynamicClassType)){ compilerError(token, "🐀 not allowed here."); } if (dynamicType) { *dynamicType = true; } return contextType; } else if (nextToken()->value[0] == E_GRAPES || (nextToken()->value[0] == E_CANDY && nextToken()->nextToken->type == VARIABLE)) { bool optional = false; if (nextToken()->value[0] == E_CANDY) { consumeToken(); optional = true; } consumeToken(); Type t(TT_CALLABLE, optional); t.arguments = 0; t.genericArguments.push_back(typeNothingness); while (!(nextToken()->type == IDENTIFIER && (nextToken()->value[0] == E_WATERMELON || nextToken()->value[0] == E_RIGHTWARDS_ARROW))) { t.arguments++; t.genericArguments.push_back(parseAndFetchType(contextType, theNamespace, dynamism, nullptr)); } if(nextToken()->type == IDENTIFIER && nextToken()->value[0] == E_RIGHTWARDS_ARROW){ consumeToken(); t.genericArguments[0] = parseAndFetchType(contextType, theNamespace, dynamism, nullptr); } const Token *token = consumeToken(IDENTIFIER); if (token->value[0] != E_WATERMELON) { compilerError(token, "Expected 🍉."); } return t; } else { EmojicodeChar typeName, typeNamespace; bool optional, existent; const Token *token = parseTypeName(&typeName, &typeNamespace, &optional, theNamespace); Type type = fetchRawType(typeName, typeNamespace, optional, token, &existent); if (!existent) { ecCharToCharStack(typeName, nameString); ecCharToCharStack(typeNamespace, namespaceString); compilerError(token, "Could not find type %s in enamespace %s.", nameString, namespaceString); } type.parseGenericArguments(contextType, theNamespace, dynamism, token); return type; } }
deprecated.disallow(); auto &variableName = stream_.consumeToken(VARIABLE); auto type = parseAndFetchType(Type(eclass), GenericTypeVariables); eclass->addInstanceVariable(Argument(variableName, type)); } break; case E_CROCODILE: { staticOnType.disallow(); override.disallow(); final.disallow(); required.disallow(); canReturnNothingness.disallow(); deprecated.disallow(); Type type = parseAndFetchType(Type(eclass), GenericTypeVariables, nullptr, true); if (type.optional()) { throw CompilerErrorException(token, "A class cannot conform to an 🍬 protocol."); } if (type.type() != TT_PROTOCOL) { throw CompilerErrorException(token, "The given type is not a protocol."); } eclass->addProtocol(type); } break; case E_PIG: { required.disallow(); canReturnNothingness.disallow();