/** * 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; } }
/** * compile the project passed as parameter to the constructor. The basic packages of Cyan, stored * in project <code>cyanLangPackageProject</code>, are added to the project. Currently there is * only one basic package of the language: "cyan.lang". This should be included in every * compilation. * * @return <code>false</code> in error */ public boolean compile(HashSet<saci.CompilationInstruction> compInstSet) { Compiler compiler; try { // list of non-generic prototypes of the programc nonGenericCompilationUnitList = new ArrayList<CompilationUnit>(); // list of generic prototypes of the program ArrayList<CompilationUnit> genericCompilationUnitList = new ArrayList<CompilationUnit>(); /* separates the compilation units (source files) that have generic prototypes from those that don´t. A prototype whose file has a digit after '(' is a generic prototype. For example, Proto(1)(1).cyan has a generic prototype Proto<T><R>. And file MyData<main.Person><Int> is put in file MyData(main.Person)(Int).cyan. */ for (CompilationUnit compilationUnit : program.getCompilationUnitList()) { /* // if the file name has a '(' character followed by a digit, then it is a // generic prototype. Note that "Stack(Int).cyan" contains prototype "Stack<Int>" // which is not considered generic * */ String filename = compilationUnit.getFilename(); boolean foundDigit = false; int ifn = 0; int sizeFilename = filename.length(); while (ifn < sizeFilename) { if (filename.charAt(ifn) == '(' && Character.isDigit(filename.charAt(ifn + 1))) { foundDigit = true; break; } ++ifn; } if (foundDigit) { compilationUnit.setHasGenericPrototype(true); genericCompilationUnitList.add(compilationUnit); } else nonGenericCompilationUnitList.add(compilationUnit); /* if ( indexOfLeftPar > 0 && Character.isDigit(compilationUnit.getFilename().charAt(indexOfLeftPar + 1)) ) genericCompilationUnitList.add(compilationUnit); else nonGenericCompilationUnitList.add(compilationUnit); */ } /** * delete all files from "tmp" directories. If a generic prototype is in a directory "D", the * Compiler creates the generic instantiations in "D\tmp". For example, if "Stack<T>" is in * directory "util", the Compiler creates prototypes "Stack<Int>" and "Stack<Person>" * (assuming the program uses "Stack<Int>" and "Stack<Person>") in directory "util\tmp". */ Set<String> pathCompilationUnitTable = new HashSet<String>(); for (CompilationUnit c : genericCompilationUnitList) { pathCompilationUnitTable.add(c.getPackageCanonicalPath()); c.getCyanPackage().setHasGenericPrototype(true); } for (String path : pathCompilationUnitTable) { File dir = new File(path + NameServer.temporaryDirName); if (dir.exists()) for (File file : dir.listFiles()) file.delete(); } String dotExtension = "." + NameServer.cyanSourceFileExtension; boolean hasCompilationError = false; /** * first of all, parse all generic prototypes. This is not allowed in step 7 of the * compilation because all generic prototype instantiation should have been created before * that. */ if (this.compilationStep.compareTo(CompilationStep.step_7) < 0) { for (CompilationUnit compilationUnit : genericCompilationUnitList) { compiler = new Compiler(compilationUnit, compInstSet, compilationStep, project, null); compiler.parse(); /** * print the errors found in the generic prototypes and apply all actions to them. An * action is a small refactoring like insert a ";" */ if (compilationUnit.hasCompilationError()) { // compilationUnit.printErrorList(printWriter); hasCompilationError = true; } if (compilationUnit.getActionList().size() > 0) compilationUnit.doActionList(printWriter); } } /* if ( hasCompilationError ) return false; */ /* * in the first step of this while statement, all non-generic prototypes are compiled. * * In the second step of the while statement, the real prototypes created in the previous step * are compiled. They may instantiate new generic prototypes. For example, Stack<Int> may * declare a variable of type "Array<Int>". This new Cyan prototype should be created and * compiled. The process continues till no new prototypes should be created. */ CompilationUnit compilationUnit; int numCompilationUnitsAlreadyCompiled = 0; int sizeNonGenericCompilationUnitList; while (numCompilationUnitsAlreadyCompiled < nonGenericCompilationUnitList.size()) { sizeNonGenericCompilationUnitList = nonGenericCompilationUnitList.size(); boolean thereWasErrors = false; // parse of all source files that were not yet parsed. That may include some // generic prototypes that were instantiated in the previous round of the above // while statement. for (int i = numCompilationUnitsAlreadyCompiled; i < sizeNonGenericCompilationUnitList; i++) { compilationUnit = nonGenericCompilationUnitList.get(i); // System.out.println("cc: " + compilationUnit.getFilename()); compiler = new Compiler(compilationUnit, compInstSet, compilationStep, project, null); compiler.parse(); // if ( ! compilationUnit.hasCompilationError() ) { // } if (compilationUnit.hasCompilationError()) { thereWasErrors = true; // compilationUnit.printErrorList(printWriter); } else if (compInstSet.contains(CompilationInstruction.createPrototypesForInterfaces) && compilationUnit.getPrototypeIsNotGeneric() && compilationUnit.getPublicPrototype() instanceof InterfaceDec) { // if public program unit is an interface, create ProtoInterface CompilationUnit newCompilationUnit = compilationUnit.createProtoInterface(); if (newCompilationUnit == null) { if (compilationUnit.hasCompilationError()) { thereWasErrors = true; compilationUnit.printErrorList(printWriter); } } else { CyanPackage thisCyanPackage = compilationUnit.getCyanPackage(); thisCyanPackage.addCompilationUnit(newCompilationUnit); newCompilationUnit.setCyanPackage(thisCyanPackage); nonGenericCompilationUnitList.add(newCompilationUnit); String name = newCompilationUnit.getFilename(); int indexDotCyan = name.indexOf(dotExtension); if (indexDotCyan > 0) name = name.substring(0, indexDotCyan); program.addCompilationUnit(newCompilationUnit); if (nameSet.contains(newCompilationUnit.getFilename())) System.out.println("error: " + newCompilationUnit.getFilename()); else nameSet.add(newCompilationUnit.getFilename()); } } // if there was not any errors and there is a list of actions ... /*if ( compilationUnit.getActionList().size() > 0 ) compilationUnit.doActionList(printWriter); compilationUnit.clearErrorsActions(); */ } if (thereWasErrors) { return false; } numCompilationUnitsAlreadyCompiled = sizeNonGenericCompilationUnitList; } } catch (Exception e) { System.out.println( "Internal error at CompilerManager::compile(). e = " + e.getClass().getName()); e.printStackTrace(); return false; } project.printErrorList(printWriter); return true; }
/** * 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(); } }