http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/AntlrParserPluginFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/AntlrParserPluginFactory.java b/src/main/java/org/codehaus/groovy/antlr/AntlrParserPluginFactory.java new file mode 100644 index 0000000..91857ee --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/AntlrParserPluginFactory.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr; + +import org.codehaus.groovy.control.ParserPlugin; +import org.codehaus.groovy.control.ParserPluginFactory; + +/** + */ +public class AntlrParserPluginFactory extends ParserPluginFactory { + + public ParserPlugin createParserPlugin() { + return new AntlrParserPlugin(); + } +}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java b/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java new file mode 100644 index 0000000..6f5fc3e --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr; + +import org.codehaus.groovy.ast.ClassHelper; +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.FieldNode; +import org.codehaus.groovy.ast.GenericsType; +import org.codehaus.groovy.ast.InnerClassNode; +import org.codehaus.groovy.ast.MixinNode; +import org.codehaus.groovy.ast.expr.Expression; +import org.codehaus.groovy.ast.expr.ListExpression; +import org.objectweb.asm.Opcodes; + +public class EnumHelper { + private static final int FS = Opcodes.ACC_FINAL | Opcodes.ACC_STATIC; + private static final int PUBLIC_FS = Opcodes.ACC_PUBLIC | FS; + + public static ClassNode makeEnumNode(String name, int modifiers, ClassNode[] interfaces, ClassNode outerClass) { + modifiers = modifiers | Opcodes.ACC_FINAL | Opcodes.ACC_ENUM; + ClassNode enumClass; + if (outerClass==null) { + enumClass = new ClassNode(name,modifiers,null,interfaces,MixinNode.EMPTY_ARRAY); + } else { + name = outerClass.getName() + "$" + name; + modifiers |= Opcodes.ACC_STATIC; + enumClass = new InnerClassNode(outerClass,name,modifiers,null,interfaces,MixinNode.EMPTY_ARRAY); + } + + // set super class and generics info + // "enum X" -> class X extends Enum<X> + GenericsType gt = new GenericsType(enumClass); + ClassNode superClass = ClassHelper.makeWithoutCaching("java.lang.Enum"); + superClass.setGenericsTypes(new GenericsType[]{gt}); + enumClass.setSuperClass(superClass); + superClass.setRedirect(ClassHelper.Enum_Type); + + return enumClass; + } + + public static FieldNode addEnumConstant(ClassNode enumClass, String name, Expression init) { + int modifiers = PUBLIC_FS | Opcodes.ACC_ENUM; + if (init != null && !(init instanceof ListExpression)) { + ListExpression list = new ListExpression(); + list.addExpression(init); + init = list; + } + FieldNode fn = new FieldNode(name, modifiers, enumClass.getPlainNodeReference(), enumClass, init); + enumClass.addField(fn); + return fn; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/GroovySourceAST.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/GroovySourceAST.java b/src/main/java/org/codehaus/groovy/antlr/GroovySourceAST.java new file mode 100644 index 0000000..d256e73 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/GroovySourceAST.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr; + +import antlr.CommonAST; +import antlr.Token; +import antlr.collections.AST; + +import java.util.ArrayList; +import java.util.List; + +/** + * We have an AST subclass so we can track source information. + * Very odd that ANTLR doesn't do this by default. + * + * @author Mike Spille + * @author Jeremy Rayner <[email protected]> + */ +public class GroovySourceAST extends CommonAST implements Comparable, SourceInfo { + private int line; + private int col; + private int lineLast; + private int colLast; + private String snippet; + + public GroovySourceAST() { + } + + public GroovySourceAST(Token t) { + super(t); + } + + public void initialize(AST ast) { + super.initialize(ast); + line = ast.getLine(); + col = ast.getColumn(); + if (ast instanceof GroovySourceAST) { + GroovySourceAST node = (GroovySourceAST)ast; + lineLast = node.getLineLast(); + colLast = node.getColumnLast(); + } + } + + public void initialize(Token t) { + super.initialize(t); + line = t.getLine(); + col = t.getColumn(); + if (t instanceof SourceInfo) { + SourceInfo info = (SourceInfo) t; + lineLast = info.getLineLast(); + colLast = info.getColumnLast(); + } + } + + public void setLast(Token last) { + lineLast = last.getLine(); + colLast = last.getColumn(); + } + + public int getLineLast() { + return lineLast; + } + + public void setLineLast(int lineLast) { + this.lineLast = lineLast; + } + + public int getColumnLast() { + return colLast; + } + + public void setColumnLast(int colLast) { + this.colLast = colLast; + } + + public void setLine(int line) { + this.line = line; + } + + public int getLine() { + return (line); + } + + public void setColumn(int column) { + this.col = column; + } + + public int getColumn() { + return (col); + } + + public void setSnippet(String snippet) { + this.snippet = snippet; + } + + public String getSnippet() { + return snippet; + } + + public int compareTo(Object object) { + if (object == null) { + return 0; + } + if (!(object instanceof AST)) { + return 0; + } + AST that = (AST) object; + + // todo - possibly check for line/col with values of 0 or less... + + if (this.getLine() < that.getLine()) { + return -1; + } + if (this.getLine() > that.getLine()) { + return 1; + } + + if (this.getColumn() < that.getColumn()) { + return -1; + } + if (this.getColumn() > that.getColumn()) { + return 1; + } + + return 0; + } + + public GroovySourceAST childAt(int position) { + List list = new ArrayList(); + AST child = this.getFirstChild(); + while (child != null) { + list.add(child); + child = child.getNextSibling(); + } + try { + return (GroovySourceAST)list.get(position); + } catch (IndexOutOfBoundsException e) { + return null; + } + } + + public GroovySourceAST childOfType(int type) { + AST child = this.getFirstChild(); + while (child != null) { + if (child.getType() == type) { return (GroovySourceAST)child; } + child = child.getNextSibling(); + } + return null; + } + + public List<GroovySourceAST> childrenOfType(int type) { + List<GroovySourceAST> result = new ArrayList<GroovySourceAST>(); + AST child = this.getFirstChild(); + while (child != null) { + if (child.getType() == type) { result.add((GroovySourceAST) child); } + child = child.getNextSibling(); + } + return result; + } + +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/GroovySourceToken.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/GroovySourceToken.java b/src/main/java/org/codehaus/groovy/antlr/GroovySourceToken.java new file mode 100644 index 0000000..38ffba0 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/GroovySourceToken.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr; + +import antlr.Token; + +/** + * This is a Token sub class to track line information + * + * @author Jochen Theodorou + */ +public class GroovySourceToken extends Token implements SourceInfo{ + protected int line; + protected String text = ""; + protected int col; + protected int lineLast; + protected int colLast; + + + /** + * Constructor using a token type + * + * @param t the type + */ + public GroovySourceToken(int t) { + super(t); + } + + public int getLine() { + return line; + } + + /** + * get the source token text + * @return the source token text + */ + public String getText() { + return text; + } + + public void setLine(int l) { + line = l; + } + + /** + * set the source token text + * @param s the text + */ + public void setText(String s) { + text = s; + } + + public String toString() { + return + "[\"" + getText() + "\",<" + type + ">,"+ + "line=" + line + ",col=" + col + + ",lineLast=" + lineLast + ",colLast=" + colLast + + "]"; + } + + public int getColumn() { + return col; + } + + public void setColumn(int c) { + col = c; + } + + public int getLineLast() { + return lineLast; + } + + public void setLineLast(int lineLast) { + this.lineLast = lineLast; + } + + public int getColumnLast() { + return colLast; + } + + public void setColumnLast(int colLast) { + this.colLast = colLast; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/LexerFrame.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/LexerFrame.java b/src/main/java/org/codehaus/groovy/antlr/LexerFrame.java new file mode 100644 index 0000000..046fd17 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/LexerFrame.java @@ -0,0 +1,279 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr; + +import antlr.CharScanner; +import antlr.Token; +import org.codehaus.groovy.antlr.java.JavaLexer; +import org.codehaus.groovy.antlr.java.JavaTokenTypes; +import org.codehaus.groovy.antlr.parser.GroovyLexer; +import org.codehaus.groovy.antlr.parser.GroovyTokenTypes; +import org.codehaus.groovy.runtime.IOGroovyMethods; +import org.codehaus.groovy.runtime.ResourceGroovyMethods; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.text.BadLocationException; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.FileReader; +import java.io.Reader; +import java.io.StringReader; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.Hashtable; + +/** + * Swing application to graphically display the tokens produced by the lexer. + */ +public class LexerFrame extends JFrame implements ActionListener { + private final JSplitPane jSplitPane1 = new JSplitPane(); + private final JScrollPane jScrollPane1 = new JScrollPane(); + private final JScrollPane jScrollPane2 = new JScrollPane(); + private final JTextPane tokenPane = new HScrollableTextPane(); + private final JButton jbutton = new JButton("open"); + private final JPanel mainPanel = new JPanel(new BorderLayout()); + private final JTextArea scriptPane = new JTextArea(); + private final Class lexerClass; + private final Hashtable tokens = new Hashtable(); + + /** + * Constructor used when invoking as a standalone application + * + * @param lexerClass the lexer class to use + * @param tokenTypesClass the lexer token types class + */ + public LexerFrame(Class lexerClass, Class tokenTypesClass) { + this(lexerClass, tokenTypesClass, null); + } + + /** + * Constructor used when invoking for a specific file + * + * @param lexerClass the lexer class to use + * @param tokenTypesClass the lexer token types class + */ + public LexerFrame(Class lexerClass, Class tokenTypesClass, Reader reader) { + super("Token Steam Viewer"); + this.lexerClass = lexerClass; + try { + jbInit(reader); + setSize(500, 500); + listTokens(tokenTypesClass); + + if (reader == null) { + final JPopupMenu popup = new JPopupMenu(); + popup.add(loadFileAction); + jbutton.setSize(30, 30); + jbutton.addMouseListener(new MouseAdapter() { + public void mouseReleased(MouseEvent e) { + //if(e.isPopupTrigger()) + popup.show(scriptPane, e.getX(), e.getY()); + } + }); + } else { + safeScanScript(reader); + } + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Creates a Groovy language LexerFrame for the given script text + * + * @param scriptText the Groovy source file to parse/render + * @return the new frame rending the parsed tokens + */ + public static LexerFrame groovyScriptFactory(String scriptText) { + return new LexerFrame(GroovyLexer.class, GroovyTokenTypes.class, new StringReader(scriptText)); + } + + private void listTokens(Class tokenTypes) throws Exception { + for (Field field : tokenTypes.getDeclaredFields()) { + tokens.put(field.get(null), field.getName()); + } + } + + public void actionPerformed(ActionEvent ae) { + Token token = (Token) ((JComponent) ae.getSource()).getClientProperty("token"); + if (token.getType() == Token.EOF_TYPE) { + scriptPane.select(0, 0); + return; + } + try { + int start = scriptPane.getLineStartOffset(token.getLine() - 1) + token.getColumn() - 1; + scriptPane.select(start, start + token.getText().length()); + scriptPane.requestFocus(); + } catch (BadLocationException ex) { + // IGNORE + } + } + + private final Action loadFileAction = new AbstractAction("Open File...") { + public void actionPerformed(ActionEvent ae) { + final JFileChooser jfc = new JFileChooser(); + final int response = jfc.showOpenDialog(LexerFrame.this); + if (response != JFileChooser.APPROVE_OPTION) { + return; + } + safeScanScript(jfc.getSelectedFile()); + } + }; + + private void safeScanScript(File file) { + try { + scanScript(new StringReader(ResourceGroovyMethods.getText(file))); + } catch (final Exception ex) { + ex.printStackTrace(); + } + } + + private void safeScanScript(Reader reader) { + try { + scanScript(reader instanceof StringReader ? (StringReader) reader : new StringReader(IOGroovyMethods.getText(reader))); + } catch (final Exception ex) { + ex.printStackTrace(); + } + } + + private void scanScript(final StringReader reader) throws Exception { + scriptPane.read(reader, null); + reader.reset(); + + // create lexer + final Constructor constructor = lexerClass.getConstructor(Reader.class); + final CharScanner lexer = (CharScanner) constructor.newInstance(reader); + + tokenPane.setEditable(true); + tokenPane.setText(""); + + int line = 1; + final ButtonGroup bg = new ButtonGroup(); + Token token; + + while (true) { + token = lexer.nextToken(); + JToggleButton tokenButton = new JToggleButton((String) tokens.get(Integer.valueOf(token.getType()))); + bg.add(tokenButton); + tokenButton.addActionListener(this); + tokenButton.setToolTipText(token.getText()); + tokenButton.putClientProperty("token", token); + tokenButton.setMargin(new Insets(0, 1, 0, 1)); + tokenButton.setFocusPainted(false); + if (token.getLine() > line) { + tokenPane.getDocument().insertString(tokenPane.getDocument().getLength(), "\n", null); + line = token.getLine(); + } + insertComponent(tokenButton); + if (token.getType() == Token.EOF_TYPE) { + break; + } + } + + tokenPane.setEditable(false); + tokenPane.setCaretPosition(0); + reader.close(); + } + + private void insertComponent(JComponent comp) { + try { + tokenPane.getDocument().insertString(tokenPane.getDocument().getLength(), " ", null); + } catch (BadLocationException ex1) { + // Ignore + } + try { + tokenPane.setCaretPosition(tokenPane.getDocument().getLength() - 1); + } catch (Exception ex) { + tokenPane.setCaretPosition(0); + } + tokenPane.insertComponent(comp); + } + + private void jbInit(Reader reader) throws Exception { + final Border border = BorderFactory.createEmptyBorder(); + jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); + tokenPane.setEditable(false); + tokenPane.setText(""); + scriptPane.setFont(new java.awt.Font("DialogInput", 0, 12)); + scriptPane.setEditable(false); + scriptPane.setMargin(new Insets(5, 5, 5, 5)); + scriptPane.setText(""); + jScrollPane1.setBorder(border); + jScrollPane2.setBorder(border); + jSplitPane1.setMinimumSize(new Dimension(800, 600)); + mainPanel.add(jSplitPane1, BorderLayout.CENTER); + if (reader == null) { + mainPanel.add(jbutton, BorderLayout.NORTH); + } + this.getContentPane().add(mainPanel); + jSplitPane1.add(jScrollPane1, JSplitPane.LEFT); + jScrollPane1.getViewport().add(tokenPane, null); + jSplitPane1.add(jScrollPane2, JSplitPane.RIGHT); + jScrollPane2.getViewport().add(scriptPane, null); + + jScrollPane1.setColumnHeaderView(new JLabel(" Token Stream:")); + jScrollPane2.setColumnHeaderView(new JLabel(" Input Script:")); + jSplitPane1.setResizeWeight(0.5); + } + + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception ignore) { + // Ignore + } + LexerFrame lexerFrame = null; + if (args.length == 0) { + lexerFrame = new LexerFrame(GroovyLexer.class, GroovyTokenTypes.class); + } else if (args.length > 1) { + System.err.println("usage: java LexerFrame [filename.ext]"); + System.exit(1); + } else { + String filename = args[0]; + if (filename.endsWith(".java")) { + lexerFrame = new LexerFrame(JavaLexer.class, JavaTokenTypes.class, new FileReader(filename)); + } else { + lexerFrame = new LexerFrame(GroovyLexer.class, GroovyTokenTypes.class, new FileReader(filename)); + } + } + lexerFrame.setVisible(true); + } + + private static class HScrollableTextPane extends JTextPane { + @Override + public boolean getScrollableTracksViewportWidth() { + return (getSize().width < getParent().getSize().width); + } + + @Override + public void setSize(final Dimension d) { + if (d.width < getParent().getSize().width) { + d.width = getParent().getSize().width; + } + super.setSize(d); + } + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/LineColumn.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/LineColumn.java b/src/main/java/org/codehaus/groovy/antlr/LineColumn.java new file mode 100644 index 0000000..c7e11b6 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/LineColumn.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr; + +/** + * An object representing a line and column position + * + * @author <a href="mailto:[email protected]">Jeremy Rayner</a> + */ +public class LineColumn { + private int line; + private int column; + + public LineColumn(int line, int column) { + this.line = line; + this.column = column; + } + + public int getLine() { + return line; + } + + public int getColumn() { + return column; + } + + public boolean equals(Object that) { + if (this == that) return true; + if (that == null || getClass() != that.getClass()) return false; + + final LineColumn lineColumn = (LineColumn) that; + + if (column != lineColumn.column) return false; + if (line != lineColumn.line) return false; + + return true; + } + + public int hashCode() { + int result; + result = line; + result = 29 * result + column; + return result; + } + + public String toString() { + return "[" + line + "," + column + "]"; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/Main.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/Main.java b/src/main/java/org/codehaus/groovy/antlr/Main.java new file mode 100644 index 0000000..ae3bb5f --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/Main.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr; + +import antlr.ASTFactory; +import antlr.CommonAST; +import antlr.Token; +import antlr.collections.AST; +import antlr.debug.misc.ASTFrame; +import org.codehaus.groovy.antlr.parser.GroovyLexer; +import org.codehaus.groovy.antlr.parser.GroovyRecognizer; + +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.FileReader; + +class Main { + + static boolean whitespaceIncluded = false; + + static boolean showTree = false; + //static boolean xml = false; + static boolean verbose = false; + public static void main(String[] args) { + // Use a try/catch block for parser exceptions + try { + // if we have at least one command-line argument + if (args.length > 0 ) { + System.err.println("Parsing..."); + + // for each directory/file specified on the command line + for(int i=0; i< args.length;i++) { + if ( args[i].equals("-showtree") ) { + showTree = true; + } + //else if ( args[i].equals("-xml") ) { + // xml = true; + //} + else if ( args[i].equals("-verbose") ) { + verbose = true; + } + else if ( args[i].equals("-trace") ) { + GroovyRecognizer.tracing = true; + GroovyLexer.tracing = true; + } + else if ( args[i].equals("-traceParser") ) { + GroovyRecognizer.tracing = true; + } + else if ( args[i].equals("-traceLexer") ) { + GroovyLexer.tracing = true; + } + else if ( args[i].equals("-whitespaceIncluded") ) { + whitespaceIncluded = true; + } + else { + doFile(new File(args[i])); // parse it + } + } } + else + System.err.println("Usage: java -jar groovyc.jar [-showtree] [-verbose] [-trace{,Lexer,Parser}]"+ + "<directory or file name>"); + } + catch(Exception e) { + System.err.println("exception: "+e); + e.printStackTrace(System.err); // so we can get stack trace + } + } + + + // This method decides what action to take based on the type of + // file we are looking at + public static void doFile(File f) + throws Exception { + // If this is a directory, walk each file/dir in that directory + if (f.isDirectory()) { + String files[] = f.list(); + for(int i=0; i < files.length; i++) + doFile(new File(f, files[i])); + } + + // otherwise, if this is a groovy file, parse it! + else if (f.getName().endsWith(".groovy")) { + System.err.println(" --- "+f.getAbsolutePath()); + // parseFile(f.getName(), new FileInputStream(f)); + SourceBuffer sourceBuffer = new SourceBuffer(); + UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(new FileReader(f),sourceBuffer); + GroovyLexer lexer = new GroovyLexer(unicodeReader); + unicodeReader.setLexer(lexer); + parseFile(f.getName(),lexer,sourceBuffer); + } + } + + // Here's where we do the real work... + public static void parseFile(String f, GroovyLexer l, SourceBuffer sourceBuffer) + throws Exception { + try { + // Create a parser that reads from the scanner + GroovyRecognizer parser = GroovyRecognizer.make(l); + parser.setSourceBuffer(sourceBuffer); + parser.setFilename(f); + + if (whitespaceIncluded) { + GroovyLexer lexer = parser.getLexer(); + lexer.setWhitespaceIncluded(true); + while (true) { + Token t = lexer.nextToken(); + System.out.println(t); + if (t == null || t.getType() == Token.EOF_TYPE) break; + } + return; + } + + // start parsing at the compilationUnit rule + parser.compilationUnit(); + + System.out.println("parseFile "+f+" => "+parser.getAST()); + + // do something with the tree + doTreeAction(f, parser.getAST(), parser.getTokenNames()); + } + catch (Exception e) { + System.err.println("parser exception: "+e); + e.printStackTrace(); // so we can get stack trace + } + } + + public static void doTreeAction(String f, AST t, String[] tokenNames) { + if ( t==null ) return; + if ( showTree ) { + CommonAST.setVerboseStringConversion(true, tokenNames); + ASTFactory factory = new ASTFactory(); + AST r = factory.create(0,"AST ROOT"); + r.setFirstChild(t); + final ASTFrame frame = new ASTFrame("Groovy AST", r); + frame.setVisible(true); + frame.addWindowListener( + new WindowAdapter() { + public void windowClosing (WindowEvent e) { + frame.setVisible(false); // hide the Frame + frame.dispose(); + System.exit(0); + } + } + ); + if (verbose) System.out.println(t.toStringList()); + } + /*if ( xml ) { + ((CommonAST)t).setVerboseStringConversion(true, tokenNames); + ASTFactory factory = new ASTFactory(); + AST r = factory.create(0,"AST ROOT"); + r.setFirstChild(t); + XStream xstream = new XStream(); + xstream.alias("ast", CommonAST.class); + try { + xstream.toXML(r,new FileWriter(f + ".xml")); + System.out.println("Written AST to " + f + ".xml"); + } catch (Exception e) { + System.out.println("couldn't write to " + f + ".xml"); + e.printStackTrace(); + } + //if (verbose) System.out.println(t.toStringList()); + }*/ + /*@todo + GroovyTreeParser tparse = new GroovyTreeParser(); + try { + tparse.compilationUnit(t); + if (verbose) System.out.println("successful walk of result AST for "+f); + } + catch (RecognitionException e) { + System.err.println(e.getMessage()); + e.printStackTrace(); + } + @todo*/ + + } +} + http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/SourceBuffer.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/SourceBuffer.java b/src/main/java/org/codehaus/groovy/antlr/SourceBuffer.java new file mode 100644 index 0000000..6b45e50 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/SourceBuffer.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr; + +import java.util.ArrayList; +import java.util.List; + +/** + * A simple buffer that provides line/col access to chunks of source code + * held within itself. + * + * @author <a href="mailto:[email protected]">Jeremy Rayner</a> + */ +public class SourceBuffer { + private final List lines; + private StringBuffer current; + + public SourceBuffer() { + lines = new ArrayList(); + //lines.add(new StringBuffer()); // dummy row for position [0] in the List + + current = new StringBuffer(); + lines.add(current); + } + + /** + * Obtains a snippet of the source code within the bounds specified + * @param start (inclusive line/ inclusive column) + * @param end (inclusive line / exclusive column) + * @return specified snippet of source code as a String, or null if no source available + */ + public String getSnippet(LineColumn start, LineColumn end) { + // preconditions + if (start == null || end == null) { return null; } // no text to return + if (start.equals(end)) { return null; } // no text to return + if (lines.size() == 1 && current.length() == 0) { return null; } // buffer hasn't been filled yet + + // working variables + int startLine = start.getLine(); + int startColumn = start.getColumn(); + int endLine = end.getLine(); + int endColumn = end.getColumn(); + + // reset any out of bounds requests + if (startLine < 1) { startLine = 1;} + if (endLine < 1) { endLine = 1;} + if (startColumn < 1) { startColumn = 1;} + if (endColumn < 1) { endColumn = 1;} + if (startLine > lines.size()) { startLine = lines.size(); } + if (endLine > lines.size()) { endLine = lines.size(); } + + // obtain the snippet from the buffer within specified bounds + StringBuffer snippet = new StringBuffer(); + for (int i = startLine - 1; i < endLine;i++) { + String line = ((StringBuffer)lines.get(i)).toString(); + if (startLine == endLine) { + // reset any out of bounds requests (again) + if (startColumn > line.length()) { startColumn = line.length();} + if (startColumn < 1) { startColumn = 1;} + if (endColumn > line.length()) { endColumn = line.length() + 1;} + if (endColumn < 1) { endColumn = 1;} + if (endColumn < startColumn) { endColumn = startColumn;} + + line = line.substring(startColumn - 1, endColumn - 1); + } else { + if (i == startLine - 1) { + if (startColumn - 1 < line.length()) { + line = line.substring(startColumn - 1); + } + } + if (i == endLine - 1) { + if (endColumn - 1 < line.length()) { + line = line.substring(0,endColumn - 1); + } + } + } + snippet.append(line); + } + return snippet.toString(); + } + + /** + * Writes the specified character into the buffer + * @param c + */ + public void write(int c) { + if (c != -1) { + current.append((char)c); + } + if (c == '\n') { + current = new StringBuffer(); + lines.add(current); + } + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/SourceInfo.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/SourceInfo.java b/src/main/java/org/codehaus/groovy/antlr/SourceInfo.java new file mode 100644 index 0000000..90126f0 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/SourceInfo.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr; + +public interface SourceInfo { + /** + * get start line + * + * @return the starting line + */ + int getLine(); + + /** + * set start line + * + * @param l the line + */ + void setLine(int l); + + /** + * get starting column + * + * @return the starting column + */ + int getColumn(); + + /** + * set start column + * + * @param c the column + */ + void setColumn(int c); + + /** + * get ending line + * + * @return the ending line + */ + int getLineLast(); + + /** + * set ending line + * + * @param lineLast the line + */ + void setLineLast(int lineLast); + + /** + * get ending column + * + * @return the ending column + */ + int getColumnLast(); + + /** + * set ending column + * + * @param colLast the column + */ + void setColumnLast(int colLast); +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/UnicodeEscapingReader.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/UnicodeEscapingReader.java b/src/main/java/org/codehaus/groovy/antlr/UnicodeEscapingReader.java new file mode 100644 index 0000000..aef7e7a --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/UnicodeEscapingReader.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr; + +import antlr.CharScanner; +import antlr.Token; +import antlr.TokenStreamException; + +import java.io.IOException; +import java.io.Reader; + +/** + * Translates GLS-defined unicode escapes into characters. Throws an exception + * in the event of an invalid unicode escape being detected. + * <p> + * No attempt has been made to optimize this class for speed or space. + */ +public class UnicodeEscapingReader extends Reader { + + private final Reader reader; + private CharScanner lexer; + private boolean hasNextChar = false; + private int nextChar; + private final SourceBuffer sourceBuffer; + private int previousLine; + private int numUnicodeEscapesFound = 0; + private int numUnicodeEscapesFoundOnCurrentLine = 0; + + private static class DummyLexer extends CharScanner { + private final Token t = new Token(); + public Token nextToken() throws TokenStreamException { + return t; + } + @Override + public int getColumn() { + return 0; + } + @Override + public int getLine() { + return 0; + } + } + + /** + * Constructor. + * @param reader The reader that this reader will filter over. + */ + public UnicodeEscapingReader(Reader reader,SourceBuffer sourceBuffer) { + this.reader = reader; + this.sourceBuffer = sourceBuffer; + this.lexer = new DummyLexer(); + } + + /** + * Sets the lexer that is using this reader. Must be called before the + * lexer is used. + */ + public void setLexer(CharScanner lexer) { + this.lexer = lexer; + } + + /** + * Reads characters from the underlying reader. + * @see java.io.Reader#read(char[],int,int) + */ + public int read(char cbuf[], int off, int len) throws IOException { + int c = 0; + int count = 0; + while (count < len && (c = read())!= -1) { + cbuf[off + count] = (char) c; + count++; + } + return (count == 0 && c == -1) ? -1 : count; + } + + /** + * Gets the next character from the underlying reader, + * translating escapes as required. + * @see java.io.Reader#close() + */ + public int read() throws IOException { + if (hasNextChar) { + hasNextChar = false; + write(nextChar); + return nextChar; + } + + if (previousLine != lexer.getLine()) { + // new line, so reset unicode escapes + numUnicodeEscapesFoundOnCurrentLine = 0; + previousLine = lexer.getLine(); + } + + int c = reader.read(); + if (c != '\\') { + write(c); + return c; + } + + // Have one backslash, continue if next char is 'u' + c = reader.read(); + if (c != 'u') { + hasNextChar = true; + nextChar = c; + write('\\'); + return '\\'; + } + + // Swallow multiple 'u's + int numberOfUChars = 0; + do { + numberOfUChars++; + c = reader.read(); + } while (c == 'u'); + + // Get first hex digit + checkHexDigit(c); + StringBuilder charNum = new StringBuilder(); + charNum.append((char) c); + + // Must now be three more hex digits + for (int i = 0; i < 3; i++) { + c = reader.read(); + checkHexDigit(c); + charNum.append((char) c); + } + int rv = Integer.parseInt(charNum.toString(), 16); + write(rv); + + numUnicodeEscapesFound += 4 + numberOfUChars; + numUnicodeEscapesFoundOnCurrentLine += 4 + numberOfUChars; + + return rv; + } + private void write(int c) { + if (sourceBuffer != null) {sourceBuffer.write(c);} + } + /** + * Checks that the given character is indeed a hex digit. + */ + private void checkHexDigit(int c) throws IOException { + if (c >= '0' && c <= '9') { + return; + } + if (c >= 'a' && c <= 'f') { + return; + } + if (c >= 'A' && c <= 'F') { + return; + } + // Causes the invalid escape to be skipped + hasNextChar = true; + nextChar = c; + throw new IOException("Did not find four digit hex character code." + + " line: " + lexer.getLine() + " col:" + lexer.getColumn()); + } + + public int getUnescapedUnicodeColumnCount() { + return numUnicodeEscapesFoundOnCurrentLine; + } + + public int getUnescapedUnicodeOffsetCount() { + return numUnicodeEscapesFound; + } + + /** + * Closes this reader by calling close on the underlying reader. + * + * @see java.io.Reader#close() + */ + public void close() throws IOException { + reader.close(); + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/UnicodeLexerSharedInputState.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/UnicodeLexerSharedInputState.java b/src/main/java/org/codehaus/groovy/antlr/UnicodeLexerSharedInputState.java new file mode 100644 index 0000000..2e90b2e --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/UnicodeLexerSharedInputState.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr; + +import antlr.LexerSharedInputState; + +/** + * GRECLIPSE-805 Support for unicode escape sequences + * @author Andrew Eisenberg + */ +public class UnicodeLexerSharedInputState extends LexerSharedInputState { + private final UnicodeEscapingReader escapingReader; + + private int prevUnescape; + + public UnicodeLexerSharedInputState(UnicodeEscapingReader in) { + super(in); + escapingReader = in; + } + + @Override + public int getColumn() { + prevUnescape = escapingReader.getUnescapedUnicodeColumnCount(); + return super.getColumn() + prevUnescape; + } + + @Override + public int getTokenStartColumn() { + if (line == tokenStartLine) { + return super.getTokenStartColumn() + escapingReader.getUnescapedUnicodeColumnCount(); + } else { + return super.getTokenStartColumn() + prevUnescape; + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/java/Groovifier.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/java/Groovifier.java b/src/main/java/org/codehaus/groovy/antlr/java/Groovifier.java new file mode 100644 index 0000000..cc551fb --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/java/Groovifier.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr.java; + +import org.codehaus.groovy.antlr.GroovySourceAST; +import org.codehaus.groovy.antlr.parser.GroovyTokenTypes; +import org.codehaus.groovy.antlr.treewalker.VisitorAdapter; + +public class Groovifier extends VisitorAdapter implements GroovyTokenTypes { + private String currentClassName = ""; + private final boolean cleanRedundantPublic; + + public Groovifier(String[] tokenNames) { + this(tokenNames, true); + } + + public Groovifier(String[] tokenNames, boolean cleanRedundantPublic) { + this.cleanRedundantPublic = cleanRedundantPublic; + } + + public void visitClassDef(GroovySourceAST t,int visit) { + if (visit == OPENING_VISIT) { + currentClassName = t.childOfType(GroovyTokenTypes.IDENT).getText(); + } + } + public void visitDefault(GroovySourceAST t,int visit) { + if (visit == OPENING_VISIT) { + // only want to do this once per node... + + // remove 'public' when implied already if requested + if (t.getType() == LITERAL_public && cleanRedundantPublic) { + t.setType(EXPR); + } + + // constructors are not distinguished from methods in java ast + if (t.getType() == METHOD_DEF) { + String methodName = t.childOfType(IDENT).getText(); + if (methodName != null && methodName.length() > 0) { + if (methodName.equals(currentClassName)) { + t.setType(CTOR_IDENT); + } + } + } + + +/* if (t.getType() == MODIFIERS) { + GroovySourceAST publicNode = t.childOfType(LITERAL_public); + if (t.getNumberOfChildren() > 1 && publicNode != null) { + // has more than one modifier, and one of them is public + + // delete 'public' node + publicNode.setType(EXPR); // near enough the same as delete for now... + } + }*/ + // ---- + } + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyConverter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyConverter.java b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyConverter.java new file mode 100644 index 0000000..d200a99 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyConverter.java @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr.java; + +import org.codehaus.groovy.antlr.GroovySourceAST; +import org.codehaus.groovy.antlr.parser.GroovyTokenTypes; +import org.codehaus.groovy.antlr.treewalker.VisitorAdapter; + +public class Java2GroovyConverter extends VisitorAdapter{ + private final int[] typeMapping; + + public Java2GroovyConverter(String[] tokenNames) { + typeMapping = new int[400]; // magic number, much greater than current number of java tokens + typeMapping[JavaTokenTypes.ABSTRACT] = GroovyTokenTypes.ABSTRACT; + + typeMapping[JavaTokenTypes.EOF] = GroovyTokenTypes.EOF; + typeMapping[JavaTokenTypes.NULL_TREE_LOOKAHEAD] = GroovyTokenTypes.NULL_TREE_LOOKAHEAD; + typeMapping[JavaTokenTypes.BLOCK] = GroovyTokenTypes.BLOCK; + typeMapping[JavaTokenTypes.MODIFIERS] = GroovyTokenTypes.MODIFIERS; + typeMapping[JavaTokenTypes.OBJBLOCK] = GroovyTokenTypes.OBJBLOCK; + typeMapping[JavaTokenTypes.SLIST] = GroovyTokenTypes.SLIST; + typeMapping[JavaTokenTypes.METHOD_DEF] = GroovyTokenTypes.METHOD_DEF; + typeMapping[JavaTokenTypes.VARIABLE_DEF] = GroovyTokenTypes.VARIABLE_DEF; + typeMapping[JavaTokenTypes.INSTANCE_INIT] = GroovyTokenTypes.INSTANCE_INIT; + typeMapping[JavaTokenTypes.STATIC_INIT] = GroovyTokenTypes.STATIC_INIT; + typeMapping[JavaTokenTypes.TYPE] = GroovyTokenTypes.TYPE; + typeMapping[JavaTokenTypes.CLASS_DEF] = GroovyTokenTypes.CLASS_DEF; + typeMapping[JavaTokenTypes.INTERFACE_DEF] = GroovyTokenTypes.INTERFACE_DEF; + typeMapping[JavaTokenTypes.PACKAGE_DEF] = GroovyTokenTypes.PACKAGE_DEF; + typeMapping[JavaTokenTypes.ARRAY_DECLARATOR] = GroovyTokenTypes.ARRAY_DECLARATOR; + typeMapping[JavaTokenTypes.EXTENDS_CLAUSE] = GroovyTokenTypes.EXTENDS_CLAUSE; + typeMapping[JavaTokenTypes.IMPLEMENTS_CLAUSE] = GroovyTokenTypes.IMPLEMENTS_CLAUSE; + typeMapping[JavaTokenTypes.PARAMETERS] = GroovyTokenTypes.PARAMETERS; + typeMapping[JavaTokenTypes.PARAMETER_DEF] = GroovyTokenTypes.PARAMETER_DEF; + typeMapping[JavaTokenTypes.LABELED_STAT] = GroovyTokenTypes.LABELED_STAT; + typeMapping[JavaTokenTypes.TYPECAST] = GroovyTokenTypes.TYPECAST; + typeMapping[JavaTokenTypes.INDEX_OP] = GroovyTokenTypes.INDEX_OP; + typeMapping[JavaTokenTypes.POST_INC] = GroovyTokenTypes.POST_INC; + typeMapping[JavaTokenTypes.POST_DEC] = GroovyTokenTypes.POST_DEC; + typeMapping[JavaTokenTypes.METHOD_CALL] = GroovyTokenTypes.METHOD_CALL; + typeMapping[JavaTokenTypes.EXPR] = GroovyTokenTypes.EXPR; + typeMapping[JavaTokenTypes.ARRAY_INIT] = GroovyTokenTypes.LIST_CONSTRUCTOR; // this assumes LIST_CONSTRUCTOR set by PreJava2GroovyConvertor + typeMapping[JavaTokenTypes.IMPORT] = GroovyTokenTypes.IMPORT; + typeMapping[JavaTokenTypes.UNARY_MINUS] = GroovyTokenTypes.UNARY_MINUS; + typeMapping[JavaTokenTypes.UNARY_PLUS] = GroovyTokenTypes.UNARY_PLUS; + typeMapping[JavaTokenTypes.CASE_GROUP] = GroovyTokenTypes.CASE_GROUP; + typeMapping[JavaTokenTypes.ELIST] = GroovyTokenTypes.ELIST; + typeMapping[JavaTokenTypes.FOR_INIT] = GroovyTokenTypes.FOR_INIT; + typeMapping[JavaTokenTypes.FOR_CONDITION] = GroovyTokenTypes.FOR_CONDITION; + typeMapping[JavaTokenTypes.FOR_ITERATOR] = GroovyTokenTypes.FOR_ITERATOR; + typeMapping[JavaTokenTypes.EMPTY_STAT] = GroovyTokenTypes.EMPTY_STAT; + typeMapping[JavaTokenTypes.FINAL] = GroovyTokenTypes.FINAL; + typeMapping[JavaTokenTypes.ABSTRACT] = GroovyTokenTypes.ABSTRACT; + typeMapping[JavaTokenTypes.STRICTFP] = GroovyTokenTypes.STRICTFP; + typeMapping[JavaTokenTypes.SUPER_CTOR_CALL] = GroovyTokenTypes.SUPER_CTOR_CALL; + typeMapping[JavaTokenTypes.CTOR_CALL] = GroovyTokenTypes.CTOR_CALL; + typeMapping[JavaTokenTypes.VARIABLE_PARAMETER_DEF] = GroovyTokenTypes.VARIABLE_PARAMETER_DEF; + typeMapping[JavaTokenTypes.STATIC_IMPORT] = GroovyTokenTypes.STATIC_IMPORT; + typeMapping[JavaTokenTypes.ENUM_DEF] = GroovyTokenTypes.ENUM_DEF; + typeMapping[JavaTokenTypes.ENUM_CONSTANT_DEF] = GroovyTokenTypes.ENUM_CONSTANT_DEF; + typeMapping[JavaTokenTypes.FOR_EACH_CLAUSE] = GroovyTokenTypes.FOR_EACH_CLAUSE; + typeMapping[JavaTokenTypes.ANNOTATION_DEF] = GroovyTokenTypes.ANNOTATION_DEF; + typeMapping[JavaTokenTypes.ANNOTATIONS] = GroovyTokenTypes.ANNOTATIONS; + typeMapping[JavaTokenTypes.ANNOTATION] = GroovyTokenTypes.ANNOTATION; + typeMapping[JavaTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR] = GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR; + typeMapping[JavaTokenTypes.ANNOTATION_FIELD_DEF] = GroovyTokenTypes.ANNOTATION_FIELD_DEF; + typeMapping[JavaTokenTypes.ANNOTATION_ARRAY_INIT] = GroovyTokenTypes.ANNOTATION_ARRAY_INIT; + typeMapping[JavaTokenTypes.TYPE_ARGUMENTS] = GroovyTokenTypes.TYPE_ARGUMENTS; + typeMapping[JavaTokenTypes.TYPE_ARGUMENT] = GroovyTokenTypes.TYPE_ARGUMENT; + typeMapping[JavaTokenTypes.TYPE_PARAMETERS] = GroovyTokenTypes.TYPE_PARAMETERS; + typeMapping[JavaTokenTypes.TYPE_PARAMETER] = GroovyTokenTypes.TYPE_PARAMETER; + typeMapping[JavaTokenTypes.WILDCARD_TYPE] = GroovyTokenTypes.WILDCARD_TYPE; + typeMapping[JavaTokenTypes.TYPE_UPPER_BOUNDS] = GroovyTokenTypes.TYPE_UPPER_BOUNDS; + typeMapping[JavaTokenTypes.TYPE_LOWER_BOUNDS] = GroovyTokenTypes.TYPE_LOWER_BOUNDS; + typeMapping[JavaTokenTypes.LITERAL_package] = GroovyTokenTypes.LITERAL_package; + typeMapping[JavaTokenTypes.SEMI] = GroovyTokenTypes.SEMI; + typeMapping[JavaTokenTypes.LITERAL_import] = GroovyTokenTypes.LITERAL_import; + typeMapping[JavaTokenTypes.LITERAL_static] = GroovyTokenTypes.LITERAL_static; + typeMapping[JavaTokenTypes.LBRACK] = GroovyTokenTypes.LBRACK; + typeMapping[JavaTokenTypes.RBRACK] = GroovyTokenTypes.RBRACK; + typeMapping[JavaTokenTypes.IDENT] = GroovyTokenTypes.IDENT; + typeMapping[JavaTokenTypes.DOT] = GroovyTokenTypes.DOT; + typeMapping[JavaTokenTypes.QUESTION] = GroovyTokenTypes.QUESTION; + typeMapping[JavaTokenTypes.LITERAL_extends] = GroovyTokenTypes.LITERAL_extends; + typeMapping[JavaTokenTypes.LITERAL_super] = GroovyTokenTypes.LITERAL_super; + typeMapping[JavaTokenTypes.LT] = GroovyTokenTypes.LT; + typeMapping[JavaTokenTypes.COMMA] = GroovyTokenTypes.COMMA; + typeMapping[JavaTokenTypes.GT] = GroovyTokenTypes.GT; + typeMapping[JavaTokenTypes.SR] = GroovyTokenTypes.SR; + typeMapping[JavaTokenTypes.BSR] = GroovyTokenTypes.BSR; + typeMapping[JavaTokenTypes.LITERAL_void] = GroovyTokenTypes.LITERAL_void; + typeMapping[JavaTokenTypes.LITERAL_boolean] = GroovyTokenTypes.LITERAL_boolean; + typeMapping[JavaTokenTypes.LITERAL_byte] = GroovyTokenTypes.LITERAL_byte; + typeMapping[JavaTokenTypes.LITERAL_char] = GroovyTokenTypes.LITERAL_char; + typeMapping[JavaTokenTypes.LITERAL_short] = GroovyTokenTypes.LITERAL_short; + typeMapping[JavaTokenTypes.LITERAL_int] = GroovyTokenTypes.LITERAL_int; + typeMapping[JavaTokenTypes.LITERAL_float] = GroovyTokenTypes.LITERAL_float; + typeMapping[JavaTokenTypes.LITERAL_long] = GroovyTokenTypes.LITERAL_long; + typeMapping[JavaTokenTypes.LITERAL_double] = GroovyTokenTypes.LITERAL_double; + typeMapping[JavaTokenTypes.STAR] = GroovyTokenTypes.STAR; + typeMapping[JavaTokenTypes.LITERAL_private] = GroovyTokenTypes.LITERAL_private; + typeMapping[JavaTokenTypes.LITERAL_public] = GroovyTokenTypes.LITERAL_public; + typeMapping[JavaTokenTypes.LITERAL_protected] = GroovyTokenTypes.LITERAL_protected; + typeMapping[JavaTokenTypes.LITERAL_transient] = GroovyTokenTypes.LITERAL_transient; + typeMapping[JavaTokenTypes.LITERAL_native] = GroovyTokenTypes.LITERAL_native; + typeMapping[JavaTokenTypes.LITERAL_threadsafe] = GroovyTokenTypes.LITERAL_threadsafe; + typeMapping[JavaTokenTypes.LITERAL_synchronized] = GroovyTokenTypes.LITERAL_synchronized; + typeMapping[JavaTokenTypes.LITERAL_volatile] = GroovyTokenTypes.LITERAL_volatile; + typeMapping[JavaTokenTypes.AT] = GroovyTokenTypes.AT; + typeMapping[JavaTokenTypes.LPAREN] = GroovyTokenTypes.LPAREN; + typeMapping[JavaTokenTypes.RPAREN] = GroovyTokenTypes.RPAREN; + typeMapping[JavaTokenTypes.ASSIGN] = GroovyTokenTypes.ASSIGN; + typeMapping[JavaTokenTypes.LCURLY] = GroovyTokenTypes.LCURLY; + typeMapping[JavaTokenTypes.RCURLY] = GroovyTokenTypes.RCURLY; + typeMapping[JavaTokenTypes.LITERAL_class] = GroovyTokenTypes.LITERAL_class; + typeMapping[JavaTokenTypes.LITERAL_interface] = GroovyTokenTypes.LITERAL_interface; + typeMapping[JavaTokenTypes.LITERAL_enum] = GroovyTokenTypes.LITERAL_enum; + typeMapping[JavaTokenTypes.BAND] = GroovyTokenTypes.BAND; + typeMapping[JavaTokenTypes.LITERAL_default] = GroovyTokenTypes.LITERAL_default; + typeMapping[JavaTokenTypes.LITERAL_implements] = GroovyTokenTypes.LITERAL_implements; + typeMapping[JavaTokenTypes.LITERAL_this] = GroovyTokenTypes.LITERAL_this; + typeMapping[JavaTokenTypes.LITERAL_throws] = GroovyTokenTypes.LITERAL_throws; + typeMapping[JavaTokenTypes.TRIPLE_DOT] = GroovyTokenTypes.TRIPLE_DOT; + typeMapping[JavaTokenTypes.COLON] = GroovyTokenTypes.COLON; + typeMapping[JavaTokenTypes.LITERAL_if] = GroovyTokenTypes.LITERAL_if; + typeMapping[JavaTokenTypes.LITERAL_else] = GroovyTokenTypes.LITERAL_else; + typeMapping[JavaTokenTypes.LITERAL_while] = GroovyTokenTypes.LITERAL_while; + typeMapping[JavaTokenTypes.LITERAL_do] = GroovyTokenTypes.LITERAL_while; // warning - do...while... ignored + typeMapping[JavaTokenTypes.LITERAL_break] = GroovyTokenTypes.LITERAL_break; + typeMapping[JavaTokenTypes.LITERAL_continue] = GroovyTokenTypes.LITERAL_continue; + typeMapping[JavaTokenTypes.LITERAL_return] = GroovyTokenTypes.LITERAL_return; + typeMapping[JavaTokenTypes.LITERAL_switch] = GroovyTokenTypes.LITERAL_switch; + typeMapping[JavaTokenTypes.LITERAL_throw] = GroovyTokenTypes.LITERAL_throw; + typeMapping[JavaTokenTypes.LITERAL_assert] = GroovyTokenTypes.LITERAL_assert; + typeMapping[JavaTokenTypes.LITERAL_for] = GroovyTokenTypes.LITERAL_for; + typeMapping[JavaTokenTypes.LITERAL_case] = GroovyTokenTypes.LITERAL_case; + typeMapping[JavaTokenTypes.LITERAL_try] = GroovyTokenTypes.LITERAL_try; + typeMapping[JavaTokenTypes.LITERAL_finally] = GroovyTokenTypes.LITERAL_finally; + typeMapping[JavaTokenTypes.LITERAL_catch] = GroovyTokenTypes.LITERAL_catch; + typeMapping[JavaTokenTypes.PLUS_ASSIGN] = GroovyTokenTypes.PLUS_ASSIGN; + typeMapping[JavaTokenTypes.MINUS_ASSIGN] = GroovyTokenTypes.MINUS_ASSIGN; + typeMapping[JavaTokenTypes.STAR_ASSIGN] = GroovyTokenTypes.STAR_ASSIGN; + typeMapping[JavaTokenTypes.DIV_ASSIGN] = GroovyTokenTypes.DIV_ASSIGN; + typeMapping[JavaTokenTypes.MOD_ASSIGN] = GroovyTokenTypes.MOD_ASSIGN; + typeMapping[JavaTokenTypes.SR_ASSIGN] = GroovyTokenTypes.SR_ASSIGN; + typeMapping[JavaTokenTypes.BSR_ASSIGN] = GroovyTokenTypes.BSR_ASSIGN; + typeMapping[JavaTokenTypes.SL_ASSIGN] = GroovyTokenTypes.SL_ASSIGN; + typeMapping[JavaTokenTypes.BAND_ASSIGN] = GroovyTokenTypes.BAND_ASSIGN; + typeMapping[JavaTokenTypes.BXOR_ASSIGN] = GroovyTokenTypes.BXOR_ASSIGN; + typeMapping[JavaTokenTypes.BOR_ASSIGN] = GroovyTokenTypes.BOR_ASSIGN; + typeMapping[JavaTokenTypes.LOR] = GroovyTokenTypes.LOR; + typeMapping[JavaTokenTypes.LAND] = GroovyTokenTypes.LAND; + typeMapping[JavaTokenTypes.BOR] = GroovyTokenTypes.BOR; + typeMapping[JavaTokenTypes.BXOR] = GroovyTokenTypes.BXOR; + typeMapping[JavaTokenTypes.NOT_EQUAL] = GroovyTokenTypes.NOT_EQUAL; + typeMapping[JavaTokenTypes.EQUAL] = GroovyTokenTypes.EQUAL; + typeMapping[JavaTokenTypes.LE] = GroovyTokenTypes.LE; + typeMapping[JavaTokenTypes.GE] = GroovyTokenTypes.GE; + typeMapping[JavaTokenTypes.LITERAL_instanceof] = GroovyTokenTypes.LITERAL_instanceof; + typeMapping[JavaTokenTypes.SL] = GroovyTokenTypes.SL; + typeMapping[JavaTokenTypes.PLUS] = GroovyTokenTypes.PLUS; + typeMapping[JavaTokenTypes.MINUS] = GroovyTokenTypes.MINUS; + typeMapping[JavaTokenTypes.DIV] = GroovyTokenTypes.DIV; + typeMapping[JavaTokenTypes.MOD] = GroovyTokenTypes.MOD; + typeMapping[JavaTokenTypes.INC] = GroovyTokenTypes.INC; + typeMapping[JavaTokenTypes.DEC] = GroovyTokenTypes.DEC; + typeMapping[JavaTokenTypes.BNOT] = GroovyTokenTypes.BNOT; + typeMapping[JavaTokenTypes.LNOT] = GroovyTokenTypes.LNOT; + typeMapping[JavaTokenTypes.LITERAL_true] = GroovyTokenTypes.LITERAL_true; + typeMapping[JavaTokenTypes.LITERAL_false] = GroovyTokenTypes.LITERAL_false; + typeMapping[JavaTokenTypes.LITERAL_null] = GroovyTokenTypes.LITERAL_null; + typeMapping[JavaTokenTypes.LITERAL_new] = GroovyTokenTypes.LITERAL_new; + typeMapping[JavaTokenTypes.NUM_INT] = GroovyTokenTypes.NUM_INT; + typeMapping[JavaTokenTypes.CHAR_LITERAL] = GroovyTokenTypes.STRING_LITERAL; // warning: treating Java chars as "String" in Groovy + typeMapping[JavaTokenTypes.STRING_LITERAL] = GroovyTokenTypes.STRING_LITERAL; + typeMapping[JavaTokenTypes.NUM_FLOAT] = GroovyTokenTypes.NUM_FLOAT; + typeMapping[JavaTokenTypes.NUM_LONG] = GroovyTokenTypes.NUM_LONG; + typeMapping[JavaTokenTypes.NUM_DOUBLE] = GroovyTokenTypes.NUM_DOUBLE; + typeMapping[JavaTokenTypes.WS] = GroovyTokenTypes.WS; + typeMapping[JavaTokenTypes.SL_COMMENT] = GroovyTokenTypes.SL_COMMENT; + typeMapping[JavaTokenTypes.ML_COMMENT] = GroovyTokenTypes.ML_COMMENT; + typeMapping[JavaTokenTypes.ESC] = GroovyTokenTypes.ESC; + typeMapping[JavaTokenTypes.HEX_DIGIT] = GroovyTokenTypes.HEX_DIGIT; + typeMapping[JavaTokenTypes.VOCAB] = GroovyTokenTypes.VOCAB; + typeMapping[JavaTokenTypes.EXPONENT] = GroovyTokenTypes.EXPONENT; + typeMapping[JavaTokenTypes.FLOAT_SUFFIX] = GroovyTokenTypes.FLOAT_SUFFIX; + } + + public void visitDefault(GroovySourceAST t,int visit) { + if (visit == OPENING_VISIT) { + // only want to do this once per node... + t.setType(typeMapping[t.getType()]); + // ---- + + // need to remove double quotes in string literals + // as groovy AST doesn't expect to have them + if (t.getType() == GroovyTokenTypes.STRING_LITERAL) { + String text = t.getText(); + if (isSingleQuoted(text) || isDoubleQuoted(text)) { + t.setText(text.substring(1, text.length() - 1)); // chop off the single quotes at start and end + } + } + } + } + + private static boolean isSingleQuoted(String text) { + return text != null && text.length() > 2 + && text.charAt(0) == '\'' + && text.charAt(text.length() - 1) == '\''; + } + private static boolean isDoubleQuoted(String text) { + return text != null && text.length() > 2 + && text.charAt(0) == '"' + && text.charAt(text.length() - 1) == '"'; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyMain.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyMain.java b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyMain.java new file mode 100644 index 0000000..d7384e0 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyMain.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr.java; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; + +import java.util.Arrays; + +public class Java2GroovyMain { + + public static void main(String[] args) { + try { + Options options = new Options(); + CommandLineParser cliParser = new DefaultParser(); + CommandLine cli = cliParser.parse(options, args); + String[] filenames = cli.getArgs(); + if (filenames.length == 0) { + System.err.println("Needs at least one filename"); + } + Java2GroovyProcessor.processFiles(Arrays.asList(filenames)); + } catch (Throwable t) { + t.printStackTrace(); + } + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyProcessor.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyProcessor.java b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyProcessor.java new file mode 100644 index 0000000..d6b47dd --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyProcessor.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr.java; + +import antlr.collections.AST; +import org.codehaus.groovy.antlr.AntlrASTProcessor; +import org.codehaus.groovy.antlr.SourceBuffer; +import org.codehaus.groovy.antlr.UnicodeEscapingReader; +import org.codehaus.groovy.antlr.parser.GroovyLexer; +import org.codehaus.groovy.antlr.parser.GroovyRecognizer; +import org.codehaus.groovy.antlr.treewalker.MindMapPrinter; +import org.codehaus.groovy.antlr.treewalker.NodePrinter; +import org.codehaus.groovy.antlr.treewalker.PreOrderTraversal; +import org.codehaus.groovy.antlr.treewalker.SourceCodeTraversal; +import org.codehaus.groovy.antlr.treewalker.SourcePrinter; +import org.codehaus.groovy.antlr.treewalker.Visitor; +import org.codehaus.groovy.runtime.ResourceGroovyMethods; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.io.StringReader; +import java.util.Iterator; +import java.util.List; + +public class Java2GroovyProcessor { + + public static void processFiles(List<String> fileNames) throws Exception { + Iterator i = fileNames.iterator(); + while (i.hasNext()) { + String filename = (String) i.next(); + File f = new File(filename); + String text = ResourceGroovyMethods.getText(f); + System.out.println(convert(filename, text, true, true)); + } + } + + public static String convert(String filename, String input) throws Exception { + return convert(filename, input, false, false); + } + + public static String convert(String filename, String input, boolean withHeader, boolean withNewLines) throws Exception { + JavaRecognizer parser = getJavaParser(input); + String[] tokenNames = parser.getTokenNames(); + parser.compilationUnit(); + AST ast = parser.getAST(); + + // output AST in format suitable for opening in http://freemind.sourceforge.net + // which is a really nice way of seeing the AST, folding nodes etc + if ("mindmap".equals(System.getProperty("ANTLR.AST".toLowerCase()))) { // uppercase to hide from jarjar + try { + PrintStream out = new PrintStream(new FileOutputStream(filename + ".mm")); + Visitor visitor = new MindMapPrinter(out, tokenNames); + AntlrASTProcessor treewalker = new PreOrderTraversal(visitor); + treewalker.process(ast); + } catch (FileNotFoundException e) { + System.out.println("Cannot create " + filename + ".mm"); + } + } + + // modify the Java AST into a Groovy AST + modifyJavaASTintoGroovyAST(tokenNames, ast); + String[] groovyTokenNames = getGroovyTokenNames(input); + // groovify the fat Java-Like Groovy AST + groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames); + + // now output + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Visitor visitor = new SourcePrinter(new PrintStream(baos), groovyTokenNames, withNewLines); + AntlrASTProcessor traverser = new SourceCodeTraversal(visitor); + + traverser.process(ast); + + String header = ""; + if (withHeader) { + header = "/*\n" + + " Automatically Converted from Java Source \n" + + " \n" + + " by java2groovy v0.0.1 Copyright Jeremy Rayner 2007\n" + + " \n" + + " !! NOT FIT FOR ANY PURPOSE !! \n" + + " 'java2groovy' cannot be used to convert one working program into another" + + " */\n\n"; + } + return header + new String(baos.toByteArray()); + } + + private static void groovifyFatJavaLikeGroovyAST(AST ast, String[] groovyTokenNames) { + Visitor groovifier = new Groovifier(groovyTokenNames); + AntlrASTProcessor groovifierTraverser = new PreOrderTraversal(groovifier); + groovifierTraverser.process(ast); + } + + private static void modifyJavaASTintoGroovyAST(String[] tokenNames, AST ast) { + // mutate the tree when in Javaland + Visitor preJava2groovyConverter = new PreJava2GroovyConverter(tokenNames); + AntlrASTProcessor preJava2groovyTraverser = new PreOrderTraversal(preJava2groovyConverter); + preJava2groovyTraverser.process(ast); + + // map the nodes to Groovy types + Visitor java2groovyConverter = new Java2GroovyConverter(tokenNames); + AntlrASTProcessor java2groovyTraverser = new PreOrderTraversal(java2groovyConverter); + java2groovyTraverser.process(ast); + } + + private static JavaRecognizer getJavaParser(String input) { + JavaRecognizer parser = null; + SourceBuffer sourceBuffer = new SourceBuffer(); + UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(new StringReader(input), sourceBuffer); + JavaLexer lexer = new JavaLexer(unicodeReader); + unicodeReader.setLexer(lexer); + parser = JavaRecognizer.make(lexer); + parser.setSourceBuffer(sourceBuffer); + return parser; + } + + public static String mindmap(String input) throws Exception { + JavaRecognizer parser = getJavaParser(input); + String[] tokenNames = parser.getTokenNames(); + parser.compilationUnit(); + AST ast = parser.getAST(); + // modify the Java AST into a Groovy AST + modifyJavaASTintoGroovyAST(tokenNames, ast); + String[] groovyTokenNames = getGroovyTokenNames(input); + // groovify the fat Java-Like Groovy AST + groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames); + + // now output + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Visitor visitor = new MindMapPrinter(new PrintStream(baos), groovyTokenNames); + AntlrASTProcessor traverser = new SourceCodeTraversal(visitor); + + traverser.process(ast); + + return new String(baos.toByteArray()); + } + + public static String nodePrinter(String input) throws Exception { + JavaRecognizer parser = getJavaParser(input); + String[] tokenNames = parser.getTokenNames(); + parser.compilationUnit(); + AST ast = parser.getAST(); + // modify the Java AST into a Groovy AST + modifyJavaASTintoGroovyAST(tokenNames, ast); + String[] groovyTokenNames = getGroovyTokenNames(input); + // groovify the fat Java-Like Groovy AST + groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames); + + // now output + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Visitor visitor = new NodePrinter(new PrintStream(baos), groovyTokenNames); + AntlrASTProcessor traverser = new SourceCodeTraversal(visitor); + + traverser.process(ast); + + return new String(baos.toByteArray()); + } + + private static String[] getGroovyTokenNames(String input) { + GroovyRecognizer groovyParser = null; + SourceBuffer groovySourceBuffer = new SourceBuffer(); + UnicodeEscapingReader groovyUnicodeReader = new UnicodeEscapingReader(new StringReader(input), groovySourceBuffer); + GroovyLexer groovyLexer = new GroovyLexer(groovyUnicodeReader); + groovyUnicodeReader.setLexer(groovyLexer); + groovyParser = GroovyRecognizer.make(groovyLexer); + return groovyParser.getTokenNames(); + } + +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/java/PreJava2GroovyConverter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/java/PreJava2GroovyConverter.java b/src/main/java/org/codehaus/groovy/antlr/java/PreJava2GroovyConverter.java new file mode 100644 index 0000000..6c5c1e2 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/java/PreJava2GroovyConverter.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.codehaus.groovy.antlr.java; + +import org.codehaus.groovy.antlr.GroovySourceAST; +import org.codehaus.groovy.antlr.treewalker.VisitorAdapter; + +import java.util.Stack; + +/** This class mutates the Java AST, whilst it is still a Java AST, in readiness for conversion to Groovy, yippee-ky-a ! */ +public class PreJava2GroovyConverter extends VisitorAdapter{ + private final Stack stack; + + public PreJava2GroovyConverter(String[] tokenNames) { + this.stack = new Stack(); + } + + public void visitDefault(GroovySourceAST t,int visit) { + if (visit == OPENING_VISIT) { + if (t.getType() == JavaTokenTypes.LITERAL_do) { + visitJavaLiteralDo(t); + } else if (t.getType() == JavaTokenTypes.ARRAY_INIT) { + visitJavaArrayInit(t); + } + } + } + + private void visitJavaLiteralDo(GroovySourceAST t) { + // todo - incomplete, as body of do...while... should be executed at least once, which this doesn't provide. + swapTwoChildren(t); + } + + /** + * Handle Arrays. Examples: + * + * <pre> + * String[] myArray = new String[] {"a","b","c"}; + * + * becomes + * + * String[] myArray = ["a", "b", "c"] + * + * --- + * + * To convert node (t) and surrounding nodes into the right structure for List Constructor + * + * (a) java/EXPR + * | + * +- (b) java/new + * | + * + (t) java/ARRAY_INIT + * + * becomes + * + * (a) groovy/LIST_CONSTRUCTOR (via ARRAY_INIT as temporary marker type) + * | + * +- (t) groovy/ELIST + * + * * note: node (b) is thrown away... + * </pre> + */ + private void visitJavaArrayInit(GroovySourceAST t) { + // given that we might have a grandParent... + if (stack.size() > 2) { + GroovySourceAST grandParent = getGrandParentNode(); + if (grandParent.getType() == JavaTokenTypes.EXPR) { + grandParent.setType(JavaTokenTypes.ARRAY_INIT); //set type as indicator for Java2GroovyConvertor to turn into LIST_CONSTRUCTOR + grandParent.setFirstChild(t); + t.setType(JavaTokenTypes.ELIST); + } + } + } + + /** To swap two children of node t... + * + *<pre> + * (t) + * | + * | + * (a) -- (b) + * + * t.down = firstNode + * a.right = b + * b.right = null + *</pre> + * becomes + *<pre> + * (t) + * | + * | + * (b) -- (a) + * + * t.down = b + * a.right = null + * b.right = a + *</pre> + * + * todo - build API of basic tree mutations like this method. + */ + public void swapTwoChildren(GroovySourceAST t) { + // this swaps the two child nodes, see javadoc above for explanation of implementation + GroovySourceAST a = (GroovySourceAST) t.getFirstChild(); + GroovySourceAST b = (GroovySourceAST) a.getNextSibling(); + + t.setFirstChild(b); + a.setNextSibling(null); + b.setNextSibling(a); + } + + + + + public void push(GroovySourceAST t) { + stack.push(t); + } + public GroovySourceAST pop() { + if (!stack.empty()) { + return (GroovySourceAST) stack.pop(); + } + return null; + } + + private GroovySourceAST getGrandParentNode() { + Object currentNode = stack.pop(); + Object parentNode = stack.pop(); + Object grandParentNode = stack.peek(); + stack.push(parentNode); + stack.push(currentNode); + return (GroovySourceAST) grandParentNode; + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/package.html ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/antlr/package.html b/src/main/java/org/codehaus/groovy/antlr/package.html new file mode 100644 index 0000000..0ecf3f6 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/antlr/package.html @@ -0,0 +1,28 @@ +<!-- + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + +--> +<html> + <head> + <title>package org.codehaus.groovy.antlr.*</title> + </head> + <body> + <p>Parser related classes.</p> + </body> +</html>
