Java tutorial
/******************************************************************************* * Copyright (C) 2003-2012 Bob Foster. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * * Bob Foster, initial API and implementation. *******************************************************************************/ package org.genantics.maven; import java.io.*; import java.util.ArrayList; import java.util.List; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.logging.Log; import org.genantics.peggen.Node; import org.genantics.peggen.Parser; import org.genantics.peggen.SimplePegGenerator; /** * Generates files based on grammar files with Antlr tool. * * This implementation ignores whatever project settings might be in * effect, but allows the user to configure directories. * * @goal generate * @phase generate-sources * @requiresDependencyResolution compile * @author Bob Foster * @version 1.0 */ public class PegGenMojo extends AbstractMojo { /** * @parameter default-value="target/generated-sources/peggen"; */ private String outputDirectory; /** * @parameter default-value="src/main/peggen"; */ private String sourceDirectory; /** * @parameter default-value="peg"; */ private String grammarExtension; private String pegDirName; /** for testing **/ private String projectPath; public boolean initForTest(File projectDir) { try { // test harness does not initialize parameters! projectPath = projectDir.getCanonicalPath(); if (!projectPath.endsWith("/")) projectPath += "/"; outputDirectory = "target/generated-sources/peggen"; sourceDirectory = "src/main/peggen"; grammarExtension = "peg"; return true; } catch (IOException e) { return false; } } public void execute() throws MojoExecutionException { // NB: This could be more compactly written using PegGen, // but calling the parser and generator separately // allows better debugging. try { Log log = getLog(); // FIXME - what is the right way to do this? File file = projectPath != null ? new File(projectPath) : new File("."); // For debugging String canon = file.getCanonicalPath(); if (!grammarExtension.startsWith(".")) grammarExtension = "." + grammarExtension; pegDirName = sourceDirectory; int slash = sourceDirectory.lastIndexOf('/'); if (slash < 0) slash = sourceDirectory.lastIndexOf(File.separatorChar); if (slash >= 0) pegDirName = sourceDirectory.substring(slash + 1); locateGrammars(file); if (grammars.isEmpty()) { log.info("There are no grammars in " + sourceDirectory); return; } for (Grammar grammar : grammars) { char[] buf = new char[(int) grammar.file.length()]; Reader reader = new FileReader(grammar.file); try { reader.read(buf); } finally { reader.close(); } Parser parser = new Parser(); Node[] nodes = parser.parseGrammar(buf, 0, buf.length); if (nodes == null || nodes.length == 0) { log.error("Parsing " + grammar.file.getCanonicalPath()); List list = parser.getErrors(); if (list != null) { for (Object err : list) { log.error(err.toString()); } } throw new MojoExecutionException("Parse errors"); } File target = new File(file, outputDirectory); if (!target.exists()) { if (!target.mkdirs()) { log.error("Can't create " + outputDirectory); return; } } StringBuilder sb = new StringBuilder(); collectRelativePath(grammar.file, sb); String relativePath = sb.toString(); File outFile = new File(target, relativePath); File outDir = outFile.getParentFile(); if (!outDir.exists()) { if (!outDir.mkdirs()) { log.error("Can't create output directory " + outDir.getCanonicalPath()); return; } } int dirEnd = relativePath.lastIndexOf('/'); String pkg = dirEnd < 0 ? "" : relativePath.substring(0, dirEnd).replace('/', '.'); PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(outFile))); String className = outFile.getName(); // extension is always .java className = className.substring(0, className.length() - ".java".length()); try { SimplePegGenerator gen = new SimplePegGenerator(); gen.generate(nodes[0], buf, writer, pkg, className, null, " "); } finally { writer.close(); } log.info("Generated " + outFile.getCanonicalPath()); } } catch (IOException e) { throw new MojoExecutionException("", e); } } private void collectRelativePath(File file, StringBuilder sb) { String name = file.getName(); if (!pegDirName.equals(name)) { collectRelativePath(file.getParentFile(), sb); if (name.endsWith(grammarExtension)) { name = makeClassName(name) + ".java"; sb.append(name); } else { sb.append(name); sb.append('/'); } } } private String makeClassName(String name) { int dot = name.lastIndexOf('.'); if (dot < 0) dot = name.length(); boolean docaps = true; StringBuilder sb = new StringBuilder(); for (int i = 0; i < dot; i++) { char c = name.charAt(i); if (!Character.isJavaIdentifierPart(c)) docaps = true; else if (docaps) { sb.append(Character.toUpperCase(c)); docaps = false; } else sb.append(c); } return sb.toString(); } private static class Grammar { File file; Grammar(File file) { this.file = file; } } List<Grammar> grammars = new ArrayList<Grammar>(); private void locateGrammars(File file) throws IOException { File root = new File(file, sourceDirectory); if (!root.exists() || !root.isDirectory()) return; locateAll(root); } private void locateAll(File root) { File[] files = root.listFiles(); for (File file : files) { if (file.isDirectory()) locateAll(file); else if (file.getName().endsWith(grammarExtension)) grammars.add(new Grammar(file)); } } }