Java tutorial
/* * Copyright 2010 Pablo Arrighi, Alex Concha, Miguel Lezama for version 1. * Copyright 2013 Pablo Arrighi, Miguel Lezama, Kevin Mazet for version 2. * * This file is part of GOOL. * * GOOL is free software: you can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation, version 3. * * GOOL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License along with GOOL, * in the file COPYING.txt. If not, see <http://www.gnu.org/licenses/>. */ package gool.parser.java; import gool.ParseGOOL; import gool.Settings; import gool.ast.core.ClassDef; import gool.generator.GoolGeneratorController; import gool.generator.common.Platform; import gool.recognizer.java.JavaRecognizer; import java.io.File; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import logger.Log; import org.apache.commons.lang.StringUtils; import com.sun.source.tree.CompilationUnitTree; import com.sun.source.util.JavacTask; import com.sun.source.util.Trees; import gool.executor.ExecutorHelper; /** * This class parses concrete Java into abstract GOOL. For this purpose it * relies on Sun's Java parser. */ public class JavaParser extends ParseGOOL { /** * Parsing concrete Java into abstract GOOL is done in three steps. - We * call Sun's java parser to produce abstract Java; - We visit abstract Java * with the JavaRecognizer to produce abstract GOOL; - We annotate the * abstract GOOL so that it carries the Target language. * * @param defaultPlatform * : specifies the Target language of the code generation that * will later be applied to the abstract GOOL, once this Java * parsing is performed. * @param compilationUnits * : An Iterable of JavaFileObject, which are Sun's java parser's * representation of the files to be parsed. * @param dependencies * : specifies imported libraries * @param visitor * : this is the class that transforms Sun's abstract java, into * abstract GOOL, i.e. the JavaRecognizer. * @return a list of classdefs, i.e. of abstract GOOL classes. * @throws Exception */ public static Collection<ClassDef> parseGool(Platform defaultPlatform, Iterable<? extends JavaFileObject> compilationUnits, List<File> dependencies, JavaRecognizer visitor) throws Exception { if (visitor == null) { throw new IllegalArgumentException("The gool visitor is null."); } /** * concreteJavaToConcretePlatform We will now setup the options to Sun's * java compiler This requires working out the dependencies */ // convert dependencies into a list of file paths to reach them List<String> stringDependencies = new ArrayList<String>(); if (dependencies != null && !dependencies.isEmpty()) { for (File file : dependencies) { stringDependencies.add(file.getAbsolutePath()); } } // further, add the GOOL library as a dependency // so that the program can use gool.imports.java stringDependencies.add(Settings.get("gool_library").toString()); // with the dependencies all set, we can make up the options List<String> options = Arrays.asList("-classpath", StringUtils.join(stringDependencies, File.pathSeparator)); /** * We now parse using Sun's java compiler */ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); JavacTask task = (JavacTask) compiler.getTask(null, null, null, options, null, compilationUnits); Iterable<? extends CompilationUnitTree> asts = task.parse(); visitor.setTypes(task.getTypes()); /** * We now analyze using Sun's java compiler so as to get a Java abstract * type tree. */ task.analyze(); Trees typetrees = Trees.instance(task); /** * We now prepare the JavaRecognizer for conversion of abstract Java to * abstract GOOL. */ // The visitor needs to know what the Target language is // Because it will annotate the abstract GOOL with this information. visitor.setDefaultPlatform(defaultPlatform); GoolGeneratorController.setCodeGenerator(defaultPlatform.getCodePrinter().getCodeGenerator()); // The visitor might need Sun's analyzed Java abstract type tree. visitor.setTrees(typetrees); /** * We launch the JavaRecognizer against each abstract Java AST */ for (CompilationUnitTree ast : asts) { visitor.setCurrentCompilationUnit(ast); visitor.scan(); } /** * Register each abstract GOOL class, so that they can see each other * and therefore represent valid types */ for (ClassDef classDef : visitor.getGoolClasses()) { classDef.getPlatform().registerCustomDependency(classDef.toString(), classDef); } return visitor.getGoolClasses(); } /** * Initially, call the parser with input files. */ public Collection<ClassDef> parseGool(Platform defaultPlatform, Collection<? extends File> inputFiles) throws Exception { return parseGool(defaultPlatform, ExecutorHelper.getJavaFileObjects(inputFiles)); } /** * Then, call the parser with no dependency yet, and with the * JavaRecognizer. */ public Collection<ClassDef> parseGool(Platform defaultPlatform, Iterable<? extends JavaFileObject> compilationUnits) throws Exception { return parseGool(defaultPlatform, compilationUnits, null, new JavaRecognizer()); } /** * if the parser is called on a directory, wrap it into a compilation unit, * and call the parser on that file. */ public Collection<ClassDef> parseGoolFiles(Platform defaultPlatform, List<File> dirs) throws Exception { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(dirs); return parseGool(defaultPlatform, compilationUnits); } /** * If the parser is called on an input string, wrap it into a compilation * unit, and call the parser on that file. */ public Collection<ClassDef> parseGool(Platform defaultPlatform, // String input) throws Exception { ArrayList<JavaFileObject> compilationUnits = new ArrayList<JavaFileObject>(); compilationUnits.add(new MyFileObject(input, "Random.java")); Log.i(input); return parseGool(defaultPlatform, compilationUnits); } /** * Sun's java parser takes his inputs as compilation units, which themselves * are the source files loaded into objects called SimpleJavaFileObject * Those objects have a name and: - a kind to say that they are source * files, - a content, retrieved by getCharContent. When we wrap a string * input into a file, we create directly such a SimpleJavaFileObject; with * getCharContent overriden to yield that input. */ static class MyFileObject extends SimpleJavaFileObject { private String input; public MyFileObject(String input, String name) { super(URI.create(name), JavaFileObject.Kind.SOURCE); this.input = input; } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return input; } } }