You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by jo...@apache.org on 2016/10/14 18:56:27 UTC

[1/3] git commit: [flex-falcon] [refs/heads/develop] - LiteralEmitter: when a function has [JSX] metadata, any XML literals inside are treated as JSX and React calls are emitted instead

Repository: flex-falcon
Updated Branches:
  refs/heads/develop 680c335c7 -> 80eb23610


LiteralEmitter: when a function has [JSX] metadata, any XML literals inside are treated as JSX and React calls are emitted instead


Project: http://git-wip-us.apache.org/repos/asf/flex-falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-falcon/commit/72f0c52a
Tree: http://git-wip-us.apache.org/repos/asf/flex-falcon/tree/72f0c52a
Diff: http://git-wip-us.apache.org/repos/asf/flex-falcon/diff/72f0c52a

Branch: refs/heads/develop
Commit: 72f0c52ad18b454b95ce4dfbf6c0e587742730eb
Parents: 8e79559
Author: Josh Tynjala <jo...@gmail.com>
Authored: Thu Oct 13 14:26:27 2016 -0700
Committer: Josh Tynjala <jo...@gmail.com>
Committed: Fri Oct 14 10:10:16 2016 -0700

----------------------------------------------------------------------
 .../js/flexjs/JSFlexJSEmitterTokens.java        |   1 +
 .../internal/codegen/js/jx/LiteralEmitter.java  | 422 ++++++++++++++++---
 .../codegen/js/flexjs/TestFlexJSJSX.java        | 180 ++++++++
 3 files changed, 534 insertions(+), 69 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/72f0c52a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitterTokens.java
----------------------------------------------------------------------
diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitterTokens.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitterTokens.java
index 4431407..4a140e3 100644
--- a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitterTokens.java
+++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitterTokens.java
@@ -55,6 +55,7 @@ public enum JSFlexJSEmitterTokens implements IEmitterTokens
     CLOSURE_FUNCTION_NAME("org.apache.flex.utils.Language.closure"),
     SKIP_AS_COERCIONS("skipAsCoercions"),
     SKIP_FUNCTION_COERCIONS("skipFunctionCoercions"),
+    JSX("JSX"),
     ;
 
     private String token;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/72f0c52a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java
----------------------------------------------------------------------
diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java
index 1be3b1e..c3e371d 100644
--- a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java
@@ -19,15 +19,25 @@
 
 package org.apache.flex.compiler.internal.codegen.js.jx;
 
+import java.util.ArrayList;
+import java.util.Stack;
+
 import org.apache.flex.compiler.codegen.ISubEmitter;
 import org.apache.flex.compiler.codegen.js.IJSEmitter;
+import org.apache.flex.compiler.common.IMetaInfo;
+import org.apache.flex.compiler.common.Multiname;
+import org.apache.flex.compiler.internal.codegen.as.ASEmitterTokens;
 import org.apache.flex.compiler.internal.codegen.js.JSSubEmitter;
+import org.apache.flex.compiler.internal.codegen.js.flexjs.JSFlexJSEmitterTokens;
 import org.apache.flex.compiler.internal.tree.as.LiteralNode;
 import org.apache.flex.compiler.internal.tree.as.RegExpLiteralNode;
 import org.apache.flex.compiler.internal.tree.as.XMLLiteralNode;
 import org.apache.flex.compiler.tree.as.IASNode;
+import org.apache.flex.compiler.tree.as.IFunctionNode;
+import org.apache.flex.compiler.tree.as.IImportNode;
 import org.apache.flex.compiler.tree.as.ILiteralNode;
 import org.apache.flex.compiler.tree.as.ILiteralNode.LiteralType;
+import org.apache.flex.compiler.tree.as.IScopedNode;
 
 public class LiteralEmitter extends JSSubEmitter implements
         ISubEmitter<ILiteralNode>
@@ -49,60 +59,83 @@ public class LiteralEmitter extends JSSubEmitter implements
         {
             if (node.getLiteralType() == LiteralType.XML)
             {
-            	newlineReplacement = "\\\\\n";
-            	XMLLiteralNode xmlNode = (XMLLiteralNode)node;
-            	if (xmlNode.getContentsNode().getChildCount() == 1)
-            	{
-	            	if (s.contains("'"))
-	            		s = "\"" + s + "\"";
-	            	else
-	            		s = "'" + s + "'";
-            	}
-            	else
-            	{
-        			StringBuilder sb = new StringBuilder();
-            		// probably contains {initializers}
-        			boolean inAttribute = false;
-            		int n = xmlNode.getContentsNode().getChildCount();
-            		for (int i = 0; i < n; i++)
-            		{
-            			if (i > 0)
-            				sb.append(" + ");
-            			IASNode child = xmlNode.getContentsNode().getChild(i);
-            			if (child instanceof LiteralNode)
-            			{
-            				s = ((LiteralNode)child).getValue(true);
-        	            	if (s.contains("'"))
-        	            		sb.append("\"" + s + "\"");
-        	            	else
-        	            		sb.append("'" + s + "'");
-            			}
-            			else
-            			{
-            				s = getEmitter().stringifyNode(child);
-            				if (inAttribute)
-            				{
-            					sb.append("'\"' + ");
-
-            					sb.append(s);
-            					
-            					sb.append(" + '\"'");
-            				}
-            				else
-            					sb.append(s);
-            			}
-        				inAttribute = s.equals("=");
-            		}
-            		s = sb.toString();
-            	}
-                char c = s.charAt(0);
-                if (c == '"')
+                boolean jsx = false;
+                IFunctionNode functionNode = (IFunctionNode) node
+                        .getAncestorOfType(IFunctionNode.class);
+                if (functionNode != null)
                 {
-                    s = s.substring(1, s.length() - 1);
-                    s = s.replace("\"", "\\\"");
-                    s = "\"" + s + "\"";
+                    IMetaInfo[] metaInfos = functionNode.getMetaInfos();
+                    for (IMetaInfo metaInfo : metaInfos)
+                    {
+                        if (metaInfo.getTagName().equals(JSFlexJSEmitterTokens.JSX.getToken()))
+                        {
+                            jsx = true;
+                            break;
+                        }
+                    }
+                }
+                XMLLiteralNode xmlNode = (XMLLiteralNode) node;
+                if (jsx)
+                {
+                    emitJSX(xmlNode);
+                    return;
+                }
+                else
+                {
+                    newlineReplacement = "\\\\\n";
+                    if (xmlNode.getContentsNode().getChildCount() == 1)
+                    {
+                        if (s.contains("'"))
+                            s = "\"" + s + "\"";
+                        else
+                            s = "'" + s + "'";
+                    }
+                    else
+                    {
+                        StringBuilder sb = new StringBuilder();
+                        // probably contains {initializers}
+                        boolean inAttribute = false;
+                        int n = xmlNode.getContentsNode().getChildCount();
+                        for (int i = 0; i < n; i++)
+                        {
+                            if (i > 0)
+                                sb.append(" + ");
+                            IASNode child = xmlNode.getContentsNode().getChild(i);
+                            if (child instanceof LiteralNode)
+                            {
+                                s = ((LiteralNode) child).getValue(true);
+                                if (s.contains("'"))
+                                    sb.append("\"" + s + "\"");
+                                else
+                                    sb.append("'" + s + "'");
+                            }
+                            else
+                            {
+                                s = getEmitter().stringifyNode(child);
+                                if (inAttribute)
+                                {
+                                    sb.append("'\"' + ");
+
+                                    sb.append(s);
+
+                                    sb.append(" + '\"'");
+                                }
+                                else
+                                    sb.append(s);
+                            }
+                            inAttribute = s.equals("=");
+                        }
+                        s = sb.toString();
+                    }
+                    char c = s.charAt(0);
+                    if (c == '"')
+                    {
+                        s = s.substring(1, s.length() - 1);
+                        s = s.replace("\"", "\\\"");
+                        s = "\"" + s + "\"";
+                    }
+                    s = "new XML( " + s + ")";
                 }
-                s = "new XML( " + s + ")";
             }
             s = s.replaceAll("\n", "__NEWLINE_PLACEHOLDER__");
             s = s.replaceAll("\r", "__CR_PLACEHOLDER__");
@@ -121,30 +154,281 @@ public class LiteralEmitter extends JSSubEmitter implements
             s = s.replaceAll("__NEWLINE_PLACEHOLDER__", newlineReplacement);
             if (node.getLiteralType() == LiteralType.STRING)
             {
-            	char c = s.charAt(0);
-            	if (c == '"')
-            	{
-            		s = s.substring(1, s.length() - 1);
-            		s = s.replace("\"", "\\\"");
-            		s = "\"" + s + "\"";
-            	}
-            	else if (c == '\'')
-            	{
-            		s = s.substring(1, s.length() - 1);
-            		s = s.replace("'", "\\'");            		
-            		s = "'" + s + "'";
-            	}
-            	s = s.replace("\u2028", "\\u2028");
-            	s = s.replace("\u2029", "\\u2029");
+                char c = s.charAt(0);
+                if (c == '"')
+                {
+                    s = s.substring(1, s.length() - 1);
+                    s = s.replace("\"", "\\\"");
+                    s = "\"" + s + "\"";
+                }
+                else if (c == '\'')
+                {
+                    s = s.substring(1, s.length() - 1);
+                    s = s.replace("'", "\\'");
+                    s = "'" + s + "'";
+                }
+                s = s.replace("\u2028", "\\u2028");
+                s = s.replace("\u2029", "\\u2029");
             }
 
         }
 
         if (!isWritten)
         {
-			startMapping(node);
+            startMapping(node);
             write(s);
-			endMapping(node);
+            endMapping(node);
+        }
+    }
+
+    private void emitJSX(XMLLiteralNode node)
+    {
+        int childCount = node.getContentsNode().getChildCount();
+        Stack<String> elementStack = new Stack<String>();
+        String elementName = null;
+        boolean endsWithAttribute = false;
+        for (int i = 0; i < childCount; i++)
+        {
+            IASNode child = node.getContentsNode().getChild(i);
+            if (child instanceof ILiteralNode)
+            {
+                ILiteralNode literalChild = (ILiteralNode) child;
+                if (literalChild.getLiteralType() != LiteralType.XML)
+                {
+                    //inside {} syntax. emit normally.
+                    getEmitter().getWalker().walk(literalChild);
+                    continue;
+                }
+                String value = literalChild.getValue(true);
+                value = value.replaceAll(ASEmitterTokens.NEW_LINE.getToken(), "");
+                value = value.trim();
+                while (value.length() > 0)
+                {
+                    int nextTagStartIndex = value.indexOf("<");
+                    int nextTagEndIndex = value.indexOf(">");
+                    boolean selfClosing = false;
+                    boolean startsWithAttribute = false;
+                    if (nextTagEndIndex > 0
+                            && value.charAt(nextTagEndIndex - 1) == '/')
+                    {
+                        selfClosing = true;
+                    }
+                    if (endsWithAttribute)
+                    {
+                        //we'll fall back into attribute parsing below
+                        endsWithAttribute = false;
+                        startsWithAttribute = true;
+                        elementName = elementStack.peek();
+                    }
+                    else if (nextTagStartIndex == 0)
+                    {
+                        //assume that the name ends at the end of the open tag
+                        int endNameIndex = nextTagEndIndex;
+                        if (endNameIndex == -1)
+                        {
+                            //literal ends with an attribute that uses {} syntax
+                            endNameIndex = value.length() - 1;
+                        }
+                        int attributeIndex = value.indexOf(" ");
+                        if (attributeIndex > 0 && attributeIndex < endNameIndex)
+                        {
+                            //if there are attributes, the name does not end at
+                            //the end of the open tag
+                            endNameIndex = attributeIndex;
+                        }
+                        elementName = value.substring(1, endNameIndex);
+                        if (elementName.endsWith("/"))
+                        {
+                            elementName = elementName.substring(0, elementName.length() - 1);
+                        }
+                        if (elementName.startsWith("/"))
+                        {
+                            //the close tag of the current element
+                            elementName = elementName.substring(1);
+                            elementName = getQualifiedElementName(elementName, node);
+                            if (elementStack.size() > 0)
+                            {
+                                indentPop();
+                            }
+                            write(ASEmitterTokens.PAREN_CLOSE);
+                            String topOfStack = elementStack.pop();
+                            assert topOfStack.equals(elementName);
+                            value = value.substring(nextTagEndIndex + 1);
+                            value = value.trim();
+                            continue;
+                        }
+                        else
+                        {
+                            //the open tag of a new element
+                            if (elementStack.size() > 0)
+                            {
+                                indentPush();
+                                writeNewline(ASEmitterTokens.COMMA);
+                            }
+                            elementName = getQualifiedElementName(elementName, node);
+                            elementStack.push(elementName);
+                            write("React.createElement");
+                            write(ASEmitterTokens.PAREN_OPEN);
+                            write(elementName);
+                            value = value.substring(endNameIndex);
+                            value = value.trim();
+                            //we changed the string, so find it again
+                            nextTagEndIndex = value.indexOf(">");
+                        }
+                    }
+                    else
+                    {
+                        //we're inside an element's open and closing tags
+                        String elementText = value.substring(0, nextTagStartIndex);
+                        writeToken(ASEmitterTokens.COMMA);
+                        emitJSXText(elementText);
+                        value = value.substring(nextTagStartIndex);
+                        continue;
+                    }
+                    //parse the tag's attributes
+                    if (nextTagEndIndex == -1)
+                    {
+                        //literal ends with an attribute that uses {} syntax
+                        endsWithAttribute = true;
+                        nextTagEndIndex = value.length() - 1;
+                    }
+                    int attributesEndIndex = (selfClosing && nextTagEndIndex > 0) ? nextTagEndIndex - 1 : nextTagEndIndex;
+                    String attributes = value.substring(0, attributesEndIndex);
+                    emitJSXAttributes(attributes, startsWithAttribute, endsWithAttribute);
+                    if (selfClosing)
+                    {
+                        //end of open tag, including attributes
+                        write(ASEmitterTokens.PAREN_CLOSE);
+                        if (elementStack.size() > 0)
+                        {
+                            indentPop();
+                        }
+                        String topOfStack = elementStack.pop();
+                        assert topOfStack.equals(elementName);
+                    }
+                    value = value.substring(nextTagEndIndex + 1);
+                    value = value.trim();
+                }
+            }
+            else
+            {
+                if (!endsWithAttribute)
+                {
+                    writeToken(ASEmitterTokens.COMMA);
+                }
+                //not a literal, and inside {} syntax. emit normally.
+                getEmitter().getWalker().walk(child);
+            }
+        }
+    }
+
+    private void emitJSXAttributes(String value, boolean startsWithAttribute, boolean endsWithAttribute)
+    {
+        int attributeCount = 0;
+        while (true)
+        {
+            int charCount = value.length();
+            if (charCount == 0)
+            {
+                break;
+            }
+            int endAttributeNameIndex = value.indexOf("=");
+            if (endAttributeNameIndex == -1)
+            {
+                endAttributeNameIndex = value.length();
+            }
+            String attributeName = value.substring(0, endAttributeNameIndex);
+            writeToken(ASEmitterTokens.COMMA);
+            if (!startsWithAttribute && attributeCount == 0)
+            {
+                writeToken(ASEmitterTokens.BLOCK_OPEN);
+            }
+            if (attributeName.indexOf('-') >= 0)
+            {
+                emitJSXText(attributeName);
+            }
+            else
+            {
+                write(attributeName);
+            }
+            writeToken(ASEmitterTokens.COLON);
+            attributeCount++;
+            if ((endAttributeNameIndex + 1) >= charCount)
+            {
+                //literal ends with an attribute that uses {} syntax
+                break;
+            }
+            int quoteChar = value.charAt(endAttributeNameIndex + 1);
+            int startAttributeValueIndex = endAttributeNameIndex + 2;
+            if (startAttributeValueIndex > charCount)
+            {
+                startAttributeValueIndex = charCount;
+            }
+            int endAttributeValueIndex = value.indexOf(quoteChar, startAttributeValueIndex);
+            if (endAttributeValueIndex == -1 || endAttributeValueIndex > charCount)
+            {
+                endAttributeValueIndex = charCount;
+            }
+            if (endAttributeValueIndex > 0)
+            {
+                String attributeValue = value.substring(startAttributeValueIndex, endAttributeValueIndex);
+                emitJSXText(attributeValue);
+                value = value.substring(endAttributeValueIndex + 1);
+                value = value.trim();
+            }
+        }
+        if (!endsWithAttribute)
+        {
+            if (!startsWithAttribute && attributeCount == 0)
+            {
+                writeToken(ASEmitterTokens.COMMA);
+                write(ASEmitterTokens.NULL);
+            }
+            else
+            {
+                write(ASEmitterTokens.SPACE);
+                write(ASEmitterTokens.BLOCK_CLOSE);
+            }
+        }
+    }
+
+    private void emitJSXText(String elementText)
+    {
+        write(ASEmitterTokens.SINGLE_QUOTE);
+        elementText = elementText.replaceAll("'", "\\\\\'");
+        write(elementText);
+        write(ASEmitterTokens.SINGLE_QUOTE);
+    }
+
+    private String getQualifiedElementName(String elementName, IASNode node)
+    {
+        String firstChar = elementName.substring(0, 1);
+        boolean isHTMLTag = firstChar.toLowerCase().equals(firstChar);
+        if (isHTMLTag)
+        {
+            return ASEmitterTokens.SINGLE_QUOTE.getToken() + elementName + ASEmitterTokens.SINGLE_QUOTE.getToken();
+        }
+        ArrayList<IImportNode> importNodes = new ArrayList<IImportNode>();
+        IScopedNode scopedNode = node.getContainingScope();
+        scopedNode.getAllImportNodes(importNodes);
+        for (IImportNode importNode : importNodes)
+        {
+            if (importNode.isWildcardImport())
+            {
+                continue;
+            }
+            String importName = importNode.getImportName();
+            String importAlias = importNode.getImportAlias();
+            if (importAlias != null && importAlias.equals(elementName))
+            {
+                return importName;
+            }
+            String baseName = Multiname.getBaseNameForQName(importName);
+            if (baseName.equals(elementName))
+            {
+                return importName;
+            }
         }
+        return elementName;
     }
 }

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/72f0c52a/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSJSX.java
----------------------------------------------------------------------
diff --git a/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSJSX.java b/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSJSX.java
new file mode 100644
index 0000000..a3c1c07
--- /dev/null
+++ b/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSJSX.java
@@ -0,0 +1,180 @@
+/*
+ *
+ *  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.codegen.js.flexjs;
+
+import org.apache.flex.compiler.driver.IBackend;
+import org.apache.flex.compiler.internal.driver.js.flexjs.FlexJSBackend;
+import org.apache.flex.compiler.internal.test.ASTestBase;
+import org.apache.flex.compiler.tree.as.IFunctionNode;
+
+import org.junit.Test;
+
+public class TestFlexJSJSX extends ASTestBase
+{
+    @Test
+    public void testJSXMetadataWithoutXMLLiterals()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n}");
+    }
+
+    @Test
+    public void testSimpleSelfClosingHTMLTag()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div/>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', null);\n}");
+    }
+
+    @Test
+    public void testSimpleSelfClosingHTMLTagWithTrailingSpace()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div />}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', null);\n}");
+    }
+
+    @Test
+    public void testSelfClosingHTMLTagWithAttribute()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div id=\"foo\"/>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', { id: 'foo' });\n}");
+    }
+
+    @Test
+    public void testSelfClosingHTMLTagWithMultipleAttributes()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div id=\"foo\" className=\"bar\"/>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', { id: 'foo', className: 'bar' });\n}");
+    }
+
+    @Test
+    public void testSelfClosingHTMLTagWithSingleQuoteAttribute()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div id=\'foo\'/>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', { id: 'foo' });\n}");
+    }
+
+    @Test
+    public void testSelfClosingHTMLTagWithSingleQuoteInAttribute()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div id=\"'\"/>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', { id: '\\\'' });\n}");
+    }
+
+    @Test
+    public void testSelfClosingHTMLTagWithDashInAttributeName()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div data-prop=\"foo\"/>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', { 'data-prop': 'foo' });\n}");
+    }
+
+    @Test
+    public void testSelfClosingHTMLTagWithSpaceInAttribute()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div className=\"foo bar\"/>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', { className: 'foo bar' });\n}");
+    }
+
+    @Test
+    public void testSelfClosingHTMLTagWithSpaceInSingleQuoteAttribute()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div className=\'foo bar\'/>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', { className: 'foo bar' });\n}");
+    }
+
+    @Test
+    public void testSelfClosingHTMLTagWithCurlyAttribute()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div id={2}/>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', { id: 2 });\n}");
+    }
+
+    @Test
+    public void testSimpleOpenAndCloseHTMLTag()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div></div>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', null);\n}");
+    }
+
+    @Test
+    public void testOpenAndCloseHTMLTagWithChildText()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div>Foo</div>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', null, 'Foo');\n}");
+    }
+
+    @Test
+    public void testOpenAndCloseHTMLTagWithAttribute()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div id=\"foo\"></div>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', { id: 'foo' });\n}");
+    }
+
+    @Test
+    public void testOpenAndCloseHTMLTagWithMultipleAttributes()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div id=\"foo\" className=\"bar\"></div>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', { id: 'foo', className: 'bar' });\n}");
+    }
+
+    @Test
+    public void testOpenAndCloseHTMLTagWithAttributeAndChildText()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div id=\"foo\">Foo</div>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', { id: 'foo' }, 'Foo');\n}");
+    }
+
+    @Test
+    public void testNestedHTMLTags()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {return <div><button/></div>}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement('div', null,\n    React.createElement('button', null));\n}");
+    }
+
+    @Test
+    public void testImportedClass()
+    {
+        IFunctionNode node = getMethod("[JSX]\nfunction foo() {\n  import flash.events.EventDispatcher;\n  return <EventDispatcher/>;\n}");
+        asBlockWalker.visitFunction(node);
+        assertOut("FalconTest_A.prototype.foo = function() {\n  return React.createElement(flash.events.EventDispatcher, null);\n}");
+    }
+
+    @Override
+    protected IBackend createBackend()
+    {
+        return new FlexJSBackend();
+    }
+}


[2/3] git commit: [flex-falcon] [refs/heads/develop] - compiler-jx: import statements are not output in JS (they were previously if they appeared in a function)

Posted by jo...@apache.org.
compiler-jx: import statements are not output in JS (they were previously if they appeared in a function)


Project: http://git-wip-us.apache.org/repos/asf/flex-falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-falcon/commit/a9650946
Tree: http://git-wip-us.apache.org/repos/asf/flex-falcon/tree/a9650946
Diff: http://git-wip-us.apache.org/repos/asf/flex-falcon/diff/a9650946

Branch: refs/heads/develop
Commit: a96509461b45e143baf52423552a0990a3821824
Parents: 680c335
Author: Josh Tynjala <jo...@gmail.com>
Authored: Fri Oct 14 10:42:26 2016 -0700
Committer: Josh Tynjala <jo...@gmail.com>
Committed: Fri Oct 14 10:42:26 2016 -0700

----------------------------------------------------------------------
 .../flex/compiler/internal/codegen/js/JSEmitter.java   |  7 +++++++
 .../internal/codegen/js/jx/StatementEmitter.java       |  6 ++++++
 .../codegen/js/flexjs/TestFlexJSStatements.java        | 13 +++++++++++++
 3 files changed, 26 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/a9650946/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/JSEmitter.java
----------------------------------------------------------------------
diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/JSEmitter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/JSEmitter.java
index 237c430..7824a87 100644
--- a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/JSEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/JSEmitter.java
@@ -69,6 +69,7 @@ import org.apache.flex.compiler.tree.as.IForLoopNode;
 import org.apache.flex.compiler.tree.as.IFunctionNode;
 import org.apache.flex.compiler.tree.as.IFunctionObjectNode;
 import org.apache.flex.compiler.tree.as.IIfNode;
+import org.apache.flex.compiler.tree.as.IImportNode;
 import org.apache.flex.compiler.tree.as.IIterationFlowNode;
 import org.apache.flex.compiler.tree.as.ILanguageIdentifierNode;
 import org.apache.flex.compiler.tree.as.ILiteralContainerNode;
@@ -340,6 +341,12 @@ public class JSEmitter extends ASEmitter implements IJSEmitter
     }
 
     @Override
+    public void emitImport(IImportNode node)
+    {
+        // do nothing
+    }
+
+    @Override
     public void emitWhileLoop(IWhileLoopNode node)
     {
         whileLoopEmitter.emit(node);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/a9650946/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/StatementEmitter.java
----------------------------------------------------------------------
diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/StatementEmitter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/StatementEmitter.java
index 1f4eb4d..40e933e 100644
--- a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/StatementEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/StatementEmitter.java
@@ -39,6 +39,12 @@ public class StatementEmitter extends JSSubEmitter implements
     {
         getWalker().walk(node);
 
+        if(node.getNodeID() == ASTNodeID.ImportID)
+        {
+            //imports aren't emitted, so don't emit anything here either
+            return;
+        }
+
         // XXX (mschmalle) this should be in the after handler?
         if (node.getParent().getNodeID() != ASTNodeID.LabledStatementID
                 && node.getNodeID() != ASTNodeID.ConfigBlockID

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/a9650946/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSStatements.java
----------------------------------------------------------------------
diff --git a/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSStatements.java b/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSStatements.java
index 733973e..604d0f1 100644
--- a/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSStatements.java
+++ b/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSStatements.java
@@ -27,6 +27,7 @@ import org.apache.flex.compiler.internal.tree.as.LabeledStatementNode;
 import org.apache.flex.compiler.tree.as.IFileNode;
 import org.apache.flex.compiler.tree.as.IForLoopNode;
 import org.apache.flex.compiler.tree.as.IIfNode;
+import org.apache.flex.compiler.tree.as.IImportNode;
 import org.apache.flex.compiler.tree.as.ILiteralNode;
 import org.apache.flex.compiler.tree.as.ISwitchNode;
 import org.apache.flex.compiler.tree.as.ITryNode;
@@ -470,6 +471,18 @@ public class TestFlexJSStatements extends TestGoogStatements
         assertOut("with (a)\n  b;");
     }
 
+    //----------------------------------
+    // import a.b.C
+    //----------------------------------
+
+    @Test
+    public void testVisitImport()
+    {
+        IImportNode node = (IImportNode) getNode("import flash.events.EventDispatcher;", IImportNode.class);
+        asBlockWalker.visitImport(node);
+        assertOut("");
+    }
+
     @Override
     @Test
     public void testVisit()


[3/3] git commit: [flex-falcon] [refs/heads/develop] - merge develop

Posted by jo...@apache.org.
merge develop


Project: http://git-wip-us.apache.org/repos/asf/flex-falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-falcon/commit/80eb2361
Tree: http://git-wip-us.apache.org/repos/asf/flex-falcon/tree/80eb2361
Diff: http://git-wip-us.apache.org/repos/asf/flex-falcon/diff/80eb2361

Branch: refs/heads/develop
Commit: 80eb2361059d483a93a087b8c844b14563074a63
Parents: 72f0c52 a965094
Author: Josh Tynjala <jo...@gmail.com>
Authored: Fri Oct 14 10:50:35 2016 -0700
Committer: Josh Tynjala <jo...@gmail.com>
Committed: Fri Oct 14 10:57:09 2016 -0700

----------------------------------------------------------------------
 .../apache/flex/compiler/clients/ASDOCJSC.java  |  13 --
 .../apache/flex/compiler/clients/COMPJSC.java   |   2 -
 .../compiler/internal/codegen/js/JSEmitter.java |   7 +
 .../internal/codegen/js/JSSessionModel.java     |   1 -
 .../codegen/js/flexjs/JSFlexJSASDocEmitter.java |  63 ------
 .../internal/codegen/js/jx/AccessorEmitter.java |   2 -
 .../codegen/js/jx/BinaryOperatorEmitter.java    |   2 -
 .../internal/codegen/js/jx/FieldEmitter.java    |  14 --
 .../codegen/js/jx/FunctionCallEmitter.java      |  30 ++-
 .../codegen/js/jx/IdentifierEmitter.java        |   4 -
 .../internal/codegen/js/jx/LiteralEmitter.java  |   8 +-
 .../codegen/js/jx/MemberAccessEmitter.java      |   3 -
 .../codegen/js/jx/StatementEmitter.java         |   6 +
 .../codegen/js/jx/SuperCallEmitter.java         |   2 -
 .../mxml/flexjs/MXMLFlexJSASDocEmitter.java     | 210 -------------------
 .../codegen/mxml/flexjs/MXMLFlexJSEmitter.java  |   6 +-
 .../driver/js/goog/ASDocConfiguration.java      |   2 -
 .../driver/mxml/ASDocASSourceFileHandler.java   |   1 -
 .../mxml/flexjs/MXMLFlexJSASDocBackend.java     |   5 -
 .../internal/projects/FlexJSProject.java        |   1 -
 .../js/flexjs/TestFlexJSGlobalClasses.java      |  26 +++
 .../js/flexjs/TestFlexJSGlobalFunctions.java    |   8 +
 .../codegen/js/flexjs/TestFlexJSStatements.java |  13 ++
 .../flex/compiler/internal/scopes/ASScope.java  |   2 -
 .../compiler/internal/tree/as/ImportNode.java   |   1 -
 .../src/test/java/as/ASInheritanceTests.java    |   1 -
 26 files changed, 91 insertions(+), 342 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/80eb2361/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java
----------------------------------------------------------------------
diff --cc compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java
index c3e371d,d3fc55d..47f0c8d
--- a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java
@@@ -59,83 -49,60 +59,83 @@@ public class LiteralEmitter extends JSS
          {
              if (node.getLiteralType() == LiteralType.XML)
              {
 -            	newlineReplacement = "\\\\\n";
 -            	XMLLiteralNode xmlNode = (XMLLiteralNode)node;
 -            	if (xmlNode.getContentsNode().getChildCount() == 1)
 -            	{
 -	            	if (s.contains("'"))
 -	            		s = "\"" + s + "\"";
 -	            	else
 -	            		s = "'" + s + "'";
 -            	}
 -            	else
 -            	{
 -        			StringBuilder sb = new StringBuilder();
 -            		// probably contains {initializers}
 -        			boolean inAttribute = false;
 -            		int n = xmlNode.getContentsNode().getChildCount();
 -            		for (int i = 0; i < n; i++)
 -            		{
 -            			if (i > 0)
 -            				sb.append(" + ");
 -            			IASNode child = xmlNode.getContentsNode().getChild(i);
 -            			if (child instanceof LiteralNode)
 -            			{
 -            				s = ((LiteralNode)child).getValue(true);
 -        	            	if (s.contains("'"))
 -        	            		sb.append("\"" + s + "\"");
 -        	            	else
 -        	            		sb.append("'" + s + "'");
 -            			}
 -            			else
 -            			{
 -            				s = getEmitter().stringifyNode(child);
 -            				if (inAttribute)
 -            				{
 -            					sb.append("'\"' + ");
 -
 -            					sb.append(s);
 -            					
 -            					sb.append(" + '\"'");
 -            				}
 -            				else
 -            					sb.append(s);
 -            			}
 -        				inAttribute = s.endsWith("=");
 -            		}
 -            		s = sb.toString();
 -            	}
 -                char c = s.charAt(0);
 -                if (c == '"')
 +                boolean jsx = false;
 +                IFunctionNode functionNode = (IFunctionNode) node
 +                        .getAncestorOfType(IFunctionNode.class);
 +                if (functionNode != null)
                  {
 -                    s = s.substring(1, s.length() - 1);
 -                    s = s.replace("\"", "\\\"");
 -                    s = "\"" + s + "\"";
 +                    IMetaInfo[] metaInfos = functionNode.getMetaInfos();
 +                    for (IMetaInfo metaInfo : metaInfos)
 +                    {
 +                        if (metaInfo.getTagName().equals(JSFlexJSEmitterTokens.JSX.getToken()))
 +                        {
 +                            jsx = true;
 +                            break;
 +                        }
 +                    }
 +                }
 +                XMLLiteralNode xmlNode = (XMLLiteralNode) node;
 +                if (jsx)
 +                {
 +                    emitJSX(xmlNode);
 +                    return;
 +                }
 +                else
 +                {
 +                    newlineReplacement = "\\\\\n";
 +                    if (xmlNode.getContentsNode().getChildCount() == 1)
 +                    {
 +                        if (s.contains("'"))
 +                            s = "\"" + s + "\"";
 +                        else
 +                            s = "'" + s + "'";
 +                    }
 +                    else
 +                    {
 +                        StringBuilder sb = new StringBuilder();
 +                        // probably contains {initializers}
 +                        boolean inAttribute = false;
 +                        int n = xmlNode.getContentsNode().getChildCount();
 +                        for (int i = 0; i < n; i++)
 +                        {
 +                            if (i > 0)
 +                                sb.append(" + ");
 +                            IASNode child = xmlNode.getContentsNode().getChild(i);
 +                            if (child instanceof LiteralNode)
 +                            {
-                                 s = ((LiteralNode) child).getValue(true);
++                                s = ((LiteralNode)child).getValue(true);
 +                                if (s.contains("'"))
 +                                    sb.append("\"" + s + "\"");
 +                                else
 +                                    sb.append("'" + s + "'");
 +                            }
 +                            else
 +                            {
 +                                s = getEmitter().stringifyNode(child);
 +                                if (inAttribute)
 +                                {
 +                                    sb.append("'\"' + ");
- 
++    
 +                                    sb.append(s);
- 
++                                    
 +                                    sb.append(" + '\"'");
 +                                }
 +                                else
 +                                    sb.append(s);
 +                            }
-                             inAttribute = s.equals("=");
++                            inAttribute = s.endsWith("=");
 +                        }
 +                        s = sb.toString();
 +                    }
 +                    char c = s.charAt(0);
 +                    if (c == '"')
 +                    {
 +                        s = s.substring(1, s.length() - 1);
 +                        s = s.replace("\"", "\\\"");
 +                        s = "\"" + s + "\"";
 +                    }
 +                    s = "new XML( " + s + ")";
                  }
 -                s = "new XML( " + s + ")";
              }
              s = s.replaceAll("\n", "__NEWLINE_PLACEHOLDER__");
              s = s.replaceAll("\r", "__CR_PLACEHOLDER__");