/* * * 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.tree.mxml; import java.util.List; import org.apache.flex.compiler.common.ISourceLocation; import org.apache.flex.compiler.constants.IASLanguageConstants; import org.apache.flex.compiler.definitions.IClassDefinition; import org.apache.flex.compiler.definitions.IDefinition; import org.apache.flex.compiler.definitions.IVariableDefinition; import org.apache.flex.compiler.internal.definitions.ClassDefinition; import org.apache.flex.compiler.internal.parsing.ISourceFragment; import org.apache.flex.compiler.internal.projects.FlexProject; import org.apache.flex.compiler.internal.tree.as.NodeBase; import org.apache.flex.compiler.mxml.IMXMLTagData; import org.apache.flex.compiler.mxml.IMXMLUnitData; import org.apache.flex.compiler.tree.ASTNodeID; import org.apache.flex.compiler.tree.as.IASNode; import org.apache.flex.compiler.tree.mxml.IMXMLClassNode; import org.apache.flex.compiler.tree.mxml.IMXMLDeferredInstanceNode; import org.apache.flex.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) { FlexProject 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) { FlexProject 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. FlexProject 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; } }