nameToken.truncate(1, 0);
else if (nameToken.getType() == MXMLTokenTypes.TOKEN_CLOSE_TAG_START)
nameToken.truncate(2, 0);
else
{
problems.add(new SyntaxProblem(nameToken));
return map;
}
// Deal with name if it is of the form name.state
int nameStart = nameToken.getStart();
MXMLStateSplitter splitState = new MXMLStateSplitter(nameToken, dialect, problems, spec);
tagName = splitState.getBaseName();
if (splitState.getStateName() != null)
{
stateName = splitState.getStateName();
stateStart = nameToken.getStart() + splitState.getStateNameOffset();
}
nameType = nameToken.getType();
int nameEnd = nameStart + tagName.length();
int contentEnd = nameEnd;
setTagOffsets(startOffset, nameEnd, nameStart, contentEnd);
setColumn(nameToken.getColumn());
setLine(nameToken.getLine());
attributesStart = getNameEnd();
ArrayList<IMXMLTagAttributeData> attrs = new ArrayList<IMXMLTagAttributeData>();
attributeMap = new LinkedHashMap<String, IMXMLTagAttributeData>(); //preserve order of attrs
boolean foundTagEnd = false;
boolean putTokenBack = false; // This is a pre-falcon algorithm that helped recover from tag nesting errors
// I am bringing it back to life
while (tokenIterator.hasNext() && !foundTagEnd)
{
MXMLToken token = tokenIterator.next();
MXMLTagAttributeData attribute = null;
switch (token.getType())
{
case MXMLTokenTypes.TOKEN_NAME:
if (nameType == MXMLTokenTypes.TOKEN_CLOSE_TAG_START)
{
problems.add(new SyntaxProblem(token));
//burn forward until the end tag
//TODO do we want to mark each token as an error, or just the first?
while (tokenIterator.hasNext() && !foundTagEnd)
{
token = tokenIterator.next();
switch (token.getType())
{
case MXMLTokenTypes.TOKEN_TAG_END:
case MXMLTokenTypes.TOKEN_EMPTY_TAG_END:
foundTagEnd = true;
break;
}
}
break;
}
if (token.getText().startsWith("xmlns"))
{
attribute = new MXMLNamespaceAttributeData(token, tokenIterator, dialect, spec, problems);
if (map == null)
map = new MutablePrefixMap();
map.add(((IMXMLNamespaceAttributeData)attribute).getNamespacePrefix(), ((IMXMLNamespaceAttributeData)attribute).getNamespace());
}
else
{
attribute = new MXMLTagAttributeData(token, tokenIterator, dialect, spec, problems);
}
attribute.setParent(this);
// add the attribute to the attributes list even if it is duplicate
// otherwise code-hinting will not work properly
if (attributeMap.containsKey(token.getText()))
{
MXMLDuplicateAttributeProblem problem = new MXMLDuplicateAttributeProblem(attribute);
problems.add(problem);
}
attrs.add(attribute);
attributeMap.put(token.getText(), attribute);
// Now advance the offsets to include the newly parsed attributes
contentEnd = attribute.getAbsoluteEnd();
setTagOffsets(startOffset, contentEnd, nameStart, contentEnd);
break;
case MXMLTokenTypes.TOKEN_TAG_END:
foundTagEnd = true;
explicitCloseToken = !token.isImplicit();
break;
case MXMLTokenTypes.TOKEN_EMPTY_TAG_END:
emptyTag = true;
explicitCloseToken = !token.isImplicit();
foundTagEnd = true;
break;
case MXMLTokenTypes.TOKEN_OPEN_TAG_START:
case MXMLTokenTypes.TOKEN_CLOSE_TAG_START:
problems.add(new SyntaxProblem(token));
foundTagEnd = true; // Don't keep going - bail from malformed tag
putTokenBack = true;
// if we added this.fEmptyTag = true; then we could repair the damage here,
// but it's better to let the balancer repair it (in case there is a matching close lurking somewhere)
break;
default:
problems.add(new SyntaxProblem(token));
break;
}
if (foundTagEnd)
{
if (token.isImplicit() && token.getStart() == -1)