blob: 14ecde0f50df2f8221db23900b466b69913c7c3f [file] [log] [blame]
/*
*
* 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.royale.compiler.internal.tree.mxml;
import java.util.List;
import org.apache.royale.compiler.common.ISourceLocation;
import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.IVariableDefinition;
import org.apache.royale.compiler.internal.definitions.ClassDefinition;
import org.apache.royale.compiler.internal.parsing.ISourceFragment;
import org.apache.royale.compiler.internal.projects.RoyaleProject;
import org.apache.royale.compiler.internal.tree.as.NodeBase;
import org.apache.royale.compiler.mxml.IMXMLTagData;
import org.apache.royale.compiler.mxml.IMXMLUnitData;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.mxml.IMXMLClassNode;
import org.apache.royale.compiler.tree.mxml.IMXMLDeferredInstanceNode;
import org.apache.royale.compiler.tree.mxml.IMXMLInstanceNode;
/**
* This AST node represents the instance of
* <code>mx.core.DeferredInstanceFromClass</code> or
* <code>mx.core.DeferredInstanceFromFunction</code> that the compiler
* implicitly creates as the value for a property of type
* <code>mx.core.IDeferredInstance</code>.
* <p>
* An {@code IMXMLDeferredInstanceNode} has exactly one child, which can be
* either an {@code IMXMLClassNode} (in the case of an
* <code>DeferredInstanceFromClass</code>) or an {@code IMXMLInstanceNode} (in
* the case of an <code>DeferredInstanceFromFunction</code)). Gordon Smith
*/
class MXMLDeferredInstanceNode extends MXMLInstanceNode implements IMXMLDeferredInstanceNode
{
/**
* Constructor
*
* @param parent The parent node of this node, or <code>null</code> if there
* is no parent.
*/
MXMLDeferredInstanceNode(NodeBase parent)
{
super(parent);
}
private IMXMLInstanceNode childNode;
@Override
public ASTNodeID getNodeID()
{
return ASTNodeID.MXMLDeferredInstanceID;
}
@Override
public IASNode getChild(int i)
{
return i == 0 ? childNode : null;
}
@Override
public int getChildCount()
{
return childNode == null ? 0 : 1;
}
@Override
protected void processChildTag(MXMLTreeBuilder builder, IMXMLTagData tag,
IMXMLTagData childTag,
MXMLNodeInfo info)
{
RoyaleProject project = builder.getProject();
// Check whether the child tag is an instance tag.
IDefinition definition = builder.getFileScope().resolveTagToDefinition(childTag);
if (definition instanceof ClassDefinition)
{
// This node should generate an instance of mx.core.DeferredInstanceFromFunction.
String qname = project.getDeferredInstanceFromFunctionClass();
setClassReference(project, qname);
builder.addExpressionDependency(qname);
childNode = MXMLInstanceNode.createInstanceNode(
builder, definition.getQualifiedName(), this);
((MXMLInstanceNode)childNode).setClassReference(project, (ClassDefinition)definition); // TODO Move this logic to initializeFromTag().
((MXMLInstanceNode)childNode).initializeFromTag(builder, childTag);
}
}
void initializeDefaultProperty(MXMLTreeBuilder builder, IVariableDefinition defaultPropertyDefinition,
List<IMXMLUnitData> contentUnits)
{
RoyaleProject project = builder.getProject();
assert (contentUnits.isEmpty()) ||
(!builder.getFileScope().isScriptTag(contentUnits.get(0))) : "Script tags should not start a default property!";
assert (contentUnits.isEmpty()) ||
(!builder.getFileScope().isScriptTag(contentUnits.get(contentUnits.size() - 1))) : "Trailing script tags should be removed from default property content units!";
// Set the location of the implicit deferred instance node
// to span the tags that specify the default property value.
setLocation(builder, contentUnits);
setClassReference(project, project.getDeferredInstanceFromFunctionClass());
// Determine whether the the default property is being set to a single Array tag.
boolean isSingleArrayTag = false;
int n = contentUnits.size();
if (n == 1 && contentUnits.get(0) instanceof IMXMLTagData)
{
IMXMLTagData tag = (IMXMLTagData)contentUnits.get(0);
IDefinition definition = builder.getFileScope().resolveTagToDefinition(tag);
isSingleArrayTag = definition.getQualifiedName().equals(IASLanguageConstants.Array);
}
String instanceType = defaultPropertyDefinition.getInstanceType(project);
if (IASLanguageConstants.Array.equals(instanceType) && !isSingleArrayTag)
{
// Create an implicit array node.
childNode = new MXMLArrayNode(this);
((MXMLArrayNode)childNode).initializeDefaultProperty(
builder, defaultPropertyDefinition, contentUnits);
}
else if ((n == 1) && (!isSingleArrayTag))
{
IMXMLTagData tag = (IMXMLTagData)contentUnits.get(0);
IDefinition type = builder.getFileScope().resolveTagToDefinition(tag);
if (type instanceof ClassDefinition)
{
IClassDefinition tagClass = (IClassDefinition)type;
MXMLInstanceNode childInstanceNode = MXMLInstanceNode.createInstanceNode(builder, type.getQualifiedName(), this);
childInstanceNode.setClassReference(project, tagClass);
childNode = childInstanceNode;
childInstanceNode.initializeFromTag(builder, tag);
}
}
}
@Override
protected void initializationComplete(MXMLTreeBuilder builder, IMXMLTagData tag,
MXMLNodeInfo info)
{
if (childNode == null)
{
ISourceLocation location = info.getSourceLocation();
if (location == null)
location = tag.getLocationOfChildUnits();
ISourceFragment[] sourceFragments = info.getSourceFragments();
initializeFromFragments(builder, location, sourceFragments);
}
}
public void initializeFromFragments(MXMLTreeBuilder builder,
ISourceLocation location,
ISourceFragment[] fragments)
{
// This node represents an instance of mx.core.DeferredInstanceFromClass.
RoyaleProject project = builder.getProject();
String qname = project.getDeferredInstanceFromClassClass();
setClassReference(project, qname);
// Add an expression dependency on that class.
builder.addExpressionDependency(qname);
// The source fragments are a class name (possibly a complex one
// like Vector.<Vector.<int>>. This is the class from which
// we're making a DeferredInstanceFromClass object.
// Create a child MXMLClassNode from it.
childNode = new MXMLClassNode(this);
((MXMLClassNode)childNode).setClassReference(project, childNode.getName()); // TODO Move this logic to initializeFromText().
((MXMLClassNode)childNode).initializeFromFragments(builder, location, fragments);
}
@Override
public IMXMLClassNode getClassNode()
{
return childNode instanceof IMXMLClassNode ? (IMXMLClassNode)childNode : null;
}
@Override
public IMXMLInstanceNode getInstanceNode()
{
// Note that IMXMLClassNode extends IMXMLInstanceNode.
return !(childNode instanceof IMXMLClassNode) ? childNode : null;
}
}