flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gordonsm...@apache.org
Subject [4/4] git commit: [flex-falcon] - Moved MXMLData-related classes into internal package
Date Tue, 16 Apr 2013 03:05:36 GMT
Moved MXMLData-related classes into internal package


Project: http://git-wip-us.apache.org/repos/asf/flex-falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-falcon/commit/bec3ba00
Tree: http://git-wip-us.apache.org/repos/asf/flex-falcon/tree/bec3ba00
Diff: http://git-wip-us.apache.org/repos/asf/flex-falcon/diff/bec3ba00

Branch: refs/heads/develop
Commit: bec3ba0024522bcd14b27960fab667b648deef9b
Parents: 1c7ddc2
Author: Gordon Smith <gosmith@adobe.com>
Authored: Mon Apr 15 20:01:28 2013 -0700
Committer: Gordon Smith <gosmith@adobe.com>
Committed: Mon Apr 15 20:01:28 2013 -0700

----------------------------------------------------------------------
 .../compiler/internal/test/FlexJSTestBase.java     |    2 +-
 .../flex/compiler/internal/test/MXMLTestBase.java  |    2 +-
 .../internal/tree/mxml/MXMLNodeBaseTests.java      |    2 +-
 .../flex/compiler/common/PrefixedXMLName.java      |    2 +-
 .../apache/flex/compiler/config/Configuration.java |    2 +-
 .../compiler/internal/caches/MXMLDataCache.java    |    2 +-
 .../flex/compiler/internal/mxml/MXMLData.java      |  980 +++++++++++++
 .../compiler/internal/mxml/MXMLDataManager.java    |    1 -
 .../internal/mxml/MXMLDatabindingData.java         |   58 +
 .../internal/mxml/MXMLDatabindingValue.java        |  113 ++
 .../compiler/internal/mxml/MXMLEntityData.java     |   80 +
 .../compiler/internal/mxml/MXMLEntityValue.java    |  144 ++
 .../internal/mxml/MXMLInstructionData.java         |   97 ++
 .../internal/mxml/MXMLNamespaceAttributeData.java  |   64 +
 .../internal/mxml/MXMLNamespaceMapping.java        |   76 +
 .../compiler/internal/mxml/MXMLStateSplitter.java  |   86 ++
 .../internal/mxml/MXMLTagAttributeData.java        |  637 ++++++++
 .../internal/mxml/MXMLTagAttributeValue.java       |   53 +
 .../compiler/internal/mxml/MXMLTagBlobData.java    |   66 +
 .../flex/compiler/internal/mxml/MXMLTagData.java   | 1135 +++++++++++++++
 .../flex/compiler/internal/mxml/MXMLTextData.java  |  404 +++++
 .../flex/compiler/internal/mxml/MXMLTextValue.java |   82 ++
 .../flex/compiler/internal/mxml/MXMLUnitData.java  |  366 +++++
 .../compiler/internal/mxml/StateDefinition.java    |   93 ++
 .../internal/mxml/StateDefinitionBase.java         |   75 +
 .../internal/mxml/StateGroupDefinition.java        |   84 ++
 .../internal/parsing/mxml/MXMLTagDataDepth.java    |    2 +-
 .../compiler/internal/projects/FlexProject.java    |    2 +-
 .../tree/mxml/MXMLClassDefinitionNode.java         |    4 +-
 .../compiler/internal/tree/mxml/MXMLStateNode.java |    2 +-
 .../org/apache/flex/compiler/mxml/IMXMLData.java   |    1 +
 .../org/apache/flex/compiler/mxml/MXMLData.java    |  977 -------------
 .../flex/compiler/mxml/MXMLDatabindingData.java    |   56 -
 .../flex/compiler/mxml/MXMLDatabindingValue.java   |  111 --
 .../apache/flex/compiler/mxml/MXMLEntityData.java  |   79 -
 .../apache/flex/compiler/mxml/MXMLEntityValue.java |  142 --
 .../flex/compiler/mxml/MXMLInstructionData.java    |   96 --
 .../compiler/mxml/MXMLNamespaceAttributeData.java  |   64 -
 .../flex/compiler/mxml/MXMLNamespaceMapping.java   |   74 -
 .../flex/compiler/mxml/MXMLStateSplitter.java      |   87 --
 .../flex/compiler/mxml/MXMLTagAttributeData.java   |  635 --------
 .../flex/compiler/mxml/MXMLTagAttributeValue.java  |   51 -
 .../apache/flex/compiler/mxml/MXMLTagBlobData.java |   65 -
 .../org/apache/flex/compiler/mxml/MXMLTagData.java | 1130 --------------
 .../apache/flex/compiler/mxml/MXMLTextData.java    |  405 -----
 .../apache/flex/compiler/mxml/MXMLTextValue.java   |   80 -
 .../apache/flex/compiler/mxml/MXMLUnitData.java    |  364 -----
 .../apache/flex/compiler/mxml/StateDefinition.java |   91 --
 .../flex/compiler/mxml/StateDefinitionBase.java    |   74 -
 .../flex/compiler/mxml/StateGroupDefinition.java   |   82 --
 50 files changed, 4705 insertions(+), 4675 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler.jx.tests/src/org/apache/flex/compiler/internal/test/FlexJSTestBase.java
----------------------------------------------------------------------
diff --git a/compiler.jx.tests/src/org/apache/flex/compiler/internal/test/FlexJSTestBase.java b/compiler.jx.tests/src/org/apache/flex/compiler/internal/test/FlexJSTestBase.java
index 7b9a421..ce25e18 100644
--- a/compiler.jx.tests/src/org/apache/flex/compiler/internal/test/FlexJSTestBase.java
+++ b/compiler.jx.tests/src/org/apache/flex/compiler/internal/test/FlexJSTestBase.java
@@ -5,9 +5,9 @@ import java.util.List;
 
 import org.apache.flex.compiler.driver.IBackend;
 import org.apache.flex.compiler.internal.driver.mxml.flexjs.MXMLFlexJSBackend;
+import org.apache.flex.compiler.internal.mxml.MXMLNamespaceMapping;
 import org.apache.flex.compiler.internal.projects.FlexJSProject;
 import org.apache.flex.compiler.mxml.IMXMLNamespaceMapping;
-import org.apache.flex.compiler.mxml.MXMLNamespaceMapping;
 import org.apache.flex.compiler.tree.mxml.IMXMLFileNode;
 import org.apache.flex.compiler.tree.mxml.IMXMLNode;
 import org.apache.flex.utils.FilenameNormalization;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler.jx.tests/src/org/apache/flex/compiler/internal/test/MXMLTestBase.java
----------------------------------------------------------------------
diff --git a/compiler.jx.tests/src/org/apache/flex/compiler/internal/test/MXMLTestBase.java b/compiler.jx.tests/src/org/apache/flex/compiler/internal/test/MXMLTestBase.java
index d0f793a..c8a1041 100644
--- a/compiler.jx.tests/src/org/apache/flex/compiler/internal/test/MXMLTestBase.java
+++ b/compiler.jx.tests/src/org/apache/flex/compiler/internal/test/MXMLTestBase.java
@@ -5,8 +5,8 @@ import java.util.List;
 
 import org.apache.flex.compiler.driver.IBackend;
 import org.apache.flex.compiler.internal.driver.mxml.MXMLBackend;
+import org.apache.flex.compiler.internal.mxml.MXMLNamespaceMapping;
 import org.apache.flex.compiler.mxml.IMXMLNamespaceMapping;
-import org.apache.flex.compiler.mxml.MXMLNamespaceMapping;
 import org.apache.flex.compiler.tree.mxml.IMXMLFileNode;
 import org.apache.flex.compiler.tree.mxml.IMXMLNode;
 import org.apache.flex.compiler.tree.mxml.IMXMLPropertySpecifierNode;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler.tests/unit-tests/org/apache/flex/compiler/internal/tree/mxml/MXMLNodeBaseTests.java
----------------------------------------------------------------------
diff --git a/compiler.tests/unit-tests/org/apache/flex/compiler/internal/tree/mxml/MXMLNodeBaseTests.java b/compiler.tests/unit-tests/org/apache/flex/compiler/internal/tree/mxml/MXMLNodeBaseTests.java
index 684c6bc..3a82b9c 100644
--- a/compiler.tests/unit-tests/org/apache/flex/compiler/internal/tree/mxml/MXMLNodeBaseTests.java
+++ b/compiler.tests/unit-tests/org/apache/flex/compiler/internal/tree/mxml/MXMLNodeBaseTests.java
@@ -29,12 +29,12 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
+import org.apache.flex.compiler.internal.mxml.MXMLNamespaceMapping;
 import org.apache.flex.compiler.internal.projects.FlexProject;
 import org.apache.flex.compiler.internal.projects.FlexProjectConfigurator;
 import org.apache.flex.compiler.internal.units.SourceCompilationUnitFactory;
 import org.apache.flex.compiler.internal.workspaces.Workspace;
 import org.apache.flex.compiler.mxml.IMXMLNamespaceMapping;
-import org.apache.flex.compiler.mxml.MXMLNamespaceMapping;
 import org.apache.flex.compiler.tree.as.IASNode;
 import org.apache.flex.compiler.tree.mxml.IMXMLFileNode;
 import org.apache.flex.compiler.units.ICompilationUnit;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/common/PrefixedXMLName.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/common/PrefixedXMLName.java b/compiler/src/org/apache/flex/compiler/common/PrefixedXMLName.java
index bce90e9..afcd6f9 100644
--- a/compiler/src/org/apache/flex/compiler/common/PrefixedXMLName.java
+++ b/compiler/src/org/apache/flex/compiler/common/PrefixedXMLName.java
@@ -20,7 +20,7 @@
 package org.apache.flex.compiler.common;
 
 import org.apache.flex.compiler.constants.IMXMLCoreConstants;
-import org.apache.flex.compiler.mxml.MXMLData;
+import org.apache.flex.compiler.internal.mxml.MXMLData;
 
 /**
  * A subclass of XMLName used by clients that need to manipulate the actual

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/config/Configuration.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/config/Configuration.java b/compiler/src/org/apache/flex/compiler/config/Configuration.java
index 362fbd7..6cbb8a7 100644
--- a/compiler/src/org/apache/flex/compiler/config/Configuration.java
+++ b/compiler/src/org/apache/flex/compiler/config/Configuration.java
@@ -79,8 +79,8 @@ import org.apache.flex.compiler.internal.config.annotations.InfiniteArguments;
 import org.apache.flex.compiler.internal.config.annotations.Mapping;
 import org.apache.flex.compiler.internal.config.annotations.SoftPrerequisites;
 import org.apache.flex.compiler.internal.config.localization.LocalizationManager;
+import org.apache.flex.compiler.internal.mxml.MXMLNamespaceMapping;
 import org.apache.flex.compiler.mxml.IMXMLTypeConstants;
-import org.apache.flex.compiler.mxml.MXMLNamespaceMapping;
 import org.apache.flex.compiler.problems.ConfigurationProblem;
 import org.apache.flex.compiler.problems.DeprecatedConfigurationOptionProblem;
 import org.apache.flex.compiler.problems.FlexOnlyConfigurationOptionNotSupported;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/caches/MXMLDataCache.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/caches/MXMLDataCache.java b/compiler/src/org/apache/flex/compiler/internal/caches/MXMLDataCache.java
index 51ec3f0..7f06a2d 100644
--- a/compiler/src/org/apache/flex/compiler/internal/caches/MXMLDataCache.java
+++ b/compiler/src/org/apache/flex/compiler/internal/caches/MXMLDataCache.java
@@ -26,9 +26,9 @@ import java.util.List;
 import org.apache.commons.io.IOUtils;
 
 import org.apache.flex.compiler.filespecs.IFileSpecification;
+import org.apache.flex.compiler.internal.mxml.MXMLData;
 import org.apache.flex.compiler.internal.parsing.mxml.MXMLToken;
 import org.apache.flex.compiler.internal.parsing.mxml.MXMLTokenizer;
-import org.apache.flex.compiler.mxml.MXMLData;
 
 /**
  * Concurrent cache for parsed MXML models. The cache is a list of key-value pairs.

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLData.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLData.java b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLData.java
new file mode 100644
index 0000000..9c4c093
--- /dev/null
+++ b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLData.java
@@ -0,0 +1,980 @@
+/*
+ *
+ *  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 org.apache.flex.compiler.internal.mxml;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+
+import org.apache.flex.compiler.common.MutablePrefixMap;
+import org.apache.flex.compiler.common.PrefixMap;
+import org.apache.flex.compiler.filespecs.FileSpecification;
+import org.apache.flex.compiler.filespecs.IFileSpecification;
+import org.apache.flex.compiler.internal.parsing.mxml.BalancingMXMLProcessor;
+import org.apache.flex.compiler.internal.parsing.mxml.MXMLToken;
+import org.apache.flex.compiler.internal.parsing.mxml.MXMLTokenizer;
+import org.apache.flex.compiler.internal.parsing.mxml.MXMLUnitDataIterator;
+import org.apache.flex.compiler.mxml.IMXMLData;
+import org.apache.flex.compiler.mxml.IMXMLTagAttributeData;
+import org.apache.flex.compiler.mxml.IMXMLTagData;
+import org.apache.flex.compiler.mxml.IMXMLUnitData;
+import org.apache.flex.compiler.parsing.MXMLTokenTypes;
+import org.apache.flex.compiler.problems.ICompilerProblem;
+import org.apache.flex.compiler.problems.SyntaxProblem;
+import org.apache.flex.utils.FastStack;
+import org.apache.flex.utils.FastStack.IFastStackDecorator;
+
+/**
+ * Encapsulation of an MXML file, with individual units for each open tag, close
+ * tag, and block of text.
+ */
+public class MXMLData implements IMXMLData
+{
+
+    private final class TokenizerPayload
+    {
+        private List<MXMLToken> tokens;
+
+        private PrefixMap prefixMap;
+
+        public TokenizerPayload(List<MXMLToken> tokens, PrefixMap prefixMap)
+        {
+            this.tokens = tokens;
+            this.prefixMap = prefixMap;
+        }
+
+        public List<MXMLToken> getMXMLTokens()
+        {
+            return tokens;
+        }
+
+        public PrefixMap getPrefixMap()
+        {
+            return prefixMap;
+        }
+    }
+
+    /**
+     * A cursor represents the offset into the document and the index of the
+     * MXML unit that contains that offset
+     */
+    public class Cursor
+    {
+        /**
+         * Offset into the document
+         */
+        private int offset;
+        /**
+         * Index of the unit that contains that offset
+         */
+        private int unitIndex;
+
+        /**
+         * Constructor (points to beginning of the MXMLData)
+         */
+        public Cursor()
+        {
+            reset();
+        }
+
+        /**
+         * Reset cursor to the beginning of the MXMLData
+         */
+        public void reset()
+        {
+            offset = 0;
+            unitIndex = 0;
+        }
+
+        /**
+         * Set the cursor to a particular offset/unit
+         * 
+         * @param offset offset into the document
+         * @param unitIndex index of the unit containing that offset
+         */
+        public void setCursor(int offset, int unitIndex)
+        {
+            this.offset = offset;
+            this.unitIndex = unitIndex;
+        }
+
+        /**
+         * Get the offset the cursor is pointing to
+         * 
+         * @return current document offset
+         */
+        public int getOffset()
+        {
+            return offset;
+        }
+
+        /**
+         * Get the index of the unit the cursor is pointing to
+         * 
+         * @return current unit index
+         */
+        public int getUnitIndex()
+        {
+            return unitIndex;
+        }
+    }
+
+    private String path = null;
+
+    /**
+     * Individual units for each open tag, close tag, and block of text
+     */
+    private IMXMLUnitData[] units;
+
+    /**
+     * Flag indicating that the tokens underlying this structure were fixed
+     */
+    private boolean wasRepaired;
+
+    private boolean shouldRepair = true;
+
+    /**
+     * This maps {@link IMXMLTagData} objects to their explicit
+     * {@link PrefixMap} if it exist
+     */
+    private HashMap<IMXMLTagData, PrefixMap> nsMap;
+
+    /**
+     * The cursor holds the result of last offset lookup into the MXMLData (see
+     * findNearestUnit, below). When an edit happens that causes the code
+     * coloring engine to recompute everything from the edit position to the end
+     * of the document, it will request MXMLOffsetInformations in order. Having
+     * the cursor speeds this up tremendously.
+     */
+    private Cursor cursor;
+
+    /**
+     * The dialect of MXML being used.
+     */
+    private MXMLDialect mxmlDialect;
+
+    private Collection<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(2);
+
+    /**
+     * Tells us if we are currently processing full MXML, or a fragment
+     */
+    private boolean fullContent = true;
+
+    /**
+     * Constructor
+     * 
+     * @param tokens MXML tokens to build the MXMLData object from
+     * @param map the {@link PrefixMap} for the document, containing the
+     * namespace/prefix mappings
+     */
+    public MXMLData(List<MXMLToken> tokens, PrefixMap map, IFileSpecification fileSpec)
+    {
+        path = fileSpec.getPath();
+        init(tokens, map);
+    }
+
+    public MXMLData(List<MXMLToken> tokens, PrefixMap map, IFileSpecification fileSpec, boolean shouldRepair)
+    {
+        path = fileSpec.getPath();
+        this.shouldRepair = false;
+        init(tokens, map);
+    }
+
+    /**
+     * Constructor
+     * 
+     * @param mxmlText input build our {@link MXMLData} from
+     */
+    public MXMLData(int startOffset, Reader mxmlText, IFileSpecification fileSpec)
+    {
+        TokenizerPayload payload = getTokens(startOffset, mxmlText);
+        path = fileSpec.getPath();
+        init(payload.getMXMLTokens(), payload.getPrefixMap());
+    }
+
+    /**
+     * Constructor
+     * 
+     * @param mxmlText input build our {@link MXMLData} from
+     */
+    public MXMLData(int startOffset, Reader mxmlText, String path, boolean fullContent)
+    {
+        this.fullContent = fullContent;
+        TokenizerPayload payload = getTokens(startOffset, mxmlText);
+        this.path = path;
+        init(payload.getMXMLTokens(), payload.getPrefixMap());
+    }
+
+    public MXMLData(Reader mxmlText, IFileSpecification fileSpec)
+    {
+        this(0, mxmlText, fileSpec);
+    }
+
+    public MXMLData(Reader mxmlText, String path)
+    {
+        // Some clients of MXML data pass in a null IPath for the source path.
+        // Specifically this seems to happen in the code that builds a new
+        // mxml document from a template.
+        this(0, mxmlText, path != null ? path : null, true);
+    }
+
+    /**
+     * Constructor
+     * 
+     * @param specification input build our {@link MXMLData} from
+     */
+    public MXMLData(IFileSpecification specification)
+    {
+        TokenizerPayload payload;
+        try
+        {
+            path = specification.getPath();
+            payload = getTokens(specification.createReader());
+            init(payload.getMXMLTokens(), payload.getPrefixMap());
+        }
+        catch (FileNotFoundException e)
+        {
+            //do nothing
+        }
+    }
+
+    private void init(List<MXMLToken> tokens, PrefixMap map)
+    {
+        mxmlDialect = MXMLDialect.getMXMLDialect(map);
+        initializeFromTokens(tokens);
+    }
+
+    /**
+     * Update the version of the mxml data
+     * 
+     * @param map the prefix map
+     */
+    public void updateMXMLVersion(PrefixMap map)
+    {
+        mxmlDialect = MXMLDialect.getMXMLDialect(map);
+    }
+
+    /**
+     * Get the namespaces defined on the root tag
+     * 
+     * @param reader The reader which would provide the root tag information
+     * @return {@link PrefixMap} for the root tag
+     * @throws IOException error
+     */
+    public static PrefixMap getRootNamespaces(Reader reader) throws IOException
+    {
+        MXMLTokenizer tokenizer = new MXMLTokenizer();
+        try
+        {
+            tokenizer.setReader(reader);
+            return tokenizer.getRootTagPrefixMap().clone();
+        }
+        finally
+        {
+            tokenizer.close();
+        }
+    }
+
+    protected TokenizerPayload getTokens(Reader reader)
+    {
+        return getTokens(0, reader);
+    }
+
+    protected TokenizerPayload getTokens(int startOffset, Reader reader)
+    {
+        List<MXMLToken> tokens = null;
+        MXMLTokenizer tokenizer = new MXMLTokenizer(startOffset);
+        try
+        {
+            tokenizer.setIsRepairing(true);
+            tokens = tokenizer.parseTokens(reader);
+            wasRepaired = tokenizer.tokensWereRepaired();
+            return new TokenizerPayload(tokens, tokenizer.getPrefixMap());
+        }
+        finally
+        {
+            IOUtils.closeQuietly(tokenizer);
+        }
+    }
+
+    @Override
+    public MXMLDialect getMXMLDialect()
+    {
+        return mxmlDialect;
+    }
+
+    @Override
+    public PrefixMap getPrefixMapForData(IMXMLTagData data)
+    {
+        PrefixMap result = nsMap.get(data);
+        if (result != null)
+            return result;
+        if (data.isCloseTag())
+        {
+            IMXMLTagData openTagData = data.getParent().findTagOrSurroundingTagContainingOffset(data.getAbsoluteStart());
+            if (openTagData != null)
+                return nsMap.get(openTagData);
+        }
+        return null;
+    }
+
+    void removePrefixMappingForTag(IMXMLTagData data)
+    {
+        nsMap.remove(data);
+    }
+
+    void clearPrefixMappings()
+    {
+        nsMap.clear();
+    }
+
+    public void setPrefixMappings(HashMap<IMXMLTagData, PrefixMap> map)
+    {
+        if (nsMap != null)
+            nsMap.clear();
+        nsMap = map;
+    }
+
+    public Map<IMXMLTagData, PrefixMap> getTagToPrefixMap()
+    {
+        return nsMap;
+    }
+
+    /**
+     * Returns a collection of prefix->namespaces mappings found within this
+     * document. This map DOES NOT maintain order, and for more fine-grained
+     * information, the getPrefixMap call on individual {@link IMXMLTagData} and
+     * {@link IMXMLTagAttributeData} objects should be called
+     * 
+     * @return a prefix map
+     */
+    public PrefixMap getDocumentPrefixMap()
+    {
+        MutablePrefixMap map = new MutablePrefixMap();
+        for (PrefixMap tagMap : nsMap.values())
+        {
+            assert tagMap != null;
+            map.addAll(tagMap);
+        }
+        return map.toImmutable();
+    }
+
+    /**
+     * Returns the PrefixMap for the root tag of this {@link MXMLData} object
+     * 
+     * @return a {@link PrefixMap} or null
+     */
+    public PrefixMap getRootTagPrefixMap()
+    {
+        IMXMLTagData rootTag = getRootTag();
+        if (rootTag != null)
+        {
+            return nsMap.get(rootTag);
+        }
+        return null;
+    }
+
+    @Override
+    public Collection<ICompilerProblem> getProblems()
+    {
+        return problems;
+    }
+
+    public boolean hasProblems()
+    {
+        return problems.size() > 0;
+    }
+
+    /**
+     * Determines if this data was built from a source that was repaired
+     * 
+     * @return true if the underlying source was repaired
+     */
+    public boolean isDataRepaired()
+    {
+        return wasRepaired;
+    }
+
+    public void setWasRepaired(boolean wasRepaired)
+    {
+        this.wasRepaired = wasRepaired;
+    }
+
+    @Override
+    public IFileSpecification getFileSpecification()
+    {
+        return new FileSpecification(path);
+    }
+
+    @Override
+    public String getPath()
+    {
+        return path;
+    }
+
+    /**
+     * API to change the path after MXMLData creation. An MXMLDocument makes an
+     * MXMLData before the actual location is known.
+     * 
+     * @param path is the absolute path to the backing source file
+     */
+    public void setPath(String path)
+    {
+        this.path = path;
+    }
+
+    /**
+     * Common code from the two constructors
+     * 
+     * @param tokens A list of MXML tokens.
+     */
+    protected void initializeFromTokens(List<MXMLToken> tokens)
+    {
+        cursor = new Cursor();
+        parse(this, tokens, mxmlDialect, problems);
+        cursor.reset();
+    }
+
+    /**
+     * Use the MXML tokens to build MXMLUnitData.
+     * 
+     * @param data the {@link MXMLData} object
+     * @param tokens the list of tokens to build this data from
+     * @param dialect the {@link MXMLDialect} we are working against
+     * @param incremental true if this data is being built incrementally. All
+     * location updates will need to be done outside this element
+     */
+    private void parse(MXMLData data, List<MXMLToken> tokens, MXMLDialect dialect, Collection<ICompilerProblem> problems)
+    {
+        ArrayList<MXMLUnitData> units = new ArrayList<MXMLUnitData>(tokens.size() / 6);
+        nsMap = new HashMap<IMXMLTagData, PrefixMap>();
+        MXMLUnitData unit = null;
+        MXMLToken currentComment = null;
+        FastStack<Integer> depth = new FastStack<Integer>(tokens.size() / 8);
+        IFileSpecification spec = new FileSpecification(data.getPath() != null ? data.getPath() : "");
+        depth.setStackDecorator(new IFastStackDecorator<Integer>() {
+            @Override
+            public Integer decorate(Integer e)
+            {
+                if (e == null)
+                    return -1;
+                return e;
+            }
+
+        });
+        int index = -1;
+        int balancingIndex = 0;
+        depth.push(index);
+        ListIterator<MXMLToken> tokenIterator = tokens.listIterator();
+        BalancingMXMLProcessor processor = new BalancingMXMLProcessor(getFileSpecification(), problems);
+        while (tokenIterator.hasNext())
+        {
+            MXMLToken token = tokenIterator.next();
+            switch (token.getType())
+            {
+                case MXMLTokenTypes.TOKEN_ASDOC_COMMENT:
+                    currentComment = token;
+                    //treat this like text.
+                    unit = new MXMLTextData(token);
+                    units.add(unit);
+                    index++;
+                    if (fullContent)
+                    {
+                        unit.setParentUnitDataIndex(depth.peek());
+                        unit.setLocation(data, index);
+                    }
+                    break;
+                case MXMLTokenTypes.TOKEN_COMMENT:
+                case MXMLTokenTypes.TOKEN_CDATA:
+                case MXMLTokenTypes.TOKEN_WHITESPACE:
+                    //treat this like text.
+                    unit = new MXMLTextData(token);
+                    units.add(unit);
+                    index++;
+                    if (fullContent)
+                    {
+                        unit.setParentUnitDataIndex(depth.peek());
+                        unit.setLocation(data, index);
+                    }
+                    break;
+                case MXMLTokenTypes.TOKEN_OPEN_TAG_START:
+                    unit = new MXMLTagData();
+                    MutablePrefixMap map = ((MXMLTagData)unit).init(this, token, tokenIterator, dialect, spec, problems);
+                    ((MXMLTagData)unit).setCommentToken(currentComment);
+                    currentComment = null;
+                    units.add(unit);
+                    index++;
+                    if (fullContent)
+                    {
+                        unit.setParentUnitDataIndex(depth.peek());
+                        unit.setLocation(data, index);
+                        if (!((MXMLTagData)unit).isEmptyTag())
+                            processor.addOpenTag((MXMLTagData)unit, balancingIndex);
+                    }
+                    if (map != null)
+                        nsMap.put((MXMLTagData)unit, map.toImmutable());
+                    if (!((MXMLTagData)unit).isEmptyTag())
+                    {
+                        depth.push(index);
+                        balancingIndex++;
+                    }
+                    break;
+                case MXMLTokenTypes.TOKEN_CLOSE_TAG_START:
+                    unit = new MXMLTagData();
+                    ((MXMLTagData)unit).init(this, token, tokenIterator, dialect, spec, problems);
+                    ((MXMLTagData)unit).setCommentToken(currentComment);
+                    if (!((MXMLTagData)unit).isEmptyTag())
+                    {
+                        depth.pop();
+                        balancingIndex--;
+                    }
+                    index++;
+                    if (fullContent)
+                    {
+                        unit.setLocation(data, index);
+                        unit.setParentUnitDataIndex(depth.peek());
+                        processor.addCloseTag((MXMLTagData)unit, balancingIndex);
+                    }
+                    currentComment = null;
+                    units.add(unit);
+                    break;
+                case MXMLTokenTypes.TOKEN_TEXT:
+                    unit = new MXMLTextData(token);
+                    units.add(unit);
+                    index++;
+                    if (fullContent)
+                    {
+                        unit.setParentUnitDataIndex(depth.peek());
+                        unit.setLocation(data, index);
+                    }
+                    break;
+                case MXMLTokenTypes.TOKEN_MXML_BLOB:
+                    unit = new MXMLTagBlobData(token);
+                    units.add(unit);
+                    index++;
+                    if (fullContent)
+                    {
+                        unit.setParentUnitDataIndex(depth.peek());
+                        unit.setLocation(data, index);
+                    }
+                    break;
+                case MXMLTokenTypes.TOKEN_DATABINDING_START:
+                    unit = new MXMLDatabindingData(token, tokenIterator);
+                    units.add(unit);
+                    index++;
+                    if (fullContent)
+                    {
+                        unit.setParentUnitDataIndex(depth.peek());
+                        unit.setLocation(data, index);
+                    }
+                    break;
+                case MXMLTokenTypes.TOKEN_PROCESSING_INSTRUCTION:
+                    unit = new MXMLInstructionData(token);
+                    units.add(unit);
+                    index++;
+                    if (fullContent)
+                    {
+                        unit.setParentUnitDataIndex(depth.peek());
+                        unit.setLocation(data, index);
+                    }
+                    break;
+                default:
+                    if (token.isEntity())
+                    {
+                        unit = new MXMLEntityData(token);
+                        units.add(unit);
+                        index++;
+                        if (fullContent)
+                        {
+                            unit.setParentUnitDataIndex(depth.peek());
+                            unit.setLocation(data, index);
+                        }
+                        break;
+                    }
+                    else
+                    {
+                        problems.add(new SyntaxProblem(token));
+                        break;
+                    }
+            }
+        }
+        this.units = units.toArray(new IMXMLUnitData[0]);
+        if (fullContent && shouldRepair)
+        {
+            this.units = processor.balance(this.units, this, nsMap);
+            if (processor.wasRepaired())
+            { //repaired, so let's rebuild our prefix maps and tag depths
+                refreshPositionData();
+            }
+        }
+    }
+
+    /**
+     * Used to rebuild the structures inside of the MXMLData, refreshing prefix
+     * maps, depth and position data. Should only be used after calls that
+     * rebuild the internal structure are called
+     */
+    public void refreshPositionData()
+    {
+        FastStack<Integer> depth = new FastStack<Integer>(units.length / 2);
+        depth.setStackDecorator(new IFastStackDecorator<Integer>() {
+            @Override
+            public Integer decorate(Integer e)
+            {
+                if (e == null)
+                    return -1;
+                return e;
+            }
+
+        });
+        depth.clear();
+        depth.push(-1);
+        for (int i = 0; i < units.length; i++)
+        {
+            if (units[i] instanceof IMXMLTagData)
+            {
+                IMXMLTagData currentTag = (IMXMLTagData)units[i];
+                if (currentTag.isCloseTag())
+                {
+                    if (!currentTag.isEmptyTag())
+                        depth.pop();
+                }
+                ((MXMLTagData)currentTag).setParentUnitDataIndex(depth.peek());
+                ((MXMLTagData)currentTag).setLocation(this, i);
+                if (currentTag.isOpenTag())
+                {
+                    if (!currentTag.isEmptyTag())
+                    {
+                        depth.push(i);
+                    }
+                }
+            }
+            else
+            {
+                ((MXMLUnitData)units[i]).setParentUnitDataIndex(depth.peek());
+                ((MXMLUnitData)units[i]).setLocation(this, i);
+            }
+        }
+    }
+
+    @Override
+    public IMXMLUnitData[] getUnits()
+    {
+        return units;
+    }
+
+    public Iterator<IMXMLUnitData> getUnitIterator()
+    {
+        return new MXMLUnitDataIterator(units);
+    }
+
+    /**
+     * Replace the list of units in this MXMLData.
+     * 
+     * @param units units to add
+     */
+    public void setUnits(IMXMLUnitData[] units)
+    {
+        this.units = units;
+    }
+
+    @Override
+    public IMXMLUnitData getUnit(int i)
+    {
+        if (i < 0 || i >= units.length)
+            return null;
+        return units[i];
+    }
+
+    @Override
+    public int getNumUnits()
+    {
+        return units.length;
+    }
+
+    /**
+     * If the offset is contained within an MXML unit, get that unit. If it's
+     * not, then get the first unit that follows the offset.
+     * 
+     * @param offset test offset
+     * @return unit that contains (or immediately follows) the offset A few
+     * subtleties: In Falcon we have endeavored to preserve the existing
+     * definition of "nearest", so that for a given MXML file, falcon will find
+     * the same "nearest" unit.
+     */
+
+    protected IMXMLUnitData findNearestUnit(int offset)
+    {
+
+        // Use the cursor as a fast search hint. But only if the cursor is at or before the
+        // are of interest.
+        // TODO: do we care that this is not thread safe?
+        int startOffset = 0;
+        if (cursor.getOffset() <= offset)
+            startOffset = cursor.getUnitIndex();
+
+        // Sanity check
+        if (startOffset < 0 || startOffset >= units.length)
+            startOffset = 0;
+
+        // Now iterate though the units and find the first one that is acceptable
+        IMXMLUnitData ret = null;
+        for (int i = startOffset; (i < units.length) && (ret == null); i++)
+        {
+            IMXMLUnitData unit = units[i];
+
+            // unit is a match if it "contains" the offset.
+            // We are using a somewhat bizarre form of "contains" here, in that we are
+            // using getStart() and getConentEnd(). This asymmetric mismatch is for several reasons:
+            //      * it's the only way to match the existing (non-falcon) behavior
+            //      * If our cursor is before the <, we want to match the tag.
+            //              example:     |<foo   >  will find "foo" as the nearest tag.
+            //      So we need to use start here (not content start)
+            //      * If our cursor is between two tags, we want to match the NEXT one, not the previous one
+            //              example:   <bar >|<foo>  should match foo, not bar
+
+            if (MXMLData.contains(unit.getAbsoluteStart(), unit.getContentEnd(), offset))
+            {
+                ret = unit;
+            }
+            // if we find a unit that starts after the offset, then it must
+            // be the "first one after", so return it
+            else if (unit.getAbsoluteStart() >= offset)
+            {
+                ret = unit;
+            }
+        }
+
+        // If we found something, update the cursor for the next search
+        if (ret != null)
+            cursor.setCursor(offset, ret.getIndex());
+        return ret;
+    }
+
+    /**
+     * Get the unit that should be referenced when looking at what tags contain
+     * this offset (i.e. tags that are opened and not closed before this offset)
+     * 
+     * @param offset test offset
+     * @return reference unit for containment searches
+     */
+    public IMXMLUnitData findContainmentReferenceUnit(int offset)
+    {
+        return findNearestUnit(offset);
+    }
+
+    /**
+     * Get the unit that contains this offset
+     * 
+     * @param offset test offset
+     * @return the containing unit (or null if no unit contains this offset)
+     */
+    public IMXMLUnitData findUnitContainingOffset(int offset)
+    {
+        IMXMLUnitData unit = findNearestUnit(offset);
+        if (unit != null && unit.containsOffset(offset))
+            return unit;
+
+        return null;
+    }
+
+    /**
+     * Get the open, close, or empty tag that contains this offset. Note that if
+     * offset is inside a text node, this returns null. If you want the
+     * surrounding tag in that case, use
+     * findTagOrSurroundingTagContainingOffset.
+     * 
+     * @param offset test offset
+     * @return the containing tag (or null, if no tag contains this offset)
+     */
+    public IMXMLTagData findTagContainingOffset(int offset)
+    {
+        IMXMLUnitData unit = findUnitContainingOffset(offset);
+        if (unit != null && unit.isTag())
+            return (IMXMLTagData)unit;
+
+        return null;
+    }
+
+    @Override
+    public IMXMLTagData findTagOrSurroundingTagContainingOffset(int offset)
+    {
+        IMXMLUnitData unit = findUnitContainingOffset(offset);
+        if (unit != null)
+        {
+            if (unit.isTag())
+            {
+                return (IMXMLTagData)unit;
+            }
+            else if (unit.isText())
+            {
+                IMXMLTagData containingTag = unit.getContainingTag(unit.getAbsoluteStart());
+                return containingTag;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the open or empty tag whose attribute list contains this offset. A
+     * tag's attribute list extends from after the tag name + first whitespace
+     * until before the closing ">" or "/>".
+     * 
+     * @param offset test offset
+     * @return tag whose attribute list contains this offset (or null, if the
+     * offset isn't in any attribute lists
+     */
+    public IMXMLTagData findAttributeListContainingOffset(int offset)
+    {
+        IMXMLTagData tag = findTagContainingOffset(offset);
+        if (tag != null && tag.isOpenTag())
+            return tag.isOffsetInAttributeList(offset) ? tag : null;
+
+        return null;
+    }
+
+    /**
+     * Test whether the offset is contained within the range from start to end.
+     * This test excludes the start position and includes the end position,
+     * which is how you want things to work for code hints.
+     * 
+     * @param start start of the range (excluded)
+     * @param end end of the range (included)
+     * @param offset test offset
+     * @return true iff the offset is contained in the range
+     */
+    public static boolean contains(int start, int end, int offset)
+    {
+        return start < offset && end >= offset;
+    }
+
+    @Override
+    public IMXMLTagData getRootTag()
+    {
+        int n = units.length;
+        for (int i = 0; i < n; i++)
+        {
+            IMXMLUnitData unit = units[i];
+            if (unit instanceof IMXMLTagData)
+                return (IMXMLTagData)unit;
+        }
+        return null;
+    }
+
+    @Override
+    public int getEnd()
+    {
+        final int n = getNumUnits();
+        return n > 0 ? getUnit(n - 1).getAbsoluteEnd() : 0;
+    }
+
+    public Cursor getCursor()
+    {
+        return cursor;
+    }
+
+    /**
+     * Verifies that all units (plus all attributes on units that are tags) have
+     * their source location information set.
+     * <p>
+     * This is used only in asserts.
+     */
+    public boolean verify()
+    {
+        for (IMXMLUnitData unit : getUnits())
+        {
+            ((MXMLUnitData)unit).verify();
+        }
+
+        return true;
+    }
+
+    // For debugging only.
+    void dumpUnits()
+    {
+        for (IMXMLUnitData unit : getUnits())
+        {
+            System.out.println(((MXMLUnitData)unit).toDumpString());
+        }
+    }
+
+    /**
+     * For debugging only.
+     */
+    @Override
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        IMXMLUnitData[] units = getUnits();
+        int n = units.length;
+        for (int i = 0; i < n; i++)
+        {
+            // Display the unit's index as, for example, [3].
+            sb.append('[');
+            sb.append(i);
+            sb.append(']');
+
+            sb.append(' ');
+
+            // Display the unit's information.
+            sb.append(units[i].toString());
+
+            sb.append('\n');
+        }
+
+        return sb.toString();
+    }
+
+    public static void main(String[] args)
+    {
+        final FileSpecification fileSpec = new FileSpecification(args[0]);
+        final MXMLTokenizer tokenizer = new MXMLTokenizer(fileSpec);
+        List<MXMLToken> tokens = null;
+        try
+        {
+            tokens = tokenizer.parseTokens(fileSpec.createReader());
+
+            // Build tags and attributes from the tokens.
+            final MXMLData mxmlData = new MXMLData(tokens, tokenizer.getPrefixMap(), fileSpec);
+
+            mxmlData.dumpUnits();
+        }
+        catch (FileNotFoundException e)
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        finally
+        {
+            IOUtils.closeQuietly(tokenizer);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDataManager.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDataManager.java b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDataManager.java
index 3364a26..19cacfa 100644
--- a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDataManager.java
+++ b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDataManager.java
@@ -22,7 +22,6 @@ package org.apache.flex.compiler.internal.mxml;
 import org.apache.flex.compiler.filespecs.IFileSpecification;
 import org.apache.flex.compiler.internal.caches.MXMLDataCache;
 import org.apache.flex.compiler.mxml.IMXMLDataManager;
-import org.apache.flex.compiler.mxml.MXMLData;
 
 /**
  * The {@code MXMLDataManager} of the {@code IWorkspace}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDatabindingData.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDatabindingData.java b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDatabindingData.java
new file mode 100644
index 0000000..da7f720
--- /dev/null
+++ b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDatabindingData.java
@@ -0,0 +1,58 @@
+/*
+ *
+ *  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 org.apache.flex.compiler.internal.mxml;
+
+import java.util.ListIterator;
+
+import org.apache.flex.compiler.internal.parsing.mxml.MXMLToken;
+import org.apache.flex.compiler.mxml.IMXMLDatabindingData;
+import org.apache.flex.compiler.mxml.IMXMLDatabindingValue;
+import org.apache.flex.compiler.parsing.IASToken;
+
+/**
+ * Represents a databinding expression found within content of MXML
+ */
+public class MXMLDatabindingData extends MXMLUnitData implements
+        IMXMLDatabindingData
+{
+    /**
+     * Constructor.
+     */
+    MXMLDatabindingData(MXMLToken start, ListIterator<MXMLToken> iterator)
+    {
+        bindingValue = new MXMLDatabindingValue(start, iterator);
+
+        setOffsets(bindingValue.getAbsoluteStart(), bindingValue.getAbsoluteEnd());
+        setLine(start.getLine());
+        setColumn(start.getColumn());
+    }
+
+    private IMXMLDatabindingValue bindingValue;
+
+    //
+    // IMXMLDatabindingData implementations
+    //
+
+    @Override
+    public IASToken[] getDatabindingContent()
+    {
+        return bindingValue.getDatabindingContent();
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDatabindingValue.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDatabindingValue.java b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDatabindingValue.java
new file mode 100644
index 0000000..2eee4d1
--- /dev/null
+++ b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLDatabindingValue.java
@@ -0,0 +1,113 @@
+/*
+ *
+ *  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 org.apache.flex.compiler.internal.mxml;
+
+import java.util.ArrayList;
+import java.util.ListIterator;
+
+import org.apache.flex.compiler.internal.parsing.mxml.MXMLToken;
+import org.apache.flex.compiler.mxml.IMXMLDatabindingValue;
+import org.apache.flex.compiler.mxml.IMXMLTagAttributeData;
+import org.apache.flex.compiler.mxml.IMXMLTextData.TextType;
+import org.apache.flex.compiler.parsing.IASToken;
+
+/**
+ * Represents a databinding expression found within an attribute value
+ */
+public class MXMLDatabindingValue extends MXMLTagAttributeValue implements
+        IMXMLDatabindingValue
+{
+    /**
+     * Constructor.
+     */
+    MXMLDatabindingValue(MXMLToken start, ListIterator<MXMLToken> iterator, IMXMLTagAttributeData parent)
+    {
+        super(parent);
+
+        setStart(start.getStart());
+        setColumn(start.getColumn());
+        setLine(start.getLine());
+
+        while (iterator.hasNext())
+        {
+            MXMLToken token = iterator.next();
+
+            setEnd(token.getEnd());
+
+            if (token.isASToken())
+                tokens.add(token);
+            else
+                break;
+        }
+    }
+
+    /**
+     * Constructor.
+     */
+    MXMLDatabindingValue(MXMLToken start, ListIterator<MXMLToken> iterator)
+    {
+        this(start, iterator, null);
+    }
+
+    private ArrayList<IASToken> tokens = new ArrayList<IASToken>(5);
+
+    //
+    // IMXMLTextData implementations
+    //
+
+    @Override
+    public String getContent()
+    {
+        StringBuilder builder = new StringBuilder();
+
+        final int size = tokens.size();
+        IASToken lastToken = null;
+        for (int i = 0; i < size; i++)
+        {
+            IASToken currentToken = tokens.get(i);
+            if (lastToken != null)
+            {
+                int spaces = currentToken.getStart() - lastToken.getEnd();
+                for (int s = 0; s < spaces; s++)
+                    builder.append(" ");
+            }
+            builder.append(currentToken.getText());
+            lastToken = currentToken;
+        }
+
+        return builder.toString();
+    }
+
+    @Override
+    public TextType getTextType()
+    {
+        return TextType.DATABINDING;
+    }
+
+    //
+    // IMXMLDatabindingData implementations
+    //
+
+    @Override
+    public IASToken[] getDatabindingContent()
+    {
+        return tokens.toArray(new IASToken[0]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLEntityData.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLEntityData.java b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLEntityData.java
new file mode 100644
index 0000000..96604cd
--- /dev/null
+++ b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLEntityData.java
@@ -0,0 +1,80 @@
+/*
+ *
+ *  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 org.apache.flex.compiler.internal.mxml;
+
+import org.apache.flex.compiler.internal.parsing.mxml.MXMLToken;
+import org.apache.flex.compiler.mxml.IMXMLEntityData;
+
+public class MXMLEntityData extends MXMLTextData implements IMXMLEntityData
+{
+    /**
+     * Constructor.
+     */
+    MXMLEntityData(MXMLToken textToken)
+    {
+        super(textToken);
+
+        type = textToken.getType();
+    }
+
+    private int type;
+
+    //
+    // Object overrides
+    //
+
+    // This method is only used for debugging.
+    @Override
+    public String toString()
+    {
+        String s = getCompilableText();
+
+        s = s.replaceAll("\n", "\\\\n");
+        s = s.replaceAll("\r", "\\\\r");
+        s = s.replaceAll("\t", "\\\\t");
+
+        StringBuilder sb = new StringBuilder();
+        sb.append(type);
+        sb.append(" \"");
+        sb.append(s);
+        sb.append("\"");
+        return sb.toString();
+    }
+
+    //
+    // MXMLTextData overrides
+    // 
+
+    @Override
+    public String getCompilableText()
+    {
+        return getDecodedContent();
+    }
+
+    //
+    // IMXMLEntityData implementations
+    //
+
+    @Override
+    public String getDecodedContent()
+    {
+        return MXMLEntityValue.getDecodedContent(getContents(), type);
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLEntityValue.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLEntityValue.java b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLEntityValue.java
new file mode 100644
index 0000000..29d7db7
--- /dev/null
+++ b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLEntityValue.java
@@ -0,0 +1,144 @@
+/*
+ *
+ *  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 org.apache.flex.compiler.internal.mxml;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.flex.compiler.mxml.IMXMLEntityValue;
+import org.apache.flex.compiler.mxml.IMXMLTagAttributeData;
+import org.apache.flex.compiler.mxml.IMXMLTextData.TextType;
+import org.apache.flex.compiler.parsing.IMXMLToken;
+import org.apache.flex.compiler.parsing.MXMLTokenTypes;
+
+public class MXMLEntityValue extends MXMLTagAttributeValue implements
+        IMXMLEntityValue
+{
+    private static final Map<String, String> NAMED_ENTITIES;
+
+    static
+    {
+        NAMED_ENTITIES = new HashMap<String, String>(5);
+
+        NAMED_ENTITIES.put("&amp;", "&");
+        NAMED_ENTITIES.put("&apos;", "'");
+        NAMED_ENTITIES.put("&gt;", ">");
+        NAMED_ENTITIES.put("&lt;", "<");
+        NAMED_ENTITIES.put("&quot;", "\"");
+
+        // TODO HTML 4 supports about 250 named characters
+        // HTML 5 supports about 2500. How many should MXML support
+        // beyond these required 5? What did Xerces/mxmlc support?
+    }
+
+    static final String getDecodedContent(String content, int type)
+    {
+        switch (type)
+        {
+            case MXMLTokenTypes.TOKEN_ENTITY:
+            {
+                return NAMED_ENTITIES.get(content);
+            }
+            case MXMLTokenTypes.TOKEN_HEX_ENTITY:
+            {
+                //thanks to the lexer, we are always: &#x00000;
+                //strip off the first 3 chars and the trailing semicolon
+                return String.valueOf(Integer.parseInt(content.substring(3, content.length() - 1), 16));
+            }
+            case MXMLTokenTypes.TOKEN_DECIMAL_ENTITY:
+            {
+                //thanks to the lexer, we are always: &#\21267;
+                //strip off the first 3 chars and the trailing semicolon
+                return String.valueOf(Integer.parseInt(content.substring(3, content.length() - 1)));
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Constructor.
+     */
+    MXMLEntityValue(IMXMLToken token, IMXMLTagAttributeData parent)
+    {
+        super(parent);
+
+        content = token.getText();
+        type = token.getType();
+
+        setStart(token.getStart());
+        setEnd(token.getEnd());
+        setColumn(token.getColumn());
+        setLine(token.getLine());
+    }
+
+    private final String content;
+
+    /**
+     * Token type which tells us what kind of entity we are dealing with
+     */
+    private final int type;
+
+    //
+    // Object overrides
+    //
+
+    // For debugging only. This format is nice in the Eclipse debugger.
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("|");
+        sb.append(getContent());
+        sb.append("| ");
+        sb.append(getLine());
+        sb.append(" ");
+        sb.append(getColumn());
+
+        return sb.toString();
+    }
+
+    //
+    // IMXMLTagAttributeValue implementations
+    //
+
+    @Override
+    public String getContent()
+    {
+        return content;
+    }
+
+    @Override
+    public TextType getTextType()
+    {
+        return TextType.ENTITY;
+    }
+
+    //
+    // IMXMLEntityValue implementations
+    //
+
+    @Override
+    public String getDecodedContent()
+    {
+        return getDecodedContent(content, type);
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLInstructionData.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLInstructionData.java b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLInstructionData.java
new file mode 100644
index 0000000..da2fec4
--- /dev/null
+++ b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLInstructionData.java
@@ -0,0 +1,97 @@
+/*
+ *
+ *  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 org.apache.flex.compiler.internal.mxml;
+
+import org.apache.flex.compiler.mxml.IMXMLInstructionData;
+import org.apache.flex.compiler.parsing.IMXMLToken;
+
+public class MXMLInstructionData extends MXMLUnitData implements
+        IMXMLInstructionData
+{
+    /**
+     * Constructor.
+     */
+    MXMLInstructionData(IMXMLToken token)
+    {
+        instructionText = token.getText();
+
+        setOffsets(token.getStart(), token.getEnd());
+        setColumn(token.getColumn());
+        setLine(token.getLine());
+    }
+
+    private String instructionText;
+
+    //
+    // Object overrides
+    //
+
+    // For debugging only. This format is nice in the Eclipse debugger.
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append('|');
+        sb.append(getInstructionText());
+        sb.append('|');
+
+        sb.append(' ');
+
+        // Display line, column, start, and end as "17:5 160-188".
+        sb.append(super.toString());
+
+        return sb.toString();
+    }
+
+    //
+    // MXMLUnitData overrides
+    //
+
+    // For debugging only. This format is nice in a text file.
+    @Override
+    public String toDumpString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(super.toDumpString());
+
+        sb.append('\t');
+
+        sb.append('"');
+        sb.append(getInstructionText());
+        sb.append('"');
+
+        return sb.toString();
+    }
+
+    //
+    // IMXMLInstructionData implementations
+    //
+
+    /**
+     * Returns the raw processing instruction. It is up to clients to parse
+     * this.
+     */
+    public String getInstructionText()
+    {
+        return instructionText;
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLNamespaceAttributeData.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLNamespaceAttributeData.java b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLNamespaceAttributeData.java
new file mode 100644
index 0000000..4c00837
--- /dev/null
+++ b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLNamespaceAttributeData.java
@@ -0,0 +1,64 @@
+/*
+ *
+ *  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 org.apache.flex.compiler.internal.mxml;
+
+import java.util.Collection;
+import java.util.ListIterator;
+
+import org.apache.flex.compiler.filespecs.IFileSpecification;
+import org.apache.flex.compiler.internal.parsing.mxml.MXMLToken;
+import org.apache.flex.compiler.mxml.IMXMLNamespaceAttributeData;
+import org.apache.flex.compiler.problems.ICompilerProblem;
+
+/**
+ * Represents an xmlns style namespace import found within the MXML language
+ */
+public class MXMLNamespaceAttributeData extends MXMLTagAttributeData implements
+        IMXMLNamespaceAttributeData
+{
+    /**
+     * Constructor.
+     */
+    MXMLNamespaceAttributeData(MXMLToken nameToken, ListIterator<MXMLToken> tokenIterator, MXMLDialect mxmlDialect, IFileSpecification spec, Collection<ICompilerProblem> problems)
+    {
+        super(nameToken, tokenIterator, mxmlDialect, spec, problems);
+
+        if (attributeName.startsWith("xmlns:"))
+            prefix = attributeName.substring(6);
+    }
+
+    private String prefix = "";
+
+    //
+    // IMXMLNamepsaceAttributeData implementations
+    //
+
+    @Override
+    public String getNamespacePrefix()
+    {
+        return prefix;
+    }
+
+    @Override
+    public String getNamespace()
+    {
+        return getRawValue();
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLNamespaceMapping.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLNamespaceMapping.java b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLNamespaceMapping.java
new file mode 100644
index 0000000..272fcc7
--- /dev/null
+++ b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLNamespaceMapping.java
@@ -0,0 +1,76 @@
+/*
+ *
+ *  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 org.apache.flex.compiler.internal.mxml;
+
+import org.apache.flex.compiler.mxml.IMXMLNamespaceMapping;
+
+/**
+ * This class stores a MXML-namespace-URI-to-manifest-file mapping.
+ */
+public class MXMLNamespaceMapping implements IMXMLNamespaceMapping
+{
+    public MXMLNamespaceMapping(String uri, String manifestFileName)
+    {
+        assert uri != null;
+        assert manifestFileName != null;
+        this.uri = uri;
+        this.manifestFileName = manifestFileName;
+    }
+
+    private String uri;
+    private String manifestFileName;
+
+    @Override
+    public String getURI()
+    {
+        return uri;
+    }
+
+    @Override
+    public String getManifestFileName()
+    {
+        return manifestFileName;
+    }
+
+    /**
+     * For debugging.
+     * 
+     * @return Debug string representation of this object.
+     */
+    @Override
+    public String toString()
+    {
+        return uri + "->" + manifestFileName;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == this)
+            return true;
+        if (!(obj instanceof MXMLNamespaceMapping))
+            return false;
+        MXMLNamespaceMapping other = (MXMLNamespaceMapping)obj;
+        if (!(uri.equals(other.uri)))
+            return false;
+        return manifestFileName.equals(other.manifestFileName);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLStateSplitter.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLStateSplitter.java b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLStateSplitter.java
new file mode 100644
index 0000000..3c78c33
--- /dev/null
+++ b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLStateSplitter.java
@@ -0,0 +1,86 @@
+/*
+ *
+ *  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 org.apache.flex.compiler.internal.mxml;
+
+import java.util.Collection;
+
+import org.apache.flex.compiler.filespecs.IFileSpecification;
+import org.apache.flex.compiler.internal.parsing.mxml.MXMLToken;
+import org.apache.flex.compiler.parsing.IMXMLToken;
+import org.apache.flex.compiler.problems.ICompilerProblem;
+import org.apache.flex.compiler.problems.SyntaxProblem;
+
+/**
+ * Simple utility for parsing attribute.state phrases.
+ */
+public class MXMLStateSplitter
+{
+    /**
+     * Constructor.
+     */
+    public MXMLStateSplitter(IMXMLToken nameToken, MXMLDialect mxmlDialect, Collection<ICompilerProblem> problems, IFileSpecification fileSpec)
+    {
+        // Is there a dot in the name?
+        String name = nameToken.getText();
+        int i = name.indexOf('.');
+        if (i >= 0)
+        {
+            if (mxmlDialect != null && mxmlDialect.isEqualToOrAfter(MXMLDialect.MXML_2009))
+            {
+                baseName = name.substring(0, i);
+                stateName = name.substring(i + 1);
+                stateNameOffset = i + 1;
+            }
+            else
+            {
+                stateNameOffset = -1;
+                baseName = name;
+                stateName = null;
+
+                // TODO: I don't think is going to make the right kind of "problem"
+                // This is how the old code worked, but I think it will give a strange message
+                if (problems != null && fileSpec != null)
+                    problems.add(new SyntaxProblem((MXMLToken)nameToken, "Spark state overrides not supported by current language version"));
+            }
+        }
+        else
+        {
+            // no dot.
+            baseName = name;
+            stateNameOffset = -1;
+            stateName = null;
+        }
+    }
+
+    /**
+     * The part of the name before the dot, or the whole name if no dot.
+     */
+    public final String baseName;
+
+    /**
+     * What's after the first dot (state override), or null if no dot
+     */
+    public final String stateName;
+
+    /**
+     * offset of state name, where zero is the first character in the name
+     */
+    public final int stateNameOffset;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/bec3ba00/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLTagAttributeData.java
----------------------------------------------------------------------
diff --git a/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLTagAttributeData.java b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLTagAttributeData.java
new file mode 100644
index 0000000..b921919
--- /dev/null
+++ b/compiler/src/org/apache/flex/compiler/internal/mxml/MXMLTagAttributeData.java
@@ -0,0 +1,637 @@
+/*
+ *
+ *  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 org.apache.flex.compiler.internal.mxml;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.ListIterator;
+
+import org.apache.flex.compiler.common.ISourceLocation;
+import org.apache.flex.compiler.common.PrefixMap;
+import org.apache.flex.compiler.common.SourceLocation;
+import org.apache.flex.compiler.common.XMLName;
+import org.apache.flex.compiler.filespecs.IFileSpecification;
+import org.apache.flex.compiler.internal.parsing.ISourceFragment;
+import org.apache.flex.compiler.internal.parsing.mxml.MXMLToken;
+import org.apache.flex.compiler.mxml.IMXMLTagAttributeData;
+import org.apache.flex.compiler.mxml.IMXMLTagAttributeValue;
+import org.apache.flex.compiler.mxml.IMXMLTagData;
+import org.apache.flex.compiler.mxml.IMXMLTextValue;
+import org.apache.flex.compiler.parsing.IMXMLToken;
+import org.apache.flex.compiler.parsing.MXMLTokenTypes;
+import org.apache.flex.compiler.problems.ICompilerProblem;
+import org.apache.flex.compiler.problems.SyntaxProblem;
+
+/**
+ * Encapsulation of a tag attribute in MXML
+ */
+public class MXMLTagAttributeData extends SourceLocation implements
+        IMXMLTagAttributeData
+{
+    /**
+     * Constructor.
+     */
+    MXMLTagAttributeData(MXMLToken nameToken, ListIterator<MXMLToken> tokenIterator, MXMLDialect mxmlDialect, IFileSpecification spec, Collection<ICompilerProblem> problems)
+    {
+        setStart(nameToken.getStart());
+        setLine(nameToken.getLine());
+        setColumn(nameToken.getColumn());
+        setEnd(nameToken.getEnd());
+
+        // Deal with name if it is of the form name.state
+        MXMLStateSplitter splitState = new MXMLStateSplitter(nameToken, mxmlDialect, problems, spec);
+        attributeName = splitState.baseName;
+        if (splitState.stateName != null)
+        {
+            stateName = splitState.stateName;
+            stateStart = nameToken.getStart() + splitState.stateNameOffset;
+        }
+
+        MXMLToken token = null;
+
+        // Look for "=" token
+        if (tokenIterator.hasNext())
+        {
+            token = tokenIterator.next();
+
+            if (token.getType() != MXMLTokenTypes.TOKEN_EQUALS)
+            {
+                problems.add(new SyntaxProblem(token));
+                // need to restore the token position in the error
+                // case to handle error recovery otherwise the any
+                // trees after this won't be created
+                tokenIterator.previous();
+                return;
+            }
+
+            valueStart = token.getEnd() + 1; //set the attributes start to right after the equals until we have a value
+            valueLine = token.getLine();
+            valueColumn = token.getColumn();
+        }
+
+        // Look for value token
+        ArrayList<IMXMLTagAttributeValue> values = new ArrayList<IMXMLTagAttributeValue>(3);
+        while (tokenIterator.hasNext())
+        {
+            token = tokenIterator.next();
+            if (token.getType() == MXMLTokenTypes.TOKEN_DATABINDING_START)
+            {
+                values.add(new MXMLDatabindingValue(token, tokenIterator, this));
+            }
+            else if (token.getType() == MXMLTokenTypes.TOKEN_STRING)
+            {
+                values.add(new MXMLTextValue(token, this));
+            }
+            else if (token.isEntity())
+            {
+                values.add(new MXMLEntityValue(token, this));
+            }
+            else
+            {
+                if (!MXMLToken.isTagEnd(token.getType()) && token.getType() != MXMLTokenTypes.TOKEN_NAME)
+                {
+                    // if we error out early, push back token - it may be start of next tag
+                    // this is "pre-falcon" repair that was lost
+                    tokenIterator.previous();
+                    problems.add(new SyntaxProblem(token));
+                }
+                else
+                {
+                    tokenIterator.previous();
+                }
+                break;
+            }
+        }
+
+        this.values = values.toArray(new MXMLTagAttributeValue[0]);
+
+        if (this.values.length > 0)
+        {
+            //set the start value
+            IMXMLTagAttributeValue value = this.values[0];
+            valueStart = value.getAbsoluteStart();
+            valueLine = value.getLine();
+            valueColumn = value.getColumn();
+            final int valueEnd = getValueEnd();
+            setEnd(valueEnd + 1);
+        }
+    }
+
+    /**
+     * The MXML tag that contains this attribute
+     */
+    protected IMXMLTagData parent;
+
+    /**
+     * The name of this attribute.
+     */
+    protected String attributeName;
+
+    /**
+     * The offset at which the attribute value starts
+     */
+    protected int valueStart;
+
+    /**
+     * The line on which the attribute value starts
+     */
+    protected int valueLine;
+
+    /**
+     * The column at which the attribute value starts
+     */
+    protected int valueColumn;
+
+    /**
+     * Array of values inside this attribute data.
+     */
+    private IMXMLTagAttributeValue[] values = new IMXMLTagAttributeValue[0];
+
+    /**
+     * The name of this state, if it exists
+     */
+    protected String stateName;
+
+    /**
+     * The offset at which the optional state starts
+     */
+    protected int stateStart;
+
+    /**
+     * The URI specified by this attribute's prefix.
+     */
+    protected String uri;
+
+    //
+    // Object overrides.
+    //
+
+    // For debugging only. This format is nice in the Eclipse debugger.
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+        buildAttributeString(false);
+        return sb.toString();
+    }
+
+    /**
+     * For unit tests only.
+     * 
+     * @return name value and offsets in string form
+     */
+    public String buildAttributeString(boolean skipSrcPath)
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getName());
+        sb.append('=');
+        sb.append('"');
+        sb.append(getRawValue());
+        sb.append('"');
+
+        sb.append(' ');
+
+        // Display line, column, start, and end as "17:5 160-188".
+        if (skipSrcPath)
+            sb.append(getOffsetsString());
+        else
+            sb.append(super.toString());
+        return sb.toString();
+    }
+
+    //
+    // Other methods
+    //
+
+    @Override
+    public IMXMLTagData getParent()
+    {
+        return parent;
+    }
+
+    /**
+     * Sets this attribute's tag.
+     * 
+     * @param parent MXML tag containing this attribute
+     */
+    public void setParent(IMXMLTagData parent)
+    {
+        this.parent = parent;
+        setSourcePath(parent.getSourcePath());
+    }
+
+    /**
+     * Adjust all associated offsets by the adjustment amount
+     * 
+     * @param offsetAdjustment amount to add to offsets
+     */
+    public void adjustOffsets(int offsetAdjustment)
+    {
+        if (attributeName != null)
+        {
+            setStart(getAbsoluteStart() + offsetAdjustment);
+            setEnd(getAbsoluteEnd() + offsetAdjustment);
+        }
+
+        if (hasValue())
+        {
+            valueStart += offsetAdjustment;
+            for (int i = 0; i < values.length; i++)
+            {
+                ((MXMLTagAttributeValue)values[i]).setStart(values[i].getAbsoluteStart() + offsetAdjustment);
+                ((MXMLTagAttributeValue)values[i]).setEnd(values[i].getAbsoluteEnd() + offsetAdjustment);
+            }
+        }
+
+        if (stateName != null)
+            stateStart += offsetAdjustment;
+    }
+
+    @Override
+    public String getName()
+    {
+        return attributeName;
+    }
+
+    @Override
+    public String getStateName()
+    {
+        return stateName != null ? stateName : "";
+    }
+
+    /**
+     * Checks whether this attribute is associated with a state.
+     * 
+     * @return True if a state association exists.
+     */
+    public boolean hasState()
+    {
+        return stateName != null;
+    }
+
+    @Override
+    public boolean hasValue()
+    {
+        return values.length > 0;
+    }
+
+    @Override
+    public IMXMLTagAttributeValue[] getValues()
+    {
+        return values;
+    }
+
+    /**
+     * Get the attribute value as a String (with quotes)
+     * 
+     * @return attribute value (with quotes)
+     */
+    public String getValueWithQuotes()
+    {
+        StringBuilder value = new StringBuilder();
+
+        final int size = values.length;
+        IMXMLTagAttributeValue lastData = null;
+        for (int i = 0; i < size; i++)
+        {
+            IMXMLTagAttributeValue data = values[i];
+            if (lastData != null)
+            {
+                for (int s = 0; s < data.getAbsoluteStart() - lastData.getAbsoluteEnd(); i++)
+                {
+                    value.append(" ");
+                }
+            }
+            value.append(data.getContent());
+        }
+
+        return value.toString();
+    }
+
+    @Override
+    public String getRawValue()
+    {
+        String value = getValueWithQuotes();
+
+        if (value != null && value.length() > 0)
+        {
+            // length can be one in case of invalid data and then the substring() call fails
+            // so, handle it here
+            if (value.charAt(0) == value.charAt(value.length() - 1) && value.length() != 1)
+                value = value.substring(1, value.length() - 1);
+            else
+                value = value.substring(1);
+        }
+
+        return value;
+    }
+
+    @Override
+    public ISourceFragment[] getValueFragments(Collection<ICompilerProblem> problems)
+    {
+        String value = getRawValue();
+        ISourceLocation location = getValueLocation();
+        MXMLDialect mxmlDialect = getMXMLDialect();
+
+        return EntityProcessor.parse(value, location, mxmlDialect, problems);
+    }
+
+    /**
+     * Returns the value of the raw token (without quotes) only if only one
+     * value exists and it is a string value New clients should take into
+     * account that multiple values exist inside of an attribute value
+     * 
+     * @return a value token, or null
+     */
+    // TODO Rename to getValueToken()
+    public IMXMLToken getRawValueToken()
+    {
+        if (hasState() && values.length == 1 && values[0] instanceof IMXMLTextValue)
+        {
+            String value = getRawValue();
+            if (value != null)
+            {
+                return new MXMLToken(MXMLTokenTypes.TOKEN_STRING, getValueStart() + 1, getValueStart() + 1 + value.length(), -1, -1, value);
+            }
+        }
+        return null;
+    }
+
+    public IFileSpecification getSource()
+    {
+        return getParent().getSource();
+    }
+
+    /**
+     * Get this unit's line number.
+     * 
+     * @return end offset
+     */
+    public final int getNameLine()
+    {
+        return getLine();
+    }
+
+    /**
+     * Get this unit's column number.
+     * 
+     * @return end offset
+     */
+    public final int getNameColumn()
+    {
+        return getColumn();
+    }
+
+    public int getNameStart()
+    {
+        return getAbsoluteStart();
+    }
+
+    /**
+     * Get this attribute's name's end offset
+     * 
+     * @return name end offset
+     */
+    public int getNameEnd()
+    {
+        return getAbsoluteStart() + attributeName.length();
+    }
+
+    @Override
+    public int getValueStart()
+    {
+        return hasValue() ? valueStart + 1 : 0;
+    }
+
+    @Override
+    public int getValueEnd()
+    {
+        if (hasValue())
+        {
+            String lastContent = values[values.length - 1].getContent();
+
+            if (lastContent.charAt(0) == lastContent.charAt(lastContent.length() - 1))
+                return getValueStart() + lastContent.length() - 2;
+
+            return getValueStart() + lastContent.length();
+        }
+
+        // If there is no valid "end", then we must return -1. Callers depend on this.
+        // See MXMLTagData.findArttributeContainingOffset for an example
+        return -1;
+    }
+
+    @Override
+    public int getValueLine()
+    {
+        return hasValue() ? valueLine : 0;
+    }
+
+    @Override
+    public int getValueColumn()
+    {
+        return hasValue() ? valueColumn + 1 : 0;
+    }
+
+    @Override
+    public SourceLocation getValueLocation()
+    {
+        return new SourceLocation(getSourcePath(), getValueStart(), getValueEnd(), getValueLine(), getValueColumn());
+    }
+
+    /**
+     * Get this attribute's state start offset if a state token is present other
+     * wise zero.
+     * 
+     * @return state start offset or zero
+     */
+    public int getStateStart()
+    {
+        return stateName != null ? stateStart : 0;
+    }
+
+    /**
+     * Get this attribute's state tokens end offset if a state token is present
+     * other wise zero.
+     * 
+     * @return state start offset or zero
+     */
+    public int getStateEnd()
+    {
+        return stateName != null ? stateStart + stateName.length() : 0;
+    }
+
+    /**
+     * Does this value have a closing quote character?
+     * 
+     * @return true if this value has a closing quote character
+     */
+    protected boolean valueIsWellFormed()
+    {
+        // If there is a value, it came from a string token.  We know (from the
+        // RawTagTokenizer) that this means it starts with a quote character.  If
+        // it ends with the same quote character, it's well formed.
+        if (hasValue())
+        {
+            String lastContent = values[values.length - 1].getContent();
+            return (lastContent.charAt(0) == lastContent.charAt(lastContent.length() - 1));
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns the {@link PrefixMap} that represents all prefix->namespace
+     * mappings are in play on this tag. For example, if a parent tag defines
+     * <code>xmlns:m="falcon"</code> and this tag defines
+     * <code>xmlns:m="eagle"</code> then in this prefix map, m will equal
+     * "eagle"
+     * 
+     * @return a {@link PrefixMap} or null
+     */
+    public PrefixMap getCompositePrefixMap()
+    {
+        return parent.getCompositePrefixMap();
+    }
+
+    /**
+     * Does the offset fall inside the bounds of the attribute name?
+     * 
+     * @param offset test offset
+     * @return true if the offset falls within the attribute name
+     */
+    public boolean isInsideName(int offset)
+    {
+        if (attributeName != null)
+            return MXMLData.contains(getNameStart(), getNameEnd(), offset);
+
+        return false;
+    }
+
+    public boolean isInsideStateName(int offset)
+    {
+        if (stateName != null)
+            return MXMLData.contains(getStateStart(), getStateEnd(), offset);
+
+        return false;
+    }
+
+    /**
+     * Does the offset fall inside the bounds of the attribute value?
+     * 
+     * @param offset test offset
+     * @return true if the offset falls within the attribute value
+     */
+    public boolean isInsideValue(int offset)
+    {
+        if (hasValue())
+            return MXMLData.contains(getValueStart() - 1, getValueEnd(), offset);
+
+        return false;
+    }
+
+    @Override
+    public String getPrefix()
+    {
+        String name = getName();
+        int i = name.indexOf(':');
+        return i != -1 ? name.substring(0, i) : null;
+    }
+
+    @Override
+    public String getShortName()
+    {
+        String name = getName();
+        int i = name.indexOf(':');
+        return i != -1 ? name.substring(i + 1) : name;
+    }
+
+    @Override
+    public XMLName getXMLName()
+    {
+        return new XMLName(getURI(), getShortName());
+    }
+
+    @Override
+    public String getURI()
+    {
+        if (uri == null)
+        {
+            //walk up our chain to find the correct uri for our namespace.  first one wins
+            String prefix = getPrefix();
+            if (prefix == null)
+                return null;
+
+            IMXMLTagData lookingAt = parent;
+
+            // For attributes with prefix, parent's parent can be null if
+            // parent is the root tag 
+            while (lookingAt != null && lookingAt.getParent() != null)
+            {
+                PrefixMap depth = lookingAt.getParent().getPrefixMapForData(lookingAt);
+                if (depth != null && depth.containsPrefix(prefix))
+                {
+                    uri = depth.getNamespaceForPrefix(prefix);
+                    break;
+                }
+
+                lookingAt = lookingAt.getParentTag();
+            }
+        }
+
+        return uri;
+    }
+
+    void invalidateURI()
+    {
+        uri = null;
+    }
+
+    @Override
+    public MXMLDialect getMXMLDialect()
+    {
+        return getParent().getParent().getMXMLDialect();
+    }
+
+    @Override
+    public boolean isSpecialAttribute(String name)
+    {
+        String languageURI = getMXMLDialect().getLanguageNamespace();
+
+        return getName().equals(name) && (getPrefix() == null || getURI() == languageURI);
+    }
+
+    /**
+     * Verifies that this attrobite has its source location information set.
+     * <p>
+     * This is used only in asserts.
+     */
+    public boolean verify()
+    {
+        // Verify the source location.
+        assert getSourcePath() != null : "Attribute has null source path: " + toString();
+        assert getStart() != UNKNOWN : "Attribute has unknown start: " + toString();
+        assert getEnd() != UNKNOWN : "Attribute has unknown end: " + toString();
+        assert getLine() != UNKNOWN : "Attribute has unknown line: " + toString();
+        assert getColumn() != UNKNOWN : "Attribute has unknown column: " + toString();
+
+        return true;
+    }
+}


Mime
View raw message