blob: 858957dc67f0ea4812050fe453c0c182ea4dbc36 [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 flex2.compiler.as3;
import java.util.Iterator;
import java.util.Map;
import macromedia.asc.parser.ArgumentListNode;
import macromedia.asc.parser.ClassDefinitionNode;
import macromedia.asc.parser.FunctionCommonNode;
import macromedia.asc.parser.FunctionDefinitionNode;
import macromedia.asc.parser.FunctionNameNode;
import macromedia.asc.parser.FunctionSignatureNode;
import macromedia.asc.parser.GetExpressionNode;
import macromedia.asc.parser.IdentifierNode;
import macromedia.asc.parser.ListNode;
import macromedia.asc.parser.LiteralBooleanNode;
import macromedia.asc.parser.LiteralFieldNode;
import macromedia.asc.parser.LiteralObjectNode;
import macromedia.asc.parser.LiteralStringNode;
import macromedia.asc.parser.MemberExpressionNode;
import macromedia.asc.parser.NodeFactory;
import macromedia.asc.parser.QualifiedIdentifierNode;
import macromedia.asc.parser.ReturnStatementNode;
import macromedia.asc.parser.StatementListNode;
import macromedia.asc.parser.Tokens;
import macromedia.asc.parser.TypeExpressionNode;
import macromedia.asc.parser.VariableDefinitionNode;
import macromedia.asc.semantics.Value;
import macromedia.asc.util.Context;
import flash.swf.tools.as3.EvaluatorAdapter;
import flex2.compiler.SymbolTable;
import flex2.compiler.as3.binding.ClassInfo;
import flex2.compiler.as3.binding.TypeAnalyzer;
import flex2.compiler.as3.reflect.NodeMagic;
import macromedia.asc.parser.Node;
/**
* This class handles processing [SkinPart] metadata.
*
* @author Greg Burch
*/
class SkinPartEvaluator extends EvaluatorAdapter
{
private SymbolTable symbolTable;
private Context currentContext;
//String Defs
private static final String SKINPARTS = "skinParts".intern();
private static final String _SKINPARTS = "_skinParts".intern();
private static final String OVERRIDE = "override".intern();
private static final String OBJECT = "Object".intern();
public SkinPartEvaluator(SymbolTable symbolTable)
{
this.symbolTable = symbolTable;
}
/**
* Evaluates the ClassDefinitionNode instance. The SkinPart metadata
* is evaluated on a per class basis.
*/
public Value evaluate(Context context, ClassDefinitionNode node)
{
super.evaluate(context, node);
//Used to populate ClassInfo via getClassInfo
TypeAnalyzer typeAnalyzer = symbolTable.getTypeAnalyzer();
//Needed for getClassInfo
String className = NodeMagic.getClassName(node);
if(className == null) return null;
currentContext = context;
//This walks the class hiearchy to insure that the tree has been parsed
//we need to do this before we use getClassInfo() to make sure we get all the
//baseclasses' info
typeAnalyzer.evaluate(context, node);
ClassInfo classInfo = typeAnalyzer.getClassInfo(className);
//Returns a hash of all skin parts, including inherited parts
Map<String, Boolean> parts = classInfo.getSkinParts(true);
if(parts != null && parts.size() > 0)
{
NodeFactory nodeFactory = context.getNodeFactory();
//Add our generated AST to the statements list
node.statements = genSkinPartsAST(parts, nodeFactory, node.statements);
}
return null;
}
/**
* @private
*
* Generates the AST for the static backing var
* which contains the AS representation of the <code>parts</code>
* Map. Also generates a public getter for accessing the Map.
*
* @param parts A hashmap of SkinParts
* @param nodeFactory
* @param statements A StatementListNode instance to add the AST to
* @return The modified StatementListNode
*/
private StatementListNode genSkinPartsAST(Map<String, Boolean> parts,
NodeFactory nodeFactory,
StatementListNode statements)
{
StatementListNode result = statements;
Iterator<String> iterator = parts.keySet().iterator();
ArgumentListNode partsList = null;
//Loop through list of SkinParts and generate key/value field
while( iterator. hasNext() ){
String key = iterator.next();
LiteralStringNode partName = nodeFactory.literalString(key);
LiteralBooleanNode required = nodeFactory.literalBoolean(parts.get(key));
LiteralFieldNode literalField = nodeFactory.literalField(partName, required);
partsList = nodeFactory.argumentList(partsList, literalField);
}
//Create literalObject with key/value pairs
TypeExpressionNode typeExpression = AbstractSyntaxTreeUtil.generateTypeExpression(nodeFactory, OBJECT, true);
LiteralObjectNode literalObject = nodeFactory.literalObject(partsList);
//And finally our completed _skinPart AST
VariableDefinitionNode skinParts = (VariableDefinitionNode)AbstractSyntaxTreeUtil.generatePrivateStaticVariable(currentContext, typeExpression, _SKINPARTS, literalObject);
//Signature for getter that takes no parameters (of course) and returns an Object
MemberExpressionNode returnTypeExpression = AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, OBJECT, true);
TypeExpressionNode returnType = nodeFactory.typeExpression(returnTypeExpression, true, false, -1);
FunctionSignatureNode functionSignature = nodeFactory.functionSignature(null, returnType);
//generate <ClassName>._skinParts
IdentifierNode identifier = AbstractSyntaxTreeUtil.generateIdentifier(nodeFactory, _SKINPARTS, false);
GetExpressionNode selector = nodeFactory.getExpression(identifier);
MemberExpressionNode memberExpression = nodeFactory.memberExpression(null, selector);
ListNode list = nodeFactory.list(null, memberExpression);
//return <ClassName>._skinParts
ReturnStatementNode returnStatement = nodeFactory.returnStatement(list);
StatementListNode rStatementList = nodeFactory.statementList(null, returnStatement);
//Create final expression
FunctionCommonNode propertyGetter = nodeFactory.functionCommon(currentContext, null, functionSignature, rStatementList);
//Create FunctionDefinition that will contain the above expression and set its type to a GETTER
QualifiedIdentifierNode qFunctionName = AbstractSyntaxTreeUtil.generatePublicQualifiedIdentifier(nodeFactory, SKINPARTS);
FunctionNameNode functionName = nodeFactory.functionName(Tokens.GET_TOKEN, qFunctionName);
FunctionDefinitionNode functionDefinition = nodeFactory.functionDefinition(currentContext, AbstractSyntaxTreeUtil.generateProtectedAttribute(nodeFactory), functionName, propertyGetter);
functionDefinition.attrs = nodeFactory.attributeList(AbstractSyntaxTreeUtil.generateGetterSelector(nodeFactory, OVERRIDE, false), functionDefinition.attrs);
//Add skinPart static var to statement list
result = nodeFactory.statementList(result, skinParts);
//Add getter to statement list
result = nodeFactory.statementList(result, functionDefinition);
return result;
}
}