/** * 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; }
/** * @param args * @param stream * @param numChRead * @param outError * @param printWriter * @throws IOException */ private void compileProgram(File file, String filename, PrintWriter outError) { Program program; FileReader stream; int numChRead; try { stream = new FileReader(file); } catch (FileNotFoundException e) { String msg = "Something wrong: file does not exist anymore"; outError.println(msg); return; } // one more character for '\0' at the end that will be added by the // compiler char[] input = new char[(int) file.length() + 1]; try { numChRead = stream.read(input, 0, (int) file.length()); if (numChRead != file.length()) { outError.println("Read error"); stream.close(); return; } stream.close(); } catch (IOException e) { String msg = "Error reading file " + filename; outError.println(msg); try { stream.close(); } catch (IOException e1) { } return; } Compiler compiler = new Compiler(); program = null; // the generated code goes to a file and so are the errors program = compiler.compile(input, outError); callMetaobjects(filename, program, outError); if (!program.hasCompilationErrors()) { String outputFileName; int lastIndex; if ((lastIndex = filename.lastIndexOf('.')) == -1) lastIndex = filename.length(); outputFileName = filename.substring(0, lastIndex); if ((lastIndex = filename.lastIndexOf('\\')) != -1) outputFileName = filename.substring(lastIndex + 1); FileOutputStream outputStream; try { outputStream = new FileOutputStream(outputFileName + ".c"); } catch (IOException e) { String msg = "File " + outputFileName + " was not found"; outError.println(msg); return; } PrintWriter printWriter = new PrintWriter(outputStream); PW pw = new PW(); pw.set(printWriter); program.genC(pw); if (printWriter.checkError()) { outError.println("There was an error in the output"); } printWriter.close(); } }