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); } }
void Type::validateGenericArgument(Type ta, uint16_t i, Type contextType, const Token *token){ if (this->type != TT_CLASS) { compilerError(token, "The compiler encountered an internal inconsistency related to generics."); } if(this->eclass->superclass){ i += this->eclass->superclass->genericArgumentCount; } if(!ta.compatibleTo(this->eclass->genericArgumentContraints[i], contextType)){ compilerError(token, "Types not matching."); } }
void if2up(char* file, char* result, char* bindir, int suppressWarnings, /* suppress warnings? */ int profiling /* profiling */ ) { char updater[MAXPATHLEN]; charStarQueue* argv = 0; sprintf(updater,"%s/if2up",bindir); enqueue(&argv,updater); enqueue(&argv,file); enqueue(&argv,result); if ( suppressWarnings ) enqueue(&argv,"-w"); if ( profiling ) enqueue(&argv,"-W"); enqueue(&argv,"-I"); /* Suppress Sequent code improvement migration */ if ( Submit(&argv) != 0 ) { compilerError("if2 update in place failure"); } }
void if2mem(char* file, char* result, char* bindir, int suppressWarnings, /* suppress warnings? */ int profiling, /* profiling */ int optimize, /* Perform aggressive optimization */ int optimizeInlined /* optimize inlined calls */ ) { char manager[MAXPATHLEN]; charStarQueue* argv = 0; sprintf(manager,"%s/if2mem",bindir); enqueue(&argv,manager); enqueue(&argv,file); enqueue(&argv,result); if ( !optimize ) { enqueue(&argv,"-v"); /* no invar */ enqueue(&argv,"-V"); /* no Oinvar */ enqueue(&argv,"-c"); /* no cse */ enqueue(&argv,"-g"); /* no gcse */ enqueue(&argv,"-f"); /* no fold */ } if ( suppressWarnings ) enqueue(&argv,"-w"); if ( profiling ) enqueue(&argv,"-W"); if ( Submit(&argv) != 0 ) { compilerError("if2 memory manager failure"); } }
const Token* Type::parseTypeName(EmojicodeChar *typeName, EmojicodeChar *enamespace, bool *optional, EmojicodeChar currentNamespace){ if (nextToken()->type == VARIABLE) { compilerError(consumeToken(), "Not in a generic context."); } auto *className = consumeToken(IDENTIFIER); if(className->value[0] == E_CANDY){ *optional = true; className = consumeToken(IDENTIFIER); } else { *optional = false; } if(className->value[0] == E_ORANGE_TRIANGLE){ const Token *nsToken = consumeToken(IDENTIFIER); *enamespace = nsToken->value[0]; className = consumeToken(IDENTIFIER); } else { *enamespace = currentNamespace; } *typeName = className->value[0]; return className; }
int main(int argc, char *argv[]) /* Process command line. */ { optionInit(&argc, argv, options); if (argc != 1) usage(); compilerError(); return 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); } }
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); }
void Package::parse(const char *path, const Token *errorToken) { packages_.emplace(name(), this); parseFile(path, this); if (version().major == 0 && version().minor == 0) { compilerError(errorToken, "Package %s does not provide a valid version.", name()); } packagesLoadingOrder_.push_back(this); finishedLoading_ = true; }
TypeObject* Method::getGenericType(TypeGenericDefinitionEntry* genericSymbol, TypeGenericEntry* genericParams) { if(m_genericParam) { TypeGenericDefinitionEntry * pDefGen = m_genericParam; TypeGenericEntry* pGen = genericParams; while(pGen && pDefGen && strcmp(pDefGen->m_genericName, genericSymbol->m_genericName)) { pDefGen = pDefGen->m_pNextGenericEntry; pGen = pGen->m_pNext; } if(!pDefGen && !pGen) { compilerError(ERR_INTERNAL, "Generic symbol was not found"); return NULL; } if(!pDefGen || pGen) { compilerError(ERR_INTERNAL, "Wrong number of generic parameters"); return NULL; } return pGen->m_instanceType; } else { return NULL; } }
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()); } } }
void Callable::parseArgumentList(TypeContext ct, Package *package){ const Token *token; //Until the grape is found we parse arguments while ((token = nextToken()) && token->type == VARIABLE) { //grape //Get the variable in which to store the argument const Token *variableToken = consumeToken(VARIABLE); auto type = Type::parseAndFetchType(ct, AllowGenericTypeVariables, package); arguments.push_back(Variable(Variable(variableToken, type))); } if (arguments.size() > UINT8_MAX) { compilerError(token, "A function cannot take more than 255 arguments."); } }
Type Type::fetchRawType(EmojicodeChar name, EmojicodeChar enamespace, bool optional, const Token *token, bool *existent){ *existent = true; if(enamespace == globalNamespace){ switch (name) { case E_OK_HAND_SIGN: return Type(TT_BOOLEAN, optional); case E_INPUT_SYMBOL_FOR_SYMBOLS: return Type(TT_SYMBOL, optional); case E_STEAM_LOCOMOTIVE: return Type(TT_INTEGER, optional); case E_ROCKET: return Type(TT_DOUBLE, optional); case E_MEDIUM_WHITE_CIRCLE: if (optional) { compilerWarning(token, "š¬āŖļø is identical to āŖļø. Do not specify š¬."); } return Type(TT_SOMETHING, false); case E_LARGE_BLUE_CIRCLE: return Type(TT_SOMEOBJECT, optional); case E_SPARKLES: compilerError(token, "The Nothingness type may not be referenced to."); } } Class *eclass = getClass(name, enamespace); if (eclass) { Type t = Type(eclass, optional); t.optional = optional; return t; } Protocol *protocol = getProtocol(name, enamespace); if(protocol){ return Type(protocol, optional); } Enum *eenum = getEnum(name, enamespace); if(eenum){ return Type(eenum, optional); } *existent = false; return typeNothingness; }
bool Package::fetchRawType(EmojicodeChar name, EmojicodeChar ns, bool optional, const Token *token, Type *type) { if (ns == globalNamespace) { switch (name) { case E_OK_HAND_SIGN: *type = Type(TT_BOOLEAN, optional); return true; case E_INPUT_SYMBOL_FOR_SYMBOLS: *type = Type(TT_SYMBOL, optional); return true; case E_STEAM_LOCOMOTIVE: *type = Type(TT_INTEGER, optional); return true; case E_ROCKET: *type = Type(TT_DOUBLE, optional); return true; case E_MEDIUM_WHITE_CIRCLE: if (optional) { compilerWarning(token, "š¬āŖļø is identical to āŖļø. Do not specify š¬."); } *type = Type(TT_SOMETHING, false); return true; case E_LARGE_BLUE_CIRCLE: *type = Type(TT_SOMEOBJECT, optional); return true; case E_SPARKLES: compilerError(token, "The Nothingness type may not be referenced to."); } } std::array<EmojicodeChar, 2> key = {ns, name}; auto it = types_.find(key); if (it != types_.end()) { auto xtype = it->second; if (optional) xtype.setOptional(); *type = xtype; return true; } else { return false; } }
void Procedure::parseGenericArguments(TypeContext ct, Package *package) { const Token *token; //Until the grape is found we parse arguments while ((token = nextToken()) && token->type == IDENTIFIER && token->value[0] == E_SPIRAL_SHELL) { //grape consumeToken(); const Token *variable = consumeToken(VARIABLE); Type t = Type::parseAndFetchType(Type(eclass), AllowGenericTypeVariables, package, nullptr); genericArgumentConstraints.push_back(t); Type rType(TT_LOCAL_REFERENCE, false); rType.reference = genericArgumentVariables.size(); if (genericArgumentVariables.count(variable->value)) { compilerError(variable, "A generic argument variable with the same name is already in use."); } genericArgumentVariables.insert(std::map<EmojicodeString, Type>::value_type(variable->value, rType)); } }
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); } } } }
static const Token* until(EmojicodeChar end, EmojicodeChar deeper, int *deep) { const Token *token = consumeToken(); if (token == nullptr) { compilerError(nullptr, "Unexpected end of program."); } if (token->type != IDENTIFIER) { return token; } if(token->value[0] == deeper){ (*deep)++; } else if(token->value[0] == end){ if (*deep == 0){ return nullptr; } (*deep)--; } return token; }
Package* Package::loadPackage(const char *name, EmojicodeChar ns, const Token *errorToken) { Package *package = findPackage(name); if (package) { if (!package->finishedLoading()) { compilerError(errorToken, "Circular dependency detected: %s tried to load a package which intiatiated %sās own loading.", name, name); } } else { char *path; asprintf(&path, packageDirectory "%s/header.emojic", name); package = new Package(name); if (strcmp("s", name) != 0) { package->loadPackage("s", globalNamespace, errorToken); } package->parse(path, errorToken); } package->loadInto(this, ns, errorToken); return package; }
void if1ld(charStarQueue** if1Files, char* mono, char* bindir, int warning, int profile, int forFortran, int forC, int separateCompilation, charStarQueue** entries, charStarQueue** entriesForC, charStarQueue** entriesForFORTRAN, charStarQueue** reductionFunctions, char* QStamps ) { char loader[MAXPATHLEN]; charStarQueue* argv = 0; char* entry = 0; sprintf(loader,"%s/if1ld",bindir); enqueue(&argv,loader); enqueue(&argv,"-o"); enqueue(&argv,mono); if ( forFortran ) { enqueue(&argv,"-F"); } else if ( forC ) { enqueue(&argv,"-C"); } else { /* enqueue(&argv,"-S"); */ } if ( !warning ) enqueue(&argv,"-w"); if ( profile ) enqueue(&argv,"-W"); if ( forFortran ) enqueue(&argv,"-F"); if ( forC ) enqueue(&argv,"-C"); if ( separateCompilation ) enqueue(&argv,"-S"); while(entries && *entries) { entry = dequeue(entries); enqueue(&argv,"-e"); enqueue(&argv,entry); } while(entriesForC && *entriesForC) { entry = dequeue(entriesForC); enqueue(&argv,"-c"); enqueue(&argv,entry); } while(entriesForFORTRAN && *entriesForFORTRAN) { entry = dequeue(entriesForC); enqueue(&argv,"-f"); enqueue(&argv,entry); } while(reductionFunctions && *reductionFunctions) { entry = dequeue(reductionFunctions); enqueue(&argv,"-r"); enqueue(&argv,entry); } enqueue(&argv,QStamps); while(if1Files && *if1Files) { entry = dequeue(if1Files); enqueue(&argv,entry); } if ( Submit(&argv) != 0 ) { compilerError("if1 loader failure"); } }
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; } }
void analyzeClassesAndWrite(FILE *fout){ Writer writer(fout); stringPool.push_back(new Token()); writer.writeByte(ByteCodeSpecificationVersion); //Decide which classes inherit initializers, if they agree to protocols, and assign virtual table indexes before we analyze the classes! for (auto eclass : classes) { //decide whether this eclass is eligible for initializer inheritance if(eclass->instanceVariables.size() == 0 && eclass->initializerList.size() == 0){ eclass->inheritsContructors = true; } if(eclass->superclass){ eclass->nextClassMethodVti = eclass->superclass->nextClassMethodVti; eclass->nextInitializerVti = eclass->inheritsContructors ? eclass->superclass->nextInitializerVti : 0; eclass->nextMethodVti = eclass->superclass->nextMethodVti; } else { eclass->nextClassMethodVti = 0; eclass->nextInitializerVti = 0; eclass->nextMethodVti = 0; } Type classType = Type(eclass); for(auto method : eclass->methodList){ Method *superMethod = eclass->superclass->getMethod(method->name); method->checkOverride(superMethod); if (superMethod){ method->checkPromises(superMethod, "super method", classType); method->vti = superMethod->vti; } else { method->vti = eclass->nextMethodVti++; } } for(auto clMethod : eclass->classMethodList){ ClassMethod *superMethod = eclass->superclass->getClassMethod(clMethod->name); clMethod->checkOverride(superMethod); if (superMethod){ clMethod->checkPromises(superMethod, "super classmethod", classType); clMethod->vti = superMethod->vti; } else { clMethod->vti = eclass->nextClassMethodVti++; } } for(auto initializer : eclass->initializerList){ //TODO: heavily incorrect Initializer *superConst = eclass->superclass->getInitializer(initializer->name); initializer->checkOverride(superConst); if (superConst){ initializer->checkPromises(superConst, "super classmethod", classType); //if a eclass has a initializer it does not inherit other initializers, therefore inheriting the VTI could have fatal consequences } initializer->vti = eclass->nextInitializerVti++; } } writer.writeUInt16(classes.size()); uint8_t pkgCount = (uint8_t)packages.size(); //must be s and _ if(pkgCount == 2){ pkgCount = 1; } if(pkgCount > 253){ compilerError(nullptr, "You exceeded the maximum of 253 packages."); } writer.writeByte(pkgCount); size_t pkgI = 0; Package *pkg = nullptr; Class *eclass; for (size_t i = 0; eclass = classes[i], i < classes.size(); i++) { if((pkg != eclass->package && pkgCount > 1) || !pkg){ //pkgCount > 1: Ignore the second s if (i > 0){ writer.writeByte(0); } pkg = eclass->package; Package *pkg = packages[pkgI++]; uint16_t l = strlen(pkg->name) + 1; writer.writeUInt16(l); writer.writeBytes(pkg->name, l); writer.writeUInt16(pkg->version.major); writer.writeUInt16(pkg->version.minor); writer.writeByte(pkg->requiresNativeBinary ? 1 : 0); } else if (i > 0){ writer.writeByte(1); } analyzeClass(Type(eclass), writer); } writer.writeByte(0); writer.writeUInt16(stringPool.size()); for (auto token : stringPool) { writer.writeUInt16(token->value.size()); for (auto c : token->value) { writer.writeEmojicodeChar(c); } } writer.writeUInt16(startingFlag.eclass->index); writer.writeUInt16(startingFlag.eclass->getClassMethod(E_CHEQUERED_FLAG)->vti); }
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); } }
void Method::setGenericParam() { m_genericParam = popGenericNameList(); if(m_genericParam != NULL && getGenre() == EGENRE::_DELEGATE) { compilerError(ERR_NOT_SUPPORTED_YET, "Generic delegates are not supported yet"); } }