Package com.dubture.twig.core.index

Source Code of com.dubture.twig.core.index.TwigIndexingVisitorExtension

/*******************************************************************************
* This file is part of the Twig eclipse plugin.
*
* (c) Robert Gruendler <r.gruendler@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
******************************************************************************/
package com.dubture.twig.core.index;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.dltk.ast.ASTNode;
import org.eclipse.dltk.ast.declarations.MethodDeclaration;
import org.eclipse.dltk.ast.declarations.ModuleDeclaration;
import org.eclipse.dltk.ast.declarations.TypeDeclaration;
import org.eclipse.dltk.ast.expressions.CallArgumentsList;
import org.eclipse.dltk.ast.expressions.Expression;
import org.eclipse.dltk.ast.references.SimpleReference;
import org.eclipse.dltk.ast.references.VariableReference;
import org.eclipse.dltk.ast.statements.Statement;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.index2.IIndexingRequestor.ReferenceInfo;
import org.eclipse.php.core.index.PhpIndexingVisitorExtension;
import org.eclipse.php.internal.core.compiler.ast.nodes.ArrayCreation;
import org.eclipse.php.internal.core.compiler.ast.nodes.ArrayElement;
import org.eclipse.php.internal.core.compiler.ast.nodes.ClassDeclaration;
import org.eclipse.php.internal.core.compiler.ast.nodes.ClassInstanceCreation;
import org.eclipse.php.internal.core.compiler.ast.nodes.ExpressionStatement;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPCallExpression;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPDocBlock;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPMethodDeclaration;
import org.eclipse.php.internal.core.compiler.ast.nodes.ReturnStatement;
import org.eclipse.php.internal.core.compiler.ast.nodes.Scalar;
import org.eclipse.php.internal.core.compiler.ast.visitor.PHPASTVisitor;
import org.json.simple.JSONObject;

import com.dubture.twig.core.TwigCoreConstants;
import com.dubture.twig.core.log.Logger;
import com.dubture.twig.core.model.Filter;
import com.dubture.twig.core.model.Function;
import com.dubture.twig.core.model.ITwigModelElement;
import com.dubture.twig.core.model.Tag;
import com.dubture.twig.core.model.Test;
import com.dubture.twig.core.model.TwigType;
import com.dubture.twig.core.util.TwigModelUtils;


/**
*
* {@link TwigIndexingVisitorExtension} indexes:
*
* - Filters - Functions - TokenParsers (used to detect start/end tags like
* if/endif, block/endblock etc
*
*
* @author Robert Gruendler <r.gruendler@gmail.com>
*
*/
@SuppressWarnings("restriction")
public class TwigIndexingVisitorExtension extends PhpIndexingVisitorExtension
{

    protected boolean inTwigExtension;
    protected boolean inTokenParser;
    protected boolean inTagParseMethod;
    protected ClassDeclaration currentClass;
    protected Tag tag;
    protected List<MethodDeclaration> methods = new ArrayList<MethodDeclaration>();
    protected List<Function> functions = new ArrayList<Function>();
    protected List<Filter> filters = new ArrayList<Filter>();
    protected List<Test> tests = new ArrayList<Test>();
   
    protected TwigIndexingVisitor visitor;

    public TwigIndexingVisitorExtension()
    {
       
    }
   
    @Override
    public void setSourceModule(ISourceModule module)
    {
        super.setSourceModule(module);
        visitor = new TwigIndexingVisitor(requestor, sourceModule);
    }
   

    @Override
    @SuppressWarnings("unchecked")
    public boolean visit(MethodDeclaration s) throws Exception
    {

        if (!methods.contains(s))
            methods.add(s);

        if (s instanceof PHPMethodDeclaration) {

            PHPMethodDeclaration phpMethod = (PHPMethodDeclaration) s;

            if (inTwigExtension&& phpMethod.getName().equals(TwigCoreConstants.GET_FILTERS)) {

                phpMethod.traverse(new PHPASTVisitor()
                {

                    @Override
                    public boolean visit(ArrayElement s) throws Exception
                    {

                        Expression key = s.getKey();
                        Expression value = s.getValue();

                        if (key == null | value == null) {
                            return false;
                        }

                        if (key.getClass() == Scalar.class && value.getClass() == ClassInstanceCreation.class) {

                            Scalar name = (Scalar) key;
                            ClassInstanceCreation filterClass = (ClassInstanceCreation) value;

                            CallArgumentsList ctorParams = filterClass.getCtorParams();
                            Object child = ctorParams.getChilds().get(0);

                            if (child instanceof VariableReference && ((VariableReference)child).getName().equals("$this") &&
                                    filterClass.getClassName().toString().equals((TwigCoreConstants.TWIG_FILTER_METHOD))) {
                               
                                    if (ctorParams.getChilds().size() > 2 && ctorParams.getChilds().get(1) instanceof Scalar) {
                                        Scalar internal = (Scalar) ctorParams.getChilds().get(1);
                                        String elemName = name.getValue().replaceAll("['\"]", "");
                                        Filter filter = new Filter(elemName);
                                        filter.setInternalFunction(internal.getValue().replaceAll("['\"]", ""));
                                        filter.setPhpClass(currentClass.getName());
                                        filters.add(filter);
                                    }
                            }
                           
                            if (!(child instanceof Scalar)) {
                                return true;
                            }

                            Scalar internal = (Scalar) child;

                            if (filterClass.getClassName().toString().equals(TwigCoreConstants.TWIG_FILTER_FUNCTION)) {

                                String elemName = name.getValue().replaceAll("['\"]", "");

                                Filter filter = new Filter(elemName);
                                filter.setInternalFunction(internal.getValue()
                                        .replaceAll("['\"]", ""));
                                filter.setPhpClass(currentClass.getName());

                                filters.add(filter);

                            }
                        }
                        return true;
                    }
                });

            } else if (inTwigExtension && TwigCoreConstants.GET_TESTS.equals(s.getName())) {

                phpMethod.traverse(new PHPASTVisitor()
                {

                    @Override
                    public boolean visit(ArrayElement s) throws Exception
                    {

                        Expression key = s.getKey();
                        Expression value = s.getValue();

                        if (key == null || value == null)
                            return false;

                        if (key.getClass() == Scalar.class && value.getClass() == ClassInstanceCreation.class) {

                            Scalar name = (Scalar) key;
                            ClassInstanceCreation functionClass = (ClassInstanceCreation) value;

                            CallArgumentsList args = functionClass.getCtorParams();
                            Scalar internalFunction = (Scalar) args.getChilds().get(0);

                            if (internalFunction == null)
                                return true;

                            if (functionClass.getClassName().toString().equals(TwigCoreConstants.TWIG_TEST_FUNCTION)) {

                                String elemName = name.getValue().replaceAll("['\"]", "");

                                JSONObject metadata = new JSONObject();
                                metadata.put(TwigType.PHPCLASS,currentClass.getName());

                                Test test = new Test(elemName);
                                test.setPhpClass(currentClass.getName());
                                test.setInternalFunction(internalFunction.getValue().replaceAll("['\"]", ""));
                                tests.add(test);

                            }
                        }
                        return true;
                    }
                });

            } else if (inTwigExtension&& TwigCoreConstants.GET_FUNCTIONS.equals(s.getName())) {

                phpMethod.traverse(new PHPASTVisitor()
                {
                    @Override
                    public boolean visit(ArrayElement s) throws Exception
                    {

                        Expression key = s.getKey();
                        Expression value = s.getValue();

                        if (key == null || value == null) {
                            return false;
                        }

                        if (key.getClass() == Scalar.class && value.getClass() == ClassInstanceCreation.class) {

                            Scalar name = (Scalar) key;
                            ClassInstanceCreation functionClass = (ClassInstanceCreation) value;
                            CallArgumentsList args = functionClass.getCtorParams();
                            String functionClassName = functionClass.getClassName().toString();
                            int index = -1;
                           
                            if (functionClassName.equals(TwigCoreConstants.TWIG_FUNCTION_FUNCTION)) {
                                index = 0;
                            } else if (functionClassName.equals(TwigCoreConstants.TWIG_FUNCTION_METHOD)) {
                                index = 1;
                            }

                            if (index > -1 && args.getChilds().get(index) instanceof Scalar) {

                                Scalar internalFunction = (Scalar) args.getChilds().get(index);

                                if (internalFunction == null) {
                                    return true;
                                }

                                String elemName = name.getValue().replaceAll("['\"]", "");
                                JSONObject metadata = new JSONObject();
                                metadata.put(TwigType.PHPCLASS, currentClass.getName());

                                Function function = new Function(elemName);
                                function.setPhpClass(currentClass.getName());
                                function.setInternalFunction(internalFunction.getValue().replaceAll("['\"]", ""));
                                functions.add(function);
                            }
                        }
                        return true;
                    }
                });

            } else if (inTokenParser && TwigCoreConstants.PARSE_TOKEN_METHOD.equals(s.getName())) {

                inTagParseMethod = true;

            } else if (inTokenParser && TwigCoreConstants.PARSE_GET_TAG_METHOD.equals(s.getName())) {

                phpMethod.traverse(new PHPASTVisitor()
                {
                    @Override
                    public boolean visit(ReturnStatement s) throws Exception
                    {
                        if (s.getExpr().getClass() == Scalar.class) {
                            Scalar scalar = (Scalar) s.getExpr();
                            tag.setStartTag(scalar.getValue().replaceAll("['\"]", ""));
                        }
                        return false;
                    }
                });
            }
        }

        return false;
    }

    @Override
    public boolean endvisit(MethodDeclaration s) throws Exception
    {
        inTagParseMethod = false;
        return true;
    }

    @Override
    public boolean visit(TypeDeclaration s) throws Exception
    {
        if (s instanceof ClassDeclaration) {

            inTwigExtension = false;
            currentClass = (ClassDeclaration) s;

            for (String superclass : currentClass.getSuperClassNames()) {
                if (superclass.equals(TwigCoreConstants.TWIG_EXTENSION)) {
                    inTwigExtension = true;
                } else if (superclass.equals(TwigCoreConstants.TWIG_TOKEN_PARSER)) {
                    tag = new Tag();
                    inTokenParser = true;
                }
            }
            return true;
        }
        return false;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean endvisit(TypeDeclaration s) throws Exception
    {
        if (s instanceof ClassDeclaration) {
            if (tag != null) {
                if (tag.getStartTag() != null) {

                    int length = currentClass.sourceEnd() - currentClass.sourceStart();
                    PHPDocBlock block = currentClass.getPHPDoc();
                    String desc = "";
                    if (block != null) {
                        String shortDesc = block.getShortDescription() != null
                                ? block.getShortDescription()
                                : "";
                        String longDesc = block.getLongDescription() != null
                                ? block.getLongDescription()
                                : "";
                        desc = shortDesc + longDesc;
                    }

                    String endTag = tag.getEndTag();

                    JSONObject metadata = new JSONObject();
                    metadata.put(TwigType.PHPCLASS, currentClass.getName());
                    metadata.put(TwigType.DOC, desc);
                    metadata.put(TwigType.IS_OPEN_CLOSE, endTag != null);

                    Logger.debugMSG("indexing twig tag: " + tag.getStartTag()
                            + " : " + tag.getEndTag() + " with metadata: "
                            + metadata.toString());

                    ReferenceInfo info = new ReferenceInfo(
                            ITwigModelElement.START_TAG,
                            currentClass.sourceStart(), length,
                            tag.getStartTag(), metadata.toString(), null);
                    addReferenceInfo(info);

                    if (endTag != null) {
                        ReferenceInfo endIinfo = new ReferenceInfo(
                                ITwigModelElement.END_TAG,
                                currentClass.sourceStart(), length,
                                tag.getEndTag(), metadata.toString(), null);
                        addReferenceInfo(endIinfo);
                    }

                }
                tag = null;
            }

            inTwigExtension = false;
            inTokenParser = false;
            currentClass = null;
        }

        return false;
    }

    @Override
    public boolean visit(Statement s) throws Exception
    {
        if (!inTagParseMethod)
            return false;

        s.traverse(new PHPASTVisitor()
        {
            @Override
            public boolean visit(PHPCallExpression callExpr) throws Exception
            {
                SimpleReference ref = callExpr.getCallName();

                if (ref != null
                        && TwigCoreConstants.PARSE_SUB.equals(ref.getName())) {

                    callExpr.traverse(new PHPASTVisitor()
                    {
                        @Override
                        public boolean visit(ArrayCreation array)
                                throws Exception
                        {
                            for (ArrayElement elem : array.getElements()) {

                                Expression value = elem.getValue();

                                if (value == null)
                                    continue;

                                if (value.getClass() == Scalar.class) {

                                    Scalar scalar = (Scalar) value;
                                    String subParseMethod = scalar.getValue().replaceAll("['\"]", "");

                                    for (MethodDeclaration method : currentClass.getMethods()) {
                                        if (subParseMethod.equals(method.getName())) {

                                            String[] endStatements = TwigModelUtils.getEndStatements((PHPMethodDeclaration) method);

                                            for (String stmt : endStatements) {
                                                if (stmt.startsWith("end")) {
                                                    tag.setEndTag(stmt);
                                                    return false;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            return true;
                        }
                    });
                }
                return true;
            }
        });

        return true;
    }

    @Override
    public boolean endvisit(Statement s) throws Exception
    {
        if (s instanceof ExpressionStatement) {

            ExpressionStatement stmt = (ExpressionStatement) s;

            if (stmt.getExpr() instanceof PHPCallExpression) {

                return true;
            }
        }

        return false;
    }

    @Override
    public boolean endvisit(ModuleDeclaration s) throws Exception
    {
        for (Test test : tests) {
            for (MethodDeclaration method : methods) {
                if (method.getName().equals(test.getInternalFunction())) {

                    PHPMethodDeclaration phpMethod = (PHPMethodDeclaration) method;
                    PHPDocBlock doc = phpMethod.getPHPDoc();

                    if (doc != null) {
                        test.addDoc(doc);
                    }

                    Logger.debugMSG("indexing test tag: "
                            + test.getElementName() + " with metadata: "
                            + test.getMetadata());

                    ReferenceInfo info = new ReferenceInfo(
                            ITwigModelElement.TEST, 0, 0,
                            test.getElementName(), test.getMetadata(), null);
                    addReferenceInfo(info);

                }
            }
        }

        for (Function function : functions) {

            for (MethodDeclaration method : methods) {

                if (method.getName().equals(function.getInternalFunction())) {

                    PHPMethodDeclaration phpMethod = (PHPMethodDeclaration) method;
                    PHPDocBlock doc = phpMethod.getPHPDoc();

                    if (doc != null) {
                        function.addDoc(doc);
                    }

                    function.addArgs(method.getArguments());

                    Logger.debugMSG("indexing function: "
                            + function.getElementName() + " with metadata: "
                            + function.getMetadata());
                    ReferenceInfo info = new ReferenceInfo(
                            ITwigModelElement.FUNCTION, 0, 0,
                            function.getElementName(), function.getMetadata(),
                            null);
                    addReferenceInfo(info);

                }
            }
        }

        for (Filter filter : filters) {

            for (MethodDeclaration method : methods) {

                if (method.getName().equals(filter.getInternalFunction())) {

                    PHPMethodDeclaration phpMethod = (PHPMethodDeclaration) method;
                    PHPDocBlock doc = phpMethod.getPHPDoc();

                    if (doc != null) {
                        filter.addDoc(doc);
                    }

                    filter.addArgs(method.getArguments());

                    Logger.debugMSG("indexing filter: "
                            + filter.getElementName() + " with metadata: "
                            + filter.getMetadata());
                    ReferenceInfo info = new ReferenceInfo(
                            ITwigModelElement.FILTER, 0, 0,
                            filter.getElementName(), filter.getMetadata(), null);
                    addReferenceInfo(info);

                }
            }
        }

        return true;

    }

    protected void addReferenceInfo(ReferenceInfo info)
    {
        try {
            requestor.addReference(info);
        } catch (Exception e) {
            Logger.logException(e);
        }
    }
   
    @Override
    public boolean visitGeneral(ASTNode node) throws Exception
    {
        if (node instanceof org.eclipse.dltk.ast.statements.Block) {
            node.traverse(new TwigIndexingVisitor(requestor, sourceModule));
        }
       
        return super.visitGeneral(node);
    }
}
TOP

Related Classes of com.dubture.twig.core.index.TwigIndexingVisitorExtension

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.