| /* |
| * |
| * 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.js.jx; |
| |
| import java.util.HashMap; |
| import java.util.Set; |
| |
| import org.apache.royale.compiler.asdoc.royale.ASDocComment; |
| import org.apache.royale.compiler.codegen.ISubEmitter; |
| import org.apache.royale.compiler.codegen.js.IJSEmitter; |
| import org.apache.royale.compiler.common.ASModifier; |
| import org.apache.royale.compiler.common.IMetaInfo; |
| import org.apache.royale.compiler.common.ModifiersSet; |
| import org.apache.royale.compiler.definitions.IAccessorDefinition; |
| import org.apache.royale.compiler.definitions.IClassDefinition; |
| import org.apache.royale.compiler.definitions.IDefinition; |
| import org.apache.royale.compiler.definitions.IFunctionDefinition; |
| import org.apache.royale.compiler.definitions.INamespaceDefinition; |
| import org.apache.royale.compiler.definitions.IParameterDefinition; |
| import org.apache.royale.compiler.definitions.ITypeDefinition; |
| import org.apache.royale.compiler.internal.as.codegen.BindableHelper; |
| import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens; |
| import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens; |
| import org.apache.royale.compiler.internal.codegen.js.JSSessionModel.PropertyNodes; |
| import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter; |
| import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter; |
| import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter; |
| import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens; |
| import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogDocEmitter; |
| import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogEmitterTokens; |
| import org.apache.royale.compiler.internal.projects.RoyaleJSProject; |
| import org.apache.royale.compiler.internal.semantics.SemanticUtils; |
| import org.apache.royale.compiler.internal.tree.as.FunctionNode; |
| import org.apache.royale.compiler.internal.tree.as.GetterNode; |
| import org.apache.royale.compiler.internal.tree.as.SetterNode; |
| import org.apache.royale.compiler.tree.ASTNodeID; |
| import org.apache.royale.compiler.tree.as.IAccessorNode; |
| import org.apache.royale.compiler.tree.as.IGetterNode; |
| import org.apache.royale.compiler.tree.as.INamespaceDecorationNode; |
| import org.apache.royale.compiler.tree.as.ISetterNode; |
| |
| public class AccessorEmitter extends JSSubEmitter implements |
| ISubEmitter<IAccessorNode> |
| { |
| |
| public AccessorEmitter(IJSEmitter emitter) |
| { |
| super(emitter); |
| } |
| |
| @Override |
| public void emit(IAccessorNode node) |
| { |
| if (node.getNodeID() == ASTNodeID.GetterID) |
| { |
| emitGet((IGetterNode) node); |
| } |
| else if (node.getNodeID() == ASTNodeID.SetterID) |
| { |
| emitSet((ISetterNode) node); |
| } |
| } |
| |
| public void emit(IClassDefinition definition) |
| { |
| // TODO (mschmalle) will remove this cast as more things get abstracted |
| JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter(); |
| RoyaleJSProject project = (RoyaleJSProject)getWalker().getProject(); |
| boolean emitExports = true; |
| if (project != null && project.config != null) |
| emitExports = project.config.getExportPublicSymbols(); |
| |
| if (!getModel().getPropertyMap().isEmpty()) |
| { |
| String qname = definition.getQualifiedName(); |
| Set<String> propertyNames = getModel().getPropertyMap().keySet(); |
| for (String propName : propertyNames) |
| { |
| PropertyNodes p = getModel().getPropertyMap().get(propName); |
| IGetterNode getterNode = p.getter; |
| ISetterNode setterNode = p.setter; |
| String baseName = p.name; |
| if (getModel().isExterns) |
| { |
| IAccessorNode node = (getterNode != null) ? getterNode : setterNode; |
| writeNewline(); |
| writeNewline(); |
| writeNewline(); |
| writeNewline("/**"); |
| if (emitExports) |
| writeNewline(" * @export"); |
| if (p.type != null) |
| writeNewline(" * @type {"+ JSGoogDocEmitter.convertASTypeToJSType(p.type.getBaseName(), p.type.getPackageName()) + "} */"); |
| else |
| writeNewline(" */"); |
| write(getEmitter().formatQualifiedName(qname)); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.PROTOTYPE); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)node).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(baseName); |
| } |
| write(ASEmitterTokens.SEMICOLON); |
| } |
| else |
| { |
| if (getterNode != null) |
| { |
| writeNewline(); |
| writeNewline(); |
| writeNewline(); |
| write(getEmitter().formatQualifiedName(qname)); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.PROTOTYPE); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)getterNode).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.GETTER_PREFIX); |
| write(baseName); |
| } |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.EQUAL); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.FUNCTION); |
| fjs.emitParameters(getterNode.getParametersContainerNode()); |
| |
| fjs.emitDefinePropertyFunction(getterNode); |
| |
| write(ASEmitterTokens.SEMICOLON); |
| } |
| if (setterNode != null) |
| { |
| boolean isClassBindable = BindableHelper.isClassCodeGenBindable(definition); |
| |
| boolean isBindable = false; |
| IAccessorDefinition setterDef = (IAccessorDefinition)setterNode.getDefinition(); |
| IAccessorDefinition getterDef = null; |
| if (getterNode != null) |
| getterDef = (IAccessorDefinition)getterNode.getDefinition(); |
| if ((getterDef != null && (setterDef.isBindable() || getterDef.isBindable()))) |
| { |
| boolean foundExplicitBindableTag = false; |
| if (setterDef.isBindable()) |
| { |
| |
| isBindable = BindableHelper.isCodeGenBindableMember(setterDef, isClassBindable); |
| foundExplicitBindableTag = BindableHelper.hasExplicitBindable(setterDef); |
| } |
| if (getterDef.isBindable()) |
| { |
| |
| isBindable = isBindable || BindableHelper.isCodeGenBindableMember(getterDef, isClassBindable); |
| foundExplicitBindableTag = foundExplicitBindableTag || BindableHelper.hasExplicitBindable(getterDef); |
| |
| } |
| |
| if (isClassBindable) { |
| //if we 'foundExplicitBindableTag' such as [Bindable(event='someEvent')], then nothing else matters, even another [Bindable] tag is ignored (Flex) |
| isBindable = !foundExplicitBindableTag; |
| } |
| } |
| writeNewline(); |
| writeNewline(); |
| writeNewline(); |
| write(getEmitter().formatQualifiedName(qname)); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.PROTOTYPE); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)setterNode).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| if (isBindable) { |
| write(JSRoyaleEmitterTokens.BINDABLE_PREFIX); |
| write(JSRoyaleEmitterTokens.SETTER_PREFIX); |
| write(getEmitter().formatPrivateName(definition.getQualifiedName(), baseName, true)); |
| } else { |
| write(JSRoyaleEmitterTokens.SETTER_PREFIX); |
| write(baseName); |
| } |
| } |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.EQUAL); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.FUNCTION); |
| fjs.emitParameters(setterNode.getParametersContainerNode()); |
| |
| fjs.emitDefinePropertyFunction(setterNode); |
| |
| write(ASEmitterTokens.SEMICOLON); |
| |
| if (isBindable) |
| { |
| writeNewline(); |
| writeNewline(); |
| writeNewline(); |
| write(getEmitter().formatQualifiedName(qname)); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.PROTOTYPE); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.SETTER_PREFIX); |
| write(baseName); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.EQUAL); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.FUNCTION); |
| write(ASEmitterTokens.PAREN_OPEN); |
| write("value"); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| write(ASEmitterTokens.SPACE); |
| writeNewline(ASEmitterTokens.BLOCK_OPEN); |
| write(ASEmitterTokens.VAR); |
| write(ASEmitterTokens.SPACE); |
| write("oldValue"); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.EQUAL); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.THIS); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.GETTER_PREFIX); |
| write(baseName); |
| write(ASEmitterTokens.PAREN_OPEN); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| writeNewline(ASEmitterTokens.SEMICOLON); |
| write(ASEmitterTokens.IF); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.PAREN_OPEN); |
| write("oldValue != value"); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| write(ASEmitterTokens.SPACE); |
| writeNewline(ASEmitterTokens.BLOCK_OPEN); |
| write(ASEmitterTokens.THIS); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.BINDABLE_PREFIX); |
| write(JSRoyaleEmitterTokens.SETTER_PREFIX); |
| write(getEmitter().formatPrivateName(definition.getQualifiedName(), baseName, true)); |
| write(ASEmitterTokens.PAREN_OPEN); |
| write("value"); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| writeNewline(ASEmitterTokens.SEMICOLON); |
| writeNewline(" this.dispatchEvent("+fjs.formatQualifiedName(BindableEmitter.VALUECHANGE_EVENT_QNAME)+".createUpdateEvent("); |
| writeNewline(" this, \"" + p.originalName + "\", oldValue, value));"); |
| writeNewline(ASEmitterTokens.BLOCK_CLOSE); |
| write(ASEmitterTokens.BLOCK_CLOSE); |
| write(ASEmitterTokens.SEMICOLON); |
| |
| } |
| } |
| } |
| } |
| } |
| if (!getModel().getPropertyMap().isEmpty() && !getModel().isExterns) |
| { |
| writeNewline(); |
| writeNewline(); |
| writeNewline(); |
| write(JSGoogEmitterTokens.OBJECT); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.DEFINE_PROPERTIES); |
| write(ASEmitterTokens.PAREN_OPEN); |
| String qname = definition.getQualifiedName(); |
| write(getEmitter().formatQualifiedName(qname)); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.PROTOTYPE); |
| write(ASEmitterTokens.COMMA); |
| write(ASEmitterTokens.SPACE); |
| write("/** @lends {" + getEmitter().formatQualifiedName(qname) |
| + ".prototype} */ "); |
| writeNewline(ASEmitterTokens.BLOCK_OPEN); |
| |
| Set<String> propertyNames = getModel().getPropertyMap().keySet(); |
| boolean firstTime = true; |
| for (String propName : propertyNames) |
| { |
| if (firstTime) |
| firstTime = false; |
| else |
| writeNewline(ASEmitterTokens.COMMA); |
| |
| boolean wroteGetter = false; |
| PropertyNodes p = getModel().getPropertyMap().get(propName); |
| String baseName = p.name; |
| IGetterNode getterNode = p.getter; |
| ISetterNode setterNode = p.setter; |
| writeNewline("/**"); |
| //if either one is marked as suppressed, both are considered to be |
| if(p.resolvedExport && !p.suppressExport) |
| { |
| writeNewline(" * @export"); |
| } |
| if (p.type != null) |
| { |
| String typeName = p.type.getBaseName(); |
| if (getModel().isInternalClass(typeName)) |
| typeName = getModel().getInternalClasses().get(typeName); |
| writeNewline(" * @type {" + JSGoogDocEmitter.convertASTypeToJSType(typeName, p.type.getPackageName()) + "} */"); |
| } |
| else |
| writeNewline(" */"); |
| FunctionNode fnNode = getterNode != null ? (FunctionNode) getterNode : (FunctionNode) setterNode; |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = fnNode.getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| //String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, baseName, false)); |
| } |
| else |
| write(baseName); |
| write(ASEmitterTokens.COLON); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.BLOCK_OPEN); |
| writeNewline(); |
| if (getterNode != null) |
| { |
| write(ASEmitterTokens.GET); |
| write(ASEmitterTokens.COLON); |
| write(ASEmitterTokens.SPACE); |
| write(getEmitter().formatQualifiedName(qname)); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.PROTOTYPE); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)getterNode).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| //String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.GETTER_PREFIX); |
| write(baseName); |
| } |
| wroteGetter = true; |
| } |
| else if (setterNode != null /* && setterNode.getDefinition().isOverride()*/) |
| { |
| // see if there is a getter on a base class. If so, we have to |
| // generate a call to the super from this class because |
| // Object.defineProperty doesn't allow overriding just the setter. |
| // If there is no getter defineProp'd the property will seen as |
| // write-only. |
| IAccessorDefinition other = (IAccessorDefinition)SemanticUtils.resolveCorrespondingAccessor(p.setter.getDefinition(), getProject()); |
| if (other != null) |
| { |
| write(ASEmitterTokens.GET); |
| write(ASEmitterTokens.COLON); |
| write(ASEmitterTokens.SPACE); |
| |
| write(getEmitter().formatQualifiedName(other.getParent().getQualifiedName())); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.PROTOTYPE); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)setterNode).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| //String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.GETTER_PREFIX); |
| write(baseName); |
| } |
| wroteGetter = true; |
| } |
| } |
| if (setterNode != null) |
| { |
| if (wroteGetter) |
| writeNewline(ASEmitterTokens.COMMA); |
| |
| write(ASEmitterTokens.SET); |
| write(ASEmitterTokens.COLON); |
| write(ASEmitterTokens.SPACE); |
| write(getEmitter().formatQualifiedName(qname)); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.PROTOTYPE); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)setterNode).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| //String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.SETTER_PREFIX); |
| write(baseName); |
| } |
| } |
| else if (getterNode != null/* && getterNode.getDefinition().isOverride()*/) |
| { |
| // see if there is a getter on a base class. If so, we have to |
| // generate a call to the super from this class because |
| // Object.defineProperty doesn't allow overriding just the getter. |
| // If there is no setter defineProp'd the property will seen as |
| // read-only. |
| IAccessorDefinition other = (IAccessorDefinition)SemanticUtils.resolveCorrespondingAccessor(p.getter.getDefinition(), getProject()); |
| if (other != null) |
| { |
| if (wroteGetter) |
| writeNewline(ASEmitterTokens.COMMA); |
| |
| write(ASEmitterTokens.SET); |
| write(ASEmitterTokens.COLON); |
| write(ASEmitterTokens.SPACE); |
| write(getEmitter().formatQualifiedName(other.getParent().getQualifiedName())); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.PROTOTYPE); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)getterNode).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| //String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.SETTER_PREFIX); |
| write(baseName); |
| } |
| } |
| } |
| write(ASEmitterTokens.BLOCK_CLOSE); |
| } |
| writeNewline(ASEmitterTokens.BLOCK_CLOSE); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| write(ASEmitterTokens.SEMICOLON); |
| } |
| if (!getModel().getStaticPropertyMap().isEmpty()) |
| { |
| String qname = definition.getQualifiedName(); |
| Set<String> propertyNames = getModel().getStaticPropertyMap().keySet(); |
| for (String propName : propertyNames) |
| { |
| PropertyNodes p = getModel().getStaticPropertyMap().get(propName); |
| IGetterNode getterNode = p.getter; |
| ISetterNode setterNode = p.setter; |
| String baseName = p.name; |
| if (getModel().isExterns) |
| { |
| IAccessorNode node = (getterNode != null) ? getterNode : setterNode; |
| writeNewline(); |
| writeNewline(); |
| writeNewline(); |
| writeNewline("/**"); |
| if (emitExports) |
| writeNewline(" * @export"); |
| if (p.type != null) |
| writeNewline(" * @type {" + JSGoogDocEmitter.convertASTypeToJSType(p.type.getBaseName(), p.type.getPackageName()) + "} */"); |
| else |
| writeNewline(" */"); |
| write(getEmitter().formatQualifiedName(qname)); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)node).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(baseName); |
| } |
| write(ASEmitterTokens.SEMICOLON); |
| } |
| else |
| { |
| if (getterNode != null) |
| { |
| writeNewline(); |
| writeNewline(); |
| writeNewline(); |
| write(getEmitter().formatQualifiedName(qname)); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)getterNode).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| //String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri , JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.GETTER_PREFIX); |
| write(baseName); |
| } |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.EQUAL); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.FUNCTION); |
| fjs.emitParameters(getterNode.getParametersContainerNode()); |
| |
| fjs.emitDefinePropertyFunction(getterNode); |
| |
| write(ASEmitterTokens.SEMICOLON); |
| } |
| if (setterNode != null) |
| { |
| writeNewline(); |
| writeNewline(); |
| writeNewline(); |
| write(getEmitter().formatQualifiedName(qname)); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)setterNode).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| //String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.SETTER_PREFIX); |
| write(baseName); |
| } |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.EQUAL); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.FUNCTION); |
| fjs.emitParameters(setterNode.getParametersContainerNode()); |
| |
| fjs.emitDefinePropertyFunction(setterNode); |
| |
| write(ASEmitterTokens.SEMICOLON); |
| } |
| } |
| } |
| } |
| if (!getModel().getStaticPropertyMap().isEmpty() && !getModel().isExterns) |
| { |
| writeNewline(); |
| writeNewline(); |
| writeNewline(); |
| write(JSGoogEmitterTokens.OBJECT); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.DEFINE_PROPERTIES); |
| write(ASEmitterTokens.PAREN_OPEN); |
| String qname = definition.getQualifiedName(); |
| write(getEmitter().formatQualifiedName(qname)); |
| write(ASEmitterTokens.COMMA); |
| write(ASEmitterTokens.SPACE); |
| write("/** @lends {" + getEmitter().formatQualifiedName(qname) |
| + "} */ "); |
| writeNewline(ASEmitterTokens.BLOCK_OPEN); |
| |
| Set<String> propertyNames = getModel().getStaticPropertyMap() |
| .keySet(); |
| boolean firstTime = true; |
| for (String propName : propertyNames) |
| { |
| if (firstTime) |
| firstTime = false; |
| else |
| writeNewline(ASEmitterTokens.COMMA); |
| |
| PropertyNodes p = getModel().getStaticPropertyMap().get( |
| propName); |
| IGetterNode getterNode = p.getter; |
| ISetterNode setterNode = p.setter; |
| String baseName = p.name; |
| writeNewline("/**"); |
| if (p.resolvedExport && !p.suppressExport) |
| writeNewline(" * @export"); |
| if (p.type != null) |
| writeNewline(" * @type {" + JSGoogDocEmitter.convertASTypeToJSType(p.type.getBaseName(), p.type.getPackageName()) + "} */"); |
| else |
| writeNewline(" */"); |
| FunctionNode fnNode = getterNode != null ? (FunctionNode) getterNode : (FunctionNode) setterNode; |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = fnNode.getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| //String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, baseName, false)); |
| } |
| else |
| write(baseName); |
| write(ASEmitterTokens.COLON); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.BLOCK_OPEN); |
| writeNewline(); |
| if (getterNode != null) |
| { |
| write(ASEmitterTokens.GET); |
| write(ASEmitterTokens.COLON); |
| write(ASEmitterTokens.SPACE); |
| write(getEmitter().formatQualifiedName(qname)); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)getterNode).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| //String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.GETTER_PREFIX); |
| write(baseName); |
| } |
| } |
| if (setterNode != null) |
| { |
| if (p.getter != null) |
| writeNewline(ASEmitterTokens.COMMA); |
| |
| write(ASEmitterTokens.SET); |
| write(ASEmitterTokens.COLON); |
| write(ASEmitterTokens.SPACE); |
| write(getEmitter().formatQualifiedName(qname)); |
| if (p.uri != null) |
| { |
| INamespaceDecorationNode ns = ((FunctionNode)setterNode).getActualNamespaceNode(); |
| INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| //String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(p.uri, JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + baseName, true)); |
| } |
| else |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSRoyaleEmitterTokens.SETTER_PREFIX); |
| write(baseName); |
| } |
| } |
| write(ASEmitterTokens.BLOCK_CLOSE); |
| } |
| writeNewline(ASEmitterTokens.BLOCK_CLOSE); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| write(ASEmitterTokens.SEMICOLON); |
| } |
| } |
| |
| public void emitGet(IGetterNode node) |
| { |
| // TODO (mschmalle) will remove this cast as more things get abstracted |
| JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter(); |
| boolean suppress = getModel().suppressExports || |
| (node.getASDocComment() != null && |
| ((ASDocComment)node.getASDocComment()).commentNoEnd().contains(JSRoyaleEmitterTokens.SUPPRESS_EXPORT.getToken())); |
| if (suppress) getModel().suppressedExportNodes.add(node); |
| |
| IDefinition def = node.getDefinition(); |
| ModifiersSet modifierSet = def.getModifiers(); |
| boolean isStatic = (modifierSet != null && modifierSet |
| .hasModifier(ASModifier.STATIC)); |
| HashMap<String, PropertyNodes> map = isStatic ? getModel() |
| .getStaticPropertyMap() : getModel().getPropertyMap(); |
| String name = node.getName(); |
| if (!isStatic && def != null && def.isPrivate() && getProject().getAllowPrivateNameConflicts()) |
| name = fjs.formatPrivateName(def.getParent().getQualifiedName(), name); |
| |
| String uri = null; |
| String key = name; |
| if (!def.getNamespaceReference().isLanguageNamespace()) { |
| //we need to include it in the name mappings |
| uri = ((INamespaceDefinition) ((GetterNode) node).getActualNamespaceNode().resolve(getProject())).getURI(); |
| //make sure the key includes the uri to avoid clashing with other equivalent base names |
| key = uri + "::" + name; |
| } |
| boolean emitExports = true; |
| boolean exportProtected = false; |
| boolean exportInternal = false; |
| RoyaleJSProject project = (RoyaleJSProject) getWalker().getProject(); |
| if (project != null && project.config != null) |
| { |
| emitExports = project.config.getExportPublicSymbols(); |
| exportProtected = project.config.getExportProtectedSymbols(); |
| exportInternal = project.config.getExportInternalSymbols(); |
| } |
| |
| PropertyNodes p = map.get(key); |
| if (p == null) |
| { |
| p = new PropertyNodes(); |
| //track name and uri separately: |
| p.name = name; |
| p.originalName = node.getName(); |
| p.uri = uri; |
| map.put(key, p); |
| } |
| if(uri != null || def.isPublic()) |
| { |
| p.resolvedExport = emitExports; |
| } |
| else if(def.isInternal()) |
| { |
| p.resolvedExport = exportInternal; |
| } |
| else if(def.isProtected()) |
| { |
| p.resolvedExport = exportProtected; |
| } |
| p.getter = node; |
| if (!p.suppressExport) p.suppressExport = suppress; |
| if (p.type == null && project != null) |
| p.type = node.getDefinition().resolveReturnType(project); |
| FunctionNode fn = (FunctionNode) node; |
| fn.parseFunctionBody(fjs.getProblems()); |
| } |
| |
| public void emitSet(ISetterNode node) |
| { |
| // TODO (mschmalle) will remove this cast as more things get abstracted |
| JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter(); |
| JSRoyaleDocEmitter doc = (JSRoyaleDocEmitter) fjs.getDocEmitter(); |
| boolean suppress = getModel().suppressExports || |
| (node.getASDocComment() != null && |
| ((ASDocComment)node.getASDocComment()).commentNoEnd().contains(JSRoyaleEmitterTokens.SUPPRESS_EXPORT.getToken())); |
| if (suppress) getModel().suppressedExportNodes.add(node); |
| |
| IFunctionDefinition def = node.getDefinition(); |
| ModifiersSet modifierSet = def.getModifiers(); |
| boolean isStatic = (modifierSet != null && modifierSet |
| .hasModifier(ASModifier.STATIC)); |
| HashMap<String, PropertyNodes> map = isStatic ? getModel() |
| .getStaticPropertyMap() : getModel().getPropertyMap(); |
| String name = node.getName(); |
| if (!isStatic && def != null && def.isPrivate() && getProject().getAllowPrivateNameConflicts()) |
| name = fjs.formatPrivateName(def.getParent().getQualifiedName(), name); |
| String uri = null; |
| String key = name; |
| if (!def.getNamespaceReference().isLanguageNamespace()) { |
| //we need to include it in the name mappings |
| uri = ((INamespaceDefinition) ((SetterNode) node).getActualNamespaceNode().resolve(getProject())).getURI(); |
| //make sure the key includes the uri to avoid clashing with other equivalent base names |
| key = uri + "::" + name; |
| } |
| boolean emitExports = true; |
| boolean exportProtected = false; |
| boolean exportInternal = false; |
| RoyaleJSProject project = (RoyaleJSProject) getWalker().getProject(); |
| if (project != null && project.config != null) |
| { |
| emitExports = project.config.getExportPublicSymbols(); |
| exportProtected = project.config.getExportProtectedSymbols(); |
| exportInternal = project.config.getExportInternalSymbols(); |
| } |
| |
| PropertyNodes p = map.get(key); |
| if (p == null) |
| { |
| p = new PropertyNodes(); |
| //track name and uri separately: |
| p.name = name; |
| p.originalName = node.getName(); |
| p.uri = uri; |
| map.put(key, p); |
| } |
| if(uri != null || def.isPublic()) |
| { |
| p.resolvedExport = emitExports; |
| } |
| else if(def.isInternal()) |
| { |
| p.resolvedExport = exportInternal; |
| } |
| else if(def.isProtected()) |
| { |
| p.resolvedExport = exportProtected; |
| } |
| p.setter = node; |
| if (!p.suppressExport) p.suppressExport = suppress; |
| if (p.type == null && project != null) |
| { |
| IParameterDefinition[] params = def.getParameters(); |
| p.type = params[0].resolveType(project); |
| } |
| FunctionNode fn = (FunctionNode) node; |
| fn.parseFunctionBody(fjs.getProblems()); |
| |
| boolean isBindableSetter = false; |
| if (node instanceof SetterNode) |
| { |
| IMetaInfo[] metaInfos = null; |
| metaInfos = node.getMetaInfos(); |
| for (IMetaInfo metaInfo : metaInfos) |
| { |
| name = metaInfo.getTagName(); |
| if (name.equals("Bindable") |
| && metaInfo.getAllAttributes().length == 0) |
| { |
| isBindableSetter = true; |
| break; |
| } |
| } |
| } |
| if (isBindableSetter) |
| { |
| IFunctionDefinition definition = node.getDefinition(); |
| ITypeDefinition type = (ITypeDefinition) definition.getParent(); |
| doc.emitMethodDoc(fn, getProject()); |
| write(fjs.formatQualifiedName(type.getQualifiedName())); |
| if (!node.hasModifier(ASModifier.STATIC)) |
| { |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write(JSEmitterTokens.PROTOTYPE); |
| } |
| |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write("__bindingWrappedSetter__"); |
| writeToken(node.getName()); |
| writeToken(ASEmitterTokens.EQUAL); |
| write(ASEmitterTokens.FUNCTION); |
| fjs.emitParameters(node.getParametersContainerNode()); |
| //writeNewline(); |
| fjs.emitMethodScope(node.getScopedNode()); |
| writeNewline(); |
| } |
| } |
| } |