/* * * 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.abc; import java.util.Vector; import org.apache.flex.abc.ABCConstants; import org.apache.flex.abc.semantics.ClassInfo; 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.PooledValue; import org.apache.flex.abc.semantics.Traits; import org.apache.flex.abc.visitors.ITraitVisitor; import org.apache.flex.abc.visitors.ITraitsVisitor; import org.apache.flex.compiler.constants.IASLanguageConstants; import org.apache.flex.compiler.definitions.IParameterDefinition; import org.apache.flex.compiler.definitions.references.INamespaceReference; import org.apache.flex.compiler.definitions.references.IReference; import org.apache.flex.compiler.definitions.references.ReferenceFactory; import org.apache.flex.compiler.internal.definitions.ClassDefinition; import org.apache.flex.compiler.internal.definitions.ConstantDefinition; import org.apache.flex.compiler.internal.definitions.DefinitionBase; import org.apache.flex.compiler.internal.definitions.FunctionDefinition; import org.apache.flex.compiler.internal.definitions.GetterDefinition; import org.apache.flex.compiler.internal.definitions.NamespaceDefinition; import org.apache.flex.compiler.internal.definitions.ParameterDefinition; import org.apache.flex.compiler.internal.definitions.SetterDefinition; import org.apache.flex.compiler.internal.definitions.TypeDefinitionBase; import org.apache.flex.compiler.internal.definitions.VariableDefinition; import org.apache.flex.compiler.internal.scopes.ASScope; import org.apache.flex.compiler.internal.scopes.FunctionScope; import org.apache.flex.compiler.scopes.IASScope; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; /** * This {@link ITraitsVisitor} creates definition for each trait, and add the * definitions to a scope object. */ public class ScopedDefinitionTraitsVisitor implements ITraitsVisitor { private static final IReference TYPE_ANY = ReferenceFactory.builtinReference(IASLanguageConstants.BuiltinType.ANY_TYPE); private static final IReference TYPE_FUNCTION = ReferenceFactory.builtinReference(IASLanguageConstants.BuiltinType.FUNCTION); private final ASScope scope; private final boolean isStatic; private final ABCScopeBuilder scopeBuilder; private final INamespaceReference interfNamespace; public ScopedDefinitionTraitsVisitor(final ABCScopeBuilder owner, final IASScope scope, boolean isStatic) { this(owner, scope, isStatic, null); } public ScopedDefinitionTraitsVisitor(final ABCScopeBuilder owner, final IASScope scope, boolean isStatic, INamespaceReference interfNamespace) { assert scope instanceof ASScope; this.scopeBuilder = owner; this.scope = (ASScope)scope; this.isStatic = isStatic; this.interfNamespace = interfNamespace; } @Override public ITraitVisitor visitSlotTrait(int kind, Name name, int slot_id, Name slot_type, Object slot_value) { final String definitionName = getDefinitionName(name); final DefinitionBase def; kind &= ABCConstants.TRAIT_KIND_MASK; switch (kind) { case ABCConstants.KIND_SLOT: def = new VariableDefinition(definitionName, slot_value); break; case ABCConstants.KIND_CONST: if (slot_value instanceof Namespace) def = NamespaceDefinition.createNamespaceDefinition(definitionName, (Namespace)slot_value); else def = new ConstantDefinition(definitionName, slot_value); break; default: throw new IllegalStateException("Invalid slot kind: " + kind); } final INamespaceReference namespaceReference = getNamespaceReference(name); def.setNamespaceReference(namespaceReference); if (isStatic) def.setStatic(); def.setTypeReference(slot_type == null ? TYPE_ANY : scopeBuilder.getReference(slot_type)); scope.addDefinition(def); return new CollectMetadataTraitVisitor(def); } @Override public ITraitVisitor visitMethodTrait(int kind, Name name, int disp_id, MethodInfo method) { final String definitionName = getDefinitionName(name); FunctionDefinition methodDef; kind &= ABCConstants.TRAIT_KIND_MASK; switch (kind) { case ABCConstants.KIND_METHOD: methodDef = new FunctionDefinition(definitionName); break; case ABCConstants.KIND_GETTER: methodDef = new GetterDefinition(definitionName); break; case ABCConstants.KIND_SETTER: methodDef = new SetterDefinition(definitionName); break; case ABCConstants.KIND_FUNCTION: methodDef = new FunctionDefinition(definitionName); break; default: throw new IllegalStateException("Invalid method kind:" + kind); } final INamespaceReference namespaceReference = getNamespaceReference(name); methodDef.setNamespaceReference(namespaceReference); int paramTypesSize = method.getParamTypes().size(); final ParameterDefinition params[] = new ParameterDefinition[paramTypesSize + (method.needsRest() ? 1 : 0)]; if (params.length > 0) { ASScope methodScope = new FunctionScope(scope); methodScope.setContainingDefinition(methodDef); methodDef.setContainedScope(methodScope); Vector<PooledValue> defaultValues = method.getDefaultValues(); int firstOptionalParam = paramTypesSize - defaultValues.size(); for (int i = 0; i < paramTypesSize; i++) { final Name paramType = method.getParamTypes().get(i); final String paramName = i < method.getParamNames().size() ? method.getParamNames().get(i) : MethodInfo.UNKNOWN_PARAM_NAME; params[i] = new ParameterDefinition(paramName); params[i].setTypeReference(paramType == null ? TYPE_ANY : scopeBuilder.getReference(paramType)); if (i >= firstOptionalParam) { Object defaultValue = defaultValues.get(i - firstOptionalParam).getValue(); params[i].setDefaultValue(defaultValue); } methodScope.addDefinition(params[i]); } if( method.needsRest() ) { ParameterDefinition rest = new ParameterDefinition(MethodInfo.UNKNOWN_PARAM_NAME); rest.setRest(); rest.setTypeReference(ReferenceFactory.builtinReference(IASLanguageConstants.BuiltinType.ARRAY)); params[paramTypesSize] = rest; } } methodDef.setParameters(params); Name returnType = method.getReturnType(); methodDef.setReturnTypeReference(returnType == null ? TYPE_ANY : scopeBuilder.getReference(returnType)); // The type of a getter or setter is its property type // (i.e., the getter's return type or the setter's parameter type). // The type of a method or function is "Function". switch (kind) { case ABCConstants.KIND_GETTER: methodDef.setTypeReference(methodDef.getReturnTypeReference()); break; case ABCConstants.KIND_SETTER: methodDef.setTypeReference(methodDef.getParameters()[0].getTypeReference()); break; case ABCConstants.KIND_METHOD: case ABCConstants.KIND_FUNCTION: methodDef.setTypeReference(TYPE_FUNCTION); break; default: throw new IllegalStateException("Invalid method kind:" + kind); } if (isStatic) methodDef.setStatic(); scope.addDefinition(methodDef); return new CollectMetadataTraitVisitor(methodDef); } @Override public ITraitVisitor visitClassTrait(int kind, Name name, int slot_id, ClassInfo clazz) { final TypeDefinitionBase classDef = scopeBuilder.classDefinitions.get(clazz); assert classDef != null : "Null class def at #" + slot_id; scope.addDefinition(classDef); classDef.getContainedScope().setContainingScope(scope); // Need to setup the scopes for the constructor and any params // here instead of ABCScopeBuilder, as we need to have a handle to the // class scope which isn't set until here. if (classDef instanceof ClassDefinition) { FunctionDefinition ctor = (FunctionDefinition)((ClassDefinition)classDef).getConstructor(); classDef.getContainedScope().addDefinition(ctor); IParameterDefinition[] params = ctor.getParameters(); if (params.length > 0) { ASScope ctorScope = new FunctionScope(scope); ctorScope.setContainingDefinition(ctor); ctor.setContainedScope(ctorScope); for (IParameterDefinition param : params) { ctorScope.addDefinition(param); } } } return new CollectMetadataTraitVisitor(classDef); } private static boolean legalDefinitionNsset(Nsset nsSet) { if (nsSet == null) return false; if (nsSet.length() == 1) return true; return Iterables.all(nsSet, new Predicate<Namespace>() { @Override public boolean apply(Namespace ns) { return ns.getApiVersion() != ABCConstants.NO_API_VERSION; } }); } public static String getDefinitionName(Name name) { final String baseName = name.getBaseName(); // A definition can only ever have one namespace entry // otherwise it is an invalid SWC. Nsset nsSet = name.getQualifiers(); if (!legalDefinitionNsset(nsSet)) { throw new IllegalStateException("Definition " + baseName + " can have only one qualifier or all qualifiers should be versioned namespaces"); } return baseName; } private INamespaceReference getNamespaceReference(Name name) { final Namespace namespace = Iterables.getFirst(name.getQualifiers(), null); assert namespace != null; INamespaceReference namespaceReference = (INamespaceReference)scopeBuilder.getNamespaceReferenceForNamespace(namespace); // Interface Namespaces are encoded as regular user defined namespaces in the ABC, but internally // we want them to be InterfaceNamespaceDefinitions. If we come across a user defined namespace while // building the traits for an interface, and it matches the interface namespace, then use the interface // namespace instead so that other processing that relies on InterfaceNamespaceDefinitions works right. if( interfNamespace != null && interfNamespace.equals(namespaceReference) ) namespaceReference = interfNamespace; return namespaceReference; } @Override public void visit() { } @Override public void visitEnd() { } @Override public Traits getTraits() { return null; } }