| /* |
| * |
| * 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; |
| |
| import flex2.compiler.abc.*; |
| import flex2.compiler.as3.BytecodeEmitter; |
| import flex2.compiler.as3.binding.TypeAnalyzer; |
| import flex2.compiler.common.CompilerConfiguration; |
| import flex2.compiler.common.Configuration; |
| import flex2.compiler.css.StyleConflictException; |
| import flex2.compiler.css.Styles; |
| import flex2.compiler.util.*; |
| import flex2.tools.oem.ProgressMeter; |
| import macromedia.asc.util.Context; |
| import macromedia.asc.util.ContextStatics; |
| import macromedia.asc.util.Namespaces; |
| import macromedia.asc.util.ObjectList; |
| |
| import java.util.*; |
| |
| /** |
| * This class supports looking up information for a class or a style |
| * and looking up a <code>Source</code> by QName or by resource bundle |
| * name. |
| */ |
| public final class SymbolTable |
| { |
| // These may look funny, but they line up with the values that ASC uses. |
| public static final String internalNamespace = "internal"; |
| public static final String privateNamespace = "private"; |
| public static final String protectedNamespace = "protected"; |
| public static final String publicNamespace = ""; |
| public static final String unnamedPackage = ""; |
| public static final String[] VISIBILITY_NAMESPACES = new String[] {SymbolTable.publicNamespace, |
| SymbolTable.protectedNamespace, |
| SymbolTable.internalNamespace, |
| SymbolTable.privateNamespace}; |
| |
| public static final String NOTYPE = "*"; |
| public static final String STRING = "String"; |
| public static final String BOOLEAN = "Boolean"; |
| public static final String NUMBER = "Number"; |
| public static final String INT = "int"; |
| public static final String UINT = "uint"; |
| public static final String NAMESPACE = "Namespace"; |
| public static final String FUNCTION = "Function"; |
| public static final String CLASS = "Class"; |
| public static final String ARRAY = "Array"; |
| public static final String OBJECT = "Object"; |
| public static final String XML = "XML"; |
| public static final String XML_LIST = "XMLList"; |
| public static final String REPARENT = "Reparent"; |
| public static final String REGEXP = "RegExp"; |
| public static final String EVENT = "flash.events:Event"; |
| public static final String VECTOR = "__AS3__.vec:Vector"; |
| |
| static class NoType implements flex2.compiler.abc.AbcClass |
| { |
| public Variable getVariable(String[] namespaces, String name, boolean inherited) |
| { |
| return null; |
| } |
| |
| public Variable getVariable(Namespaces namespaces, String name, boolean inherited) |
| { |
| return null; |
| } |
| |
| public Method getMethod(String[] namespaces, String name, boolean inherited) |
| { |
| return null; |
| } |
| public Method getMethod(Namespaces namespaces, String name, boolean inherited) |
| { |
| return null; |
| } |
| |
| public Method getGetter(String[] namespaces, String name, boolean inherited) |
| { |
| return null; |
| } |
| public Method getGetter(Namespaces namespaces, String name, boolean inherited) |
| { |
| return null; |
| } |
| |
| public Method getSetter(String[] namespaces, String name, boolean inherited) |
| { |
| return null; |
| } |
| public Method getSetter(Namespaces namespaces, String name, boolean inherited) |
| { |
| return null; |
| } |
| |
| public String getName() |
| { |
| return NOTYPE; |
| } |
| |
| public String getElementTypeName() |
| { |
| return null; |
| } |
| |
| public String getSuperTypeName() |
| { |
| return null; |
| } |
| |
| public String[] getInterfaceNames() |
| { |
| return null; |
| } |
| |
| public List<MetaData> getMetaData(boolean inherited) |
| { |
| return null; |
| } |
| |
| public List<MetaData> getMetaData(String name, boolean inherited) |
| { |
| return null; |
| } |
| |
| public boolean implementsInterface(String interfaceName) |
| { |
| return false; |
| } |
| |
| public boolean isSubclassOf(String baseName) |
| { |
| return false; |
| } |
| |
| public boolean isInterface() |
| { |
| assert false; |
| return false; |
| } |
| |
| public boolean isDynamic() |
| { |
| return true; |
| } |
| |
| public boolean isPublic() |
| { |
| return true; |
| } |
| |
| public void setTypeTable(Object typeTable) |
| { |
| } |
| |
| public Iterator<Variable> getVarIterator() |
| { |
| return new EmptyIter<Variable>(); |
| } |
| public Iterator<Method> getMethodIterator() |
| { |
| return new EmptyIter<Method>(); |
| } |
| public Iterator<Method> getGetterIterator() |
| { |
| return new EmptyIter<Method>(); |
| } |
| public Iterator<Method> getSetterIterator() |
| { |
| return new EmptyIter<Method>(); |
| } |
| |
| class EmptyIter<T> implements Iterator<T> |
| { |
| public boolean hasNext() |
| { |
| return false; |
| } |
| public T next() |
| { |
| throw new NoSuchElementException(); |
| } |
| public void remove() |
| { |
| } |
| } |
| |
| public void freeze() |
| { |
| |
| } |
| } |
| |
| private static final NoType NoTypeClass = new NoType(); |
| |
| /** |
| * This constructor is useful when an existing ContextStatics |
| * should be reused. FlashBuilder entrypoint. |
| */ |
| public SymbolTable(Configuration configuration, ContextStatics contextStatics) |
| { |
| classTable = new HashMap<String, AbcClass>(300); |
| styles = new Styles(); |
| perCompileData = contextStatics; |
| |
| CompilerConfiguration compilerConfiguration = configuration.getCompilerConfiguration(); |
| perCompileData.use_static_semantics = compilerConfiguration.strict(); |
| perCompileData.dialect = compilerConfiguration.dialect(); |
| perCompileData.languageID = Context.getLanguageID(Locale.getDefault().getCountry().toUpperCase()); |
| perCompileData.setAbcVersion(configuration.getTargetPlayerTargetAVM()); |
| |
| // Leave out trace() statements when emitting bytecode |
| perCompileData.omitTrace = !compilerConfiguration.debug() && compilerConfiguration.omitTraceStatements(); |
| |
| // set up use_namespaces anytime before parsing begins |
| assert configuration.getTargetPlayerRequiredUseNamespaces() != null; |
| perCompileData.use_namespaces.addAll(configuration.getTargetPlayerRequiredUseNamespaces()); |
| |
| ContextStatics.useVerboseErrors = false; |
| |
| qNameTable = new QNameMap<Source>(300); |
| multiNames = new HashMap<MultiName, QName>(1024); |
| Context cx = new Context(perCompileData); |
| emitter = new BytecodeEmitter(cx, null, false, false); |
| cx.setEmitter(emitter); |
| typeAnalyzer = new TypeAnalyzer(this); |
| |
| rbNames = new HashMap<String, QName[]>(); |
| rbNameTable = new HashMap<String, Source>(); |
| } |
| |
| /** |
| * This constructor is useful when starting a fresh compile where |
| * a ContextStatics isn't available or doing a one-off compile |
| * where an existing ContextStatics shouldn't be poluted. |
| * FlashBuilder entrypoint. |
| */ |
| public SymbolTable(Configuration configuration) |
| { |
| this(configuration, new ContextStatics()); |
| } |
| |
| private final Map<String, AbcClass> classTable; |
| |
| // C: if possible, move styles out of SymbolTable... |
| private final Styles styles; |
| |
| // C: ContextStatics stays here because it holds namespace and type info... |
| public final ContextStatics perCompileData; |
| |
| private final QNameMap<Source> qNameTable; |
| private final Map<MultiName, QName> multiNames; |
| |
| // C: This single instance is for ConstantEvaluator to calculate doubles only. |
| public final BytecodeEmitter emitter; |
| |
| private CompilerContext context; |
| |
| // C: please see CompilerConfiguration.suppressWarningsInIncremental |
| private boolean suppressWarnings; |
| // See CompilerConfiguration.cfgDebug(). |
| private boolean debug; |
| |
| private final Map<String, QName[]> rbNames; |
| private final Map<String, Source> rbNameTable; |
| |
| public int tick = 0; |
| public int currentPercentage = 0; |
| |
| public void adjustProgress() |
| { |
| ProgressMeter meter = ThreadLocalToolkit.getProgressMeter(); |
| |
| for (int i = currentPercentage + 1; meter != null && i <= 100; i++) |
| { |
| meter.percentDone(i); |
| } |
| } |
| |
| public void registerClass(String className, AbcClass cls) |
| { |
| assert className.indexOf('/') == -1; |
| |
| classTable.put(className, cls); |
| } |
| |
| public AbcClass getClass(String className) |
| { |
| assert className == null || (className.indexOf('/') == -1) && NameFormatter.toColon(className).equals(className) : className; |
| AbcClass result = null; |
| |
| if (className != null) |
| { |
| if (className.equals("*")) |
| { |
| result = NoTypeClass; |
| } |
| else |
| { |
| result = classTable.get(className); |
| } |
| } |
| |
| return result; |
| } |
| |
| public Set<String> getClassNames() |
| { |
| return classTable.keySet(); |
| } |
| |
| // app-wide style management |
| |
| public void registerStyles(Styles newStyles) throws StyleConflictException |
| { |
| styles.addStyles(newStyles); |
| } |
| |
| public MetaData getStyle(String styleName) |
| { |
| if (styleName != null) |
| { |
| return styles.getStyle(styleName); |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| public Styles getStyles() |
| { |
| return styles; |
| } |
| |
| /** |
| * It is possible for a Source to define multiple definitions. This method creates mappings between |
| * the definitions and the Source instance. |
| */ |
| void registerQNames(QNameList qNames, Source source) |
| { |
| for (int i = 0, size = qNames.size(); i < size; i++) |
| { |
| QName qN = qNames.get(i); |
| qNameTable.put(qN, source); |
| } |
| } |
| |
| /** |
| * If CompilerAPI.resolveMultiName() is successful, the QName result should be associated with a Source object. |
| * Store the mapping here... |
| * |
| * @param qName ClassDefinitionNode.cframe.classname |
| * @param source Source |
| */ |
| public void registerQName(QName qName, Source source) |
| { |
| Source old = qNameTable.get(qName); |
| if (old == null) |
| { |
| qNameTable.put(new QName(qName), source); |
| } |
| else if (!old.getName().equals(source.getName())) |
| { |
| assert false : qName + " defined in " + old + " and " + source.getName(); |
| } |
| } |
| |
| public void registerResourceBundle(String rbName, Source source) |
| { |
| /* |
| Source old = (Source) rbNameTable.get(rbName); |
| if (old == null) |
| { |
| rbNameTable.put(rbName, source); |
| } |
| */ |
| rbNameTable.put(rbName, source); |
| } |
| |
| /** |
| * If CompilerAPI.resolveMultiName() is successful, the QName result should be associated with a Source object. |
| * This method allows for quick lookups given a qname. |
| */ |
| public Source findSourceByQName(QName qName) |
| { |
| return qNameTable.get(qName); |
| } |
| |
| /** |
| * If CompilerAPI.resolveMultiName() is successful, the QName result should be associated with a Source object. |
| * This method allows for quick lookups given a qname. |
| */ |
| public Source findSourceByQName(String namespaceURI, String localPart) |
| { |
| return qNameTable.get(namespaceURI, localPart); |
| } |
| |
| public Source findSourceByResourceBundleName(String rbName) |
| { |
| return rbNameTable.get(rbName); |
| } |
| |
| /** |
| * If CompilerAPI.resolveMultiName() successfully resolves a multiname to a qname, the result will be stored here. |
| */ |
| void registerMultiName(MultiName multiName, QName qName) |
| { |
| multiNames.put(multiName, qName); |
| } |
| |
| void registerResourceBundleName(String rbName, QName[] qNames) |
| { |
| rbNames.put(rbName, qNames); |
| } |
| |
| /** |
| * If CompilerAPI.resolveMultiName() successfully resolves a multiname to a qname, the result will be stored here. |
| * This method allows for quick lookup. |
| */ |
| public QName isMultiNameResolved(MultiName multiName) |
| { |
| return multiNames.get(multiName); |
| } |
| |
| public QName[] isResourceBundleResolved(String rbName) |
| { |
| return rbNames.get(rbName); |
| } |
| |
| /** |
| * placeholder for transient data |
| */ |
| public CompilerContext getContext() |
| { |
| if (context == null) |
| { |
| context = new CompilerContext(); |
| } |
| |
| return context; |
| } |
| |
| /** |
| * dereference the flex2.compiler.abc.AbcClass instances from flex2.compiler.as3.reflect.TypeTable. This is |
| * necessary for lowering the peak memory. It also makes the instances reusable in subsequent compilations. |
| */ |
| public void cleanClassTable() |
| { |
| for (Iterator<String> i = classTable.keySet().iterator(); i.hasNext();) |
| { |
| flex2.compiler.abc.AbcClass c = classTable.get(i.next()); |
| c.setTypeTable(null); |
| } |
| } |
| |
| // The following is for TypeAnalyzer only... please do not expand the usage to the other classes... |
| |
| private TypeAnalyzer typeAnalyzer; |
| |
| public TypeAnalyzer getTypeAnalyzer() |
| { |
| return typeAnalyzer; |
| } |
| |
| public boolean getSuppressWarningsIncremental() |
| { |
| return suppressWarnings; |
| } |
| |
| public void register(String rbName, QName[] qNames, Source source) |
| { |
| if (source != null) |
| { |
| registerResourceBundleName(rbName, qNames); |
| registerResourceBundle(rbName, source); |
| |
| for (int i = 0, length = qNames == null ? 0 : qNames.length; i < length; i++) |
| { |
| registerQName(qNames[i], source); |
| } |
| } |
| } |
| } |