Package flex2.compiler.as3.binding

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

/*
*
*  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.CompilerContext;
import flex2.compiler.Source;
import flex2.compiler.SymbolTable;
import flex2.compiler.as3.AbstractSyntaxTreeUtil;
import flex2.compiler.as3.As3Compiler;
import flex2.compiler.as3.Extension;
import flex2.compiler.as3.reflect.TypeTable;
import flex2.compiler.common.PathResolver;
import flex2.compiler.io.FileUtil;
import flex2.compiler.io.TextFile;
import flex2.compiler.io.VirtualFile;
import flex2.compiler.mxml.SourceCodeBuffer;
import flex2.compiler.mxml.gen.VelocityUtil;
import flex2.compiler.mxml.lang.StandardDefs;
import flex2.compiler.mxml.rep.BindingExpression;
import flex2.compiler.util.*;
import macromedia.asc.embedding.ConfigVar;
import macromedia.asc.parser.*;
import macromedia.asc.util.Context;
import macromedia.asc.util.ObjectList;
import org.apache.flex.forks.velocity.Template;
import org.apache.flex.forks.velocity.VelocityContext;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* This compiler extension handles running the
* DataBindingFirstPassEvaluator during the generate phase and
* generating watchers if the original MXML document contained one or more data
* binding expressions.
*
* @author Paul Reilly
*/
public final class DataBindingExtension implements Extension
{
    private static final String TEMPLATE_PATH = "flex2/compiler/as3/binding/";
    private static final String DATA_BINDING_INFO_KEY = "dataBindingInfo";

    private static final String DOT = ".";
    private static final String DOT_AS = ".as";
    private static final String EMPTY_STRING = "";

    // intern all identifier constants
    private static final String ADD_CHILD = "addChild".intern();
    private static final String APPLY = "apply".intern();
    private static final String ARRAY = "Array".intern();
    private static final String ARRAY_ELEMENT_WATCHER = "ArrayElementWatcher".intern();
    private static final String ARRAY_WATCHER = "arrayWatcher".intern();
    private static final String BINDINGS = "bindings".intern();
    private static final String EXCLUDE_CLASS = "ExcludeClass".intern();
    private static final String FBS = "fbs".intern();
    private static final String FUNCTION = "Function".intern();
    private static final String FUNCTION_RETURN_WATCHER = "FunctionReturnWatcher".intern();
    private static final String IFLEX_MODULE_FACTORY = "IFlexModuleFactory".intern();
    private static final String INIT = "init".intern();
    private static final String IWATCHER_SETUP_UTIL2 = "IWatcherSetupUtil2".intern();
    private static final String OBJECT = "Object".intern();
    private static final String PARENT_WATCHER = "parentWatcher".intern();
    private static final String PROPERTY_GETTER = "propertyGetter".intern();
    private static final String PROPERTY_WATCHER = "PropertyWatcher".intern();
    private static final String REPEATER_COMPONENT_WATCHER = "RepeaterComponentWatcher".intern();
    private static final String REPEATER_ITEM_WATCHER = "RepeaterItemWatcher".intern();
    private static final String SETUP = "setup".intern();
    private static final String STATIC_PROPERTY_GETTER = "staticPropertyGetter".intern();
    private static final String STATIC_PROPERTY_WATCHER = "StaticPropertyWatcher".intern();
    private static final String TARGET = "target".intern();
    private static final String UPDATE_PARENT = "updateParent".intern();
    private static final String WATCHERS = "watchers".intern();
    private static final String WATCHER_SETUP_UTIL = "watcherSetupUtil".intern();
    private static final String XML_WATCHER = "XMLWatcher".intern();

    private String generatedOutputDirectory;
    private boolean showBindingWarnings;
    private boolean generateAbstractSyntaxTree;
    private ObjectList<ConfigVar> defines;

    public DataBindingExtension(String generatedOutputDirectory, boolean showBindingWarnings,
                                boolean generateAbstractSyntaxTree, ObjectList<ConfigVar> defines)
    {
        this.generatedOutputDirectory = generatedOutputDirectory;
        this.showBindingWarnings = showBindingWarnings;
        this.generateAbstractSyntaxTree = generateAbstractSyntaxTree;
        this.defines = defines;
    }

    public void parse1(CompilationUnit compilationUnit, TypeTable typeTable)
    {
    }

    public void parse2(CompilationUnit compilationUnit, TypeTable typeTable)
    {
    }

    public void analyze1(CompilationUnit compilationUnit, TypeTable typeTable)
    {
    }

    public void analyze2(CompilationUnit compilationUnit, TypeTable typeTable)
    {
    }

    public void analyze3(CompilationUnit compilationUnit, TypeTable typeTable)
    {
    }

    public void analyze4(CompilationUnit compilationUnit, TypeTable typeTable)
    {
    }

    public void generate(CompilationUnit compilationUnit, TypeTable typeTable)
    {
        CompilerContext context = compilationUnit.getContext();
        Context cx = context.getAscContext();
        Node node = (Node) compilationUnit.getSyntaxTree();
        DataBindingFirstPassEvaluator dataBindingFirstPassEvaluator =
            new DataBindingFirstPassEvaluator(compilationUnit, typeTable, showBindingWarnings);

        node.evaluate(cx, dataBindingFirstPassEvaluator);

        List dataBindingInfoList = dataBindingFirstPassEvaluator.getDataBindingInfoList();

        if (dataBindingInfoList.size() > 1)
        {
            assert false : compilationUnit.getSource().getName();
        }

        if (dataBindingInfoList.size() > 0)
        {
          // watcher setup classes should match the originating source timestamp.
            Map<QName, Source> generatedSources = generateWatcherSetupUtilClasses(compilationUnit,
                                                                   typeTable.getSymbolTable(),
                                                                   dataBindingInfoList);
            compilationUnit.addGeneratedSources(generatedSources);
        }
    }

    /**
     *
     */
    private Source createSource(String fileName, String shortName, long lastModified,
                  PathResolver resolver, SourceCodeBuffer sourceCodeBuffer)
    {
        Source result = null;

        if (sourceCodeBuffer.getBuffer() != null)
        {
            String sourceCode = sourceCodeBuffer.toString();

            if (generatedOutputDirectory != null)
            {
                try
                {
                    FileUtil.writeFile(generatedOutputDirectory + File.separatorChar + fileName, sourceCode);
                }
                catch (IOException e)
                {
                    ThreadLocalToolkit.log(new VelocityException.UnableToWriteGeneratedFile(fileName, e.getMessage()));
                }
            }

      VirtualFile generatedFile = new TextFile(sourceCode, fileName, null, MimeMappings.AS, lastModified);

            result = new Source(generatedFile,
                                "",
                                shortName,
                                null,
                                false,
                                false,
                                false);
            result.setPathResolver(resolver);
        }

        return result;
    }

    private FunctionCommonNode generateAccessorFunction(NodeFactory nodeFactory, Context cx,
                                                        HashSet<String> configNamespaces,
                                                        ArrayElementWatcher arrayElementWatcher)
    {
        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(null, null);

        List<Node> nodeList = AbstractSyntaxTreeUtil.parseExpression(cx, configNamespaces,
                                                                     arrayElementWatcher.getEvaluationPart());
        ListNode list = null;

        assert (nodeList.size() == 0) || (nodeList.size() == 1) : nodeList.size();

        if (!nodeList.isEmpty())
        {
            ExpressionStatementNode expressionStatement = (ExpressionStatementNode) nodeList.get(0);
            list = (ListNode) expressionStatement.expr;
        }

        ReturnStatementNode returnStatement = nodeFactory.returnStatement(list);
        StatementListNode statementList = nodeFactory.statementList(null, returnStatement);

        return nodeFactory.functionCommon(cx, null, functionSignature, statementList);
    }

    private FunctionCommonNode generateAccessorFunction(NodeFactory nodeFactory, Context cx,
                                                        HashSet<String> configNamespaces,
                                                        FunctionReturnWatcher functionReturnWatcher)
    {
        MemberExpressionNode memberExpression = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, ARRAY, false);
        TypeExpressionNode returnType = nodeFactory.typeExpression(memberExpression, true, false, -1);
        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(null, returnType);

        List<Node> nodeList = AbstractSyntaxTreeUtil.parseExpression(cx, configNamespaces,
                                                                     functionReturnWatcher.getEvaluationPart());
        ArgumentListNode argumentList = null;

        assert (nodeList.size() == 0) || (nodeList.size() == 1) : nodeList.size();

        if (!nodeList.isEmpty())
        {
            ExpressionStatementNode expressionStatement = (ExpressionStatementNode) nodeList.get(0);
            ListNode list = (ListNode) expressionStatement.expr;
            Iterator<Node> iterator = list.items.iterator();

            while (iterator.hasNext())
            {
                argumentList = nodeFactory.argumentList(argumentList, iterator.next());
            }
        }

        LiteralArrayNode literalArray = nodeFactory.literalArray(argumentList);
        ListNode outerList = nodeFactory.list(null, literalArray);
        ReturnStatementNode returnStatement = nodeFactory.returnStatement(outerList);
        StatementListNode statementList = nodeFactory.statementList(null, returnStatement);

        return nodeFactory.functionCommon(cx, null, functionSignature, statementList);
    }

    private ExpressionStatementNode generateAddChild(NodeFactory nodeFactory, Watcher watcher)
    {
        MemberExpressionNode watchersMemberExpression = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);

        GetExpressionNode getExpression = generateArrayIndex(nodeFactory, watcher.getParent().getId());
        getExpression.setMode(Tokens.LEFTBRACKET_TOKEN);
        MemberExpressionNode base = nodeFactory.memberExpression(watchersMemberExpression, getExpression);

        IdentifierNode identifier = nodeFactory.identifier(ADD_CHILD, false);
        MemberExpressionNode childBase = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);
        GetExpressionNode childSelector = generateArrayIndex(nodeFactory, watcher.getId());
        childSelector.setMode(Tokens.LEFTBRACKET_TOKEN);
        MemberExpressionNode childMemberExpression = nodeFactory.memberExpression(childBase, childSelector);

        ArgumentListNode args = nodeFactory.argumentList(null, childMemberExpression);
        CallExpressionNode selector = (CallExpressionNode) nodeFactory.callExpression(identifier, args);
        selector.setRValue(false);

        MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, selector);
        ListNode list = nodeFactory.list(null, memberExpression);
        return nodeFactory.expressionStatement(list);
    }

    private GetExpressionNode generateArrayIndex(NodeFactory nodeFactory, int index)
    {
        LiteralNumberNode literalNumber = nodeFactory.literalNumber(index);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, literalNumber);
        return nodeFactory.getExpression(argumentList);
    }

    private Node generateChangeEvents(NodeFactory nodeFactory, Watcher watcher)
    {
        Node result;
        Iterator<ChangeEvent> iterator = watcher.getChangeEvents().iterator();

        if (iterator.hasNext())
        {
            ArgumentListNode argumentList = null;

            while (iterator.hasNext())
            {
                ChangeEvent changeEvent = iterator.next();
                IdentifierNode identifierNode = nodeFactory.identifier(changeEvent.getName());
                LiteralBooleanNode literalBoolean = nodeFactory.literalBoolean(changeEvent.getCommitting());
                LiteralFieldNode literalField = nodeFactory.literalField(identifierNode, literalBoolean);
                argumentList = nodeFactory.argumentList(argumentList, literalField);
            }

            result = nodeFactory.literalObject(argumentList);
        }
        else
        {
            result = nodeFactory.literalNull();
        }

        return result;
    }

    private ClassDefinitionNode generateClassDefinition(Context cx, HashSet<String> configNamespaces,
                                                        String name, DataBindingInfo dataBindingInfo,
                                                        StandardDefs standardDefs)
    {
        NodeFactory nodeFactory = cx.getNodeFactory();
        nodeFactory.StartClassDefs();
        MemberExpressionNode iWatcherSetupUtilMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, standardDefs.getBindingPackage(), IWATCHER_SETUP_UTIL2, false);
        ListNode interfaces = nodeFactory.list(null, iWatcherSetupUtilMemberExpression);
        InheritanceNode inheritance = nodeFactory.inheritance(null, interfaces);

        FunctionDefinitionNode constructorFunctionDefinition =
            AbstractSyntaxTreeUtil.generateConstructor(cx, name, null, true, null, -1);
        StatementListNode statementList = nodeFactory.statementList(null, constructorFunctionDefinition);

        FunctionCommonNode initFunctionCommon = generateInitFunctionCommon(nodeFactory, cx, dataBindingInfo);
        initFunctionCommon.setUserDefinedBody(true);
        FunctionDefinitionNode initFunctionDefinition = generateInitFunctionDefinition(nodeFactory, cx, initFunctionCommon);
        statementList = nodeFactory.statementList(statementList, initFunctionDefinition);

        FunctionCommonNode setupFunctionCommon = generateSetupFunctionCommon(nodeFactory, cx, configNamespaces,
                                                                             dataBindingInfo, standardDefs);
        setupFunctionCommon.setUserDefinedBody(true);
        FunctionDefinitionNode setupFunctionDefinition = generateSetupFunctionDefinition(nodeFactory, cx, setupFunctionCommon);
        statementList = nodeFactory.statementList(statementList, setupFunctionDefinition);

        ClassDefinitionNode classDefinition =
            nodeFactory.classDefinition(cx,
                                        AbstractSyntaxTreeUtil.generatePublicAttribute(nodeFactory),
                                        AbstractSyntaxTreeUtil.generatePublicQualifiedIdentifier(nodeFactory, name),
                                        inheritance,
                                        statementList);

        return classDefinition;
    }

    private ExpressionStatementNode generateEvaluationWatcherPart(NodeFactory nodeFactory,
                                                                  EvaluationWatcher evaluationWatcher)
    {
        MemberExpressionNode watchersBase = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);
        GetExpressionNode watchersSelector = generateArrayIndex(nodeFactory, evaluationWatcher.getId());
        MemberExpressionNode watcherBase = nodeFactory.memberExpression(watchersBase, watchersSelector);
        watchersSelector.setMode(Tokens.LEFTBRACKET_TOKEN);

        IdentifierNode parentVariableIdentifier = null;

        if (evaluationWatcher instanceof ArrayElementWatcher)
        {
            parentVariableIdentifier = nodeFactory.identifier(ARRAY_WATCHER, false);
        }
        else if (evaluationWatcher instanceof FunctionReturnWatcher)
        {
            parentVariableIdentifier = nodeFactory.identifier(PARENT_WATCHER, false);
        }
        else
        {
            assert false : "Unhandled EvaluationWatcher type: " + evaluationWatcher.getClass().getName();
        }

        MemberExpressionNode parentWatchersBase =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);
        GetExpressionNode parentWatchersSelector = generateArrayIndex(nodeFactory, evaluationWatcher.getParent().getId());
        parentWatchersSelector.setMode(Tokens.LEFTBRACKET_TOKEN);
        MemberExpressionNode parentWatcherBase = nodeFactory.memberExpression(parentWatchersBase, parentWatchersSelector);

        ArgumentListNode argumentList = nodeFactory.argumentList(null, parentWatcherBase);
        SetExpressionNode setExpression = nodeFactory.setExpression(parentVariableIdentifier, argumentList, false);
        setExpression.setMode(Tokens.DOT_TOKEN);

        MemberExpressionNode memberExpression = nodeFactory.memberExpression(watcherBase, setExpression);
        ListNode list = nodeFactory.list(null, memberExpression);
        return nodeFactory.expressionStatement(list);
    }

    private FunctionCommonNode generateInitFunctionCommon(NodeFactory nodeFactory, Context cx,
                                                          DataBindingInfo dataBindingInfo)
    {
        ParameterNode parameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, FBS, IFLEX_MODULE_FACTORY, false);
        ParameterListNode parameterList = nodeFactory.parameterList(null, parameter);
        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(parameterList, null);
        functionSignature.void_anno = true;

        String className = dataBindingInfo.getClassName();

        ImportDirectiveNode importDirective = AbstractSyntaxTreeUtil.generateImport(cx, className);
        StatementListNode statementList = nodeFactory.statementList(null, importDirective);

        int index = className.lastIndexOf(DOT);
        ListNode base;

        if (index > 0)
        {
            base = nodeFactory.list(null, AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, className.substring(0, index),
                                                                                        className.substring(index + 1), true));
        }
        else
        {
            base = nodeFactory.list(null, AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, className, true));
        }

        IdentifierNode watcherSetupUtilIdentifier = nodeFactory.identifier(WATCHER_SETUP_UTIL, false);
        IdentifierNode watcherSetupUtilClassIdentifier = nodeFactory.identifier(dataBindingInfo.getWatcherSetupUtilClassName());
        CallExpressionNode callExpression = (CallExpressionNode) nodeFactory.callExpression(watcherSetupUtilClassIdentifier, null);
        callExpression.setRValue(false);
        callExpression.is_new = true;

        MemberExpressionNode newMemberExpression = nodeFactory.memberExpression(null, callExpression);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, newMemberExpression);
        SetExpressionNode selector = nodeFactory.setExpression(watcherSetupUtilIdentifier, argumentList, false);

        MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, selector);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement = nodeFactory.expressionStatement(list);
        statementList = nodeFactory.statementList(statementList, expressionStatement);

        return nodeFactory.functionCommon(cx, null, functionSignature, statementList);
    }

    private FunctionDefinitionNode generateInitFunctionDefinition(NodeFactory nodeFactory, Context cx,
                                                                  FunctionCommonNode functionCommon)
    {
        AttributeListNode attributeList = AbstractSyntaxTreeUtil.generatePublicStaticAttribute(nodeFactory);
        IdentifierNode identifier = nodeFactory.identifier(INIT, false);
        FunctionNameNode functionName = nodeFactory.functionName(Tokens.EMPTY_TOKEN, identifier);
        return nodeFactory.functionDefinition(cx, attributeList, functionName, functionCommon);
    }

    private LiteralArrayNode generateListener(NodeFactory nodeFactory, int id)
    {
        MemberExpressionNode base = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, BINDINGS, false);
        GetExpressionNode selector = generateArrayIndex(nodeFactory, id);
        selector.setMode(Tokens.LEFTBRACKET_TOKEN);
        MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, selector);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, memberExpression);

        return nodeFactory.literalArray(argumentList);
    }

    private LiteralArrayNode generateListeners(NodeFactory nodeFactory, PropertyWatcher propertyWatcher)
    {
        ArgumentListNode argumentList = null;
        Iterator<BindingExpression> iterator = propertyWatcher.getBindingExpressions().iterator();

        while (iterator.hasNext())
        {
            BindingExpression bindingExpression = iterator.next();
            MemberExpressionNode base =
                AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, BINDINGS, false);
            GetExpressionNode selector = generateArrayIndex(nodeFactory, bindingExpression.getId());
            selector.setMode(Tokens.LEFTBRACKET_TOKEN);
            MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, selector);
            argumentList = nodeFactory.argumentList(argumentList, memberExpression);
        }

        return nodeFactory.literalArray(argumentList);
    }

    private MemberExpressionNode generatePath(NodeFactory nodeFactory, String path)
    {
        int index = path.lastIndexOf(DOT);
        String string;
        Node base;

        if (index > 0)
        {
            string = path.substring(index + 1);
            base = generatePath(nodeFactory, path.substring(0, index));
        }
        else
        {
            string = path;
            base = null;
        }

        IdentifierNode identifier = nodeFactory.identifier(string);
        GetExpressionNode getExpression = nodeFactory.getExpression(identifier);
        getExpression.setMode(Tokens.DOT_TOKEN);

        return nodeFactory.memberExpression(base, getExpression);
    }

    private StatementListNode generateRootWatcherBottom(NodeFactory nodeFactory, Context cx,
                                                        StatementListNode statementList, Watcher watcher)
    {
        StatementListNode result = statementList;
        MemberExpressionNode watchersMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);
        GetExpressionNode getExpression = generateArrayIndex(nodeFactory, watcher.getId());
        getExpression.setMode(Tokens.LEFTBRACKET_TOKEN);
        MemberExpressionNode base = nodeFactory.memberExpression(watchersMemberExpression, getExpression);

        IdentifierNode identifier = nodeFactory.identifier(UPDATE_PARENT, false);
        MemberExpressionNode parentMemberExpression;
        String className = watcher.getClassName();

        if (className != null)
        {
            result = nodeFactory.statementList(result, AbstractSyntaxTreeUtil.generateImport(cx, className));

            int index = className.lastIndexOf(DOT);

            if (index > 0)
            {
                parentMemberExpression =
                    AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory,
                                                                  className.substring(0, index),
                                                                  className.substring(index + 1),
                                                                  true);
            }
            else
            {
                parentMemberExpression =
                    AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, className, true);
            }
        }
        else
        {
            parentMemberExpression =
                AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, TARGET, false);
        }

        ArgumentListNode args = nodeFactory.argumentList(null, parentMemberExpression);
        CallExpressionNode selector = (CallExpressionNode) nodeFactory.callExpression(identifier, args);
        selector.setRValue(false);
        MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, selector);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement = nodeFactory.expressionStatement(list);
        result = nodeFactory.statementList(result, expressionStatement);
        return result;
    }

    private FunctionCommonNode generateSetupFunctionCommon(NodeFactory nodeFactory, Context cx,
                                                           HashSet<String> configNamespaces,
                                                           DataBindingInfo dataBindingInfo,
                                                           StandardDefs standardDefs)
    {
        ParameterListNode parameterList = null;

        ParameterNode targetParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, TARGET, OBJECT, false);
        parameterList = nodeFactory.parameterList(parameterList, targetParameter);
        ParameterNode propertyGetterParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, PROPERTY_GETTER, FUNCTION, false);
        parameterList = nodeFactory.parameterList(parameterList, propertyGetterParameter);
        ParameterNode staticPropertyGetterParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, STATIC_PROPERTY_GETTER, FUNCTION, false);
        parameterList = nodeFactory.parameterList(parameterList, staticPropertyGetterParameter);
        ParameterNode bindingsParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, BINDINGS, ARRAY, false);
        parameterList = nodeFactory.parameterList(parameterList, bindingsParameter);
        ParameterNode watchersParameter =
            AbstractSyntaxTreeUtil.generateParameter(nodeFactory, WATCHERS, ARRAY, false);
        parameterList = nodeFactory.parameterList(parameterList, watchersParameter);

        FunctionSignatureNode functionSignature = nodeFactory.functionSignature(parameterList, null);
        functionSignature.void_anno = true;

        StatementListNode statementList = null;

        Iterator<String> importIterator = dataBindingInfo.getImports().iterator();

        while (importIterator.hasNext())
        {
            ImportDirectiveNode importDirective = AbstractSyntaxTreeUtil.generateImport(cx, importIterator.next());
            statementList = nodeFactory.statementList(statementList, importDirective);
        }

        Iterator<Watcher> iterator = dataBindingInfo.getRootWatchers().values().iterator();

        while (iterator.hasNext())
        {
            Watcher watcher = iterator.next();

            if (watcher.shouldWriteSelf())
            {
                if (watcher instanceof ArrayElementWatcher)
                {
                    ArrayElementWatcher arrayElementWatcher = (ArrayElementWatcher) watcher;
                    statementList = generateWatcher(nodeFactory, cx, configNamespaces, statementList,
                                                    arrayElementWatcher, standardDefs);
                }
                else if (watcher instanceof FunctionReturnWatcher)
                {
                    FunctionReturnWatcher functionReturnWatcher = (FunctionReturnWatcher) watcher;
                    statementList = generateWatcher(nodeFactory, cx, configNamespaces, statementList,
                                                    functionReturnWatcher, standardDefs);
                }
                else if (watcher instanceof RepeaterComponentWatcher)
                {
                    RepeaterComponentWatcher repeaterComponentWatcher = (RepeaterComponentWatcher) watcher;
                    statementList = generateWatcher(nodeFactory, statementList, repeaterComponentWatcher, standardDefs);
                }
                else if (watcher instanceof RepeaterItemWatcher)
                {
                    RepeaterItemWatcher repeaterItemWatcher = (RepeaterItemWatcher) watcher;
                    statementList = generateWatcher(nodeFactory, cx, statementList, repeaterItemWatcher, standardDefs);
                }
                else if (watcher instanceof XMLWatcher)
                {
                    XMLWatcher xmlWatcher = (XMLWatcher) watcher;
                    statementList = generateWatcher(nodeFactory, statementList, xmlWatcher, standardDefs);
                }
                else if (watcher instanceof PropertyWatcher)
                {
                    PropertyWatcher propertyWatcher = (PropertyWatcher) watcher;
                    statementList = generateWatcher(nodeFactory, cx, statementList, propertyWatcher, standardDefs,
                                                    dataBindingInfo.getClassName());
                }
                else
                {
                    assert false : "Unhandled Watcher type: " + watcher.getClass().getName();
                }
            }

            if (watcher.shouldWriteChildren())
            {
                statementList = generateWatcherChildren(nodeFactory, cx, configNamespaces,
                                                        statementList, watcher, standardDefs,
                                                        dataBindingInfo.getClassName());
            }
        }

        iterator = dataBindingInfo.getRootWatchers().values().iterator();

        while (iterator.hasNext())
        {
            Watcher watcher = iterator.next();
            statementList = generateWatcherBottom(nodeFactory, cx, statementList, watcher);
        }

        return nodeFactory.functionCommon(cx, null, functionSignature, statementList);
    }

    private FunctionDefinitionNode generateSetupFunctionDefinition(NodeFactory nodeFactory, Context cx,
                                                                   FunctionCommonNode functionCommon)
    {
        AttributeListNode attributeList = AbstractSyntaxTreeUtil.generatePublicAttribute(nodeFactory);
        IdentifierNode identifier = nodeFactory.identifier(SETUP, false);
        FunctionNameNode functionName = nodeFactory.functionName(Tokens.EMPTY_TOKEN, identifier);
        return nodeFactory.functionDefinition(cx, attributeList, functionName, functionCommon);
    }

    private ExpressionStatementNode generateUpdateParentProperty(NodeFactory nodeFactory, int watcherId, PropertyWatcher parent)
    {
        MemberExpressionNode watchersBase = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);
        GetExpressionNode idSelector = generateArrayIndex(nodeFactory, watcherId);
        idSelector.setMode(Tokens.LEFTBRACKET_TOKEN);
        MemberExpressionNode watcherBase = nodeFactory.memberExpression(watchersBase, idSelector);

        IdentifierNode updateParentIdentifier = nodeFactory.identifier(UPDATE_PARENT, false);
        MemberExpressionNode parentMemberExpression = generatePath(nodeFactory, TARGET + DOT + parent.getPathToProperty());
        ArgumentListNode args = nodeFactory.argumentList(null, parentMemberExpression);
        CallExpressionNode updateParentSelector = (CallExpressionNode) nodeFactory.callExpression(updateParentIdentifier, args);
        updateParentSelector.setRValue(false);

        MemberExpressionNode memberExpression = nodeFactory.memberExpression(watcherBase, updateParentSelector);
        ListNode list = nodeFactory.list(null, memberExpression);
        return nodeFactory.expressionStatement(list);
    }

    private ExpressionStatementNode generateUpdateParentPrivateProperty(NodeFactory nodeFactory, int watcherId,
                                                                        PropertyWatcher parent)
    {
        MemberExpressionNode watchersBase =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);
        GetExpressionNode idSelector = generateArrayIndex(nodeFactory, watcherId);
        idSelector.setMode(Tokens.LEFTBRACKET_TOKEN);
        MemberExpressionNode watcherBase = nodeFactory.memberExpression(watchersBase, idSelector);

        IdentifierNode updateParentIdentifier = nodeFactory.identifier(UPDATE_PARENT, false);

        MemberExpressionNode propertyGetterBase =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, PROPERTY_GETTER, false);
        IdentifierNode applyIdentifier = nodeFactory.identifier(APPLY, false);
        IdentifierNode targetIdentifier = nodeFactory.identifier(TARGET, false);
        ArgumentListNode applyArgs = nodeFactory.argumentList(null, targetIdentifier);
        LiteralStringNode literalString = nodeFactory.literalString(parent.getProperty());
        ArgumentListNode argumentList = nodeFactory.argumentList(null, literalString);
        LiteralArrayNode literalArray = nodeFactory.literalArray(argumentList);
        applyArgs = nodeFactory.argumentList(applyArgs, literalArray);
        CallExpressionNode propertyGetterSelector = (CallExpressionNode) nodeFactory.callExpression(applyIdentifier, applyArgs);
        propertyGetterSelector.setRValue(false);
        MemberExpressionNode propertyGetterMemberExpression = nodeFactory.memberExpression(propertyGetterBase, propertyGetterSelector);

        ArgumentListNode updateParentArgs = nodeFactory.argumentList(null, propertyGetterMemberExpression);
        CallExpressionNode updateParentSelector = (CallExpressionNode) nodeFactory.callExpression(updateParentIdentifier, updateParentArgs);
        updateParentSelector.setRValue(false);
        MemberExpressionNode memberExpression = nodeFactory.memberExpression(watcherBase, updateParentSelector);
        ListNode list = nodeFactory.list(null, memberExpression);
        return nodeFactory.expressionStatement(list);
    }

    private ExpressionStatementNode generateUpdateParentStaticProperty(NodeFactory nodeFactory, int watcherId,
                                                                       PropertyWatcher parent)
    {
        MemberExpressionNode watchersBase =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);
        GetExpressionNode idSelector = generateArrayIndex(nodeFactory, watcherId);
        idSelector.setMode(Tokens.LEFTBRACKET_TOKEN);
        MemberExpressionNode watcherBase = nodeFactory.memberExpression(watchersBase, idSelector);

        IdentifierNode updateParentIdentifier = nodeFactory.identifier(UPDATE_PARENT, false);
        MemberExpressionNode parentMemberExpression = generatePath(nodeFactory, parent.getClassName() + DOT + parent.getPathToProperty());
        ArgumentListNode args = nodeFactory.argumentList(null, parentMemberExpression);
        CallExpressionNode updateParentSelector = (CallExpressionNode) nodeFactory.callExpression(updateParentIdentifier, args);
        updateParentSelector.setRValue(false);

        MemberExpressionNode memberExpression = nodeFactory.memberExpression(watcherBase, updateParentSelector);
        ListNode list = nodeFactory.list(null, memberExpression);
        return nodeFactory.expressionStatement(list);
    }

    private StatementListNode generateWatcher(NodeFactory nodeFactory, Context cx,
                                              HashSet<String> configNamespaces,
                                              StatementListNode statementList,
                                              ArrayElementWatcher arrayElementWatcher,
                                              StandardDefs standardDefs)
    {
        StatementListNode result = statementList;

        // Only generate a watcher for the Array element if it will
        // have children, because an Array element watcher will not
        // ever receive a change event.  This is due to our inability
        // to add data binding support to Array.
        if (arrayElementWatcher.shouldWriteChildren())
        {
            MemberExpressionNode base = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);

            QualifiedIdentifierNode qualifiedIdentifier =
                AbstractSyntaxTreeUtil.generateQualifiedIdentifier(nodeFactory, standardDefs.getBindingPackage(), ARRAY_ELEMENT_WATCHER, false);

            LiteralNumberNode literalNumber = nodeFactory.literalNumber(arrayElementWatcher.getId());
            ArgumentListNode expression = nodeFactory.argumentList(null, literalNumber);

            MemberExpressionNode targetMemberExpression =
                AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, TARGET, false);
            ArgumentListNode argumentList = nodeFactory.argumentList(null, targetMemberExpression);
            argumentList = nodeFactory.argumentList(argumentList, generateAccessorFunction(nodeFactory, cx, configNamespaces,
                                                                                           arrayElementWatcher));
            int listenerId = arrayElementWatcher.getBindingExpression().getId();
            argumentList = nodeFactory.argumentList(argumentList, generateListener(nodeFactory, listenerId));

            CallExpressionNode callExpression = (CallExpressionNode) nodeFactory.callExpression(qualifiedIdentifier, argumentList);
            callExpression.setRValue(false);
            callExpression.is_new = true;
            MemberExpressionNode callMemberExpression = nodeFactory.memberExpression(null, callExpression);
            ArgumentListNode args = nodeFactory.argumentList(null, callMemberExpression);
            SetExpressionNode selector = nodeFactory.setExpression(expression, args, false);
            selector.setMode(Tokens.LEFTBRACKET_TOKEN);

            MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, selector);
            ListNode list = nodeFactory.list(null, memberExpression);
            ExpressionStatementNode expressionStatement = nodeFactory.expressionStatement(list);
            result = nodeFactory.statementList(result, expressionStatement);
        }

        return result;
    }

    private StatementListNode generateWatcher(NodeFactory nodeFactory, Context cx,
                                              HashSet<String> configNamespaces,
                                              StatementListNode statementList,
                                              FunctionReturnWatcher functionReturnWatcher,
                                              StandardDefs standardDefs)
    {
        MemberExpressionNode base = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);

        QualifiedIdentifierNode qualifiedIdentifier =
            AbstractSyntaxTreeUtil.generateQualifiedIdentifier(nodeFactory, standardDefs.getBindingPackage(), FUNCTION_RETURN_WATCHER, false);

        LiteralNumberNode literalNumber = nodeFactory.literalNumber(functionReturnWatcher.getId());
        ArgumentListNode expression = nodeFactory.argumentList(null, literalNumber);

        LiteralStringNode literalString = nodeFactory.literalString(functionReturnWatcher.getFunctionName());
        ArgumentListNode argumentList = nodeFactory.argumentList(null, literalString);
        MemberExpressionNode targetMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, TARGET, false);
        argumentList = nodeFactory.argumentList(argumentList, targetMemberExpression);
        argumentList = nodeFactory.argumentList(argumentList, generateAccessorFunction(nodeFactory, cx, configNamespaces,
                                                                                       functionReturnWatcher));
        argumentList = nodeFactory.argumentList(argumentList, generateChangeEvents(nodeFactory, functionReturnWatcher));

        int listenerId = functionReturnWatcher.getBindingExpression().getId();
        argumentList = nodeFactory.argumentList(argumentList, generateListener(nodeFactory, listenerId));

        if ((functionReturnWatcher.getParent() != null) || (functionReturnWatcher.getClassName() != null))
        {
            argumentList = nodeFactory.argumentList(argumentList, nodeFactory.literalNull());
        }
        else
        {
            MemberExpressionNode propertyGetterMemberExpression =
                AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, PROPERTY_GETTER, false);
            argumentList = nodeFactory.argumentList(argumentList, propertyGetterMemberExpression);
        }

        if (functionReturnWatcher.isStyleWatcher())
        {
            argumentList = nodeFactory.argumentList(argumentList, nodeFactory.literalBoolean(true));
        }

        CallExpressionNode callExpression =
            (CallExpressionNode) nodeFactory.callExpression(qualifiedIdentifier, argumentList);
        callExpression.setRValue(false);
        callExpression.is_new = true;
        MemberExpressionNode callMemberExpression = nodeFactory.memberExpression(null, callExpression);
        ArgumentListNode args = nodeFactory.argumentList(null, callMemberExpression);
        SetExpressionNode selector = nodeFactory.setExpression(expression, args, false);
        selector.setMode(Tokens.LEFTBRACKET_TOKEN);

        MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, selector);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement = nodeFactory.expressionStatement(list);
        StatementListNode result = nodeFactory.statementList(statementList, expressionStatement);

        return result;
    }

    private StatementListNode generateWatcher(NodeFactory nodeFactory, Context cx,
                                              StatementListNode statementList,
                                              PropertyWatcher propertyWatcher,
                                              StandardDefs standardDefs,
                                              String documentClassName)
    {
        MemberExpressionNode base =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);

        String type;

        if (propertyWatcher.getStaticProperty())
        {
            type = STATIC_PROPERTY_WATCHER;
        }
        else
        {
            type = PROPERTY_WATCHER;
        }

        QualifiedIdentifierNode qualifiedIdentifier =
            AbstractSyntaxTreeUtil.generateQualifiedIdentifier(nodeFactory, standardDefs.getBindingPackage(), type, false);
        LiteralNumberNode literalNumber = nodeFactory.literalNumber(propertyWatcher.getId());
        ArgumentListNode expression = nodeFactory.argumentList(null, literalNumber);

        LiteralStringNode literalString = nodeFactory.literalString(propertyWatcher.getProperty());
        ArgumentListNode argumentList = nodeFactory.argumentList(null, literalString);
        argumentList = nodeFactory.argumentList(argumentList, generateChangeEvents(nodeFactory, propertyWatcher));
        argumentList = nodeFactory.argumentList(argumentList, generateListeners(nodeFactory, propertyWatcher));

        if ((propertyWatcher.getParent() != null) ||
            (propertyWatcher.getClassName() != null) &&
            !propertyWatcher.getClassName().equals(documentClassName))
        {
            argumentList = nodeFactory.argumentList(argumentList, nodeFactory.literalNull());
        }
        else if (propertyWatcher.getStaticProperty())
        {
            MemberExpressionNode staticPropertyGetterMemberExpression =
                AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, STATIC_PROPERTY_GETTER, false);
            argumentList = nodeFactory.argumentList(argumentList, staticPropertyGetterMemberExpression);
        }
        else
        {
            MemberExpressionNode propertyGetterMemberExpression =
                AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, PROPERTY_GETTER, false);
            argumentList = nodeFactory.argumentList(argumentList, propertyGetterMemberExpression);
        }

        CallExpressionNode callExpression = (CallExpressionNode) nodeFactory.callExpression(qualifiedIdentifier, argumentList);
        callExpression.setRValue(false);
        callExpression.is_new = true;
        MemberExpressionNode callMemberExpression = nodeFactory.memberExpression(null, callExpression);
        ArgumentListNode args = nodeFactory.argumentList(null, callMemberExpression);
        SetExpressionNode selector = nodeFactory.setExpression(expression, args, false);
    selector.setMode(Tokens.LEFTBRACKET_TOKEN);

        MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, selector);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement = nodeFactory.expressionStatement(list);
        StatementListNode result = nodeFactory.statementList(statementList, expressionStatement);

        return result;
    }

    private StatementListNode generateWatcherChildren(NodeFactory nodeFactory, Context cx,
                                                      HashSet<String> configNamespaces,
                                                      StatementListNode statementList, Watcher watcher,
                                                      StandardDefs standardDefs, String documentClassName)
    {
        StatementListNode result = statementList;

        Iterator<Watcher> iterator = watcher.getChildren().iterator();

        while (iterator.hasNext())
        {
            Watcher childWatcher = iterator.next();

            if (childWatcher.shouldWriteSelf())
            {
                if (childWatcher instanceof ArrayElementWatcher)
                {
                    ArrayElementWatcher childArrayElementWatcher = (ArrayElementWatcher) childWatcher;
                    result = generateWatcher(nodeFactory, cx, configNamespaces, result,
                                             childArrayElementWatcher, standardDefs);
                }
                else if (childWatcher instanceof FunctionReturnWatcher)
                {
                    FunctionReturnWatcher childFunctionReturnWatcher = (FunctionReturnWatcher) childWatcher;
                    result = generateWatcher(nodeFactory, cx, configNamespaces, result,
                                             childFunctionReturnWatcher, standardDefs);
                }
                else if (childWatcher instanceof RepeaterComponentWatcher)
                {
                    RepeaterComponentWatcher childRepeaterComponentWatcher = (RepeaterComponentWatcher) childWatcher;
                    result = generateWatcher(nodeFactory, result, childRepeaterComponentWatcher, standardDefs);
                }
                else if (childWatcher instanceof RepeaterItemWatcher)
                {
                    RepeaterItemWatcher childRepeaterItemWatcher = (RepeaterItemWatcher) childWatcher;
                    result = generateWatcher(nodeFactory, cx, result, childRepeaterItemWatcher, standardDefs);
                }
                else if (childWatcher instanceof XMLWatcher)
                {
                    XMLWatcher childXMLWatcher = (XMLWatcher) childWatcher;
                    result = generateWatcher(nodeFactory, result, childXMLWatcher, standardDefs);
                }
                else if (childWatcher instanceof PropertyWatcher)
                {
                    PropertyWatcher childPropertyWatcher = (PropertyWatcher) childWatcher;
                    result = generateWatcher(nodeFactory, cx, result, childPropertyWatcher, standardDefs,
                                             documentClassName);
                }
                else
                {
                    assert false : "Unhandled Watcher type: " + childWatcher.getClass().getName();
                }
            }

            if (childWatcher.shouldWriteChildren())
            {
                result = generateWatcherChildren(nodeFactory, cx, configNamespaces, result, childWatcher,
                                                 standardDefs, documentClassName);
            }
        }

        return result;
    }

    private Map<QName, Source> generateWatcherSetupUtilClasses(CompilationUnit compilationUnit, SymbolTable symbolTable,
                                                List dataBindingInfoList)
    {
        Map<QName, Source> extraSources = new HashMap<QName, Source>();
        Iterator iterator = dataBindingInfoList.iterator();

        while ( iterator.hasNext() )
        {
            DataBindingInfo dataBindingInfo = (DataBindingInfo) iterator.next();
            QName classQName = new QName(dataBindingInfo.getWatcherSetupUtilClassName());

            if (generateAbstractSyntaxTree)
            {
                extraSources.put(classQName, generateWatcherSetupUtilAST(compilationUnit, symbolTable,
                                                                         dataBindingInfo));
            }
            else
            {
                extraSources.put(classQName, generateWatcherSetupUtil(compilationUnit, dataBindingInfo));
            }
        }

        return extraSources;
    }

    private StatementListNode generateWatcher(NodeFactory nodeFactory, StatementListNode statementList,
                                              RepeaterComponentWatcher repeaterComponentWatcher,
                                              StandardDefs standardDefs)
    {
        MemberExpressionNode base = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);
        QualifiedIdentifierNode qualifiedIdentifier =
            AbstractSyntaxTreeUtil.generateQualifiedIdentifier(nodeFactory, standardDefs.getBindingPackage(), REPEATER_COMPONENT_WATCHER, false);
        LiteralNumberNode literalNumber = nodeFactory.literalNumber(repeaterComponentWatcher.getId());
        ArgumentListNode expression = nodeFactory.argumentList(null, literalNumber);

        LiteralStringNode literalString = nodeFactory.literalString(repeaterComponentWatcher.getProperty());
        ArgumentListNode argumentList = nodeFactory.argumentList(null, literalString);
        argumentList = nodeFactory.argumentList(argumentList, generateChangeEvents(nodeFactory, repeaterComponentWatcher));
        argumentList = nodeFactory.argumentList(argumentList, generateListeners(nodeFactory, repeaterComponentWatcher));
        MemberExpressionNode propertyGetterMemberExpression =
            AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, PROPERTY_GETTER, false);
        argumentList = nodeFactory.argumentList(argumentList, propertyGetterMemberExpression);

        CallExpressionNode callExpression = (CallExpressionNode) nodeFactory.callExpression(qualifiedIdentifier, argumentList);
        callExpression.setRValue(false);
        callExpression.is_new = true;
        MemberExpressionNode callMemberExpression = nodeFactory.memberExpression(null, callExpression);
        ArgumentListNode args = nodeFactory.argumentList(null, callMemberExpression);
        SetExpressionNode selector = nodeFactory.setExpression(expression, args, false);
    selector.setMode(Tokens.LEFTBRACKET_TOKEN);

        MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, selector);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement = nodeFactory.expressionStatement(list);
        StatementListNode result = nodeFactory.statementList(statementList, expressionStatement);

        return result;
    }

    private StatementListNode generateWatcher(NodeFactory nodeFactory, Context cx,
                                              StatementListNode statementList, RepeaterItemWatcher repeaterItemWatcher,
                                              StandardDefs standardDefs)
    {
        MemberExpressionNode base = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);

        QualifiedIdentifierNode qualifiedIdentifier = AbstractSyntaxTreeUtil.generateQualifiedIdentifier(nodeFactory,
                standardDefs.getBindingPackage(), REPEATER_ITEM_WATCHER, false);

        LiteralNumberNode id = nodeFactory.literalNumber(repeaterItemWatcher.getId());
        ArgumentListNode expression = nodeFactory.argumentList(null, id);

        MemberExpressionNode parentWatchersBase = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);

        LiteralNumberNode parentId = nodeFactory.literalNumber(repeaterItemWatcher.getParent().getId());
        ArgumentListNode parentExpression = nodeFactory.argumentList(null, parentId);
        GetExpressionNode parentSelector = nodeFactory.getExpression(parentExpression);
    parentSelector.setMode(Tokens.LEFTBRACKET_TOKEN);
        MemberExpressionNode parentMemberExpression= nodeFactory.memberExpression(parentWatchersBase, parentSelector);
        ArgumentListNode argumentList = nodeFactory.argumentList(null, parentMemberExpression);

        CallExpressionNode callExpression = (CallExpressionNode) nodeFactory.callExpression(qualifiedIdentifier, argumentList);
        callExpression.setRValue(false);
        callExpression.is_new = true;
        MemberExpressionNode callMemberExpression = nodeFactory.memberExpression(null, callExpression);
        ArgumentListNode args = nodeFactory.argumentList(null, callMemberExpression);

        SetExpressionNode selector = nodeFactory.setExpression(expression, args, false);
    selector.setMode(Tokens.LEFTBRACKET_TOKEN);

        MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, selector);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement = nodeFactory.expressionStatement(list);
        StatementListNode result = nodeFactory.statementList(statementList, expressionStatement);

        return result;
    }

    private StatementListNode generateWatcher(NodeFactory nodeFactory, StatementListNode statementList,
                                              XMLWatcher xmlWatcher, StandardDefs standardDefs)
    {
        MemberExpressionNode base = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, WATCHERS, false);
        QualifiedIdentifierNode qualifiedIdentifier =
            AbstractSyntaxTreeUtil.generateQualifiedIdentifier(nodeFactory, standardDefs.getBindingPackage(), XML_WATCHER, false);
        LiteralNumberNode literalNumber = nodeFactory.literalNumber(xmlWatcher.getId());
        ArgumentListNode expression = nodeFactory.argumentList(null, literalNumber);

        LiteralStringNode literalString = nodeFactory.literalString(xmlWatcher.getProperty());
        ArgumentListNode argumentList = nodeFactory.argumentList(null, literalString);
        argumentList = nodeFactory.argumentList(argumentList, generateListeners(nodeFactory, xmlWatcher));

        CallExpressionNode callExpression = (CallExpressionNode) nodeFactory.callExpression(qualifiedIdentifier, argumentList);
        callExpression.setRValue(false);
        callExpression.is_new = true;
        MemberExpressionNode callMemberExpression = nodeFactory.memberExpression(null, callExpression);
        ArgumentListNode args = nodeFactory.argumentList(null, callMemberExpression);
        SetExpressionNode selector = nodeFactory.setExpression(expression, args, false);
    selector.setMode(Tokens.LEFTBRACKET_TOKEN);

        MemberExpressionNode memberExpression = nodeFactory.memberExpression(base, selector);
        ListNode list = nodeFactory.list(null, memberExpression);
        ExpressionStatementNode expressionStatement = nodeFactory.expressionStatement(list);
        StatementListNode result = nodeFactory.statementList(statementList, expressionStatement);

        return result;
    }

    private StatementListNode generateWatcherBottom(NodeFactory nodeFactory, Context cx,
                                                    StatementListNode statementList, Watcher watcher)
    {
        StatementListNode result = statementList;

        if (watcher.shouldWriteSelf())
        {
            if (((watcher instanceof ArrayElementWatcher) &&
                 watcher.shouldWriteSelf() &&
                 watcher.shouldWriteChildren()) ||
                (watcher instanceof FunctionReturnWatcher))
            {
                EvaluationWatcher evaluationWatcher = (EvaluationWatcher) watcher;

                if ((watcher.getParent() != null) && watcher.getParent().shouldWriteSelf())
                {
                    result = nodeFactory.statementList(result, generateEvaluationWatcherPart(nodeFactory,
                                                                                             evaluationWatcher));
                }
            }

            if (watcher.getParent() != null)
            {
                if (watcher.getParent().shouldWriteSelf())
                {
                    result = nodeFactory.statementList(result, generateAddChild(nodeFactory, watcher));
                }
                else
                {
                    Watcher parent = watcher.getParent();

                    if (parent instanceof PropertyWatcher)
                    {
                        PropertyWatcher propertyWatcher = (PropertyWatcher) parent;

                        if (propertyWatcher.getStaticProperty())
                        {
                            result = nodeFactory.statementList(result,
                                                               generateUpdateParentStaticProperty(nodeFactory,
                                                                                                  watcher.getId(),
                                                                                                  propertyWatcher));
                        }
                        else
                        {
                            if (parent.getParent() != null)
                            {
                                result = nodeFactory.statementList(result,
                                                                   generateUpdateParentProperty(nodeFactory,
                                                                                                watcher.getId(),
                                                                                                propertyWatcher));
                            }
                            else
                            {
                                result = nodeFactory.statementList(result,
                                                                   generateUpdateParentPrivateProperty(nodeFactory,
                                                                                                       watcher.getId(),
                                                                                                       propertyWatcher));
                            }
                        }
                    }
                }
            }
            else
            {
                result = generateRootWatcherBottom(nodeFactory, cx, result, watcher);
            }
        }

        if (watcher.shouldWriteChildren())
        {
            Iterator<Watcher> iterator = watcher.getChildren().iterator();

            while (iterator.hasNext())
            {
                Watcher childWatcher = iterator.next();
                result = generateWatcherBottom(nodeFactory, cx, result, childWatcher);
            }
        }

        return result;
    }

    /**
     *
     */
    private Source generateWatcherSetupUtil(CompilationUnit compilationUnit, DataBindingInfo dataBindingInfo)
    {
        Template template;

        StandardDefs standardDefs = compilationUnit.getStandardDefs();
        String templatePath = TEMPLATE_PATH + standardDefs.getWatcherSetupUtilTemplate();

        try
        {
            template = VelocityManager.getTemplate(templatePath);
        }
        catch (Exception exception)
        {
            ThreadLocalToolkit.log(new VelocityException.TemplateNotFound(templatePath));
            return null;
        }

        String className = dataBindingInfo.getWatcherSetupUtilClassName();
        String shortName = className.substring(className.lastIndexOf(DOT) + 1);

        String generatedName = className.replace('.', File.separatorChar) + DOT_AS;

        SourceCodeBuffer out = new SourceCodeBuffer();

        try
        {
            VelocityUtil util = new VelocityUtil(TEMPLATE_PATH, false, out, null);
            VelocityContext velocityContext = VelocityManager.getCodeGenContext(util);
            velocityContext.put(DATA_BINDING_INFO_KEY, dataBindingInfo);
            template.merge(velocityContext, out);
        }
        catch (Exception e)
        {
            ThreadLocalToolkit.log(new VelocityException.GenerateException(compilationUnit.getSource().getRelativePath(),
                                                                           e.getLocalizedMessage()));
            return null;
        }

        return createSource(generatedName, shortName, compilationUnit.getSource().getLastModified(),
                  compilationUnit.getSource().getPathResolver(), out);
    }

    private Source generateWatcherSetupUtilAST(CompilationUnit compilationUnit, SymbolTable symbolTable,
                                               DataBindingInfo dataBindingInfo)
    {
        String className = dataBindingInfo.getWatcherSetupUtilClassName();
        String shortName = className.substring(className.lastIndexOf(DOT) + 1);
        String fileName = className.replace('.', File.separatorChar) + DOT_AS;
        VirtualFile emptyFile = new TextFile(EMPTY_STRING, fileName, null, MimeMappings.AS,
                                             compilationUnit.getSource().getLastModified());
        Source result = new Source(emptyFile, EMPTY_STRING, shortName, null, false, false, false);

        Context cx = AbstractSyntaxTreeUtil.generateContext(symbolTable.perCompileData, result,
                                                            symbolTable.emitter, defines);
        NodeFactory nodeFactory = cx.getNodeFactory();

        HashSet<String> configNamespaces = new HashSet<String>();
        StatementListNode configVars = AbstractSyntaxTreeUtil.parseConfigVars(cx, configNamespaces);
        ProgramNode program = AbstractSyntaxTreeUtil.generateProgram(cx, configVars, EMPTY_STRING);
        StatementListNode programStatementList = program.statements;

        String[] watcherImports = compilationUnit.getStandardDefs().getImports();
        for (int i = 0; i < watcherImports.length; i++)
        {
            ImportDirectiveNode importDirective = AbstractSyntaxTreeUtil.generateImport(cx, watcherImports[i]);
            programStatementList = nodeFactory.statementList(programStatementList, importDirective);
        }

        MetaDataNode metaDataNode = AbstractSyntaxTreeUtil.generateMetaData(nodeFactory, EXCLUDE_CLASS);
        programStatementList = nodeFactory.statementList(programStatementList, metaDataNode);

        ClassDefinitionNode classDefinition = generateClassDefinition(cx, configNamespaces, shortName,
                                                                      dataBindingInfo, compilationUnit.getStandardDefs());
        programStatementList = nodeFactory.statementList(programStatementList, classDefinition);
        program.statements = programStatementList;

        PackageDefinitionNode packageDefinition = nodeFactory.finishPackage(cx, null);
        nodeFactory.statementList(programStatementList, packageDefinition);

    CompilerContext context = new CompilerContext();
    context.setAscContext(cx);
    result.newCompilationUnit(program, context).setSyntaxTree(program);

        // Useful when comparing abstract syntax trees
        //flash.swf.tools.SyntaxTreeDumper.dump(program, "/tmp/" + className + "New.xml");

        As3Compiler.cleanNodeFactory(nodeFactory);

        return result;
    }


}
TOP

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

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.