const Token& PackageParser::parseAndValidateNewTypeName(EmojicodeChar *name, EmojicodeChar *ns) { bool optional; auto &nameToken = parseTypeName(name, ns, &optional); if (optional) { throw CompilerErrorException(nameToken, "🍬 cannot be declared as type."); } Type type = typeNothingness; if (package_->fetchRawType(*name, *ns, optional, nameToken, &type)) { auto str = type.toString(typeNothingness, true); throw CompilerErrorException(nameToken, "Type %s is already defined.", str.c_str()); } return nameToken; }
void PackageParser::parseProtocol(const EmojicodeString &documentation, const Token &theToken, bool exported) { EmojicodeChar name, enamespace; parseAndValidateNewTypeName(&name, &enamespace); auto protocol = new Protocol(name, package_, documentation, theToken); parseGenericArgumentList(protocol, Type(protocol, false)); protocol->finalizeGenericArguments(); 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); } auto protocolType = Type(protocol, false); package_->registerType(protocolType, name, enamespace, exported); while (stream_.nextTokenIsEverythingBut(E_WATERMELON)) { auto documentation = parseDocumentationToken(); auto token = stream_.consumeToken(IDENTIFIER); auto deprecated = Attribute<E_WARNING_SIGN>().parse(&stream_); if (token.value[0] != E_PIG) { throw CompilerErrorException(token, "Only method declarations are allowed inside a protocol."); } auto methodName = stream_.consumeToken(IDENTIFIER); auto method = new Method(methodName.value[0], PUBLIC, false, nullptr, package_, methodName.position(), false, documentation, deprecated.set()); auto a = parseArgumentList(method, protocolType); auto b = parseReturnType(method, protocolType); if (a || b) { protocol->setUsesSelf(); } protocol->addMethod(method); } stream_.consumeToken(IDENTIFIER); }
void PackageParser::parseEnum(const EmojicodeString &documentation, bool exported) { EmojicodeChar name, enamespace; parseAndValidateNewTypeName(&name, &enamespace); Enum *eenum = new Enum(name, package_, documentation); package_->registerType(Type(eenum, false), name, enamespace, exported); 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)) { eenum->addValueFor(stream_.consumeToken().value[0]); } stream_.consumeToken(IDENTIFIER); }
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();
void PackageParser::reservedEmojis(const Token &token, const char *place) const { EmojicodeChar name = token.value[0]; switch (name) { case E_CUSTARD: case E_DOUGHNUT: case E_SHORTCAKE: case E_CHOCOLATE_BAR: case E_COOKING: case E_COOKIE: case E_LOLLIPOP: case E_CLOCKWISE_RIGHTWARDS_AND_LEFTWARDS_OPEN_CIRCLE_ARROWS: case E_CLOCKWISE_RIGHTWARDS_AND_LEFTWARDS_OPEN_CIRCLE_ARROWS_WITH_CIRCLED_ONE_OVERLAY: case E_RED_APPLE: case E_BEER_MUG: case E_CLINKING_BEER_MUGS: case E_LEMON: case E_GRAPES: case E_STRAWBERRY: case E_BLACK_SQUARE_BUTTON: case E_LARGE_BLUE_DIAMOND: case E_DOG: case E_HIGH_VOLTAGE_SIGN: case E_CLOUD: case E_BANANA: case E_HONEY_POT: case E_SOFT_ICE_CREAM: case E_ICE_CREAM: case E_TANGERINE: case E_WATERMELON: case E_AUBERGINE: case E_SPIRAL_SHELL: case E_BLACK_RIGHT_POINTING_DOUBLE_TRIANGLE: case E_BLACK_RIGHT_POINTING_DOUBLE_TRIANGLE_WITH_VERTICAL_BAR: { ecCharToCharStack(name, nameString); throw CompilerErrorException(token, "%s is reserved and cannot be used as %s name.", nameString, place); } } }
void Token::validateDouble() const { if (value.back() == '.') { throw CompilerErrorException(position(), "Expected a digit after decimal seperator."); } }
void Token::validateInteger(bool isHex) const { if (isHex && value.size() < 3) { throw CompilerErrorException(position(), "Expected a digit after integer literal prefix."); } }
void PackageParser::parse() { while (stream_.hasMoreTokens()) { auto documentation = parseDocumentationToken(); auto exported = Attribute<E_EARTH_GLOBE_EUROPE_AFRICA>().parse(&stream_); auto theToken = stream_.consumeToken(IDENTIFIER); switch (theToken.value[0]) { case E_PACKAGE: { exported.disallow(); auto nameToken = stream_.consumeToken(VARIABLE); auto namespaceToken = stream_.consumeToken(IDENTIFIER); auto name = nameToken.value.utf8CString(); package_->loadPackage(name, namespaceToken.value[0], theToken); continue; } case E_CROCODILE: parseProtocol(documentation, theToken, exported.set()); continue; case E_TURKEY: parseEnum(documentation, exported.set()); continue; case E_RADIO: exported.disallow(); package_->setRequiresBinary(); if (strcmp(package_->name(), "_") == 0) { throw CompilerErrorException(theToken, "You may not set 📻 for the _ package."); } continue; case E_CRYSTAL_BALL: { exported.disallow(); if (package_->validVersion()) { throw CompilerErrorException(theToken, "Package version already declared."); } auto major = stream_.consumeToken(INTEGER).value.utf8CString(); auto minor = stream_.consumeToken(INTEGER).value.utf8CString(); uint16_t majori = strtol(major, nullptr, 0); uint16_t minori = strtol(minor, nullptr, 0); delete [] major; delete [] minor; package_->setPackageVersion(PackageVersion(majori, minori)); if (!package_->validVersion()) { throw CompilerErrorException(theToken, "The provided package version is not valid."); } continue; } case E_WALE: { exported.disallow(); EmojicodeChar className, enamespace; bool optional; auto &classNameToken = parseTypeName(&className, &enamespace, &optional); if (optional) { throw CompilerErrorException(classNameToken, "Optional types are not extendable."); } Type type = typeNothingness; if (!package_->fetchRawType(className, enamespace, optional, theToken, &type)) { throw CompilerErrorException(classNameToken, "Class does not exist."); } if (type.type() != TT_CLASS) { throw CompilerErrorException(classNameToken, "Only classes are extendable."); } // Native extensions are allowed if the class was defined in this package. parseClassBody(type.eclass, nullptr, type.eclass->package() == package_); continue; } case E_RABBIT: parseClass(documentation, theToken, exported.set()); continue; case E_SCROLL: { exported.disallow(); auto pathString = stream_.consumeToken(STRING); auto relativePath = pathString.position().file; auto fileString = pathString.value.utf8CString(); char *str = fileString; const char *lastSlash = strrchr(relativePath, '/'); if (lastSlash != nullptr) { const char *directory = strndup(relativePath, lastSlash - relativePath); asprintf(&str, "%s/%s", directory, fileString); delete [] fileString; delete [] directory; } PackageParser(package_, lex(str)).parse(); delete [] str; continue; } default: ecCharToCharStack(theToken.value[0], f); throw CompilerErrorException(theToken, "Unexpected identifier %s", f); break; } } }