Package flex2.compiler.as3

Source Code of flex2.compiler.as3.InheritanceEvaluator

/*
*
*  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 flex2.compiler.as3;

import flash.swf.tools.as3.EvaluatorAdapter;
import flex2.compiler.util.MultiName;
import flex2.compiler.util.Name;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import macromedia.asc.parser.BinaryClassDefNode;
import macromedia.asc.parser.BinaryInterfaceDefinitionNode;
import macromedia.asc.parser.ClassDefinitionNode;
import macromedia.asc.parser.IdentifierNode;
import macromedia.asc.parser.ImportDirectiveNode;
import macromedia.asc.parser.InterfaceDefinitionNode;
import macromedia.asc.parser.LiteralStringNode;
import macromedia.asc.parser.MemberExpressionNode;
import macromedia.asc.parser.PackageDefinitionNode;
import macromedia.asc.parser.PackageIdentifiersNode;
import macromedia.asc.parser.PackageNameNode;
import macromedia.asc.parser.QualifiedIdentifierNode;
import macromedia.asc.semantics.NamespaceValue;
import macromedia.asc.semantics.Value;
import macromedia.asc.util.Context;

/**
* This Evaluator fills in the CompilationUnit's inheritance Set.
* It's meant to be used during the parse1 phase, so that all of a
* CompilationUnit's inheritance dependencies will be parsed before
* the parse2 phase begins.  TypeAnalyzer requires this to work
* properly.
*
* @author Paul Reilly
@ @see flex2.compiler.as3.binding.TypeAnalyzer
*/
public class InheritanceEvaluator extends EvaluatorAdapter
{
    private Set<String> imports;
    private Map<String, String> qualifiedImports;
    private List<String> inheritanceNames = new ArrayList<String>();
    private Set<Name> inheritanceMultiNames = new HashSet<Name>();
    private List<MultiName> definitionMultiNames = new ArrayList<MultiName>();

    public InheritanceEvaluator()
    {
        addImport("");
    }

    private void addImport(String importName)
    {
        assert importName != null;

        if (imports == null)
        {
            imports = new TreeSet<String>();
        }

        imports.add(importName);
    }

    private void addQualifiedImport(String localPart, String namespace)
    {
        assert (localPart != null) && (localPart.length() > 0) && (namespace != null);

        if (qualifiedImports == null)
        {
            qualifiedImports = new TreeMap<String, String>();
        }

        qualifiedImports.put(localPart, namespace);
    }

    public Value evaluate(Context context, BinaryInterfaceDefinitionNode binaryInterfaceDefinition)
    {
        if ((binaryInterfaceDefinition.cframe != null) &&
            (binaryInterfaceDefinition.cframe.name != null) &&
            (binaryInterfaceDefinition.cframe.name.ns != null) &&
            (binaryInterfaceDefinition.cframe.name.ns.name.length() > 0))
        {
            addImport(binaryInterfaceDefinition.cframe.name.ns.name);
        }

        return evaluateInterface(binaryInterfaceDefinition);
    }

    public Value evaluate(Context context, BinaryClassDefNode binaryClassDefinition)
    {
        if ((binaryClassDefinition.cframe != null) &&
            (binaryClassDefinition.cframe.name != null) &&
            (binaryClassDefinition.cframe.name.ns != null) &&
            (binaryClassDefinition.cframe.name.ns.name.length() > 0))
        {
            addImport(binaryClassDefinition.cframe.name.ns.name);
        }

        return evaluate(context, (ClassDefinitionNode) binaryClassDefinition);
    }

    public Value evaluate(Context context, ClassDefinitionNode classDefinition)
    {
        if (classDefinition.pkgdef != null)
        {
            processImports(classDefinition.pkgdef.statements.items.iterator());

            PackageNameNode packageName = classDefinition.pkgdef.name;

            if (packageName != null)
            {
                PackageIdentifiersNode packageIdentifiers = packageName.id;

                if ((packageIdentifiers != null) && (packageIdentifiers.pkg_part != null))
                {
                    definitionMultiNames.add(new MultiName(packageIdentifiers.pkg_part, classDefinition.name.name));
                }
            }
        }

        if (classDefinition.statements != null)
        {
            processImports(classDefinition.statements.items.iterator());
        }

        // process extends
        if (classDefinition.baseclass != null)
        {
            if (classDefinition.baseclass instanceof MemberExpressionNode)
            {
                MemberExpressionNode memberExpression = (MemberExpressionNode) classDefinition.baseclass;

                if (memberExpression.selector != null)
                {
                    IdentifierNode identifier = memberExpression.selector.getIdentifier();
                    String baseClassName = toString(identifier);
                    inheritanceNames.add(baseClassName);
                }
            }
            else if (classDefinition.baseclass instanceof LiteralStringNode)
            {
                String baseClassName = ((LiteralStringNode) classDefinition.baseclass).value;
                inheritanceNames.add(baseClassName);
            }
            else
            {
                assert false;
            }
        }
        else
        {
          inheritanceNames.add(":Object");
        }

        // process interfaces
        if (classDefinition.interfaces != null)
        {
            Iterator iterator = classDefinition.interfaces.items.iterator();

            while ( iterator.hasNext() )
            {
                MemberExpressionNode memberExpression = (MemberExpressionNode) iterator.next();

                if (memberExpression.selector != null)
                {
                    IdentifierNode identifier = memberExpression.selector.getIdentifier();
                    String interfaceName = toString(identifier);

                    if ((identifier.ref != null) && (identifier.ref.namespaces != null))
                    {
                        NamespaceValue namespaceValue = (NamespaceValue) identifier.ref.namespaces.get(0);
                        if (namespaceValue.name.length() > 0)
                        {
                            inheritanceMultiNames.add(new MultiName(namespaceValue.name, interfaceName));
                        }
                        else
                        {
                            inheritanceNames.add(interfaceName);
                        }
                    }
                    else
                    {
                        inheritanceNames.add(interfaceName);
                    }
                }
            }
        }

        return null;
    }

    public Value evaluate(Context context, ImportDirectiveNode importDirective)
    {
        if (importDirective.name.id.def_part.length() == 0)
        {
            addImport(importDirective.name.id.pkg_part);
        }
        else
        {
            addQualifiedImport(importDirective.name.id.def_part,
                               importDirective.name.id.pkg_part);
        }
       
        return null;
    }

    public Value evaluate(Context context, InterfaceDefinitionNode interfaceDefinition)
    {
        return evaluateInterface(interfaceDefinition);
    }

    public Value evaluate(Context cx, PackageDefinitionNode packageDefinition)
    {
        PackageNameNode packageName = packageDefinition.name;

        if (packageName != null)
        {
            PackageIdentifiersNode packageIdentifiers = packageName.id;
            if ((packageIdentifiers != null) && (packageIdentifiers.pkg_part != null))
            {
                addImport(packageIdentifiers.pkg_part);
            }
        }

        return null;
    }

    private Value evaluateInterface(ClassDefinitionNode interfaceDefinition)
    {
        if (interfaceDefinition.pkgdef != null)
        {
            processImports(interfaceDefinition.pkgdef.statements.items.iterator());

            PackageNameNode packageName = interfaceDefinition.pkgdef.name;

            if (packageName != null)
            {
                PackageIdentifiersNode packageIdentifiers = packageName.id;

                if ((packageIdentifiers != null) && (packageIdentifiers.pkg_part != null))
                {
                    definitionMultiNames.add(new MultiName(packageIdentifiers.pkg_part, interfaceDefinition.name.name));
                }
            }
        }

        if (interfaceDefinition.statements != null)
        {
            processImports(interfaceDefinition.statements.items.iterator());
        }

        // process extends
        if (interfaceDefinition.baseclass != null)
        {
            if (interfaceDefinition.baseclass instanceof MemberExpressionNode)
            {
                MemberExpressionNode memberExpression = (MemberExpressionNode) interfaceDefinition.baseclass;

                if (memberExpression.selector != null)
                {
                    IdentifierNode identifier = memberExpression.selector.getIdentifier();
                    String baseInterfaceName = toString(identifier);
                    inheritanceNames.add(baseInterfaceName);
                }
            }
            else
            {
                assert false;
            }
        }
        else
        {
          inheritanceNames.add(":Object");
        }

        // process interfaces: It would seem that ASC sometimes puts an interface's base
        // interface in the InterfaceDefinitionNode's interfaces list.  I'm not sure if
        // this is always the case, though.
        if (interfaceDefinition.interfaces != null)
        {
            Iterator iterator = interfaceDefinition.interfaces.items.iterator();

            while ( iterator.hasNext() )
            {
                MemberExpressionNode memberExpression = (MemberExpressionNode) iterator.next();

                if (memberExpression.selector != null)
                {
                    IdentifierNode identifier = memberExpression.selector.getIdentifier();
                    String baseInterfaceName = toString(identifier);

                    if ((identifier.ref != null) && (identifier.ref.namespaces != null))
                    {
                        NamespaceValue namespaceValue = (NamespaceValue) identifier.ref.namespaces.get(0);
                        if (namespaceValue.name.length() > 0)
                        {
                            inheritanceMultiNames.add(new MultiName(namespaceValue.name, baseInterfaceName));
                        }
                        else
                        {
                            inheritanceNames.add(baseInterfaceName);
                        }
                    }
                    else
                    {
                        inheritanceNames.add(baseInterfaceName);
                    }
                }
            }
        }

        return null;
    }

    public Set<Name> getInheritance()
    {
        if (inheritanceNames != null)
        {
            Iterator<String> iterator = inheritanceNames.iterator();

            while ( iterator.hasNext() )
            {
                String inheritanceName = iterator.next();

                MultiName inheritanceMultiName = getMultiName(inheritanceName);

                inheritanceMultiNames.add(inheritanceMultiName);
            }
        }

        // Remove definitions from the inheritance, so we don't run into circular
        // reference errors downstream.
        Iterator inheritanceIterator = inheritanceMultiNames.iterator();

        while ( inheritanceIterator.hasNext() )
        {
            MultiName inheritanceMultiName = (MultiName) inheritanceIterator.next();
            String[] namespaces = inheritanceMultiName.getNamespace();
            Iterator<MultiName> definitionIterator = definitionMultiNames.iterator();

            while ( definitionIterator.hasNext() )
            {
                MultiName definitionMultiName = definitionIterator.next();
                String namespace = definitionMultiName.getNamespace()[0];

                if (inheritanceMultiName.getLocalPart().equals(definitionMultiName.getLocalPart()))
                {
                    for (int i = 0; i < inheritanceMultiName.namespaceURI.length; i++)
                    {
                        if (namespaces[i].equals(namespace))
                        {
                            inheritanceIterator.remove();
                        }
                    }
                }
            }
        }

        return inheritanceMultiNames;
    }

    private MultiName getMultiName(String name)
    {
        assert name != null : "InheritanceEvaluator.getMultiName(): null name";

        MultiName result;

        int lastIndex = name.lastIndexOf(":");

        if (lastIndex < 0)
        {
            lastIndex = name.lastIndexOf(".");
        }

        if (lastIndex >= 0)
        {
            result = new MultiName(new String[] {name.substring(0, lastIndex)},
                                   name.substring(lastIndex + 1));
        }
        else if ((qualifiedImports != null) && qualifiedImports.containsKey(name))
        {
            result = new MultiName(new String[] {qualifiedImports.get(name)}, name);
        }
        else if (imports != null)
        {
            String[] namespaces = new String[imports.size()];
            imports.toArray(namespaces);
            result = new MultiName(namespaces, name);
        }
        else
        {
            result = new MultiName(name);
        }

        return result;
    }

    private void processImports(Iterator iterator)
    {
        while ( iterator.hasNext() )
        {
            Object node = iterator.next();

            if (node instanceof ImportDirectiveNode)
            {
                ImportDirectiveNode importDirective = (ImportDirectiveNode) node;

                if (importDirective.name.id.def_part.length() == 0)
                {
                    addImport(importDirective.name.id.pkg_part);
                }
                else
                {
                    addQualifiedImport(importDirective.name.id.def_part,
                                       importDirective.name.id.pkg_part);
                }
            }
        }
    }

    private String toString(IdentifierNode identifier)
    {
        String result = null;

        if (identifier instanceof QualifiedIdentifierNode)
        {
            QualifiedIdentifierNode qualifiedIdentifier = (QualifiedIdentifierNode) identifier;

            if (qualifiedIdentifier.qualifier instanceof LiteralStringNode)
            {
                LiteralStringNode literalString = (LiteralStringNode) qualifiedIdentifier.qualifier;
                result = literalString.value + ":" + qualifiedIdentifier.name;
            }
            else
            {
                assert false : ("Unhandled QualifiedIdentifierNode qualifier type: " +
                                qualifiedIdentifier.qualifier.getClass().getName());
            }
        }
        else
        {
            result = identifier.name;
        }

        return result;
    }
}
TOP

Related Classes of flex2.compiler.as3.InheritanceEvaluator

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.