net.sf.j2s.core.astvisitors.ASTJ2SDocVisitor.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.j2s.core.astvisitors.ASTJ2SDocVisitor.java

Source

/*******************************************************************************
 * Copyright (c) 2007 java2script.org and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Zhou Renjian - initial API and implementation
 *******************************************************************************/

package net.sf.j2s.core.astvisitors;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.CatchClause;
import org.eclipse.jdt.core.dom.Comment;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IMemberValuePairBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.Initializer;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.TagElement;
import org.eclipse.jdt.core.dom.TextElement;

/**
 * This level of Visitor will try to focus on dealing with those
 * j2s* Javadoc tags.
 * 
 * @author zhou renjian
 *
 * 2006-12-4
 */
public class ASTJ2SDocVisitor extends ASTKeywordVisitor {

    private Javadoc[] nativeJavadoc = null;

    private ASTNode javadocRoot = null;

    private boolean isDebugging = false;

    public boolean isDebugging() {
        return isDebugging;
    }

    public void setDebugging(boolean isDebugging) {
        this.isDebugging = isDebugging;
    }

    public boolean visit(Block node) {
        blockLevel++;
        buffer.append("{\r\n");
        ASTNode parent = node.getParent();
        if (parent instanceof MethodDeclaration) {
            MethodDeclaration method = (MethodDeclaration) parent;
            Javadoc javadoc = method.getJavadoc();
            /*
             * if comment contains "@j2sNative", then output the given native 
             * JavaScript codes directly. 
             */
            if (visitNativeJavadoc(javadoc, node, true) == false) {
                return false;
            }
            IMethodBinding methodBinding = method.resolveBinding();
            if (methodBinding != null) {
                ITypeBinding superclass = methodBinding.getDeclaringClass().getSuperclass();
                boolean containsSuperPrivateMethod = false;
                while (superclass != null) {
                    IMethodBinding[] methods = superclass.getDeclaredMethods();
                    for (int i = 0; i < methods.length; i++) {
                        if (methods[i].getName().equals(methodBinding.getName())
                                && (methods[i].getModifiers() & Modifier.PRIVATE) != 0) {
                            containsSuperPrivateMethod = true;
                            break;
                        }
                    }
                    if (containsSuperPrivateMethod) {
                        break;
                    }
                    superclass = superclass.getSuperclass();
                }
                if (containsSuperPrivateMethod) {
                    buffer.append("var $private = Clazz.checkPrivateMethod (arguments);\r\n");
                    buffer.append("if ($private != null) {\r\n");
                    buffer.append("return $private.apply (this, arguments);\r\n");
                    buffer.append("}\r\n");
                }
            }
        } else if (parent instanceof Initializer) {
            Initializer initializer = (Initializer) parent;
            Javadoc javadoc = initializer.getJavadoc();
            /*
             * if comment contains "@j2sNative", then output the given native 
             * JavaScript codes directly. 
             */
            if (visitNativeJavadoc(javadoc, node, true) == false) {
                return false;
            }
        }
        int blockStart = node.getStartPosition();
        int previousStart = getPreviousStartPosition(node);
        ASTNode root = node.getRoot();
        checkJavadocs(root);
        //for (int i = 0; i < nativeJavadoc.length; i++) {
        for (int i = nativeJavadoc.length - 1; i >= 0; i--) {
            Javadoc javadoc = nativeJavadoc[i];
            int commentStart = javadoc.getStartPosition();
            if (commentStart > previousStart && commentStart < blockStart) {
                /*
                 * if the block's leading comment contains "@j2sNative", 
                 * then output the given native JavaScript codes directly. 
                 */
                if (visitNativeJavadoc(javadoc, node, true) == false) {
                    return false;
                }
            }
        }
        return super.visit(node);
    }

    boolean visitNativeJavadoc(Javadoc javadoc, Block node, boolean superVisit) {
        if (javadoc != null) {
            List tags = javadoc.tags();
            if (tags.size() != 0) {
                for (Iterator iter = tags.iterator(); iter.hasNext();) {
                    TagElement tagEl = (TagElement) iter.next();
                    if ("@j2sIgnore".equals(tagEl.getTagName())) {
                        if (superVisit)
                            super.visit(node);
                        return false;
                    }
                }
                if (isDebugging()) {
                    for (Iterator iter = tags.iterator(); iter.hasNext();) {
                        TagElement tagEl = (TagElement) iter.next();
                        if ("@j2sDebug".equals(tagEl.getTagName())) {
                            if (superVisit)
                                super.visit(node);
                            visitJavadocJ2SSource(tagEl);
                            return false;
                        }
                    }
                }
                boolean toCompileVariableName = ((ASTVariableVisitor) getAdaptable(ASTVariableVisitor.class))
                        .isToCompileVariableName();

                if (!toCompileVariableName) {
                    for (Iterator iter = tags.iterator(); iter.hasNext();) {
                        TagElement tagEl = (TagElement) iter.next();
                        if ("@j2sNativeSrc".equals(tagEl.getTagName())) {
                            if (superVisit)
                                super.visit(node);
                            visitJavadocJ2SSource(tagEl);
                            return false;
                        }
                    }
                }
                for (Iterator iter = tags.iterator(); iter.hasNext();) {
                    TagElement tagEl = (TagElement) iter.next();
                    if ("@j2sNative".equals(tagEl.getTagName())) {
                        if (superVisit)
                            super.visit(node);
                        visitJavadocJ2SSource(tagEl);
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private void visitJavadocJ2SSource(TagElement tagEl) {
        List fragments = tagEl.fragments();
        boolean isFirstLine = true;
        StringBuffer buf = new StringBuffer();
        for (Iterator iterator = fragments.iterator(); iterator.hasNext();) {
            TextElement commentEl = (TextElement) iterator.next();
            String text = commentEl.getText().trim();
            if (isFirstLine) {
                if (text.length() == 0) {
                    continue;
                }
            }
            buf.append(text);
            buf.append("\r\n");
        }
        buffer.append(fixCommentBlock(buf.toString()));
    }

    /*
     * Read JavaScript sources from @j2sNative, @J2SPrefix or others
     */
    boolean readSources(BodyDeclaration node, String tagName, String prefix, String suffix, boolean both) {
        boolean existed = false;
        Javadoc javadoc = node.getJavadoc();
        if (javadoc != null) {
            List tags = javadoc.tags();
            if (tags.size() != 0) {
                for (Iterator iter = tags.iterator(); iter.hasNext();) {
                    TagElement tagEl = (TagElement) iter.next();
                    if (tagName.equals(tagEl.getTagName())) {
                        if (tagEl != null) {
                            List fragments = tagEl.fragments();
                            StringBuffer buf = new StringBuffer();
                            boolean isFirstLine = true;
                            for (Iterator iterator = fragments.iterator(); iterator.hasNext();) {
                                TextElement commentEl = (TextElement) iterator.next();
                                String text = commentEl.getText().trim();
                                if (isFirstLine) {
                                    if (text.length() == 0) {
                                        continue;
                                    }
                                }
                                buf.append(text);
                                buf.append("\r\n");
                            }
                            String sources = buf.toString().trim();
                            sources = sources.replaceAll("(\\/)-\\*|\\*-(\\/)", "$1*$2").replaceAll("<@>", "@");
                            buffer.append(prefix + sources + suffix);
                            existed = true;
                        }
                    }
                }
            }
        }
        if (existed && !both) {
            return existed;
        }
        List modifiers = node.modifiers();
        for (Iterator iter = modifiers.iterator(); iter.hasNext();) {
            Object obj = (Object) iter.next();
            if (obj instanceof Annotation) {
                Annotation annotation = (Annotation) obj;
                String qName = annotation.getTypeName().getFullyQualifiedName();
                int index = qName.indexOf("J2S");
                if (index != -1) {
                    String annName = qName.substring(index);
                    annName = annName.replaceFirst("J2S", "@j2s");
                    if (annName.startsWith(tagName)) {
                        StringBuffer buf = new StringBuffer();
                        IAnnotationBinding annotationBinding = annotation.resolveAnnotationBinding();
                        if (annotationBinding != null) {
                            IMemberValuePairBinding[] valuePairs = annotationBinding.getAllMemberValuePairs();
                            if (valuePairs != null && valuePairs.length > 0) {
                                for (int i = 0; i < valuePairs.length; i++) {
                                    Object value = valuePairs[i].getValue();
                                    if (value != null) {
                                        if (value instanceof Object[]) {
                                            Object[] lines = (Object[]) value;
                                            for (int j = 0; j < lines.length; j++) {
                                                buf.append(lines[j]);
                                                buf.append("\r\n");
                                            }
                                        } else if (value instanceof String) {
                                            buf.append(value);
                                            buf.append("\r\n");
                                        }
                                    }
                                }
                            }
                        }
                        buffer.append(prefix + buf.toString().trim() + suffix);
                        existed = true;
                    }
                }
            }
        }
        return existed;
    }

    private String fixCommentBlock(String text) {
        if (text == null || text.length() == 0) {
            return text;
        }
        return Pattern.compile("\\/-\\*(.*)\\*-\\/", Pattern.MULTILINE | Pattern.DOTALL).matcher(text)
                .replaceAll("/*$1*/");
    }

    private void checkJavadocs(ASTNode root) {
        if (root != javadocRoot) {
            nativeJavadoc = null;
            javadocRoot = root;
        }
        if (nativeJavadoc == null) {
            nativeJavadoc = new Javadoc[0];
            if (root instanceof CompilationUnit) {
                CompilationUnit unit = (CompilationUnit) root;
                List commentList = unit.getCommentList();
                ArrayList list = new ArrayList();
                for (Iterator iter = commentList.iterator(); iter.hasNext();) {
                    Comment comment = (Comment) iter.next();
                    if (comment instanceof Javadoc) {
                        Javadoc javadoc = (Javadoc) comment;
                        List tags = javadoc.tags();
                        if (tags.size() != 0) {
                            for (Iterator itr = tags.iterator(); itr.hasNext();) {
                                TagElement tagEl = (TagElement) itr.next();
                                String tagName = tagEl.getTagName();
                                if ("@j2sIgnore".equals(tagName) || "@j2sDebug".equals(tagName)
                                        || "@j2sNative".equals(tagName)) {
                                    list.add(comment);
                                }
                            }
                        }
                    }
                }
                nativeJavadoc = (Javadoc[]) list.toArray(nativeJavadoc);
            }
        }
    }

    private int getPreviousStartPosition(Block node) {
        int previousStart = 0;
        ASTNode blockParent = node.getParent();
        if (blockParent != null) {
            if (blockParent instanceof Statement) {
                Statement sttmt = (Statement) blockParent;
                previousStart = sttmt.getStartPosition();
                if (sttmt instanceof Block) {
                    Block parentBlock = (Block) sttmt;
                    for (Iterator iter = parentBlock.statements().iterator(); iter.hasNext();) {
                        Statement element = (Statement) iter.next();
                        if (element == node) {
                            break;
                        }
                        previousStart = element.getStartPosition() + element.getLength();
                    }
                } else if (sttmt instanceof IfStatement) {
                    IfStatement ifSttmt = (IfStatement) sttmt;
                    if (ifSttmt.getElseStatement() == node) {
                        Statement thenSttmt = ifSttmt.getThenStatement();
                        previousStart = thenSttmt.getStartPosition() + thenSttmt.getLength();
                    }
                }
            } else if (blockParent instanceof MethodDeclaration) {
                MethodDeclaration method = (MethodDeclaration) blockParent;
                previousStart = method.getStartPosition();
            } else if (blockParent instanceof Initializer) {
                Initializer initializer = (Initializer) blockParent;
                previousStart = initializer.getStartPosition();
            } else if (blockParent instanceof CatchClause) {
                CatchClause catchClause = (CatchClause) blockParent;
                previousStart = catchClause.getStartPosition();
            }
        }
        return previousStart;
    }

    /**
     * Method with "j2s*" tag.
     * 
     * @param node
     * @return
     */
    protected Object getJ2STag(BodyDeclaration node, String tagName) {
        Javadoc javadoc = node.getJavadoc();
        if (javadoc != null) {
            List tags = javadoc.tags();
            if (tags.size() != 0) {
                for (Iterator iter = tags.iterator(); iter.hasNext();) {
                    TagElement tagEl = (TagElement) iter.next();
                    if (tagName.equals(tagEl.getTagName())) {
                        return tagEl;
                    }
                }
            }
        }
        List modifiers = node.modifiers();
        if (modifiers != null && modifiers.size() > 0) {
            for (Iterator iter = modifiers.iterator(); iter.hasNext();) {
                Object obj = (Object) iter.next();
                if (obj instanceof Annotation) {
                    Annotation annotation = (Annotation) obj;
                    String qName = annotation.getTypeName().getFullyQualifiedName();
                    int idx = qName.indexOf("J2S");
                    if (idx != -1) {
                        String annName = qName.substring(idx);
                        annName = annName.replaceFirst("J2S", "@j2s");
                        if (annName.startsWith(tagName)) {
                            return annotation;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * Native method without "j2sDebug" or "j2sNative" tag should be ignored
     * directly.
     * 
     * @param node
     * @return
     */
    protected boolean isMethodNativeIgnored(MethodDeclaration node) {
        if ((node.getModifiers() & Modifier.NATIVE) != 0) {
            if (isDebugging() && getJ2STag(node, "@j2sDebug") != null) {
                return false;
            }
            if (getJ2STag(node, "@j2sNative") != null) {
                return false;
            }
            return true;
        }
        return true; // interface!
    }

}