Esempio n. 1
0
void Procedure::checkOverride(Procedure *superProcedure){
    if(overriding && !superProcedure){
        ecCharToCharStack(name, mn);
        compilerError(dToken, "%s was declared ✒️ but does not override anything.", mn);
    }
    else if(!overriding && superProcedure){
        ecCharToCharStack(name, mn);
        compilerError(dToken, "If you want to override %s add ✒️.", mn);
    }
}
Esempio n. 2
0
void Package::loadInto(Package *destinationPackage, EmojicodeChar ns, const Token *errorToken) const {
    for (auto exported : exportedTypes_) {
        Type type = typeNothingness;
        if (destinationPackage->fetchRawType(exported.name, ns, false, nullptr, &type)) {
            ecCharToCharStack(ns, nss);
            ecCharToCharStack(exported.name, tname);
            compilerError(errorToken, "Package %s could not be loaded into namespace %s of package %s: %s collides with a type of the same name in the same namespace.", name(), nss, destinationPackage->name(), tname);
        }
        
        destinationPackage->registerType(exported.type, exported.name, ns, false);
    }
}
Esempio n. 3
0
void reportProcedureInformation(Procedure *p, ReturnManner returnm, bool last, TypeContext tc){
    ecCharToCharStack(p->name, nameString);
    
    printf("{");
    printf("\"name\": \"%s\",", nameString);
    
    if (returnm == Return) {
        reportType("returnType", p->returnType, false, tc);
    }
    else if (returnm == CanReturnNothingness) {
        printf("\"canReturnNothingness\": true,");
    }
    
    reportGenericArguments(p->genericArgumentVariables, p->genericArgumentConstraints, 0, tc);
    reportDocumentation(p->documentationToken);
    
    printf("\"arguments\": [");
    for (int i = 0; i < p->arguments.size(); i++) {
        printf("{");
        Variable variable = p->arguments[i];
        
        const char *varname = variable.name->value.utf8CString();
        
        reportType("type", variable.type, false, tc);
        printf("\"name\":");
        printJSONStringToFile(varname, stdout);
        printf("}%s", i + 1 == p->arguments.size() ? "" : ",");
        
        delete [] varname;
    }
    printf("]");
    
    printf("}%s", last ? "" : ",");
}
Esempio n. 4
0
void Procedure::deprecatedWarning(const Token *callToken) {
    if (deprecated) {
        ecCharToCharStack(name, mn);
        if (documentationToken) {
            char *documentation = documentationToken->value.utf8CString();
            compilerWarning(callToken, "%s is deprecated. Please refer to the documentation for further information:\n%s", mn, documentation);
            delete [] documentation;
        }
        else {
            compilerWarning(callToken, "%s is deprecated.", mn);
        }
    }
}
Esempio n. 5
0
void Procedure::checkPromises(Procedure *superProcedure, const char *on, Type contextType) {
    if(superProcedure->final){
        ecCharToCharStack(this->name, mn);
        compilerError(this->dToken, "%s of %s was marked 🔏.", on, mn);
    }
    if (!this->returnType.compatibleTo(superProcedure->returnType, contextType)) {
        ecCharToCharStack(this->name, mn);
        auto supername = superProcedure->returnType.toString(contextType, true);
        auto thisname = this->returnType.toString(contextType, true);
        compilerError(this->dToken, "Return type %s of %s is not compatible with the return type %s of its %s.", thisname.c_str(), mn, supername.c_str(), on);
    }
    if(superProcedure->arguments.size() != this->arguments.size()){
        ecCharToCharStack(this->name, mn);
        compilerError(this->dToken, "%s expects %s arguments than its %s.", mn, (superProcedure->arguments.size() < this->arguments.size()) ? "more" : "less", on);
    }
    for (uint8_t i = 0; i < superProcedure->arguments.size(); i++) {
        //other way, because the method may define a more generic type
        if (!superProcedure->arguments[i].type.compatibleTo(this->arguments[i].type, contextType)) {
            auto supertype = superProcedure->arguments[i].type.toString(contextType, true);
            auto thisname = this->arguments[i].type.toString(contextType, true);
            compilerError(superProcedure->dToken, "Type %s of argument %d is not compatible with its %s argument type %s.", thisname.c_str(), i + 1, on, supertype.c_str());
        }
    }
}
Esempio n. 6
0
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);
}
Esempio n. 7
0
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);
}
Esempio n. 8
0
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();
Esempio n. 9
0
void Procedure::parseBody(bool allowNative) {
    if(nextToken()->value[0] == E_RADIO){
        const Token *t = consumeToken(IDENTIFIER);
        if(!allowNative){
            compilerError(t, "Native code is not allowed in this context.");
        }
        native = true;
        return;
    }
    
    const Token *token = consumeToken(IDENTIFIER);
    
    if (token->value[0] != E_GRAPES){
        ecCharToCharStack(token->value[0], c);
        compilerError(token, "Expected 🍇 but found %s instead.", c);
    }
    
    firstToken = currentToken;
    
    int d = 0;
    while ((token = until(E_WATERMELON, E_GRAPES, &d)) != nullptr);
}
Esempio n. 10
0
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);
        }
    }
}
Esempio n. 11
0
void stringAppendEc(EmojicodeChar c, std::string *string){
    ecCharToCharStack(c, sc);
    string->append(sc);
}
Esempio n. 12
0
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;
    }
}
Esempio n. 13
0
void report(Package *package){
    std::list<Enum *> enums;
    std::list<Class *> classes;
    std::list<Protocol *> protocols;
    
    for (auto exported : package->exportedTypes()) {
        switch (exported.type.type) {
            case TT_CLASS:
                classes.push_back(exported.type.eclass);
                break;
            case TT_ENUM:
                enums.push_back(exported.type.eenum);
                break;
            case TT_PROTOCOL:
                protocols.push_back(exported.type.protocol);
                break;
            default:
                break;
        }
    }
    
    bool printedClass = false;
    printf("{");
    printf("\"classes\": [");
    for(auto eclass : classes){
        if (printedClass) {
            putchar(',');
        }
        printedClass = true;
        
        printf("{");
        
        ecCharToCharStack(eclass->name, className);
        printf("\"name\": \"%s\",", className);

        reportGenericArguments(eclass->ownGenericArgumentVariables, eclass->genericArgumentConstraints, eclass->superGenericArguments.size(), TypeContext(eclass));
        reportDocumentation(eclass->documentationToken);
        
        if (eclass->superclass) {
            ecCharToCharStack(eclass->superclass->name, superClassName);
            printf("\"superclass\": {\"package\": \"%s\", \"name\": \"%s\"},", eclass->superclass->package->name(), superClassName);
        }
        
        printf("\"methods\": [");
        for(size_t i = 0; i < eclass->methodList.size(); i++){
            Method *method = eclass->methodList[i];
            reportProcedureInformation(method, Return, i + 1 == eclass->methodList.size(), TypeContext(eclass, method));
        }
        printf("],");
        
        printf("\"initializers\": [");
        for(size_t i = 0; i < eclass->initializerList.size(); i++){
            Initializer *initializer = eclass->initializerList[i];
            reportProcedureInformation(initializer, initializer->canReturnNothingness ? CanReturnNothingness : NoReturn, i + 1 == eclass->initializerList.size(), TypeContext(eclass, initializer));
        }
        printf("],");
        
        printf("\"classMethods\": [");
        for(size_t i = 0; i < eclass->classMethodList.size(); i++){
            ClassMethod *classMethod = eclass->classMethodList[i];
            reportProcedureInformation((Procedure *)classMethod, Return, eclass->classMethodList.size() == i + 1, TypeContext(eclass, classMethod));
        }
        printf("],");
        
        printf("\"conformsTo\": [");
        for(size_t i = 0; i < eclass->protocols().size(); i++){
            Protocol *protocol = eclass->protocols()[i];
            reportType(nullptr, Type(protocol, false), i + 1 == eclass->protocols().size(), TypeContext(eclass));
        }
        printf("]}");
    }
    printf("],");
    
    printf("\"enums\": [");
    bool printedEnum = false;
    for(auto eenum : enums){
        if (printedEnum) {
            putchar(',');
        }
        printf("{");
        
        printedEnum = true;
        
        ecCharToCharStack(eenum->name, enumName);
        printf("\"name\": \"%s\",", enumName);
        
        reportDocumentation(eenum->documentationToken);
        
        bool printedValue = false;
        printf("\"values\": [");
        for(auto it : eenum->map){
            ecCharToCharStack(it.first, value);
            if (printedValue){
                putchar(',');
            }
            printf("\"%s\"", value);
            printedValue = true;
        }
        printf("]}");
    }
    printf("],");
    
    printf("\"protocols\": [");
    bool printedProtocol = false;
    for(auto protocol : protocols){
        if (printedProtocol) {
            putchar(',');
        }
        printedProtocol = true;
        printf("{");
        
        ecCharToCharStack(protocol->name, protocolName);
        printf("\"name\": \"%s\",", protocolName);
        
        reportDocumentation(protocol->documentationToken);
        
        printf("\"methods\": [");
        for(size_t i = 0; i < protocol->methods().size(); i++){
            Method *method = protocol->methods()[i];
            reportProcedureInformation((Procedure *)method, Return, i + 1 == protocol->methods().size(), TypeContext(Type(protocol, false)));
        }
        printf("]}");
    }
    printf("]");
    printf("}");
}
Esempio n. 14
0
void report(const char *packageName){
    bool printedClass = false;
    printf("{");
    printf("\"classes\": [");
    for(auto eclass : classes){
        if (strcmp(eclass->package->name, packageName) != 0) {
            continue;
        }
        
        if (printedClass) {
            putchar(',');
        }
        printedClass = true;
        
        printf("{");
        
        ecCharToCharStack(eclass->name, className);
        printf("\"name\": \"%s\",", className);
        
        reportDocumentation(eclass->documentationToken);
        
        if (eclass->superclass) {
            ecCharToCharStack(eclass->superclass->name, superClassName);
            printf("\"superclass\": {\"package\": \"%s\", \"name\": \"%s\"},", eclass->superclass->package->name, superClassName);
        }
        
        printf("\"methods\": [");
        for(size_t i = 0; i < eclass->methodList.size(); i++){
            Method *method = eclass->methodList[i];
            reportProcedureInformation(method, Return, i + 1 == eclass->methodList.size());
        }
        printf("],");
        
        printf("\"initializers\": [");
        for(size_t i = 0; i < eclass->initializerList.size(); i++){
            Initializer *initializer = eclass->initializerList[i];
            reportProcedureInformation(initializer, initializer->canReturnNothingness ? CanReturnNothingness : NoReturn, i + 1 == eclass->initializerList.size());
        }
        printf("],");
        
        printf("\"classMethods\": [");
        for(size_t i = 0; i < eclass->classMethodList.size(); i++){
            ClassMethod *classMethod = eclass->classMethodList[i];
            reportProcedureInformation((Procedure *)classMethod, Return, eclass->classMethodList.size() == i + 1);
        }
        printf("],");
        
        printf("\"conformsTo\": [");
        for(size_t i = 0; i < eclass->protocols().size(); i++){
            Protocol *protocol = eclass->protocols()[i];
            reportType(nullptr, Type(protocol, false), i + 1 == eclass->protocols().size());
        }
        printf("]}");
    }
    printf("],");
    printf("\"enums\": [");
    bool printedEnum = false;
    for(auto it : enumsRegister){
        Enum *eenum = it.second;
        
        if (strcmp(eenum->package.name, packageName) != 0) {
            continue;
        }
        if (printedEnum) {
            putchar(',');
        }
        printf("{");
        
        printedEnum = true;
        
        ecCharToCharStack(eenum->name, enumName);
        printf("\"name\": \"%s\",", enumName);
        
        reportDocumentation(eenum->documentationToken);
        
        bool printedValue = false;
        printf("\"values\": [");
        for(auto it : eenum->map){
            ecCharToCharStack(it.first, value);
            if (printedValue){
                putchar(',');
            }
            printf("\"%s\"", value);
            printedValue = true;
        }
        printf("]}");
    }
    printf("],");
    printf("\"protocols\": [");
    bool printedProtocol = false;
    for(auto it : protocolsRegister){
        Protocol *protocol = it.second;
        
        if (strcmp(protocol->package->name, packageName) != 0) {
            continue;
        }
        if (printedProtocol) {
            putchar(',');
        }
        printedProtocol = true;
        printf("{");
        
        ecCharToCharStack(protocol->name, protocolName);
        printf("\"name\": \"%s\",", protocolName);
        
        reportDocumentation(protocol->documentationToken);
        
        printf("\"methods\": [");
        for(size_t i = 0; i < protocol->methods().size(); i++){
            Method *method = protocol->methods()[i];
            reportProcedureInformation((Procedure *)method, Return, i + 1 == protocol->methods().size());
        }
        printf("]}");
    }
    printf("]");
    printf("}");
}
Esempio n. 15
0
void analyzeClass(Type classType, Writer &writer){
    auto eclass = classType.eclass;
    
    writer.writeEmojicodeChar(eclass->name);
    if(eclass->superclass){
        writer.writeUInt16(eclass->superclass->index);
    }
    else { //If the eclass does not have a superclass the own index gets written
        writer.writeUInt16(eclass->index);
    }
    
    Scope objectScope(true);
    
    //Get the ID offset for this eclass by summing up all superclasses instance variable counts
    uint16_t offset = 0;
    for(Class *aClass = eclass->superclass; aClass != nullptr; aClass = aClass->superclass){
        offset += aClass->instanceVariables.size();
    }
    writer.writeUInt16(eclass->instanceVariables.size() + offset);
    
    //Number of methods inclusive superclass
    writer.writeUInt16(eclass->nextMethodVti);
    //Number of eclass methods inclusive superclass
    writer.writeUInt16(eclass->nextClassMethodVti);
    //Initializer inclusive superclass
    writer.writeByte(eclass->inheritsContructors ? 1 : 0);
    writer.writeUInt16(eclass->nextInitializerVti);
    
    writer.writeUInt16(eclass->methodList.size());
    writer.writeUInt16(eclass->initializerList.size());
    writer.writeUInt16(eclass->classMethodList.size());
    
    for (auto var : eclass->instanceVariables) {
        CompilerVariable *cv = new CompilerVariable(var->type, offset++, 1, false);
        cv->variable = var;
        objectScope.setLocalVariable(var->name, cv);
    }
    
    pushScope(&objectScope);
    
    for (auto method : eclass->methodList) {
        StaticFunctionAnalyzer::writeAndAnalyzeProcedure(*method, writer, classType);
    }
    
    for (auto initializer : eclass->initializerList) {
        StaticFunctionAnalyzer::writeAndAnalyzeProcedure(*initializer, writer, classType, false, initializer);
    }
    
    popScope();
    
    for (auto classMethod : eclass->classMethodList) {
        StaticFunctionAnalyzer::writeAndAnalyzeProcedure(*classMethod, writer, classType, true);
    }
    
    if (eclass->instanceVariables.size() > 0 && eclass->initializerList.size() == 0) {
        auto str = classType.toString(typeNothingness, true);
        compilerWarning(eclass->classBegin, "Class %s defines %d instances variables but has no initializers.", str.c_str(), eclass->instanceVariables.size());
    }
    
    writer.writeUInt16(eclass->protocols().size());
    
    if (eclass->protocols().size() > 0) {
        auto biggestPlaceholder = writer.writePlaceholder<uint16_t>();
        auto smallestPlaceholder = writer.writePlaceholder<uint16_t>();

        uint_fast16_t smallestProtocolIndex = UINT_FAST16_MAX;
        uint_fast16_t biggestProtocolIndex = 0;
        
        for (auto protocol : eclass->protocols()) {
            writer.writeUInt16(protocol->index);
            
            if (protocol->index > biggestProtocolIndex) {
                biggestProtocolIndex = protocol->index;
            }
            if (protocol->index < smallestProtocolIndex) {
                smallestProtocolIndex = protocol->index;
            }
            
            writer.writeUInt16(protocol->methods().size());
            
            for (auto method : protocol->methods()) {
                Method *clm = eclass->getMethod(method->name);
                
                if (clm == nullptr) {
                    auto className = classType.toString(typeNothingness, true);
                    auto protocolName = Type(protocol, false).toString(typeNothingness, true);
                    ecCharToCharStack(method->name, ms);
                    compilerError(eclass->classBegin, "Class %s does not agree to protocol %s: Method %s is missing.", className.c_str(), protocolName.c_str(), ms);
                }
                
                writer.writeUInt16(clm->vti);
                clm->checkPromises(method, "protocol definition", classType);
            }
        }
        
        biggestPlaceholder.write(biggestProtocolIndex);
        smallestPlaceholder.write(smallestProtocolIndex);
    }
}
Esempio n. 16
0
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;
        }
    }
}