Package flex2.compiler.as3.binding

Source Code of flex2.compiler.as3.binding.BindableSecondPassEvaluator

/*
*
*  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.binding;

import flex2.compiler.CompilationUnit;
import flex2.compiler.as3.AbstractSyntaxTreeUtil;
import flex2.compiler.as3.MetaDataEvaluator;
import flex2.compiler.as3.genext.GenerativeClassInfo.AccessorInfo;
import flex2.compiler.as3.genext.GenerativeClassInfo.GetterSetterInfo;
import flex2.compiler.as3.genext.GenerativeClassInfo.VariableInfo;
import flex2.compiler.as3.genext.GenerativeClassInfo;
import flex2.compiler.as3.genext.GenerativeExtension;
import flex2.compiler.as3.genext.GenerativeSecondPassEvaluator;
import flex2.compiler.as3.reflect.NodeMagic;
import flex2.compiler.mxml.lang.StandardDefs;
import flex2.compiler.util.CompilerMessage;
import flex2.compiler.util.MultiName;
import flex2.compiler.util.QName;
import macromedia.asc.parser.ArgumentListNode;
import macromedia.asc.parser.AttributeListNode;
import macromedia.asc.parser.BinaryExpressionNode;
import macromedia.asc.parser.ClassDefinitionNode;
import macromedia.asc.parser.CallExpressionNode;
import macromedia.asc.parser.DefinitionNode;
import macromedia.asc.parser.DocCommentNode;
import macromedia.asc.parser.ExpressionStatementNode;
import macromedia.asc.parser.FunctionCommonNode;
import macromedia.asc.parser.FunctionDefinitionNode;
import macromedia.asc.parser.FunctionNameNode;
import macromedia.asc.parser.FunctionSignatureNode;
import macromedia.asc.parser.GetExpressionNode;
import macromedia.asc.parser.IdentifierNode;
import macromedia.asc.parser.ListNode;
import macromedia.asc.parser.LiteralBooleanNode;
import macromedia.asc.parser.LiteralNullNode;
import macromedia.asc.parser.LiteralNumberNode;
import macromedia.asc.parser.LiteralStringNode;
import macromedia.asc.parser.MemberExpressionNode;
import macromedia.asc.parser.MetaDataNode;
import macromedia.asc.parser.Node;
import macromedia.asc.parser.NodeFactory;
import macromedia.asc.parser.ParameterListNode;
import macromedia.asc.parser.ParameterNode;
import macromedia.asc.parser.QualifiedIdentifierNode;
import macromedia.asc.parser.ReturnStatementNode;
import macromedia.asc.parser.SetExpressionNode;
import macromedia.asc.parser.StatementListNode;
import macromedia.asc.parser.Tokens;
import macromedia.asc.parser.ThisExpressionNode;
import macromedia.asc.parser.TypeExpressionNode;
import macromedia.asc.parser.VariableDefinitionNode;
import macromedia.asc.semantics.Value;
import macromedia.asc.util.Context;

import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;

/**
* This class handles the AST manipulation of wrapping properties and
* variables, with getter/setter pairs, which handle change detection
* and the dispatching of mx.events.PropertyChangeEvent's.
*
* @author Paul Reilly
*/
public class BindableSecondPassEvaluator extends GenerativeSecondPassEvaluator
{
    private static final String ADD_EVENT_LISTENER = "addEventListener".intern();
    private static final String BINDABLE = "Bindable".intern();
    private static final String BOOLEAN = "Boolean".intern();
    private static final String CREATE_UPDATE_EVENT = "createUpdateEvent".intern();
    private static final String DISPATCH_EVENT = "dispatchEvent".intern();
    private static final String EVENT_VAR = "event".intern();
    private static final String EVENT_CLASS = "Event".intern();
    private static final String EVENT_DISPATCHER_VAR = "eventDispatcher".intern();
    private static final String EVENT_DISPATCHER_CLASS = "EventDispatcher".intern();
    private static final String FLASH_EVENTS = "flash.events".intern();
    private static final String FUNCTION = "Function".intern();
    private static final String HAS_EVENT_LISTENER = "hasEventListener".intern();
    private static final String INT = "int".intern();
    private static final String I_EVENT_DISPATCHER = "IEventDispatcher".intern();
    private static final String LISTENER = "listener".intern();
    private static final String MX_EVENTS = "mx.events".intern();
    private static final String OBJECT = "Object".intern();
    private static final String OLD_VALUE= "oldValue".intern();
    private static final String PRIORITY = "priority".intern();
    private static final String PROPERTY_CHANGE = "propertyChange".intern();
    private static final String PROPERTY_CHANGE_EVENT = "PropertyChangeEvent".intern();
    private static final String REMOVE_EVENT_LISTENER = "removeEventListener".intern();
    private static final String STRING = "String".intern();
    private static final String TYPE = "type".intern();
    private static final String USE_CAPTURE = "useCapture".intern();
    private static final String VALUE = "value".intern();
    private static final String WEAK_REF = "weakRef".intern();
    private static final String WILL_TRIGGER = "willTrigger".intern();
    private static final String _BINDING_EVENT_DISPATCHER = "_bindingEventDispatcher".intern();
    private static final String _STATIC_BINDING_EVENT_DISPATCHER = "_staticBindingEventDispatcher".intern();

    private static final String DOT = ".";
    private static final String SPACE = " ";

  private static final String CODEGEN_TEMPLATE_PATH = "flex2/compiler/as3/binding/";
  private static final String STATIC_EVENT_DISPATCHER = "staticEventDispatcher";
  private BindableInfo bindableInfo;
  private boolean inClass = false;

  public BindableSecondPassEvaluator(CompilationUnit unit, Map<String, ? extends GenerativeClassInfo> classMap,
                     TypeAnalyzer typeAnalyzer, String generatedOutputDirectory,
                                       boolean generateAbstractSyntaxTree, boolean processComments)
  {
    super(unit, classMap, typeAnalyzer, generatedOutputDirectory, generateAbstractSyntaxTree, processComments);
  }

    private void addIEventDispatcherImplementation(Context context, ClassDefinitionNode classDefinition)
    {
        NodeFactory nodeFactory = context.getNodeFactory();
        MemberExpressionNode memberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, FLASH_EVENTS,
                                                          I_EVENT_DISPATCHER, false);
        classDefinition.interfaces = nodeFactory.list(classDefinition.interfaces, memberExpression);

        VariableDefinitionNode variableDefinition = generateBindingEventDispatcherVariable(nodeFactory);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, variableDefinition);

        DocCommentNode docCommentNode = generateInheritDocComment(context);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, docCommentNode);
       
        FunctionDefinitionNode addEventListenerFunctionDefinition =
            generateAddEventListenerFunctionDefinition(context);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, addEventListenerFunctionDefinition);

        docCommentNode = generateInheritDocComment(context);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, docCommentNode);
       
        FunctionDefinitionNode dispatchEventFunctionDefinition =
            generateDispatchEventFunctionDefinition(context);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, dispatchEventFunctionDefinition);

        docCommentNode = generateInheritDocComment(context);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, docCommentNode);
       
        FunctionDefinitionNode hasEventListenerFunctionDefinition =
            generateHasEventListenerFunctionDefinition(context);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, hasEventListenerFunctionDefinition);

        docCommentNode = generateInheritDocComment(context);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, docCommentNode);
       
        FunctionDefinitionNode removeEventListenerFunctionDefinition =
            generateRemoveEventListenerFunctionDefinition(context);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, removeEventListenerFunctionDefinition);

        docCommentNode = generateInheritDocComment(context);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, docCommentNode);
       
        FunctionDefinitionNode willTriggerFunctionDefinition =
            generateWillTriggerFunctionDefinition(context);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, willTriggerFunctionDefinition);
    }

    private void addStaticEventDispatcherImplementation(Context context, ClassDefinitionNode classDefinition)
    {
        NodeFactory nodeFactory = context.getNodeFactory();
        VariableDefinitionNode variableDefinition = generateStaticBindingEventDispatcherVariable(nodeFactory);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, variableDefinition);

        FunctionDefinitionNode addEventListenerFunctionDefinition =
            generateStaticEventDispatcherGetter(context);
        classDefinition.statements =
            nodeFactory.statementList(classDefinition.statements, addEventListenerFunctionDefinition);
    }

  /**
   *
   */
  public Value evaluate(Context context, ClassDefinitionNode node)
  {
    if (!evaluatedClasses.contains(node))
    {
      inClass = true;

      String className = NodeMagic.getClassName(node);

      bindableInfo = (BindableInfo) classMap.get(className);

      if (bindableInfo != null)
      {
        ClassInfo classInfo = bindableInfo.getClassInfo();
        if (!classInfo.implementsInterface(StandardDefs.PACKAGE_FLASH_EVENTS,
                           GenerativeExtension.IEVENT_DISPATCHER))
        {
          bindableInfo.setNeedsToImplementIEventDispatcher(true);

          MultiName multiName = new MultiName(StandardDefs.PACKAGE_FLASH_EVENTS,
                            GenerativeExtension.IEVENT_DISPATCHER);
          InterfaceInfo interfaceInfo = typeAnalyzer.analyzeInterface(context, multiName, classInfo);

                    // interfaceInfo will be null if IEventDispatcher was not resolved.
                    // This most likely means that playerglobal.swc was not in the
                    // external-library-path and other errors will be reported, so punt.
          if ((interfaceInfo == null) || checkForExistingMethods(context, node, classInfo, interfaceInfo))
          {
            return null;
          }

          classInfo.addInterfaceMultiName(StandardDefs.PACKAGE_FLASH_EVENTS,
                          GenerativeExtension.IEVENT_DISPATCHER);
        }

        if (bindableInfo.getRequiresStaticEventDispatcher() &&
          (!classInfo.definesVariable(STATIC_EVENT_DISPATCHER) &&
           !classInfo.definesGetter(STATIC_EVENT_DISPATCHER, true)))
        {
          bindableInfo.setNeedsStaticEventDispatcher(true);
        }

        postProcessClassInfo(context, bindableInfo);
        prepClassDef(node);

        if (node.statements != null)
        {
          node.statements.evaluate(context, this);
          modifySyntaxTree(context, node, bindableInfo);
        }

        bindableInfo = null;
      }

      inClass = false;

      // Make sure we don't process this class again.
      evaluatedClasses.add(node);
    }

    return null;
  }

    private AttributeListNode generateAttributeList(NodeFactory nodeFactory, String attributeString)
    {
        AttributeListNode result = null;

        if (attributeString.length() > 0)
        {
            int index = attributeString.indexOf(SPACE);

            if (index > -1)
            {
                IdentifierNode identifier = nodeFactory.identifier(attributeString.substring(index + 1));
                AttributeListNode attributeList = nodeFactory.attributeList(identifier, null);
                MemberExpressionNode memberExpression =
                    AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, attributeString.substring(0, index), true);
                ListNode list = nodeFactory.list(null, memberExpression);
                result = nodeFactory.attributeList(list, attributeList);
            }
            else
            {
                MemberExpressionNode memberExpression =
                    AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, attributeString, true);
                ListNode list = nodeFactory.list(null, memberExpression);
                result = nodeFactory.attributeList(list, null);
            }
        }

        return result;
    }

    private VariableDefinitionNode generateBindingEventDispatcherVariable(NodeFactory nodeFactory)
    {
        // Equivalent AS:
        //
        //   private var _bindingEventDispatcher:flash.events.EventDispatcher =
        //     new flash.events.EventDispatcher(flash.events.IEventDispatcher(this));
        AttributeListNode attributeList = AbstractSyntaxTreeUtil.generatePrivateAttribute(nodeFactory);
        IdentifierNode identifier = nodeFactory.identifier(_BINDING_EVENT_DISPATCHER, false);
        QualifiedIdentifierNode eventDispatcherQualifiedIdentifier =
            AbstractSyntaxTreeUtil.generateQualifiedIdentifier(nodeFactory, FLASH_EVENTS,
                                                               EVENT_DISPATCHER_CLASS, false);
        QualifiedIdentifierNode iEventDispatcherQualifiedIdentifier =
            AbstractSyntaxTreeUtil.generateQualifiedIdentifier(nodeFactory, FLASH_EVENTS,
                                                               I_EVENT_DISPATCHER, false);
        ThisExpressionNode thisExpression = nodeFactory.thisExpression(0);
        ArgumentListNode castArgumentList = nodeFactory.argumentList(null, thisExpression);
        CallExpressionNode castCallExpression =
            (CallExpressionNode) nodeFactory.callExpression(iEventDispatcherQualifiedIdentifier,
                                                            castArgumentList);
        castCallExpression.setRValue(false);
        MemberExpressionNode innerMemberExpression = nodeFactory.memberExpression(null, castCallExpression);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, innerMemberExpression);
        CallExpressionNode callExpression =
            (CallExpressionNode) nodeFactory.callExpression(eventDispatcherQualifiedIdentifier,
                                                            argumentList);
        callExpression.is_new = true;
        callExpression.setRValue(false);
        MemberExpressionNode memberExpression = nodeFactory.memberExpression(null, callExpression);
        return AbstractSyntaxTreeUtil.generateVariable(nodeFactory, attributeList, identifier,
                                                       FLASH_EVENTS, EVENT_DISPATCHER_CLASS,
                                                       false, memberExpression);
    }

    private StatementListNode generateDispatchEventCall(NodeFactory nodeFactory, StatementListNode then,
                                                        String qualifiedPropertyName)
    {
        // Equivalent AS:
        //   if (this.hasEventListener("propertyChange"))
        //       this.dispatchEvent(mx.events.PropertyChangeEvent.createUpdateEvent(this, "$entry.qualifiedPropertyName", oldValue, value));
        ThisExpressionNode innerThisExpression = nodeFactory.thisExpression(0);
        IdentifierNode dispatchEventIdentifier = nodeFactory.identifier(DISPATCH_EVENT, false);

        MemberExpressionNode propertyChangeEventMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, MX_EVENTS, PROPERTY_CHANGE_EVENT, false);;
        IdentifierNode createUpdateEventIdentifier = nodeFactory.identifier(CREATE_UPDATE_EVENT, false);
        ThisExpressionNode thisExpression = nodeFactory.thisExpression(0);
        ArgumentListNode createUpdateEventArgumentList = nodeFactory.argumentList(null, innerThisExpression);

        LiteralStringNode literalString = nodeFactory.literalString(qualifiedPropertyName);
        createUpdateEventArgumentList = nodeFactory.argumentList(createUpdateEventArgumentList, literalString);

        MemberExpressionNode oldValueMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, OLD_VALUE, false);
        createUpdateEventArgumentList =
            nodeFactory.argumentList(createUpdateEventArgumentList, oldValueMemberExpression);

        MemberExpressionNode valueMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, VALUE, false);
        createUpdateEventArgumentList =
            nodeFactory.argumentList(createUpdateEventArgumentList, valueMemberExpression);

        CallExpressionNode createUpdateEventCallExpression =
            (CallExpressionNode) nodeFactory.callExpression(createUpdateEventIdentifier, createUpdateEventArgumentList);
        createUpdateEventCallExpression.setRValue(false);
        MemberExpressionNode createUpdateEventMemberExpression =
            nodeFactory.memberExpression(propertyChangeEventMemberExpression, createUpdateEventCallExpression);
        ArgumentListNode dispatchEventArgumentList =
            nodeFactory.argumentList(null, createUpdateEventMemberExpression);
        CallExpressionNode dispatchEventCallExpression =
            (CallExpressionNode) nodeFactory.callExpression(dispatchEventIdentifier, dispatchEventArgumentList);
        dispatchEventCallExpression.setRValue(false);
        MemberExpressionNode memberExpression =
            nodeFactory.memberExpression(thisExpression, dispatchEventCallExpression);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement =
            nodeFactory.expressionStatement(list);
       
        // if (this.hasEventListener("propertyChange"))
        ThisExpressionNode ifThisExpression = nodeFactory.thisExpression(0);
        IdentifierNode hasEventListenerIdentifier = nodeFactory.identifier(HAS_EVENT_LISTENER, false);
        LiteralStringNode propChangeLiteralString = nodeFactory.literalString(PROPERTY_CHANGE);
        CallExpressionNode hasEventListenerCallExpression =
            (CallExpressionNode) nodeFactory.callExpression(hasEventListenerIdentifier, nodeFactory.argumentList(null, propChangeLiteralString));
        hasEventListenerCallExpression.setRValue(false);
        MemberExpressionNode ifMemberExpression =
            nodeFactory.memberExpression(ifThisExpression, hasEventListenerCallExpression);
        ListNode iftest = nodeFactory.list(null, ifMemberExpression);
        Node ifStatement = nodeFactory.ifStatement(iftest, expressionStatement, null);
       
        return nodeFactory.statementList(then, ifStatement);
    }

    private DocCommentNode generateInheritDocComment(Context context)
    {
        // Equivalent AS:
        //
        //    /**
      //     * @inheritDoc
      //     */
        NodeFactory nodeFactory = context.getNodeFactory();

        return AbstractSyntaxTreeUtil.generateInheritDocComment(nodeFactory);
    }
   
    private FunctionDefinitionNode generateAddEventListenerFunctionDefinition(Context context)
    {
        // Equivalent AS:
        //
        //    public function addEventListener(type:String, listener:Function,
        //                                     useCapture:Boolean = false,
        //                                     priority:int = 0,
        //                                     weakRef:Boolean = false):void
        //    {
        //        _bindingEventDispatcher.addEventListener(type, listener, useCapture,
        //                                                 priority, weakRef);
        //    }
        NodeFactory nodeFactory = context.getNodeFactory();

        AttributeListNode attributeList = AbstractSyntaxTreeUtil.generatePublicAttribute(nodeFactory);

        IdentifierNode addEventListenerIdentifier = nodeFactory.identifier(ADD_EVENT_LISTENER, false);
        FunctionNameNode functionName = nodeFactory.functionName(Tokens.EMPTY_TOKEN, addEventListenerIdentifier);

        ParameterNode typeParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, TYPE, STRING, false);
        ParameterListNode parameterList = nodeFactory.parameterList(null, typeParameter);
        ParameterNode listenerParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, LISTENER, FUNCTION, false);
        parameterList = nodeFactory.parameterList(parameterList, listenerParameter);
        LiteralBooleanNode literalBoolean = nodeFactory.literalBoolean(false);
        ParameterNode useCaptureParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, USE_CAPTURE, BOOLEAN,
                                                     false, literalBoolean);
        parameterList = nodeFactory.parameterList(parameterList, useCaptureParameter);
        LiteralNumberNode literalNumber = nodeFactory.literalNumber(0);
        ParameterNode priorityParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, PRIORITY, INT,
                                                     false, literalNumber);
        parameterList = nodeFactory.parameterList(parameterList, priorityParameter);
        literalBoolean = nodeFactory.literalBoolean(false);
        ParameterNode weakRefParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, WEAK_REF, BOOLEAN,
                                                     false, literalBoolean);
        parameterList = nodeFactory.parameterList(parameterList, weakRefParameter);
        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(parameterList, null);
        functionSignature.void_anno = true;

        MemberExpressionNode _bindingEventDispatcherGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, _BINDING_EVENT_DISPATCHER, false);
        IdentifierNode identifier = nodeFactory.identifier(ADD_EVENT_LISTENER, false);
        MemberExpressionNode typeGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, TYPE, false);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, typeGetterSelector);
        MemberExpressionNode listenerGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, LISTENER, false);
        argumentList = nodeFactory.argumentList(argumentList, listenerGetterSelector);
        MemberExpressionNode useCaptureGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, USE_CAPTURE, false);
        argumentList = nodeFactory.argumentList(argumentList, useCaptureGetterSelector);
        MemberExpressionNode priorityGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, PRIORITY, false);
        argumentList = nodeFactory.argumentList(argumentList, priorityGetterSelector);
        MemberExpressionNode weakRefGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WEAK_REF, false);
        argumentList = nodeFactory.argumentList(argumentList, weakRefGetterSelector);
        CallExpressionNode callExpression =
            (CallExpressionNode) nodeFactory.callExpression(identifier, argumentList);
        callExpression.setRValue(false);
        MemberExpressionNode memberExpression =
            nodeFactory.memberExpression(_bindingEventDispatcherGetterSelector, callExpression);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement = nodeFactory.expressionStatement(list);

        StatementListNode functionStatementList = nodeFactory.statementList(null, expressionStatement);

        FunctionCommonNode functionCommon = nodeFactory.functionCommon(context, null, functionSignature,
                                                                       functionStatementList);
        functionCommon.setUserDefinedBody(true);

        return nodeFactory.functionDefinition(context, attributeList, functionName, functionCommon);
    }

    private FunctionDefinitionNode generateDispatchEventFunctionDefinition(Context context)
    {
        // Equivalent AS:
        //
        //    public function dispatchEvent(event:flash.events.Event):Boolean
        //    {
        //        return _bindingEventDispatcher.dispatchEvent(event);
        //    }
        NodeFactory nodeFactory = context.getNodeFactory();

        AttributeListNode attributeList = AbstractSyntaxTreeUtil.generatePublicAttribute(nodeFactory);

        IdentifierNode dispatchEventIdentifier = nodeFactory.identifier(DISPATCH_EVENT, false);
        FunctionNameNode functionName = nodeFactory.functionName(Tokens.EMPTY_TOKEN, dispatchEventIdentifier);

        ParameterNode parameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, EVENT_VAR, FLASH_EVENTS, EVENT_CLASS, false);
        ParameterListNode parameterList = nodeFactory.parameterList(null, parameter);
        MemberExpressionNode returnTypeMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, BOOLEAN, true);
        TypeExpressionNode returnType = nodeFactory.typeExpression(returnTypeMemberExpression, true, false, -1);
        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(parameterList, returnType);

        MemberExpressionNode _bindingEventDispatcherGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, _BINDING_EVENT_DISPATCHER, false);
        IdentifierNode identifier = nodeFactory.identifier(DISPATCH_EVENT, false);
        MemberExpressionNode eventGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, EVENT_VAR, false);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, eventGetterSelector);
        CallExpressionNode callExpression =
            (CallExpressionNode) nodeFactory.callExpression(identifier, argumentList);
        callExpression.setRValue(false);

        MemberExpressionNode memberExpression =
            nodeFactory.memberExpression(_bindingEventDispatcherGetterSelector, callExpression);
        ListNode returnList = nodeFactory.list(null, memberExpression);
        ReturnStatementNode returnStatement = nodeFactory.returnStatement(returnList);

        StatementListNode functionStatementList = nodeFactory.statementList(null, returnStatement);

        FunctionCommonNode functionCommon = nodeFactory.functionCommon(context, null, functionSignature,
                                                                       functionStatementList);
        functionCommon.setUserDefinedBody(true);

        return nodeFactory.functionDefinition(context, attributeList, functionName, functionCommon);
    }

    private ListNode generateEventDispatcherNotNull(NodeFactory nodeFactory)
    {
        // Equivalent AS:
        //
        //   if (eventDispatcher != null)
        MemberExpressionNode memberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, EVENT_DISPATCHER_VAR, false);
        LiteralNullNode literalNull = nodeFactory.literalNull();
        BinaryExpressionNode binaryExpression = nodeFactory.binaryExpression(Tokens.STRICTNOTEQUALS_TOKEN,
                                                                             memberExpression,
                                                                             literalNull);
        return nodeFactory.list(null, binaryExpression);
    }

    private FunctionDefinitionNode generateGetter(Context context, String className,
                                                  AccessorInfo accessorInfo)
    {
        // Equivalent AS:
        //
        //  $entry.attributeString function get ${entry.propertyName}():$entry.typeName
        NodeFactory nodeFactory = context.getNodeFactory();
        String typeName = accessorInfo.getTypeName();
        int index = typeName.lastIndexOf(DOT);
        int position = ((VariableInfo) accessorInfo).getPosition();
        TypeExpressionNode returnType = AbstractSyntaxTreeUtil.generateTypeExpression(nodeFactory, typeName, true);
        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(null, returnType);
        AttributeListNode attributeList = generateAttributeList(nodeFactory, accessorInfo.getAttributeString());
        IdentifierNode identifier = nodeFactory.identifier(accessorInfo.getPropertyName());
        FunctionNameNode functionName = nodeFactory.functionName(Tokens.GET_TOKEN, identifier);

        ReturnStatementNode returnStatement;

        if (accessorInfo.getIsStatic())
        {
            // Equivalent AS:
            //
            //  return ${bindableInfo.className}.${entry.qualifiedBackingPropertyName};
            MemberExpressionNode getterSelector =
                AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, className, false);
            String qualifiedBackingPropertyName = accessorInfo.getQualifiedBackingPropertyName().intern();
            IdentifierNode identifer =
                AbstractSyntaxTreeUtil.generateIdentifier(nodeFactory, qualifiedBackingPropertyName, false);
            GetExpressionNode getExpression = nodeFactory.getExpression(identifer);
            MemberExpressionNode memberExpression = nodeFactory.memberExpression(getterSelector, getExpression);
            ListNode returnList = nodeFactory.list(null, memberExpression);
            returnStatement = nodeFactory.returnStatement(returnList);
        }
        else
        {
            // Equivalent AS:
            //
            //  return this.${entry.qualifiedBackingPropertyName};
            ThisExpressionNode thisExpression = nodeFactory.thisExpression(0);
            String qualifiedBackingPropertyName = accessorInfo.getQualifiedBackingPropertyName().intern();
            IdentifierNode identifer =
                AbstractSyntaxTreeUtil.generateIdentifier(nodeFactory, qualifiedBackingPropertyName, false);
            GetExpressionNode getExpression = nodeFactory.getExpression(identifer);
            MemberExpressionNode memberExpression = nodeFactory.memberExpression(thisExpression, getExpression);
            ListNode returnList = nodeFactory.list(null, memberExpression);
            returnStatement = nodeFactory.returnStatement(returnList);
        }

        StatementListNode functionStatementList = nodeFactory.statementList(null, returnStatement);

        FunctionCommonNode functionCommon = nodeFactory.functionCommon(context, null, functionSignature,
                                                                       functionStatementList, position);
        functionCommon.setUserDefinedBody(true);

        return nodeFactory.functionDefinition(context, attributeList, functionName, functionCommon);
    }

    private FunctionDefinitionNode generateHasEventListenerFunctionDefinition(Context context)
    {
        // Equivalent AS:
        //
        //    public function hasEventListener(type:String):Boolean
        //    {
        //        return _bindingEventDispatcher.hasEventListener(type);
        //    }
        NodeFactory nodeFactory = context.getNodeFactory();

        AttributeListNode attributeList = AbstractSyntaxTreeUtil.generatePublicAttribute(nodeFactory);

        IdentifierNode hasEventListenerIdentifier = nodeFactory.identifier(HAS_EVENT_LISTENER, false);
        FunctionNameNode functionName = nodeFactory.functionName(Tokens.EMPTY_TOKEN, hasEventListenerIdentifier);

        ParameterNode typeParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, TYPE, STRING, false);
        ParameterListNode parameterList = nodeFactory.parameterList(null, typeParameter);
        MemberExpressionNode returnTypeMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, BOOLEAN, true);
        TypeExpressionNode returnType = nodeFactory.typeExpression(returnTypeMemberExpression, true, false, -1);
        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(parameterList, returnType);

        MemberExpressionNode _bindingEventDispatcherGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, _BINDING_EVENT_DISPATCHER, false);
        IdentifierNode identifier = nodeFactory.identifier(HAS_EVENT_LISTENER, false);
        MemberExpressionNode typeGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, TYPE, false);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, typeGetterSelector);
        CallExpressionNode callExpression =
            (CallExpressionNode) nodeFactory.callExpression(identifier, argumentList);
        callExpression.setRValue(false);
        MemberExpressionNode memberExpression =
            nodeFactory.memberExpression(_bindingEventDispatcherGetterSelector, callExpression);
        ListNode returnList = nodeFactory.list(null, memberExpression);
        ReturnStatementNode returnStatement = nodeFactory.returnStatement(returnList);

        StatementListNode functionStatementList = nodeFactory.statementList(null, returnStatement);

        FunctionCommonNode functionCommon = nodeFactory.functionCommon(context, null, functionSignature,
                                                                       functionStatementList);
        functionCommon.setUserDefinedBody(true);

        return nodeFactory.functionDefinition(context, attributeList, functionName, functionCommon);
    }

    private ListNode generateOldValueStrictlyNotEqualsValueText(NodeFactory nodeFactory)
    {
        // Equivalent AS:
        //
        // if (oldValue !== value)
        MemberExpressionNode oldValueMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, OLD_VALUE, false);
        MemberExpressionNode valueMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, VALUE, false);
        BinaryExpressionNode binaryExpression = nodeFactory.binaryExpression(Tokens.STRICTNOTEQUALS_TOKEN,
                                                                             oldValueMemberExpression,
                                                                             valueMemberExpression);
        return nodeFactory.list(null, binaryExpression);
    }

    private VariableDefinitionNode generateOldValueVariable(NodeFactory nodeFactory,
                                                            String setterAccessPropertyName)
    {
        // Equivalent AS:
        //
        //   var oldValue:Object = this.$setterAccessPropertyName;
        ThisExpressionNode thisExpression = nodeFactory.thisExpression(0);
        IdentifierNode identifer =
            AbstractSyntaxTreeUtil.generateIdentifier(nodeFactory, setterAccessPropertyName, false);
        GetExpressionNode getExpression = nodeFactory.getExpression(identifer);
        MemberExpressionNode memberExpression = nodeFactory.memberExpression(thisExpression, getExpression);
        return AbstractSyntaxTreeUtil.generateVariable(nodeFactory, OLD_VALUE, OBJECT, false, memberExpression);
    }

    private FunctionDefinitionNode generateRemoveEventListenerFunctionDefinition(Context context)
    {
        // Equivalent AS:
        //
        //    public function removeEventListener(type:String,
        //                                        listener:Function,
        //                                        useCapture:Boolean = false):void
        //    {
        //        _bindingEventDispatcher.removeEventListener(type, listener, useCapture);
        //    }
        NodeFactory nodeFactory = context.getNodeFactory();

        AttributeListNode attributeList = AbstractSyntaxTreeUtil.generatePublicAttribute(nodeFactory);

        IdentifierNode removeEventListenerIdentifier = nodeFactory.identifier(REMOVE_EVENT_LISTENER, false);
        FunctionNameNode functionName = nodeFactory.functionName(Tokens.EMPTY_TOKEN, removeEventListenerIdentifier);

        ParameterNode typeParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, TYPE, STRING, false);
        ParameterListNode parameterList = nodeFactory.parameterList(null, typeParameter);
        ParameterNode listenerParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, LISTENER, FUNCTION, false);
        parameterList = nodeFactory.parameterList(parameterList, listenerParameter);
        LiteralBooleanNode literalBoolean = nodeFactory.literalBoolean(false);
        ParameterNode useCaptureParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, USE_CAPTURE, BOOLEAN,
                                                     false, literalBoolean);
        parameterList = nodeFactory.parameterList(parameterList, useCaptureParameter);
        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(parameterList, null);
        functionSignature.void_anno = true;

        MemberExpressionNode _bindingEventDispatcherGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, _BINDING_EVENT_DISPATCHER, false);
        IdentifierNode identifier = nodeFactory.identifier(REMOVE_EVENT_LISTENER, false);
        MemberExpressionNode typeGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, TYPE, false);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, typeGetterSelector);
        MemberExpressionNode listenerGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, LISTENER, false);
        argumentList = nodeFactory.argumentList(argumentList, listenerGetterSelector);
        MemberExpressionNode useCaptureGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, USE_CAPTURE, false);
        argumentList = nodeFactory.argumentList(argumentList, useCaptureGetterSelector);
        CallExpressionNode callExpression =
            (CallExpressionNode) nodeFactory.callExpression(identifier, argumentList);
        callExpression.setRValue(false);
        MemberExpressionNode memberExpression =
            nodeFactory.memberExpression(_bindingEventDispatcherGetterSelector, callExpression);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement = nodeFactory.expressionStatement(list);

        StatementListNode functionStatementList = nodeFactory.statementList(null, expressionStatement);

        FunctionCommonNode functionCommon = nodeFactory.functionCommon(context, null, functionSignature,
                                                                       functionStatementList);
        functionCommon.setUserDefinedBody(true);

        return nodeFactory.functionDefinition(context, attributeList, functionName, functionCommon);
    }

    private FunctionDefinitionNode generateSetter(Context context, String className, AccessorInfo accessorInfo)
    {
        // Equivalent AS:
        //
        //   $entry.attributeString function set ${entry.propertyName}(value:${entry.typeName}):void
        NodeFactory nodeFactory = context.getNodeFactory();
        int position = -1;

        if (accessorInfo instanceof VariableInfo)
        {
            position = ((VariableInfo) accessorInfo).getPosition();
        }
        else if (accessorInfo instanceof GetterSetterInfo)
        {
            position = ((GetterSetterInfo) accessorInfo).getSetterPosition();
        }

        ParameterNode parameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, VALUE, accessorInfo.getTypeName(), true, position);
        ParameterListNode parameterList = nodeFactory.parameterList(null, parameter);
        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(parameterList, null);
        functionSignature.void_anno = true;
        AttributeListNode attributeList = generateAttributeList(nodeFactory, accessorInfo.getAttributeString());
        IdentifierNode propertyNameIdentifier = nodeFactory.identifier(accessorInfo.getPropertyName());
        FunctionNameNode functionName = nodeFactory.functionName(Tokens.SET_TOKEN, propertyNameIdentifier);
        StatementListNode functionStatementList;
        String qualifiedBackingPropertyName = accessorInfo.getQualifiedBackingPropertyName().intern();
        String setterAccessPropertyName;

        if (accessorInfo.getIsFunction())
        {
            setterAccessPropertyName = accessorInfo.getQualifiedPropertyName().intern();
        }
        else
        {
            setterAccessPropertyName = qualifiedBackingPropertyName;
        }

        if (accessorInfo.getIsStatic())
        {
            VariableDefinitionNode variableDefinition =
                generateStaticOldValueVariable(nodeFactory, className, setterAccessPropertyName);
            functionStatementList = nodeFactory.statementList(null, variableDefinition);

            ListNode test = generateOldValueStrictlyNotEqualsValueText(nodeFactory);
            StatementListNode then =
                generateStaticSetterAssignment(nodeFactory, className, qualifiedBackingPropertyName);
            then = generateStaticDispatchEventCall(nodeFactory, then, className, accessorInfo.getQualifiedPropertyName());

            Node ifStatement = nodeFactory.ifStatement(test, then, null);
            functionStatementList = nodeFactory.statementList(functionStatementList, ifStatement);
        }
        else
        {
            VariableDefinitionNode variableDefinition = generateOldValueVariable(nodeFactory, setterAccessPropertyName);
            functionStatementList = nodeFactory.statementList(null, variableDefinition);

            ListNode test = generateOldValueStrictlyNotEqualsValueText(nodeFactory);
            StatementListNode then = generateSetterAssignment(nodeFactory, qualifiedBackingPropertyName);
            then = generateDispatchEventCall(nodeFactory, then, accessorInfo.getQualifiedPropertyName());

            Node ifStatement = nodeFactory.ifStatement(test, then, null);;
            functionStatementList = nodeFactory.statementList(functionStatementList, ifStatement);
        }

        FunctionCommonNode functionCommon = nodeFactory.functionCommon(context, null, functionSignature,
                                                                       functionStatementList);
        functionCommon.setUserDefinedBody(true);

        return nodeFactory.functionDefinition(context, attributeList, functionName, functionCommon);
    }

    private StatementListNode generateSetterAssignment(NodeFactory nodeFactory,
                                                       String qualifiedBackingPropertyName)
    {
        // Equivalent AS:
        //
        //   this.${entry.qualifiedBackingPropertyName} = value;
        ThisExpressionNode outerThisExpression = nodeFactory.thisExpression(0);
        IdentifierNode identifier =
            AbstractSyntaxTreeUtil.generateIdentifier(nodeFactory, qualifiedBackingPropertyName, false);
        MemberExpressionNode getterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, VALUE, false);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, getterSelector);
        SetExpressionNode setExpression = nodeFactory.setExpression(identifier, argumentList, false);
        MemberExpressionNode memberExpression = nodeFactory.memberExpression(outerThisExpression, setExpression);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement =
            nodeFactory.expressionStatement(list);
        return nodeFactory.statementList(null, expressionStatement);
    }

    private VariableDefinitionNode generateStaticBindingEventDispatcherVariable(NodeFactory nodeFactory)
    {
        // Equivalent AS:
        //
        //    private static var _staticBindingEventDispatcher:flash.events.EventDispatcher =
        //        new flash.events.EventDispatcher();
        AttributeListNode attributeList = AbstractSyntaxTreeUtil.generatePrivateStaticAttribute(nodeFactory);
        IdentifierNode _staticBindingEventDispatcherIdentifier = nodeFactory.identifier(_STATIC_BINDING_EVENT_DISPATCHER, false);
        QualifiedIdentifierNode qualifiedIdentifier =
            AbstractSyntaxTreeUtil.generateQualifiedIdentifier(nodeFactory, FLASH_EVENTS,
                                                               EVENT_DISPATCHER_CLASS, false);
        CallExpressionNode callExpression =
            (CallExpressionNode) nodeFactory.callExpression(qualifiedIdentifier, null);
        callExpression.is_new = true;
        callExpression.setRValue(false);
        MemberExpressionNode memberExpression = nodeFactory.memberExpression(null, callExpression);
        return AbstractSyntaxTreeUtil.generateVariable(nodeFactory, attributeList,
                                                       _staticBindingEventDispatcherIdentifier,
                                                       FLASH_EVENTS, EVENT_DISPATCHER_CLASS,
                                                       false, memberExpression);

    }

    private StatementListNode generateStaticDispatchEventCall(NodeFactory nodeFactory, StatementListNode outerThen,
                                                              String className, String qualifiedPropertyName)
    {
        // Equivalent AS:
        //
        //   var eventDispatcher:IEventDispatcher = ${bindableInfo.className}.staticEventDispatcher;
        MemberExpressionNode base = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, className, false);
        IdentifierNode staticEventDispatcherIdentifier = nodeFactory.identifier(STATIC_EVENT_DISPATCHER, false);
        GetExpressionNode selector = nodeFactory.getExpression(staticEventDispatcherIdentifier);
        MemberExpressionNode rvalue = nodeFactory.memberExpression(base, selector);
        VariableDefinitionNode variableDefinition =
            AbstractSyntaxTreeUtil.generateVariable(nodeFactory, EVENT_DISPATCHER_VAR,
                                                    FLASH_EVENTS, I_EVENT_DISPATCHER,
                                                    false, rvalue);
        outerThen = nodeFactory.statementList(outerThen, variableDefinition);
       
        ListNode test = generateEventDispatcherNotNull(nodeFactory);

        // Equivalent AS:
        //
        //   eventDispatcher.dispatchEvent(mx.events.PropertyChangeEvent.createUpdateEvent(${bindableInfo.className}, "$entry.qualifiedPropertyName", oldValue, value));
        IdentifierNode dispatchEventIdentifier = nodeFactory.identifier(DISPATCH_EVENT, false);

        MemberExpressionNode propertyChangeEventMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, MX_EVENTS, PROPERTY_CHANGE_EVENT, false);;
        IdentifierNode createUpdateEventIdentifier = nodeFactory.identifier(CREATE_UPDATE_EVENT, false);
        MemberExpressionNode getterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, className, false);
        ArgumentListNode createUpdateEventArgumentList = nodeFactory.argumentList(null, getterSelector);

        LiteralStringNode literalString = nodeFactory.literalString(qualifiedPropertyName);
        createUpdateEventArgumentList = nodeFactory.argumentList(createUpdateEventArgumentList, literalString);

        MemberExpressionNode oldValueMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, OLD_VALUE, false);
        createUpdateEventArgumentList =
            nodeFactory.argumentList(createUpdateEventArgumentList, oldValueMemberExpression);

        MemberExpressionNode valueMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, VALUE, false);
        createUpdateEventArgumentList =
            nodeFactory.argumentList(createUpdateEventArgumentList, valueMemberExpression);

        CallExpressionNode createUpdateEventCallExpression =
            (CallExpressionNode) nodeFactory.callExpression(createUpdateEventIdentifier, createUpdateEventArgumentList);
        createUpdateEventCallExpression.setRValue(false);
        MemberExpressionNode createUpdateEventMemberExpression =
            nodeFactory.memberExpression(propertyChangeEventMemberExpression, createUpdateEventCallExpression);
        ArgumentListNode dispatchEventArgumentList =
            nodeFactory.argumentList(null, createUpdateEventMemberExpression);
        CallExpressionNode dispatchEventCallExpression =
            (CallExpressionNode) nodeFactory.callExpression(dispatchEventIdentifier, dispatchEventArgumentList);
        dispatchEventCallExpression.setRValue(false);
        MemberExpressionNode eventDispatcherMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, EVENT_DISPATCHER_VAR, false);
        MemberExpressionNode memberExpression =
            nodeFactory.memberExpression(eventDispatcherMemberExpression, dispatchEventCallExpression);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement =
            nodeFactory.expressionStatement(list);
        StatementListNode then = nodeFactory.statementList(null, expressionStatement);

        Node ifStatement = nodeFactory.ifStatement(test, then, null);
        return nodeFactory.statementList(outerThen, ifStatement);
    }

    private FunctionDefinitionNode generateStaticEventDispatcherGetter(Context context)
    {
        // Equivalent AS:
        //
        //    public static function get staticEventDispatcher():IEventDispatcher
        //    {
        //        return _staticBindingEventDispatcher;
        //    }
        NodeFactory nodeFactory = context.getNodeFactory();
        MemberExpressionNode returnTypeMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, I_EVENT_DISPATCHER, true);
        TypeExpressionNode returnType = nodeFactory.typeExpression(returnTypeMemberExpression, true, false, -1);
        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(null, returnType);
        AttributeListNode attributeList = AbstractSyntaxTreeUtil.generatePublicStaticAttribute(nodeFactory);
        IdentifierNode staticEventDispatcherIdentifier = nodeFactory.identifier(STATIC_EVENT_DISPATCHER, false);
        FunctionNameNode functionName = nodeFactory.functionName(Tokens.GET_TOKEN, staticEventDispatcherIdentifier);
        MemberExpressionNode memberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, _STATIC_BINDING_EVENT_DISPATCHER, false);
        ListNode returnList = nodeFactory.list(null, memberExpression);
        ReturnStatementNode returnStatement = nodeFactory.returnStatement(returnList);
        StatementListNode functionStatementList = nodeFactory.statementList(null, returnStatement);
        FunctionCommonNode functionCommon = nodeFactory.functionCommon(context, null, functionSignature,
                                                                       functionStatementList);
        functionCommon.setUserDefinedBody(true);
        return nodeFactory.functionDefinition(context, attributeList, functionName, functionCommon);
    }

    private VariableDefinitionNode generateStaticOldValueVariable(NodeFactory nodeFactory,
                                                                  String className,
                                                                  String qualifiedBackingPropertyName)
    {
        // Equivalent AS:
        //
        //   var oldValue:Object = ${bindableInfo.className}.$setterAccessPropertyName;
        MemberExpressionNode base = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, className, false);
        IdentifierNode identifer = nodeFactory.identifier(qualifiedBackingPropertyName, false);
        GetExpressionNode getExpression = nodeFactory.getExpression(identifer);
        MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, getExpression);
        return AbstractSyntaxTreeUtil.generateVariable(nodeFactory, OLD_VALUE, OBJECT, false, memberExpression);
    }

    private StatementListNode generateStaticSetterAssignment(NodeFactory nodeFactory, String className,
                                                             String qualifiedBackingPropertyName)
    {
        // Equivalent AS:
        //
        //   ${bindableInfo.className}.${entry.qualifiedBackingPropertyName} = value;
        MemberExpressionNode base = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, className, false);       
        IdentifierNode identifier =
            AbstractSyntaxTreeUtil.generateIdentifier(nodeFactory, qualifiedBackingPropertyName, false);
        MemberExpressionNode getterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, VALUE, false);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, getterSelector);
        SetExpressionNode setExpression = nodeFactory.setExpression(identifier, argumentList, false);
        MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, setExpression);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement =
            nodeFactory.expressionStatement(list);
        return nodeFactory.statementList(null, expressionStatement);
    }

    private FunctionDefinitionNode generateWillTriggerFunctionDefinition(Context context)
    {
        // Equivalent AS:
        //
        //    public function willTrigger(type:String):Boolean
        //    {
        //        return _bindingEventDispatcher.willTrigger(type);
        //    }
        NodeFactory nodeFactory = context.getNodeFactory();
        AttributeListNode attributeList = AbstractSyntaxTreeUtil.generatePublicAttribute(nodeFactory);

        IdentifierNode willTriggerIdentifier = nodeFactory.identifier(WILL_TRIGGER, false);
        FunctionNameNode functionName = nodeFactory.functionName(Tokens.EMPTY_TOKEN, willTriggerIdentifier);

        ParameterNode typeParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, TYPE, STRING, false);
        ParameterListNode parameterList = nodeFactory.parameterList(null, typeParameter);
        MemberExpressionNode returnTypeMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, BOOLEAN, true);
        TypeExpressionNode returnType = nodeFactory.typeExpression(returnTypeMemberExpression, true, false, -1);
        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(parameterList, returnType);

        MemberExpressionNode _bindingEventDispatcherGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, _BINDING_EVENT_DISPATCHER, false);
        IdentifierNode identifier = nodeFactory.identifier(WILL_TRIGGER, false);
        MemberExpressionNode typeGetterSelector =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, TYPE, false);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, typeGetterSelector);
        CallExpressionNode callExpression =
            (CallExpressionNode) nodeFactory.callExpression(identifier, argumentList);
        callExpression.setRValue(false);

        MemberExpressionNode memberExpression =
            nodeFactory.memberExpression(_bindingEventDispatcherGetterSelector, callExpression);
        ListNode returnList = nodeFactory.list(null, memberExpression);
        ReturnStatementNode returnStatement = nodeFactory.returnStatement(returnList);

        StatementListNode functionStatementList = nodeFactory.statementList(null, returnStatement);

        FunctionCommonNode functionCommon = nodeFactory.functionCommon(context, null, functionSignature,
                                                                       functionStatementList);
        functionCommon.setUserDefinedBody(true);

        return nodeFactory.functionDefinition(context, attributeList, functionName, functionCommon);
    }

  protected void modifySyntaxTree(Context context, ClassDefinitionNode classDefinition,
                                    BindableInfo bindableInfo)
  {
        if (generateAbstractSyntaxTree)
        {
            Map<QName, AccessorInfo> accessors = bindableInfo.getAccessors();

            if (accessors != null)
            {
                for (AccessorInfo accessorInfo : accessors.values())
                {
                    NodeFactory nodeFactory = context.getNodeFactory();
                    String className = bindableInfo.getClassName().intern();
                    StatementListNode statementList = classDefinition.statements;

                    if (!accessorInfo.getIsFunction())
                    {
                        FunctionDefinitionNode getter = generateGetter(context, className, accessorInfo);

                        moveMetaDataToNewDefinition(nodeFactory, accessorInfo.getDefinitionNode(),
                                                    getter, statementList, true);

                        nodeFactory.statementList(statementList, getter);
                    }

                    FunctionDefinitionNode setter = generateSetter(context, className, accessorInfo);

                    if (accessorInfo.getIsFunction())
                    {
                        GetterSetterInfo getterSetterInfo = (GetterSetterInfo) accessorInfo;
                        boolean processedBindable =
                            processGetterMetaData(nodeFactory,
                                                  getterSetterInfo.getGetterFunctionDefinition());
                        moveMetaDataToNewDefinition(nodeFactory,
                                                    getterSetterInfo.getSetterFunctionDefinition(),
                                                    setter, statementList, !processedBindable);
                    }

                    nodeFactory.statementList(statementList, setter);
                }
            }

            if (bindableInfo.getNeedsToImplementIEventDispatcher())
            {
                addIEventDispatcherImplementation(context, classDefinition);
            }

            if (bindableInfo.getNeedsStaticEventDispatcher())
            {
                addStaticEventDispatcherImplementation(context, classDefinition);
            }
        }
        else
        {
            super.modifySyntaxTree(context, classDefinition, bindableInfo);
        }
  }

    /**
     * Moves metadata from the initial definition to the new
     * definition.  If emtpy Bindable metadata is found, an event
     * attribute is added to it.
     */
    private void moveMetaDataToNewDefinition(NodeFactory nodeFactory,
                                             DefinitionNode fromDefinition,
                                             DefinitionNode toDefinition,
                                             StatementListNode classDefinitionStatementList,
                                             boolean addBindableMetaData)
    {
        boolean processedBindableMetaData = false;

        if ((fromDefinition != null) && (fromDefinition.metaData != null))
        {
            for (Node node : fromDefinition.metaData.items)
            {
                MetaDataNode metaData = (MetaDataNode) node;

                if ((metaData.getId() != null) &&
                    metaData.getId().equals(StandardDefs.MD_BINDABLE) &&
                    metaData.count() == 0)
                {
                    processBindableMetaData(nodeFactory, metaData);
                    processedBindableMetaData = true;
                }

                metaData.def = toDefinition;
                classDefinitionStatementList.items.remove(metaData);
                nodeFactory.statementList(classDefinitionStatementList, metaData);
                toDefinition.metaData = nodeFactory.statementList(toDefinition.metaData, metaData);
            }

            fromDefinition.metaData = null;
        }

        if (addBindableMetaData && !processedBindableMetaData)
        {
            MetaDataNode bindableMetaData =
                AbstractSyntaxTreeUtil.generateMetaData(nodeFactory, BINDABLE,
                                                        EVENT_VAR, PROPERTY_CHANGE);
            nodeFactory.statementList(classDefinitionStatementList, bindableMetaData);           
            prepMetaDataNode(nodeFactory.getContext(), bindableMetaData);
        }
    }

    /**
     * Added an event attribute to Bindable metadata.
     */
    private void processBindableMetaData(NodeFactory nodeFactory, MetaDataNode metaData)
    {
        assert metaData.count() == 0;

        Value[] vals =  new Value[1];
        vals[0] = new macromedia.asc.parser.MetaDataEvaluator.KeyValuePair(EVENT_VAR, PROPERTY_CHANGE);
        metaData.setValues(vals);
        prepMetaDataNode(nodeFactory.getContext(), metaData);
    }

    /**
     * Looks for empty Bindable metadata and if found, adds an event attribute to it.
     */
    private boolean processGetterMetaData(NodeFactory nodeFactory, FunctionDefinitionNode getter)
    {
        boolean processedBindableMetaData = false;       

        if ((getter != null) && (getter.metaData != null))
        {
            for (Node node : getter.metaData.items)
            {
                MetaDataNode metaData = (MetaDataNode) node;

                if ((metaData.getId() != null) &&
                    metaData.getId().equals(StandardDefs.MD_BINDABLE) &&
                    metaData.count() == 0)
                {
                    processBindableMetaData(nodeFactory, metaData);
                    processedBindableMetaData = true;
                }
            }
        }

        return processedBindableMetaData;
    }

  /**
   * prepare class def node for augmentation. Currently, all we need to do is strip class-level [Bindable] md.
   */
  private void prepClassDef(ClassDefinitionNode node)
  {
    if (node.metaData != null && node.metaData.items != null)
    {
      for (Iterator iter = node.metaData.items.iterator(); iter.hasNext(); )
      {
        MetaDataNode md = (MetaDataNode)iter.next();
        if (StandardDefs.MD_BINDABLE.equals(md.getId()) && md.count() == 0)
        {
          iter.remove();
        }
      }
    }
  }

  /**
   * Hide *setters* which have had bindable versions generated. Getters are not wrapped.
   *
   * In BindableFirstPassEvaluator we visited the interior of a function definition, in order to generate errors on
   * [Bindable] metadata we found there. Here we avoid FunctionDefinitionNodes because the VariableDefinitionNodes
   * within them might otherwise be spuriously renamed.
   */
  public Value evaluate(Context context, FunctionDefinitionNode node)
  {
    if (inClass)
    {
      QName qname = new QName(NodeMagic.getUserNamespace(node), NodeMagic.getFunctionName(node));
      GenerativeClassInfo.AccessorInfo accessorInfo = bindableInfo.getAccessor(qname);

      if (accessorInfo instanceof GetterSetterInfo)
      {
        if (NodeMagic.functionIsSetter(node))
        {
          hideFunction(node, accessorInfo);
          registerRenamedAccessor(accessorInfo);
                    ((GetterSetterInfo) accessorInfo).setSetterInfo(node);
        }
                else
                {
                    ((GetterSetterInfo) accessorInfo).setGetterInfo(node);

                    if (!bindableInfo.getClassInfo().definesSetter(qname.getLocalPart(), false))
                    {
                        context.localizedError2(node.pos(), new MissingNonInheritedSetter(qname.getLocalPart()));
                    }
                }
      }
    }

    return null;
  }

  /**
   * visits all variable definitions that occur inside class definitions, outside function definitions, and mangles
   * their names if they've been marked for [Bindable] codegen.
   */
  public Value evaluate(Context context, VariableDefinitionNode node)
  {
    if (inClass)
    {
      QName qname = new QName(NodeMagic.getUserNamespace(node), NodeMagic.getVariableName(node));
      GenerativeClassInfo.AccessorInfo accessorInfo = bindableInfo.getAccessor(qname);
      if (accessorInfo != null)
      {
        hideVariable(node, accessorInfo);
        registerRenamedAccessor(accessorInfo);
      }
    }

    return null;
  }

  /**
   *
   */
  protected String getTemplateName()
  {
    return standardDefs.getBindablePropertyTemplate();
  }

  protected String getTemplatePath()
  {
    return CODEGEN_TEMPLATE_PATH;
  }

  /**
   *
   */
  protected Map<String, BindableInfo> getTemplateVars()
  {
    Map<String, BindableInfo> vars = new HashMap<String, BindableInfo>();
    vars.put("bindableInfo", bindableInfo);

    return vars;
  }

  /**
   *
   */
  protected String getGeneratedSuffix()
  {
    return "-binding-generated.as";
  }

  public static class MissingNonInheritedSetter extends CompilerMessage.CompilerError
  {
    private static final long serialVersionUID = -1787062656834309810L;
        public String getter;

    public MissingNonInheritedSetter(String getter)
    {
      this.getter = getter;
    }
  }
}
TOP

Related Classes of flex2.compiler.as3.binding.BindableSecondPassEvaluator

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.