/** * Create an instantiation of a generic prototype given by parameter gt * * @param gt * @param env * @return */ private CompilationUnit createGenericPrototypeInstantiation( ExprGenericPrototypeInstantiation gt, Env env) { CompilationUnit genericProto = null; /* if ( gt.getName().equals("generic02.gb.G1<X>") ) { System.out.println("generic02.gb.G1<X>"); gt.ifPrototypeReturnsNameWithPackageAndType(env); } */ String genSourceFileName = gt.getGenericSourceFileName(); String genSourceFileNameVaryingNumberOfParameters = gt.getGenericSourceFileNameWithVaryingNumberOfParameters(); // if ( gt.getRealTypeListList().size() > 1 ) // System.out.println("3"); boolean isInterface = false; if (NameServer.isPrototypeFromInterface(genSourceFileName)) { // int sizePrefix = NameServer.prefixProtoInterface.length(); isInterface = true; /* genSourceFileName = genSourceFileName.substring(sizePrefix); genSourceFileNameVaryingNumberOfParameters = genSourceFileNameVaryingNumberOfParameters.substring(sizePrefix); */ genSourceFileName = NameServer.prototypeFileNameFromInterfaceFileName(genSourceFileName); genSourceFileNameVaryingNumberOfParameters = NameServer.prototypeFileNameFromInterfaceFileName( genSourceFileNameVaryingNumberOfParameters); } // something like util.Stack if gt is "util.Stack<Int>" or // Stack if gt is Stack<Int> ExprIdentStar typeIdent = gt.getTypeIdent(); if (typeIdent.getIdentSymbolArray().size() == 1) { // no package preceding the generic prototype name as in "Stack<Int>" ProgramUnit pu = env.searchProgramUnitBySourceFileName(genSourceFileName, gt.getFirstSymbol(), false); if (pu != null) { genericProto = pu.getCompilationUnit(); ProgramUnit pu2 = env.searchProgramUnitBySourceFileName( genSourceFileNameVaryingNumberOfParameters, gt.getFirstSymbol(), false); if (pu2 != null) /* found both generic prototype and generic prototype with varying number of parameters * Example: found both Tuple<T> and Tuple<T+> */ env.error( gt.getFirstSymbol(), "Ambiguity in creating a real prototype from a generic prototype. There is both " + pu.getCompilationUnit().getPackageName() + "." + genSourceFileName + " and " + pu2.getCompilationUnit().getPackageName() + "." + genSourceFileNameVaryingNumberOfParameters, true); } if (genericProto == null) { pu = env.searchProgramUnitBySourceFileName( genSourceFileNameVaryingNumberOfParameters, gt.getFirstSymbol(), false); if (pu != null) genericProto = pu.getCompilationUnit(); } } else { // package preceding the generic prototype name as in "util.Stack<Int>" int i = 0; ArrayList<Symbol> symbolList = typeIdent.getIdentSymbolArray(); int sizeLessOne = symbolList.size() - 1; String packageName = ""; while (i < sizeLessOne) { packageName = packageName + symbolList.get(i).getSymbolString(); ++i; if (i < sizeLessOne) packageName += "."; } CyanPackage cyanPackage = env.getProject().searchPackage(packageName); if (cyanPackage == null) { env.error(typeIdent.getFirstSymbol(), "Package '" + packageName + "' was not found", true); return null; } // first searches for something like "Stack(1)" in package 'util' for (CompilationUnit cunit : cyanPackage.getCompilationUnitList()) { if (genSourceFileName.equals(cunit.getFileNameWithoutExtension())) { genericProto = cunit; break; } } CompilationUnit genericProto2 = null; // searches for a generic prototype with varying number of parameters // something like "Stack(1+)" for (CompilationUnit cunit : cyanPackage.getCompilationUnitList()) { if (genSourceFileNameVaryingNumberOfParameters.equals( cunit.getFileNameWithoutExtension())) { genericProto2 = cunit; break; } } if (genericProto != null && genericProto2 != null) { env.error( gt.getFirstSymbol(), "Ambiguity in creating a real prototype from a generic prototype. There is both " + genericProto.getPackageName() + "." + genSourceFileName + " and " + genericProto2.getPackageName() + "." + genSourceFileNameVaryingNumberOfParameters, true); } if (genericProto == null) genericProto = genericProto2; } // genericProto = nameGenProtoUnitTable.get(genSourceFileName); if (genericProto == null) { env.error( true, gt.getFirstSymbol(), "Prototype '" + gt.getName() + "' was not found", gt.getName(), ErrorKind.prototype_was_not_found_inside_method); /*gt.getProgramUnit().getCompilationUnit().error(null, "Internal error at CompilerManager::createInterfaceObjectFunctionAndArray: cannot create " + gt.getName()); */ return null; } else { /** * if there was no compilation error in "Stack(1).cyan", then create an instance of the * generic prototype */ if (isInterface) { gt.removeProtoPrefix(); } CompilationUnit newCompilationUnit = genericProto.createInstanceGenericPrototype(gt, env); CompilationUnit interCompilationUnit = null; /** * if the package for this generic prototype instantiation was not created before, create it * now. */ CyanPackage cyanPackage = genericProto.getCyanPackage(); cyanPackage.addCompilationUnit(newCompilationUnit); newCompilationUnit.setCyanPackage(cyanPackage); nonGenericCompilationUnitList.add(newCompilationUnit); if (nameSet.contains(newCompilationUnit.getFullFileNamePath())) { env.error(gt.getFirstSymbol(), "Internal error in CompilerManager"); gt.ifPrototypeReturnsNameWithPackageAndType(env); } else nameSet.add(newCompilationUnit.getFullFileNamePath()); program.addCompilationUnit(newCompilationUnit); newCompilationUnit.readSourceFile(); HashSet<saci.CompilationInstruction> compInstSet = new HashSet<>(); compInstSet.add(CompilationInstruction.dpa_actions); compInstSet.add(CompilationInstruction.pp_addCode); if (compilationStep.compareTo(CompilationStep.step_5) >= 0) compInstSet.add(CompilationInstruction.new_addCode); Compiler compiler = new Compiler(newCompilationUnit, compInstSet, compilationStep, project, null); compiler.parse(); if (newCompilationUnit.hasCompilationError()) { // newCompilationUnit.printErrorList(printWriter); env.setThereWasError(true); throw new CompileErrorException(); } else if (compInstSet.contains(CompilationInstruction.createPrototypesForInterfaces) && newCompilationUnit.getPrototypeIsNotGeneric() && newCompilationUnit.getPublicPrototype() instanceof InterfaceDec) { // if public program unit is an interface, create ProtoInterface interCompilationUnit = newCompilationUnit.createProtoInterface(); if (interCompilationUnit != null) { interCompilationUnit.setCyanPackage(cyanPackage); cyanPackage.addCompilationUnit(interCompilationUnit); newCompilationUnit.setCyanPackage(cyanPackage); nonGenericCompilationUnitList.add(interCompilationUnit); String nameInter = interCompilationUnit.getFilename(); if (nameInter.endsWith(NameServer.dotCyanSourceFileExtension)) nameInter = nameInter.substring( 0, nameInter.length() - NameServer.sizeCyanSourceFileExtensionPlusOne); // nameRealGenProtoUnitTable.put(nameInter, interCompilationUnit); program.addCompilationUnit(interCompilationUnit); interCompilationUnit.readSourceFile(); compiler = new Compiler(interCompilationUnit, compInstSet, compilationStep, project, null); compiler.parse(); if (interCompilationUnit.getActionList().size() > 0) interCompilationUnit.doActionList(printWriter); interCompilationUnit.clearErrorsActions(); } } // newCompilationUnit.clearErrorsActions(); if (isInterface) return interCompilationUnit; else return newCompilationUnit; } }
/** * Create a generic prototype from parameter gpi. The new prototype is compiled. If it is an * interface, the prototype Proto_IntefaceName is created too. Methods calcInterfaceTypes and * calcInternalTypes are called for both the prototype and its Proto_InterfaceName, if any. * * @param gpi * @param env * @return */ public static ProgramUnit createGenericPrototype(ExprGenericPrototypeInstantiation gpi, Env env) { saci.Tuple<String, Type> t = gpi.ifPrototypeReturnsNameWithPackageAndType(env); // t.f1 is the name of the prototype if (t != null && t.f2 != null) { /* * prototype has already been created before */ if (t.f2 instanceof ProgramUnit) { return (ProgramUnit) t.f2; } else { env.error( gpi.getFirstSymbol(), "Internal error: a type that is not a program unit is used to instantiate a generic prototype"); return null; } } else { /* * prototype has not been created. Create it. */ // if ( env.getCurrentMethod() != null && env.getCurrentMethod().getName().contains("run2") ) // gpi.ifPrototypeReturnsItsNameWithPackage(env); /* * first, create all prototypes that are real parameters to this generic prototype instantiation */ for (ArrayList<Expr> realTypeList : gpi.getRealTypeListList()) { for (Expr realType : realTypeList) { if (realType instanceof ExprGenericPrototypeInstantiation) { ExprGenericPrototypeInstantiation genRealType = (ExprGenericPrototypeInstantiation) realType; genRealType.setType(createGenericPrototype(genRealType, env)); // javaName = type.getJavaName(); genRealType.setJavaName(genRealType.getType().getJavaName()); } } } CompilationUnit compUnit = env.getProject().getCompilerManager().createGenericPrototypeInstantiation(gpi, env); Env newEnv = new Env(env.getProject()); /* * If a generic prototype is created when method calcInterfaceTypes of Program is being executed * (env.getProject().getProgram().getInCalcInterfaceTypes() returns true), it is not necessary * to call its method calcInterfaceTypes. It will be called in the loop of * method Program::calcInterfaceTypes. * If a generic prototype is created when method calcInternalTypes of Program is being executed, * method calcInterfaceTypes of this generic prototype should be called because the interface * of this prototype is necessary in methods calcInternalTypes. Method calcInternalTypes * of this newly created generic prototype will be called in the loop of * method Program::calcInternalTypes. * * calcInternalTypes cannot be called when a generic prototype is created when * the compiler is calling calcInterfaceTypes. If this is allowed, some calcInternalType * method could try to use the interface of some prototype P whose method calcInterfaceTypes * have not been called. */ if (!env.getProject().getProgram().getInCalcInterfaceTypes()) { compUnit.calcInterfaceTypes(newEnv); // compUnit.calcInternalTypes(newEnv); } CompilationUnit interfaceCompilationUnit = compUnit.getInterfaceCompilationUnit(); if (interfaceCompilationUnit != null) { newEnv = new Env(env.getProject()); if (!env.getProject().getProgram().getInCalcInterfaceTypes()) { interfaceCompilationUnit.calcInterfaceTypes(newEnv); } } /* * if the generic prototype was created from phase (4), included, onwards, then execute * the ati actions. A generic prototype instantiation can only change itself and * no other prototype can change it. */ if (env.getProject().getCompilerManager().getCompilationStep().ordinal() > CompilationStep.step_3.ordinal()) { apply_ati_ActionsToGenericPrototype(newEnv, compUnit); if (interfaceCompilationUnit != null) { apply_ati_ActionsToGenericPrototype(env, interfaceCompilationUnit); } } return compUnit.getPublicPrototype(); } }