/** * 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(); } }