blob: f15d7d58ecb90d7d40b19c2bab9f4620f6a9b6d1 [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.flex.compiler.internal.as.codegen;
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.visitors.IABCVisitor;
import org.apache.flex.abc.visitors.IClassVisitor;
import org.apache.flex.abc.visitors.ITraitVisitor;
import org.apache.flex.abc.visitors.ITraitsVisitor;
import org.apache.flex.compiler.common.DependencyType;
import org.apache.flex.compiler.definitions.IDefinition;
import org.apache.flex.compiler.internal.definitions.ClassDefinition;
import org.apache.flex.compiler.internal.definitions.FunctionDefinition;
import org.apache.flex.compiler.internal.scopes.ASScope;
import org.apache.flex.compiler.internal.tree.as.ClassNode;
import org.apache.flex.compiler.internal.tree.as.FunctionNode;
import org.apache.flex.compiler.internal.tree.as.ImportNode;
import org.apache.flex.compiler.internal.tree.as.InterfaceNode;
import org.apache.flex.compiler.internal.tree.as.PackageNode;
import org.apache.flex.compiler.internal.tree.as.VariableNode;
import org.apache.flex.compiler.problems.DuplicateFunctionDefinitionProblem;
import org.apache.flex.compiler.problems.ICompilerProblem;
import org.apache.flex.compiler.scopes.IASScope;
import org.apache.flex.compiler.tree.ASTNodeID;
import org.apache.flex.compiler.tree.as.IASNode;
import org.apache.flex.compiler.tree.mxml.IMXMLDocumentNode;
/**
* A GlobalDirectiveProcessor translates directives at global scope into ABC.
* JSGlobalDirectiveProcessor is derived from GlobalDirectiveProcessor and adds
* workarounds necessary for FalconJS. Ideally FalconJS should use
* GlobalDirectiveProcessor and retire JSGlobalDirectiveProcessor. This
* implementation is part of FalconJS. For more details on FalconJS see
* org.apache.flex.compiler.JSDriver
*/
public class JSGlobalDirectiveProcessor extends GlobalDirectiveProcessor
{
JSGenerator m_generator;
private String m_packageName = null;
/**
* @param current_scope - the scope to use. It may be created a priori by
* the caller, so it's not created by nesting an enclosing scope.
* @param emitter - the ABC emitter.
*/
public JSGlobalDirectiveProcessor(JSGenerator generator, LexicalScope current_scope, IABCVisitor emitter)
{
super(current_scope, emitter);
m_generator = generator;
}
@Override
void declareFunction(FunctionNode f)
{
// No modifiers allowed at global scope.
// super.verifyModifiers(f);
// MISSING in GlobalDirectiveProcessor
MethodInfo mi = m_generator.generateFunction(f, currentScope, null);
if (mi != null)
{
FunctionDefinition funcDef = f.getDefinition();
JSSharedData.instance.registerDefinition(funcDef);
// TODO: generalize excluding functions using metadata annotations.
final String packageName = funcDef.getPackageName();
if (!packageName.equals("com.jquery"))
{
final IClassVisitor cv = ((JSEmitter)emitter).visitPackage(m_packageName);
cv.visit();
this.currentScope.traitsVisitor = cv.visitClassTraits();
cv.visitEnd();
/*
* InstanceInfo iinfo = new InstanceInfo(); iinfo.name =
* JSGeneratingReducer.makeName(packageName); IClassVisitor cv =
* emitter.visitClass(iinfo, new ClassInfo()); cv.visit();
* cv.visitInstanceTraits(); ITraitsVisitor ctraits =
* cv.visitClassTraits(); final Name funcName =
* funcDef.getMName(currentScope.getProject(),
* currentScope.getProblems()); final ITraitVisitor tv =
* ctraits.visitMethodTrait(TRAIT_Method, funcName, 0, mi);
* tv.visitAttribute(Trait.TRAIT_FINAL, Boolean.TRUE);
*/
/*
* final String key = packageName; ICompilationUnit cu =
* m_generator.m_compilationUnit; ICompilationUnit registeredCU
* = JSSharedData.instance.getCompilationUnit(key); if( cu !=
* registeredCU ) { // make the current cu dependent on the
* registered cu. if( registeredCU != null ) { final
* CompilerProject compilerProject =
* (CompilerProject)cu.getProject();
* compilerProject.addDependency(cu, registeredCU,
* DependencyType.INHERITANCE); } else {
* JSSharedData.instance.registerCompilationUnit(key, cu); } }
*/
}
Name funcName = funcDef.getMName(this.currentScope.getProject());
if (funcName == null)
{
// getMName() emitted a diagnostic,
// repair and continue.
funcName = new Name("<invalid>");
}
ITraitVisitor tv = null;
int traitKind = this.processingPackage ?
DirectiveProcessor.functionTraitKind(f, ABCConstants.TRAIT_Method) :
DirectiveProcessor.functionTraitKind(f, ABCConstants.TRAIT_Var);
if (!this.currentScope.traitsVisitor.getTraits().containsTrait(traitKind, funcName))
{
this.currentScope.declareVariableName(funcName);
if (!this.processingPackage)
{
// Functions at the global scope create a var of type '*'
// TODO: this should be typed as 'Function' if strict mode is on
if (f.isGetter() || f.isSetter())
{
tv = this.currentScope.traitsVisitor.visitMethodTrait(
DirectiveProcessor.functionTraitKind(f, ABCConstants.TRAIT_Var),
funcName,
ITraitsVisitor.RUNTIME_DISP_ID,
mi);
}
else
{
tv = this.currentScope.traitsVisitor.visitSlotTrait(
DirectiveProcessor.functionTraitKind(f, ABCConstants.TRAIT_Var),
funcName,
ITraitsVisitor.RUNTIME_SLOT,
LexicalScope.anyType,
LexicalScope.noInitializer);
/*
* this.currentScope.getInitInstructions().addInstruction
* (ABCConstants.OP_getglobalscope);
* this.currentScope.getInitInstructions
* ().addInstruction(ABCConstants.OP_newfunction, mi);
* this
* .currentScope.getInitInstructions().addInstruction
* (ABCConstants.OP_setproperty, funcName);
*/
}
}
else
{
tv = this.currentScope.traitsVisitor.visitMethodTrait(DirectiveProcessor.functionTraitKind(f, ABCConstants.TRAIT_Method), funcName, 0, mi);
}
if (tv != null)
{
this.currentScope.processMetadata(tv, funcDef.getAllMetaTags());
}
}
else
{
ICompilerProblem problem = new DuplicateFunctionDefinitionProblem(f, funcName.getBaseName());
this.currentScope.addProblem(problem);
}
}
}
/**
* Declare a class.
*/
@Override
void declareClass(ClassNode c)
{
verifyClassModifiers(c);
verifySkinning(c.getDefinition());
currentScope.getMethodBodySemanticChecker().checkNamespaceOfDefinition(c, c.getDefinition(), currentScope.getProject());
JSClassDirectiveProcessor cp = JSSharedData.backend.createClassDirectiveProcessor(m_generator, c, this.currentScope, this.emitter);
cp.traverse(c.getScopedNode());
cp.finishClassDefinition();
}
/**
* Declare an interface.
*/
@Override
void declareInterface(InterfaceNode interface_ast)
{
verifyInterfaceModifiers(interface_ast);
currentScope.getMethodBodySemanticChecker().checkNamespaceOfDefinition(interface_ast, interface_ast.getDefinition(), currentScope.getProject());
InterfaceDirectiveProcessor ip = JSSharedData.backend.createInterfaceDirectiveProcessor(m_generator, interface_ast, this.currentScope, this.emitter);
ip.traverse(interface_ast.getScopedNode());
ip.finishInterfaceDefinition();
}
/**
* Process a random directive, which at the global level is probably a loose
* instruction.
*/
@Override
void processDirective(IASNode n)
{
// Use nodes have no effect
/*
* if(n.getNodeID() == ASTNodeID.UseID ) { if(
* !JSSharedData.GENERATE_EMBED_WRAPPER ) return; }
*/
// workaround for Falcon bug.
// DirectiveProcessor is observing NamespaceIdentifierID instead of NamespaceID
if (n.getNodeID() == ASTNodeID.NamespaceID)
{
try
{
final IClassVisitor cv = ((JSEmitter)emitter).visitPackage(m_packageName);
cv.visit();
this.currentScope.traitsVisitor = cv.visitClassTraits();
cv.visitEnd();
m_generator.generateInstructions(n, CmcEmitter.__statement_NT, this.currentScope);
// assert(stmt_insns == null);
}
finally
{
// this.currentScope.traitsVisitor = null;
}
return;
}
// Handle a loose statement.
InstructionList stmt_insns = m_generator.generateInstructions(n, CmcJSEmitter.__statement_NT, currentScope);
if (stmt_insns != null)
directiveInsns.addAll(stmt_insns);
}
@Override
void declarePackage(PackageNode p)
{
m_packageName = p.getName();
((JSEmitter)emitter).visitPackage(m_packageName);
JSSharedData.instance.registerPackage(m_packageName);
super.declarePackage(p);
}
/**
* Declare a variable.
*/
@Override
void declareVariable(VariableNode var)
{
super.declareVariable(var);
}
/**
* Translate a ImportNode AST into ABC. Subclasses should override this if
* they can process imports.
*
* @param imp - the import's AST.
*/
@Override
void processImportDirective(ImportNode imp)
{
String importName = imp.getImportName();
if (!importName.contains("."))
{
final IASScope scope = JSGeneratingReducer.getScopeFromNode(imp);
final IDefinition def = ((ASScope)scope).findProperty(currentScope.getProject(), imp.getImportName(), DependencyType.INHERITANCE);
if (def == null)
{
importName = null;
}
else
{
// workaround for Falcon bug.
// Falcon does not always recognize dependencies to package functions provided by SWCs.
// In this workaround we explicitly set a EXPRESSION dependency.
/*
* if( def != null ) { final ICompilationUnit fromCU =
* m_generator.m_compilationUnit; final CompilerProject
* compilerProject = (CompilerProject)currentScope.project;
* final ASProjectScope projectScope =
* compilerProject.getScope(); final ICompilationUnit toCU =
* projectScope.getCompilationUnitForDefinition(def); if( fromCU
* != toCU ) { // sharedData.verboseMessage(
* "Adding dependency: " + className );
* compilerProject.addDependency(fromCU, toCU,
* DependencyGraph.DependencyType.EXPRESSION); } }
*/
// skip imports from the same package.
if (def.getPackageName().equals(m_packageName))
importName = null;
else
importName = JSGeneratingReducer.definitionToString(currentScope.getProject(), def);
}
}
if (importName != null)
{
JSEmitter emitter = (JSEmitter)this.currentScope.getEmitter();
emitter.visitImport(importName, imp.getImportKind());
}
}
/**
* Declare an MXML document.
*/
@Override
void declareMXMLDocument(IMXMLDocumentNode d)
{
verifySkinning((ClassDefinition)d.getDefinition());
try
{
MXMLClassDirectiveProcessor dp;
dp = new JSMXMLClassDirectiveProcessor(d, this.currentScope, this.emitter);
dp.processMainClassDefinitionNode(d);
dp.finishClassDefinition();
}
catch (Error e)
{
System.out.print(e);
}
}
}