blob: f0fcd24a342fcb01a34a0197b322084ac043cb61 [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.codegen.typedefs.reference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import org.apache.royale.compiler.clients.ExternCConfiguration;
import org.apache.royale.compiler.clients.ExternCConfiguration.ExcludedMember;
import org.apache.royale.compiler.clients.ExternCConfiguration.ReadOnlyMember;
import org.apache.royale.compiler.clients.ExternCConfiguration.TrueConstant;
import org.apache.royale.compiler.clients.problems.ProblemQuery;
import org.apache.royale.compiler.internal.codegen.typedefs.utils.DebugLogUtils;
import com.google.javascript.jscomp.Compiler;
import com.google.javascript.jscomp.NodeUtil;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.JSTypeExpression;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.jstype.JSType;
public class ReferenceModel
{
public ProblemQuery problems;
private ExternCConfiguration configuration;
private Compiler jscompiler;
private List<String> namespaces = new ArrayList<String>();
private HashMap<String, ClassReference> typedefs = new HashMap<String, ClassReference>();
private HashMap<String, ClassReference> classes = new HashMap<String, ClassReference>();
private HashMap<String, FunctionReference> functions = new HashMap<String, FunctionReference>();
private HashMap<String, ConstantReference> constants = new HashMap<String, ConstantReference>();
// public Compiler getJSCompiler()
// {
// return jscompiler;
// }
public void setJSCompiler(Compiler compiler)
{
this.jscompiler = compiler;
}
public ExternCConfiguration getConfiguration()
{
return configuration;
}
public ClassReference getObjectReference()
{
return classes.get("Object");
}
public Collection<String> getNamespaces()
{
return namespaces;
}
public Collection<ClassReference> getTypedefs()
{
return typedefs.values();
}
public Collection<ClassReference> getClasses()
{
return classes.values();
}
public Collection<FunctionReference> getFunctions()
{
return functions.values();
}
public Collection<ConstantReference> getConstants()
{
return constants.values();
}
public ReferenceModel(ExternCConfiguration config)
{
this.configuration = config;
}
public ClassReference getClassReference(String qualifiedName)
{
return classes.get(qualifiedName);
}
public ClassReference getInterfaceReference(String qualifiedName)
{
ClassReference reference = classes.get(qualifiedName);
if (reference != null && reference.isInterface())
return reference;
return null;
}
public ClassReference getTypeDefReference(String qualifiedName)
{
return typedefs.get(qualifiedName);
}
public void addNamespace(Node node, String qualifiedName)
{
if (namespaces.contains(qualifiedName))
{
err("Duplicate namesapce [" + qualifiedName + "]");
return;
}
log("Model.addNamespace(" + qualifiedName + ")");
namespaces.add(qualifiedName);
}
public void addClass(Node node, String qualifiedName)
{
if (getConfiguration().isClassToFunctions(qualifiedName))
{
addFunction(node, qualifiedName);
return;
}
if (classes.containsKey(qualifiedName))
{
err("Duplicate class [" + qualifiedName + "]");
return;
}
log("Model.addClass(" + qualifiedName + ")");
ClassReference reference = new ClassReference(this, node, qualifiedName);
// TODO (mschmalle) Figure out if gcc makes any decisions about what is final or dynamic
if (reference.getQualifiedName().equals("Object")
|| reference.getQualifiedName().equals("Class"))
{
reference.setDynamic(true);
}
classes.put(qualifiedName, reference);
}
public void addEnum(Node node, String qualifiedName)
{
if (classes.containsKey(qualifiedName))
{
err("Duplicate class, @enum conflict [" + qualifiedName + "]");
return;
}
log("Model.addEnum(" + qualifiedName + ")");
ClassReference reference = new ClassReference(this, node, qualifiedName);
classes.put(qualifiedName, reference);
}
public void addTypeDef(Node node, String qualifiedName)
{
if (typedefs.containsKey(qualifiedName))
{
err("Duplicate @typedef [" + qualifiedName + "]");
return;
}
log("Model.addTypeDef(" + qualifiedName + ")");
ClassReference reference = new ClassReference(this, node, qualifiedName);
typedefs.put(qualifiedName, reference);
}
public void addInterface(Node node, String qualifiedName)
{
if (classes.containsKey(qualifiedName))
{
err("Duplicate @interface [" + qualifiedName + "]");
return;
}
log("Model.addInterface(" + qualifiedName + ")");
ClassReference reference = new ClassReference(this, node, qualifiedName);
classes.put(qualifiedName, reference);
}
public void addFinalClass(Node node, String qualifiedName)
{
if (classes.containsKey(qualifiedName))
{
err("Duplicate final class [" + qualifiedName + "]");
return;
}
log("Model.addFinalClass(" + qualifiedName + ")");
ClassReference reference = new ClassReference(this, node, qualifiedName);
reference.setFinal(true);
classes.put(qualifiedName, reference);
}
public void addFunction(Node node, String qualifiedName)
{
if (functions.containsKey(qualifiedName))
{
err("Duplicate global function [" + qualifiedName + "]");
return;
}
log("Model.addFunction(" + qualifiedName + ")");
FunctionReference reference = new FunctionReference(this, node, qualifiedName, node.getJSDocInfo());
functions.put(qualifiedName, reference);
}
public boolean hasFunction(String functionName)
{
return functions.containsKey(functionName);
}
public boolean hasClass(String className)
{
return classes.containsKey(className);
}
public boolean hasConstant(String qualifiedName)
{
return constants.containsKey(qualifiedName);
}
public void addConstant(Node node, String qualifiedName)
{
if (constants.containsKey(qualifiedName))
{
// XXX Record warning;
return;
}
log("Model.addConstant(" + qualifiedName + ")");
ConstantReference reference = new ConstantReference(this, node, qualifiedName, node.getJSDocInfo());
constants.put(qualifiedName, reference);
}
public void addConstantType(Node node, String qualifiedName, JSType type)
{
if (constants.containsKey(qualifiedName))
{
// XXX Record warning;
return;
}
log("Model.addConstantType(" + qualifiedName + ")");
ConstantReference reference = new ConstantReference(this, node, qualifiedName, node.getJSDocInfo(), type);
constants.put(qualifiedName, reference);
}
public void addField(Node node, String className, String memberName)
{
ClassReference classReference = getClassReference(className);
if (classReference != null)
classReference.addField(node, memberName, node.getJSDocInfo(), false);
}
public void addStaticField(Node node, String className, String memberName)
{
ClassReference classReference = getClassReference(className);
// XXX this is here because for now, the doc might be on the parent ASSIGN node
// if it's a static property with a value
JSDocInfo comment = NodeUtil.getBestJSDocInfo(node);
if (classReference != null)
{
classReference.addField(node, memberName, comment, true);
}
else
{
err(">>>> {ReferenceModel} Class [" + className + "] not found in " + node.getSourceFileName());
}
}
public void addMethod(Node node, String className, String memberName)
{
JSDocInfo comment = NodeUtil.getBestJSDocInfo(node);
ClassReference classReference = getClassReference(className);
if (classReference != null)
classReference.addMethod(node, memberName, comment, false);
}
public void addStaticMethod(Node node, String className, String memberName)
{
ClassReference classReference = getClassReference(className);
// XXX this is here because for now, the doc might be on the parent ASSIGN node
// if it's a static property with a value
JSDocInfo comment = NodeUtil.getBestJSDocInfo(node);
if (classReference != null)
{
classReference.addMethod(node, memberName, comment, true);
}
else
{
err(">>>> {ReferenceModel} Class [" + className + "] not found in " + node.getSourceFileName());
}
}
public final JSType evaluate(JSTypeExpression expression)
{
JSType jsType = null;
if (expression != null)
{
try
{
jsType = expression.evaluate(null, jscompiler.getTypeRegistry());
}
catch (Exception e)
{
e.printStackTrace();
}
}
return jsType;
}
//--------------------------------------------------------------------------
public ExcludedMember isExcludedClass(BaseReference classReference)
{
return getConfiguration().isExcludedClass(classReference);
}
public ExcludedMember isExcludedMember(ClassReference classReference, MemberReference memberReference)
{
return getConfiguration().isExcludedMember(classReference, memberReference);
}
public ReadOnlyMember isReadOnlyMember(ClassReference classReference, MemberReference memberReference)
{
return getConfiguration().isReadOnlyMember(classReference, memberReference);
}
//--------------------------------------------------------------------------
protected void log(Node n)
{
DebugLogUtils.err(n);
}
protected void err(Node n)
{
DebugLogUtils.err(n);
}
protected void log(String message)
{
DebugLogUtils.log(message);
}
protected void err(String message)
{
DebugLogUtils.err(message);
}
public TrueConstant isTrueConstant(ClassReference classReference,
MemberReference memberReference) {
return getConfiguration().isTrueConstant(classReference, memberReference);
}
}