blob: 0f098cc423250086451cff7df2ae43df567eacf9 [file] [log] [blame]
package org.apache.flex.compiler.internal.as.codegen;
import static org.apache.flex.abc.ABCConstants.CONSTANT_PrivateNs;
import static org.apache.flex.abc.ABCConstants.OP_applytype;
import static org.apache.flex.abc.ABCConstants.OP_callproperty;
import static org.apache.flex.abc.ABCConstants.OP_callpropvoid;
import static org.apache.flex.abc.ABCConstants.OP_construct;
import static org.apache.flex.abc.ABCConstants.OP_constructprop;
import static org.apache.flex.abc.ABCConstants.OP_dup;
import static org.apache.flex.abc.ABCConstants.OP_finddef;
import static org.apache.flex.abc.ABCConstants.OP_findpropstrict;
import static org.apache.flex.abc.ABCConstants.OP_getlex;
import static org.apache.flex.abc.ABCConstants.OP_getlocal0;
import static org.apache.flex.abc.ABCConstants.OP_getlocal3;
import static org.apache.flex.abc.ABCConstants.OP_getproperty;
import static org.apache.flex.abc.ABCConstants.OP_newarray;
import static org.apache.flex.abc.ABCConstants.OP_newobject;
import static org.apache.flex.abc.ABCConstants.OP_pushdouble;
import static org.apache.flex.abc.ABCConstants.OP_pushfalse;
import static org.apache.flex.abc.ABCConstants.OP_pushnull;
import static org.apache.flex.abc.ABCConstants.OP_pushstring;
import static org.apache.flex.abc.ABCConstants.OP_pushtrue;
import static org.apache.flex.abc.ABCConstants.OP_pushuint;
import static org.apache.flex.abc.ABCConstants.OP_setproperty;
import static org.apache.flex.abc.ABCConstants.TRAIT_Const;
import static org.apache.flex.abc.ABCConstants.TRAIT_Method;
import static org.apache.flex.abc.ABCConstants.TRAIT_Var;
import static org.apache.flex.compiler.mxml.IMXMLTypeConstants.ADD_EVENT_LISTENER_CALL_OPERANDS;
import static org.apache.flex.compiler.mxml.IMXMLTypeConstants.CREATE_XML_DOCUMENT_CALL_OPERANDS;
import static org.apache.flex.compiler.mxml.IMXMLTypeConstants.GET_INSTANCE_CALL_OPERANDS;
import static org.apache.flex.compiler.mxml.IMXMLTypeConstants.NAME_HANDLER_FUNCTION;
import static org.apache.flex.compiler.mxml.IMXMLTypeConstants.NAME_ID;
import static org.apache.flex.compiler.mxml.IMXMLTypeConstants.NAME_NAME;
import static org.apache.flex.compiler.mxml.IMXMLTypeConstants.NAME_OVERRIDES;
import static org.apache.flex.compiler.mxml.IMXMLTypeConstants.NAME_TARGET;
import static org.apache.flex.compiler.mxml.IMXMLTypeConstants.NAME_VALUE;
import static org.apache.flex.compiler.mxml.IMXMLTypeConstants.SET_STYLE_CALL_OPERANDS;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.apache.flex.abc.ABCConstants;
import org.apache.flex.abc.instructionlist.InstructionList;
import org.apache.flex.abc.semantics.MethodInfo;
import org.apache.flex.abc.semantics.Name;
import org.apache.flex.abc.semantics.Namespace;
import org.apache.flex.abc.semantics.Nsset;
import org.apache.flex.abc.semantics.Trait;
import org.apache.flex.abc.visitors.IABCVisitor;
import org.apache.flex.abc.visitors.ITraitVisitor;
import org.apache.flex.abc.visitors.ITraitsVisitor;
import org.apache.flex.compiler.common.ASModifier;
import org.apache.flex.compiler.constants.IASLanguageConstants;
import org.apache.flex.compiler.constants.IASLanguageConstants.BuiltinType;
import org.apache.flex.compiler.css.ICSSDocument;
import org.apache.flex.compiler.definitions.IDefinition;
import org.apache.flex.compiler.definitions.ITypeDefinition;
import org.apache.flex.compiler.exceptions.CodegenInterruptedException;
import org.apache.flex.compiler.internal.as.codegen.ICodeGenerator.IConstantValue;
import org.apache.flex.compiler.internal.as.codegen.MXMLClassDirectiveProcessor.Context;
import org.apache.flex.compiler.internal.as.codegen.MXMLClassDirectiveProcessor.IL;
import org.apache.flex.compiler.internal.caches.CSSDocumentCache;
import org.apache.flex.compiler.internal.css.codegen.CSSCompilationSession;
import org.apache.flex.compiler.internal.css.codegen.CSSEmitter;
import org.apache.flex.compiler.internal.css.codegen.CSSReducer;
import org.apache.flex.compiler.internal.definitions.ClassDefinition;
import org.apache.flex.compiler.internal.definitions.DefinitionBase;
import org.apache.flex.compiler.internal.definitions.FunctionDefinition;
import org.apache.flex.compiler.internal.definitions.NamespaceDefinition;
import org.apache.flex.compiler.internal.definitions.TypeDefinitionBase;
import org.apache.flex.compiler.internal.projects.FlexProject;
import org.apache.flex.compiler.internal.resourcebundles.ResourceBundleUtils;
import org.apache.flex.compiler.internal.scopes.ASProjectScope;
import org.apache.flex.compiler.internal.scopes.ASScope;
import org.apache.flex.compiler.internal.semantics.SemanticUtils;
import org.apache.flex.compiler.internal.tree.as.FunctionNode;
import org.apache.flex.compiler.internal.tree.as.NodeBase;
import org.apache.flex.compiler.internal.tree.as.VariableNode;
import org.apache.flex.compiler.mxml.IMXMLLanguageConstants;
import org.apache.flex.compiler.mxml.IMXMLTypeConstants;
import org.apache.flex.compiler.problems.CSSCodeGenProblem;
import org.apache.flex.compiler.problems.ICompilerProblem;
import org.apache.flex.compiler.problems.MXMLNotImplementedProblem;
import org.apache.flex.compiler.problems.MXMLOuterDocumentAlreadyDeclaredProblem;
import org.apache.flex.compiler.projects.ICompilerProject;
import org.apache.flex.compiler.projects.IFlexProject;
import org.apache.flex.compiler.tree.ASTNodeID;
import org.apache.flex.compiler.tree.as.IASNode;
import org.apache.flex.compiler.tree.as.IExpressionNode;
import org.apache.flex.compiler.tree.mxml.IMXMLArrayNode;
import org.apache.flex.compiler.tree.mxml.IMXMLBooleanNode;
import org.apache.flex.compiler.tree.mxml.IMXMLClassDefinitionNode;
import org.apache.flex.compiler.tree.mxml.IMXMLClassNode;
import org.apache.flex.compiler.tree.mxml.IMXMLClassReferenceNode;
import org.apache.flex.compiler.tree.mxml.IMXMLComponentNode;
import org.apache.flex.compiler.tree.mxml.IMXMLConcatenatedDataBindingNode;
import org.apache.flex.compiler.tree.mxml.IMXMLDeferredInstanceNode;
import org.apache.flex.compiler.tree.mxml.IMXMLDesignLayerNode;
import org.apache.flex.compiler.tree.mxml.IMXMLEffectSpecifierNode;
import org.apache.flex.compiler.tree.mxml.IMXMLEmbedNode;
import org.apache.flex.compiler.tree.mxml.IMXMLEventSpecifierNode;
import org.apache.flex.compiler.tree.mxml.IMXMLFactoryNode;
import org.apache.flex.compiler.tree.mxml.IMXMLFunctionNode;
import org.apache.flex.compiler.tree.mxml.IMXMLInstanceNode;
import org.apache.flex.compiler.tree.mxml.IMXMLIntNode;
import org.apache.flex.compiler.tree.mxml.IMXMLNode;
import org.apache.flex.compiler.tree.mxml.IMXMLNumberNode;
import org.apache.flex.compiler.tree.mxml.IMXMLObjectNode;
import org.apache.flex.compiler.tree.mxml.IMXMLPropertySpecifierNode;
import org.apache.flex.compiler.tree.mxml.IMXMLRegExpNode;
import org.apache.flex.compiler.tree.mxml.IMXMLRemoteObjectMethodNode;
import org.apache.flex.compiler.tree.mxml.IMXMLResourceNode;
import org.apache.flex.compiler.tree.mxml.IMXMLSingleDataBindingNode;
import org.apache.flex.compiler.tree.mxml.IMXMLStateNode;
import org.apache.flex.compiler.tree.mxml.IMXMLStringNode;
import org.apache.flex.compiler.tree.mxml.IMXMLStyleNode;
import org.apache.flex.compiler.tree.mxml.IMXMLStyleSpecifierNode;
import org.apache.flex.compiler.tree.mxml.IMXMLUintNode;
import org.apache.flex.compiler.tree.mxml.IMXMLVectorNode;
import org.apache.flex.compiler.tree.mxml.IMXMLWebServiceOperationNode;
import org.apache.flex.compiler.tree.mxml.IMXMLXMLListNode;
import org.apache.flex.compiler.tree.mxml.IMXMLXMLNode;
import org.apache.flex.compiler.units.ICompilationUnit;
import com.google.common.base.Strings;
/**
* {@link MXMLClassDirectiveProcessor} is a subclass of
* {@code ClassDirectiveProcessor} that generates an ABC class
* from an {@link IMXMLClassDefinitionNode} and its contents.
*
* Here are some register usage conventions for Code Generation:
* local3: during parts of the constructor, local3 is used for a
* lookup array of DeferredInstanceFromFunction.
* local1 and 2: Used during the constructor as temporaries
* for some data-binding init.
*/
public class JSMXMLClassDirectiveProcessor extends MXMLClassDirectiveProcessor
{
/**
* Initialize the {@link MXMLClassDirectiveProcessor} and its
* associated AET data structures.
* @param d - the MXML document's AST.
* @param enclosingScope - the immediately enclosing lexical scope.
* @param emitter - the active ABC emitter.
*/
JSMXMLClassDirectiveProcessor(IMXMLClassDefinitionNode classDefinitionNode,
LexicalScope enclosingScope, IABCVisitor emitter)
{
super(classDefinitionNode,
enclosingScope, emitter);
JSMXMLEmitter jsMXMLEmitter = (JSMXMLEmitter)emitter;
jsMXMLEmitter.register(this);
}
/**
* A Map mapping an event node to the Name of the event handler
* method (>0, >1, etc.) associated with that node.
* <p>
* The handler method may or may not exist at the time
* that the handler name is assigned to the event node.
* For example, when a State tag appears before
* an instance tag with a state-dependent event,
* the name will get assigned and the code generated later.
* <p>
* This map is managed ONLY by getEventHandlerName().
*/
private final Map<IMXMLEventSpecifierNode, Name> eventHandlerMap =
new HashMap<IMXMLEventSpecifierNode, Name>();
/**
* An incrementing counter used to create the names of the
* auto-generated event handler methods.
*/
private int eventHandlerCounter = 0;
/**
* Autogenerated event handler methods are named $EH0, $EH1, etc.
* Using short names, and using the same names in each MXML document,
* decreases SWF size.
* Using a character that is not legal in ActionScript identifiers
* means that even if the event handler must be public
* (because it is referenced in a descriptor)
* the name will not collide with the name of a developer-written
* method and cannot be accessed from developer code.
*/
private static final String EVENT_HANDLER_NAME_BASE = "$EH";
private String NEWLINE = "\n";
public ArrayList<Name> variableTraits;
private ArrayList<String> instanceData = new ArrayList<String>();
public ArrayList<String> fragments = new ArrayList<String>();
private FragmentList properties = new FragmentList();
private FragmentList styles = new FragmentList();
private FragmentList events = new FragmentList();
private FragmentList children = new FragmentList();
private FragmentList model = new FragmentList();
private FragmentList beads = new FragmentList();
private FragmentList currentList;
private boolean inContentFactory;
private String className;
@Override
public void processMainClassDefinitionNode(IMXMLClassDefinitionNode node)
{
// Leave a reference to the class on the stack.
ClassDefinition classDefinition =
(ClassDefinition)((IMXMLClassDefinitionNode)node).getClassDefinition();
className = classDefinition.getQualifiedName();
currentList = properties;
super.processMainClassDefinitionNode(node);
}
@Override
public void addVariableTrait(Name varName, Name varType)
{
if (variableTraits == null)
variableTraits = new ArrayList<Name>();
variableTraits.add(varName);
variableTraits.add(varType);
}
@Override
public void addBindableVariableTrait(Name varName, Name varType, IDefinition def)
{
String var = /*"_" + */varName.getBaseName();
Name backingVar = new Name(new Namespace(JSSharedData.CONSTANT_PrivateNs), var);
variableTraits.add(backingVar);
variableTraits.add(varType);
fragments.add("/**"
+ NEWLINE + " * @this {" + className + "}"
+ NEWLINE + " * @return {" + varType.getBaseName() + "}"
+ NEWLINE + " */"
+ NEWLINE + className + ".prototype.get_" + varName.getBaseName() + " = function()"
+ NEWLINE + "{"
+ NEWLINE + " return this." + var + ";"
+ NEWLINE + "};");
fragments.add("/**"
+ NEWLINE + " * @this {" + className + "}"
+ NEWLINE + " * @param {" + varType.getBaseName() + "} value"
+ NEWLINE + " */"
+ NEWLINE + className + ".prototype.set_" + varName.getBaseName() + " = function(value)"
+ NEWLINE + "{"
+ NEWLINE + " if (value != this." + var + ")"
+ NEWLINE + " this." + var + " = value;"
+ NEWLINE + "};");
}
@Override
protected void processMXMLClassDefinition(IMXMLClassDefinitionNode node, Context context)
{
// Create the <Component> or <Definition> class.
MXMLClassDirectiveProcessor dp = new MXMLClassDirectiveProcessor(node, globalScope, emitter);
dp.processMainClassDefinitionNode(node);
dp.finishClassDefinition();
}
@Override
void setDocument(IMXMLClassReferenceNode node, boolean conditionally, Context context)
{
if (node.isVisualElementContainer() || node.isContainer())
{
currentList.add("document");
currentList.add(true);
currentList.addExplicit("this");
}
}
/**
* Adds the current set of childEvents, childStyles, and childProperties to currentList;
* @param context
* @param addCounters
* @param skipContentFactory
* @return
*/
@Override
int setSpecifiers(Context context, Boolean addCounters, Boolean skipContentFactory)
{
if (skipContentFactory)
return 0;
int numProperties = properties.size() / 3;
if (context.hasBeads)
numProperties++;
if (context.hasModel)
numProperties++;
currentList.add(numProperties);
if (context.hasModel)
{
currentList.add("model");
currentList.addObjectTypeMarker();
currentList.addExplicit("[" + model.toString() + "]");
}
currentList.addAll(properties);
if (context.hasBeads)
{
currentList.add("beads");
currentList.addExplicit(beads.toString());
}
currentList.add(styles.size() / 3);
currentList.addAll(styles);
currentList.add(events.size() / 2);
currentList.addAll(events);
if (children.size() == 0)
currentList.addNull();
else
currentList.addExplicit("[" + children.toString() + "]");
return (properties.size() + styles.size() + events.size()) / 3;
}
@Override
void overrideMXMLDescriptorGetter(IMXMLClassDefinitionNode node, Context context)
{
// Leave a reference to the class on the stack.
ClassDefinition classDefinition =
(ClassDefinition)((IMXMLClassDefinitionNode)node).getClassDefinition();
String className = classDefinition.getQualifiedName();
fragments.add("/**"
+ NEWLINE + " * @override"
+ NEWLINE + " * @this {" + className + "}"
+ NEWLINE + " * @return {Array} the Array of UI element descriptors."
+ NEWLINE + " */"
+ NEWLINE + className + ".prototype.get_MXMLDescriptor = function()"
+ NEWLINE + "{"
+ NEWLINE + " if (this.mxmldd == undefined)"
+ NEWLINE + " {"
+ NEWLINE + " /** @type {Array} */"
+ NEWLINE + " var arr = goog.base(this, 'get_MXMLDescriptor');"
+ NEWLINE + " /** @type {Array} */"
+ NEWLINE + " var data = " + addInstanceData()
+ NEWLINE + " if (arr)"
+ NEWLINE + " this.mxmldd = arr.concat(data);"
+ NEWLINE + " else"
+ NEWLINE + " this.mxmldd = data;"
+ NEWLINE + " }"
+ NEWLINE + " return this.mxmldd;"
+ NEWLINE + "};");
}
private String addInstanceData()
{
StringBuilder sb = new StringBuilder();
sb.append("[" + NEWLINE);
int n = children.size();
for (int i = 0; i < n; i++)
{
String s = children.get(i);
sb.append(s);
if (i < n - 1)
sb.append("," + NEWLINE);
else
sb.append(NEWLINE);
}
sb.append("];" + NEWLINE);
return sb.toString();
}
void overrideMXMLPropertiesGetter(IMXMLClassDefinitionNode node, Context context, int numElements)
{
// Leave a reference to the class on the stack.
ClassDefinition classDefinition =
(ClassDefinition)((IMXMLClassDefinitionNode)node).getClassDefinition();
String className = classDefinition.getQualifiedName();
fragments.add("/**"
+ NEWLINE + " * @override"
+ NEWLINE + " * @this {" + className + "}"
+ NEWLINE + " * @return {Array} the Array of UI element descriptors."
+ NEWLINE + " */"
+ NEWLINE + className + ".prototype.get_MXMLProperties = function()"
+ NEWLINE + "{"
+ NEWLINE + " if (this.mxmldp == undefined)"
+ NEWLINE + " {"
+ NEWLINE + " /** @type {Array} */"
+ NEWLINE + " var arr = goog.base(this, 'get_MXMLProperties');"
+ NEWLINE + " /** @type {Array} */"
+ NEWLINE + " var data = " + addPropertiesData(context)
+ NEWLINE + " if (arr)"
+ NEWLINE + " this.mxmldp = arr.concat(data);"
+ NEWLINE + " else"
+ NEWLINE + " this.mxmldp = data;"
+ NEWLINE + " }"
+ NEWLINE + " return this.mxmldp;"
+ NEWLINE + "};");
}
private String addPropertiesData(Context context)
{
StringBuilder sb = new StringBuilder();
sb.append("[" + NEWLINE);
int n = properties.size();
int numProperties = n / 3;
if (context.hasModel)
numProperties++;
if (context.hasBeads)
numProperties++;
sb.append(new Integer(numProperties).toString() + ',' + NEWLINE);
if (context.hasModel)
{
sb.append("'model'");
sb.append("," + NEWLINE);
sb.append(model.toString());
sb.append("," + NEWLINE);
}
for (int i = 0; i < n; i++)
{
String s = properties.get(i);
sb.append(s);
sb.append("," + NEWLINE);
}
if (context.hasBeads)
{
sb.append("'beads'");
sb.append("," + NEWLINE);
sb.append(beads.toString());
sb.append("," + NEWLINE);
}
n = styles.size();
sb.append(new Integer(n / 3).toString() + ',' + NEWLINE);
for (int i = 0; i < n; i++)
{
String s = styles.get(i);
sb.append(s);
sb.append("," + NEWLINE);
}
n = events.size();
if (n == 0)
sb.append("0" + NEWLINE);
else
sb.append(new Integer(n / 2).toString() + ',' + NEWLINE);
for (int i = 0; i < n; i++)
{
String s = events.get(i);
sb.append(s);
if (i < n - 1)
sb.append("," + NEWLINE);
else
sb.append(NEWLINE);
}
sb.append("];" + NEWLINE);
return sb.toString();
}
@Override
void processMXMLBoolean(IMXMLBooleanNode booleanNode, Context context)
{
if (booleanNode.getParent().getNodeID() == ASTNodeID.MXMLPropertySpecifierID)
currentList.addSimpleTypeMarker(); // simple type
boolean value = isDataBound(booleanNode) ? false : booleanNode.getValue();
currentList.add(value);
traverse(booleanNode, context);
}
@Override
void processMXMLInt(IMXMLIntNode intNode, Context context)
{
if (intNode.getParent().getNodeID() == ASTNodeID.MXMLPropertySpecifierID)
currentList.addSimpleTypeMarker(); // simple type
int value = isDataBound(intNode) ? 0 : intNode.getValue();
currentList.add(value);
traverse(intNode, context);
}
@Override
void processMXMLUint(IMXMLUintNode uintNode, Context context)
{
if (uintNode.getParent().getNodeID() == ASTNodeID.MXMLPropertySpecifierID)
currentList.addSimpleTypeMarker(); // simple type
long value = isDataBound(uintNode) ? 0 : uintNode.getValue();
currentList.add(value);
traverse(uintNode, context);
}
@Override
void processMXMLNumber(IMXMLNumberNode numberNode, Context context)
{
if (numberNode.getParent().getNodeID() == ASTNodeID.MXMLPropertySpecifierID)
currentList.addSimpleTypeMarker(); // simple type
double value = isDataBound(numberNode) ? Double.NaN : numberNode.getValue();
currentList.add(value);
traverse(numberNode, context);
}
@Override
void processMXMLString(IMXMLStringNode stringNode, Context context)
{
if (stringNode.getParent().getNodeID() == ASTNodeID.MXMLPropertySpecifierID)
currentList.addSimpleTypeMarker(); // simple type
String value = isDataBound(stringNode) ? null : stringNode.getValue();
if (value != null)
currentList.add(value);
else
currentList.addNull();
traverse(stringNode, context);
}
@Override
void processMXMLClass(IMXMLClassNode classNode, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(classNode, "MXML Class");
getProblems().add(problem);
/*
// Don't call skipCodegen() because a null Class is represented
// by the expression node being null.
if (isDataBindingNode(classNode))
return;
IExpressionNode expressionNode = (IExpressionNode)classNode.getExpressionNode();
if (expressionNode != null)
{
InstructionList init_expression = classScope.getGenerator().generateInstructions(
expressionNode, CmcEmitter.__expression_NT, this.classScope);
context.addAll(init_expression);
}
else
{
context.addInstruction(OP_pushnull);
}
*/
}
/**
* Generates an instruction in the current context
* to push the value of an {@code IMXMLFunctionNode}.
*
* Will also generate the function, if the FunctionNode specifies a function expression.
*
* If no expression is provided in the function node, this will push null
*/
void processMXMLFunction(IMXMLFunctionNode functionNode, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(functionNode, "MXML Function");
getProblems().add(problem);
/*
// Don't call skipCodegen() because a null Function is represented
// by the expression node being null.
if (isDataBindingNode(functionNode))
return;
IExpressionNode expressionNode = (IExpressionNode)functionNode.getExpressionNode();
if (expressionNode != null)
{
InstructionList init_expression = classScope.getGenerator().generateInstructions(
expressionNode, CmcEmitter.__expression_NT, this.classScope);
context.addAll(init_expression);
}
else
{
context.addInstruction(OP_pushnull);
}
*/
}
@Override
void processMXMLRegExp(IMXMLRegExpNode regexpNode, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(regexpNode, "MXML RegExp");
getProblems().add(problem);
/*
// Don't call skipCodegen() because a parameterless RegExp is represented
// by the expression node being null.
if (isDataBindingNode(regexpNode))
return;
IExpressionNode expressionNode = (IExpressionNode)regexpNode.getExpressionNode();
if (expressionNode != null )
{
InstructionList init_expression = classScope.getGenerator().generateInstructions(
expressionNode, CmcEmitter.__expression_NT, this.classScope);
context.addAll(init_expression);
}
else
{
context.addInstruction(OP_findpropstrict, ABCGeneratingReducer.regexType);
context.addInstruction(OP_constructprop, new Object[] {ABCGeneratingReducer.regexType, 0});
}
*/
}
@Override
void processMXMLDesignLayer(IMXMLDesignLayerNode node, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(node, "MXML DesignLayer");
getProblems().add(problem);
}
@Override
void processMXMLWebServiceOperation(IMXMLWebServiceOperationNode node, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(node, "MXML WebServices");
getProblems().add(problem);
}
@Override
void processMXMLRemoteObjectMethod(IMXMLRemoteObjectMethodNode node, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(node, "MXML Remote Object");
getProblems().add(problem);
}
@Override
void processMXMLObject(IMXMLObjectNode objectNode, Context context)
{
FragmentList savedCurrentList = currentList;
currentList = new FragmentList();
traverse(objectNode, context);
StringBuilder sb = new StringBuilder();
sb.append("{");
int n = currentList.size();
for (int i = 0; i < n; i++)
{
String s = currentList.get(i++);
sb.append(s + ":");
sb.append(currentList.get(i));
if (i < n - 1)
sb.append(",");
}
sb.append("}");
currentList = savedCurrentList;
currentList.addExplicit(sb.toString());
}
@Override
void processMXMLArray(IMXMLArrayNode arrayNode, Context context)
{
boolean savedMakingArrayValues = context.makingArrayValues;
if (!inContentFactory)
{
if (context.parentContext.isStateDescriptor)
currentList.addArrayTypeMarker(); // array of descriptors
else
{
boolean isSimple = true;
for (int i = 0; i < arrayNode.getChildCount(); i++)
{
final IASNode child = arrayNode.getChild(i);
ASTNodeID nodeID = child.getNodeID();
if (nodeID == ASTNodeID.MXMLArrayID || nodeID == ASTNodeID.MXMLInstanceID)
{
isSimple = false;
break;
}
}
context.makingArrayValues = true;
if (isSimple)
currentList.addSimpleTypeMarker(); // arrays are simple values
else
currentList.addArrayTypeMarker();
}
}
FragmentList savedCurrentList = currentList;
currentList = new FragmentList();
traverse(arrayNode, context);
FragmentList childList = currentList;
currentList = savedCurrentList;
// TODO: can we do better?
// Now that stack will have the array children on it.
// But we may not have created one for every child of arrayNode.
// It would be best if we could remember how many we created, but
// we can't easily do that. So we use our "knowledge" that children
// are always created unless they are state dependent instances.
int nMax = arrayNode.getChildCount();
int numStateDependentChildren=0;
for (int i=0; i<nMax; ++i)
{
IASNode ch = arrayNode.getChild(i);
if (isStateDependentInstance(ch))
{
++numStateDependentChildren;
}
}
if (inContentFactory)
{
// pass the number of things we found up to the parent context. In spark controls
// the array of children is buried by a layer or two
currentList.addAll(childList);
}
else if (context.parentContext.isStateDescriptor)
{
StringBuilder sb = new StringBuilder();
sb.append("[");
sb.append(childList.toString());
sb.append("]");
currentList.addExplicit(sb.toString());
}
else if (context.makingArrayValues)
{
currentList.addAll(childList);
}
context.makingArrayValues = savedMakingArrayValues;
}
@Override
void processMXMLVector(IMXMLVectorNode vectorNode, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(vectorNode, "MXML Vector");
getProblems().add(problem);
}
void processMXMLInstance(IMXMLInstanceNode instanceNode, Context context)
{
FragmentList savedList = currentList;
FragmentList savedProperties = properties;
FragmentList savedStyles = styles;
FragmentList savedEvents = events;
FragmentList savedChildren = children;
FragmentList savedBeads = beads;
FragmentList savedModel = model;
boolean savedHasBeads = context.hasBeads;
boolean savedHasModel = context.hasModel;
properties = new FragmentList();
styles = new FragmentList();
events = new FragmentList();
children = new FragmentList();
beads = new FragmentList();
model = new FragmentList();
context.hasBeads = false;
context.hasModel = false;
if (!context.isStateDescriptor && !inContentFactory && !context.parentContext.makingArrayValues)
currentList.addObjectTypeMarker(); // complex type
traverse(instanceNode, context);
int numElements = 0;
currentList = properties;
setDocument(instanceNode, false, context);
// Sets the id property if the instance
// implements IDeferredInstantiationUIComponent.
String id = instanceNode.getID();
if (id != null)
{
currentList.add("id");
currentList.addSimpleTypeMarker();
currentList.add(id);
}
else
{
id = instanceNode.getEffectiveID();
if (id != null)
{
currentList.add("_id");
currentList.addSimpleTypeMarker();
currentList.add(id);
}
}
// bail out now. Other properties will be added in processMXMLState
if (context.isStateDescriptor)
return;
if (!inContentFactory)
currentList = new FragmentList();
else
currentList = savedList;
currentList.add(context.instanceClassName);
numElements += setSpecifiers(context, true, false);
if (!inContentFactory)
{
StringBuilder sb = new StringBuilder();
sb.append("[");
sb.append(currentList.toString());
sb.append("]");
currentList = savedList;
currentList.addExplicit(sb.toString());
}
currentList = savedList;
properties = savedProperties;
styles = savedStyles;
events = savedEvents;
children = savedChildren;
beads = savedBeads;
model = savedModel;
context.hasBeads = savedHasBeads;
context.hasModel = savedHasModel;
}
@Override
void processMXMLFactory(IMXMLFactoryNode factoryNode, Context context)
{
// Get the Name for the mx.core.ClassFactory class.
ICompilerProject project = getProject();
ClassDefinition classReference = (ClassDefinition)factoryNode.getClassReference(project);
Name factoryClassName = classReference.getMName(project);
// Push this class.
currentList.add(factoryClassName);
// Push the class to be used as the generator,
// by traversing the child MXMLClassNode.
traverse(factoryNode, context);
// Call new ClassFactory(generator), leaving the new instance on the stack.
currentList.addExplicit("new " + factoryClassName.toString());
}
@Override
void processMXMLDeferredInstance(IMXMLDeferredInstanceNode deferredInstanceNode, Context context)
{
// Push the class or function to be used as the generator,
// by traversing the child MXMLClassNode or MXMLInstanceNode.
traverse(deferredInstanceNode, context);
}
@Override
void processMXMLPropertySpecifier(IMXMLPropertySpecifierNode propertyNode, Context context)
{
// State-dependent nodes are handled by processMXMLState().
if (isStateDependent(propertyNode))
return;
String propertyName = propertyNode.getName();
if (propertyName.equals("mxmlContentFactory") || propertyName.equals("mxmlContent"))
{
FragmentList savedList = currentList;
currentList = children;
inContentFactory = true;
traverse(propertyNode, context);
inContentFactory = false;
currentList = savedList;
}
else if (propertyName.equals("states"))
{
context.isStateDescriptor = true;
FragmentList savedList = currentList;
currentList = properties;
currentList.add(propertyName);
traverse(propertyNode, context);
currentList = savedList;
}
else if (propertyName.equals("model"))
{
context.hasModel = true;
FragmentList savedList = currentList;
currentList = model;
traverse(propertyNode, context);
currentList = savedList;
}
else if (propertyName.equals("beads"))
{
context.hasBeads = true;
FragmentList savedList = currentList;
currentList = beads;
boolean savedInContentFactory = inContentFactory;
inContentFactory = false;
traverse(propertyNode, context);
inContentFactory = savedInContentFactory;
currentList = savedList;
}
else
{
FragmentList savedList = currentList;
currentList = properties;
currentList.add(propertyName);
traverse(propertyNode, context);
currentList = savedList;
}
}
@Override
void processMXMLStyleSpecifier(IMXMLStyleSpecifierNode styleNode, Context context)
{
// State-dependent nodes are handled by processMXMLState().
if (isStateDependent(styleNode))
return;
// Data bound styles don't need this processing either
IMXMLInstanceNode value = styleNode.getInstanceNode();
if (isDataBindingNode(value))
{
return;
}
// Style specifiers on the class definition node
// generate code in the moduleFactory setter.
if (styleNode.getParent() instanceof IMXMLClassDefinitionNode)
{
FragmentList savedList = currentList;
currentList = styles;
// Push the second argument: the value of the style.
// Do this by codegen'ing sole child, which is an IMXMLInstanceNode.
traverse(styleNode, context);
currentList = savedList;
}
else
{
FragmentList savedList = currentList;
currentList = styles;
String styleName = styleNode.getName();
// Push the first argument: the name of the style.
currentList.add(styleName);
// Push the second argument: the value of the style.
// Do this by codegen'ing sole child, which is an IMXMLInstanceNode.
traverse(styleNode, context);
currentList = savedList;
}
}
@Override
void processMXMLEffectSpecifier(IMXMLEffectSpecifierNode effectNode, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(effectNode, "MXML Effect");
getProblems().add(problem);
}
@Override
void processMXMLEventSpecifier(IMXMLEventSpecifierNode eventNode, Context context)
{
// Event nodes (including state-dependent ones)
// generate a new event handler method.
// Create a MethodInfo and a method trait for the handler.
Name name = getEventHandlerName(eventNode);
MethodInfo methodInfo = createEventHandlerMethodInfo(
getProject(), eventNode, name.getBaseName());
ITraitVisitor traitVisitor =
itraits.visitMethodTrait(TRAIT_Method, name, 0, methodInfo);
// Use ABCGenerator to codegen the handler body from the
// ActionScript nodes that are the children of the event node.
classScope.getGenerator().generateMethodBodyForFunction(
methodInfo, eventNode, classScope, null);
// Otherwise, state-dependent nodes are handled by processMXMLState().
if (isStateDependent(eventNode))
return;
String eventName = eventNode.getName();
Name eventHandler = getEventHandlerName(eventNode);
FragmentList savedList = currentList;
currentList = events;
currentList.add(eventName);
currentList.addExplicit("this." + eventHandler.getBaseName());
currentList = savedList;
}
@Override
void processMXMLResource(IMXMLResourceNode node, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(node, "MXML Resources");
getProblems().add(problem);
}
@Override
void processMXMLState(IMXMLStateNode stateNode, Context context)
{
int numElements = 1;
context.isStateDescriptor = true;
// First process the State node as an instance node,
// so that properties (name, stateGroups, basedOn) get set
// and event handlers (enterState, etc.) get set.
processMXMLInstance(stateNode, context);
// Init the name property of the state (it's not a normal property specifier nodes
// TODO: should we make this a property node?
String name = stateNode.getStateName();
if (name != null)
{
currentList.add("name");
currentList.addSimpleTypeMarker();
currentList.add(name);
}
// In MXML 2009 and later, a state's 'overrides' property is implicitly
// determined by the nodes that are dependent on this state.
// We use these nodes to autogenerate runtime IOverride objects
// and set them as the value of the 'overrides' property.
IMXMLClassDefinitionNode classDefinitionNode = stateNode.getClassDefinitionNode();
List<IMXMLNode> nodes = classDefinitionNode.getNodesDependentOnState(stateNode.getStateName());
if (nodes != null)
{
currentList.add("overrides");
currentList.addArrayTypeMarker(); // complex array
// First step: process all instance overrides before any other overrides.
// why: because a) ensure instances exists before trying to apply property overrides
// b) because the old compiler did
// Do it in reverse order
// a) because the way old compiler generated destination and relativeTo
// properties relies on doing it backwards.
//
// Each one will generate code to push an IOverride instance.
for (int i=nodes.size()-1; i>=0; --i)
{
IMXMLNode node = nodes.get(i);
if (node.getNodeID() == ASTNodeID.MXMLInstanceID)
{
processInstanceOverride((IMXMLInstanceNode)node, context);
}
}
// Next process the non-instance overrides dependent on this state.
// Each one will generate code to push an IOverride instance.
for (IMXMLNode node : nodes)
{
switch (node.getNodeID())
{
case MXMLPropertySpecifierID:
{
processPropertyOverride((IMXMLPropertySpecifierNode)node, context);
break;
}
case MXMLStyleSpecifierID:
{
processStyleOverride((IMXMLStyleSpecifierNode)node, context);
break;
}
case MXMLEventSpecifierID:
{
processEventOverride((IMXMLEventSpecifierNode)node, context);
break;
}
}
}
numElements += setSpecifiers(context, true, false);
}
}
@Override
void processPropertyOrStyleOverride(Name overrideName, IMXMLPropertySpecifierNode propertyOrStyleNode, Context context)
{
IASNode parentNode = propertyOrStyleNode.getParent();
String id = parentNode instanceof IMXMLInstanceNode ?
((IMXMLInstanceNode)parentNode).getEffectiveID() :
"";
String name = propertyOrStyleNode.getName();
IMXMLInstanceNode propertyOrStyleValueNode = propertyOrStyleNode.getInstanceNode();
// Construct the SetProperty or SetStyle object.
currentList.add(overrideName);
currentList.add(3);
// Set its 'target' property to the id of the object
// whose property or style this override will set.
currentList.add("target");
currentList.addSimpleTypeMarker();
currentList.add(id);
// Set its 'name' property to the name of the property or style.
currentList.add("name");
currentList.addSimpleTypeMarker();
currentList.add(name);
// Set its 'value' property to the value of the property or style.
currentList.add("value");
processNode(propertyOrStyleValueNode, context); // push value
currentList.add(0); // styles
currentList.add(0); // effects
currentList.add(0); // events
currentList.addNull(); // children
}
/**
* Generates instructions in the current context
* to create an instance of mx.states.SetEventHandler
* with its <code>target</code>, <code>name</code>,
* and <code>handlerFunction</code> properties set.
*/
void processEventOverride(IMXMLEventSpecifierNode eventNode, Context context)
{
FlexProject project = getProject();
Name eventOverride = project.getEventOverrideClassName();
IASNode parentNode = eventNode.getParent();
String id = parentNode instanceof IMXMLInstanceNode ?
((IMXMLInstanceNode)parentNode).getEffectiveID() :
"";
String name = eventNode.getName();
Name eventHandler = getEventHandlerName(eventNode);
// Construct the SetEventHandler object.
currentList.add(eventOverride);
currentList.add(3);
// Set its 'target' property to the id of the object
// whose event this override will set.
currentList.add(NAME_TARGET);
currentList.addSimpleTypeMarker();
currentList.add(id);
// Set its 'name' property to the name of the event.
currentList.add(NAME_NAME);
currentList.addSimpleTypeMarker();
currentList.add(name);
// Set its 'handlerFunction' property to the autogenerated event handler.
currentList.add(NAME_HANDLER_FUNCTION);
currentList.addSimpleTypeMarker();
currentList.add(eventHandler);
}
/**
* Generates instructions in the current context
* to create an instance of mx.states.AddItems...
*
* Assumes lookup table is still in local3
*/
void processInstanceOverride(IMXMLInstanceNode instanceNode, Context context)
{
FlexProject project = getProject();
Name instanceOverrideName = project.getInstanceOverrideClassName();
currentList.add(instanceOverrideName);
// Now set properties on it!
//----------------------------------------------------------------------
// First property: set itemsFactory to the deferredInstanceFunction we created earlier
Integer index = nodeToIndexMap.get(instanceNode);
assert index != null;
FragmentList addItemsList = new FragmentList();
addItemsList.add("itemsDescriptor");
addItemsList.addSimpleTypeMarker(); // the value is an array of descriptor data that will be parsed later
FragmentList savedList = currentList;
currentList = new FragmentList();
InstructionList il = nodeToInstanceDescriptorMap.get(instanceNode);
addItemsList.addExplicit("[" + currentList.toString() + "]");
currentList = savedList;
//-----------------------------------------------------------------------------
// Second property set: maybe set destination and propertyName
// get the property specifier node for the property the instanceNode represents
IMXMLPropertySpecifierNode propertySpecifier = (IMXMLPropertySpecifierNode)
instanceNode.getAncestorOfType( IMXMLPropertySpecifierNode.class);
if (propertySpecifier == null)
{
assert false; // I think this indicates an invalid tree...
}
else
{
// Check the parent - if it's an instance then we want to use these
// nodes to get our property values from. If not, then it's the root
// and we don't need to specify destination
IASNode parent = propertySpecifier.getParent();
if (parent instanceof IMXMLInstanceNode)
{
IMXMLInstanceNode parentInstance = (IMXMLInstanceNode)parent;
String parentId = parentInstance.getEffectiveID();
assert parentId != null;
String propName = propertySpecifier.getName();
addItemsList.add("destination");
addItemsList.addSimpleTypeMarker(); // simple type
addItemsList.add(parentId);
addItemsList.add("propertyName");
addItemsList.addSimpleTypeMarker(); // simple type
addItemsList.add(propName);
}
}
//---------------------------------------------------------------
// Third property set: position and relativeTo
String positionPropertyValue = null;
String relativeToPropertyValue = null;
// look to see if we have any sibling nodes that are not state dependent
// that come BEFORE us
IASNode instanceParent = instanceNode.getParent();
IASNode prevStatelessSibling=null;
for (int i=0; i< instanceParent.getChildCount(); ++i)
{
IASNode sib = instanceParent.getChild(i);
assert sib instanceof IMXMLInstanceNode; // surely our siblings are also instances?
// stop looking for previous nodes when we find ourself
if (sib == instanceNode)
break;
if (!isStateDependent(sib))
{
prevStatelessSibling = sib;
}
}
if (prevStatelessSibling == null) {
positionPropertyValue = "first"; // TODO: these should be named constants
}
else {
positionPropertyValue = "after";
relativeToPropertyValue = ((IMXMLInstanceNode)prevStatelessSibling).getEffectiveID();
}
addItemsList.add("position");
addItemsList.addSimpleTypeMarker(); // simple type
addItemsList.add(positionPropertyValue);
// relativeTo
if (relativeToPropertyValue != null)
{
addItemsList.add("relativeTo");
addItemsList.addSimpleTypeMarker(); // simple type
addItemsList.add(relativeToPropertyValue);
}
currentList.add(addItemsList.size() / 3);
currentList.addAll(addItemsList);
currentList.add(0); // styles
currentList.add(0); // effects
currentList.add(0); // events
currentList.addNull(); // children
}
void processMXMLComponent(IMXMLComponentNode node, Context context)
{
// Resolve the outer document, and if it doesn't resolve to the contingent
// definition, that means there is already an existing definition declared
// which is an error.
ClassDefinition componentClass = (ClassDefinition)node.getContainedClassDefinition();
ASScope classScope = componentClass.getContainedScope();
IDefinition outerDocument = classScope.getPropertyFromDef(
getProject(), componentClass, IMXMLLanguageConstants.PROPERTY_OUTER_DOCUMENT, false);
assert (outerDocument != null) : "outerDocument should never be null, as always added";
if (!outerDocument.isContingent())
{
ICompilerProblem problem = new MXMLOuterDocumentAlreadyDeclaredProblem(outerDocument);
getProblems().add(problem);
}
// Process the MXMLComponentNode as an MXMLFactoryNode, which it extends.
// This leaves a ClassFactory on the stack.
processMXMLFactory(node, context);
// factory.properties = { outerDocument: this }
currentList.add(IMXMLTypeConstants.NAME_PROPERTIES);
currentList.addSimpleTypeMarker();
currentList.addExplicit("{" + IMXMLLanguageConstants.PROPERTY_OUTER_DOCUMENT + ": this}");
}
void processMXMLEmbed(IMXMLEmbedNode node, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(node, "MXML Embedding");
getProblems().add(problem);
}
void processMXMLXML(IMXMLXMLNode node, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(node, "MXML XML");
getProblems().add(problem);
}
void processMXMLXMLList(IMXMLXMLListNode node, Context context)
{
MXMLNotImplementedProblem problem = new MXMLNotImplementedProblem(node, "MXML XMLList");
getProblems().add(problem);
}
/**
* Copied from JSClassDirectiveProcessor
* Declare a function. TODO: static vs. instance.
*/
@Override
void declareFunction(FunctionNode func)
{
func.parseFunctionBody(classScope.getProblems());
boolean is_constructor = func.isConstructor();
functionSemanticChecks(func);
// Save the constructor function until
// we've seen all the instance variables
// that might need initialization.
if (is_constructor)
{
this.ctorFunction = func;
}
else
{
MethodInfo mi = classScope.getGenerator().generateFunction(func, classScope, null);
ITraitVisitor tv;
if (mi != null)
{
FunctionDefinition funcDef = func.getDefinition();
Name funcName = funcDef.getMName(classScope.getProject());
if (func.hasModifier(ASModifier.STATIC))
tv = ctraits.visitMethodTrait(functionTraitKind(func, TRAIT_Method), funcName, 0, mi);
else
{
tv = itraits.visitMethodTrait(functionTraitKind(func, TRAIT_Method), funcName, 0, mi);
if (funcDef.getNamespaceReference() instanceof NamespaceDefinition.IProtectedNamespaceDefinition)
this.iinfo.flags |= ABCConstants.CLASS_FLAG_protected;
}
this.classScope.processMetadata(tv, funcDef.getAllMetaTags());
if (func.hasModifier(ASModifier.FINAL))
tv.visitAttribute(Trait.TRAIT_FINAL, Boolean.TRUE);
if (func.hasModifier(ASModifier.OVERRIDE))
tv.visitAttribute(Trait.TRAIT_OVERRIDE, Boolean.TRUE);
}
}
}
/**
* Copied from JSClassDirectiveProcessor
* Declare a variable. TODO: static vs. instance.
*/
@Override
void declareVariable(VariableNode var)
{
verifyVariableModifiers(var);
DefinitionBase varDef = var.getDefinition();
JSGenerator jsGenerator = (JSGenerator)classScope.getGenerator();
jsGenerator.getReducer().startDeclareVariable(varDef);
boolean is_static = var.hasModifier(ASModifier.STATIC);
boolean is_const = SemanticUtils.isConst(var, classScope.getProject());
// simple initializers for public/protected vars go right on prototype.
// the rest (all private vars), all "complex" initializers (like array) get
// initialized in the constructor
boolean needs_constructor_init = true;
// generateConstantValue() returns null if no constant value
// can be generated, and null is the correct value for "no value."
IConstantValue constantValue = jsGenerator.generateConstantValue(var.getAssignedValueNode(), this.classScope.getProject());
// initializer is null if no constant value
// can be generated, and null is the correct value for "no value."
Object initializer = constantValue != null ? constantValue.getValue() : null;
ITraitVisitor tv = declareVariable(var, varDef, is_static, is_const, initializer);
this.classScope.processMetadata(tv, varDef.getAllMetaTags());
// Generate variable initializers and append them to the
// proper initialization list.
if (var.getChildCount() > 1)
{
// We need to put the correct traits visitor on the class'
// LexicalScope; the BURM may encounter variable declarations
// chained onto this one, and it will need the traits visitor to declare them.
// Save the scope's current traits visitor (which should be null)
// and restore it
ITraitsVisitor saved_traits_visitor = this.classScope.traitsVisitor;
assert (saved_traits_visitor == null);
try
{
// the following line causes duplicate Traits.
// JSEmitter::emitTraits works around duplicate Traits by checking against
// a visitedTraits set.
this.classScope.traitsVisitor = (is_static) ? ctraits : itraits;
this.classScope.resetDebugInfo();
InstructionList init_expression = jsGenerator.generateInstructions(var, CmcJSEmitter.__statement_NT, this.classScope);
if (init_expression != null && !init_expression.isEmpty())
{
// final JSEmitter emitter = (JSEmitter)this.classScope.getEmitter();
final String str = JSGeneratingReducer.instructionListToString(init_expression, true);
if (str.contains(" = "))
{
final String varInit = jsGenerator.getReducer().getVariableInitializer(varDef);
if (varInit != null && !varInit.isEmpty())
{
// set the value of the slot trait.
final String varName = varDef.getBaseName();
for (Trait t : this.classScope.traitsVisitor.getTraits())
{
final byte kind = t.getKind();
if (kind == TRAIT_Const || kind == TRAIT_Var)
{
boolean is_private = false;
final Name name = t.getNameAttr(Trait.TRAIT_NAME);
Namespace ns = name.getSingleQualifier();
if (ns.getKind() == CONSTANT_PrivateNs)
is_private = true;
if (name.getBaseName().equals(varName))
{
t.setAttr(Trait.SLOT_VALUE, varInit);
if (!is_private)
needs_constructor_init = false;
break;
}
}
}
}
if (is_static)
{
// see finishClassDefinition.
// We clear cinitInsns only if there are no side effects
// by initializing the static members directly.
// If varInit is null, or varInit is isEmpty()
// then we have side effects.
if (!init_expression.isEmpty())
registerClassInit(var);
cinitInsns.addAll(init_expression);
}
else if (needs_constructor_init)
iinitInsns.addAll(init_expression);
}
}
}
finally
{
this.classScope.traitsVisitor = saved_traits_visitor;
}
}
jsGenerator.getReducer().endDeclareVariable(varDef);
}
private void registerClassInit(IASNode node)
{
final String fullName = JSGeneratingReducer.createFullNameFromDefinition(classScope.getProject(), classDefinition);
if (!fullName.equals(JSSharedData.JS_FRAMEWORK_NAME))
{
JSGenerator jsGenerator = (JSGenerator)classScope.getGenerator();
JSSharedData.instance.registerClassInit(fullName);
jsGenerator.getReducer().warnClassInitPerformance(node);
jsGenerator.getReducer().setNeedsSecondPass();
}
}
/**
* Determines the Name of the event handler method for an event node.
* This can get called to preassign the name before the method gets generated.
*/
protected Name getEventHandlerName(IMXMLEventSpecifierNode eventNode)
{
// Check the map to see if a handler name
// has already been assigned to this event node.
Name name = eventHandlerMap.get(eventNode);
// If so, return it.
if (name != null)
return name;
// Otherwise, generate the next one in the sequence "$EH0", "$EH1", etc.
String baseName = EVENT_HANDLER_NAME_BASE + eventHandlerCounter++;
name = new Name(baseName);
// Remember it in the map.
eventHandlerMap.put(eventNode, name);
return name;
}
static class FragmentList
{
ArrayList<String> list = new ArrayList<String>();
void add(boolean value)
{
if (value)
list.add("true");
else
list.add("false");
}
void add(int value)
{
list.add(new Integer(value).toString());
}
void add(long value)
{
list.add(new Long(value).toString());
}
void add(double value)
{
list.add(new Double(value).toString());
}
void add(Name name)
{
StringBuilder sb = new StringBuilder();
String s = name.getSingleQualifier().getName();
if (s.length() > 0)
{
sb.append(s);
sb.append(".");
}
sb.append(name.getBaseName());
list.add(sb.toString());
}
void add(String string)
{
list.add("'" + string + "'");
}
void addExplicit(String string)
{
list.add(string);
}
void addAll(FragmentList addlist)
{
list.addAll(addlist.list);
}
void addSimpleTypeMarker()
{
list.add("true");
}
void addObjectTypeMarker()
{
list.add("false");
}
void addArrayTypeMarker()
{
list.add("null");
}
void addNull()
{
list.add("null");
}
int size()
{
return list.size();
}
String get(int i)
{
return list.get(i);
}
public String toString()
{
StringBuilder sb = new StringBuilder();
int n = list.size();
for (int i = 0; i < n; i++)
{
sb.append(list.get(i));
if (i < n - 1)
sb.append(", ");
}
return sb.toString();
}
}
}